make/tools/CompileProperties/CompileProperties.java

Mon, 11 Jan 2010 14:09:15 -0800

author
jjg
date
Mon, 11 Jan 2010 14:09:15 -0800
changeset 465
f983c1dca202
parent 1
9a66ca7c79fa
child 554
9d9f26857129
permissions
-rw-r--r--

6764569: [PATCH] Fix unused imports in list resource bundles
Reviewed-by: ksrini
Contributed-by: jesse.glick@sun.com

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

mercurial