SPRNET-1237: Custom namespace enhancements and some bug fixes

- Parsing of velocity properties in custom namespace 
- Additional configuration options for velocity resource loader and resource manager
- Additional namespace element for spring and custom resource loader definitions
This commit is contained in:
erezmazor
2009-08-01 12:00:30 +00:00
parent 05cfcbc832
commit 546003e095
13 changed files with 938 additions and 206 deletions

View File

@@ -51,7 +51,7 @@
linkend="objects-factory-lifecycle-factoryobject" />. A custom namespace
parser is provided to simplify the configuration of a NVelocity template
engine. For more information on custom namespace parser see <xref
linkend="context-custom-parsers" />. </para>
linkend="context-custom-parsers" />.</para>
<section xml:id="templating-nvelocity-file">
<title>Simple file based template engine definition</title>
@@ -67,7 +67,8 @@
&lt;/objects&gt;</programlisting>
<para>The velocity engine could then be used to load and merge a local
template using a simple relative path:</para>
template using a simple relative path (the default resource loader path
is the current execution directory):</para>
<programlisting language="csharp">StringWriter stringWriter = new StringWriter();
Hashtable modelTable = new Hashtable();
@@ -81,6 +82,86 @@ string mergedContent = stringWriter.ToString();</programlisting>
&lt;engine/&gt; to false.</para>
</section>
<section xml:id="templating-nvelocity-engine-configuration">
<title>Configuration Options</title>
<para>You can define several attributes on the &lt;engine&gt; element to
control how the factory is configured:</para>
<table id="template-velocity-engine-config-tbl">
<title>Engine Factory Configuration Options</title>
<tgroup cols="4">
<colspec colname="c1" colwidth="2*" />
<colspec colname="c2" colwidth="4*" />
<colspec colname="c3" colwidth="1*" />
<colspec colname="c4" colwidth="1*" />
<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
<entry>Default Value</entry>
</row>
</thead>
<tbody>
<row>
<entry>config-file</entry>
<entry>
<para>A uri of a properties file defining the NVelocity
configuration. This value accepts all spring resource loader
uri (e.g., file://, http://). See <xref
linkend="templating-nvelocity-resource-config" /></para>
</entry>
<entry>no</entry>
<entry>N/A</entry>
</row>
<row>
<entry>prefer-file-system-access</entry>
<entry>
<para>Instructs the NVelocity engine factory to attempt use
NVelocity's file loader. When set to false the provided
<literal>SpringResourceLoader</literal> will be used (and the <literal>ResourceLoaderPath</literal>
property must be set)</para>
</entry>
<entry>no</entry>
<entry>true</entry>
</row>
<row>
<entry>override-logging</entry>
<entry>
<para>Instructs the NVelocity engine factory to use the
provided spring commons logging based logging system. See See
<xref
linkend="templating-nvelocity-resource-logging" /></para>
</entry>
<entry>no</entry>
<entry>true</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section xml:id="templating-nvelocity-assembly">
<title>Assembly based template loading</title>
@@ -99,7 +180,7 @@ string mergedContent = stringWriter.ToString();</programlisting>
<programlisting language="csharp">velocityEngine.MergeTemplate("MyAssembly.MyNamespace.MyTemplate.vm", Encoding.UTF8.WebName, velocityContext, stringWriter);</programlisting>
</section>
<section xml:id="templating-nvelocity-resource-loader">
<section xml:id="templating-nvelocity-spring-resource-loader">
<title>Using Spring's <literal>IResourceLoader</literal> to load
templates</title>
@@ -110,9 +191,9 @@ string mergedContent = stringWriter.ToString();</programlisting>
object definition loads the NVelocity templates from a single
path</para>
<programlisting>&lt;nv:engine id="velocityEngine"&gt;
<programlisting language="myxml">&lt;nv:engine id="velocityEngine"&gt;
&lt;nv:resource-loader&gt;
&lt;nv:file path="MyTemplateFolder/AnotherFolder/" /&gt;
&lt;nv:spring uri="file://Template/Velocity/"/&gt;
&lt;/nv:resource-loader&gt;
&lt;/nv:engine&gt;</programlisting>
@@ -120,24 +201,127 @@ string mergedContent = stringWriter.ToString();</programlisting>
<programlisting language="myxml">&lt;nv:engine id="velocityEngine"&gt;
&lt;nv:resource-loader&gt;
&lt;nv:file path="MyTemplateFolder/AnotherFolder/" /&gt;
&lt;nv:file path="MyOtherTemplateFolder/" /&gt;
&lt;nv:spring uri="file://Template/Velocity/"/&gt;
&lt;nv:spring uri="assembly://MyAssembly/MyNameSpace"/&gt;
&lt;/nv:resource-loader&gt;
&lt;/nv:engine&gt;
</programlisting>
<note>
<para>By default spring will attempt to load resources using file
based template loading (useful for detection of template changes at
runtime). If this is not desirable you set the
<literal>prefer-file-system-access</literal> element of the
&lt;/engine&gt; element to <literal>false.</literal></para>
<para>By default spring will attempt to load resources using NVelocity's
file based template loading (useful for detection of template changes at
runtime). If this is not desirable you set the
<literal>prefer-file-system-access</literal> property of the factory object
to <literal>false</literal> which will cause the factory to utilize the supplied
spring resource loader.</para>
</note>
<para>Using the example above when resource loader paths are defined
templates can be loaded using their name:</para>
<programlisting language="csharp">string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "MyTemplate.vm", Encoding.UTF8.WebName, model);</programlisting>
<programlisting language="csharp">string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "MyFileTemplate.vm", Encoding.UTF8.WebName, model); // template loaded from file://Template/Velocity/
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "MyAseemblyTemplate.vm", Encoding.UTF8.WebName, model); // template loaded from assembly://MyAssembly/MyNameSpace</programlisting>
</section>
<section xml:id="templating-nvelocity-custom-resource-loader">
<title>Defining a custom resource loader</title>
<para>The following defines a custom resource loader (the type is an
extension of NVelocity's <literal>ResourceLoader</literal>
class):</para>
<programlisting language="myxml">&lt;nv:engine id="velocityEngine"&gt;
&lt;nv:resource-loader&gt;
&lt;nv:custom name="myResourceLoader"
description="A custom resource loader"
type="MyNamespace.MyResourceLoader, MyAssembly"
path="Template/Velocity/"/&gt;
&lt;/nv:resource-loader&gt;
&lt;/nv:engine&gt;
</programlisting>
</section>
<section xml:id="templating-nvelocity-resource-loader-configuration">
<title>Resource Loader configuration options</title>
<para>The &lt;nv:resource-loader&gt; element has additional attributes
which define how NVelocity's resource manager and resource loader
behave.</para>
<table id="templating-nvelocity-resource-loader-configuration-tbl">
<title>Resource Loader Configuration Options</title>
<tgroup cols="4">
<colspec colname="c1" colwidth="2*" />
<colspec colname="c2" colwidth="4*" />
<colspec colname="c3" colwidth="1*" />
<colspec colname="c4" colwidth="1*" />
<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
<entry>Required</entry>
<entry>Default Value</entry>
</row>
</thead>
<tbody>
<row>
<entry>default-cache-size</entry>
<entry>
<para>defines resource manager global cache size, applies when
caching is turned on. This maps to NVelocity's resource
manager <literal>resource.manager.defaultcache.size</literal>
property</para>
</entry>
<entry>no</entry>
<entry>89</entry>
</row>
<row>
<entry>template-caching</entry>
<entry>
<para>Enables template caching for the defined resource
loader. This maps to NVelocity's resource loader
<literal>&lt;name&gt;.resource.loader.cache</literal>
property</para>
</entry>
<entry>no</entry>
<entry>false</entry>
</row>
<row>
<entry>modification-check-interval</entry>
<entry>
<para>The modification check interval value (seconds) of the
resource loader, applies only to resource loader with change
detection capabilities (file or custom). This maps to
NVelocity's resource loader
<literal>&lt;name&gt;.resource.loader.modificationCheckInterval</literal>
property</para>
</entry>
<entry>no</entry>
<entry>2</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section xml:id="templating-nvelocity-resource-config">
@@ -152,7 +336,7 @@ string mergedContent = stringWriter.ToString();</programlisting>
<literal>VelocityProperties</literal> property to the NVelocity factory
object (shown above)</para>
<programlisting>&lt;nv:engine id="customNamespaceVelocityTemplate" config-file="foo.prop"&gt;
<programlisting language="myxml">&lt;nv:engine id="velocityTemplate" &gt;
&lt;nv:nvelocity-properties&gt;
&lt;entry key="input.encoding" value="ISO-8859-1"/&gt;
&lt;entry key="output.encoding" value="ISO-8859-1"/&gt;
@@ -161,12 +345,8 @@ string mergedContent = stringWriter.ToString();</programlisting>
</section>
<section xml:id="templating-nvelocity-resource-logging">
<title>Logging</title>
<para>By default Spring will override NVelocity's default
<literal>ILogSystem</literal> implementation with its own
<literal>CommonsLoggingLogSystem</literal> implementation so that the
@@ -174,12 +354,8 @@ string mergedContent = stringWriter.ToString();</programlisting>
Spring uses. If this is not desirable, you can specify the following
property of the NVelocity factory object:</para>
<programlisting language="myxml">&lt;template:nvelocity id="velocityEngine" override-logging="false" /&gt;
</programlisting>
</section>
</section>
@@ -202,7 +378,7 @@ string mergedContent = stringWriter.ToString();</programlisting>
<para>To create a VelocityEngine using the default file resource loader
use the definition:</para>
<programlisting>&lt;!-- Simple no arg file based configuration use's NVeclocity default file resource loader --&gt;
<programlisting language="myxml">&lt;!-- Simple no arg file based configuration use's NVelocity default file resource loader --&gt;
&lt;object id="velocityEngine" type="Spring.Template.Velocity.VelocityEngineFactoryObject, Spring.Template.Velocity" /&gt;</programlisting>
<para>For convenience in defining NVelocity engine instances a custom
@@ -210,13 +386,13 @@ string mergedContent = stringWriter.ToString();</programlisting>
done this way:</para>
<programlisting language="myxml">
&lt;objects xmlns="http://www.springframework.net" xmlns:template="http://www.springframework.net/template"&gt;
&lt;objects xmlns="http://www.springframework.net" xmlns:nv="http://www.springframework.net/nvelocity"&gt;
&lt;template:nvelocity id="customNamespaceVelocityTemplate" &gt;
&lt;template:resource-loader&gt;
&lt;template:file path="Template/Velocity/" /&gt;
&lt;/template:resource-loader&gt;
&lt;/template:nvelocity&gt;
&lt;nv:nvelocity id="velocityEngine" &gt;
&lt;nv:resource-loader&gt;
&lt;nv:file path="Template/Velocity/" /&gt;
&lt;/nv:resource-loader&gt;
&lt;/nv:nvelocity&gt;
&lt;/objects</programlisting>
@@ -224,7 +400,7 @@ string mergedContent = stringWriter.ToString();</programlisting>
resource loader can be used to define where templates reside:</para>
<programlisting language="myxml">&lt;!-- Assembly based template loading with NVelocity assembly resource loader --&gt;
&lt;object id="assemblyBasedVelocityEngine" type="Spring.Template.Velocity.VelocityEngineFactoryObject, Spring.Template.Velocity"&gt;
&lt;object id="velocityEngine" type="Spring.Template.Velocity.VelocityEngineFactoryObject, Spring.Template.Velocity"&gt;
&lt;property name="VelocityProperties"&gt;
&lt;dictionary key-type="string" value-type="object"&gt;
&lt;entry key="resource.loader" value="assembly"/&gt;
@@ -255,11 +431,12 @@ string mergedContent = stringWriter.ToString();</programlisting>
&lt;/object&gt;</programlisting>
<note>
<para>By default spring will attempt to load resources using file based
template loading (useful for detection of template changes at runtime).
If this is not desirable you set the
<para>By default spring will attempt to load resources using NVelocity's
file based template loading (useful for detection of template changes at
runtime). If this is not desirable you set the
<literal>preferFileSystemAccess</literal> property of the factory object
to <literal>false.</literal></para>
to <literal>false</literal> which will cause the factory to utilize the supplied
spring resource loader.</para>
</note>
<para>To refer to a property file based configuration of the
@@ -275,7 +452,7 @@ string mergedContent = stringWriter.ToString();</programlisting>
</note></para>
<para>To not integrate with the Common.Logging subsystem, set the
OverrideLogging property to false: </para>
OverrideLogging property to false:</para>
<programlisting language="myxml">&lt;object id="velocityEngine" type="Spring.Template.Velocity.VelocityEngineFactoryObject, Spring.Template.Velocity" &gt;
&lt;property name="OverrideLogging" value="false" /&gt;

