Mega Code Archive

 
Categories / Java / File Input Output
 

Java File Generator

/* 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]));   } }