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