| /* |
| * Copyright 2008 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.i18n.tools; |
| |
| import com.google.gwt.i18n.client.Constants; |
| import com.google.gwt.i18n.client.ConstantsWithLookup; |
| import com.google.gwt.i18n.client.Localizable; |
| import com.google.gwt.i18n.client.Messages; |
| import com.google.gwt.i18n.rebind.AbstractLocalizableInterfaceCreator; |
| import com.google.gwt.i18n.rebind.ConstantsInterfaceCreator; |
| import com.google.gwt.i18n.rebind.MessagesInterfaceCreator; |
| import com.google.gwt.util.tools.ArgHandlerExtra; |
| import com.google.gwt.util.tools.ArgHandlerString; |
| import com.google.gwt.util.tools.ToolBase; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| |
| /** |
| * Common public access point for localization support methods. |
| */ |
| public class I18NSync extends ToolBase { |
| |
| private class classNameArgHandler extends ArgHandlerExtra { |
| |
| @Override |
| public boolean addExtraArg(String str) { |
| if (classNameArg != null) { |
| System.err.println("Too many arguments."); |
| return false; |
| } |
| // We wish to use the same sets of checks for validity whether the user |
| // calls the static method to create localizable fields or uses the |
| // command line, as the java call must throw IOException, here we must |
| // catch it and convert it to a System.err message. |
| try { |
| File resourceFile = urlToResourceFile(str); |
| checkValidResourceInputFile(resourceFile); |
| classNameArg = str; |
| } catch (IOException e) { |
| System.err.println("Error: " + e.getMessage()); |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public String getPurpose() { |
| return "Identifies the Constants/Messages class to be created. For example com.google.sample.i18n.client.Colors"; |
| } |
| |
| @Override |
| public String[] getTagArgs() { |
| String[] interfaceArg = {"name of the Constants/Messages interface to create"}; |
| return interfaceArg; |
| } |
| |
| @Override |
| public boolean isRequired() { |
| return true; |
| } |
| } |
| |
| private class outDirHandler extends ArgHandlerString { |
| @Override |
| public String getPurpose() { |
| return "Java source directory, defaults to the resource's class path."; |
| } |
| |
| @Override |
| public String getTag() { |
| return "-out"; |
| } |
| |
| @Override |
| public String[] getTagArgs() { |
| String[] resourceArgs = {"fileName"}; |
| return resourceArgs; |
| } |
| |
| @Override |
| public boolean isRequired() { |
| return false; |
| } |
| |
| @Override |
| public boolean setString(String str) { |
| |
| // We wish to use the same sets of checks for validity whether the user |
| // calls the static method to create localizable classes or uses the |
| // command line, as the java call must throw IOException, here we must |
| // catch it and convert it to a System.err message. |
| outDirArg = new File(str); |
| try { |
| checkValidSourceDir(outDirArg); |
| } catch (IOException e) { |
| System.err.println("Error: " + e.getMessage()); |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| /** |
| * Creates a <code>Constants</code> interface from a class name. The |
| * resource file needed to create the class must be on your class path. |
| * |
| * @param className the name of the Constants class to be created |
| * @param outDir source dir root |
| * @throws IOException |
| */ |
| public static void createConstantsInterfaceFromClassName(String className, |
| File outDir) throws IOException { |
| createConstantsInterfaceFromClassName(className, outDir, Constants.class); |
| } |
| |
| /** |
| * Creates a <code>ConstantsWithLookup</code> interface from a class name. |
| * The resource file needed to create the class must be on your class path. |
| * |
| * @param className the name of the Constants class to be created |
| * @throws IOException |
| */ |
| public static void createConstantsWithLookupInterfaceFromClassName( |
| String className) throws IOException { |
| createConstantsInterfaceFromClassName(className, null, |
| ConstantsWithLookup.class); |
| } |
| |
| /** |
| * Creates a <code>ConstantsWithLookup</code> interface from a class name. |
| * The resource file needed to create the class must be on your class path. |
| * |
| * @param className the name of the Constants class to be created |
| * @param sourceDir source dir root |
| * @throws IOException |
| */ |
| public static void createConstantsWithLookupInterfaceFromClassName( |
| String className, File sourceDir) throws IOException { |
| createConstantsInterfaceFromClassName(className, sourceDir, |
| ConstantsWithLookup.class); |
| } |
| |
| /** |
| * Creates one of a Messages, ConstantsWithLookup, or Constants subclass. |
| * |
| * @param className Name of the subclass to be created |
| * @param sourceDir source directory root |
| * @param interfaceType What kind of base class to use |
| * @throws IOException |
| */ |
| public static void createInterfaceFromClassName(String className, |
| File sourceDir, Class<? extends Localizable> interfaceType) |
| throws IOException { |
| if (interfaceType == Messages.class) { |
| createMessagesInterfaceFromClassName(className, sourceDir); |
| } else { |
| if (!Constants.class.isAssignableFrom(interfaceType)) { |
| throw new RuntimeException( |
| "Internal Error: Unable to create i18n class derived from " + |
| interfaceType.getName()); |
| } |
| createConstantsInterfaceFromClassName(className, sourceDir, |
| interfaceType.asSubclass(Constants.class)); |
| } |
| } |
| |
| /** |
| * Creates a <code>Messages</code> interface from a class name. The resource |
| * file needed to create the class must be on your class path. |
| * |
| * @param className the name of the Constants class to be created |
| * @throws IOException |
| */ |
| public static void createMessagesInterfaceFromClassName(String className) |
| throws IOException { |
| createMessagesInterfaceFromClassName(className, null); |
| } |
| |
| /** |
| * Creates a <code>Messages</code> interface from a class name. The resource |
| * file needed to create the class must be on your class path. |
| * |
| * @param className the name of the Constants class to be created |
| * @param sourceDir source directory root |
| * @throws IOException |
| */ |
| public static void createMessagesInterfaceFromClassName(String className, |
| File sourceDir) throws IOException { |
| File resource = urlToResourceFile(className); |
| File source; |
| if (sourceDir == null) { |
| source = synthesizeSourceFile(resource); |
| } else { |
| checkValidSourceDir(sourceDir); |
| String sourcePath = className.replace('.', File.separatorChar); |
| sourcePath = sourceDir.getCanonicalFile() + File.separator + sourcePath |
| + ".java"; |
| source = new File(sourcePath); |
| } |
| // Need both source path and class name for this check |
| checkValidJavaSourceOutputFile(source); |
| checkValidResourceInputFile(resource); |
| |
| int classDiv = className.lastIndexOf("."); |
| String packageName = className.substring(0, classDiv); |
| String name = className.substring(classDiv + 1); |
| AbstractLocalizableInterfaceCreator creator = new MessagesInterfaceCreator( |
| name, packageName, resource, source); |
| creator.generate(); |
| } |
| |
| /** |
| * Creates Messages and Constants java source files. |
| * |
| * @param args arguments for generation |
| */ |
| public static void main(String[] args) { |
| I18NSync creator = new I18NSync(); |
| if (creator.processArgs(args)) { |
| if (creator.run()) { |
| return; |
| } |
| } |
| System.exit(1); |
| } |
| |
| static void checkValidJavaSourceOutputFile(File targetSource) |
| throws IOException { |
| |
| if (targetSource.isDirectory()) { |
| throw new IOException("Output file'" + targetSource |
| + "' exists and is a directory; cannot overwrite"); |
| } |
| if (targetSource.getParentFile().isDirectory() == false) { |
| throw new IOException("The target source's directory '" |
| + targetSource.getParent() + "' must be an existing directory"); |
| } |
| } |
| |
| static void checkValidResourceInputFile(File resource) throws IOException { |
| if (!resource.getPath().endsWith(".properties")) { |
| throw new IOException("Properties files " + resource |
| + " should end with '.properties'"); |
| } |
| if (!resource.exists() || !resource.isFile()) { |
| throw new IOException("Properties file not found: " + resource); |
| } |
| } |
| |
| private static void checkValidSourceDir(File outDir) throws IOException { |
| if (outDir.isDirectory() == false) { |
| throw new IOException(outDir |
| + " must be an existing directory. Current path is " |
| + new File(".").getCanonicalPath()); |
| } |
| } |
| |
| private static void createConstantsInterfaceFromClassName(String className, |
| File sourceDir, Class<? extends Constants> interfaceClass) |
| throws IOException { |
| File resource = urlToResourceFile(className); |
| File source; |
| if (sourceDir == null) { |
| source = synthesizeSourceFile(resource); |
| } else { |
| checkValidSourceDir(sourceDir); |
| String sourcePath = className.replace('.', File.separatorChar); |
| sourcePath = sourceDir.getCanonicalFile() + File.separator + sourcePath |
| + ".java"; |
| source = new File(sourcePath); |
| } |
| // Need both source path and class name for this check |
| checkValidJavaSourceOutputFile(source); |
| checkValidResourceInputFile(resource); |
| |
| int classDiv = className.lastIndexOf("."); |
| String packageName = className.substring(0, classDiv); |
| String name = className.substring(classDiv + 1); |
| AbstractLocalizableInterfaceCreator creator = new ConstantsInterfaceCreator( |
| name, packageName, resource, source, interfaceClass); |
| creator.generate(); |
| } |
| |
| private static File synthesizeSourceFile(File resource) { |
| String javaPath = resource.getName(); |
| javaPath = javaPath.substring(0, javaPath.lastIndexOf(".")); |
| javaPath = resource.getParentFile().getPath() + File.separator + javaPath |
| + ".java"; |
| File targetClassFile = new File(javaPath); |
| return targetClassFile; |
| } |
| |
| private static File urlToResourceFile(String className) |
| throws IOException { |
| if (className.endsWith(".java") || className.endsWith(".properties") |
| || className.endsWith(".class") |
| || className.indexOf(File.separator) > 0) { |
| throw new IllegalArgumentException( |
| "class '" |
| + className |
| + "'should not contain an extension. \"com.google.gwt.SomeClass\" is an example of a correctly formed class string"); |
| } |
| String resourcePath = className.replace('.', '/') + ".properties"; |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| if (cl == null) { |
| cl = ClassLoader.getSystemClassLoader(); |
| } |
| URL r = cl.getResource(resourcePath); |
| if (r == null) { |
| throw new FileNotFoundException("Could not find the resource '" |
| + resourcePath + " matching '" + className |
| + "' did you remember to add it to your classpath?"); |
| } |
| File resourceFile = new File(URLDecoder.decode(r.getPath(), "utf-8")); |
| return resourceFile; |
| } |
| |
| private ArgHandlerValueChooser chooser; |
| private String classNameArg; |
| private File outDirArg; |
| |
| private I18NSync() { |
| registerHandler(new classNameArgHandler()); |
| registerHandler(new outDirHandler()); |
| chooser = new ArgHandlerValueChooser(); |
| registerHandler(chooser.getConstantsWithLookupArgHandler()); |
| registerHandler(chooser.getMessagesArgHandler()); |
| } |
| |
| /** |
| * Creates the interface. |
| * |
| * @return whether the interface was created |
| */ |
| protected boolean run() { |
| try { |
| createInterfaceFromClassName(classNameArg, outDirArg, |
| chooser.getArgValue()); |
| return true; |
| } catch (Throwable e) { |
| System.err.println(e.getMessage()); |
| return false; |
| } |
| } |
| } |