And here is the patch :) .
csanders wrote:
> Attached is a patch for RuntimeInstance.java that adds two methods,
> private String replaceEnviornmentalVariable(String string) , private
> void replaceEnviormentalVariables(ExtendedProperties properties) ...
> and changes initializeProperties and setProperty() to replace them as
> they come in.
>
> Can someone review it and let me know what it needs to be included in
> Velocity ?
>
> Thanks!
> Charles
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
dev-unsubscribe@...
> For additional commands, e-mail:
dev-help@...
>
Index: /home/csanders/workspace/Velocity/src/java/org/apache/velocity/runtime/RuntimeInstance.java
===================================================================
--- /home/csanders/workspace/Velocity/src/java/org/apache/velocity/runtime/RuntimeInstance.java (revision 653607)
+++ /home/csanders/workspace/Velocity/src/java/org/apache/velocity/runtime/RuntimeInstance.java (working copy)
@@ -29,6 +29,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
@@ -64,23 +65,15 @@
import org.apache.velocity.util.introspection.UberspectLoggable;
/**
- * This is the Runtime system for Velocity. It is the
- * single access point for all functionality in Velocity.
- * It adheres to the mediator pattern and is the only
- * structure that developers need to be familiar with
- * in order to get Velocity to perform.
- *
- * The Runtime will also cooperate with external
- * systems like Turbine. Runtime properties can
- * set and then the Runtime is initialized.
- *
- * Turbine, for example, knows where the templates
- * are to be loaded from, and where the Velocity
- * log file should be placed.
- *
- * So in the case of Velocity cooperating with Turbine
- * the code might look something like the following:
- *
+ * This is the Runtime system for Velocity. It is the single access point for all functionality in Velocity. It adheres to the mediator pattern and is the only
+ * structure that developers need to be familiar with in order to get Velocity to perform.
+ *
+ * The Runtime will also cooperate with external systems like Turbine. Runtime properties can set and then the Runtime is initialized.
+ *
+ * Turbine, for example, knows where the templates are to be loaded from, and where the Velocity log file should be placed.
+ *
+ * So in the case of Velocity cooperating with Turbine the code might look something like the following:
+ *
* <blockquote><code><pre>
* ri.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH, templatePath);
* ri.setProperty(Runtime.RUNTIME_LOG, pathToVelocityLog);
@@ -86,7 +79,7 @@
* ri.setProperty(Runtime.RUNTIME_LOG, pathToVelocityLog);
* ri.init();
* </pre></code></blockquote>
- *
+ *
* <pre>
* -----------------------------------------------------------------------
* N O T E S O N R U N T I M E I N I T I A L I Z A T I O N
@@ -92,7 +85,6 @@
* N O T E S O N R U N T I M E I N I T I A L I Z A T I O N
* -----------------------------------------------------------------------
* init()
- *
* If init() is called by itself the RuntimeInstance will initialize
* with a set of default values.
* -----------------------------------------------------------------------
@@ -97,7 +89,6 @@
* with a set of default values.
* -----------------------------------------------------------------------
* init(String/Properties)
- *
* In this case the default velocity properties are layed down
* first to provide a solid base, then any properties provided
* in the given properties object will override the corresponding
@@ -104,7 +95,7 @@
* default property.
* -----------------------------------------------------------------------
* </pre>
- *
+ *
* @author <a href="mailto:
jvanzyl@...">Jason van Zyl</a>
* @author <a href="mailto:
jlb@...">Jeff Bowden</a>
* @author <a href="mailto:
geirm@...">Geir Magusson Jr.</a>
@@ -110,1585 +101,1446 @@
* @author <a href="mailto:
geirm@...">Geir Magusson Jr.</a>
* @version $Id$
*/
-public class RuntimeInstance implements RuntimeConstants, RuntimeServices
-{
- /**
- * VelocimacroFactory object to manage VMs
- */
- private VelocimacroFactory vmFactory = null;
+public class RuntimeInstance implements RuntimeConstants, RuntimeServices {
+ /**
+ * VelocimacroFactory object to manage VMs
+ */
+ private VelocimacroFactory vmFactory = null;
- /**
- * The Runtime logger. We start with an instance of
- * a 'primordial logger', which just collects log messages
- * then, when the log system is initialized, all the
- * messages get dumpted out of the primordial one into the real one.
- */
- private Log log = new Log();
+ /**
+ * The Runtime logger. We start with an instance of a 'primordial logger', which just collects log messages then, when the log system is initialized, all
+ * the messages get dumpted out of the primordial one into the real one.
+ */
+ private Log log = new Log();
- /**
- * The Runtime parser pool
- */
- private ParserPool parserPool;
+ /**
+ * The Runtime parser pool
+ */
+ private ParserPool parserPool;
- /**
- * Indicate whether the Runtime is in the midst of initialization.
- */
- private boolean initializing = false;
+ /**
+ * Indicate whether the Runtime is in the midst of initialization.
+ */
+ private boolean initializing = false;
- /**
- * Indicate whether the Runtime has been fully initialized.
- */
- private boolean initialized = false;
+ /**
+ * Indicate whether the Runtime has been fully initialized.
+ */
+ private boolean initialized = false;
- /**
- * These are the properties that are laid down over top
- * of the default properties when requested.
- */
- private ExtendedProperties overridingProperties = null;
+ /**
+ * These are the properties that are laid down over top of the default properties when requested.
+ */
+ private ExtendedProperties overridingProperties = null;
- /**
- * This is a hashtable of initialized directives.
- * The directives that populate this hashtable are
- * taken from the RUNTIME_DEFAULT_DIRECTIVES
- * property file. This hashtable is passed
- * to each parser that is created.
- */
- private Hashtable runtimeDirectives;
+ /**
+ * This is a hashtable of initialized directives. The directives that populate this hashtable are taken from the RUNTIME_DEFAULT_DIRECTIVES property file.
+ * This hashtable is passed to each parser that is created.
+ */
+ private Hashtable runtimeDirectives;
- /**
- * Object that houses the configuration options for
- * the velocity runtime. The ExtendedProperties object allows
- * the convenient retrieval of a subset of properties.
- * For example all the properties for a resource loader
- * can be retrieved from the main ExtendedProperties object
- * using something like the following:
- *
- * ExtendedProperties loaderConfiguration =
- * configuration.subset(loaderID);
- *
- * And a configuration is a lot more convenient to deal
- * with then conventional properties objects, or Maps.
- */
- private ExtendedProperties configuration = new ExtendedProperties();
+ /**
+ * Object that houses the configuration options for the velocity runtime. The ExtendedProperties object allows the convenient retrieval of a subset of
+ * properties. For example all the properties for a resource loader can be retrieved from the main ExtendedProperties object using something like the
+ * following:
+ *
+ * ExtendedProperties loaderConfiguration = configuration.subset(loaderID);
+ *
+ * And a configuration is a lot more convenient to deal with then conventional properties objects, or Maps.
+ */
+ private ExtendedProperties configuration = new ExtendedProperties();
- private ResourceManager resourceManager = null;
+ private ResourceManager resourceManager = null;
- /**
- * This stores the engine-wide set of event handlers. Event handlers for
- * each specific merge are stored in the context.
- */
- private EventCartridge eventCartridge = null;
+ /**
+ * This stores the engine-wide set of event handlers. Event handlers for each specific merge are stored in the context.
+ */
+ private EventCartridge eventCartridge = null;
- /*
- * Each runtime instance has it's own introspector
- * to ensure that each instance is completely separate.
- */
- private Introspector introspector = null;
+ /*
+ * Each runtime instance has it's own introspector to ensure that each instance is completely separate.
+ */
+ private Introspector introspector = null;
+ /*
+ * Opaque reference to something specificed by the application for use in application supplied/specified pluggable components
+ */
+ private Map applicationAttributes = null;
- /*
- * Opaque reference to something specificed by the
- * application for use in application supplied/specified
- * pluggable components
- */
- private Map applicationAttributes = null;
+ private Uberspect uberSpect;
+ /**
+ * Creates a new RuntimeInstance object.
+ */
+ public RuntimeInstance() {
+ /*
+ * create a VM factory, introspector, and application attributes
+ */
+ vmFactory = new VelocimacroFactory(this);
- private Uberspect uberSpect;
+ /*
+ * make a new introspector and initialize it
+ */
+ introspector = new Introspector(getLog());
- /**
- * Creates a new RuntimeInstance object.
- */
- public RuntimeInstance()
- {
- /*
- * create a VM factory, introspector, and application attributes
- */
- vmFactory = new VelocimacroFactory( this );
+ /*
+ * and a store for the application attributes
+ */
+ applicationAttributes = new HashMap();
+ }
- /*
- * make a new introspector and initialize it
- */
- introspector = new Introspector(getLog());
+ /**
+ * This is the primary initialization method in the Velocity Runtime. The systems that are setup/initialized here are as follows:
+ *
+ * <ul>
+ * <li>Logging System</li>
+ * <li>ResourceManager</li>
+ * <li>EventHandler</li>
+ * <li>Parser Pool</li>
+ * <li>Global Cache</li>
+ * <li>Static Content Include System</li>
+ * <li>Velocimacro System</li>
+ * </ul>
+ *
+ * @throws Exception
+ * When an error occured during initialization.
+ */
+ public synchronized void init() throws Exception {
+ if (!initialized && !initializing) {
+ initializing = true;
- /*
- * and a store for the application attributes
- */
- applicationAttributes = new HashMap();
- }
+ log.trace("*******************************************************************");
+ log.debug("Starting Apache Velocity
v@...@ (compiled: @build.time@)");
+ log.trace("RuntimeInstance initializing.");
- /**
- * This is the primary initialization method in the Velocity
- * Runtime. The systems that are setup/initialized here are
- * as follows:
- *
- * <ul>
- * <li>Logging System</li>
- * <li>ResourceManager</li>
- * <li>EventHandler</li>
- * <li>Parser Pool</li>
- * <li>Global Cache</li>
- * <li>Static Content Include System</li>
- * <li>Velocimacro System</li>
- * </ul>
- * @throws Exception When an error occured during initialization.
- */
- public synchronized void init()
- throws Exception
- {
- if (!initialized && !initializing)
- {
- initializing = true;
+ initializeProperties();
+ initializeLog();
+ initializeResourceManager();
+ initializeDirectives();
+ initializeEventHandlers();
+ initializeParserPool();
- log.trace("*******************************************************************");
- log.debug("Starting Apache Velocity
v@...@ (compiled: @build.time@)");
- log.trace("RuntimeInstance initializing.");
+ initializeIntrospection();
+ /*
+ * initialize the VM Factory. It will use the properties accessable from Runtime, so keep this here at the end.
+ */
+ vmFactory.initVelocimacro();
- initializeProperties();
- initializeLog();
- initializeResourceManager();
- initializeDirectives();
- initializeEventHandlers();
- initializeParserPool();
+ log.trace("RuntimeInstance successfully initialized.");
- initializeIntrospection();
- /*
- * initialize the VM Factory. It will use the properties
- * accessable from Runtime, so keep this here at the end.
- */
- vmFactory.initVelocimacro();
+ initialized = true;
+ initializing = false;
+ }
+ }
- log.trace("RuntimeInstance successfully initialized.");
+ /**
+ * Returns true if the RuntimeInstance has been successfully initialized.
+ *
+ * @return True if the RuntimeInstance has been successfully initialized.
+ */
+ public boolean isInitialized() {
+ return initialized;
+ }
- initialized = true;
- initializing = false;
- }
- }
+ /**
+ * Gets the classname for the Uberspect introspection package and instantiates an instance.
+ */
+ private void initializeIntrospection() throws Exception {
+ String rm = getString(RuntimeConstants.UBERSPECT_CLASSNAME);
- /**
- * Returns true if the RuntimeInstance has been successfully initialized.
- * @return True if the RuntimeInstance has been successfully initialized.
- */
- public boolean isInitialized()
- {
- return initialized;
- }
+ if (rm != null && rm.length() > 0) {
+ Object o = null;
- /**
- * Gets the classname for the Uberspect introspection package and
- * instantiates an instance.
- */
- private void initializeIntrospection()
- throws Exception
- {
- String rm = getString(RuntimeConstants.UBERSPECT_CLASSNAME);
+ try {
+ o = ClassUtils.getNewInstance(rm);
+ }
+ catch (ClassNotFoundException cnfe) {
+ String err = "The specified class for Uberspect (" + rm + ") does not exist or is not accessible to the current classloader.";
+ log.error(err);
+ throw new Exception(err);
+ }
- if (rm != null && rm.length() > 0)
- {
- Object o = null;
+ if (!(o instanceof Uberspect)) {
+ String err = "The specified class for Uberspect (" + rm + ") does not implement " + Uberspect.class.getName()
+ + "; Velocity is not initialized correctly.";
- try
- {
- o = ClassUtils.getNewInstance( rm );
- }
- catch (ClassNotFoundException cnfe)
- {
- String err = "The specified class for Uberspect (" + rm
- + ") does not exist or is not accessible to the current classloader.";
- log.error(err);
- throw new Exception(err);
- }
+ log.error(err);
+ throw new Exception(err);
+ }
- if (!(o instanceof Uberspect))
- {
- String err = "The specified class for Uberspect ("
- + rm + ") does not implement " + Uberspect.class.getName()
- + "; Velocity is not initialized correctly.";
+ uberSpect = (Uberspect) o;
- log.error(err);
- throw new Exception(err);
- }
+ if (uberSpect instanceof UberspectLoggable) {
+ ((UberspectLoggable) uberSpect).setLog(getLog());
+ }
- uberSpect = (Uberspect) o;
+ if (uberSpect instanceof RuntimeServicesAware) {
+ ((RuntimeServicesAware) uberSpect).setRuntimeServices(this);
+ }
- if (uberSpect instanceof UberspectLoggable)
- {
- ((UberspectLoggable) uberSpect).setLog(getLog());
- }
+ uberSpect.init();
+ }
+ else {
+ /*
+ * someone screwed up. Lets not fool around...
+ */
- if (uberSpect instanceof RuntimeServicesAware)
- {
- ((RuntimeServicesAware) uberSpect).setRuntimeServices(this);
- }
-
- uberSpect.init();
- }
- else
- {
- /*
- * someone screwed up. Lets not fool around...
- */
+ String err = "It appears that no class was specified as the" + " Uberspect. Please ensure that all configuration" + " information is correct.";
- String err = "It appears that no class was specified as the"
- + " Uberspect. Please ensure that all configuration"
- + " information is correct.";
+ log.error(err);
+ throw new Exception(err);
+ }
+ }
- log.error(err);
- throw new Exception(err);
- }
- }
+ /**
+ * Initializes the Velocity Runtime with properties file. The properties file may be in the file system proper, or the properties file may be in the
+ * classpath.
+ */
+ private void setDefaultProperties() {
+ InputStream inputStream = null;
+ try {
+ inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_PROPERTIES);
- /**
- * Initializes the Velocity Runtime with properties file.
- * The properties file may be in the file system proper,
- * or the properties file may be in the classpath.
- */
- private void setDefaultProperties()
- {
- InputStream inputStream = null;
- try
- {
- inputStream = getClass()
- .getResourceAsStream('/' + DEFAULT_RUNTIME_PROPERTIES);
+ configuration.load(inputStream);
- configuration.load( inputStream );
+ if (log.isDebugEnabled()) {
+ log.debug("Default Properties File: " + new File(DEFAULT_RUNTIME_PROPERTIES).getPath());
+ }
- if (log.isDebugEnabled())
- {
- log.debug("Default Properties File: " +
- new File(DEFAULT_RUNTIME_PROPERTIES).getPath());
- }
+ }
+ catch (IOException ioe) {
+ log.error("Cannot get Velocity Runtime default properties!", ioe);
+ }
+ finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ catch (IOException ioe) {
+ log.error("Cannot close Velocity Runtime default properties!", ioe);
+ }
+ }
+ }
+ /**
+ * Allows an external system to set a property in the Velocity Runtime.
+ *
+ * @param key
+ * property key
+ * @param value
+ * property value
+ */
+ public void setProperty(String key, Object value) {
- }
- catch (IOException ioe)
- {
- log.error("Cannot get Velocity Runtime default properties!", ioe);
- }
- finally
- {
- try
- {
- if (inputStream != null)
- {
- inputStream.close();
- }
- }
- catch (IOException ioe)
- {
- log.error("Cannot close Velocity Runtime default properties!", ioe);
- }
- }
- }
+ if (overridingProperties == null) {
+ overridingProperties = new ExtendedProperties();
+ }
- /**
- * Allows an external system to set a property in
- * the Velocity Runtime.
- *
- * @param key property key
- * @param value property value
- */
- public void setProperty(String key, Object value)
- {
- if (overridingProperties == null)
- {
- overridingProperties = new ExtendedProperties();
- }
+ if (value instanceof String)
+ {
+ String newValue = replaceEnviornmentalVariable((String) value);
+ overridingProperties.setProperty(key, newValue);
+ }
+ else if ( value instanceof String[] )
+ {
+ String[] stringArray = (String[])value;
+ String[] newStringArray = new String [ stringArray.length] ;
+ for ( int i = 0 ; i < stringArray.length;i ++ )
+ {
+ newStringArray[i] = replaceEnviornmentalVariable(stringArray[i]);
+ }
+
+ overridingProperties.setProperty(key, newStringArray);
+ }
+
+ }
- overridingProperties.setProperty(key, value);
- }
+ /**
+ * Allow an external system to set an ExtendedProperties object to use. This is useful where the external system also uses the ExtendedProperties class and
+ * the velocity configuration is a subset of parent application's configuration. This is the case with Turbine.
+ *
+ * @param configuration
+ */
+ public void setConfiguration(ExtendedProperties configuration) {
+ if (overridingProperties == null) {
+ overridingProperties = configuration;
+ }
+ else {
+ // Avoid possible ConcurrentModificationException
+ if (overridingProperties != configuration) {
+ overridingProperties.combine(configuration);
+ }
+ }
+ }
- /**
- * Allow an external system to set an ExtendedProperties
- * object to use. This is useful where the external
- * system also uses the ExtendedProperties class and
- * the velocity configuration is a subset of
- * parent application's configuration. This is
- * the case with Turbine.
- *
- * @param configuration
- */
- public void setConfiguration( ExtendedProperties configuration)
- {
- if (overridingProperties == null)
- {
- overridingProperties = configuration;
- }
- else
- {
- // Avoid possible ConcurrentModificationException
- if (overridingProperties != configuration)
- {
- overridingProperties.combine(configuration);
- }
- }
- }
+ /**
+ * Add a property to the configuration. If it already exists then the value stated here will be added to the configuration entry. For example, if
+ *
+ * resource.loader = file
+ *
+ * is already present in the configuration and you
+ *
+ * addProperty("resource.loader", "classpath")
+ *
+ * Then you will end up with a Vector like the following:
+ *
+ * ["file", "classpath"]
+ *
+ * @param key
+ * @param value
+ */
+ public void addProperty(String key, Object value) {
+ if (overridingProperties == null) {
+ overridingProperties = new ExtendedProperties();
+ }
- /**
- * Add a property to the configuration. If it already
- * exists then the value stated here will be added
- * to the configuration entry. For example, if
- *
- * resource.loader = file
- *
- * is already present in the configuration and you
- *
- * addProperty("resource.loader", "classpath")
- *
- * Then you will end up with a Vector like the
- * following:
- *
- * ["file", "classpath"]
- *
- * @param key
- * @param value
- */
- public void addProperty(String key, Object value)
- {
- if (overridingProperties == null)
- {
- overridingProperties = new ExtendedProperties();
- }
+ overridingProperties.addProperty(key, value);
+ }
- overridingProperties.addProperty(key, value);
- }
+ /**
+ * Clear the values pertaining to a particular property.
+ *
+ * @param key
+ * of property to clear
+ */
+ public void clearProperty(String key) {
+ if (overridingProperties != null) {
+ overridingProperties.clearProperty(key);
+ }
+ }
- /**
- * Clear the values pertaining to a particular
- * property.
- *
- * @param key of property to clear
- */
- public void clearProperty(String key)
- {
- if (overridingProperties != null)
- {
- overridingProperties.clearProperty(key);
- }
- }
+ /**
+ * Allows an external caller to get a property. The calling routine is required to know the type, as this routine will return an Object, as that is what
+ * properties can be.
+ *
+ * @param key
+ * property to return
+ * @return Value of the property or null if it does not exist.
+ */
+ public Object getProperty(String key) {
+ Object o = null;
- /**
- * Allows an external caller to get a property. The calling
- * routine is required to know the type, as this routine
- * will return an Object, as that is what properties can be.
- *
- * @param key property to return
- * @return Value of the property or null if it does not exist.
- */
- public Object getProperty(String key)
- {
- Object o = null;
-
- /**
- * Before initialization, check the user-entered properties first.
- */
- if (!initialized && !initializing && overridingProperties != null)
- {
- o = overridingProperties.get(key);
- }
-
- /**
- * After initialization, configuration will hold all properties.
- */
- if (o == null)
- {
- o = configuration.getProperty(key);
- }
- if (o instanceof String)
- {
- return StringUtils.nullTrim((String) o);
- }
- else
- {
- return o;
- }
- }
+ /**
+ * Before initialization, check the user-entered properties first.
+ */
+ if (!initialized && !initializing && overridingProperties != null) {
+ o = overridingProperties.get(key);
+ }
- /**
- * Initialize Velocity properties, if the default
- * properties have not been laid down first then
- * do so. Then proceed to process any overriding
- * properties. Laying down the default properties
- * gives a much greater chance of having a
- * working system.
- */
- private void initializeProperties()
- {
- /*
- * Always lay down the default properties first as
- * to provide a solid base.
- */
- if (configuration.isInitialized() == false)
- {
- setDefaultProperties();
- }
+ /**
+ * After initialization, configuration will hold all properties.
+ */
+ if (o == null) {
+ o = configuration.getProperty(key);
+ }
+ if (o instanceof String) {
+ return StringUtils.nullTrim((String) o);
+ }
+ else {
+ return o;
+ }
+ }
- if( overridingProperties != null)
- {
- configuration.combine(overridingProperties);
- }
- }
+ /**
+ * Replace all environmental variables in the form of ${VELOCITY_HOME} with their
+ * expansions
+ * @param properties
+ */
+
+ private void replaceEnviormentalVariables(ExtendedProperties properties) {
- /**
- * Initialize the Velocity Runtime with a Properties
- * object.
- *
- * @param p
- * @throws Exception When an error occurs during initialization.
- */
- public void init(Properties p) throws Exception
- {
- overridingProperties = ExtendedProperties.convertProperties(p);
- init();
- }
+ Iterator iterator = properties.getKeys();
+ Map convertedKeys = new HashMap();
- /**
- * Initialize the Velocity Runtime with the name of
- * ExtendedProperties object.
- *
- * @param configurationFile
- * @throws Exception When an error occurs during initialization.
- */
- public void init(String configurationFile)
- throws Exception
- {
- overridingProperties = new ExtendedProperties(configurationFile);
- init();
- }
+ while (iterator.hasNext()) {
+ String key = (String) iterator.next();
+ Object value = properties.get(key);
- private void initializeResourceManager()
- throws Exception
- {
- /*
- * Which resource manager?
- */
+ if (value instanceof String) {
- String rm = getString(RuntimeConstants.RESOURCE_MANAGER_CLASS);
+ String v = replaceEnviornmentalVariable((String) value);
+ convertedKeys.put(key, v);
- if (rm != null && rm.length() > 0)
- {
- /*
- * if something was specified, then make one.
- * if that isn't a ResourceManager, consider
- * this a huge error and throw
- */
+ }
+ else if (value instanceof String[]) {
+ String[] stringArray = (String[]) value;
+ for (int i = 0; i < stringArray.length; i++) {
+ String val = stringArray[i];
+ String v = replaceEnviornmentalVariable((String) val);
+ convertedKeys.put(key, v);
- Object o = null;
+ }
+ }
- try
- {
- o = ClassUtils.getNewInstance( rm );
- }
- catch (ClassNotFoundException cnfe )
- {
- String err = "The specified class for ResourceManager (" + rm
- + ") does not exist or is not accessible to the current classloader.";
- log.error(err);
- throw new Exception(err);
- }
+ }
- if (!(o instanceof ResourceManager))
- {
- String err = "The specified class for ResourceManager (" + rm
- + ") does not implement " + ResourceManager.class.getName()
- + "; Velocity is not initialized correctly.";
+ properties.putAll(convertedKeys);
- log.error(err);
- throw new Exception(err);
- }
+ }
- resourceManager = (ResourceManager) o;
+ /**
+ * Replace all occurrences of ${} in a string with its corresponding expanded environmental var's
+ * @param string
+ * @return
+ */
+
+ private String replaceEnviornmentalVariable(String string) {
- resourceManager.initialize(this);
- }
- else
- {
- /*
- * someone screwed up. Lets not fool around...
- */
+ int start = string.indexOf("${");
- String err = "It appears that no class was specified as the"
- + " ResourceManager. Please ensure that all configuration"
- + " information is correct.";
+ if (start != -1) {
- log.error(err);
- throw new Exception( err );
- }
- }
+ int end = string.indexOf('}');
- private void initializeEventHandlers()
- throws Exception
- {
+ if (end != -1) {
+ String env = string.substring(start + 2, end);
+ String regex = "\\$\\{" + env + "\\}";
+ String replacement = System.getenv(env);
+ if (replacement != null) {
+ return string.replaceAll(regex, replacement);
- eventCartridge = new EventCartridge();
+ }
- /**
- * For each type of event handler, get the class name, instantiate it, and store it.
- */
+ }
- String[] referenceinsertion = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION);
- if ( referenceinsertion != null )
- {
- for ( int i=0; i < referenceinsertion.length; i++ )
- {
- EventHandler ev = initializeSpecificEventHandler(referenceinsertion[i],RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,ReferenceInsertionEventHandler.class);
- if (ev != null)
- eventCartridge.addReferenceInsertionEventHandler((ReferenceInsertionEventHandler) ev);
- }
- }
+ }
+ return string;
- String[] nullset = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_NULLSET);
- if ( nullset != null )
- {
- for ( int i=0; i < nullset.length; i++ )
- {
- EventHandler ev = initializeSpecificEventHandler(nullset[i],RuntimeConstants.EVENTHANDLER_NULLSET,NullSetEventHandler.class);
- if (ev != null)
- eventCartridge.addNullSetEventHandler((NullSetEventHandler) ev);
- }
- }
+ }
- String[] methodexception = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION);
- if ( methodexception != null )
- {
- for ( int i=0; i < methodexception.length; i++ )
- {
- EventHandler ev = initializeSpecificEventHandler(methodexception[i],RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,MethodExceptionEventHandler.class);
- if (ev != null)
- eventCartridge.addMethodExceptionHandler((MethodExceptionEventHandler) ev);
- }
- }
+ /**
+ * Initialize Velocity properties, if the default properties have not been laid down first then do so. Then proceed to process any overriding properties.
+ * Laying down the default properties gives a much greater chance of having a working system.
+ */
+ private void initializeProperties() {
+ /*
+ * Always lay down the default properties first as to provide a solid base.
+ */
+ if (configuration.isInitialized() == false) {
+ setDefaultProperties();
+ replaceEnviormentalVariables(configuration);
+ }
- String[] includeHandler = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INCLUDE);
- if ( includeHandler != null )
- {
- for ( int i=0; i < includeHandler.length; i++ )
- {
- EventHandler ev = initializeSpecificEventHandler(includeHandler[i],RuntimeConstants.EVENTHANDLER_INCLUDE,IncludeEventHandler.class);
- if (ev != null)
- eventCartridge.addIncludeEventHandler((IncludeEventHandler) ev);
- }
- }
+ if (overridingProperties != null) {
+ replaceEnviormentalVariables(overridingProperties);
+ configuration.combine(overridingProperties);
+ }
+ }
- String[] invalidReferenceSet = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES);
- if ( invalidReferenceSet != null )
- {
- for ( int i=0; i < invalidReferenceSet.length; i++ )
- {
- EventHandler ev = initializeSpecificEventHandler(invalidReferenceSet[i],RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES,InvalidReferenceEventHandler.class);
- if (ev != null)
- {
- eventCartridge.addInvalidReferenceEventHandler((InvalidReferenceEventHandler) ev);
- }
- }
- }
+ /**
+ * Initialize the Velocity Runtime with a Properties object.
+ *
+ * @param p
+ * @throws Exception
+ * When an error occurs during initialization.
+ */
+ public void init(Properties p) throws Exception {
+ overridingProperties = ExtendedProperties.convertProperties(p);
+ init();
+ }
+ /**
+ * Initialize the Velocity Runtime with the name of ExtendedProperties object.
+ *
+ * @param configurationFile
+ * @throws Exception
+ * When an error occurs during initialization.
+ */
+ public void init(String configurationFile) throws Exception {
+ overridingProperties = new ExtendedProperties(configurationFile);
+ init();
+ }
- }
+ private void initializeResourceManager() throws Exception {
+ /*
+ * Which resource manager?
+ */
- private EventHandler initializeSpecificEventHandler(String classname, String paramName, Class EventHandlerInterface)
- throws Exception
- {
- if ( classname != null && classname.length() > 0)
- {
- Object o = null;
- try {
- o = ClassUtils.getNewInstance(classname);
- }
- catch (ClassNotFoundException cnfe )
- {
- String err = "The specified class for "
- + paramName + " (" + classname
- + ") does not exist or is not accessible to the current classloader.";
- log.error(err);
- throw new Exception(err);
- }
+ String rm = getString(RuntimeConstants.RESOURCE_MANAGER_CLASS);
- if (!EventHandlerInterface.isAssignableFrom(EventHandlerInterface))
- {
- String err = "The specified class for " + paramName + " ("
- + classname + ") does not implement "
- + EventHandlerInterface.getName()
- + "; Velocity is not initialized correctly.";
+ if (rm != null && rm.length() > 0) {
+ /*
+ * if something was specified, then make one. if that isn't a ResourceManager, consider this a huge error and throw
+ */
- log.error(err);
- throw new Exception(err);
- }
+ Object o = null;
- EventHandler ev = (EventHandler) o;
- if ( ev instanceof RuntimeServicesAware )
- ((RuntimeServicesAware) ev).setRuntimeServices(this);
- return ev;
+ try {
+ o = ClassUtils.getNewInstance(rm);
+ }
+ catch (ClassNotFoundException cnfe) {
+ String err = "The specified class for ResourceManager (" + rm + ") does not exist or is not accessible to the current classloader.";
+ log.error(err);
+ throw new Exception(err);
+ }
- } else
- return null;
- }
+ if (!(o instanceof ResourceManager)) {
+ String err = "The specified class for ResourceManager (" + rm + ") does not implement " + ResourceManager.class.getName()
+ + "; Velocity is not initialized correctly.";
- /**
- * Initialize the Velocity logging system.
- *
- * @throws Exception
- */
- private void initializeLog() throws Exception
- {
- // since the Log we started with was just placeholding,
- // let's update it with the real LogChute settings.
- LogManager.updateLog(this.log, this);
- }
+ log.error(err);
+ throw new Exception(err);
+ }
+ resourceManager = (ResourceManager) o;
- /**
- * This methods initializes all the directives
- * that are used by the Velocity Runtime. The
- * directives to be initialized are listed in
- * the RUNTIME_DEFAULT_DIRECTIVES properties
- * file.
- *
- * @throws Exception
- */
- private void initializeDirectives()
- throws Exception
- {
- /*
- * Initialize the runtime directive table.
- * This will be used for creating parsers.
- */
- runtimeDirectives = new Hashtable();
+ resourceManager.initialize(this);
+ }
+ else {
+ /*
+ * someone screwed up. Lets not fool around...
+ */
- Properties directiveProperties = new Properties();
+ String err = "It appears that no class was specified as the" + " ResourceManager. Please ensure that all configuration"
+ + " information is correct.";
- /*
- * Grab the properties file with the list of directives
- * that we should initialize.
- */
+ log.error(err);
+ throw new Exception(err);
+ }
+ }
- InputStream inputStream = null;
+ private void initializeEventHandlers() throws Exception {
- try
- {
- inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_DIRECTIVES);
+ eventCartridge = new EventCartridge();
- if (inputStream == null)
- {
- throw new Exception("Error loading directive.properties! " +
- "Something is very wrong if these properties " +
- "aren't being located. Either your Velocity " +
- "distribution is incomplete or your Velocity " +
- "jar file is corrupted!");
- }
+ /**
+ * For each type of event handler, get the class name, instantiate it, and store it.
+ */
- directiveProperties.load(inputStream);
+ String[] referenceinsertion = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION);
+ if (referenceinsertion != null) {
+ for (int i = 0; i < referenceinsertion.length; i++) {
+ EventHandler ev = initializeSpecificEventHandler(referenceinsertion[i], RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,
+ ReferenceInsertionEventHandler.class);
+ if (ev != null) eventCartridge.addReferenceInsertionEventHandler((ReferenceInsertionEventHandler) ev);
+ }
+ }
- }
- catch (IOException ioe)
- {
- log.error("Error while loading directive properties!", ioe);
- }
- finally
- {
- try
- {
- if (inputStream != null)
- {
- inputStream.close();
- }
- }
- catch (IOException ioe)
- {
- log.error("Cannot close directive properties!", ioe);
- }
- }
+ String[] nullset = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_NULLSET);
+ if (nullset != null) {
+ for (int i = 0; i < nullset.length; i++) {
+ EventHandler ev = initializeSpecificEventHandler(nullset[i], RuntimeConstants.EVENTHANDLER_NULLSET, NullSetEventHandler.class);
+ if (ev != null) eventCartridge.addNullSetEventHandler((NullSetEventHandler) ev);
+ }
+ }
+ String[] methodexception = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION);
+ if (methodexception != null) {
+ for (int i = 0; i < methodexception.length; i++) {
+ EventHandler ev = initializeSpecificEventHandler(methodexception[i], RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,
+ MethodExceptionEventHandler.class);
+ if (ev != null) eventCartridge.addMethodExceptionHandler((MethodExceptionEventHandler) ev);
+ }
+ }
- /*
- * Grab all the values of the properties. These
- * are all class names for example:
- *
- * org.apache.velocity.runtime.directive.Foreach
- */
- Enumeration directiveClasses = directiveProperties.elements();
+ String[] includeHandler = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INCLUDE);
+ if (includeHandler != null) {
+ for (int i = 0; i < includeHandler.length; i++) {
+ EventHandler ev = initializeSpecificEventHandler(includeHandler[i], RuntimeConstants.EVENTHANDLER_INCLUDE, IncludeEventHandler.class);
+ if (ev != null) eventCartridge.addIncludeEventHandler((IncludeEventHandler) ev);
+ }
+ }
- while (directiveClasses.hasMoreElements())
- {
- String directiveClass = (String) directiveClasses.nextElement();
- loadDirective(directiveClass);
- log.debug("Loaded System Directive: " + directiveClass);
- }
+ String[] invalidReferenceSet = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES);
+ if (invalidReferenceSet != null) {
+ for (int i = 0; i < invalidReferenceSet.length; i++) {
+ EventHandler ev = initializeSpecificEventHandler(invalidReferenceSet[i], RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES,
+ InvalidReferenceEventHandler.class);
+ if (ev != null) {
+ eventCartridge.addInvalidReferenceEventHandler((InvalidReferenceEventHandler) ev);
+ }
+ }
+ }
- /*
- * now the user's directives
- */
+ }
- String[] userdirective = configuration.getStringArray("userdirective");
+ private EventHandler initializeSpecificEventHandler(String classname, String paramName, Class EventHandlerInterface) throws Exception {
+ if (classname != null && classname.length() > 0) {
+ Object o = null;
+ try {
+ o = ClassUtils.getNewInstance(classname);
+ }
+ catch (ClassNotFoundException cnfe) {
+ String err = "The specified class for " + paramName + " (" + classname + ") does not exist or is not accessible to the current classloader.";
+ log.error(err);
+ throw new Exception(err);
+ }
- for( int i = 0; i < userdirective.length; i++)
- {
- loadDirective(userdirective[i]);
- if (log.isDebugEnabled())
- {
- log.debug("Loaded User Directive: " + userdirective[i]);
- }
- }
+ if (!EventHandlerInterface.isAssignableFrom(EventHandlerInterface)) {
+ String err = "The specified class for " + paramName + " (" + classname + ") does not implement " + EventHandlerInterface.getName()
+ + "; Velocity is not initialized correctly.";
- }
+ log.error(err);
+ throw new Exception(err);
+ }
- /**
- * Programatically add a directive.
- * @param directive
- */
- public void addDirective(Directive directive)
- {
- runtimeDirectives.put(directive.getName(), directive);
- }
+ EventHandler ev = (EventHandler) o;
+ if (ev instanceof RuntimeServicesAware) ((RuntimeServicesAware) ev).setRuntimeServices(this);
+ return ev;
- /**
- * Retrieve a previously instantiated directive.
- * @param name name of the directive
- * @return
- */
- public Directive getDirective(String name)
- {
- return (Directive) runtimeDirectives.get(name);
- }
+ }
+ else return null;
+ }
- /**
- * Remove a directive.
- * @param name name of the directive.
- */
- public void removeDirective(String name)
- {
- runtimeDirectives.remove(name);
- }
+ /**
+ * Initialize the Velocity logging system.
+ *
+ * @throws Exception
+ */
+ private void initializeLog() throws Exception {
+ // since the Log we started with was just placeholding,
+ // let's update it with the real LogChute settings.
+ LogManager.updateLog(this.log, this);
+ }
- /**
- * instantiates and loads the directive with some basic checks
- *
- * @param directiveClass classname of directive to load
- */
- private void loadDirective(String directiveClass)
- {
- try
- {
- Object o = ClassUtils.getNewInstance( directiveClass );
+ /**
+ * This methods initializes all the directives that are used by the Velocity Runtime. The directives to be initialized are listed in the
+ * RUNTIME_DEFAULT_DIRECTIVES properties file.
+ *
+ * @throws Exception
+ */
+ private void initializeDirectives() throws Exception {
+ /*
+ * Initialize the runtime directive table. This will be used for creating parsers.
+ */
+ runtimeDirectives = new Hashtable();
- if (o instanceof Directive)
- {
- Directive directive = (Directive) o;
- addDirective(directive);
- }
- else
- {
- log.error(directiveClass + " does not implement "
- + Directive.class.getName() + "; it cannot be loaded.");
- }
- }
- // The ugly threesome: ClassNotFoundException,
- // IllegalAccessException, InstantiationException.
- // Ignore Findbugs complaint for now.
- catch (Exception e)
- {
- log.error("Failed to load Directive: " + directiveClass, e);
- }
- }
+ Properties directiveProperties = new Properties();
+ /*
+ * Grab the properties file with the list of directives that we should initialize.
+ */
- /**
- * Initializes the Velocity parser pool.
- */
- private void initializeParserPool() throws Exception
- {
- /*
- * Which parser pool?
- */
- String pp = getString(RuntimeConstants.PARSER_POOL_CLASS);
+ InputStream inputStream = null;
- if (pp != null && pp.length() > 0)
- {
- /*
- * if something was specified, then make one.
- * if that isn't a ParserPool, consider
- * this a huge error and throw
- */
+ try {
+ inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_DIRECTIVES);
- Object o = null;
+ if (inputStream == null) { throw new Exception("Error loading directive.properties! " + "Something is very wrong if these properties "
+ + "aren't being located. Either your Velocity " + "distribution is incomplete or your Velocity " + "jar file is corrupted!"); }
- try
- {
- o = ClassUtils.getNewInstance( pp );
- }
- catch (ClassNotFoundException cnfe )
- {
- String err = "The specified class for ParserPool ("
- + pp
- + ") does not exist (or is not accessible to the current classloader.";
- log.error(err);
- throw new Exception(err);
- }
+ directiveProperties.load(inputStream);
- if (!(o instanceof ParserPool))
- {
- String err = "The specified class for ParserPool ("
- + pp + ") does not implement " + ParserPool.class
- + " Velocity not initialized correctly.";
+ }
+ catch (IOException ioe) {
+ log.error("Error while loading directive properties!", ioe);
+ }
+ finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ catch (IOException ioe) {
+ log.error("Cannot close directive properties!", ioe);
+ }
+ }
- log.error(err);
- throw new Exception(err);
- }
+ /*
+ * Grab all the values of the properties. These are all class names for example:
+ *
+ * org.apache.velocity.runtime.directive.Foreach
+ */
+ Enumeration directiveClasses = directiveProperties.elements();
- parserPool = (ParserPool) o;
+ while (directiveClasses.hasMoreElements()) {
+ String directiveClass = (String) directiveClasses.nextElement();
+ loadDirective(directiveClass);
+ log.debug("Loaded System Directive: " + directiveClass);
+ }
- parserPool.initialize(this);
- }
- else
- {
- /*
- * someone screwed up. Lets not fool around...
- */
+ /*
+ * now the user's directives
+ */
- String err = "It appears that no class was specified as the"
- + " ParserPool. Please ensure that all configuration"
- + " information is correct.";
+ String[] userdirective = configuration.getStringArray("userdirective");
- log.error(err);
- throw new Exception( err );
- }
+ for (int i = 0; i < userdirective.length; i++) {
+ loadDirective(userdirective[i]);
+ if (log.isDebugEnabled()) {
+ log.debug("Loaded User Directive: " + userdirective[i]);
+ }
+ }
- }
+ }
- /**
- * Returns a JavaCC generated Parser.
- *
- * @return Parser javacc generated parser
- */
- public Parser createNewParser()
- {
- /* must be initialized before we use runtimeDirectives */
- if (!initialized && !initializing)
- {
- log.debug("Velocity was not initialized! Calling init()...");
- try
- {
- init();
- }
- catch (Exception e)
- {
- getLog().error("Could not auto-initialize Velocity", e);
- throw new IllegalStateException("Velocity could not be initialized!");
- }
- }
+ /**
+ * Programatically add a directive.
+ *
+ * @param directive
+ */
+ public void addDirective(Directive directive) {
+ runtimeDirectives.put(directive.getName(), directive);
+ }
- Parser parser = new Parser(this);
- parser.setDirectives(runtimeDirectives);
- return parser;
- }
+ /**
+ * Retrieve a previously instantiated directive.
+ *
+ * @param name
+ * name of the directive
+ * @return
+ */
+ public Directive getDirective(String name) {
+ return (Directive) runtimeDirectives.get(name);
+ }
- /**
- * Parse the input and return the root of
- * AST node structure.
- * <br><br>
- * In the event that it runs out of parsers in the
- * pool, it will create and let them be GC'd
- * dynamically, logging that it has to do that. This
- * is considered an exceptional condition. It is
- * expected that the user will set the
- * PARSER_POOL_SIZE property appropriately for their
- * application. We will revisit this.
- *
- * @param reader Reader retrieved by a resource loader
- * @param templateName name of the template being parsed
- * @return A root node representing the template as an AST tree.
- * @throws ParseException When the template could not be parsed.
- */
- public SimpleNode parse(Reader reader, String templateName)
- throws ParseException
- {
- /*
- * do it and dump the VM namespace for this template
- */
- return parse(reader, templateName, true);
- }
+ /**
+ * Remove a directive.
+ *
+ * @param name
+ * name of the directive.
+ */
+ public void removeDirective(String name) {
+ runtimeDirectives.remove(name);
+ }
- /**
- * Parse the input and return the root of the AST node structure.
- *
- * @param reader Reader retrieved by a resource loader
- * @param templateName name of the template being parsed
- * @param dumpNamespace flag to dump the Velocimacro namespace for this template
- * @return A root node representing the template as an AST tree.
- * @throws ParseException When the template could not be parsed.
- */
- public SimpleNode parse(Reader reader, String templateName, boolean dumpNamespace)
- throws ParseException
- {
- /* must be initialized before using parserPool */
- if (!initialized && !initializing)
- {
- log.debug("Velocity was not initialized! Calling init()...");
- try
- {
- init();
- }
- catch (Exception e)
- {
- getLog().error("Could not auto-initialize Velocity", e);
- throw new IllegalStateException("Velocity could not be initialized!");
- }
- }
+ /**
+ * instantiates and loads the directive with some basic checks
+ *
+ * @param directiveClass
+ * classname of directive to load
+ */
+ private void loadDirective(String directiveClass) {
+ try {
+ Object o = ClassUtils.getNewInstance(directiveClass);
- SimpleNode ast = null;
- Parser parser = (Parser) parserPool.get();
+ if (o instanceof Directive) {
+ Directive directive = (Directive) o;
+ addDirective(directive);
+ }
+ else {
+ log.error(directiveClass + " does not implement " + Directive.class.getName() + "; it cannot be loaded.");
+ }
+ }
+ // The ugly threesome: ClassNotFoundException,
+ // IllegalAccessException, InstantiationException.
+ // Ignore Findbugs complaint for now.
+ catch (Exception e) {
+ log.error("Failed to load Directive: " + directiveClass, e);
+ }
+ }
- if (parser == null)
- {
- /*
- * if we couldn't get a parser from the pool
- * make one and log it.
- */
+ /**
+ * Initializes the Velocity parser pool.
+ */
+ private void initializeParserPool() throws Exception {
+ /*
+ * Which parser pool?
+ */
+ String pp = getString(RuntimeConstants.PARSER_POOL_CLASS);
- if (log.isInfoEnabled())
- {
- log.info("Runtime : ran out of parsers. Creating a new one. "
- + " Please increment the parser.pool.size property."
- + " The current value is too small.");
- }
+ if (pp != null && pp.length() > 0) {
+ /*
+ * if something was specified, then make one. if that isn't a ParserPool, consider this a huge error and throw
+ */
- parser = createNewParser();
+ Object o = null;
- }
+ try {
+ o = ClassUtils.getNewInstance(pp);
+ }
+ catch (ClassNotFoundException cnfe) {
+ String err = "The specified class for ParserPool (" + pp + ") does not exist (or is not accessible to the current classloader.";
+ log.error(err);
+ throw new Exception(err);
+ }
- /*
- * now, if we have a parser
- */
+ if (!(o instanceof ParserPool)) {
+ String err = "The specified class for ParserPool (" + pp + ") does not implement " + ParserPool.class + " Velocity not initialized correctly.";
- if (parser != null)
- {
- try
- {
- /*
- * dump namespace if we are told to. Generally, you want to
- * do this - you don't in special circumstances, such as
- * when a VM is getting init()-ed & parsed
- */
+ log.error(err);
+ throw new Exception(err);
+ }
- if (dumpNamespace)
- {
- dumpVMNamespace(templateName);
- }
+ parserPool = (ParserPool) o;
- ast = parser.parse(reader, templateName);
- }
- finally
- {
- /*
- * put it back
- */
- parserPool.put(parser);
+ parserPool.initialize(this);
+ }
+ else {
+ /*
+ * someone screwed up. Lets not fool around...
+ */
- }
- }
- else
- {
- log.error("Runtime : ran out of parsers and unable to create more.");
- }
- return ast;
- }
+ String err = "It appears that no class was specified as the" + " ParserPool. Please ensure that all configuration" + " information is correct.";
- /**
- * Renders the input string using the context into the output writer.
- * To be used when a template is dynamically constructed, or want to use
- * Velocity as a token replacer.
- *
- * @param context context to use in rendering input string
- * @param out Writer in which to render the output
- * @param logTag string to be used as the template name for log
- * messages in case of error
- * @param instring input string containing the VTL to be rendered
- *
- * @return true if successful, false otherwise. If false, see
- * Velocity runtime log
- * @throws ParseErrorException The template could not be parsed.
- * @throws MethodInvocationException A method on a context object could not be invoked.
- * @throws ResourceNotFoundException A referenced resource could not be loaded.
- * @throws IOException While rendering to the writer, an I/O problem occured.
- * @since Velocity 1.6
- */
- public boolean evaluate(Context context, Writer out,
- String logTag, String instring) throws IOException
- {
- return evaluate(context, out, logTag,
- new BufferedReader(new StringReader(instring)));
- }
+ log.error(err);
+ throw new Exception(err);
+ }
- /**
- * Renders the input reader using the context into the output writer.
- * To be used when a template is dynamically constructed, or want to
- * use Velocity as a token replacer.
- *
- * @param context context to use in rendering input string
- * @param writer Writer in which to render the output
- * @param logTag string to be used as the template name for log messages
- * in case of error
- * @param reader Reader containing the VTL to be rendered
- *
- * @return true if successful, false otherwise. If false, see
- * Velocity runtime log
- * @throws ParseErrorException The template could not be parsed.
- * @throws MethodInvocationException A method on a context object could not be invoked.
- * @throws ResourceNotFoundException A referenced resource could not be loaded.
- * @throws IOException While reading from the reader or rendering to the writer,
- * an I/O problem occured.
- * @since Velocity 1.6
- */
- public boolean evaluate(Context context, Writer writer,
- String logTag, Reader reader) throws IOException
- {
- if (logTag == null)
- {
- throw new NullPointerException("logTag (i.e. template name) cannot be null, you must provide an identifier for the content being evaluated");
- }
+ }
- SimpleNode nodeTree = null;
- try
- {
- nodeTree = parse(reader, logTag);
- }
- catch (ParseException pex)
- {
- throw new ParseErrorException(pex);
- }
- catch (TemplateInitException pex)
- {
- throw new ParseErrorException(pex);
- }
+ /**
+ * Returns a JavaCC generated Parser.
+ *
+ * @return Parser javacc generated parser
+ */
+ public Parser createNewParser() {
+ /* must be initialized before we use runtimeDirectives */
+ if (!initialized && !initializing) {
+ log.debug("Velocity was not initialized! Calling init()...");
+ try {
+ init();
+ }
+ catch (Exception e) {
+ getLog().error("Could not auto-initialize Velocity", e);
+ throw new IllegalStateException("Velocity could not be initialized!");
+ }
+ }
- if (nodeTree == null)
- {
- return false;
- }
- else
- {
- return render(context, writer, logTag, nodeTree);
- }
- }
+ Parser parser = new Parser(this);
+ parser.setDirectives(runtimeDirectives);
+ return parser;
+ }
+ /**
+ * Parse the input and return the root of AST node structure. <br>
+ * <br>
+ * In the event that it runs out of parsers in the pool, it will create and let them be GC'd dynamically, logging that it has to do that. This is considered
+ * an exceptional condition. It is expected that the user will set the PARSER_POOL_SIZE property appropriately for their application. We will revisit this.
+ *
+ * @param reader
+ * Reader retrieved by a resource loader
+ * @param templateName
+ * name of the template being parsed
+ * @return A root node representing the template as an AST tree.
+ * @throws ParseException
+ * When the template could not be parsed.
+ */
+ public SimpleNode parse(Reader reader, String templateName) throws ParseException {
+ /*
+ * do it and dump the VM namespace for this template
+ */
+ return parse(reader, templateName, true);
+ }
- /**
- * Initializes and renders the AST {@link SimpleNode} using the context
- * into the output writer.
- *
- * @param context context to use in rendering input string
- * @param writer Writer in which to render the output
- * @param logTag string to be used as the template name for log messages
- * in case of error
- * @param nodeTree SimpleNode which is the root of the AST to be rendered
- *
- * @return true if successful, false otherwise. If false, see
- * Velocity runtime log for errors
- * @throws ParseErrorException The template could not be parsed.
- * @throws MethodInvocationException A method on a context object could not be invoked.
- * @throws ResourceNotFoundException A referenced resource could not be loaded.
- * @throws IOException While rendering to the writer, an I/O problem occured.
- * @since Velocity 1.6
- */
- public boolean render(Context context, Writer writer,
- String logTag, SimpleNode nodeTree) throws IOException
- {
- /*
- * we want to init then render
- */
- InternalContextAdapterImpl ica =
- new InternalContextAdapterImpl(context);
+ /**
+ * Parse the input and return the root of the AST node structure.
+ *
+ * @param reader
+ * Reader retrieved by a resource loader
+ * @param templateName
+ * name of the template being parsed
+ * @param dumpNamespace
+ * flag to dump the Velocimacro namespace for this template
+ * @return A root node representing the template as an AST tree.
+ * @throws ParseException
+ * When the template could not be parsed.
+ */
+ public SimpleNode parse(Reader reader, String templateName, boolean dumpNamespace) throws ParseException {
+ /* must be initialized before using parserPool */
+ if (!initialized && !initializing) {
+ log.debug("Velocity was not initialized! Calling init()...");
+ try {
+ init();
+ }
+ catch (Exception e) {
+ getLog().error("Could not auto-initialize Velocity", e);
+ throw new IllegalStateException("Velocity could not be initialized!");
+ }
+ }
- ica.pushCurrentTemplateName(logTag);
+ SimpleNode ast = null;
+ Parser parser = (Parser) parserPool.get();
- try
- {
- try
- {
- nodeTree.init(ica, this);
- }
- catch (TemplateInitException pex)
- {
- throw new ParseErrorException(pex);
- }
- /**
- * pass through application level runtime exceptions
- */
- catch(RuntimeException e)
- {
- throw e;
- }
- catch(Exception e)
- {
- getLog().error("RuntimeInstance.render(): init exception for tag = "
- + logTag, e);
- }
+ if (parser == null) {
+ /*
+ * if we couldn't get a parser from the pool make one and log it.
+ */
- /*
- * now render, and let any exceptions fly
- */
- nodeTree.render(ica, writer);
- }
- finally
- {
- ica.popCurrentTemplateName();
- }
+ if (log.isInfoEnabled()) {
+ log.info("Runtime : ran out of parsers. Creating a new one. " + " Please increment the parser.pool.size property."
+ + " The current value is too small.");
+ }
- return true;
- }
+ parser = createNewParser();
- /**
- * Invokes a currently registered Velocimacro with the params provided
- * and places the rendered stream into the writer.
- * <br>
- * Note : currently only accepts args to the VM if they are in the context.
- *
- * @param vmName name of Velocimacro to call
- * @param logTag string to be used for template name in case of error. if null,
- * the vmName will be used
- * @param params keys for args used to invoke Velocimacro, in java format
- * rather than VTL (eg "foo" or "bar" rather than "$foo" or "$bar")
- * @param context Context object containing data/objects used for rendering.
- * @param writer Writer for output stream
- * @return true if Velocimacro exists and successfully invoked, false otherwise.
- * @throws IOException While rendering to the writer, an I/O problem occured.
- */
- public boolean invokeVelocimacro(final String vmName, String logTag,
- String[] params, final Context context,
- final Writer writer)
- throws IOException
- {
- /* check necessary parameters */
- if (vmName == null || context == null || writer == null)
- {
- getLog().error("RuntimeInstance.invokeVelocimacro() : invalid call : vmName, context, and writer must not be null");
- return false;
- }
+ }
- /* handle easily corrected parameters */
- if (logTag == null)
- {
- logTag = vmName;
- }
- if (params == null)
- {
- params = new String[0];
- }
+ /*
+ * now, if we have a parser
+ */
- /* does the VM exist? */
- if (!isVelocimacro(vmName, logTag))
- {
- getLog().error("RuntimeInstance.invokeVelocimacro() : VM '" + vmName
- + "' is not registered.");
- return false;
- }
+ if (parser != null) {
+ try {
+ /*
+ * dump namespace if we are told to. Generally, you want to do this - you don't in special circumstances, such as when a VM is getting init()-ed &
+ * parsed
+ */
- /* now just create the VM call, and use evaluate */
- StringBuffer template = new StringBuffer("#");
- template.append(vmName);
- template.append("(");
- for( int i = 0; i < params.length; i++)
- {
- template.append(" $");
- template.append(params[i]);
- }
- template.append(" )");
+ if (dumpNamespace) {
+ dumpVMNamespace(templateName);
+ }
- return evaluate(context, writer, logTag, template.toString());
- }
+ ast = parser.parse(reader, templateName);
+ }
+ finally {
+ /*
+ * put it back
+ */
+ parserPool.put(parser);
- /**
- * Returns a <code>Template</code> from the resource manager.
- * This method assumes that the character encoding of the
- * template is set by the <code>input.encoding</code>
- * property. The default is "ISO-8859-1"
- *
- * @param name The file name of the desired template.
- * @return The template.
- * @throws ResourceNotFoundException if template not found
- * from any available source.
- * @throws ParseErrorException if template cannot be parsed due
- * to syntax (or other) error.
- * @throws Exception if an error occurs in template initialization
- */
- public Template getTemplate(String name)
- throws ResourceNotFoundException, ParseErrorException, Exception
- {
- return getTemplate(name, getString( INPUT_ENCODING, ENCODING_DEFAULT));
- }
+ }
+ }
+ else {
+ log.error("Runtime : ran out of parsers and unable to create more.");
+ }
+ return ast;
+ }
- /**
- * Returns a <code>Template</code> from the resource manager
- *
- * @param name The name of the desired template.
- * @param encoding Character encoding of the template
- * @return The template.
- * @throws ResourceNotFoundException if template not found
- * from any available source.
- * @throws ParseErrorException if template cannot be parsed due
- * to syntax (or other) error.
- * @throws Exception if an error occurs in template initialization
- */
- public Template getTemplate(String name, String encoding)
- throws ResourceNotFoundException, ParseErrorException, Exception
- {
- /* must be initialized before using resourceManager */
- if (!initialized && !initializing)
- {
- log.debug("Velocity not initialized yet. Calling init()...");
- init();
- }
+ /**
+ * Renders the input string using the context into the output writer. To be used when a template is dynamically constructed, or want to use Velocity as a
+ * token replacer.
+ *
+ * @param context
+ * context to use in rendering input string
+ * @param out
+ * Writer in which to render the output
+ * @param logTag
+ * string to be used as the template name for log messages in case of error
+ * @param instring
+ * input string containing the VTL to be rendered
+ *
+ * @return true if successful, false otherwise. If false, see Velocity runtime log
+ * @throws ParseErrorException
+ * The template could not be parsed.
+ * @throws MethodInvocationException
+ * A method on a context object could not be invoked.
+ * @throws ResourceNotFoundException
+ * A referenced resource could not be loaded.
+ * @throws IOException
+ * While rendering to the writer, an I/O problem occured.
+ * @since Velocity 1.6
+ */
+ public boolean evaluate(Context context, Writer out, String logTag, String instring) throws IOException {
+ return evaluate(context, out, logTag, new BufferedReader(new StringReader(instring)));
+ }
- return (Template)
- resourceManager.getResource(name,
- ResourceManager.RESOURCE_TEMPLATE, encoding);
- }
+ /**
+ * Renders the input reader using the context into the output writer. To be used when a template is dynamically constructed, or want to use Velocity as a
+ * token replacer.
+ *
+ * @param context
+ * context to use in rendering input string
+ * @param writer
+ * Writer in which to render the output
+ * @param logTag
+ * string to be used as the template name for log messages in case of error
+ * @param reader
+ * Reader containing the VTL to be rendered
+ *
+ * @return true if successful, false otherwise. If false, see Velocity runtime log
+ * @throws ParseErrorException
+ * The template could not be parsed.
+ * @throws MethodInvocationException
+ * A method on a context object could not be invoked.
+ * @throws ResourceNotFoundException
+ * A referenced resource could not be loaded.
+ * @throws IOException
+ * While reading from the reader or rendering to the writer, an I/O problem occured.
+ * @since Velocity 1.6
+ */
+ public boolean evaluate(Context context, Writer writer, String logTag, Reader reader) throws IOException {
+ if (logTag == null) { throw new NullPointerException(
+ "logTag (i.e. template name) cannot be null, you must provide an identifier for the content being evaluated"); }
- /**
- * Returns a static content resource from the
- * resource manager. Uses the current value
- * if INPUT_ENCODING as the character encoding.
- *
- * @param name Name of content resource to get
- * @return parsed ContentResource object ready for use
- * @throws ResourceNotFoundException if template not found
- * from any available source.
- * @throws ParseErrorException When the template could not be parsed.
- * @throws Exception Any other error.
- */
- public ContentResource getContent(String name)
- throws ResourceNotFoundException, ParseErrorException, Exception
- {
- /*
- * the encoding is irrelvant as we don't do any converstion
- * the bytestream should be dumped to the output stream
- */
+ SimpleNode nodeTree = null;
+ try {
+ nodeTree = parse(reader, logTag);
+ }
+ catch (ParseException pex) {
+ throw new ParseErrorException(pex);
+ }
+ catch (TemplateInitException pex) {
+ throw new ParseErrorException(pex);
+ }
- return getContent(name, getString( INPUT_ENCODING, ENCODING_DEFAULT));
- }
+ if (nodeTree == null) {
+ return false;
+ }
+ else {
+ return render(context, writer, logTag, nodeTree);
+ }
+ }
- /**
- * Returns a static content resource from the
- * resource manager.
- *
- * @param name Name of content resource to get
- * @param encoding Character encoding to use
- * @return parsed ContentResource object ready for use
- * @throws ResourceNotFoundException if template not found
- * from any available source.
- * @throws ParseErrorException When the template could not be parsed.
- * @throws Exception Any other error.
- */
- public ContentResource getContent(String name, String encoding)
- throws ResourceNotFoundException, ParseErrorException, Exception
- {
- /* must be initialized before using resourceManager */
- if (!initialized && !initializing)
- {
- log.debug("Velocity not initialized yet. Calling init()...");
- init();
- }
+ /**
+ * Initializes and renders the AST {@link SimpleNode} using the context into the output writer.
+ *
+ * @param context
+ * context to use in rendering input string
+ * @param writer
+ * Writer in which to render the output
+ * @param logTag
+ * string to be used as the template name for log messages in case of error
+ * @param nodeTree
+ * SimpleNode which is the root of the AST to be rendered
+ *
+ * @return true if successful, false otherwise. If false, see Velocity runtime log for errors
+ * @throws ParseErrorException
+ * The template could not be parsed.
+ * @throws MethodInvocationException
+ * A method on a context object could not be invoked.
+ * @throws ResourceNotFoundException
+ * A referenced resource could not be loaded.
+ * @throws IOException
+ * While rendering to the writer, an I/O problem occured.
+ * @since Velocity 1.6
+ */
+ public boolean render(Context context, Writer writer, String logTag, SimpleNode nodeTree) throws IOException {
+ /*
+ * we want to init then render
+ */
+ InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
- return (ContentResource)
- resourceManager.getResource(name,
- ResourceManager.RESOURCE_CONTENT, encoding);
- }
+ ica.pushCurrentTemplateName(logTag);
+ try {
+ try {
+ nodeTree.init(ica, this);
+ }
+ catch (TemplateInitException pex) {
+ throw new ParseErrorException(pex);
+ }
+ /**
+ * pass through application level runtime exceptions
+ */
+ catch (RuntimeException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ getLog().error("RuntimeInstance.render(): init exception for tag = " + logTag, e);
+ }
- /**
- * Determines if a template exists and returns name of the loader that
- * provides it. This is a slightly less hokey way to support
- * the Velocity.resourceExists() utility method, which was broken
- * when per-template encoding was introduced. We can revisit this.
- *
- * @param resourceName Name of template or content resource
- * @return class name of loader than can provide it
- */
- public String getLoaderNameForResource(String resourceName)
- {
- /* must be initialized before using resourceManager */
- if (!initialized && !initializing)
- {
- log.debug("Velocity was not initialized! Calling init()...");
- try
- {
- init();
- }
- catch (Exception e)
- {
- getLog().error("Could not initialize Velocity", e);
- throw new IllegalStateException("Velocity could not be initialized!");
- }
- }
+ /*
+ * now render, and