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