Java tutorial
package com.github.pfmiles.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 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.Map; import java.util.Properties; import com.github.pfmiles.minvelocity.ImplHelper; import com.github.pfmiles.minvelocity.StringTemplate; import com.github.pfmiles.org.apache.commons.collections.ExtendedProperties; import com.github.pfmiles.org.apache.velocity.Template; import com.github.pfmiles.org.apache.velocity.context.Context; import com.github.pfmiles.org.apache.velocity.context.InternalContextAdapterImpl; import com.github.pfmiles.org.apache.velocity.exception.MethodInvocationException; import com.github.pfmiles.org.apache.velocity.exception.ParseErrorException; import com.github.pfmiles.org.apache.velocity.exception.ResourceNotFoundException; import com.github.pfmiles.org.apache.velocity.exception.TemplateInitException; import com.github.pfmiles.org.apache.velocity.exception.VelocityException; import com.github.pfmiles.org.apache.velocity.runtime.directive.Directive; import com.github.pfmiles.org.apache.velocity.runtime.log.Log; import com.github.pfmiles.org.apache.velocity.runtime.log.LogManager; import com.github.pfmiles.org.apache.velocity.runtime.parser.ParseException; import com.github.pfmiles.org.apache.velocity.runtime.parser.Parser; import com.github.pfmiles.org.apache.velocity.runtime.parser.node.SimpleNode; import com.github.pfmiles.org.apache.velocity.runtime.resource.ContentResource; import com.github.pfmiles.org.apache.velocity.runtime.resource.Resource; import com.github.pfmiles.org.apache.velocity.runtime.resource.ResourceManager; import com.github.pfmiles.org.apache.velocity.util.ClassUtils; import com.github.pfmiles.org.apache.velocity.util.RuntimeServicesAware; import com.github.pfmiles.org.apache.velocity.util.StringUtils; import com.github.pfmiles.org.apache.velocity.util.introspection.ChainableUberspector; import com.github.pfmiles.org.apache.velocity.util.introspection.Introspector; import com.github.pfmiles.org.apache.velocity.util.introspection.LinkingUberspector; import com.github.pfmiles.org.apache.velocity.util.introspection.Uberspect; import com.github.pfmiles.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: * * <blockquote><code><pre> * ri.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH, templatePath); * 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 * ----------------------------------------------------------------------- * 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> * @author pf-miles * @version $Id: RuntimeInstance.java 898050 2010-01-11 20:15:31Z nbubna $ */ 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 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 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. */ 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 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; // /** // * 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 specificed 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() { /* * 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(); } /** * 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) { log.debug("Initializing Velocity, Calling init()..."); initializing = true; log.trace("*******************************************************************"); log.debug("Starting pf_miles' Min-Velocity v1.0 (based on Apache Velocity v1.7)"); log.trace("RuntimeInstance initializing."); initializeProperties(); initializeLog(); initializeResourceManager(); initializeDirectives(); // initializeEventHandlers(); // initializeParserPool(); initializeIntrospection(); // initializeEvaluateScopeSettings(); /* * initialize the VM Factory. It will use the properties accessable * from Runtime, so keep this here at the end. */ // vmFactory.initVelocimacro(); log.trace("RuntimeInstance successfully initialized."); initialized = true; initializing = false; } } /** * 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 ExtendedProperties(); } overridingProperties.setProperty(key, value); } /** * Add all properties contained in the file fileName to the RuntimeInstance * properties */ public void setProperties(String fileName) { ExtendedProperties props = null; try { props = new ExtendedProperties(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 */ 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(); } 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(ExtendedProperties.convertProperties(p)); init(); } private void setProperties(ExtendedProperties 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 ExtendedProperties(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[] 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); // } // } // // 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() { // since the Log we started with was just placeholding, // let's update it with the real LogChute settings. try { LogManager.updateLog(this.log, this); } 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 string * String to be parsed * @param templateName * name of the template being parsed * @return A root node representing the template as an AST tree. * @throws ParseException * When the string could not be parsed as a template. * @since 1.6 */ public SimpleNode parse(String string, String templateName) throws ParseException { return parse(new StringReader(string), templateName); } /** * 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); } /** * 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 { requireInitialization(); Parser parser = this.createNewParser(); // boolean keepParser = true; if (parser == null) { throw new RuntimeException("Create parser instance failed."); /* * 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 // { /* * 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 */ // if (dumpNamespace) // { // dumpVMNamespace(templateName); // } return parser.parse(reader, templateName); // } // finally // { // if (keepParser) // { // 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. // * // * @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. // * // * @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; // try // { // nodeTree = parse(reader, logTag); // } // 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)); // } // 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. // * // * @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? */ // // if (!isVelocimacro(vmName, logTag)) // // { // // 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 */ // StrBuilder template = new StrBuilder("#"); // 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) { 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 "UTF-8" * * @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, getDefaultEncoding()); } /** * 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(); 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 Log getLog() { return log; } /** * @deprecated Use getLog() and call warn() on it. * @see Log#warn(Object) * @param message * The message to log. */ public void warn(Object message) { getLog().warn(message); } /** * @deprecated Use getLog() and call info() on it. * @see Log#info(Object) * @param message * The message to log. */ public void info(Object message) { getLog().info(message); } /** * @deprecated Use getLog() and call error() on it. * @see Log#error(Object) * @param message * The message to log. */ public void error(Object message) { getLog().error(message); } /** * @deprecated Use getLog() and call debug() on it. * @see Log#debug(Object) * @param message * The message to log. */ public void debug(Object message) { getLog().debug(message); } /** * 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); } /* * -------------------------------------------------------------------- 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 ExtendedProperties 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; } public Template getTempSupportRelPath(String name, String inputEncoding, String curPath) { if (name.startsWith("/")) { // ? return this.getTemplate(name, inputEncoding); } else { // return this.getTemplate(ImplHelper.resolveAbsName(name, curPath), inputEncoding); } } public Resource getCttSupportRelPath(String name, String inputEncoding, String curPath) { if (name.startsWith("/")) { // ? return this.getContent(name, inputEncoding); } else { // return this.getContent(ImplHelper.resolveAbsName(name, curPath), inputEncoding); } } public void init(ExtendedProperties props) { setProperties(props); init(); } /** * ?string?template */ public Template getStringTemplate(String templateString) { requireInitialization(); Template ret = new StringTemplate(templateString); ret.setRuntimeServices(this); ret.process(); return ret; } }