View File

@@ -69,7 +69,8 @@
<ItemGroup>
<Compile Include="Template\Velocity\Config\TemplateNamespaceParser.cs" />
<Compile Include="Template\Velocity\CommonsLoggingLogSystem.cs" />
<Compile Include="Template\Velocity\SpringResourceLoader.cs" />
<Compile Include="Template\Velocity\SpringResourceLoader.cs" />
<Compile Include="Template\Velocity\VelocityConstants.cs" />
<Compile Include="Template\Velocity\VelocityEngineFactory.cs" />
<Compile Include="Template\Velocity\VelocityEngineFactoryObject.cs" />
<Compile Include="Template\Velocity\VelocityEngineUtils.cs" />

View File

@@ -21,9 +21,11 @@
#region Imports
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using NVelocity.Runtime;
using NVelocity.Runtime.Resource.Loader;
using Spring.Core.TypeResolution;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Support;
@@ -46,6 +48,7 @@ namespace Spring.Template.Velocity.Config {
]
public sealed class TemplateNamespaceParser : AbstractSingleObjectDefinitionParser {
private const string TemplateTypePrefix = "template: ";
private static readonly ObjectNamespaceParserHelper objectNamespaceParserHelper = new ObjectNamespaceParserHelper();
static TemplateNamespaceParser() {
TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject));
@@ -58,134 +61,369 @@ namespace Spring.Template.Velocity.Config {
}
/// <summary>
///
/// Parses single object definition for the templating namespace
/// </summary>
/// <param name="element"></param>
/// <param name="parserContext"></param>
/// <param name="builder"></param>
/// <param name="element">the current XmlElement to parse</param>
/// <param name="parserContext">the parser context</param>
/// <param name="builder">the ObjectDefinitionBuilder used to configure this object</param>
/// <see cref="AbstractSingleObjectDefinitionParser"/>
protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) {
switch (element.LocalName) {
case TemplateDefinitionConstants.NVelocityElement:
ParseNVelocityTemplate(element, parserContext, builder);
ParseNVelocityEngine(element, parserContext, builder);
return;
default:
throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName));
}
}
private void ParseNVelocityTemplate(XmlElement element, ParserContext parseContext, ObjectDefinitionBuilder builder) {
/// <summary>
/// Parses the object definition for the engine object, configures a single NVelocity template engine based
/// on the element definitions.
/// </summary>
/// <param name="element">the root element defining the velocity engine</param>
/// <param name="parserContext">the parser context</param>
/// <param name="builder">the ObjectDefinitionBuilder used to configure this object</param>
private void ParseNVelocityEngine(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) {
string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess);
string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging);
string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile);
if (StringUtils.HasText(preferFileSystemAccess)) {
builder.AddPropertyValue(NVelocityEngineFactoryProperties.PropertyPreferFileSystemAccess, preferFileSystemAccess);
builder.AddPropertyValue(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess);
}
if (StringUtils.HasText(overrideLogging)) {
builder.AddPropertyValue(NVelocityEngineFactoryProperties.PropertyOverrideLogging, overrideLogging);
builder.AddPropertyValue(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging);
}
if (StringUtils.HasText(configFile)) {
builder.AddPropertyValue(NVelocityEngineFactoryProperties.PropertyConfigFile, configFile);
builder.AddPropertyValue(TemplateDefinitionConstants.PropertyConfigFile, configFile);
}
XmlNodeList childElements = element.ChildNodes;
if (childElements.Count > 0) {
ParseChildDefinitions(childElements, parseContext, builder);
ParseChildDefinitions(childElements, parserContext, builder);
}
}
private void ParseChildDefinitions(XmlNodeList childElements, ParserContext context, ObjectDefinitionBuilder builder) {
/// <summary>
/// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here
/// </summary>
/// <param name="childElements">the XmlNodeList representing the child configuration of the root NVelocity engine element</param>
/// <param name="parserContext">the parser context</param>
/// <param name="builder">the ObjectDefinitionBuilder used to configure this object</param>
private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, ObjectDefinitionBuilder builder) {
IDictionary<string, object> properties = new Dictionary<string, object>();
foreach (XmlElement element in childElements) {
switch (element.LocalName) {
case TemplateDefinitionConstants.ElementResourceLoader:
ParseResourceLoader(element, context, builder, properties);
ParseResourceLoader(element, builder, properties);
break;
case TemplateDefinitionConstants.ElementNVelocityProperties:
ParseNVelocityProperties(element, properties);
ParseNVelocityProperties(element, parserContext, properties);
break;
}
}
if (properties.Count > 0) {
builder.AddPropertyValue(NVelocityEngineFactoryProperties.PropertyVelocityProperties, properties);
builder.AddPropertyValue(TemplateDefinitionConstants.PropertyVelocityProperties, properties);
}
}
private void ParseResourceLoader(XmlElement element, ParserContext context, ObjectDefinitionBuilder builder, IDictionary<string, object> properties) {
string loaderTypeDefinition = GetAttributeValue(element, TemplateDefinitionConstants.AttributeLoaderType);
/// <summary>
/// Configures the NVelocity resource loader definitions from the xml definition
/// </summary>
/// <param name="element">the root resource loader element</param>
/// <param name="builder">the ObjectDefinitionBuilder used to configure this object</param>
/// <param name="properties">the properties used to initialize the velocity engine</param>
private void ParseResourceLoader(XmlElement element, ObjectDefinitionBuilder builder, IDictionary<string, object> properties) {
string caching = GetAttributeValue(element, TemplateDefinitionConstants.AttributeTemplateCaching);
string defaultCacheSize = GetAttributeValue(element, TemplateDefinitionConstants.AttributeDefaultCacheSize);
string modificationCheckInterval = GetAttributeValue(element, TemplateDefinitionConstants.AttributeModificationCheckInterval);
if (!string.IsNullOrEmpty(defaultCacheSize)) {
properties.Add(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE, defaultCacheSize);
}
XmlNodeList loaderElements = element.ChildNodes;
foreach (XmlElement loaderElement in loaderElements) {
switch (loaderElement.LocalName) {
case TemplateDefinitionConstants.ElementResourceLoaderFile:
AppendResourceLoaderPaths(loaderElements, builder);
break;
case TemplateDefinitionConstants.ElementResourceLoaderAssembly:
AppendAssemblyLoaderProperties((XmlElement)loaderElements.Item(0), properties, loaderTypeDefinition);
break;
}
switch (loaderElements[0].LocalName) {
case VelocityConstants.File:
AppendFileLoaderProperties(loaderElements, properties);
AppendResourceLoaderGlobalProperties(properties, VelocityConstants.File, caching,
modificationCheckInterval);
break;
case VelocityConstants.Assembly:
AppendAssemblyLoaderProperties(loaderElements, properties);
AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null);
break;
case TemplateDefinitionConstants.Spring:
AppendResourceLoaderPaths(loaderElements, builder);
AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null);
break;
case TemplateDefinitionConstants.Custom:
XmlElement firstElement = (XmlElement)loaderElements.Item(0);
AppendCustomLoaderProperties(firstElement, properties);
AppendResourceLoaderGlobalProperties(properties, firstElement.LocalName, caching, modificationCheckInterval);
break;
default:
throw new ArgumentException(string.Format("undefined element for resource loadre type: {0}", element.LocalName));
}
}
private void AppendAssemblyLoaderProperties(XmlElement element, IDictionary<string, object> properties, string loaderTypeDefinition) {
string assemblyName = GetAttributeValue(element, TemplateDefinitionConstants.AttributeName);
string loaderType = (StringUtils.HasText(loaderTypeDefinition))
? loaderTypeDefinition
: "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader";
properties.Add(RuntimeConstants.RESOURCE_LOADER, element.LocalName);
properties.Add(element.LocalName + "." + RuntimeConstants.RESOURCE_LOADER + ".class", loaderType);
properties.Add(element.LocalName + "." + RuntimeConstants.RESOURCE_LOADER + ".assembly", assemblyName);
/// <summary>
/// Set the caching and modification interval checking properties of a resource loader of a given type
/// </summary>
/// <param name="properties">the properties used to initialize the velocity engine</param>
/// <param name="type">type of the resource loader</param>
/// <param name="caching">caching flag</param>
/// <param name="modificationInterval">modification interval value</param>
private void AppendResourceLoaderGlobalProperties(IDictionary<string, object> properties, string type, string caching, string modificationInterval) {
AppendResourceLoaderGlobalProperty(properties, type,
TemplateDefinitionConstants.PropertyResourceLoaderCaching,
Convert.ToBoolean(caching));
AppendResourceLoaderGlobalProperty
(properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval));
}
/// <summary>
/// Set global velocity resource loader properties (caching, modification interval etc.)
/// </summary>
/// <param name="properties">the properties used to initialize the velocity engine</param>
/// <param name="type">the type of resource loader</param>
/// <param name="property">the suffix property</param>
/// <param name="value">the value of the property</param>
private void AppendResourceLoaderGlobalProperty(IDictionary<string, object> properties, string type, string property, object value) {
if (null != value) {
properties.Add(type + VelocityConstants.Separator + property, value);
}
}
/// <summary>
/// Creates a nvelocity file based resource loader by setting the required properties
/// </summary>
/// <param name="elements">a list of nv:file elements defining the paths to template files</param>
/// <param name="properties">the properties used to initialize the velocity engine</param>
private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary<string, object> properties) {
IList paths = new List<string>(elements.Count);
foreach (XmlElement element in elements) {
paths.Add(GetAttributeValue(element, VelocityConstants.Path));
}
properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File);
properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class), TemplateDefinitionConstants.FileResourceLoaderClass);
properties.Add(getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path), StringUtils.CollectionToCommaDelimitedString(paths));
}
/// <summary>
/// Creates a nvelocity assembly based resource loader by setting the required properties
/// </summary>
/// <param name="elements">a list of nv:assembly elements defining the assemblies</param>
/// <param name="properties">the properties used to initialize the velocity engine</param>
private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary<string, object> properties) {
IList assemblies = new List<string>(elements.Count);
foreach (XmlElement element in elements) {
assemblies.Add(GetAttributeValue(element, VelocityConstants.Name));
}
properties.Add(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.Assembly);
properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class), TemplateDefinitionConstants.AssemblyResourceLoaderClass);
properties.Add(getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Assembly), StringUtils.CollectionToCommaDelimitedString(assemblies));
}
/// <summary>
/// Creates a spring resource loader by setting the ResourceLoaderPaths of the
/// engine factory (the resource loader itself will be created internally either as
/// spring or as file resource loader based on the value of prefer-file-system-access
/// attribute).
/// </summary>
/// <param name="elements">list of resource loader path elements</param>
/// <param name="builder">the object definiton builder to set the property for the engine factory</param>
private void AppendResourceLoaderPaths(XmlNodeList elements, ObjectDefinitionBuilder builder) {
IList<string> paths = new List<string>();
foreach (XmlElement element in elements) {
string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributePath);
string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri);
paths.Add(path);
}
builder.AddPropertyValue(NVelocityEngineFactoryProperties.PropertyResourceLoaderPaths, paths);
builder.AddPropertyValue(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths);
}
private void ParseNVelocityProperties(XmlElement element, IDictionary<string, object> dictionary) {
// todo add impl
/// <summary>
/// Create a custom resource loader from an nv:custom element
/// generates the 4 required nvelocity props for a resource loader (name, description, class and path).
/// </summary>
/// <param name="element">the nv:custom xml definition element</param>
/// <param name="properties">the properties used to initialize the velocity engine</param>
private void AppendCustomLoaderProperties(XmlElement element, IDictionary<string, object> properties) {
string name = GetAttributeValue(element, VelocityConstants.Name);
string description = GetAttributeValue(element, VelocityConstants.Description);
string type = GetAttributeValue(element, VelocityConstants.Type);
string path = GetAttributeValue(element, VelocityConstants.Path);
properties.Add(RuntimeConstants.RESOURCE_LOADER, name);
properties.Add(getResourceLoaderProperty(name, VelocityConstants.Description), description);
properties.Add(getResourceLoaderProperty(name, VelocityConstants.Class), type.Replace(',', ';'));
properties.Add(getResourceLoaderProperty(name, VelocityConstants.Path), path);
}
protected override string GetObjectTypeName(XmlElement element) {
string typeName = GetAttributeValue(element, ObjectDefinitionConstants.TypeAttribute);
if (StringUtils.IsNullOrEmpty(typeName)) {
return TemplateTypePrefix + element.LocalName;
/// <summary>
/// Parses the nvelocity properties map using <code>ObjectNamespaceParserHelper</code>
/// and appends it to the properties dictionary
/// </summary>
/// <param name="element">root element of the map element</param>
/// <param name="parserContext">the parser context</param>
/// <param name="properties">the properties used to initialize the velocity engine</param>
private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary<string, object> properties) {
IDictionary parsedProperties = objectNamespaceParserHelper.ParseDictionaryElementInternal(element, "NVelocityProperties", parserContext);
foreach (DictionaryEntry entry in parsedProperties) {
properties.Add(Convert.ToString(entry.Key), entry.Value);
}
return typeName;
}
/// <summary>
/// construct the element type name (e.g, nv:engine, nv:resource-loader)
/// </summary>
/// <param name="element">the current xml element</param>
protected override string GetObjectTypeName(XmlElement element) {
return TemplateTypePrefix + element.LocalName;
}
/// <summary>
/// Helper class to access the ParseDictionaryElement of the ObjectsNamespaceParser
/// todo: remove this and externalize the logic in ObjectsNamespaceParser.ParseDictionaryElement
/// </summary>
internal sealed class ObjectNamespaceParserHelper : ObjectsNamespaceParser {
public IDictionary ParseDictionaryElementInternal(XmlElement element, string name, ParserContext parserContext) {
return ParseDictionaryElement(element, name, parserContext);
}
}
/// <summary>
/// constructs an nvelocity style resource loader property in the format:
/// prefix.resource.loader.suffix
/// </summary>
/// <param name="type">the prefix</param>
/// <param name="suffix">the suffix</param>
/// <returns>a concatenated string like: prefix.resource.loader.suffix</returns>
public static string getResourceLoaderProperty(string type, string suffix) {
return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator +
suffix;
}
#region Element & Attribute Name Constants
private class TemplateDefinitionConstants {
/// <summary>
/// Template definition constants
/// </summary>
public class TemplateDefinitionConstants {
/// <summary>
/// Engine element definition
/// </summary>
public const string NVelocityElement = "engine";
public const string AttributePreferFileSystemAccess = "prefer-file-system-access";
public const string AttributeConfigFile = "config-file";
public const string AttributeOverrideLogging = "override-logging";
public const string AttributeLoaderType = "loader-type";
public const string ElementResourceLoader = "resource-loader";
public const string ElementResourceLoaderFile = "file";
public const string ElementResourceLoaderAssembly = "assembly";
public const string ElementNVelocityProperties = "nvelocity-properties";
public const string AttributeName = "name";
public const string AttributePath = "path";
}
private class NVelocityEngineFactoryProperties {
/// <summary>
/// Spring resource loader element definition
/// </summary>
public const string Spring = "spring";
/// <summary>
/// Custom resource loader element definition
/// </summary>
public const string Custom = "custom";
/// <summary>
/// uri attribute of the spring element
/// </summary>
public const string AttributeUri = "uri";
/// <summary>
/// prefer-file-system-access attribute of the engine factory
/// </summary>
public const string AttributePreferFileSystemAccess = "prefer-file-system-access";
/// <summary>
/// config-file attribute of the engine factory
/// </summary>
public const string AttributeConfigFile = "config-file";
/// <summary>
/// override-logging attribute of the engine factory
/// </summary>
public const string AttributeOverrideLogging = "override-logging";
/// <summary>
/// template-caching attribute of the nvelocity engine
/// </summary>
public const string AttributeTemplateCaching = "template-caching";
/// <summary>
/// default-cache-size attribute of the nvelocity engine resource manager
/// </summary>
public const string AttributeDefaultCacheSize = "default-cache-size";
/// <summary>
/// modification-check-interval attribute of the nvelocity engine resource loader
/// </summary>
public const string AttributeModificationCheckInterval = "modification-check-interval";
/// <summary>
/// resource loader element
/// </summary>
public const string ElementResourceLoader = "resource-loader";
/// <summary>
/// nvelocity propeties element (map)
/// </summary>
public const string ElementNVelocityProperties = "nvelocity-properties";
/// <summary>
/// PreferFileSystemAccess property of the engine factory
/// </summary>
public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess";
/// <summary>
/// OverrideLogging property of the engine factory
/// </summary>
public const string PropertyOverrideLogging = "OverrideLogging";
/// <summary>
/// ConfigLocation property of the engine factory
/// </summary>
public const string PropertyConfigFile = "ConfigLocation";
/// <summary>
/// ResourceLoaderPaths property of the engine factory
/// </summary>
public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths";
/// <summary>
/// VelocityProperties property of the engine factory
/// </summary>
public const string PropertyVelocityProperties = "VelocityProperties";
/// <summary>
/// resource.loader.cache property of the resource loader configuration
/// </summary>
public const string PropertyResourceLoaderCaching = "resource.loader.cache";
/// <summary>
/// resource.loader.modificationCheckInterval property of the resource loader configuration
/// </summary>
public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval";
/// <summary>
/// the type used for file resource loader
/// </summary>
public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity";
/// <summary>
/// the type used for assembly resource loader
/// </summary>
public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity";
/// <summary>
/// the type used for spring resource loader
/// </summary>
public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity";
}
#endregion
}

View File

@@ -50,7 +50,8 @@
<xsd:attribute name="config-file" use="optional">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation><![CDATA[Optional location of a properties file defining the NVelocity configuration.]]></xsd:documentation>
<xsd:documentation><![CDATA[Optional location of a properties file defining the
NVelocity configuration.]]></xsd:documentation>
</xsd:annotation>
<xsd:restriction base="objects:nonNullString"/>
</xsd:simpleType>
@@ -58,7 +59,8 @@
<xsd:attribute name="prefer-file-system-access" use="optional" default="true">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation><![CDATA[Optional. Instructs the NVelocity engine factory to attempt use NVelocity's file loader with hot tracking.]]></xsd:documentation>
<xsd:documentation><![CDATA[Optional. Instructs the NVelocity engine factory to
attempt use NVelocity's file loader with hot tracking.]]></xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:boolean"/>
</xsd:simpleType>
@@ -66,7 +68,8 @@
<xsd:attribute name="override-logging" use="optional" default="true">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation><![CDATA[Optional. Instructs the NVelocity engine factory to use the provided spring commons logging based logging system.]]></xsd:documentation>
<xsd:documentation><![CDATA[Optional. Instructs the NVelocity engine factory to use the provided
spring commons logging based logging system.]]></xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:boolean"/>
</xsd:simpleType>
@@ -79,9 +82,10 @@
<xsd:documentation><![CDATA[Defines Assembly based template loader.]]></xsd:documentation>
</xsd:annotation>
<xsd:choice>
<xsd:element name="assembly" minOccurs="1" maxOccurs="1">
<xsd:element name="assembly" minOccurs="1" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[The assembly where templates reside.]]></xsd:documentation>
<xsd:documentation><![CDATA[An assembly based resource loader, when used
NVelocity's AssemblyResourceLoader will be used.]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="name" type="objects:nonNullString" use="required">
@@ -94,7 +98,8 @@
</xsd:element>
<xsd:element name="file" minOccurs="1" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[The location of the template files.]]></xsd:documentation>
<xsd:documentation><![CDATA[A file based resource loader, when used NVelocity's
FileResourceLoader will be used.]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="path" type="objects:nonNullString" use="required">
@@ -104,14 +109,73 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="spring" minOccurs="1" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[A spring resource loader based on spring's resource abstraction.
When used detection of template changes is disabled]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="uri" type="objects:nonNullString" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[A fully qualified spring resource locator
(e.g., file://, assembly://, http://) uri]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="custom" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[A custom resource loader.]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="name" type="objects:nonNullString" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[A logical name (resource.loader property) for the resource loader
(e.g., custom), cannot contain whitespace.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="description" type="objects:nonNullString" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[Description (<name>.loader.description property) of the resource loader]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="type" type="objects:nonNullString" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[The type (<name>.resource.loader.class property) of the resource loader]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="path" type="objects:nonNullString" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[The paths (<name>.resource.loader.path property) of the resource loader]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:choice>
<xsd:attribute name="loader-type" type="objects:nonNullString" use="optional">
<xsd:attribute name="default-cache-size" type="xsd:integer" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[Optional. The NVelocity.Runtime.Resource.Loader.ResourceLoader extension class used to load the files. By default a file based resource loader is used (unless prefer-file-system-access is set to false)]]></xsd:documentation>
<xsd:documentation>
<![CDATA[Optional (default is 89, resource.manager.defaultcache.size property),
defines resource manager global cache size
applies when caching is turned on]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="template-caching" type="xsd:boolean" use="optional">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Enabled or disables template caching
(<name>.resource.loader.cache property) of the resource loader).]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="modification-check-interval" type="xsd:integer" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[The modification check interval value
(<name>.resource.loader.modificationCheckInterval property) of the resource loader,
applies only to resource loader with change detection capabilities (file or custom)]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="engine" type="nvelocityTemplate" />
</xsd:schema>

View File

@@ -0,0 +1,12 @@
namespace Spring.Template.Velocity{
public class VelocityConstants{
public const string File = "file";
public const string Type = "type";
public const string Assembly = "assembly";
public const string Class = "class";
public const string Name = "name";
public const string Description = "description";
public const string Path = "path";
public const string Separator = ".";
}
}

View File

@@ -31,6 +31,7 @@ using NVelocity.Runtime;
using NVelocity.Runtime.Resource.Loader;
using Spring.Context.Support;
using Spring.Core.IO;
using Spring.Util;
namespace Spring.Template.Velocity {
/// <summary>
@@ -195,18 +196,17 @@ namespace Spring.Template.Velocity {
/// <see cref="PostProcessVelocityEngine" />
/// <see cref="VelocityEngine.Init()" />
public VelocityEngine CreateVelocityEngine() {
VelocityEngine velocityEngine = NewVelocityEngine();
ExtendedProperties extendedProperties = new ExtendedProperties();
VelocityEngine velocityEngine = NewVelocityEngine();
// load defaults - see documentation why this is needed
LoadDefaultProperties(velocityEngine);
LoadDefaultProperties(extendedProperties);
// Load config file if set.
if (configLocation != null) {
if (log.IsInfoEnabled) {
log.Info(string.Format("Loading Velocity config from [{0}]", configLocation));
}
FillProperties(extendedProperties, configLocation);
FillProperties(extendedProperties, configLocation, false);
}
// merge local properties if set.
@@ -217,12 +217,12 @@ namespace Spring.Template.Velocity {
}
// Set a resource loader path, if required.
if( !preferFileSystemAccess && resourceLoaderPaths.Count == 0){
if (!preferFileSystemAccess && resourceLoaderPaths.Count == 0) {
throw new ArgumentException("When using SpringResourceLoader you must provide a path using the ResourceLoaderPath property");
}
if (resourceLoaderPaths.Count > 0) {
InitVelocityResourceLoader(velocityEngine, resourceLoaderPaths);
InitVelocityResourceLoader(velocityEngine, extendedProperties, resourceLoaderPaths);
}
// Log via Commons Logging?
@@ -233,13 +233,7 @@ namespace Spring.Template.Velocity {
PostProcessVelocityEngine(velocityEngine);
try {
// do not init with extended properties rather set one by one
foreach (DictionaryEntry property in extendedProperties) {
velocityEngine.SetProperty(Convert.ToString(property.Key), property.Value);
}
// velocity engine initialization - required
velocityEngine.Init();
velocityEngine.Init(extendedProperties);
} catch (Exception ex) {
throw new VelocityException(ex.ToString(), ex);
}
@@ -261,16 +255,11 @@ namespace Spring.Template.Velocity {
/// directive.manager=NVelocity.Runtime.Directive.DirectiveManager <br/>
/// runtime.introspector.uberspect=NVelocity.Util.Introspection.UberspectImpl <br/>
/// </summary>
/// <param name="velocityEngine">the instance of the velocity engine unto which we load the default properties</param>
private static void LoadDefaultProperties(VelocityEngine velocityEngine) {
ExtendedProperties extendedProperties = new ExtendedProperties();
private static void LoadDefaultProperties(ExtendedProperties extendedProperties) {
IResource defaultRuntimeProperties = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/nvelocity.properties");
IResource defaultRuntimeDirectives = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/directive.properties");
FillProperties(extendedProperties, defaultRuntimeProperties);
FillProperties(extendedProperties, defaultRuntimeDirectives);
foreach (DictionaryEntry property in extendedProperties) {
velocityEngine.SetProperty(Convert.ToString(property.Key), property.Value);
}
FillProperties(extendedProperties, defaultRuntimeProperties, true);
FillProperties(extendedProperties, defaultRuntimeDirectives, true);
}
/// <summary>
@@ -295,51 +284,37 @@ namespace Spring.Template.Velocity {
/// <see cref="SpringResourceLoader"/>
/// <see cref="InitSpringResourceLoader"/>
/// <see cref="CreateVelocityEngine"/>
protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, IList paths) {
protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, IList paths) {
if (PreferFileSystemAccess) {
// Try to load via the file system, fall back to SpringResourceLoader
// (for hot detection of template changes, if possible).
IList resolvedPaths = new ArrayList();
foreach (string path in paths){
foreach (string path in paths) {
IResource resource = ResourceLoader.GetResource(path);
resolvedPaths.Add(resource.File.FullName);
}
try {
velocityEngine.SetProperty(RuntimeConstants.RESOURCE_LOADER, "file");
velocityEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
velocityEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, joinList(resolvedPaths));
extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File);
extendedProperties.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH,
StringUtils.CollectionToCommaDelimitedString(resolvedPaths));
} catch (IOException ex) {
if (log.IsDebugEnabled) {
log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", joinList(resolvedPaths)), ex);
log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader",
StringUtils.CollectionToCommaDelimitedString(resolvedPaths)), ex);
}
InitSpringResourceLoader(velocityEngine, joinList(paths));
InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths));
}
} else {
// Always load via SpringResourceLoader (without hot detection of template changes).
if (log.IsDebugEnabled) {
log.Debug("File system access not preferred: using SpringResourceLoader");
}
InitSpringResourceLoader(velocityEngine, joinList(paths));
InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths));
}
}
/// <summary>
/// Join the list of strings to a comma delimited string
/// </summary>
/// <param name="values">values list of strings to join</param>
/// <returns>comma delimited string representation of the list</returns>
private static string joinList(IList values) {
StringBuilder result = new StringBuilder();
foreach (string value in values) {
result.Append(value);
result.Append(DELIMITER);
}
return result.ToString(0, result.Length < 1 ? 0 : result.Length - 1);
}
/// <summary>
/// Initialize a SpringResourceLoader for the given VelocityEngine.
/// <br/>Called by <code>InitVelocityResourceLoader</code>.
@@ -354,12 +329,11 @@ namespace Spring.Template.Velocity {
/// <param name="resourceLoaderPathString">resourceLoaderPath the path to load Velocity resources from</param>
/// <see cref="SpringResourceLoader"/>
/// <see cref="InitVelocityResourceLoader"/>
protected void InitSpringResourceLoader(VelocityEngine velocityEngine, string resourceLoaderPathString) {
velocityEngine.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME);
protected void InitSpringResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, string resourceLoaderPathString) {
extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME);
Type springResourceLoaderType = typeof(SpringResourceLoader);
string springResourceLoaderTypeName = springResourceLoaderType.FullName + "; " + springResourceLoaderType.Assembly.GetName().Name;
velocityEngine.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName);
velocityEngine.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true");
extendedProperties.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName);
velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader);
velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString);
}
@@ -375,7 +349,7 @@ namespace Spring.Template.Velocity {
/// <exception cref="IOException" />
/// <see cref="CreateVelocityEngine"/>
/// <see cref="VelocityEngine.Init()"/>
protected static void PostProcessVelocityEngine(VelocityEngine velocityEngine) {
protected void PostProcessVelocityEngine(VelocityEngine velocityEngine) {
}
/// <summary>
@@ -383,9 +357,18 @@ namespace Spring.Template.Velocity {
/// </summary>
/// <param name="extendedProperties">ExtendedProperties instance to populate</param>
/// <param name="resource">The resource from which to load the properties</param>
private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource) {
/// <param name="append">A flag indicated weather the properties loaded from the resource should be appended or replaced in the extendedProperties</param>
private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource, bool append) {
try {
extendedProperties.Load(resource.InputStream);
if (append) {
extendedProperties.Load(resource.InputStream);
} else {
ExtendedProperties overrides = new ExtendedProperties();
overrides.Load(resource.InputStream);
foreach (DictionaryEntry entry in overrides) {
extendedProperties.SetProperty(Convert.ToString(entry.Key), entry.Value);
}
}
} finally {
resource.InputStream.Close();
}

View File

@@ -47,7 +47,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Template\Velocity\Config\TemplateNamespaceParserTests.cs" />
<Compile Include="Template\Velocity\VelocityEngineFactoryObjectTests.cs" />
<Compile Include="Template\Velocity\VelocityEngineTestBase.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spring\Spring.Core\Spring.Core.2008.csproj">
@@ -75,6 +77,8 @@
<None Include="Template\Velocity\config.properties">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<EmbeddedResource Include="Template\Velocity\EmbeddedTemplate.vm">
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />

View File

@@ -0,0 +1,192 @@
#region License
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed 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.
*/
#endregion
#region Imports
using System.Collections;
using System.IO;
using Commons.Collections;
using NUnit.Framework;
using NVelocity.App;
using NVelocity.Runtime;
using NVelocity.Runtime.Resource;
using NVelocity.Runtime.Resource.Loader;
using Spring.Core.IO;
using Spring.Template.Velocity.Config;
#endregion
namespace Spring.Template.Velocity.Tests.Template.Velocity.Config {
/// <summary>
/// This class contains tests for the template namespace configuration parser
/// </summary>
/// <author>Erez Mazor</author>
[TestFixture]
public class TemplateNamespaceParserTests : VelocityEngineTestBase {
#region convinience properties aliases
private const string PropertyModificationCheck =
TemplateNamespaceParser.TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval;
private const string PropertyResourceLoaderCachce =
TemplateNamespaceParser.TemplateDefinitionConstants.PropertyResourceLoaderCaching;
#endregion
#region test constants
private const int DEFAULT_CACHE_SIZE = 200;
private const int DEFAULT_MOD_CHECK = 30;
private const bool DEFAULT_CACHE_FLAG = true;
#endregion
/// <summary>
/// Test a full file-base configuration
/// </summary>
[Test]
public void TestFileBasedConfig() {
VelocityEngine velocityEngine = appContext.GetObject("cnFileVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocity engine is null");
Assert.AreEqual(VelocityConstants.File, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual(TemplateNamespaceParser.TemplateDefinitionConstants.FileResourceLoaderClass, getSingleProperty(velocityEngine,
TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Class)), "incorrect resource loader type");
Assert.AreEqual(new string[]{"Template/Velocity/", "Template/"}, velocityEngine.GetProperty(
TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.File, VelocityConstants.Path)), "incorrect resource loader path");
Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size");
Assert.AreEqual(DEFAULT_MOD_CHECK, velocityEngine.GetProperty(
VelocityConstants.File + VelocityConstants.Separator + PropertyModificationCheck), "incorrect mod check interval");
Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.File + VelocityConstants.Separator + PropertyResourceLoaderCachce),
"incorrect caching flag");
AssertMergedValue(velocityEngine, "SimpleTemplate.vm");
}
/// <summary>
/// Test a full aaembly-based configuration
/// </summary>
[Test]
public void TestAssemblyBasedConfig() {
VelocityEngine velocityEngine = appContext.GetObject("cnAssemblyVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocity engine is null");
Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual(TemplateNamespaceParser.TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine,
TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type");
Assert.AreEqual("Spring.Template.Velocity.Tests", getSingleProperty(velocityEngine,
TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly,VelocityConstants.Assembly)), "incorrect resource loader path");
Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size");
Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(VelocityConstants.Assembly + VelocityConstants.Separator + PropertyResourceLoaderCachce),
"incorrect caching flag");
AssertMergedValue(velocityEngine, "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm");
}
/// <summary>
/// Test a full aaembly-based configuration
/// </summary>
[Test]
public void TestSpringBasedConfig() {
VelocityEngine velocityEngine = appContext.GetObject("cnSpringVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocity engine is null");
const string PropertySpring = TemplateNamespaceParser.TemplateDefinitionConstants.Spring;
Assert.AreEqual(PropertySpring, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual(TemplateNamespaceParser.TemplateDefinitionConstants.SpringResourceLoaderClass, getSingleProperty(velocityEngine,
TemplateNamespaceParser.getResourceLoaderProperty(PropertySpring, VelocityConstants.Class)), "incorrect resource loader type");
// no way to test the path property other than trying to actually perform a merge (it is set in velocity engine as an application attribute which is not exposed)
Assert.AreEqual(DEFAULT_CACHE_SIZE, velocityEngine.GetProperty(RuntimeConstants.RESOURCE_MANAGER_DEFAULTCACHE_SIZE), "incorrect default cache size");
Assert.AreEqual(DEFAULT_CACHE_FLAG, velocityEngine.GetProperty(PropertySpring + VelocityConstants.Separator + PropertyResourceLoaderCachce),
"incorrect caching flag");
AssertMergedValue(velocityEngine, "SimpleTemplate.vm");
AssertMergedValue(velocityEngine, "EmbeddedTemplate.vm");
}
/// <summary>
/// Test using an external configuration properties definition
/// </summary>
[Test]
public void TestGlobalConfig() {
VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngineConfig") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocity engine is null");
string classProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class);
string descProp = TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Description);
Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual("NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader",
getSingleProperty(velocityEngine,classProp), "incorrect resource loader type");
Assert.AreEqual("TestDescription", getSingleProperty(velocityEngine, descProp), "incorrect description");
}
/// <summary>
/// Test a custom resource loader definition
/// </summary>
[Test]
public void TestCustomResourceLoader() {
VelocityEngine velocityEngine = appContext.GetObject("cnVelocityEngingCustomResourceLoader") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocity engine is null");
const string PropertyMyResourceLoader = "myResourceLoader";
string classProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Class);
string descProp = TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Description);
Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual("Spring.Template.Velocity.Tests.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Tests",
getSingleProperty(velocityEngine, classProp), "incorrect resource loader type");
Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader");
Assert.AreEqual("A custom resource loader",
getSingleProperty(velocityEngine, descProp), "incorrect resource loader description");
Assert.AreEqual("Template/Velocity/", getSingleProperty(velocityEngine,
TemplateNamespaceParser.getResourceLoaderProperty(PropertyMyResourceLoader, VelocityConstants.Path)), "incorrect resource loader path");
AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm");
}
#region internal test methods
/// <summary>
/// Grab a single property from (if it's an array return the first value) from the velocityEngine
/// </summary>
private string getSingleProperty(VelocityEngine velocityEngine, string prop) {
object property = velocityEngine.GetProperty(prop);
if (property is ArrayList) {
ArrayList list = (ArrayList)property;
return (string)list[0];
}
return (string)property;
}
#endregion
}
#region test classes
/// <summary>
/// Test class for a custom resource loader class
/// </summary>
internal sealed class TestCustomResourceLoader : ResourceLoader {
public override void Init(ExtendedProperties configuration) {
}
public override Stream GetResourceStream(string source) {
return new ConfigurableResourceLoader().GetResource(source).InputStream;
}
public override bool IsSourceModified(Resource resource) {
return false;
}
public override long GetLastModified(Resource resource) {
return resource.LastModified;
}
}
#endregion
}

