make/tools/CompileProperties/CompileProperties.java

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

mercurial