Tue, 08 Jan 2019 16:17:56 -0800
Added tag jdk8u202-b26 for changeset c0f526208190
1 /*
2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package compileproperties;
28 import java.io.BufferedWriter;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.io.OutputStreamWriter;
35 import java.io.Writer;
36 import java.text.MessageFormat;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Properties;
43 /** Translates a .properties file into a .java file containing the
44 * definition of a java.util.Properties subclass which can then be
45 * compiled with javac. <P>
46 *
47 * Usage: java CompileProperties [path to .properties file] [path to .java file to be output] [super class]
48 *
49 * Infers the package by looking at the common suffix of the two
50 * inputs, eliminating "classes" from it.
51 *
52 * @author Scott Violet
53 * @author Kenneth Russell
54 */
56 public class CompileProperties {
58 public static void main(String[] args) {
59 CompileProperties cp = new CompileProperties();
60 boolean ok = cp.run(args);
61 if ( !ok ) {
62 System.exit(1);
63 }
64 }
66 public static interface Log {
67 void info(String msg);
68 void verbose(String msg);
69 void error(String msg, Exception e);
70 }
72 private String propfiles[];
73 private String outfiles[] ;
74 private String supers[] ;
75 private int compileCount = 0;
76 private boolean quiet = false;
77 public Log log;
79 public void setLog(Log log) {
80 this.log = log;
81 }
83 public boolean run(String[] args) {
84 if (log == null) {
85 log = new Log() {
86 public void error(String msg, Exception e) {
87 System.err.println("ERROR: CompileProperties: " + msg);
88 if ( e != null ) {
89 System.err.println("EXCEPTION: " + e.toString());
90 e.printStackTrace();
91 }
92 }
93 public void info(String msg) {
94 System.out.println(msg);
95 }
96 public void verbose(String msg) {
97 if (!quiet)
98 System.out.println(msg);
99 }
100 };
101 }
103 boolean ok = true;
104 /* Original usage */
105 if (args.length == 2 && args[0].charAt(0) != '-' ) {
106 ok = createFile(args[0], args[1], "java.util.ListResourceBundle");
107 } else if (args.length == 3) {
108 ok = createFile(args[0], args[1], args[2]);
109 } else if (args.length == 0) {
110 usage(log);
111 ok = false;
112 } else {
113 /* New batch usage */
114 ok = parseOptions(args);
115 if ( ok && compileCount == 0 ) {
116 log.error("options parsed but no files to compile", null);
117 ok = false;
118 }
119 /* Need at least one file. */
120 if ( !ok ) {
121 usage(log);
122 } else {
123 /* Process files */
124 for ( int i = 0; i < compileCount && ok ; i++ ) {
125 ok = createFile(propfiles[i], outfiles[i], supers[i]);
126 }
127 }
128 }
129 return ok;
130 }
132 private boolean parseOptions(String args[]) {
133 boolean ok = true;
134 if ( compileCount > 0 ) {
135 String new_propfiles[] = new String[compileCount + args.length];
136 String new_outfiles[] = new String[compileCount + args.length];
137 String new_supers[] = new String[compileCount + args.length];
138 System.arraycopy(propfiles, 0, new_propfiles, 0, compileCount);
139 System.arraycopy(outfiles, 0, new_outfiles, 0, compileCount);
140 System.arraycopy(supers, 0, new_supers, 0, compileCount);
141 propfiles = new_propfiles;
142 outfiles = new_outfiles;
143 supers = new_supers;
144 } else {
145 propfiles = new String[args.length];
146 outfiles = new String[args.length];
147 supers = new String[args.length];
148 }
150 for ( int i = 0; i < args.length ; i++ ) {
151 if ( "-compile".equals(args[i]) && i+3 < args.length ) {
152 propfiles[compileCount] = args[++i];
153 outfiles[compileCount] = args[++i];
154 supers[compileCount] = args[++i];
155 compileCount++;
156 } else if ( "-optionsfile".equals(args[i]) && i+1 < args.length ) {
157 String filename = args[++i];
158 FileInputStream finput = null;
159 byte contents[] = null;
160 try {
161 finput = new FileInputStream(filename);
162 int byteCount = finput.available();
163 if ( byteCount <= 0 ) {
164 log.error("The -optionsfile file is empty", null);
165 ok = false;
166 } else {
167 contents = new byte[byteCount];
168 int bytesRead = finput.read(contents);
169 if ( byteCount != bytesRead ) {
170 log.error("Cannot read all of -optionsfile file", null);
171 ok = false;
172 }
173 }
174 } catch ( IOException e ) {
175 log.error("cannot open " + filename, e);
176 ok = false;
177 }
178 if ( finput != null ) {
179 try {
180 finput.close();
181 } catch ( IOException e ) {
182 ok = false;
183 log.error("cannot close " + filename, e);
184 }
185 }
186 if ( ok = true && contents != null ) {
187 String tokens[] = (new String(contents)).split("\\s+");
188 if ( tokens.length > 0 ) {
189 ok = parseOptions(tokens);
190 }
191 }
192 if ( !ok ) {
193 break;
194 }
195 } else if ( "-quiet".equals(args[i]) ) {
196 quiet = true;
197 } else {
198 log.error("argument error", null);
199 ok = false;
200 }
201 }
202 return ok;
203 }
205 private boolean createFile(String propertiesPath, String outputPath,
206 String superClass) {
207 boolean ok = true;
208 log.verbose("parsing: " + propertiesPath);
209 Properties p = new Properties();
210 try {
211 p.load(new FileInputStream(propertiesPath));
212 } catch ( FileNotFoundException e ) {
213 ok = false;
214 log.error("Cannot find file " + propertiesPath, e);
215 } catch ( IOException e ) {
216 ok = false;
217 log.error("IO error on file " + propertiesPath, e);
218 }
219 if ( ok ) {
220 String packageName = inferPackageName(propertiesPath, outputPath);
221 log.verbose("inferred package name: " + packageName);
222 List<String> sortedKeys = new ArrayList<String>();
223 for ( Object key : p.keySet() ) {
224 sortedKeys.add((String)key);
225 }
226 Collections.sort(sortedKeys);
227 Iterator<String> keys = sortedKeys.iterator();
229 StringBuffer data = new StringBuffer();
231 while (keys.hasNext()) {
232 String key = keys.next();
233 data.append(" { \"" + escape(key) + "\", \"" +
234 escape((String)p.get(key)) + "\" },\n");
235 }
237 // Get class name from java filename, not the properties filename.
238 // (zh_TW properties might be used to create zh_HK files)
239 File file = new File(outputPath);
240 String name = file.getName();
241 int dotIndex = name.lastIndexOf('.');
242 String className;
243 if (dotIndex == -1) {
244 className = name;
245 } else {
246 className = name.substring(0, dotIndex);
247 }
249 String packageString = "";
250 if (packageName != null && !packageName.equals("")) {
251 packageString = "package " + packageName + ";\n\n";
252 }
254 Writer writer = null;
255 try {
256 writer = new BufferedWriter(
257 new OutputStreamWriter(new FileOutputStream(outputPath), "8859_1"));
258 MessageFormat format = new MessageFormat(FORMAT);
259 writer.write(format.format(new Object[] { packageString, className, superClass, data }));
260 } catch ( IOException e ) {
261 ok = false;
262 log.error("IO error writing to file " + outputPath, e);
263 }
264 if ( writer != null ) {
265 try {
266 writer.flush();
267 } catch ( IOException e ) {
268 ok = false;
269 log.error("IO error flush " + outputPath, e);
270 }
271 try {
272 writer.close();
273 } catch ( IOException e ) {
274 ok = false;
275 log.error("IO error close " + outputPath, e);
276 }
277 }
278 log.verbose("wrote: " + outputPath);
279 }
280 return ok;
281 }
283 private static void usage(Log log) {
284 log.info("usage:");
285 log.info(" java CompileProperties path_to_properties_file path_to_java_output_file [super_class]");
286 log.info(" -OR-");
287 log.info(" java CompileProperties {-compile path_to_properties_file path_to_java_output_file super_class} -or- -optionsfile filename");
288 log.info("");
289 log.info("Example:");
290 log.info(" java CompileProperties -compile test.properties test.java java.util.ListResourceBundle");
291 log.info(" java CompileProperties -optionsfile option_file");
292 log.info("option_file contains: -compile test.properties test.java java.util.ListResourceBundle");
293 }
295 private static String escape(String theString) {
296 // This is taken from Properties.saveConvert with changes for Java strings
297 int len = theString.length();
298 StringBuffer outBuffer = new StringBuffer(len*2);
300 for(int x=0; x<len; x++) {
301 char aChar = theString.charAt(x);
302 switch(aChar) {
303 case '\\':outBuffer.append('\\'); outBuffer.append('\\');
304 break;
305 case '\t':outBuffer.append('\\'); outBuffer.append('t');
306 break;
307 case '\n':outBuffer.append('\\'); outBuffer.append('n');
308 break;
309 case '\r':outBuffer.append('\\'); outBuffer.append('r');
310 break;
311 case '\f':outBuffer.append('\\'); outBuffer.append('f');
312 break;
313 default:
314 if ((aChar < 0x0020) || (aChar > 0x007e)) {
315 outBuffer.append('\\');
316 outBuffer.append('u');
317 outBuffer.append(toHex((aChar >> 12) & 0xF));
318 outBuffer.append(toHex((aChar >> 8) & 0xF));
319 outBuffer.append(toHex((aChar >> 4) & 0xF));
320 outBuffer.append(toHex( aChar & 0xF));
321 } else {
322 if (specialSaveChars.indexOf(aChar) != -1) {
323 outBuffer.append('\\');
324 }
325 outBuffer.append(aChar);
326 }
327 }
328 }
329 return outBuffer.toString();
330 }
332 private static String inferPackageName(String inputPath, String outputPath) {
333 // Normalize file names
334 inputPath = new File(inputPath).getPath();
335 outputPath = new File(outputPath).getPath();
336 // Split into components
337 String sep;
338 if (File.separatorChar == '\\') {
339 sep = "\\\\";
340 } else {
341 sep = File.separator;
342 }
343 String[] inputs = inputPath.split(sep);
344 String[] outputs = outputPath.split(sep);
345 // Match common names, eliminating first "classes" entry from
346 // each if present
347 int inStart = 0;
348 int inEnd = inputs.length - 2;
349 int outEnd = outputs.length - 2;
350 int i = inEnd;
351 int j = outEnd;
352 while (i >= 0 && j >= 0) {
353 if (!inputs[i].equals(outputs[j]) ||
354 (inputs[i].equals("gensrc") && inputs[j].equals("gensrc"))) {
355 ++i;
356 ++j;
357 break;
358 }
359 --i;
360 --j;
361 }
362 String result;
363 if (i < 0 || j < 0 || i >= inEnd || j >= outEnd) {
364 result = "";
365 } else {
366 if (inputs[i].equals("classes") && outputs[j].equals("classes")) {
367 ++i;
368 }
369 inStart = i;
370 StringBuffer buf = new StringBuffer();
371 for (i = inStart; i <= inEnd; i++) {
372 buf.append(inputs[i]);
373 if (i < inEnd) {
374 buf.append('.');
375 }
376 }
377 result = buf.toString();
378 }
379 return result;
380 }
382 private static final String FORMAT =
383 "{0}" +
384 "public final class {1} extends {2} '{'\n" +
385 " protected final Object[][] getContents() '{'\n" +
386 " return new Object[][] '{'\n" +
387 "{3}" +
388 " };\n" +
389 " }\n" +
390 "}\n";
392 // This comes from Properties
393 private static char toHex(int nibble) {
394 return hexDigit[(nibble & 0xF)];
395 }
397 // This comes from Properties
398 private static final char[] hexDigit = {
399 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
400 };
402 // Note: different from that in Properties
403 private static final String specialSaveChars = "\"";
404 }