View File

@@ -0,0 +1 @@
value=${var1}

View File

@@ -21,42 +21,20 @@
#region Imports
using System;
using System.Collections;
using System.Text;
using NUnit.Framework;
using NVelocity.App;
using Spring.Context.Support;
using Spring.Objects.Factory.Xml;
#endregion
namespace Spring.Template.Velocity.Tests.Template.Velocity {
/// <summary>
/// This class contains tests for VelocityEngineFactoryObject
/// </summary>
/// <author>Mark Pollack</author>
/// <author>Erez Mazor</author>
[TestFixture]
public class VelocityEngineFactoryObjectTests {
private const string TEST_VALUE = "TEST_VALUE";
private XmlApplicationContext appContext;
private readonly Hashtable model = new Hashtable();
[SetUp]
public void Setup() {
appContext = new XmlApplicationContext(false,
ReadOnlyXmlTestResource.GetFilePath(
"VelocityEngineFactoryObjectTests.xml",
typeof(VelocityEngineFactoryObjectTests)));
model.Add("var1", TEST_VALUE);
}
[TearDown]
public void TearDown() {
appContext.Dispose();
model.Clear();
}
public class VelocityEngineFactoryObjectTests : VelocityEngineTestBase {
/// <summary>
/// Test the assemblyBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml
/// </summary>
@@ -64,9 +42,8 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
public void TestMergeUsingAssembly() {
VelocityEngine velocityEngine = appContext.GetObject("assemblyBasedVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm", Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate);
}
AssertMergedValue(velocityEngine, "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm");
}
/// <summary>
/// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml
@@ -75,9 +52,7 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
public void TestMergeUsingFile() {
VelocityEngine velocityEngine = appContext.GetObject("fileBasedVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(
velocityEngine, "Template/Velocity/SimpleTemplate.vm", Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate);
AssertMergedValue(velocityEngine, "Template/Velocity/SimpleTemplate.vm");
}
/// <summary>
@@ -86,11 +61,9 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
[Test]
public void TestMergeUsingCustomNamespaceDefinition() {
VelocityEngine velocityEngine =
appContext.GetObject("customNamespaceVelocityTemplate") as VelocityEngine;
appContext.GetObject("cnFileVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "SimpleTemplate.vm",
Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate);
AssertMergedValue(velocityEngine, "SimpleTemplate.vm");
}
/// <summary>
@@ -101,9 +74,7 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
VelocityEngine velocityEngine =
appContext.GetObject("pathBasedVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "SimpleTemplate.vm",
Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate);
AssertMergedValue(velocityEngine, "SimpleTemplate.vm");
}
/// <summary>
@@ -114,10 +85,7 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
VelocityEngine velocityEngine =
appContext.GetObject("propertiesFileBasedVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine,
"Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm",
Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate);
AssertMergedValue(velocityEngine, "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm");
}
/// <summary>
@@ -128,9 +96,7 @@ namespace Spring.Template.Velocity.Tests.Template.Velocity {
VelocityEngine velocityEngine =
appContext.GetObject("springResourceLoaderBasedVelocityEngine") as VelocityEngine;
Assert.IsNotNull(velocityEngine, "velocityEngine is null");
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, "SimpleTemplate.vm",
Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate);
AssertMergedValue(velocityEngine, "SimpleTemplate.vm");
}
/// <summary>

