[Adapdev-commits] Adapdev/src/Adapdev.NVelocity/Runtime RuntimeConstants.cs,1.2,1.3 RuntimeInstance.
Status: Beta
Brought to you by:
intesar66
Update of /cvsroot/adapdev/Adapdev/src/Adapdev.NVelocity/Runtime In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22005/src/Adapdev.NVelocity/Runtime Added Files: RuntimeConstants.cs RuntimeInstance.cs RuntimeServices.cs RuntimeSingleton.cs VelocimacroFactory.cs VelocimacroManager.cs Log Message: --- NEW FILE: RuntimeConstants.cs --- namespace NVelocity.Runtime { using System; /// <summary> /// This class defines the keys that are used in the /// velocity.properties file so that they can be referenced as a constant /// within Java code. /// </summary> /// <author> <a href="mailto:jo...@la...">Jon S. Stevens</a></author> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a></author> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a></author> public struct RuntimeConstants_Fields { public const String RUNTIME_LOG = "runtime.log"; public const String RUNTIME_LOG_LOGSYSTEM = "runtime.log.logsystem"; public const String RUNTIME_LOG_LOGSYSTEM_CLASS = "runtime.log.logsystem.class"; public const String RUNTIME_LOG_ERROR_STACKTRACE = "runtime.log.error.stacktrace"; public const String RUNTIME_LOG_WARN_STACKTRACE = "runtime.log.warn.stacktrace"; public const String RUNTIME_LOG_INFO_STACKTRACE = "runtime.log.info.stacktrace"; public const String RUNTIME_LOG_REFERENCE_LOG_INVALID = "runtime.log.invalid.references"; public const String DEBUG_PREFIX = " [debug] "; public const String INFO_PREFIX = " [info] "; public const String WARN_PREFIX = " [warn] "; public const String ERROR_PREFIX = " [error] "; public const String UNKNOWN_PREFIX = " [unknown] "; public const String LOGSYSTEM_LOG4NET_CATEGORY = "runtime.log.logsystem.log4net.category"; public const String LOGSYSTEM_LOG4NET_PATTERN = "runtime.log.logsystem.log4net.pattern"; public const String LOGSYSTEM_LOG4NET_FILE_SIZE = "runtime.log.logsystem.log4net.file.size"; public const String LOGSYSTEM_LOG4NET_FILE_BACKUPS = "runtime.log.logsystem.log4net.file.backups"; public const String LOGSYSTEM_LOG4NET_SYSLOGD_HOST = "runtime.log.logsystem.log4net.syslogd.host"; public const String LOGSYSTEM_LOG4NET_SYSLOGD_FACILITY = "runtime.log.logsystem.log4net.syslogd.facility"; public const String LOGSYSTEM_LOG4NET_REMOTE_HOST = "runtime.log.logsystem.log4net.remote.host"; public const String LOGSYSTEM_LOG4NET_REMOTE_PORT = "runtime.log.logsystem.log4net.remote.port"; public const String LOGSYSTEM_LOG4NET_EMAIL_SERVER = "runtime.log.logsystem.log4net.email.server"; public const String LOGSYSTEM_LOG4NET_EMAIL_FROM = "runtime.log.logsystem.log4net.email.from"; public const String LOGSYSTEM_LOG4NET_EMAIL_TO = "runtime.log.logsystem.log4net.email.to"; public const String LOGSYSTEM_LOG4NET_EMAIL_SUBJECT = "runtime.log.logsystem.log4net.email.subject"; public const String LOGSYSTEM_LOG4NET_EMAIL_BUFFER_SIZE = "runtime.log.logsystem.log4net.email.buffer.size"; public const String COUNTER_NAME = "directive.foreach.counter.name"; public const String COUNTER_INITIAL_VALUE = "directive.foreach.counter.initial.value"; public const String ERRORMSG_START = "directive.include.output.errormsg.start"; public const String ERRORMSG_END = "directive.include.output.errormsg.end"; public const String PARSE_DIRECTIVE_MAXDEPTH = "directive.parse.max.depth"; public const String RESOURCE_MANAGER_CLASS = "resource.manager.class"; public const String RESOURCE_MANAGER_CACHE_CLASS = "resource.manager.cache.class"; public const String RESOURCE_MANAGER_LOGWHENFOUND = "resource.manager.logwhenfound"; public const String RESOURCE_LOADER = "resource.loader"; public const String FILE_RESOURCE_LOADER_PATH = "file.resource.loader.path"; public const String FILE_RESOURCE_LOADER_CACHE = "file.resource.loader.cache"; public const String VM_LIBRARY = "velocimacro.library"; public const String VM_LIBRARY_AUTORELOAD = "velocimacro.library.autoreload"; public const String VM_PERM_ALLOW_INLINE = "velocimacro.permissions.allow.inline"; public const String VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL = "velocimacro.permissions.allow.inline.to.replace.global"; public const String VM_PERM_INLINE_LOCAL = "velocimacro.permissions.allow.inline.local.scope"; public const String VM_MESSAGES_ON = "velocimacro.messages.on"; public const String VM_CONTEXT_LOCALSCOPE = "velocimacro.context.localscope"; public const String INTERPOLATE_STRINGLITERALS = "runtime.interpolate.string.literals"; public const String INPUT_ENCODING = "input.encoding"; public const String OUTPUT_ENCODING = "output.encoding"; public const String ENCODING_DEFAULT = "ISO-8859-1"; public const String DEFAULT_RUNTIME_PROPERTIES = "nvelocity.properties"; public const String DEFAULT_RUNTIME_DIRECTIVES = "directive.properties"; public const int NUMBER_OF_PARSERS = 20; public const String PARSER_POOL_SIZE = "parser.pool.size"; } public interface RuntimeConstants { /* * ---------------------------------------------------------------------- * These are public constants that are used as handles for the * properties that can be specified in your typical * nvelocity.properties file. * ---------------------------------------------------------------------- */ /* * ---------------------------------------------------------------------- * L O G G I N G C O N F I G U R A T I O N * ---------------------------------------------------------------------- */ /// /// <summary> Location of the velocity log file. /// </summary> /// <summary> externally provided logger /// </summary> /// <summary> class of log system to use /// </summary> /// /// <summary> Stack trace output for error messages. /// </summary> /// /// <summary> Stack trace output for warning messages. /// </summary> /// /// <summary> Stack trace output for info messages. /// </summary> /// <summary> Logging of invalid references. /// </summary> /// <summary> Log message prefixes /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /// <summary> Log4Net configuration /// </summary> /* * ---------------------------------------------------------------------- * D I R E C T I V E C O N F I G U R A T I O N * ---------------------------------------------------------------------- * Directive properties are of the form: * * directive.<directive-name>.<property> * ---------------------------------------------------------------------- */ /// /// <summary> Initial counter value in #foreach directives. /// </summary> /// /// <summary> Initial counter value in #foreach directives. /// </summary> /// <summary> Starting tag for error messages triggered by passing /// a parameter not allowed in the #include directive. Only /// string literals, and references are allowed. /// </summary> /// <summary> Ending tag for error messages triggered by passing /// a parameter not allowed in the #include directive. Only /// string literals, and references are allowed. /// </summary> /// <summary> Maximum recursion depth allowed for the #parse directive. /// </summary> /* * ---------------------------------------------------------------------- * R E S O U R C E M A N A G E R C O N F I G U R A T I O N * ---------------------------------------------------------------------- */ /* * ---------------------------------------------------------------------- * R E S O U R C E L O A D E R C O N F I G U R A T I O N * ---------------------------------------------------------------------- */ /// <summary> controls if the finding of a resource is logged /// </summary> /// <summary> Key used to retrieve the names of the resource loaders /// to be used. In a properties file they may appear as /// the following: /// * /// resource.loader = file,classpath /// </summary> /// <summary> The public handle for setting a path in /// the FileResourceLoader. /// </summary> /// <summary> The public handle for turning the caching on in the /// FileResourceLoader. /// </summary> /* * ---------------------------------------------------------------------- * V E L O C I M A C R O C O N F I G U R A T I O N * ---------------------------------------------------------------------- */ /// /// <summary> Name of local Velocimacro library template. /// </summary> /// /// <summary> switch for autoloading library-sourced VMs (for development) /// </summary> /// /// <summary> boolean (true/false) default true : allow /// inline (in-template) macro definitions /// </summary> /// <summary> boolean (true/false) default false : allow inline /// (in-template) macro definitions to replace existing /// </summary> /// /// <summary> Switch for forcing inline macros to be local : default false. /// </summary> /// /// <summary> Switch for VM blather : default true. /// </summary> /// /// <summary> switch for local context in VM : default false /// </summary> /* * ---------------------------------------------------------------------- * G E N E R A L R U N T I M E C O N F I G U R A T I O N * ---------------------------------------------------------------------- */ /// <summary> Switch for the interpolation facility for string literals /// </summary> /// /// <summary> The character encoding for the templates. Used by the parser in /// processing the input streams. /// </summary> /// <summary> Encoding for the output stream. Currently used by Anakia and /// VelocityServlet /// </summary> /* * ---------------------------------------------------------------------- * These constants are used internally by the Velocity runtime i.e. * the constansts listed below are strictly used in the Runtime * class itself. * ---------------------------------------------------------------------- */ /// /// <summary> Default Runtime properties. /// </summary> /// /// <summary> Default Runtime properties /// </summary> /// <summary> Number of parsers to create /// </summary> } } --- NEW FILE: RuntimeSingleton.cs --- namespace NVelocity.Runtime { using System; using System.IO; using Commons.Collections; using NVelocity.Runtime.Parser.Node; using NVelocity.Runtime.Resource; using NVelocity.Util.Introspection; /// <summary> 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: /// * /// <pre> /// Runtime.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH, templatePath); /// Runtime.setProperty(Runtime.RUNTIME_LOG, pathToVelocityLog); /// Runtime.init(); /// </pre> /// * /// <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 /// ----------------------------------------------------------------------- /// Runtime.init() /// /// If Runtime.init() is called by itself the Runtime will /// initialize with a set of default values. /// ----------------------------------------------------------------------- /// Runtime.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> /// * /// </summary> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a> /// </author> /// <author> <a href="mailto:jl...@ho...">Jeff Bowden</a> /// </author> /// <author> <a href="mailto:ge...@op...">Geir Magusson Jr.</a> /// </author> /// <version> $Id: RuntimeSingleton.cs,v 1.3 2005/11/16 05:45:24 intesar66 Exp $ /// /// </version> public class RuntimeSingleton : RuntimeConstants { public static RuntimeServices RuntimeServices { get { return (RuntimeServices) ri; } } public static ExtendedProperties Configuration { get { return ri.Configuration; } set { ri.Configuration = value; } } public static Introspector Introspector { get { return ri.Introspector; } } public static RuntimeInstance RuntimeInstance { get { return ri; } } private static RuntimeInstance ri = new RuntimeInstance(); /* * 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>Parser Pool</li> * <li>Global Cache</li> * <li>Static Content Include System</li> * <li>Velocimacro System</li> * </ul> */ public static void init() { lock (typeof (RuntimeSingleton)) { ri.init(); } } /// <summary> Allows an external system to set a property in /// the Velocity Runtime. /// * /// </summary> /// <param name="String">property key /// </param> /// <param name="String">property value /// /// </param> public static void setProperty(String key, Object value_Renamed) { ri.setProperty(key, value_Renamed); } /// <summary> 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. /// * /// </summary> /// <param name="ExtendedProperties">configuration /// /// </param> /// <summary> 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"] /// * /// </summary> /// <param name="String">key /// </param> /// <param name="String">value /// /// </param> public static void addProperty(String key, Object value_Renamed) { ri.addProperty(key, value_Renamed); } /// <summary> Clear the values pertaining to a particular /// property. /// * /// </summary> /// <param name="String">key of property to clear /// /// </param> public static void clearProperty(String key) { ri.clearProperty(key); } /// <summary> 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. /// * /// </summary> /// <param name="key">property to return /// /// </param> public static Object getProperty(String key) { return ri.getProperty(key); } /// <summary> Initialize the Velocity Runtime with a Properties /// object. /// * /// </summary> /// <param name="">Properties /// /// </param> public static void init(ExtendedProperties p) { ri.init(p); } /// <summary> Initialize the Velocity Runtime with the name of /// ExtendedProperties object. /// * /// </summary> /// <param name="">Properties /// /// </param> public static void init(String configurationFile) { ri.init(configurationFile); } /// <summary> Returns a JavaCC generated Parser. /// * /// </summary> /// <returns>Parser javacc generated parser /// /// </returns> private static Parser.Parser createNewParser() { return ri.createNewParser(); } /// <summary> 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. /// * /// </summary> /// <param name="InputStream">inputstream retrieved by a resource loader /// </param> /// <param name="String">name of the template being parsed /// /// </param> public static SimpleNode parse(TextReader reader, String templateName) { return ri.parse(reader, templateName); } /// <summary> Parse the input and return the root of the AST node structure. /// * /// </summary> /// <param name="InputStream">inputstream retrieved by a resource loader /// </param> /// <param name="String">name of the template being parsed /// </param> /// <param name="dumpNamespace">flag to dump the Velocimacro namespace for this template /// /// </param> public static SimpleNode parse(TextReader reader, String templateName, bool dumpNamespace) { return ri.parse(reader, templateName, dumpNamespace); } /// <summary> Returns a <code>Template</code> from the resource manager. /// This method assumes that the character encoding of the /// template is set by the <code>input.encoding</code> /// property. The default is "ISO-8859-1" /// * /// </summary> /// <param name="name">The file name of the desired template. /// </param> /// <returns> The template. /// @throws ResourceNotFoundException if template not found /// from any available source. /// @throws ParseErrorException if template cannot be parsed due /// to syntax (or other) error. /// @throws Exception if an error occurs in template initialization /// /// </returns> public static Template getTemplate(String name) { return ri.getTemplate(name); } /// <summary> Returns a <code>Template</code> from the resource manager /// * /// </summary> /// <param name="name">The name of the desired template. /// </param> /// <param name="encoding">Character encoding of the template /// </param> /// <returns> The template. /// @throws ResourceNotFoundException if template not found /// from any available source. /// @throws ParseErrorException if template cannot be parsed due /// to syntax (or other) error. /// @throws Exception if an error occurs in template initialization /// /// </returns> public static Template getTemplate(String name, String encoding) { return ri.getTemplate(name, encoding); } /// <summary> Returns a static content resource from the /// resource manager. Uses the current value /// if INPUT_ENCODING as the character encoding. /// * /// </summary> /// <param name="name">Name of content resource to get /// </param> /// <returns>parsed ContentResource object ready for use /// @throws ResourceNotFoundException if template not found /// from any available source. /// /// </returns> public static ContentResource getContent(String name) { return ri.getContent(name); } /// <summary> Returns a static content resource from the /// resource manager. /// * /// </summary> /// <param name="name">Name of content resource to get /// </param> /// <param name="encoding">Character encoding to use /// </param> /// <returns>parsed ContentResource object ready for use /// @throws ResourceNotFoundException if template not found /// from any available source. /// /// </returns> public static ContentResource getContent(String name, String encoding) { return ri.getContent(name, encoding); } /// <summary> Determines is a template exists, and returns name of the loader that /// provides it. This is a slightly less hokey way to support /// the Velocity.templateExists() utility method, which was broken /// when per-template encoding was introduced. We can revisit this. /// * /// </summary> /// <param name="resourceName">Name of template or content resource /// </param> /// <returns>class name of loader than can provide it /// /// </returns> public static String getLoaderNameForResource(String resourceName) { return ri.getLoaderNameForResource(resourceName); } /// <summary> Log a warning message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> public static void warn(Object message) { ri.warn(message); } /// /// <summary> Log an info message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> public static void info(Object message) { ri.info(message); } /// <summary> Log an error message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> public static void error(Object message) { ri.error(message); } /// <summary> Log a debug message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> public static void debug(Object message) { ri.debug(message); } /// <summary> String property accessor method with default to hide the /// configuration implementation. /// /// </summary> /// <param name="String">key property key /// </param> /// <param name="String">defaultValue default value to return if key not /// found in resource manager. /// </param> /// <returns>String value of key or default /// /// </returns> public static String getString(String key, String defaultValue) { return ri.getString(key, defaultValue); } /// <summary> Returns the appropriate VelocimacroProxy object if strVMname /// is a valid current Velocimacro. /// * /// </summary> /// <param name="String">vmName Name of velocimacro requested /// </param> /// <returns>String VelocimacroProxy /// /// </returns> public static Directive.Directive getVelocimacro(String vmName, String templateName) { return ri.getVelocimacro(vmName, templateName); } /// <summary> Adds a new Velocimacro. Usually called by Macro only while parsing. /// * /// </summary> /// <param name="String">name Name of velocimacro /// </param> /// <param name="String">macro String form of macro body /// </param> /// <param name="String">argArray Array of strings, containing the /// #macro() arguments. the 0th is the name. /// </param> /// <returns>boolean True if added, false if rejected for some /// reason (either parameters or permission settings) /// /// </returns> public static bool addVelocimacro(String name, String macro, String[] argArray, String sourceTemplate) { return ri.addVelocimacro(name, macro, argArray, sourceTemplate); } /// <summary> Checks to see if a VM exists /// * /// </summary> /// <param name="name"> Name of velocimacro /// </param> /// <returns>boolean True if VM by that name exists, false if not /// /// </returns> public static bool isVelocimacro(String vmName, String templateName) { return ri.isVelocimacro(vmName, templateName); } /// <summary> tells the vmFactory to dump the specified namespace. This is to support /// clearing the VM list when in inline-VM-local-scope mode /// </summary> public static bool dumpVMNamespace(String namespace_Renamed) { return ri.dumpVMNamespace(namespace_Renamed); } /* -------------------------------------------------------------------- * 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. * -------------------------------------------------------------------- */ /// <summary> String property accessor method to hide the configuration implementation /// </summary> /// <param name="key"> property key /// </param> /// <returns> value of key or null /// /// </returns> public static String getString(String key) { return ri.getString(key); } /// <summary> Int property accessor method to hide the configuration implementation. /// * /// </summary> /// <param name="String">key property key /// </param> /// <returns>int value /// /// </returns> public static int getInt(String key) { return ri.getInt(key); } /// <summary> Int property accessor method to hide the configuration implementation. /// * /// </summary> /// <param name="key"> property key /// </param> /// <param name="int">default value /// </param> /// <returns>int value /// /// </returns> public static int getInt(String key, int defaultValue) { return ri.getInt(key, defaultValue); } /// <summary> Boolean property accessor method to hide the configuration implementation. /// /// </summary> /// <param name="String">key property key /// </param> /// <param name="boolean">default default value if property not found /// </param> /// <returns>boolean value of key or default value /// /// </returns> public static bool getBoolean(String key, bool def) { return ri.getBoolean(key, def); } /// <summary> Return the velocity runtime configuration object. /// * /// </summary> /// <returns>ExtendedProperties configuration object which houses /// the velocity runtime properties. /// /// </returns> /// <summary> Return the Introspector for this RuntimeInstance /// * /// </summary> /// <returns>Introspector object for this runtime instance /// /// </returns> /// <summary> returns the RuntimeInstance object for this singleton /// For internal use only :) /// * /// </summary> /// <returns>RuntimeInstance the RuntimeInstance used by this Singleton /// instance /// /// </returns> } } --- NEW FILE: VelocimacroFactory.cs --- namespace NVelocity.Runtime { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Velocity", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ using System; using System.Collections; using NVelocity.Runtime.Directive; /// <summary> VelocimacroFactory.java /// * /// manages the set of VMs in a running Velocity engine. /// * /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a> /// </author> /// <version> $Id: VelocimacroFactory.cs,v 1.3 2005/11/16 05:45:24 intesar66 Exp $ /// /// </version> public class VelocimacroFactory { private bool TemplateLocalInline { get { return templateLocal; } set { templateLocal = value; } } private bool AddMacroPermission { set { bool b = addNewAllowed; addNewAllowed = value; // TODO: looks like original code must have returned the value that was replaced //return b; } } private bool ReplacementPermission { set { bool b = replaceAllowed; replaceAllowed = value; // TODO: looks like original code must have returned the value that was replaced //return b; } } private bool Blather { get { return blather; } set { blather = value; } } private bool Autoload { get { return autoReloadLibrary; } set { autoReloadLibrary = value; } } /// <summary> runtime services for this instance /// </summary> private RuntimeServices rsvc = null; /// <summary> VMManager : deal with namespace management /// and actually keeps all the VM definitions /// </summary> private VelocimacroManager vmManager = null; /// <summary> determines if replacement of global VMs are allowed /// controlled by VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL /// </summary> private bool replaceAllowed = false; /// <summary> controls if new VMs can be added. Set by /// VM_PERM_ALLOW_INLINE Note the assumption that only /// through inline defs can this happen. /// additions through autoloaded VMs is allowed /// </summary> private bool addNewAllowed = true; /// <summary> sets if template-local namespace in used /// </summary> private bool templateLocal = false; /// <summary> controls log output /// </summary> private bool blather = false; /// <summary> determines if the libraries are auto-loaded /// when they change /// </summary> private bool autoReloadLibrary = false; /// <summary> vector of the library names /// </summary> private ArrayList macroLibVec = null; /// <summary> map of the library Template objects /// used for reload determination /// </summary> private Hashtable libModMap; /// <summary> CTOR : requires a runtime services from now /// on /// </summary> public VelocimacroFactory(RuntimeServices rs) { this.rsvc = rs; /* * we always access in a synchronized(), so we * can use an unsynchronized hashmap */ libModMap = new Hashtable(); vmManager = new VelocimacroManager(rsvc); } /// <summary> initialize the factory - setup all permissions /// load all global libraries. /// </summary> public virtual void initVelocimacro() { /* * maybe I'm just paranoid... */ lock (this) { /* * allow replacements while we add the libraries, if exist */ ReplacementPermission = true; Blather = true; logVMMessageInfo("Velocimacro : initialization starting."); /* * add all library macros to the global namespace */ vmManager.NamespaceUsage = false; /* * now, if there is a global or local libraries specified, use them. * All we have to do is get the template. The template will be parsed; * VM's are added during the parse phase */ Object libfiles = rsvc.getProperty(RuntimeConstants_Fields.VM_LIBRARY); if (libfiles != null) { if (libfiles is ArrayList) { macroLibVec = (ArrayList) libfiles; } else if (libfiles is String) { macroLibVec = new ArrayList(); macroLibVec.Add(libfiles); } for (int i = 0; i < macroLibVec.Count; i++) { String lib = (String) macroLibVec[i]; /* * only if it's a non-empty string do we bother */ if (lib != null && !lib.Equals("")) { /* * let the VMManager know that the following is coming * from libraries - need to know for auto-load */ vmManager.RegisterFromLib = true; logVMMessageInfo("Velocimacro : adding VMs from " + "VM library template : " + lib); try { Template template = rsvc.getTemplate(lib); /* * save the template. This depends on the assumption * that the Template object won't change - currently * this is how the Resource manager works */ Twonk twonk = new Twonk(this); twonk.template = template; twonk.modificationTime = template.LastModified; libModMap[lib] = twonk; } catch (System.Exception e) { logVMMessageInfo("Velocimacro : error using VM " + "library template " + lib + " : " + e); } logVMMessageInfo("Velocimacro : VM library template " + "macro registration complete."); vmManager.RegisterFromLib = false; } } } /* * now, the permissions */ /* * allowinline : anything after this will be an inline macro, I think * there is the question if a #include is an inline, and I think so * * default = true */ AddMacroPermission = true; if (!rsvc.getBoolean(RuntimeConstants_Fields.VM_PERM_ALLOW_INLINE, true)) { AddMacroPermission = false; logVMMessageInfo("Velocimacro : allowInline = false : VMs can not " + "be defined inline in templates"); } else { logVMMessageInfo("Velocimacro : allowInline = true : VMs can be " + "defined inline in templates"); } /* * allowInlineToReplaceGlobal : allows an inline VM , if allowed at all, * to replace an existing global VM * * default = false */ ReplacementPermission = false; if (rsvc.getBoolean(RuntimeConstants_Fields.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, false)) { ReplacementPermission = true; logVMMessageInfo("Velocimacro : allowInlineToOverride = true : VMs " + "defined inline may replace previous VM definitions"); } else { logVMMessageInfo("Velocimacro : allowInlineToOverride = false : VMs " + "defined inline may NOT replace previous VM definitions"); } /* * now turn on namespace handling as far as permissions allow in the * manager, and also set it here for gating purposes */ vmManager.NamespaceUsage = true; /* * template-local inline VM mode : default is off */ TemplateLocalInline = rsvc.getBoolean(RuntimeConstants_Fields.VM_PERM_INLINE_LOCAL, false); if (TemplateLocalInline) { logVMMessageInfo("Velocimacro : allowInlineLocal = true : VMs " + "defined inline will be local to their defining template only."); } else { logVMMessageInfo("Velocimacro : allowInlineLocal = false : VMs " + "defined inline will be global in scope if allowed."); } vmManager.TemplateLocalInlineVM = TemplateLocalInline; /* * general message switch. default is on */ Blather = rsvc.getBoolean(RuntimeConstants_Fields.VM_MESSAGES_ON, true); if (Blather) { logVMMessageInfo("Velocimacro : messages on : VM system " + "will output logging messages"); } else { logVMMessageInfo("Velocimacro : messages off : VM system will be quiet"); } /* * autoload VM libraries */ Autoload = rsvc.getBoolean(RuntimeConstants_Fields.VM_LIBRARY_AUTORELOAD, false); if (Autoload) { logVMMessageInfo("Velocimacro : autoload on : VM system " + "will automatically reload global library macros"); } else { logVMMessageInfo("Velocimacro : autoload off : VM system " + "will not automatically reload global library macros"); } rsvc.info("Velocimacro : initialization complete."); } return; } /// <summary> adds a macro to the factory. /// </summary> public virtual bool addVelocimacro(String name, String macroBody, String[] argArray, String sourceTemplate) { /* * maybe we should throw an exception, maybe just tell * the caller like this... * * I hate this : maybe exceptions are in order here... */ if (name == null || macroBody == null || argArray == null || sourceTemplate == null) { logVMMessageWarn("Velocimacro : VM addition rejected : " + "programmer error : arg null"); return false; } /* * see if the current ruleset allows this addition */ if (!canAddVelocimacro(name, sourceTemplate)) { return false; } /* * seems like all is good. Lets do it. */ lock (this) { vmManager.addVM(name, macroBody, argArray, sourceTemplate); } /* * if we are to blather, blather... */ if (blather) { String s = "#" + argArray[0]; s += "("; for (int i = 1; i < argArray.Length; i++) { s += " "; s += argArray[i]; } s += " ) : source = "; s += sourceTemplate; logVMMessageInfo("Velocimacro : added new VM : " + s); } return true; } /// <summary> determines if a given macro/namespace (name, source) combo is allowed /// to be added /// * /// </summary> /// <param name="name">Name of VM to add /// </param> /// <param name="sourceTemplate">Source template that contains the defintion of the VM /// </param> /// <returns>true if it is allowed to be added, false otherwise /// /// </returns> private bool canAddVelocimacro(String name, String sourceTemplate) { /* * short circuit and do it if autoloader is on, and the * template is one of the library templates */ if (Autoload) { /* * see if this is a library template */ for (int i = 0; i < macroLibVec.Count; i++) { String lib = (String) macroLibVec[i]; if (lib.Equals(sourceTemplate)) { return true; } } } /* * maybe the rules should be in manager? I dunno. It's to manage * the namespace issues first, are we allowed to add VMs at all? * This trumps all. */ if (!addNewAllowed) { logVMMessageWarn("Velocimacro : VM addition rejected : " + name + " : inline VMs not allowed."); return false; } /* * are they local in scope? Then it is ok to add. */ if (!templateLocal) { /* * otherwise, if we have it already in global namespace, and they can't replace * since local templates are not allowed, the global namespace is implied. * remember, we don't know anything about namespace managment here, so lets * note do anything fancy like trying to give it the global namespace here * * so if we have it, and we aren't allowed to replace, bail */ if (isVelocimacro(name, sourceTemplate) && !replaceAllowed) { logVMMessageWarn("Velocimacro : VM addition rejected : " + name + " : inline not allowed to replace existing VM"); return false; } } return true; } /// <summary> localization of the logging logic /// </summary> private void logVMMessageInfo(String s) { if (blather) rsvc.info(s); } /// <summary> localization of the logging logic /// </summary> private void logVMMessageWarn(String s) { if (blather) rsvc.warn(s); } /// <summary> Tells the world if a given directive string is a Velocimacro /// </summary> public virtual bool isVelocimacro(String vm, String sourceTemplate) { lock (this) { /* * first we check the locals to see if we have * a local definition for this template */ if (vmManager.get(vm, sourceTemplate) != null) return true; } return false; } /// <summary> actual factory : creates a Directive that will /// behave correctly wrt getting the framework to /// dig out the correct # of args /// </summary> public virtual Directive.Directive getVelocimacro(String vmName, String sourceTemplate) { VelocimacroProxy vp = null; lock (this) { /* * don't ask - do */ vp = vmManager.get(vmName, sourceTemplate); /* * if this exists, and autoload is on, we need to check * where this VM came from */ if (vp != null && Autoload) { /* * see if this VM came from a library. Need to pass sourceTemplate * in the event namespaces are set, as it could be masked by local */ String lib = vmManager.getLibraryName(vmName, sourceTemplate); if (lib != null) { try { /* * get the template from our map */ Twonk tw = (Twonk) libModMap[lib]; if (tw != null) { Template template = tw.template; /* * now, compare the last modified time of the resource * with the last modified time of the template * if the file has changed, then reload. Otherwise, we should * be ok. */ long tt = tw.modificationTime; long ft = template.ResourceLoader.getLastModified(template); if (ft > tt) { logVMMessageInfo("Velocimacro : autoload reload for VMs from " + "VM library template : " + lib); /* * when there are VMs in a library that invoke each other, * there are calls into getVelocimacro() from the init() * process of the VM directive. To stop the infinite loop * we save the current time reported by the resource loader * and then be honest when the reload is complete */ tw.modificationTime = ft; template = rsvc.getTemplate(lib); /* * and now we be honest */ tw.template = template; tw.modificationTime = template.LastModified; /* * note that we don't need to put this twonk back * into the map, as we can just use the same reference * and this block is synchronized */ } } } catch (System.Exception e) { logVMMessageInfo("Velocimacro : error using VM " + "library template " + lib + " : " + e); } /* * and get again */ vp = vmManager.get(vmName, sourceTemplate); } } } return vp; } /// <summary> tells the vmManager to dump the specified namespace /// </summary> public virtual bool dumpVMNamespace(String namespace_Renamed) { return vmManager.dumpNamespace(namespace_Renamed); } /// <summary> sets permission to have VMs local in scope to their declaring template /// note that this is really taken care of in the VMManager class, but /// we need it here for gating purposes in addVM /// eventually, I will slide this all into the manager, maybe. /// </summary> /// <summary> sets the permission to add new macros /// </summary> /// <summary> sets the permission for allowing addMacro() calls to /// replace existing VM's /// </summary> /// <summary> set output message mode /// </summary> /// <summary> get output message mode /// </summary> /// <summary> set the switch for automatic reloading of /// global library-based VMs /// </summary> /// <summary> get the switch for automatic reloading of /// global library-based VMs /// </summary> /// <summary> small continer class to hold the duple /// of a template and modification time. /// We keep the modification time so we can /// 'override' it on a reload to prevent /// recursive reload due to inter-calling /// VMs in a library /// </summary> //UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'Twonk' to access its enclosing instance. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1019"' private class Twonk { public Twonk(VelocimacroFactory enclosingInstance) { InitBlock(enclosingInstance); } private void InitBlock(VelocimacroFactory enclosingInstance) { this.enclosingInstance = enclosingInstance; } private VelocimacroFactory enclosingInstance; public VelocimacroFactory Enclosing_Instance { get { return enclosingInstance; } } public Template template; public long modificationTime; } } } --- NEW FILE: RuntimeServices.cs --- namespace NVelocity.Runtime { using System; using System.IO; using Commons.Collections; using NVelocity.Runtime.Parser.Node; using NVelocity.Runtime.Resource; using NVelocity.Util.Introspection; /// <summary> Interface for internal runtime services that are needed by the /// various components w/in Velocity. This was taken from the old /// Runtime singleton, and anything not necessary was removed. /// /// Currently implemented by RuntimeInstance. /// </summary> public interface RuntimeServices { ExtendedProperties Configuration { get; set; } Introspector Introspector { get; } /* * 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>Parser Pool</li> * <li>Global Cache</li> * <li>Static Content Include System</li> * <li>Velocimacro System</li> * </ul> */ void init(); /// <summary> Allows an external system to set a property in /// the Velocity Runtime. /// * /// </summary> /// <param name="String">property key /// </param> /// <param name="String">property value /// /// </param> void setProperty(String key, Object value_Renamed); /// <summary> 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. /// * /// </summary> /// <param name="ExtendedProperties">configuration /// /// </param> /// <summary> 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"] /// * /// </summary> /// <param name="String">key /// </param> /// <param name="String">value /// /// </param> void addProperty(String key, Object value_Renamed); /// <summary> Clear the values pertaining to a particular /// property. /// * /// </summary> /// <param name="String">key of property to clear /// /// </param> void clearProperty(String key); /// <summary> 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. /// * /// </summary> /// <param name="key">property to return /// /// </param> Object getProperty(String key); /// <summary> Initialize the Velocity Runtime with a Properties /// object. /// * /// </summary> /// <param name="">Properties /// /// </param> // TODO //void init(System.Configuration.AppSettingsReader p); /// <summary> Initialize the Velocity Runtime with the name of /// ExtendedProperties object. /// * /// </summary> /// <param name="">Properties /// /// </param> void init(String configurationFile); /// <summary> 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. /// * /// </summary> /// <param name="InputStream">inputstream retrieved by a resource loader /// </param> /// <param name="String">name of the template being parsed /// /// </param> SimpleNode parse(TextReader reader, String templateName); /// <summary> Parse the input and return the root of the AST node structure. /// * /// </summary> /// <param name="InputStream">inputstream retrieved by a resource loader /// </param> /// <param name="String">name of the template being parsed /// </param> /// <param name="dumpNamespace">flag to dump the Velocimacro namespace for this template /// /// </param> SimpleNode parse(TextReader reader, String templateName, bool dumpNamespace); /// <summary> Returns a <code>Template</code> from the resource manager. /// This method assumes that the character encoding of the /// template is set by the <code>input.encoding</code> /// property. The default is "ISO-8859-1" /// * /// </summary> /// <param name="name">The file name of the desired template. /// </param> /// <returns> The template. /// @throws ResourceNotFoundException if template not found /// from any available source. /// @throws ParseErrorException if template cannot be parsed due /// to syntax (or other) error. /// @throws Exception if an error occurs in template initialization /// /// </returns> Template getTemplate(String name); /// <summary> Returns a <code>Template</code> from the resource manager /// * /// </summary> /// <param name="name">The name of the desired template. /// </param> /// <param name="encoding">Character encoding of the template /// </param> /// <returns> The template. /// @throws ResourceNotFoundException if template not found /// from any available source. /// @throws ParseErrorException if template cannot be parsed due /// to syntax (or other) error. /// @throws Exception if an error occurs in template initialization /// /// </returns> Template getTemplate(String name, String encoding); /// <summary> Returns a static content resource from the /// resource manager. Uses the current value /// if INPUT_ENCODING as the character encoding. /// * /// </summary> /// <param name="name">Name of content resource to get /// </param> /// <returns>parsed ContentResource object ready for use /// @throws ResourceNotFoundException if template not found /// from any available source. /// /// </returns> ContentResource getContent(String name); /// <summary> Returns a static content resource from the /// resource manager. /// * /// </summary> /// <param name="name">Name of content resource to get /// </param> /// <param name="encoding">Character encoding to use /// </param> /// <returns>parsed ContentResource object ready for use /// @throws ResourceNotFoundException if template not found /// from any available source. /// /// </returns> ContentResource getContent(String name, String encoding); /// <summary> Determines is a template exists, and returns name of the loader that /// provides it. This is a slightly less hokey way to support /// the Velocity.templateExists() utility method, which was broken /// when per-template encoding was introduced. We can revisit this. /// * /// </summary> /// <param name="resourceName">Name of template or content resource /// </param> /// <returns>class name of loader than can provide it /// /// </returns> String getLoaderNameForResource(String resourceName); /// <summary> Log a warning message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> void warn(Object message); /// /// <summary> Log an info message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> void info(Object message); /// <summary> Log an error message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> void error(Object message); /// <summary> Log a debug message. /// * /// </summary> /// <param name="Object">message to log /// /// </param> void debug(Object message); /// <summary> String property accessor method with default to hide the /// configuration implementation. /// /// </summary> /// <param name="String">key property key /// </param> /// <param name="String">defaultValue default value to return if key not /// found in resource manager. /// </param> /// <returns>String value of key or default /// /// </returns> String getString(String key, String defaultValue); /// <summary> Returns the appropriate VelocimacroProxy object if strVMname /// is a valid current Velocimacro. /// * /// </summary> /// <param name="String">vmName Name of velocimacro requested /// </param> /// <returns>String VelocimacroProxy /// /// </returns> Directive.Directive getVelocimacro(String vmName, String templateName); /// <summary> Adds a new Velocimacro. Usually called by Macro only while parsing. /// * /// </summary> /// <param name="String">name Name of velocimacro /// </param> /// <param name="String">macro String form of macro body /// </param> /// <param name="String">argArray Array of strings, containing the /// #macro() arguments. the 0th is the name. /// </param> /// <returns>boolean True if added, false if rejected for some /// reason (either parameters or permission settings) /// /// </returns> bool addVelocimacro(String name, String macro, String[] argArray, String sourceTemplate); /// <summary> Checks to see if a VM exists /// * /// </summary> /// <param name="name"> Name of velocimacro /// </param> /// <returns>boolean True if VM by that name exists, false if not /// /// </returns> bool isVelocimacro(String vmName, String templateName); /// <summary> tells the vmFactory to dump the specified namespace. This is to support /// clearing the VM list when in inline-VM-local-scope mode /// </summary> bool dumpVMNamespace(String namespace_Renamed); /// <summary> String property accessor method to hide the configuration implementation /// </summary> /// <param name="key"> property key /// </param> /// <returns> value of key or null /// /// </returns> String getString(String key); /// <summary> Int property accessor method to hide the configuration implementation. /// * /// </summary> /// <param name="String">key property key /// </param> /// <returns>int value /// /// </returns> int getInt(String key); /// <summary> Int property accessor method to hide the configuration implementation. /// * /// </summary> /// <param name="key"> property key /// </param> /// <param name="int">default value /// </param> /// <returns>int value /// /// </returns> int getInt(String key, int defaultValue); /// <summary> Boolean property accessor method to hide the configuration implementation. /// /// </summary> /// <param name="String">key property key /// </param> /// <param name="boolean">default default value if property not found /// </param> /// <returns>boolean value of key or default value /// /// </returns> bool getBoolean(String key, bool def); /// <summary> Return the velocity runtime configuration object. /// * /// </summary> /// <returns>ExtendedProperties configuration object which houses /// the velocity runtime properties. /// /// </returns> /* * Return this instance's Introspector */ /* * Return the specified applcation attribute */ Object getApplicationAttribute(Object key); } } --- NEW FILE: RuntimeInstance.cs --- namespace NVelocity.Runtime { using System; using System.Collections; using System.IO; using Commons.Collections; using NVelocity.Runtime.Parser.Node; using NVelocity.Runtime.Resource; using NVelocity.Runtime.Resource.Loader; using NVelocity.Util; using NVelocity.Util.Introspection; /// <summary> 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 [...1021 lines suppressed...] /// <summary> Return the velocity runtime configuration object. /// * /// </summary> /// <returns>ExtendedProperties configuration object which houses /// the velocity runtime properties. /// /// </returns> /// <summary> Return the Introspector for this instance /// </summary> public virtual Object getApplicationAttribute(Object key) { return applicationAttributes[key]; } public virtual Object setApplicationAttribute(Object key, Object o) { return applicationAttributes[key] = o; } } } --- NEW FILE: VelocimacroManager.cs --- namespace NVelocity.Runtime { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Velocity", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER... [truncated message content] |