/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.faces.generate; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Stack; /** * <p>Abstract base class for Java and TLD generators.</p> * * <p>The methods in this class presume the following command line option * names and corresponding values:</p> * <ul> * </ul> */ public abstract class AbstractGenerator implements Generator { // -------------------------------------------------------- Static Variables // The set of default values for primitives, keyed by the primitive type protected static final Map<String,String> TYPE_DEFAULTS = new HashMap<String, String>(); static { TYPE_DEFAULTS.put("boolean", "false"); TYPE_DEFAULTS.put("byte", "Byte.MIN_VALUE"); TYPE_DEFAULTS.put("char", "Character.MIN_VALUE"); TYPE_DEFAULTS.put("double", "Double.MIN_VALUE"); TYPE_DEFAULTS.put("float", "Float.MIN_VALUE"); TYPE_DEFAULTS.put("int", "Integer.MIN_VALUE"); TYPE_DEFAULTS.put("long", "Long.MIN_VALUE"); TYPE_DEFAULTS.put("short", "Short.MIN_VALUE"); } // The set of reserved keywords in the Java language protected static final Set<String> JAVA_KEYWORDS = new HashSet<String>(); static { JAVA_KEYWORDS.add("abstract"); JAVA_KEYWORDS.add("boolean"); JAVA_KEYWORDS.add("break"); JAVA_KEYWORDS.add("byte"); JAVA_KEYWORDS.add("case"); JAVA_KEYWORDS.add("cast"); JAVA_KEYWORDS.add("catch"); JAVA_KEYWORDS.add("char"); JAVA_KEYWORDS.add("class"); JAVA_KEYWORDS.add("const"); JAVA_KEYWORDS.add("continue"); JAVA_KEYWORDS.add("default"); JAVA_KEYWORDS.add("do"); JAVA_KEYWORDS.add("double"); JAVA_KEYWORDS.add("else"); JAVA_KEYWORDS.add("enum"); JAVA_KEYWORDS.add("extends"); JAVA_KEYWORDS.add("final"); JAVA_KEYWORDS.add("finally"); JAVA_KEYWORDS.add("float"); JAVA_KEYWORDS.add("for"); JAVA_KEYWORDS.add("future"); JAVA_KEYWORDS.add("generic"); JAVA_KEYWORDS.add("goto"); JAVA_KEYWORDS.add("if"); JAVA_KEYWORDS.add("implements"); JAVA_KEYWORDS.add("import"); JAVA_KEYWORDS.add("inner"); JAVA_KEYWORDS.add("instanceof"); JAVA_KEYWORDS.add("int"); JAVA_KEYWORDS.add("interface"); JAVA_KEYWORDS.add("long"); JAVA_KEYWORDS.add("native"); JAVA_KEYWORDS.add("new"); JAVA_KEYWORDS.add("null"); JAVA_KEYWORDS.add("operator"); JAVA_KEYWORDS.add("outer"); JAVA_KEYWORDS.add("package"); JAVA_KEYWORDS.add("private"); JAVA_KEYWORDS.add("protected"); JAVA_KEYWORDS.add("public"); JAVA_KEYWORDS.add("rest"); JAVA_KEYWORDS.add("return"); JAVA_KEYWORDS.add("short"); JAVA_KEYWORDS.add("static"); JAVA_KEYWORDS.add("strictfp"); JAVA_KEYWORDS.add("super"); JAVA_KEYWORDS.add("switch"); JAVA_KEYWORDS.add("synchronized"); JAVA_KEYWORDS.add("this"); JAVA_KEYWORDS.add("throw"); JAVA_KEYWORDS.add("throws"); JAVA_KEYWORDS.add("transient"); JAVA_KEYWORDS.add("try"); JAVA_KEYWORDS.add("var"); JAVA_KEYWORDS.add("void"); JAVA_KEYWORDS.add("volatile"); JAVA_KEYWORDS.add("while"); } // ------------------------------------------------------- Protected Methods /** * <p>Return the capitalized version of the specified property name.</p> * * @param name Uncapitalized property name */ protected static String capitalize(String name) { return (Character.toUpperCase(name.charAt(0)) + name.substring(1)); } /** * <p>Return a mangled version of the specified name if it conflicts with * a Java keyword; otherwise, return the specified name unchanged.</p> * * @param name Name to be potentially mangled */ protected static String mangle(String name) { if (JAVA_KEYWORDS.contains(name)) { return ('_' + name); } else { return (name); } } /** * <p>Parse the command line options into a <code>Map</code>.</p> * * @param args Command line arguments passed to this program * * @exception IllegalArgumentException if an option flag does not start * with a '-' or is missing a corresponding value */ protected static Map<String,String> options(String[] args) { Map<String,String> options = new HashMap<String, String>(); int i = 0; while (i < args.length) { if (!args[i].startsWith("-")) { throw new IllegalArgumentException ("Invalid option name '" + args[i] + '\''); } else if ((i + 1) >= args.length) { throw new IllegalArgumentException ("Missing value for option '" + args[i] + '\''); } options.put(args[i], args[i+1]); i += 2; } return (options); } /** * <p>Return <code>true</code> if the specified type is a primitive.</p> * * @param type Type to be tested */ protected static boolean primitive(String type) { return ((GeneratorUtil.convertToPrimitive(type) != null)); } /** * <p>Return the short class name from the specified (potentially fully * qualified) class name. If the specified name has no periods, the * input value is returned unchanged.</p> * * @param className Class name that is optionally fully qualified */ protected static String shortName(String className) { int index = className.lastIndexOf('.'); if (index >= 0) { return (className.substring(index + 1)); } else { return (className); } } // ----------------------------------------------------------- Inner Classes protected static class CodeWriter extends BufferedWriter { private final static String TAB = " "; private final int TAB_LENGTH = TAB.length(); private Stack<String> depth; private String formatString = ""; // -------------------------------------------------------- Constructors public CodeWriter(Writer writer) { super(writer); depth = new Stack<String>(); } // END CodeWriter public void indent() { depth.push(TAB); updateFormatString(depth.size()); } // END indent public void outdent() { depth.pop(); updateFormatString(depth.size()); } // END outdent public void fwrite(String str) throws IOException { super.write(formatString + str); } // END write public void writePackage(String packageName) throws IOException { fwrite(new StringBuffer("package ").append(packageName). append(";\n").toString()); } // END writePackage public void writeImport(String fullyQualifiedClassName) throws IOException { fwrite(new StringBuffer("import "). append(fullyQualifiedClassName).append(";\n"). toString()); } // END writeImport public void writePublicClassDeclaration(String className, String extendsClass, String[] implementsClasses, boolean isAbstract, boolean isFinal) throws IOException { if (isAbstract && isFinal) { throw new IllegalArgumentException("Cannot have a class" + " declaration be both abstract and final."); } StringBuffer sb = new StringBuffer("public"); if (isAbstract) { sb.append(" abstract"); } if (isFinal) { sb.append(" final"); } sb.append(" class ").append(className); if (extendsClass != null && extendsClass.length() > 0) { sb.append(" extends ").append(extendsClass); } if (implementsClasses != null && implementsClasses.length > 0) { sb.append(" implements "); for (int i = 0; i < implementsClasses.length; i++) { sb.append(implementsClasses[i]); if (i < implementsClasses.length-1) { sb.append(", "); } } } sb.append(" {\n\n"); fwrite(sb.toString()); } // END writePublicClassDeclaration public void writeJavadocComment(String str) throws IOException { fwrite("/**\n"); String[] tokens = str.split("\r|\n|\t"); for (int i = 0; i < tokens.length; i++) { fwrite(" * "); write(tokens[i].trim()); write('\n'); } fwrite(" */\n"); } // END writeJavadocComment public void writeLineComment(String str) throws IOException { String[] tokens = str.split("\r|\n|\t"); for (int i = 0; i < tokens.length; i++) { fwrite("// "); write(tokens[i].trim()); write('\n'); } } // END writeLineComment public void writeBlockComment(String str) throws IOException { fwrite("/*\n"); String[] tokens = str.split("\r|\n|\t"); for (int i = 0; i < tokens.length; i++) { fwrite(" * "); write(tokens[i].trim()); write('\n'); } fwrite(" */\n"); } // END writeBlockComment public void writeReadWriteProperty(String propertyName, String type, String defaultValue) throws IOException { String iVarName = mangle(propertyName); String methodName = capitalize(propertyName); writeLineComment("PROPERTY: " + propertyName); fwrite("private " + type + ' ' + iVarName + (defaultValue == null ? ";" : " = " + defaultValue) + '\n'); fwrite("public void set" + methodName + '(' + type + ' ' + iVarName + ") {\n"); indent(); fwrite("this." + iVarName + " = " + iVarName + ";\n"); outdent(); fwrite("}\n\n"); fwrite("public " + type + "get" + methodName + "() {\n"); indent(); fwrite("return this." + iVarName + ";\n"); outdent(); fwrite("}\n\n"); } // END writeReadWriteProperty public void writeReadWriteProperty(String propertyName, String type) throws IOException { writeReadWriteProperty(propertyName, type, null); } // END writeReadWriteProperty public void writeReadOnlyProperty(String propertyName, String type, String defaultValue) throws IOException { writeLineComment("PROPERTY: " + propertyName); String iVarName = mangle(propertyName); fwrite("private " + type + ' ' + iVarName + (defaultValue == null ? ";" : " = " + defaultValue) + '\n'); fwrite("public " + type + "get" + capitalize(propertyName) + "() {\n"); indent(); fwrite("return this." + iVarName + ";\n"); outdent(); fwrite("}\n\n"); } // END writeReadOnlyProperty public void writeReadOnlyProperty(String propertyName, String type) throws IOException { writeReadOnlyProperty(propertyName, type, null); } // END writeReadOnlyProperty public void writeWriteOnlyProperty(String propertyName, String type, String defaultValue) throws IOException { writeLineComment("PROPERTY: " + propertyName); String iVarName = mangle(propertyName); fwrite("private " + type + ' ' + iVarName + (defaultValue == null ? ";" : " = " + defaultValue + ";") + '\n'); fwrite("public void set" + capitalize(propertyName) + '(' + type + ' ' + iVarName + ") {\n"); indent(); fwrite("this." + iVarName + " = " + iVarName + ";\n"); outdent(); fwrite("}\n\n"); } // END writeWriteOnlyProperty public void writeWriteOnlyProperty(String propertyName, String type) throws IOException { writeWriteOnlyProperty(propertyName, type, null); } // END writeWriteOnlyProperty // ----------------------------------------------------- Private Methods private void updateFormatString(int numTabs) { if (numTabs == 0) { formatString = ""; } else { StringBuffer sb = new StringBuffer(numTabs * TAB_LENGTH); for (int i = 0; i < numTabs; i++) { sb.append(TAB); } formatString = sb.toString(); } } // END updateFormatString } }