View File

@@ -1,12 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" xmlns:nv="http://www.springframework.net/nvelocity">
<nv:engine id="customNamespaceVelocityTemplate">
<nv:resource-loader>
<nv:file path="Template/Velocity/" />
<nv:engine id="cnFileVelocityEngine" >
<nv:resource-loader default-cache-size="200" modification-check-interval="30" template-caching="true">
<nv:file path="Template/Velocity/" />
<nv:file path="Template/" />
</nv:resource-loader>
</nv:engine>
<nv:engine id="cnAssemblyVelocityEngine" >
<nv:resource-loader default-cache-size="200" modification-check-interval="30" template-caching="true">
<nv:assembly name="Spring.Template.Velocity.Tests" />
</nv:resource-loader>
</nv:engine>
<nv:engine id="cnSpringVelocityEngine" prefer-file-system-access="false">
<nv:resource-loader default-cache-size="200" modification-check-interval="30" template-caching="true">
<nv:spring uri="file://Template/Velocity/"/>
<nv:spring uri="assembly://Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.Template.Velocity/"/>
</nv:resource-loader>
</nv:engine>
<nv:engine id="cnVelocityEngineConfig" config-file="file://Template/Velocity/config.properties" override-logging="false" />
<nv:engine id="cnVelocityEngingCustomResourceLoader">
<nv:resource-loader default-cache-size="200" modification-check-interval="30" template-caching="true">
<nv:custom name="myResourceLoader"
description="A custom resource loader"
type="Spring.Template.Velocity.Tests.Template.Velocity.Config.TestCustomResourceLoader, Spring.Template.Velocity.Tests"
path="Template/Velocity/"/>
</nv:resource-loader>
</nv:engine>
</nv:engine>
<!-- Does file system access with hot tracking with NVelocity assembly resource loader -->
<object id="assemblyBasedVelocityEngine" type="Spring.Template.Velocity.VelocityEngineFactoryObject, Spring.Template.Velocity">
<property name="VelocityProperties">

