| package org.apache.velocity.runtime; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.commons.collections.ExtendedProperties; |
| import org.apache.velocity.Template; |
| import org.apache.velocity.app.event.EventCartridge; |
| import org.apache.velocity.app.event.EventHandler; |
| import org.apache.velocity.app.event.IncludeEventHandler; |
| import org.apache.velocity.app.event.InvalidReferenceEventHandler; |
| import org.apache.velocity.app.event.MethodExceptionEventHandler; |
| import org.apache.velocity.app.event.ReferenceInsertionEventHandler; |
| import org.apache.velocity.context.Context; |
| import org.apache.velocity.context.InternalContextAdapterImpl; |
| import org.apache.velocity.exception.MethodInvocationException; |
| import org.apache.velocity.exception.ParseErrorException; |
| import org.apache.velocity.exception.ResourceNotFoundException; |
| import org.apache.velocity.exception.TemplateInitException; |
| import org.apache.velocity.exception.VelocityException; |
| import org.apache.velocity.runtime.directive.Directive; |
| import org.apache.velocity.runtime.directive.Macro; |
| import org.apache.velocity.runtime.directive.Scope; |
| import org.apache.velocity.runtime.directive.StopCommand; |
| import org.apache.velocity.runtime.parser.ParseException; |
| import org.apache.velocity.runtime.parser.Parser; |
| import org.apache.velocity.runtime.parser.node.Node; |
| import org.apache.velocity.runtime.parser.node.SimpleNode; |
| import org.apache.velocity.runtime.resource.ContentResource; |
| import org.apache.velocity.runtime.resource.ResourceManager; |
| import org.apache.velocity.util.ClassUtils; |
| import org.apache.velocity.util.ExtProperties; |
| import org.apache.velocity.util.RuntimeServicesAware; |
| import org.apache.velocity.util.StringUtils; |
| import org.apache.velocity.util.introspection.ChainableUberspector; |
| import org.apache.velocity.util.introspection.Introspector; |
| import org.apache.velocity.util.introspection.LinkingUberspector; |
| import org.apache.velocity.util.introspection.Uberspect; |
| import org.apache.velocity.util.introspection.UberspectLoggable; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.Writer; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| /** |
| * 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, which can make all needed setProperty() calls |
| * before calling init(). |
| * |
| * ----------------------------------------------------------------------- |
| * 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. |
| * ----------------------------------------------------------------------- |
| * 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 |
| * default property. |
| * ----------------------------------------------------------------------- |
| * </pre> |
| * |
| * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> |
| * @author <a href="mailto:jlb@houseofdistraction.com">Jeff Bowden</a> |
| * @author <a href="mailto:geirm@optonline.net">Geir Magusson Jr.</a> |
| * @version $Id$ |
| */ |
| public class RuntimeInstance implements RuntimeConstants, RuntimeServices |
| { |
| /** |
| * VelocimacroFactory object to manage VMs |
| */ |
| private VelocimacroFactory vmFactory = null; |
| |
| /** |
| * The Runtime logger. The default instance is the "Velocity" logger. |
| */ |
| private Logger log = LoggerFactory.getLogger("Velocity"); |
| |
| /** |
| * 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 has been fully initialized. |
| */ |
| private volatile boolean initialized = false; |
| |
| /** |
| * These are the properties that are laid down over top |
| * of the default properties when requested. |
| */ |
| private ExtProperties overridingProperties = null; |
| |
| /** |
| * This is a hashtable of initialized directives. |
| * The directives that populate this hashtable are |
| * taken from the RUNTIME_DEFAULT_DIRECTIVES |
| * property file. |
| */ |
| private Map runtimeDirectives = new Hashtable(); |
| /** |
| * Copy of the actual runtimeDirectives that is shared between |
| * parsers. Whenever directives are updated, the synchronized |
| * runtimeDirectives is first updated and then an unsynchronized |
| * copy of it is passed to parsers. |
| */ |
| private Map runtimeDirectivesShared; |
| |
| /** |
| * Object that houses the configuration options for |
| * the velocity runtime. The ExtProperties 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 ExtProperties object |
| * using something like the following: |
| * |
| * ExtProperties loaderConfiguration = |
| * configuration.subset(loaderID); |
| * |
| * And a configuration is a lot more convenient to deal |
| * with then conventional properties objects, or Maps. |
| */ |
| private ExtProperties configuration = new ExtProperties(); |
| |
| 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; |
| |
| /* |
| * Each runtime instance has it's own introspector |
| * to ensure that each instance is completely separate. |
| */ |
| private Introspector introspector = null; |
| |
| /* |
| * Settings for provision of root scope for evaluate(...) calls. |
| */ |
| private String evaluateScopeName = "evaluate"; |
| private boolean provideEvaluateScope = false; |
| |
| /* |
| * Opaque reference to something specified by the |
| * application for use in application supplied/specified |
| * pluggable components |
| */ |
| private Map applicationAttributes = null; |
| private Uberspect uberSpect; |
| private String encoding; |
| |
| /** |
| * Creates a new RuntimeInstance object. |
| */ |
| public RuntimeInstance() |
| { |
| reset(); |
| } |
| |
| /** |
| * 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> |
| */ |
| public synchronized void init() |
| { |
| if (!initialized && !initializing) |
| { |
| try |
| { |
| log.debug("Initializing Velocity, Calling init()..."); |
| initializing = true; |
| |
| log.trace("*******************************************************************"); |
| log.debug("Starting Apache Velocity v2.0-dev (compiled: 2009-02-05 07:40:05)"); |
| log.trace("RuntimeInstance initializing."); |
| |
| initializeProperties(); |
| initializeLog(); |
| initializeResourceManager(); |
| initializeDirectives(); |
| initializeEventHandlers(); |
| initializeParserPool(); |
| |
| initializeIntrospection(); |
| initializeEvaluateScopeSettings(); |
| /* |
| * initialize the VM Factory. It will use the properties |
| * accessible from Runtime, so keep this here at the end. |
| */ |
| vmFactory.initVelocimacro(); |
| |
| log.trace("RuntimeInstance successfully initialized."); |
| |
| initialized = true; |
| initializing = false; |
| } |
| catch(RuntimeException re) |
| { |
| // initialization failed at some point... try to reset everything |
| try |
| { |
| reset(); |
| } |
| catch(RuntimeException re2) {} // prefer throwing the original exception |
| throw re; |
| } |
| finally |
| { |
| initializing = false; |
| } |
| } |
| } |
| |
| /** |
| * Resets the instance, so Velocity can be re-initialized again. |
| * |
| * @since 2.0.0 |
| */ |
| public synchronized void reset() |
| { |
| this.configuration = new ExtProperties(); |
| this.encoding = null; |
| this.evaluateScopeName = "evaluate"; |
| this.eventCartridge = null; |
| this.initialized = false; |
| this.initializing = false; |
| this.overridingProperties = null; |
| this.parserPool = null; |
| this.provideEvaluateScope = false; |
| this.resourceManager = null; |
| this.runtimeDirectives = new Hashtable(); |
| this.runtimeDirectivesShared = null; |
| this.uberSpect = null; |
| |
| /* |
| * create a VM factory, introspector, and application attributes |
| */ |
| vmFactory = new VelocimacroFactory( this ); |
| |
| /* |
| * make a new introspector and initialize it |
| */ |
| introspector = new Introspector(getLog()); |
| |
| /* |
| * and a store for the application attributes |
| */ |
| applicationAttributes = new HashMap(); |
| } |
| |
| /** |
| * Returns true if the RuntimeInstance has been successfully initialized. |
| * @return True if the RuntimeInstance has been successfully initialized. |
| * @since 1.5 |
| */ |
| public boolean isInitialized() |
| { |
| return initialized; |
| } |
| |
| /** |
| * Init or die! (with some log help, of course) |
| */ |
| private void requireInitialization() |
| { |
| if (!initialized) |
| { |
| try |
| { |
| init(); |
| } |
| catch (Exception e) |
| { |
| getLog().error("Could not auto-initialize Velocity", e); |
| throw new RuntimeException("Velocity could not be initialized!", e); |
| } |
| } |
| } |
| |
| /** |
| * Gets the classname for the Uberspect introspection package and |
| * instantiates an instance. |
| */ |
| private void initializeIntrospection() |
| { |
| String[] uberspectors = configuration.getStringArray(RuntimeConstants.UBERSPECT_CLASSNAME); |
| for (int i=0; i <uberspectors.length;i++) |
| { |
| String rm = uberspectors[i]; |
| Object o = null; |
| |
| 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 VelocityException(err, cnfe); |
| } |
| catch (InstantiationException ie) |
| { |
| throw new VelocityException("Could not instantiate class '" + rm + "'", ie); |
| } |
| catch (IllegalAccessException ae) |
| { |
| throw new VelocityException("Cannot access class '" + rm + "'", ae); |
| } |
| |
| if (!(o instanceof Uberspect)) |
| { |
| String err = "The specified class for Uberspect (" |
| + rm + ") does not implement " + Uberspect.class.getName() |
| + "; Velocity is not initialized correctly."; |
| |
| log.error(err); |
| throw new VelocityException(err); |
| } |
| |
| Uberspect u = (Uberspect)o; |
| |
| if (u instanceof UberspectLoggable) |
| { |
| ((UberspectLoggable)u).setLog(getLog()); |
| } |
| |
| if (u instanceof RuntimeServicesAware) |
| { |
| ((RuntimeServicesAware)u).setRuntimeServices(this); |
| } |
| |
| if (uberSpect == null) |
| { |
| uberSpect = u; |
| } |
| else |
| { |
| if (u instanceof ChainableUberspector) |
| { |
| ((ChainableUberspector)u).wrap(uberSpect); |
| uberSpect = u; |
| } |
| else |
| { |
| uberSpect = new LinkingUberspector(uberSpect,u); |
| } |
| } |
| } |
| |
| if(uberSpect != null) |
| { |
| 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."; |
| |
| log.error(err); |
| throw new VelocityException(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); |
| |
| configuration.load( inputStream ); |
| |
| if (log.isDebugEnabled()) |
| { |
| log.debug("Default Properties File: {}", |
| new File(DEFAULT_RUNTIME_PROPERTIES).getPath()); |
| } |
| |
| |
| } |
| catch (IOException ioe) |
| { |
| String msg = "Cannot get Velocity Runtime default properties!"; |
| log.error(msg, ioe); |
| throw new RuntimeException(msg, ioe); |
| } |
| finally |
| { |
| try |
| { |
| if (inputStream != null) |
| { |
| inputStream.close(); |
| } |
| } |
| catch (IOException ioe) |
| { |
| String msg = "Cannot close Velocity Runtime default properties!"; |
| log.error(msg, ioe); |
| throw new RuntimeException(msg, 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) |
| { |
| if (overridingProperties == null) |
| { |
| overridingProperties = new ExtProperties(); |
| } |
| |
| overridingProperties.setProperty(key, value); |
| } |
| |
| |
| /** |
| * Add all properties contained in the file fileName to the RuntimeInstance properties |
| */ |
| public void setProperties(String fileName) |
| { |
| ExtProperties props = null; |
| try |
| { |
| props = new ExtProperties(fileName); |
| } |
| catch (IOException e) |
| { |
| throw new VelocityException("Error reading properties from '" |
| + fileName + "'", e); |
| } |
| |
| Enumeration en = props.keys(); |
| while (en.hasMoreElements()) |
| { |
| String key = en.nextElement().toString(); |
| setProperty(key, props.get(key)); |
| } |
| } |
| |
| |
| /** |
| * Add all the properties in props to the RuntimeInstance properties |
| */ |
| public void setProperties(Properties props) |
| { |
| Enumeration en = props.keys(); |
| while (en.hasMoreElements()) |
| { |
| String key = en.nextElement().toString(); |
| setProperty(key, props.get(key)); |
| } |
| } |
| |
| /** |
| * 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 |
| * @deprecated use {@link #setConfiguration(ExtProperties)} |
| */ |
| public @Deprecated void setConfiguration( ExtendedProperties configuration) |
| { |
| if (overridingProperties == null) |
| { |
| overridingProperties = ExtProperties.convertProperties(configuration); |
| } |
| else |
| { |
| overridingProperties.combine(ExtProperties.convertProperties(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 |
| * @since 2.0 |
| */ |
| public void setConfiguration( ExtProperties 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 ExtProperties(); |
| } |
| |
| 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); |
| } |
| } |
| |
| /** |
| * 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 && 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; |
| } |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| if( overridingProperties != null) |
| { |
| configuration.combine(overridingProperties); |
| } |
| } |
| |
| /** |
| * Initialize the Velocity Runtime with a Properties |
| * object. |
| * |
| * @param p Velocity properties for initialization |
| */ |
| public void init(Properties p) |
| { |
| setProperties(ExtProperties.convertProperties(p)); |
| init(); |
| } |
| |
| private void setProperties(ExtProperties p) |
| { |
| if (overridingProperties == null) |
| { |
| overridingProperties = p; |
| } |
| else |
| { |
| overridingProperties.combine(p); |
| } |
| } |
| |
| /** |
| * Initialize the Velocity Runtime with the name of |
| * ExtendedProperties object. |
| * |
| * @param configurationFile |
| */ |
| public void init(String configurationFile) |
| { |
| try |
| { |
| setProperties(new ExtProperties(configurationFile)); |
| } |
| catch (IOException e) |
| { |
| throw new VelocityException("Error reading properties from '" |
| + configurationFile + "'", e); |
| } |
| init(); |
| } |
| |
| private void initializeResourceManager() |
| { |
| /* |
| * Which resource manager? |
| */ |
| String rm = getString(RuntimeConstants.RESOURCE_MANAGER_CLASS); |
| |
| 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 |
| */ |
| |
| 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 VelocityException(err, cnfe); |
| } |
| catch (InstantiationException ie) |
| { |
| throw new VelocityException("Could not instantiate class '" + rm + "'", ie); |
| } |
| catch (IllegalAccessException ae) |
| { |
| throw new VelocityException("Cannot access class '" + rm + "'", ae); |
| } |
| |
| if (!(o instanceof ResourceManager)) |
| { |
| String err = "The specified class for ResourceManager (" + rm |
| + ") does not implement " + ResourceManager.class.getName() |
| + "; Velocity is not initialized correctly."; |
| |
| log.error(err); |
| throw new VelocityException(err); |
| } |
| |
| resourceManager = (ResourceManager) o; |
| |
| resourceManager.initialize(this); |
| } |
| else |
| { |
| /* |
| * someone screwed up. Lets not fool around... |
| */ |
| |
| String err = "It appears that no class was specified as the" |
| + " ResourceManager. Please ensure that all configuration" |
| + " information is correct."; |
| |
| log.error(err); |
| throw new VelocityException( err ); |
| } |
| } |
| |
| private void initializeEventHandlers() |
| { |
| |
| 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); |
| } |
| } |
| |
| 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); |
| } |
| } |
| |
| 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); |
| } |
| } |
| |
| 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); |
| } |
| } |
| } |
| |
| |
| } |
| |
| private EventHandler initializeSpecificEventHandler(String classname, String paramName, Class EventHandlerInterface) |
| { |
| 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 VelocityException(err, cnfe); |
| } |
| catch (InstantiationException ie) |
| { |
| throw new VelocityException("Could not instantiate class '" + classname + "'", ie); |
| } |
| catch (IllegalAccessException ae) |
| { |
| throw new VelocityException("Cannot access class '" + classname + "'", ae); |
| } |
| |
| 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 VelocityException(err); |
| } |
| |
| EventHandler ev = (EventHandler) o; |
| if ( ev instanceof RuntimeServicesAware ) |
| ((RuntimeServicesAware) ev).setRuntimeServices(this); |
| return ev; |
| |
| } else |
| return null; |
| } |
| |
| /** |
| * Initialize the Velocity logging system. |
| */ |
| private void initializeLog() |
| { |
| // if we were provided a specific logger or logger name, let's use it |
| try |
| { |
| /* If a Logger instance was set as a configuration |
| * value, use that. This is any class the user specifies. |
| */ |
| Object o = getProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE); |
| if (o != null) |
| { |
| // check for a Logger |
| if (Logger.class.isAssignableFrom(o.getClass())) |
| { |
| //looks ok |
| log = (Logger)o; |
| } |
| else |
| { |
| String msg = o.getClass().getName() + " object set as runtime.log.instance is not a valid org.slf4j.Logger implementation."; |
| log.error(msg); |
| throw new VelocityException(msg); |
| } |
| } |
| else |
| { |
| /* otherwise, see if a logger name was specified. |
| */ |
| o = getProperty(RuntimeConstants.RUNTIME_LOG_NAME); |
| if (o != null) |
| { |
| if (o instanceof String) |
| { |
| log = LoggerFactory.getLogger((String)o); |
| } |
| else |
| { |
| String msg = o.getClass().getName() + " object set as runtime.log.name is not a valid string."; |
| log.error(msg); |
| throw new VelocityException(msg); |
| } |
| } |
| } |
| /* else keep our default Velocity logger |
| */ |
| } |
| catch (Exception e) |
| { |
| throw new VelocityException("Error initializing log: " + e.getMessage(), e); |
| } |
| } |
| |
| |
| /** |
| * 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. |
| */ |
| private void initializeDirectives() |
| { |
| Properties directiveProperties = new Properties(); |
| |
| /* |
| * Grab the properties file with the list of directives |
| * that we should initialize. |
| */ |
| |
| InputStream inputStream = null; |
| |
| try |
| { |
| inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_DIRECTIVES); |
| |
| if (inputStream == null) |
| { |
| throw new VelocityException("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!"); |
| } |
| |
| directiveProperties.load(inputStream); |
| |
| } |
| catch (IOException ioe) |
| { |
| String msg = "Error while loading directive properties!"; |
| log.error(msg, ioe); |
| throw new RuntimeException(msg, ioe); |
| } |
| finally |
| { |
| try |
| { |
| if (inputStream != null) |
| { |
| inputStream.close(); |
| } |
| } |
| catch (IOException ioe) |
| { |
| String msg = "Cannot close directive properties!"; |
| log.error(msg, ioe); |
| throw new RuntimeException(msg, ioe); |
| } |
| } |
| |
| |
| /* |
| * Grab all the values of the properties. These |
| * are all class names for example: |
| * |
| * org.apache.velocity.runtime.directive.Foreach |
| */ |
| Enumeration directiveClasses = directiveProperties.elements(); |
| |
| while (directiveClasses.hasMoreElements()) |
| { |
| String directiveClass = (String) directiveClasses.nextElement(); |
| loadDirective(directiveClass); |
| log.debug("Loaded System Directive: {}", directiveClass); |
| } |
| |
| /* |
| * now the user's directives |
| */ |
| |
| String[] userdirective = configuration.getStringArray("userdirective"); |
| |
| for( int i = 0; i < userdirective.length; i++) |
| { |
| loadDirective(userdirective[i]); |
| if (log.isDebugEnabled()) |
| { |
| log.debug("Loaded User Directive: {}", userdirective[i]); |
| } |
| } |
| |
| } |
| |
| /** |
| * Programatically add a directive. |
| * @param directive |
| */ |
| public synchronized void addDirective(Directive directive) |
| { |
| runtimeDirectives.put(directive.getName(), directive); |
| updateSharedDirectivesMap(); |
| } |
| |
| /** |
| * Retrieve a previously instantiated directive. |
| * @param name name of the directive |
| * @return the {@link Directive} for that name |
| */ |
| public Directive getDirective(String name) |
| { |
| return (Directive) runtimeDirectivesShared.get(name); |
| } |
| |
| /** |
| * Remove a directive. |
| * @param name name of the directive. |
| */ |
| public synchronized void removeDirective(String name) |
| { |
| runtimeDirectives.remove(name); |
| updateSharedDirectivesMap(); |
| } |
| |
| /** |
| * Makes an unsynchronized copy of the directives map |
| * that is used for Directive lookups by all parsers. |
| * |
| * This follows Copy-on-Write pattern. The cost of creating |
| * a new map is acceptable since directives are typically |
| * set and modified only during Velocity setup phase. |
| */ |
| private void updateSharedDirectivesMap() |
| { |
| Map tmp = new HashMap(runtimeDirectives); |
| runtimeDirectivesShared = tmp; |
| } |
| |
| /** |
| * instantiates and loads the directive with some basic checks |
| * |
| * @param directiveClass classname of directive to load |
| */ |
| public void loadDirective(String directiveClass) |
| { |
| try |
| { |
| Object o = ClassUtils.getNewInstance( directiveClass ); |
| |
| if (o instanceof Directive) |
| { |
| Directive directive = (Directive) o; |
| addDirective(directive); |
| } |
| else |
| { |
| String msg = directiveClass + " does not implement " |
| + Directive.class.getName() + "; it cannot be loaded."; |
| log.error(msg); |
| throw new VelocityException(msg); |
| } |
| } |
| // The ugly threesome: ClassNotFoundException, |
| // IllegalAccessException, InstantiationException. |
| // Ignore Findbugs complaint for now. |
| catch (Exception e) |
| { |
| String msg = "Failed to load Directive: " + directiveClass; |
| log.error(msg, e); |
| throw new VelocityException(msg, e); |
| } |
| } |
| |
| |
| /** |
| * Initializes the Velocity parser pool. |
| */ |
| private void initializeParserPool() |
| { |
| /* |
| * Which parser pool? |
| */ |
| String pp = getString(RuntimeConstants.PARSER_POOL_CLASS); |
| |
| 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 |
| */ |
| |
| 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 VelocityException(err, cnfe); |
| } |
| catch (InstantiationException ie) |
| { |
| throw new VelocityException("Could not instantiate class '" + pp + "'", ie); |
| } |
| catch (IllegalAccessException ae) |
| { |
| throw new VelocityException("Cannot access class '" + pp + "'", ae); |
| } |
| |
| if (!(o instanceof ParserPool)) |
| { |
| String err = "The specified class for ParserPool (" |
| + pp + ") does not implement " + ParserPool.class |
| + " Velocity not initialized correctly."; |
| |
| log.error(err); |
| throw new VelocityException(err); |
| } |
| |
| parserPool = (ParserPool) o; |
| |
| parserPool.initialize(this); |
| } |
| else |
| { |
| /* |
| * someone screwed up. Lets not fool around... |
| */ |
| |
| String err = "It appears that no class was specified as the" |
| + " ParserPool. Please ensure that all configuration" |
| + " information is correct."; |
| |
| log.error(err); |
| throw new VelocityException( err ); |
| } |
| |
| } |
| |
| /** |
| * Returns a JavaCC generated Parser. |
| * |
| * @return Parser javacc generated parser |
| */ |
| public Parser createNewParser() |
| { |
| requireInitialization(); |
| |
| Parser parser = new Parser(this); |
| 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 template 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, Template template) |
| throws ParseException |
| { |
| requireInitialization(); |
| |
| Parser parser = (Parser) parserPool.get(); |
| boolean keepParser = true; |
| if (parser == null) |
| { |
| /* |
| * if we couldn't get a parser from the pool make one and log it. |
| */ |
| 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."); |
| } |
| parser = createNewParser(); |
| keepParser = false; |
| } |
| |
| try |
| { |
| return parser.parse(reader, template); |
| } |
| finally |
| { |
| if (keepParser) |
| { |
| /* drop the parser Template reference to allow garbage collection */ |
| parser.currentTemplate = null; |
| parserPool.put(parser); |
| } |
| |
| } |
| } |
| |
| private void initializeEvaluateScopeSettings() |
| { |
| String property = evaluateScopeName+'.'+PROVIDE_SCOPE_CONTROL; |
| provideEvaluateScope = getBoolean(property, provideEvaluateScope); |
| } |
| |
| /** |
| * 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. |
| * <br> |
| * Note! Macros defined in evaluate() calls are not persisted in memory so next evaluate() call |
| * does not know about macros defined during previous calls. |
| * |
| * @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. |
| * @since Velocity 1.6 |
| */ |
| public boolean evaluate(Context context, Writer out, |
| String logTag, String instring) |
| { |
| return evaluate(context, out, logTag, new StringReader(instring)); |
| } |
| |
| /** |
| * 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. |
| * <br> |
| * Note! Macros defined in evaluate() calls are not persisted in memory so next evaluate() call |
| * does not know about macros defined during previous calls. |
| * |
| * @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. |
| * @since Velocity 1.6 |
| */ |
| public boolean evaluate(Context context, Writer writer, |
| String logTag, Reader reader) |
| { |
| 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; |
| Template t = new Template(); |
| t.setName(logTag); |
| try |
| { |
| nodeTree = parse(reader, t); |
| } |
| catch (ParseException pex) |
| { |
| throw new ParseErrorException(pex, null); |
| } |
| catch (TemplateInitException pex) |
| { |
| throw new ParseErrorException(pex, null); |
| } |
| |
| if (nodeTree == null) |
| { |
| return false; |
| } |
| else |
| { |
| return render(context, writer, logTag, nodeTree); |
| } |
| } |
| |
| |
| /** |
| * 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. |
| * @since Velocity 1.6 |
| */ |
| public boolean render(Context context, Writer writer, |
| String logTag, SimpleNode nodeTree) |
| { |
| /* |
| * we want to init then render |
| */ |
| InternalContextAdapterImpl ica = |
| new InternalContextAdapterImpl(context); |
| |
| ica.pushCurrentTemplateName(logTag); |
| |
| try |
| { |
| try |
| { |
| nodeTree.init(ica, this); |
| } |
| catch (TemplateInitException pex) |
| { |
| throw new ParseErrorException(pex, null); |
| } |
| /** |
| * pass through application level runtime exceptions |
| */ |
| catch(RuntimeException e) |
| { |
| throw e; |
| } |
| catch(Exception e) |
| { |
| String msg = "RuntimeInstance.render(): init exception for tag = "+logTag; |
| getLog().error(msg, e); |
| throw new VelocityException(msg, e); |
| } |
| |
| try |
| { |
| if (provideEvaluateScope) |
| { |
| Object previous = ica.get(evaluateScopeName); |
| context.put(evaluateScopeName, new Scope(this, previous)); |
| } |
| /** |
| * optionally put the context in itself if asked so |
| */ |
| String self = getString(CONTEXT_AUTOREFERENCE_KEY); |
| if (self != null) context.put(self, context); |
| nodeTree.render(ica, writer); |
| } |
| catch (StopCommand stop) |
| { |
| if (!stop.isFor(this)) |
| { |
| throw stop; |
| } |
| else if (getLog().isDebugEnabled()) |
| { |
| getLog().debug(stop.getMessage()); |
| } |
| } |
| catch (IOException e) |
| { |
| throw new VelocityException("IO Error in writer: " + e.getMessage(), e); |
| } |
| } |
| finally |
| { |
| ica.popCurrentTemplateName(); |
| if (provideEvaluateScope) |
| { |
| Object obj = ica.get(evaluateScopeName); |
| if (obj instanceof Scope) |
| { |
| Scope scope = (Scope)obj; |
| if (scope.getParent() != null) |
| { |
| ica.put(evaluateScopeName, scope.getParent()); |
| } |
| else if (scope.getReplaced() != null) |
| { |
| ica.put(evaluateScopeName, scope.getReplaced()); |
| } |
| else |
| { |
| ica.remove(evaluateScopeName); |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * 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. |
| * <br> |
| * Note: only macros in the global context can be called. This method doesn't find macros defined by |
| * templates during previous mergeTemplate calls if Velocity.VM_PERM_INLINE_LOCAL has been enabled. |
| * |
| * @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. |
| * @since 1.6 |
| */ |
| public boolean invokeVelocimacro(final String vmName, String logTag, |
| String[] params, final Context context, |
| final Writer writer) |
| { |
| /* check necessary parameters */ |
| if (vmName == null || context == null || writer == null) |
| { |
| String msg = "RuntimeInstance.invokeVelocimacro() : invalid call : vmName, context, and writer must not be null"; |
| getLog().error(msg); |
| throw new NullPointerException(msg); |
| } |
| |
| /* handle easily corrected parameters */ |
| if (logTag == null) |
| { |
| logTag = vmName; |
| } |
| if (params == null) |
| { |
| params = new String[0]; |
| } |
| |
| /* does the VM exist? (only global scope is scanned so this doesn't find inline macros in templates) */ |
| if (!isVelocimacro(vmName, null)) |
| { |
| String msg = "RuntimeInstance.invokeVelocimacro() : VM '" + vmName |
| + "' is not registered."; |
| getLog().error(msg); |
| throw new VelocityException(msg); |
| } |
| |
| /* now just create the VM call, and use evaluate */ |
| StringBuilder template = new StringBuilder("#"); |
| template.append(vmName); |
| template.append("("); |
| for( int i = 0; i < params.length; i++) |
| { |
| template.append(" $"); |
| template.append(params[i]); |
| } |
| template.append(" )"); |
| |
| return evaluate(context, writer, logTag, template.toString()); |
| } |
| |
| /** |
| * Retrieves and caches the configured default encoding |
| * for better performance. (VELOCITY-606) |
| */ |
| private String getDefaultEncoding() |
| { |
| if (encoding == null) |
| { |
| /* |
| * first try to get the OS encoding |
| */ |
| encoding = System.getProperty("file.encoding"); |
| if (encoding == null) |
| { |
| /* |
| * then fall back to default |
| */ |
| encoding = getString(INPUT_ENCODING, ENCODING_DEFAULT); |
| } |
| } |
| return encoding; |
| } |
| |
| /** |
| * 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 platform dependant. |
| * |
| * @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. |
| */ |
| public Template getTemplate(String name) |
| throws ResourceNotFoundException, ParseErrorException |
| { |
| return getTemplate(name, null); |
| } |
| |
| /** |
| * 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. |
| */ |
| public Template getTemplate(String name, String encoding) |
| throws ResourceNotFoundException, ParseErrorException |
| { |
| requireInitialization(); |
| if (encoding == null) encoding = getDefaultEncoding(); |
| return (Template) |
| resourceManager.getResource(name, |
| ResourceManager.RESOURCE_TEMPLATE, encoding); |
| } |
| |
| /** |
| * 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. |
| */ |
| public ContentResource getContent(String name) |
| throws ResourceNotFoundException, ParseErrorException |
| { |
| /* |
| * the encoding is irrelvant as we don't do any converstion |
| * the bytestream should be dumped to the output stream |
| */ |
| |
| return getContent(name, getDefaultEncoding()); |
| } |
| |
| /** |
| * 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. |
| */ |
| public ContentResource getContent(String name, String encoding) |
| throws ResourceNotFoundException, ParseErrorException |
| { |
| requireInitialization(); |
| |
| return (ContentResource) |
| resourceManager.getResource(name, |
| ResourceManager.RESOURCE_CONTENT, encoding); |
| } |
| |
| |
| /** |
| * 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) |
| { |
| requireInitialization(); |
| |
| return resourceManager.getLoaderNameForResource(resourceName); |
| } |
| |
| /** |
| * Returns a convenient Log instance that wraps the current LogChute. |
| * Use this to log error messages. It has the usual methods. |
| * |
| * @return A convenience Log instance that wraps the current LogChute. |
| * @since 1.5 |
| */ |
| public Logger getLog() |
| { |
| return log; |
| } |
| |
| /** |
| * String property accessor method with default to hide the |
| * configuration implementation. |
| * |
| * @param key property key |
| * @param defaultValue default value to return if key not |
| * found in resource manager. |
| * @return value of key or default |
| */ |
| public String getString( String key, String defaultValue) |
| { |
| return configuration.getString(key, defaultValue); |
| } |
| |
| /** |
| * Returns the appropriate VelocimacroProxy object if vmName |
| * is a valid current Velocimacro. |
| * |
| * @param vmName Name of velocimacro requested |
| * @param renderingTemplate Template we are currently rendering. This |
| * information is needed when VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL setting is true |
| * and template contains a macro with the same name as the global macro library. |
| * @param template Template which acts as the host for the macro |
| * |
| * @return VelocimacroProxy |
| */ |
| public Directive getVelocimacro(String vmName, Template renderingTemplate, Template template) |
| { |
| return vmFactory.getVelocimacro(vmName, renderingTemplate, template); |
| } |
| |
| /** |
| * Adds a new Velocimacro. Usually called by Macro only while parsing. |
| * |
| * @param name Name of velocimacro |
| * @param macro root AST node of the parsed macro |
| * @param macroArgs Array of macro arguments, containing the |
| * #macro() arguments and default values. the 0th is the name. |
| * @param definingTemplate Template containing the source of the macro |
| * |
| * @return boolean True if added, false if rejected for some |
| * reason (either parameters or permission settings) |
| */ |
| public boolean addVelocimacro( String name, |
| Node macro, |
| List<Macro.MacroArg> macroArgs, |
| Template definingTemplate) |
| { |
| return vmFactory.addVelocimacro(name.intern(), macro, macroArgs, definingTemplate); |
| } |
| |
| /** |
| * Checks to see if a VM exists |
| * |
| * @param vmName Name of the Velocimacro. |
| * @param template Template on which to look for the Macro. |
| * @return True if VM by that name exists, false if not |
| */ |
| public boolean isVelocimacro(String vmName, Template template) |
| { |
| return vmFactory.isVelocimacro(vmName.intern(), template); |
| } |
| |
| /* -------------------------------------------------------------------- |
| * R U N T I M E A C C E S S O R M E T H O D S |
| * -------------------------------------------------------------------- |
| * These are the getXXX() methods that are a simple wrapper |
| * around the configuration object. This is an attempt |
| * to make a the Velocity Runtime the single access point |
| * for all things Velocity, and allow the Runtime to |
| * adhere as closely as possible the the Mediator pattern |
| * which is the ultimate goal. |
| * -------------------------------------------------------------------- |
| */ |
| |
| /** |
| * String property accessor method to hide the configuration implementation |
| * @param key property key |
| * @return value of key or null |
| */ |
| public String getString(String key) |
| { |
| return StringUtils.nullTrim(configuration.getString(key)); |
| } |
| |
| /** |
| * Int property accessor method to hide the configuration implementation. |
| * |
| * @param key Property key |
| * @return value |
| */ |
| public int getInt(String key) |
| { |
| return configuration.getInt(key); |
| } |
| |
| /** |
| * Int property accessor method to hide the configuration implementation. |
| * |
| * @param key property key |
| * @param defaultValue The default value. |
| * @return value |
| */ |
| public int getInt(String key, int defaultValue) |
| { |
| return configuration.getInt(key, defaultValue); |
| } |
| |
| /** |
| * Boolean property accessor method to hide the configuration implementation. |
| * |
| * @param key property key |
| * @param def The default value if property not found. |
| * @return value of key or default value |
| */ |
| public boolean getBoolean(String key, boolean def) |
| { |
| return configuration.getBoolean(key, def); |
| } |
| |
| /** |
| * Return the velocity runtime configuration object. |
| * |
| * @return Configuration object which houses the Velocity runtime |
| * properties. |
| */ |
| public ExtProperties getConfiguration() |
| { |
| return configuration; |
| } |
| |
| /** |
| * Return the Introspector for this instance |
| * @return The Introspector for this instance |
| */ |
| public Introspector getIntrospector() |
| { |
| return introspector; |
| } |
| |
| /** |
| * Returns the event handlers for the application. |
| * @return The event handlers for the application. |
| * @since 1.5 |
| */ |
| public EventCartridge getApplicationEventCartridge() |
| { |
| return eventCartridge; |
| } |
| |
| |
| /** |
| * Gets the application attribute for the given key |
| * |
| * @param key |
| * @return The application attribute for the given key. |
| */ |
| public Object getApplicationAttribute(Object key) |
| { |
| return applicationAttributes.get(key); |
| } |
| |
| /** |
| * Sets the application attribute for the given key |
| * |
| * @param key |
| * @param o The new application attribute. |
| * @return The old value of this attribute or null if it hasn't been set before. |
| */ |
| public Object setApplicationAttribute(Object key, Object o) |
| { |
| return applicationAttributes.put(key, o); |
| } |
| |
| /** |
| * Returns the Uberspect object for this Instance. |
| * |
| * @return The Uberspect object for this Instance. |
| */ |
| public Uberspect getUberspect() |
| { |
| return uberSpect; |
| } |
| |
| } |