package com.spun.util.velocity;
import java.io.File;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.NullLogSystem;
import com.spun.util.Asserts;
import com.spun.util.ObjectUtils;
import com.spun.util.io.FileUtils;
import com.spun.util.parser.ParserCommons;
public class VelocityParser
{
private static VelocityEngine currentEngine = null;
/***********************************************************************/
static
{
for (Enumeration e = LogManager.getCurrentLoggers(); e.hasMoreElements();)
{
((Logger) e.nextElement()).setLevel(Level.OFF);
}
}
/***********************************************************************/
public static String parseFile(String template, ContextAware process)
{
Asserts.assertFileExists("Velocity template", template);
Properties props = new Properties();
int pathBreak = template.lastIndexOf(File.separatorChar);
pathBreak = pathBreak == -1 ? template.length() : pathBreak;
String path = template.substring(0, pathBreak);
String file = template.substring(pathBreak + 1);
props.put("resource.loader", "file");
props.put("runtime.introspector.uberspect", TestableUberspect.class.getName());
props.put("file.resource.loader.path", path);
props.put("velocimacro.context.localscope", "" + true);
props.put("velocimacro.permissions.allow.inline.local.scope", "" + true);
return parse(file, props, new ContextAware[]{process, Default.INSTANCE});
}
/***********************************************************************/
public static String parseJar(String template, ContextAware process)
{
Properties props = new Properties();
props.put("resource.loader", "class");
props.put("class.resource.loader.description", "Velocity Classpath Resource Loader");
props.put("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
props.put("class.resource.cache", "" + true);
props.put("runtime.introspector.uberspect", "com.spun.util.velocity.TestableUberspect");
props.put("velocimacro.context.localscope", "" + true);
props.put("velocimacro.permissions.allow.inline.local.scope", "" + true);
return parse(template, props, new ContextAware[]{process,Default.INSTANCE});
}
/***********************************************************************/
public static String parseString(String template, ContextAware process)
{
Properties props = new Properties();
props.put("resource.loader", "class");
props.put("class.resource.loader.class", StringResourceLoader.class.getName());
props.put("velocimacro.context.localscope", "" + true);
props.put("runtime.introspector.uberspect", TestableUberspect.class.getName());
props.put("velocimacro.permissions.allow.inline.local.scope", "" + true);
return parse(template, props, new ContextAware[]{process,Default.INSTANCE});
}
/***********************************************************************/
public static String parse(String template, Properties props, ContextAware process)
{
return parse(template, props, new ContextAware[]{process,Default.INSTANCE});
}/***********************************************************************/
public static String parse(String template, Properties props, ContextAware[] process)
{
StringWriter out = new StringWriter();
parse(template, props, process, out);
return out.toString();
}
/***********************************************************************/
public static Writer parse(String template, Properties props, ContextAware process[], Writer out)
{
try
{
props.put("directive.foreach.counter.initial.value", "0");
props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogSystem.class.getName());
VelocityEngine engine = initializeEngine(props);
VelocityContext context = new VelocityContext();
Template velocityTemplate = engine.getTemplate(template);
for (int i = 0; i < process.length; i++)
{
if(process[i] != null) process[i].setupContext(context);
}
velocityTemplate.merge(context, out);
return out;
}
catch (Exception e)
{
throw ObjectUtils.throwAsError(e);
}
}
public static synchronized VelocityEngine initializeEngine(Properties props) throws Exception
{
if (currentEngine == null || isDifferentForProperties(props, currentEngine, new String[]{"resource.loader", "file.resource.loader.path"}))
{
currentEngine = new VelocityEngine();
currentEngine.init(props);
}
return currentEngine;
}
/***********************************************************************/
private static boolean isDifferentForProperties(Properties props, VelocityEngine velo, String[] keys)
{
for (int i = 0; i < keys.length; i++)
{
String key = keys[i];
if (!ObjectUtils.isEqual(props.get(key), velo.getProperty(key))) { return true; }
}
return false;
}
/***********************************************************************/
/**
* Parse a File to a File
**/
public static String parseFile(String templateFileName, String outputFileName, ContextAware process)
{
return parseFile(templateFileName, new File(outputFileName), process);
}
/***********************************************************************/
/**
* Parse a File to a File
**/
public static String parseFile(String templateFileName, File outputFile, ContextAware process)
{
try
{
String output = parseFile(templateFileName, process);
FileUtils.writeFile(outputFile, output);
return output;
}
catch (Exception e)
{
throw ObjectUtils.throwAsError(e);
}
}
/***********************************************************************/
public static class FileParseCall implements ParseCall
{
public static FileParseCall INSTANCE = new FileParseCall();
public String parse(String template, ContextAware process)
{
return parseFile(template, process);
}
}
/***********************************************************************/
public static class JarParseCall implements ParseCall
{
public static JarParseCall INSTANCE = new JarParseCall();
public String parse(String template, ContextAware process)
{
return parseJar(template, process);
}
}
/***********************************************************************/
public static class Default implements ContextAware
{
public static ContextAware INSTANCE = new Default();
public void setupContext(Context context)
{
context.put("commons", ParserCommons.INSTANCE);
}
}
/***********************************************************************/
/***********************************************************************/
public static String parseFromClassPath(Class clazz, String string, ContextAware context)
{
String resource = FileUtils.readFromClassPath(clazz, string);
return parseString(resource, context);
}
}