Java tutorial
/* Copyright (c) 2008, Paul Cager. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; /** * Generates boiler-plate files from templates. Only very basic * template processing is supplied - if we need something more * sophisticated I suggest we use a third-party library. * * @author paulcager * @since 4.2 */ public class JavaFileGenerator { /** * @param templateName the name of the template. E.g. * "/templates/Token.template". * @param options the processing options in force, such * as "STATIC=yes" */ public JavaFileGenerator(String templateName, Map options) { this.templateName = templateName; this.options = options; } private final String templateName; private final Map options; private String currentLine; /** * Generate the output file. * @param out * @throws IOException */ public void generate(PrintWriter out) throws IOException { InputStream is = getClass().getResourceAsStream(templateName); if (is == null) throw new IOException("Invalid template name: " + templateName); BufferedReader in = new BufferedReader(new InputStreamReader(is)); process(in, out, false); } private String peekLine(BufferedReader in) throws IOException { if (currentLine == null) currentLine = in.readLine(); return currentLine; } private String getLine(BufferedReader in) throws IOException { String line = currentLine; currentLine = null; if (line == null) in.readLine(); return line; } private boolean evaluate(String condition) { condition = condition.trim(); Object obj = options.get(condition); if (obj == null) { return condition.equalsIgnoreCase("true") || condition.equalsIgnoreCase("yes"); } if (obj instanceof Boolean) { return ((Boolean) obj).booleanValue(); } else if (obj instanceof String) { String string = ((String) obj).trim(); return string.length() > 0 && !string.equalsIgnoreCase("false") && !string.equalsIgnoreCase("no"); } return false; } private String substitute(String text) throws IOException { int startPos; if ((startPos = text.indexOf("${")) == -1) { return text; } // Find matching "}". int braceDepth = 1; int endPos = startPos + 2; while (endPos < text.length() && braceDepth > 0) { if (text.charAt(endPos) == '{') braceDepth++; else if (text.charAt(endPos) == '}') braceDepth--; endPos++; } if (braceDepth != 0) throw new IOException("Mismatched \"{}\" in template string: " + text); final String variableExpression = text.substring(startPos + 2, endPos - 1); // Find the end of the variable name String value = null; for (int i = 0; i < variableExpression.length(); i++) { char ch = variableExpression.charAt(i); if (ch == ':' && i < variableExpression.length() - 1 && variableExpression.charAt(i + 1) == '-') { value = substituteWithDefault(variableExpression.substring(0, i), variableExpression.substring(i + 2)); break; } else if (ch == '?') { value = substituteWithConditional(variableExpression.substring(0, i), variableExpression.substring(i + 1)); break; } else if (ch != '_' && !Character.isJavaIdentifierPart(ch)) { throw new IOException("Invalid variable in " + text); } } if (value == null) { value = substituteWithDefault(variableExpression, ""); } return text.substring(0, startPos) + value + text.substring(endPos); } /** * @param substring * @param defaultValue * @return * @throws IOException */ private String substituteWithConditional(String variableName, String values) throws IOException { // Split values into true and false values. int pos = values.indexOf(':'); if (pos == -1) throw new IOException("No ':' separator in " + values); if (evaluate(variableName)) return substitute(values.substring(0, pos)); else return substitute(values.substring(pos + 1)); } /** * @param variableName * @param defaultValue * @return */ private String substituteWithDefault(String variableName, String defaultValue) throws IOException { Object obj = options.get(variableName.trim()); if (obj == null || obj.toString().length() == 0) return substitute(defaultValue); return obj.toString(); } private void write(PrintWriter out, String text) throws IOException { while (text.indexOf("${") != -1) { text = substitute(text); } out.println(text); } private void process(BufferedReader in, PrintWriter out, boolean ignoring) throws IOException { // out.println("*** process ignore=" + ignoring + " : " + peekLine(in)); while (peekLine(in) != null) { if (peekLine(in).trim().startsWith("#if")) { String line = getLine(in).trim(); final boolean condition = evaluate(line.substring(3).trim()); process(in, out, ignoring || !condition); if (peekLine(in) != null && peekLine(in).trim().startsWith("#else")) { getLine(in); // Discard the #else line process(in, out, ignoring || condition); } line = getLine(in); if (line == null) throw new IOException("Missing \"#fi\""); if (!line.trim().startsWith("#fi")) throw new IOException("Expected \"#fi\", got: " + line); } else if (peekLine(in).trim().startsWith("#")) { break; } else { String line = getLine(in); if (!ignoring) write(out, line); } } out.flush(); } public static void main(String[] args) throws Exception { Map map = new HashMap(); map.put("falseArg", Boolean.FALSE); map.put("trueArg", Boolean.TRUE); map.put("stringValue", "someString"); new JavaFileGenerator(args[0], map).generate(new PrintWriter(args[1])); } }