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]));
}
}
Related examples in the same category