blob: 3294237e6e355635f611eeeefc200d3e44e48641 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.trinidadbuild.plugin.i18n.uixtools;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Enumeration;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Generates JavaScript libraries containing the Locale information from
* Java.
* @version $Name: $ ($Revision: 1.3 $) $Date: 2004/03/25 22:36:42 $
*/
public class JSLocaleElementsGenerator
{
public static void main(String[] args)
{
if ((args.length == 1) && ("?".equals(args[0])))
{
System.out.println("Generates JavaScript Locale information files");
System.out.println("for the Locales available in the JVM.");
System.out.println("These files are used by the Cabo HTML client");
System.out.println("logic to handle date formatting and validation.");
System.out.println();
System.out.println("Parameters:");
System.out.println("\tprettyPrint=false\tTurns off pretty printed output");
System.out.println("\toutDir=[path]\t\tDirectory path to write JavaScript files to");
System.out.println("\tsourceDir=[path]\t\tRoot directory path to write Java source to");
System.out.println("\tbundleOutDir=[path]\t\tRoot directory path to write Java ResourceBundles to (defaults to sourceDir).");
System.out.println("\tvariant=[variant name]\t\tIf supplied utility will generate ResourceBundles for this variant, and nothing else.");
System.out.println("\tverbose=true\t\tTurns on verbose output");
System.out.println("\tgenerateBundleBaseOnly=true\t\tGenerates the base LocaleElement.java file only");
System.exit(0);
}
// whether the output should be pretty printed for legibility
boolean prettyPrint = getArgBooleanValue(args, "prettyPrint", true);
// whether verbose ouput should be generated.
boolean verbose = getArgBooleanValue(args, "verbose", false);
boolean writeSource = getArgBooleanValue(args, "writeSource", true);
boolean writeJavascript = getArgBooleanValue(args, "writeJavascript", true);
// whether only the Base LocaleElements.java file should be created.
// this is based on the Locale.US
boolean generateBundleBaseOnly = getArgBooleanValue(args,"generateBundleBaseOnly",false);
// the output directory
String outDir = getArgStringValue(args, "outDir", null);
if (outDir == null)
{
outDir = System.getProperty("user.dir") +
File.separator +
_DEFAULT_LOCATION_PATH;
}
if (!outDir.endsWith(File.separator))
{
outDir = outDir + File.separator;
}
// the requested variant
String variant = getArgStringValue(args, "variant", null);
boolean writeAll = true;
if (variant != null)
{
writeAll = false;
variant = variant.toUpperCase();
}
// the source directory
String sourceDir = getArgStringValue(args, "sourceDir", null);
if (sourceDir == null)
{
sourceDir = System.getProperty("user.dir");
}
String bundleOutDir = getArgStringValue(args, "bundleOutDir", null);
if (bundleOutDir == null)
bundleOutDir = sourceDir;
// The bundle output dir is the base of the heirarchy, we'll actually put
// the files into the appropriate sub directory for the package.
String fullBundleOutDir = (bundleOutDir
+ (bundleOutDir.endsWith(File.separator)
? ""
: File.separator)
+ _DEFAULT_BUNDLE_LOCATION_PATH);
String version = getArgStringValue(args, "version", null);
version = VersionUtils.normalizeVersionSuffix(version);
if (verbose)
{
System.out.println("Writing files to: " + outDir);
if (writeAll)
{
System.out.println("Writing source to: " + sourceDir);
}
System.out.println("Writing bundles to: " + fullBundleOutDir);
}
try
{
File localeListFile = null;
if (writeSource)
(new File(fullBundleOutDir)).mkdirs();
if (writeJavascript)
(new File(outDir)).mkdirs();
if (writeAll && writeSource && !generateBundleBaseOnly)
{
localeListFile = new File(sourceDir, _LOCALE_LIST_PATH);
localeListFile.getParentFile().mkdirs();
localeListFile.createNewFile();
}
Locale[] locales = null;
if (generateBundleBaseOnly)
{
locales = new Locale[1];
locales[0] = Locale.US;
}
else
{
locales = Locale.getAvailableLocales();
}
//
// loop through the available Locales, writing their contents out
// as JavaScript libraries and/or ResourceBundles
//
for (int i = 0; i < locales.length; i++)
{
// write the JavaSCript library for this locale
_generateJSLocaleElements(outDir, fullBundleOutDir, locales[i],
variant, prettyPrint, verbose,
writeJavascript, writeSource, generateBundleBaseOnly, version);
}
// And write out a listing of all the locales, but not when we want to
// just generate the base Resource file.
if (writeAll && writeSource && !generateBundleBaseOnly)
{
Writer sourceWriter = new FileWriter(localeListFile);
sourceWriter.write(_LOCALE_LIST_CODE_START);
for (int i = 0; i < locales.length; i++)
{
sourceWriter.write(" new Locale(\"");
sourceWriter.write(locales[i].getLanguage());
sourceWriter.write("\",\"");
sourceWriter.write(locales[i].getCountry());
sourceWriter.write("\",\"");
sourceWriter.write(locales[i].getVariant());
sourceWriter.write("\"),\n");
}
sourceWriter.write(_LOCALE_LIST_CODE_END);
sourceWriter.close();
}
}
catch (IOException e)
{
System.err.println(e);
e.printStackTrace();
}
if (verbose)
{
System.out.println("Done writing files");
}
}
private static String getArgStringValue(
String[] args,
String argName,
String defaultValue
)
{
int argLength = argName.length();
for (int i = 0; i < args.length; i++)
{
String currArg = args[i];
if (currArg.startsWith(argName))
{
if (!currArg.equals(argName) &&
('=' == currArg.charAt(argLength)))
{
return currArg.substring(argLength + 1);
}
}
}
return defaultValue;
}
private static boolean getArgBooleanValue(
String[] args,
String argName,
boolean defaultValue
)
{
//
// check for = true or = false
//
String argValue = getArgStringValue(args, argName, null);
if (argValue != null)
{
// check for = self
if (argName.equals(argValue))
{
return true;
}
else
{
return Boolean.valueOf(argValue).booleanValue();
}
}
//
// check for the name by itself
//
for (int i = 0; i < args.length; i++)
{
if (args[i].equals(argName))
{
return true;
}
}
//
// check for the name turned off
//
String notName = "-" + argName;
for (int i = 0; i < args.length; i++)
{
if (args[i].equals(notName))
{
return false;
}
}
return defaultValue;
}
private static void _generateJSLocaleElements(
String outDir,
String bundleOutDir,
Locale targetLocale,
String variant,
boolean prettyPrint,
boolean verbose,
boolean writeJavascript,
boolean writeSource,
boolean generateBundleBaseOnly,
String version
) throws IOException
{
String fileName;
PrintWriter localeWriter;
if (variant == null && writeJavascript)
{
fileName = _getFileName(targetLocale, version, generateBundleBaseOnly) + _JAVASCRIPT_EXTENSION;
if (verbose)
{
System.out.println("Writing " + fileName);
}
// create the file to write to
localeWriter = new PrintWriter
(new BufferedWriter(new FileWriter(outDir + fileName),
_DEFAULT_BUFFER_SIZE));
_writeLocale(localeWriter, targetLocale, prettyPrint);
localeWriter.close();
}
}
private static void _writeJavaBundle(
Writer output,
Locale targetLocale,
String fileName
) throws IOException
{
output.write(_LOCALE_JAVA_CODE_START);
output.write("public class "
+ fileName
+ " extends ListResourceBundle\n{\n"
+ " public Object[][] getContents()\n {\n"
+ " return contents;\n }\n\n");
try
{
ResourceBundle elementsData =
ResourceBundle.getBundle(_LOCALE_ELEMENTS_PATH, targetLocale);
boolean doneOne = false;
for (int i = 0; i < LOCALE_ELEMENTS_GET_KEYS.length; i ++)
{
String currKey = LOCALE_ELEMENTS_GET_KEYS[i];
Object data = _getElementData(currKey, elementsData, targetLocale);
_writeJavaBundleElement(output, currKey, data, doneOne);
doneOne = true;
}
doneOne = false;
output.write(" static final Object[][] contents = \n {\n");
for (int i = 0; i < LOCALE_ELEMENTS_GET_KEYS.length; i ++)
{
String currKey = LOCALE_ELEMENTS_GET_KEYS[i];
output.write((doneOne ? ",\n" : "")
+ " { \""
+ currKey
+ "\", "
+ _getKeyArrayName(currKey)
+ "}");
doneOne = true;
}
output.write("\n };");
}
catch (MissingResourceException e)
{
// make sure that the class will, at least, compile even if incomplete.
output.write(" // Bundle generation error:\n // " + e);
output.write("\n static final Object[][] contents = null;");
System.err.println(e);
}
output.write("\n}\n");
}
private static void _writeLocale(
Writer output,
Locale targetLocale,
boolean prettyPrint
) throws IOException
{
output.write("var LocaleSymbols_");
output.write(targetLocale.toString());
output.write(" = new LocaleSymbols({");
if (prettyPrint)
output.write('\n');
// write the locale elements into the file
_writeResourceContents(output,
_LOCALE_ELEMENTS_PATH,
new ArrayEnumeration(LOCALE_ELEMENTS_GET_KEYS),
targetLocale,
prettyPrint);
output.write("});");
if (prettyPrint)
output.write('\n');
}
private static void _writeResourceContents(
Writer output,
String baseName,
Enumeration keys,
Locale targetLocale,
boolean prettyPrint
) throws IOException
{
try
{
while(keys.hasMoreElements())
{
String currKey = (String)keys.nextElement();
Object data = null;
if ("CurrencyElements".equals(currKey))
data = _getCurrencyData(targetLocale);
else if ("PercentElements".equals(currKey))
data = _getPercentData(targetLocale);
else
data = LocaleDataResolver.getElementData(currKey, targetLocale);
boolean wroteElement = _writeResourceElement(
output,
currKey,
data,
keys.hasMoreElements(),
prettyPrint);
if (wroteElement && prettyPrint)
{
output.write('\n');
}
}
}
catch (MissingResourceException e)
{
System.err.println(e);
}
}
private static Object _getCurrencyData(
Locale targetLocale)
{
DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(targetLocale);
DecimalFormatSymbols decimalFormatSymbols = df.getDecimalFormatSymbols();
Object[] currencyData = new Object[6];
currencyData[0] = decimalFormatSymbols.getCurrencySymbol();
currencyData[1] = decimalFormatSymbols.getCurrency().getCurrencyCode();
currencyData[2] = df.getPositivePrefix();
currencyData[3] = df.getPositiveSuffix();
currencyData[4] = df.getNegativePrefix();
currencyData[5] = df.getNegativeSuffix();
return currencyData;
}
private static Object _getPercentData(
Locale targetLocale)
{
DecimalFormat df = (DecimalFormat)NumberFormat.getPercentInstance(targetLocale);
Object[] percentData = new Object[2];
percentData[0] = df.getPositiveSuffix();
percentData[1] = df.getNegativeSuffix();
//percentData[2] = df.getPositivePrefix();
//percentData[3] = df.getNegativePrefix();
return percentData;
}
private static Object _getElementData(
String currKey,
ResourceBundle elementsData,
Locale targetLocale
)
{
return elementsData.getObject(currKey);
}
private static boolean _writeResourceElement(
Writer output,
String key,
Object value,
boolean notLast,
boolean prettyPrint
) throws IOException
{
if (key != null)
{
// start writing element, using key as the property name
output.write(key);
output.write(':');
}
Object[] values = null;
int valueCount = 0;
if (value instanceof Object[])
{
values = (Object[])value;
valueCount = values.length;
if (valueCount == 0)
{
value = "";
}
}
if (valueCount != 0)
{
// output.write("new Array(");
output.write('[');
for (int i = 0; i < valueCount; i++)
{
_writeResourceElement(output,
null,
values[i],
i < valueCount - 1,
prettyPrint);
}
//output.write(')');
output.write(']');
}
else
{
output.write('\"');
_writeEscapedString(output, value.toString(), false);
output.write('\"');
}
if (notLast)
{
output.write(',');
if (prettyPrint)
{
output.write(' ');
}
}
// we wrote some ouput
return true;
}
private static void _writeJavaBundleElement(
Writer output,
String key,
Object value,
boolean wasPrevious
) throws IOException
{
output.write(" private static final String "
+ _getKeyArrayName(key)
+ "[]");
Object[] values = null;
int valueCount = 0;
boolean doneOne = false;
if (value instanceof Object[])
{
values = (Object[]) value;
valueCount = values.length;
if (valueCount <= 0)
{
values = _EMPTY_VALUES;
valueCount = 1;
}
}
if (valueCount > 0)
{
output.write(" = \n {\n");
for (int i = 0; i < valueCount; i++)
{
output.write((doneOne ? ", \n" : "") + " \"");
_writeEscapedString(output, values[i].toString(), true);
output.write("\"");
doneOne = true;
}
output.write("\n };\n\n");
}
else
output.write(" = null");
}
private static void _writeEscapedString(
Writer output,
String value,
boolean isJava
) throws IOException
{
int length = value.length();
for (int i = 0; i < length; i++)
{
char currChar = value.charAt(i);
if (currChar > 255)
{
output.write("\\u");
output.write(_getHexString(currChar, 4));
}
else
{
if (isJava)
{
if ((currChar > 31)
&& (currChar < 128))
{
if (currChar == '\"')
output.write("\\\"");
else
output.write(currChar);
}
else
{
output.write("\\u");
output.write(_getHexString(currChar, 4));
}
}
else
{
// write ascii printable characters, except for the double quote,
// which needs to be escaped because we are already in a String.
if ((currChar > 31) &&
(currChar < 128) &&
(currChar != '\"') &&
(currChar != '\''))
{
output.write(currChar);
}
else
{
output.write("\\x");
output.write(_getHexString(currChar, 2));
}
}
}
}
}
private static String _getHexString(
int number,
int minDigits
)
{
String hexString = Integer.toHexString(number);
int hexLength = hexString.length();
int zeroPadding = minDigits - hexLength;
if (zeroPadding > 0)
{
String paddedString = "0";
while (zeroPadding > 1)
{
paddedString += "0";
zeroPadding--;
}
hexString = paddedString + hexString;
}
else
{
if (zeroPadding < 0)
{
throw new IllegalArgumentException();
}
}
return hexString;
}
private static String _getKeyArrayName(String key)
{
return "_array" + key;
}
private static String _getFileName(
Locale locale,
String version,
boolean generateBundleBaseOnly
)
{
if (generateBundleBaseOnly)
{
return "LocaleElements";
}
if (version == null)
return "LocaleElements_" + locale;
return "LocaleElements_" + locale + version;
}
private static String _getLocaleSuffix(
Locale locale
)
{
String localeString = locale.toString();
return localeString.substring(localeString.indexOf('_'));
}
//
// Array of DateFormatZoneData key names to retrieve.
// Only keys from this list are used to generate locale information
//
private static final String[] LOCALE_ELEMENTS_GET_KEYS =
{
"MonthNames",
"MonthAbbreviations",
"DayNames",
"DayAbbreviations",
"AmPmMarkers",
"Eras",
"DateTimePatterns",
"DateTimeElements",
"NumberElements",
"CurrencyElements",
"PercentElements"
};
//
// Array of DateFormatZoneData key names to retrieve.
// Only keys from this list are used to generate locale information
//
private static final String[] LOCALE_ELEMENTS_MAPPINGS =
{
"MonthNames", "getMonths",
"MonthAbbreviations", "getShortMonths",
"DayNames", "getWeekdays",
"DayAbbreviations", "getShortWeekdays",
"AmPmMarkers", "getAmPmStrings",
"Eras", "getEras",
"DateTimePatterns", null,
"DateTimeElements", null,
"NumberElements", null
};
//
// Array of LocaleElements key names to retrieve.
// Only keys from this list are used to generate locale information
//
private static final String[] DATE_FORMAT_ZONE_GET_KEYS = {};
// J2SE 1.3:
// private static String _RESOURCES_PACKAGE = "java.text.resources";
// J2SE 1.4:
private static String _RESOURCES_PACKAGE = "sun.text.resources";
private static final String _DATE_FORMAT_ZONE_PATH =
_RESOURCES_PACKAGE + ".DateFormatZoneData";
private static final String _LOCALE_ELEMENTS_PATH =
_RESOURCES_PACKAGE + ".LocaleElements";
private static final String _DEFAULT_LOCATION_PATH =
"org\\apache\\myfaces\\trinidadinternal\\ui\\jsLibs\\resources\\".replace('\\',
File.separatorChar);
// Mimicking to be in api path. In the trinidad-faces impl side we have
// the following directory structure. There is identical directory sturcture
// in trinidad-faces api side.
// Only _TRINIDAD_LOCALE_ELEMENT base file will be added to the api side,
// while all the variants will be in impl side in the directory structure
// defined below.
private static final String _TRINIDAD_LOCALE_ELEMENTS_PACKAGE =
"org.apache.myfaces.trinidad.resource";
public static final String _DEFAULT_BUNDLE_LOCATION_PATH =
(_TRINIDAD_LOCALE_ELEMENTS_PACKAGE.replace('.', File.separatorChar)
+ File.separatorChar);
private static final String _TRINIDAD_LOCALE_ELEMENTS_PATH =
_TRINIDAD_LOCALE_ELEMENTS_PACKAGE + ".LocaleElements";
// buffer size of the BufferedWriter to which output is written
private static final int _DEFAULT_BUFFER_SIZE = 1 << 14;
private static final String _LOCALE_LIST_PATH =
"org\\apache\\myfaces\\trinidadinternal\\ui\\laf\\base\\xhtml\\LocaleList.java".replace('\\',
File.separatorChar);
private static final String _EMPTY_VALUES[] = { "" };
private static final String _LOCALE_LIST_CODE_START =
"/*\n" +
"**\n" +
"**34567890123456789012345678901234567890123456789012345678901234567890123456789\n" +
"*/\n" +
"package org.apache.myfaces.trinidadinternal.ui.laf.base.xhtml;\n" +
"\n" +
"import java.util.Locale;\n" +
"\n" +
"import java.util.HashMap;\n" +
"\n" +
"/*\n" +
" * List of supported locales. Automatically generated - do not modify!\n" +
" */\n" +
"public class LocaleList\n" +
"{\n" +
" /*\n" +
" * Returns the list of supported locales.\n" +
" */\n" +
" static public HashMap<Locale, Locale> getSupportedLocales()\n" +
" {\n" +
" return _sLocaleMapper;\n" +
" }\n" +
" \n" +
" private LocaleList()\n" +
" {\n" +
" }\n" +
"\n" +
" static private final Locale[] _sLocales = new Locale[]\n" +
" {\n";
private static final String _LOCALE_LIST_CODE_END =
" };\n" +
"\n" +
" static private HashMap<Locale, Locale> _sLocaleMapper;\n" +
"\n" +
" static\n" +
" {\n" +
" _sLocaleMapper = new HashMap<Locale, Locale>();\n" +
" for(Locale locale : _sLocales)\n" +
" {\n" +
" _sLocaleMapper.put(locale, locale);\n" +
" }\n" +
" }\n" +
"}\n";
private static final String _LOCALE_JAVA_CODE_START =
"// Do not edit this file!\n"
+ "// This file has been automatically generated.\n"
+ "// Edit JSLocaleElementsGenerator instead.\n//\n"
+ "package "
+ _TRINIDAD_LOCALE_ELEMENTS_PACKAGE
+ ";\n\n"
+ "import java.util.ListResourceBundle;\n";
private static final String _JAVASCRIPT_EXTENSION = ".js";
private static final String _JAVA_EXTENSION = ".java";
//Introduced to remove the dependency on bali-share in the api side.
private static class ArrayEnumeration implements Enumeration
{
public ArrayEnumeration(Object[] array)
{
_objects = (array == null)? _EMPTY_ARRAY : array;
}
public boolean hasMoreElements()
{
return _currentIndex < _objects.length;
}
public Object nextElement()
{
return _objects[_currentIndex++];
}
private Object[] _objects;
private int _currentIndex;
private static final Object[] _EMPTY_ARRAY = new Object[0];
}
}