View File

@@ -0,0 +1,68 @@
#region License
/*
* Copyright © 2002-2009 the original author or authors.
*
* Licensed 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.
*/
#endregion
#region Imports
using System.Collections;
using System.Text;
using NUnit.Framework;
using NVelocity.App;
using Spring.Context.Support;
using Spring.Objects.Factory.Xml;
#endregion
namespace Spring.Template.Velocity.Tests.Template.Velocity {
public class VelocityEngineTestBase {
protected XmlApplicationContext appContext;
protected readonly Hashtable model = new Hashtable();
protected const string TEST_VALUE = "TEST_VALUE";
#region setup
[SetUp]
public void Setup() {
appContext = new XmlApplicationContext(false,
ReadOnlyXmlTestResource.GetFilePath(
"VelocityEngineFactoryObjectTests.xml",
typeof(VelocityEngineFactoryObjectTests)));
model.Add("var1", TEST_VALUE);
}
#endregion
#region teardown
[TearDown]
public void TearDown() {
appContext.Dispose();
model.Clear();
}
#endregion
#region base helper methods
/// <summary>
/// Basic method for asserting the expected TEST_VALUE in the merged template
/// </summary>
protected void AssertMergedValue(VelocityEngine velocityEngine, string template){
string mergedTemplate = VelocityEngineUtils.MergeTemplateIntoString(velocityEngine, template, Encoding.UTF8.WebName, model);
Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate);
}
#endregion
}
}

View File

@@ -1,3 +1,4 @@
resource.loader=assembly
assembly.resource.loader.class=NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader
assembly.resource.loader.assembly=Spring.Template.Velocity.Tests
assembly.resource.loader.assembly=Spring.Template.Velocity.Tests
assembly.resource.loader.description=TestDescription