make/tools/CompileProperties/CompileProperties.java

changeset 1
9a66ca7c79fa
child 465
f983c1dca202
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/make/tools/CompileProperties/CompileProperties.java	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,403 @@
     1.4 +/*
     1.5 + * Copyright 2002-2005 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Sun designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Sun in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.26 + * have any questions.
    1.27 + */
    1.28 +
    1.29 +import java.io.BufferedWriter;
    1.30 +import java.io.File;
    1.31 +import java.io.FileInputStream;
    1.32 +import java.io.FileNotFoundException;
    1.33 +import java.io.FileOutputStream;
    1.34 +import java.io.IOException;
    1.35 +import java.io.OutputStreamWriter;
    1.36 +import java.io.Writer;
    1.37 +import java.text.MessageFormat;
    1.38 +import java.util.ArrayList;
    1.39 +import java.util.Collections;
    1.40 +import java.util.Iterator;
    1.41 +import java.util.List;
    1.42 +import java.util.Properties;
    1.43 +
    1.44 +/** Translates a .properties file into a .java file containing the
    1.45 + *  definition of a java.util.Properties subclass which can then be
    1.46 + *  compiled with javac. <P>
    1.47 + *
    1.48 + *  Usage: java CompileProperties [path to .properties file] [path to .java file to be output] [super class]
    1.49 + *
    1.50 + *  Infers the package by looking at the common suffix of the two
    1.51 + *  inputs, eliminating "classes" from it.
    1.52 + *
    1.53 + * @author Scott Violet
    1.54 + * @author Kenneth Russell
    1.55 + */
    1.56 +
    1.57 +public class CompileProperties {
    1.58 +
    1.59 +    public static void main(String[] args) {
    1.60 +        CompileProperties cp = new CompileProperties();
    1.61 +        boolean ok = cp.run(args);
    1.62 +        if ( !ok ) {
    1.63 +            System.exit(1);
    1.64 +        }
    1.65 +    }
    1.66 +
    1.67 +    static interface Log {
    1.68 +        void info(String msg);
    1.69 +        void verbose(String msg);
    1.70 +        void error(String msg, Exception e);
    1.71 +    }
    1.72 +
    1.73 +    private String propfiles[];
    1.74 +    private String outfiles[] ;
    1.75 +    private String supers[]   ;
    1.76 +    private int compileCount = 0;
    1.77 +    private boolean quiet = false;
    1.78 +    private Log log;
    1.79 +
    1.80 +    public void setLog(Log log) {
    1.81 +        this.log = log;
    1.82 +    }
    1.83 +
    1.84 +    public boolean run(String[] args) {
    1.85 +        if (log == null) {
    1.86 +            log = new Log() {
    1.87 +                public void error(String msg, Exception e) {
    1.88 +                    System.err.println("ERROR: CompileProperties: " + msg);
    1.89 +                    if ( e != null ) {
    1.90 +                        System.err.println("EXCEPTION: " + e.toString());
    1.91 +                        e.printStackTrace();
    1.92 +                    }
    1.93 +                }
    1.94 +                public void info(String msg) {
    1.95 +                    System.out.println(msg);
    1.96 +                }
    1.97 +                public void verbose(String msg) {
    1.98 +                    if (!quiet)
    1.99 +                        System.out.println(msg);
   1.100 +                }
   1.101 +            };
   1.102 +        }
   1.103 +
   1.104 +        boolean ok = true;
   1.105 +        /* Original usage */
   1.106 +        if (args.length == 2 && args[0].charAt(0) != '-' ) {
   1.107 +            ok = createFile(args[0], args[1], "ListResourceBundle");
   1.108 +        } else if (args.length == 3) {
   1.109 +            ok = createFile(args[0], args[1], args[2]);
   1.110 +        } else if (args.length == 0) {
   1.111 +            usage(log);
   1.112 +            ok = false;
   1.113 +        } else {
   1.114 +            /* New batch usage */
   1.115 +            ok = parseOptions(args);
   1.116 +            if ( ok && compileCount == 0 ) {
   1.117 +                log.error("options parsed but no files to compile", null);
   1.118 +                ok = false;
   1.119 +            }
   1.120 +            /* Need at least one file. */
   1.121 +            if ( !ok ) {
   1.122 +                usage(log);
   1.123 +            } else {
   1.124 +                /* Process files */
   1.125 +                for ( int i = 0; i < compileCount && ok ; i++ ) {
   1.126 +                    ok = createFile(propfiles[i], outfiles[i], supers[i]);
   1.127 +                }
   1.128 +            }
   1.129 +        }
   1.130 +        return ok;
   1.131 +    }
   1.132 +
   1.133 +    private boolean parseOptions(String args[]) {
   1.134 +        boolean ok = true;
   1.135 +        if ( compileCount > 0 ) {
   1.136 +            String new_propfiles[] = new String[compileCount + args.length];
   1.137 +            String new_outfiles[]  = new String[compileCount + args.length];
   1.138 +            String new_supers[]    = new String[compileCount + args.length];
   1.139 +            System.arraycopy(propfiles, 0, new_propfiles, 0, compileCount);
   1.140 +            System.arraycopy(outfiles, 0, new_outfiles, 0, compileCount);
   1.141 +            System.arraycopy(supers, 0, new_supers, 0, compileCount);
   1.142 +            propfiles = new_propfiles;
   1.143 +            outfiles  = new_outfiles;
   1.144 +            supers    = new_supers;
   1.145 +        } else {
   1.146 +            propfiles = new String[args.length];
   1.147 +            outfiles  = new String[args.length];
   1.148 +            supers    = new String[args.length];
   1.149 +        }
   1.150 +
   1.151 +        for ( int i = 0; i < args.length ; i++ ) {
   1.152 +            if ( "-compile".equals(args[i]) && i+3 < args.length ) {
   1.153 +                propfiles[compileCount] = args[++i];
   1.154 +                outfiles[compileCount]  = args[++i];
   1.155 +                supers[compileCount]    = args[++i];
   1.156 +                compileCount++;
   1.157 +            } else if ( "-optionsfile".equals(args[i]) && i+1 < args.length ) {
   1.158 +                String filename = args[++i];
   1.159 +                FileInputStream finput = null;
   1.160 +                byte contents[] = null;
   1.161 +                try {
   1.162 +                    finput = new FileInputStream(filename);
   1.163 +                    int byteCount = finput.available();
   1.164 +                    if ( byteCount <= 0 ) {
   1.165 +                        log.error("The -optionsfile file is empty", null);
   1.166 +                        ok = false;
   1.167 +                    } else {
   1.168 +                        contents = new byte[byteCount];
   1.169 +                        int bytesRead = finput.read(contents);
   1.170 +                        if ( byteCount != bytesRead ) {
   1.171 +                            log.error("Cannot read all of -optionsfile file", null);
   1.172 +                            ok = false;
   1.173 +                        }
   1.174 +                    }
   1.175 +                } catch ( IOException e ) {
   1.176 +                    log.error("cannot open " + filename, e);
   1.177 +                    ok = false;
   1.178 +                }
   1.179 +                if ( finput != null ) {
   1.180 +                    try {
   1.181 +                        finput.close();
   1.182 +                    } catch ( IOException e ) {
   1.183 +                        ok = false;
   1.184 +                        log.error("cannot close " + filename, e);
   1.185 +                    }
   1.186 +                }
   1.187 +                if ( ok = true && contents != null ) {
   1.188 +                    String tokens[] = (new String(contents)).split("\\s+");
   1.189 +                    if ( tokens.length > 0 ) {
   1.190 +                        ok = parseOptions(tokens);
   1.191 +                    }
   1.192 +                }
   1.193 +                if ( !ok ) {
   1.194 +                    break;
   1.195 +                }
   1.196 +            } else if ( "-quiet".equals(args[i]) ) {
   1.197 +                quiet = true;
   1.198 +            } else {
   1.199 +                log.error("argument error", null);
   1.200 +                ok = false;
   1.201 +            }
   1.202 +        }
   1.203 +        return ok;
   1.204 +    }
   1.205 +
   1.206 +    private boolean createFile(String propertiesPath, String outputPath,
   1.207 +            String superClass) {
   1.208 +        boolean ok = true;
   1.209 +        log.verbose("parsing: " + propertiesPath);
   1.210 +        Properties p = new Properties();
   1.211 +        try {
   1.212 +            p.load(new FileInputStream(propertiesPath));
   1.213 +        } catch ( FileNotFoundException e ) {
   1.214 +            ok = false;
   1.215 +            log.error("Cannot find file " + propertiesPath, e);
   1.216 +        } catch ( IOException e ) {
   1.217 +            ok = false;
   1.218 +            log.error("IO error on file " + propertiesPath, e);
   1.219 +        }
   1.220 +        if ( ok ) {
   1.221 +            String packageName = inferPackageName(propertiesPath, outputPath);
   1.222 +            log.verbose("inferred package name: " + packageName);
   1.223 +            List<String> sortedKeys = new ArrayList<String>();
   1.224 +            for ( Object key : p.keySet() ) {
   1.225 +                sortedKeys.add((String)key);
   1.226 +            }
   1.227 +            Collections.sort(sortedKeys);
   1.228 +            Iterator keys = sortedKeys.iterator();
   1.229 +
   1.230 +            StringBuffer data = new StringBuffer();
   1.231 +
   1.232 +            while (keys.hasNext()) {
   1.233 +                Object key = keys.next();
   1.234 +                data.append("            { \"" + escape((String)key) + "\", \"" +
   1.235 +                        escape((String)p.get(key)) + "\" },\n");
   1.236 +            }
   1.237 +
   1.238 +            // Get class name from java filename, not the properties filename.
   1.239 +            //   (zh_TW properties might be used to create zh_HK files)
   1.240 +            File file = new File(outputPath);
   1.241 +            String name = file.getName();
   1.242 +            int dotIndex = name.lastIndexOf('.');
   1.243 +            String className;
   1.244 +            if (dotIndex == -1) {
   1.245 +                className = name;
   1.246 +            } else {
   1.247 +                className = name.substring(0, dotIndex);
   1.248 +            }
   1.249 +
   1.250 +            String packageString = "";
   1.251 +            if (packageName != null && !packageName.equals("")) {
   1.252 +                packageString = "package " + packageName + ";\n\n";
   1.253 +            }
   1.254 +
   1.255 +            Writer writer = null;
   1.256 +            try {
   1.257 +                writer = new BufferedWriter(
   1.258 +                        new OutputStreamWriter(new FileOutputStream(outputPath), "8859_1"));
   1.259 +                MessageFormat format = new MessageFormat(FORMAT);
   1.260 +                writer.write(format.format(new Object[] { packageString, className, superClass, data }));
   1.261 +            } catch ( IOException e ) {
   1.262 +                ok = false;
   1.263 +                log.error("IO error writing to file " + outputPath, e);
   1.264 +            }
   1.265 +            if ( writer != null ) {
   1.266 +                try {
   1.267 +                    writer.flush();
   1.268 +                } catch ( IOException e ) {
   1.269 +                    ok = false;
   1.270 +                    log.error("IO error flush " + outputPath, e);
   1.271 +                }
   1.272 +                try {
   1.273 +                    writer.close();
   1.274 +                } catch ( IOException e ) {
   1.275 +                    ok = false;
   1.276 +                    log.error("IO error close " + outputPath, e);
   1.277 +                }
   1.278 +            }
   1.279 +            log.verbose("wrote: " + outputPath);
   1.280 +        }
   1.281 +        return ok;
   1.282 +    }
   1.283 +
   1.284 +    private static void usage(Log log) {
   1.285 +        log.info("usage:");
   1.286 +        log.info("    java CompileProperties path_to_properties_file path_to_java_output_file [super_class]");
   1.287 +        log.info("      -OR-");
   1.288 +        log.info("    java CompileProperties {-compile path_to_properties_file path_to_java_output_file super_class} -or- -optionsfile filename");
   1.289 +        log.info("");
   1.290 +        log.info("Example:");
   1.291 +        log.info("    java CompileProperties -compile test.properties test.java ListResourceBundle");
   1.292 +        log.info("    java CompileProperties -optionsfile option_file");
   1.293 +        log.info("option_file contains: -compile test.properties test.java ListResourceBundle");
   1.294 +    }
   1.295 +
   1.296 +    private static String escape(String theString) {
   1.297 +        // This is taken from Properties.saveConvert with changes for Java strings
   1.298 +        int len = theString.length();
   1.299 +        StringBuffer outBuffer = new StringBuffer(len*2);
   1.300 +
   1.301 +        for(int x=0; x<len; x++) {
   1.302 +            char aChar = theString.charAt(x);
   1.303 +            switch(aChar) {
   1.304 +                case '\\':outBuffer.append('\\'); outBuffer.append('\\');
   1.305 +                break;
   1.306 +                case '\t':outBuffer.append('\\'); outBuffer.append('t');
   1.307 +                break;
   1.308 +                case '\n':outBuffer.append('\\'); outBuffer.append('n');
   1.309 +                break;
   1.310 +                case '\r':outBuffer.append('\\'); outBuffer.append('r');
   1.311 +                break;
   1.312 +                case '\f':outBuffer.append('\\'); outBuffer.append('f');
   1.313 +                break;
   1.314 +                default:
   1.315 +                    if ((aChar < 0x0020) || (aChar > 0x007e)) {
   1.316 +                        outBuffer.append('\\');
   1.317 +                        outBuffer.append('u');
   1.318 +                        outBuffer.append(toHex((aChar >> 12) & 0xF));
   1.319 +                        outBuffer.append(toHex((aChar >>  8) & 0xF));
   1.320 +                        outBuffer.append(toHex((aChar >>  4) & 0xF));
   1.321 +                        outBuffer.append(toHex( aChar        & 0xF));
   1.322 +                    } else {
   1.323 +                        if (specialSaveChars.indexOf(aChar) != -1) {
   1.324 +                            outBuffer.append('\\');
   1.325 +                        }
   1.326 +                        outBuffer.append(aChar);
   1.327 +                    }
   1.328 +            }
   1.329 +        }
   1.330 +        return outBuffer.toString();
   1.331 +    }
   1.332 +
   1.333 +    private static String inferPackageName(String inputPath, String outputPath) {
   1.334 +        // Normalize file names
   1.335 +        inputPath  = new File(inputPath).getPath();
   1.336 +        outputPath = new File(outputPath).getPath();
   1.337 +        // Split into components
   1.338 +        String sep;
   1.339 +        if (File.separatorChar == '\\') {
   1.340 +            sep = "\\\\";
   1.341 +        } else {
   1.342 +            sep = File.separator;
   1.343 +        }
   1.344 +        String[] inputs  = inputPath.split(sep);
   1.345 +        String[] outputs = outputPath.split(sep);
   1.346 +        // Match common names, eliminating first "classes" entry from
   1.347 +        // each if present
   1.348 +        int inStart  = 0;
   1.349 +        int inEnd    = inputs.length - 2;
   1.350 +        int outEnd   = outputs.length - 2;
   1.351 +        int i = inEnd;
   1.352 +        int j = outEnd;
   1.353 +        while (i >= 0 && j >= 0) {
   1.354 +            if (!inputs[i].equals(outputs[j]) ||
   1.355 +                    (inputs[i].equals("gensrc") && inputs[j].equals("gensrc"))) {
   1.356 +                ++i;
   1.357 +                ++j;
   1.358 +                break;
   1.359 +            }
   1.360 +            --i;
   1.361 +            --j;
   1.362 +        }
   1.363 +        String result;
   1.364 +        if (i < 0 || j < 0 || i >= inEnd || j >= outEnd) {
   1.365 +            result = "";
   1.366 +        } else {
   1.367 +            if (inputs[i].equals("classes") && outputs[j].equals("classes")) {
   1.368 +                ++i;
   1.369 +            }
   1.370 +            inStart = i;
   1.371 +            StringBuffer buf = new StringBuffer();
   1.372 +            for (i = inStart; i <= inEnd; i++) {
   1.373 +                buf.append(inputs[i]);
   1.374 +                if (i < inEnd) {
   1.375 +                    buf.append('.');
   1.376 +                }
   1.377 +            }
   1.378 +            result = buf.toString();
   1.379 +        }
   1.380 +        return result;
   1.381 +    }
   1.382 +
   1.383 +    private static final String FORMAT =
   1.384 +            "{0}" +
   1.385 +            "import java.util.ListResourceBundle;\n\n" +
   1.386 +            "public final class {1} extends {2} '{'\n" +
   1.387 +            "    protected final Object[][] getContents() '{'\n" +
   1.388 +            "        return new Object[][] '{'\n" +
   1.389 +            "{3}" +
   1.390 +            "        };\n" +
   1.391 +            "    }\n" +
   1.392 +            "}\n";
   1.393 +
   1.394 +    // This comes from Properties
   1.395 +    private static char toHex(int nibble) {
   1.396 +        return hexDigit[(nibble & 0xF)];
   1.397 +    }
   1.398 +
   1.399 +    // This comes from Properties
   1.400 +    private static final char[] hexDigit = {
   1.401 +        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
   1.402 +    };
   1.403 +
   1.404 +    // Note: different from that in Properties
   1.405 +    private static final String specialSaveChars = "\"";
   1.406 +}

mercurial