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