blob: 3e18f44d91097e461e0115480f747fb296168f68 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed 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 com.google.gwt.tools.cldr;
import com.google.gwt.codegen.server.AbortablePrintWriter;
import com.google.gwt.codegen.server.JavaSourceWriterBuilder;
import com.google.gwt.codegen.server.LoggingCodeGenContext;
import com.google.gwt.i18n.shared.GwtLocale;
import org.unicode.cldr.util.CLDRFile;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Base class for CLDR processors that generate GWT i18n resources.
*/
public abstract class Processor {
/**
* A CodeGenContext implementation that logs to j.u.logging and creates
* output files using {@link Processor#createOutputFile(String, String)}.
*/
protected class ProcessorCodeGenContext extends LoggingCodeGenContext {
@Override
public JavaSourceWriterBuilder addClass(String superPkg, String pkgName, String className) {
String pkgPath = superPkg == null ? pkgName : superPkg + '/' + pkgName;
if (pkgPath.length() > 0) {
pkgPath = pkgPath.replace('.', '/') + '/';
}
String classPath = className.replace('.', '_');
String fileName = pkgPath + classPath + ".java";
try {
PrintWriter pw = createOutputFile("", fileName);
AbortablePrintWriter apw = new AbortablePrintWriter(pw);
printHeader(apw);
return new JavaSourceWriterBuilder(apw, pkgName, className);
} catch (FileNotFoundException e) {
error("Unable to create " + fileName, e);
return null;
} catch (IOException e) {
error("Unable to create " + fileName, e);
return null;
}
}
}
protected static final String I18N_PACKAGE_PATH = "user/src/com/google/gwt/i18n/";
protected static <T> String join(String joiner, Iterable<T> objects) {
StringBuilder buf = new StringBuilder();
for (Object obj : objects) {
if (buf.length() > 0) {
buf.append(joiner);
}
buf.append(obj.toString());
}
return buf.toString();
}
protected static String localeSuffix(GwtLocale locale) {
return (locale.isDefault() ? "" : "_") + locale.getAsString();
}
/**
* @param value
* @return value with all quotes escaped
*/
protected static String quote(String value) {
return value.replace("\"", "\\\"");
}
protected final InputFactory cldrFactory;
protected final LocaleData localeData;
protected final File outputDir;
private boolean useOverride;
/**
* Initialize the shared portion of a Processor.
*
* @param outputDir output directory for created files
* @param cldrFactory CLDR factory used to create new CLDRFile instances
* @param localeData LocaleData instance to collect data from CLDR files
*/
protected Processor(File outputDir, InputFactory cldrFactory, LocaleData localeData) {
this.outputDir = outputDir;
this.cldrFactory = cldrFactory;
this.localeData = localeData;
useOverride = true;
}
/**
* Execute this processor.
*
* It will call loadData, cleanupData, writeOutputFiles, and then reset on its
* localeData instance.
*
* @throws IOException
*/
public final void run() throws IOException {
try {
loadData();
cleanupData();
writeOutputFiles();
} finally {
localeData.reset();
}
}
/**
* Override hook for subclasses to implement any cleanup needed, such as
* removing values which duplicate those from ancestors.
*/
protected void cleanupData() {
// do nothing by default
}
protected PrintWriter createOutputFile(String suffix) throws IOException, FileNotFoundException {
return createOutputFile(I18N_PACKAGE_PATH, suffix);
}
protected PrintWriter createOutputFile(String prefix, String suffix) throws IOException,
FileNotFoundException {
PrintWriter pw;
File f = new File(outputDir, prefix + suffix);
File parent = f.getParentFile();
if (parent != null) {
parent.mkdirs();
}
f.createNewFile();
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f),
"UTF-8")), false);
return pw;
}
protected void generateIntMethod(PrintWriter pw, String category, GwtLocale locale, String key,
String method) {
String value = localeData.getEntry(category, locale, key);
if (value != null) {
pw.println();
if (useOverride) {
pw.println(" @Override");
}
pw.println(" public int " + method + "() {");
pw.println(" return " + value + ";");
pw.println(" }");
}
}
protected void generateStringMethod(PrintWriter pw, String category, GwtLocale locale,
String key, String method) {
String value = localeData.getEntry(category, locale, key);
generateStringValue(pw, method, value);
}
protected void generateStringValue(PrintWriter pw, String method, String value) {
if (value != null) {
pw.println();
if (useOverride) {
pw.println(" @Override");
}
pw.println(" public String " + method + "() {");
pw.println(" return \"" + quote(value) + "\";");
pw.println(" }");
}
}
/**
* @return true if generated methods should use @Override.
*/
protected boolean getOverrides() {
return useOverride;
}
/**
* Load data needed by this processor.
*
* @throws IOException
*/
protected abstract void loadData() throws IOException;
protected void printHeader(PrintWriter pw) {
printJavaHeader(pw);
}
protected void printJavaHeader(PrintWriter pw) {
int year = 2012;
pw.println("/*");
pw.println(" * Copyright " + year + " Google Inc.");
pw.println(" * ");
pw.println(" * Licensed under the Apache License, Version 2.0 (the "
+ "\"License\"); you may not");
pw.println(" * use this file except in compliance with the License. You "
+ "may obtain a copy of");
pw.println(" * the License at");
pw.println(" * ");
pw.println(" * http://www.apache.org/licenses/LICENSE-2.0");
pw.println(" * ");
pw.println(" * Unless required by applicable law or agreed to in writing, " + "software");
pw.println(" * distributed under the License is distributed on an \"AS "
+ "IS\" BASIS, WITHOUT");
pw.println(" * WARRANTIES OR CONDITIONS OF ANY KIND, either express or " + "implied. See the");
pw.println(" * License for the specific language governing permissions and "
+ "limitations under");
pw.println(" * the License.");
pw.println(" */");
}
protected void printPropertiesHeader(PrintWriter pw) {
int year = 2012;
pw.println("# Copyright " + year + " Google Inc.");
pw.println("# ");
pw.println("# Licensed under the Apache License, Version 2.0 (the "
+ "\"License\"); you may not");
pw.println("# use this file except in compliance with the License. You "
+ "may obtain a copy of");
pw.println("# the License at");
pw.println("# ");
pw.println("# http://www.apache.org/licenses/LICENSE-2.0");
pw.println("# ");
pw.println("# Unless required by applicable law or agreed to in writing, " + "software");
pw.println("# distributed under the License is distributed on an \"AS "
+ "IS\" BASIS, WITHOUT");
pw.println("# WARRANTIES OR CONDITIONS OF ANY KIND, either express or " + "implied. See the");
pw.println("# License for the specific language governing permissions and "
+ "limitations under");
pw.println("# the License.");
}
protected void printVersion(PrintWriter pw, GwtLocale locale, String prefix) {
pw.println(prefix + "DO NOT EDIT - GENERATED FROM CLDR DATA");
}
/**
* Writes a file containing CLDR version information.
* @param path the filename, relative to {@link #I18N_PACKAGE_PATH}.
*/
protected void writeVersionFile(String path, Set<GwtLocale> locales) throws IOException {
Map<String, GwtLocale> byName = new HashMap<String, GwtLocale>();
for (GwtLocale locale : locales) {
String name = locale.getAsString();
if (byName.containsKey(name)) {
throw new RuntimeException("more than one locale with name: " + name);
}
byName.put(name, locale);
}
List<String> names = new ArrayList<String>(byName.keySet());
Collections.sort(names);
PrintWriter out = createOutputFile(path);
out.println("cldrVersion=" + CLDRFile.GEN_VERSION);
out.println();
for (String name : names) {
Map<String, String> props = localeData.getEntries("version", byName.get(name));
List<String> keys = new ArrayList<String>(props.keySet());
Collections.sort(keys);
for (String key : keys) {
if (key.equals("date") || key.equals("type")) {
// The date comes from Subversion and depends on the local machine's timezone.
// Skip it to make the build deterministic.
// There is more than one "type" field and it's not obviously useful.
continue;
}
String value = props.get(key);
if (!name.isEmpty()) {
key = name + "." + key;
}
out.println(key + "=" + value);
}
}
out.close();
}
/**
* Set whether method definitions should use @Override.
*
* @param useOverride
*/
protected void setOverrides(boolean useOverride) {
this.useOverride = useOverride;
}
/**
* Write output files produced by this processor.
*
* @throws IOException
*/
protected abstract void writeOutputFiles() throws IOException;
}