001 /* 002 // $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaBaseGenerator.java#4 $ 003 // Package org.eigenbase.resgen is an i18n resource generator. 004 // Copyright (C) 2005-2005 The Eigenbase Project 005 // Copyright (C) 2005-2005 Disruptive Tech 006 // Copyright (C) 2005-2005 LucidEra, Inc. 007 // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. 008 // 009 // This library is free software; you can redistribute it and/or modify it 010 // under the terms of the GNU Lesser General Public License as published by the 011 // Free Software Foundation; either version 2 of the License, or (at your 012 // option) any later version approved by The Eigenbase Project. 013 // 014 // This library is distributed in the hope that it will be useful, 015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 // GNU Lesser General Public License for more details. 018 // 019 // You should have received a copy of the GNU Lesser General Public License 020 // along with this library; if not, write to the Free Software 021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 022 */ 023 package org.eigenbase.resgen; 024 025 import org.apache.tools.ant.BuildException; 026 027 import java.io.PrintWriter; 028 import java.io.File; 029 import java.lang.reflect.Constructor; 030 import java.util.HashSet; 031 import java.util.Set; 032 033 /** 034 * Generates a Java class for the base locale. 035 * 036 * @author jhyde 037 * @since 19 September, 2005 038 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaBaseGenerator.java#4 $ 039 */ 040 class JavaBaseGenerator extends AbstractJavaGenerator 041 { 042 protected final Set warnedClasses = new HashSet(); 043 044 JavaBaseGenerator( 045 File srcFile, 046 File file, 047 String className, 048 String baseClassName, 049 ResourceDef.ResourceBundle resourceBundle) 050 { 051 super(srcFile, file, className, resourceBundle, baseClassName); 052 } 053 054 public void generateModule( 055 ResourceGen generator, 056 ResourceDef.ResourceBundle resourceList, PrintWriter pw) 057 { 058 generateHeader(pw); 059 String className = getClassName(); 060 final String classNameSansPackage = Util.removePackage(className); 061 pw.print("public class " + classNameSansPackage); 062 final String baseClass = getBaseClassName(); 063 if (baseClass != null) { 064 pw.print(" extends " + baseClass); 065 } 066 pw.println(" {"); 067 pw.println(" public " + classNameSansPackage + "() throws IOException {"); 068 pw.println(" }"); 069 pw.println(" private static final String baseName = " + Util.quoteForJava(getClassName()) + ";"); 070 pw.println(" /**"); 071 pw.println(" * Retrieves the singleton instance of {@link " + classNameSansPackage + "}. If"); 072 pw.println(" * the application has called {@link #setThreadLocale}, returns the"); 073 pw.println(" * resource for the thread's locale."); 074 pw.println(" */"); 075 pw.println(" public static synchronized " + classNameSansPackage + " instance() {"); 076 pw.println(" return (" + classNameSansPackage + ") instance(baseName, getThreadOrDefaultLocale(), ResourceBundle.getBundle(baseName, getThreadOrDefaultLocale()));"); 077 pw.println(" }"); 078 pw.println(" /**"); 079 pw.println(" * Retrieves the instance of {@link " + classNameSansPackage + "} for the given locale."); 080 pw.println(" */"); 081 pw.println(" public static synchronized " + classNameSansPackage + " instance(Locale locale) {"); 082 pw.println(" return (" + classNameSansPackage + ") instance(baseName, locale, ResourceBundle.getBundle(baseName, locale));"); 083 pw.println(" }"); 084 if (resourceList.code != null) { 085 pw.println(" // begin of included code"); 086 pw.print(resourceList.code.cdata); 087 pw.println(" // end of included code"); 088 } 089 090 for (int j = 0; j < resourceList.resources.length; j++) { 091 ResourceDef.Resource resource = resourceList.resources[j]; 092 generateResource(resource, pw); 093 } 094 pw.println(""); 095 postModule(pw); 096 pw.println("}"); 097 } 098 099 protected void postModule(PrintWriter pw) 100 { 101 } 102 103 public void generateResource(ResourceDef.Resource resource, PrintWriter pw) 104 { 105 if (resource.text == null) { 106 throw new BuildException( 107 "Resource '" + resource.name + "' has no message"); 108 } 109 String text = resource.text.cdata; 110 String comment = ResourceGen.getComment(resource); 111 final String resourceInitcap = ResourceGen.getResourceInitcap(resource);// e.g. "Internal" 112 113 String definitionClass = "org.eigenbase.resgen.ResourceDefinition"; 114 String parameterList = getParameterList(text); 115 String argumentList = getArgumentList(text); // e.g. "p0, p1" 116 String argumentArray = argumentList.equals("") ? 117 "emptyObjectArray" : 118 "new Object[] {" + argumentList + "}"; // e.g. "new Object[] {p0, p1}" 119 120 pw.println(); 121 Util.generateCommentBlock(pw, resource.name, text, comment); 122 123 pw.println(" public static final " + definitionClass + " " + resourceInitcap + " = new " + definitionClass + "(\"" + resourceInitcap + "\", " + Util.quoteForJava(text) + ");"); 124 pw.println(" public String get" + resourceInitcap + "(" + parameterList + ") {"); 125 pw.println(" return " + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + ").toString();"); 126 pw.println(" }"); 127 if (resource instanceof ResourceDef.Exception) { 128 ResourceDef.Exception exception = (ResourceDef.Exception) resource; 129 String errorClassName = getErrorClass(exception); 130 final ExceptionDescription ed = new ExceptionDescription(errorClassName); 131 if (ed.hasInstCon) { 132 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); 133 pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "));"); 134 pw.println(" }"); 135 } else if (ed.hasInstThrowCon) { 136 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); 137 pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "), null);"); 138 pw.println(" }"); 139 } else if (ed.hasStringCon) { 140 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); 141 pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "));"); 142 pw.println(" }"); 143 } else if (ed.hasStringThrowCon) { 144 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); 145 pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "), null);"); 146 pw.println(" }"); 147 } 148 if (ed.hasInstThrowCon) { 149 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + addLists(parameterList, "Throwable err") + ") {"); 150 pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "), err);"); 151 pw.println(" }"); 152 } else if (ed.hasStringThrowCon) { 153 pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + addLists(parameterList, "Throwable err") + ") {"); 154 pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "), err);"); 155 pw.println(" }"); 156 } 157 } 158 } 159 160 /** 161 * Description of the constructs that an exception class has. 162 */ 163 class ExceptionDescription { 164 boolean hasInstCon; 165 boolean hasInstThrowCon; 166 boolean hasStringCon; 167 boolean hasStringThrowCon; 168 169 /** 170 * Figures out what constructors the exception class has. We'd 171 * prefer to use 172 * <code>init(ResourceDefinition rd)</code> or 173 * <code>init(ResourceDefinition rd, Throwable e)</code> 174 * if it has them, but we can use 175 * <code>init(String s)</code> and 176 * <code>init(String s, Throwable e)</code> 177 * as a fall-back. 178 * 179 * Prints a warming message if the class cannot be loaded. 180 * 181 * @param errorClassName Name of exception class 182 */ 183 ExceptionDescription(String errorClassName) 184 { 185 hasInstCon = false; 186 hasInstThrowCon = false; 187 hasStringCon = false; 188 hasStringThrowCon = false; 189 try { 190 Class errorClass; 191 try { 192 errorClass = Class.forName(errorClassName); 193 } catch (ClassNotFoundException e) { 194 // Might be in the java.lang package, for which we 195 // allow them to omit the package name. 196 errorClass = Class.forName("java.lang." + errorClassName); 197 } 198 Constructor[] constructors = errorClass.getConstructors(); 199 for (int i = 0; i < constructors.length; i++) { 200 Constructor constructor = constructors[i]; 201 Class[] types = constructor.getParameterTypes(); 202 if (types.length == 1 && 203 ResourceInstance.class.isAssignableFrom(types[0])) { 204 hasInstCon = true; 205 } 206 if (types.length == 1 && 207 String.class.isAssignableFrom(types[0])) { 208 hasStringCon = true; 209 } 210 if (types.length == 2 && 211 ResourceInstance.class.isAssignableFrom(types[0]) && 212 Throwable.class.isAssignableFrom(types[1])) { 213 hasInstThrowCon = true; 214 } 215 if (types.length == 2 && 216 String.class.isAssignableFrom(types[0]) && 217 Throwable.class.isAssignableFrom(types[1])) { 218 hasStringThrowCon = true; 219 } 220 } 221 } catch (ClassNotFoundException e) { 222 if (warnedClasses.add(errorClassName)) { 223 System.out.println("Warning: Could not find exception " + 224 "class '" + errorClassName + "' on classpath. " + 225 "Exception factory methods will not be generated."); 226 } 227 } 228 } 229 } 230 231 // helper 232 protected static String addLists(String x, String y) { 233 if (x == null || x.equals("")) { 234 if (y == null || y.equals("")) { 235 return ""; 236 } else { 237 return y; 238 } 239 } else if (y == null || y.equals("")) { 240 return x; 241 } else { 242 return x + ", " + y; 243 } 244 } 245 246 protected static String addLists(String x, String y, String z) { 247 return addLists(x, addLists(y, z)); 248 } 249 } 250 251 // End JavaBaseGenerator.java