aboutsummaryrefslogtreecommitdiff
path: root/velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java
diff options
context:
space:
mode:
Diffstat (limited to 'velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java')
-rw-r--r--velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java338
1 files changed, 338 insertions, 0 deletions
diff --git a/velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java b/velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java
new file mode 100644
index 00000000..469ca45d
--- /dev/null
+++ b/velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java
@@ -0,0 +1,338 @@
+package org.apache.velocity.script;
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * 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. Neither the name of the Sun Microsystems nor the names of
+ * is contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+
+ * 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.
+ */
+
+/*
+ * Main class for the Velocity script engine.
+ * All the variants of the eval() methods return the writer. The default writer is a PrintWriter towards System.out.
+ * To specify a specific writer, use getContext().setWriter(writer). To get a resulting string, pass a StringWriter.
+ *
+ * You can specify a pathname towards a Velocity properties file using the "org.apache.velocity.script.properties" key,
+ * either as a ScriptContext attribute, or as a System property.
+ *
+ * Example use:
+ * <pre>
+ * ScriptEngine vel = new VelocityScriptEngine();
+ * vel.getContext().setAttribute(VelocityScriptEngine.VELOCITY_PROPERTIES_KEY, "path/to/velocity.properties");
+ * vel.getContext().setWriter(new StringWriter());
+ * vel.put("foo","World");
+ * Object result = vel.eval("Hello $foo !");
+ * String helloWorld = result.toString()
+ * </pre>
+ *
+ * Please refer to the javax.script.ScriptEngine documentation for additional details.
+ *
+ * @author A. Sundararajan
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ * @version $Id: VelocityScriptEngine.java$
+ */
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeInstance;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
+
+import javax.script.AbstractScriptEngine;
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Properties;
+
+public class VelocityScriptEngine extends AbstractScriptEngine implements Compilable
+{
+ /**
+ * Key used to provide this engine with the pathname of the Velocity properties file.
+ * This key is first searched in the ScriptContext attributes, then as a System property
+ */
+ public static final String VELOCITY_PROPERTIES_KEY = "org.apache.velocity.script.properties";
+
+ // my factory, may be null
+ private volatile ScriptEngineFactory factory;
+ private volatile RuntimeInstance velocityEngine;
+
+ /**
+ * constructs a new Velocity script engine, linked to the given factory
+ * @param factory
+ */
+ public VelocityScriptEngine(ScriptEngineFactory factory)
+ {
+ this.factory = factory;
+ }
+
+ /**
+ * constructs a new standalone Velocity script engine
+ */
+ public VelocityScriptEngine()
+ {
+ this(null);
+ }
+
+ /**
+ * get the internal Velocity RuntimeInstance
+ * @return the internal Velocity RuntimeInstance
+ */
+ protected RuntimeInstance getVelocityEngine()
+ {
+ return velocityEngine;
+ }
+
+ /**
+ * Evaluate the given script.
+ * If you wish to get a resulting string, call getContext().setWriter(new StringWriter()) then call toString()
+ * on the returned writer.
+ * @param str script source
+ * @param ctx script context
+ * @return the script context writer (by default a PrintWriter towards System.out)
+ * @throws ScriptException
+ */
+ @Override
+ public Object eval(String str, ScriptContext ctx)
+ throws ScriptException
+ {
+ return eval(new StringReader(str), ctx);
+ }
+
+ /**
+ * Evaluate the given script.
+ * If you wish to get a resulting string, call getContext().setWriter(new StringWriter()) then call toString()
+ * on the returned writer.
+ * @param reader script source reader
+ * @param ctx script context
+ * @return the script context writer (by default a PrintWriter towards System.out)
+ * @throws ScriptException
+ */
+ @Override
+ public Object eval(Reader reader, ScriptContext ctx)
+ throws ScriptException
+ {
+ initVelocityEngine(ctx);
+ String fileName = getFilename(ctx);
+ VelocityContext vctx = getVelocityContext(ctx);
+ Writer out = ctx.getWriter();
+ if (out == null)
+ {
+ out = new StringWriter();
+ ctx.setWriter(out);
+ }
+ try
+ {
+ velocityEngine.evaluate(vctx, out, fileName, reader);
+ out.flush();
+ }
+ catch (Exception exp)
+ {
+ throw new ScriptException(exp);
+ }
+ return out;
+ }
+
+ /**
+ * get the factory used to create this script engine
+ * @return factory
+ */
+ @Override
+ public ScriptEngineFactory getFactory()
+ {
+ if (factory == null)
+ {
+ synchronized (this)
+ {
+ if (factory == null)
+ {
+ factory = new VelocityScriptEngineFactory();
+ }
+ }
+ }
+ return factory;
+ }
+
+ /**
+ * creates a new Bindings to be used with this script
+ * @return new bindings
+ */
+ @Override
+ public Bindings createBindings()
+ {
+ return new SimpleBindings();
+ }
+
+ private void initVelocityEngine(ScriptContext ctx)
+ {
+ if (ctx == null)
+ {
+ ctx = getContext();
+ }
+ if (velocityEngine == null)
+ {
+ synchronized (this)
+ {
+ if (velocityEngine != null) return;
+
+ Properties props = getVelocityProperties(ctx);
+ RuntimeInstance tmpEngine = new RuntimeInstance();
+ try
+ {
+ if (props != null)
+ {
+ tmpEngine.init(props);
+ }
+ else
+ {
+ tmpEngine.init();
+ }
+ }
+ catch (RuntimeException rexp)
+ {
+ throw rexp;
+ }
+ catch (Exception exp)
+ {
+ throw new RuntimeException(exp);
+ }
+ velocityEngine = tmpEngine;
+ }
+ }
+ }
+
+ protected static VelocityContext getVelocityContext(ScriptContext ctx)
+ {
+ ctx.setAttribute("context", ctx, ScriptContext.ENGINE_SCOPE);
+ Bindings globalScope = ctx.getBindings(ScriptContext.GLOBAL_SCOPE);
+ Bindings engineScope = ctx.getBindings(ScriptContext.ENGINE_SCOPE);
+ if (globalScope != null)
+ {
+ return new VelocityContext(engineScope, new VelocityContext(globalScope));
+ }
+ else
+ {
+ return new VelocityContext(engineScope);
+ }
+ }
+
+ protected static String getFilename(ScriptContext ctx)
+ {
+ Object fileName = ctx.getAttribute(ScriptEngine.FILENAME);
+ return fileName != null? fileName.toString() : "<unknown>";
+ }
+
+ protected static Properties getVelocityProperties(ScriptContext ctx)
+ {
+ try
+ {
+ Object props = ctx.getAttribute(VELOCITY_PROPERTIES_KEY);
+ if (props instanceof Properties)
+ {
+ return (Properties) props;
+ }
+ else
+ {
+ String propsName = System.getProperty(VELOCITY_PROPERTIES_KEY);
+ if (propsName != null)
+ {
+ File propsFile = new File(propsName);
+ if (propsFile.exists() && propsFile.canRead())
+ {
+ Properties p = new Properties();
+ p.load(new FileInputStream(propsFile));
+ return p;
+ }
+ }
+ }
+ }
+ catch (Exception exp)
+ {
+ System.err.println(exp);
+ }
+ return null;
+ }
+
+ /**
+ * Compile a template
+ * @param script template source
+ * @return compiled template
+ * @throws ScriptException
+ */
+ @Override
+ public CompiledScript compile(String script) throws ScriptException
+ {
+ return compile(new StringReader(script));
+ }
+
+ /**
+ * Compile a template
+ * @param script template source
+ * @return compiled template
+ * @throws ScriptException
+ */
+ @Override
+ public CompiledScript compile(Reader script) throws ScriptException
+ {
+ initVelocityEngine(null);
+ ResourceLoader resourceLoader = new SingleResourceReader(script);
+ Template template = new Template();
+ template.setRuntimeServices(velocityEngine);
+ template.setResourceLoader(resourceLoader);
+ try
+ {
+ template.process();
+ }
+ catch(Exception e)
+ {
+ // CB TODO - exception may have line/col informations, that ScriptException can exploit
+ throw new ScriptException(e);
+ }
+ return new VelocityCompiledScript(this, template);
+ }
+
+ // a dummy resource reader class, serving a single resource given by the provided resource reader
+ protected static class SingleResourceReader extends StringResourceLoader
+ {
+ private Reader reader;
+
+ public SingleResourceReader(Reader r)
+ {
+ reader = r;
+ }
+
+ @Override
+ public Reader getResourceReader(String source, String encoding) throws ResourceNotFoundException
+ {
+ return reader;
+ }
+ }
+}