From e46320ecbb073a8af08f590ef2834a9f32956e77 Mon Sep 17 00:00:00 2001 From: djechelon Date: Sun, 15 Mar 2015 18:54:34 +0100 Subject: [PATCH] NOW tests pass --- ...pring.Template.Velocity.Castle.2010.csproj | 4 +- .../Config/TemplateNamespaceParser.cs | 473 ++++++++++++++++++ .../Config/TemplateNamespaceParserTests.cs | 4 +- 3 files changed, 476 insertions(+), 5 deletions(-) create mode 100644 src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs diff --git a/src/Spring/Spring.Template.Velocity.Castle/Spring.Template.Velocity.Castle.2010.csproj b/src/Spring/Spring.Template.Velocity.Castle/Spring.Template.Velocity.Castle.2010.csproj index 19205663..99cbac0a 100644 --- a/src/Spring/Spring.Template.Velocity.Castle/Spring.Template.Velocity.Castle.2010.csproj +++ b/src/Spring/Spring.Template.Velocity.Castle/Spring.Template.Velocity.Castle.2010.csproj @@ -76,9 +76,6 @@ Template\Velocity\CommonsLoggingLogSystem.cs - - Template\Velocity\Config\TemplateNamespaceParser.cs - Template\Velocity\VelocityConstants.cs @@ -92,6 +89,7 @@ Template\Velocity\VelocityEngineUtils.cs + diff --git a/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs new file mode 100644 index 00000000..394ccdfa --- /dev/null +++ b/src/Spring/Spring.Template.Velocity.Castle/Template/Velocity/Config/TemplateNamespaceParser.cs @@ -0,0 +1,473 @@ +#region License + +/* + * Copyright 2002-2010 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; +using System.Collections; +using System.Collections.Generic; +using System.Xml; + +using NVelocity.Runtime; + +using Spring.Core.TypeResolution; +using Spring.Objects; +using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Support; +using Spring.Objects.Factory.Xml; +using Spring.Util; + +#endregion + +namespace Spring.Template.Velocity.Config { + /// + /// Implementation of the custom configuration parser for template configurations + /// based on + /// + /// + /// Erez Mazor + /// + [ + NamespaceParser( + Namespace = "http://www.springframework.net/nvelocity", + SchemaLocationAssemblyHint = typeof(TemplateNamespaceParser), + SchemaLocation = "/Spring.Template.Velocity.Config/spring-nvelocity-1.3.xsd") + ] + public class TemplateNamespaceParser : ObjectsNamespaceParser { + private const string TemplateTypePrefix = "template: "; + + static TemplateNamespaceParser() { + TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); + } + + /// + /// Initializes a new instance of the class. + /// + public TemplateNamespaceParser() { + } + + /// + public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext) { + string name = element.GetAttribute(ObjectDefinitionConstants.IdAttribute); + IConfigurableObjectDefinition templateDefinition = ParseTemplateDefinition(element, parserContext); + if (!StringUtils.HasText(name)) { + name = ObjectDefinitionReaderUtils.GenerateObjectName(templateDefinition, parserContext.Registry); + } + parserContext.Registry.RegisterObjectDefinition(name, templateDefinition); + return null; + } + + /// + /// Parse a template definition from the templating namespace + /// + /// the root element defining the templating object + /// the parser context + /// + private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) { + switch (element.LocalName) { + case TemplateDefinitionConstants.NVelocityElement: + return ParseNVelocityEngine(element, parserContext); + default: + throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); + } + } + + /// + /// Parses the object definition for the engine object, configures a single NVelocity template engine based + /// on the element definitions. + /// + /// the root element defining the velocity engine + /// the parser context + private IConfigurableObjectDefinition ParseNVelocityEngine(XmlElement element, ParserContext parserContext) { + string typeName = GetTypeName(element); + IConfigurableObjectDefinition configurableObjectDefinition = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition( + typeName, null, parserContext.ReaderContext.Reader.Domain); + + string preferFileSystemAccess = GetAttributeValue(element, TemplateDefinitionConstants.AttributePreferFileSystemAccess); + string overrideLogging = GetAttributeValue(element, TemplateDefinitionConstants.AttributeOverrideLogging); + string configFile = GetAttributeValue(element, TemplateDefinitionConstants.AttributeConfigFile); + + MutablePropertyValues objectDefinitionProperties = new MutablePropertyValues(); + if (StringUtils.HasText(preferFileSystemAccess)) { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); + } + + if (StringUtils.HasText(overrideLogging)) { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); + } + + if (StringUtils.HasText(configFile)) { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); + } + + XmlNodeList childElements = element.ChildNodes; + if (childElements.Count > 0) { + ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); + } + configurableObjectDefinition.PropertyValues = objectDefinitionProperties; + return configurableObjectDefinition; + } + + /// + /// Parses child element definitions for the NVelocity engine. Typically resource loaders and locally defined properties are parsed here + /// + /// the XmlNodeList representing the child configuration of the root NVelocity engine element + /// the parser context + /// the MutablePropertyValues used to configure this object + private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, MutablePropertyValues objectDefinitionProperties) { + IDictionary properties = new Dictionary(); + + foreach (XmlElement element in childElements) { + switch (element.LocalName) { + case TemplateDefinitionConstants.ElementResourceLoader: + ParseResourceLoader(element, objectDefinitionProperties, properties); + break; + case TemplateDefinitionConstants.ElementNVelocityProperties: + ParseNVelocityProperties(element, parserContext, properties); + break; + } + } + + if (properties.Count > 0) { + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); + } + } + + /// + /// Configures the NVelocity resource loader definitions from the xml definition + /// + /// the root resource loader element + /// the MutablePropertyValues used to configure this object + /// the properties used to initialize the velocity engine + private void ParseResourceLoader(XmlElement element, MutablePropertyValues objectDefinitionProperties, IDictionary 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; + 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, objectDefinitionProperties); + 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)); + } + } + + + /// + /// Set the caching and modification interval checking properties of a resource loader of a given type + /// + /// the properties used to initialize the velocity engine + /// type of the resource loader + /// caching flag + /// modification interval value + private void AppendResourceLoaderGlobalProperties(IDictionary properties, string type, string caching, string modificationInterval) { + AppendResourceLoaderGlobalProperty(properties, type, + TemplateDefinitionConstants.PropertyResourceLoaderCaching, + Convert.ToBoolean(caching)); + AppendResourceLoaderGlobalProperty + (properties, type, TemplateDefinitionConstants.PropertyResourceLoaderModificationCheckInterval, Convert.ToInt64(modificationInterval)); + } + + /// + /// Set global velocity resource loader properties (caching, modification interval etc.) + /// + /// the properties used to initialize the velocity engine + /// the type of resource loader + /// the suffix property + /// the value of the property + private void AppendResourceLoaderGlobalProperty(IDictionary properties, string type, string property, object value) { + if (null != value) { + properties.Add(type + VelocityConstants.Separator + property, value); + } + } + + /// + /// Creates a nvelocity file based resource loader by setting the required properties + /// + /// a list of nv:file elements defining the paths to template files + /// the properties used to initialize the velocity engine + private void AppendFileLoaderProperties(XmlNodeList elements, IDictionary properties) { + IList paths = new List(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)); + } + + /// + /// Creates a nvelocity assembly based resource loader by setting the required properties + /// + /// a list of nv:assembly elements defining the assemblies + /// the properties used to initialize the velocity engine + private void AppendAssemblyLoaderProperties(XmlNodeList elements, IDictionary properties) { + IList assemblies = new List(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)); + } + + /// + /// 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). + /// + /// list of resource loader path elements + /// the MutablePropertyValues to set the property for the engine factory + private void AppendResourceLoaderPaths(XmlNodeList elements, MutablePropertyValues objectDefinitionProperties) { + IList paths = new List(); + foreach (XmlElement element in elements) { + string path = GetAttributeValue(element, TemplateDefinitionConstants.AttributeUri); + paths.Add(path); + } + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); + } + + /// + /// 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). + /// + /// the nv:custom xml definition element + /// the properties used to initialize the velocity engine + private void AppendCustomLoaderProperties(XmlElement element, IDictionary 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); + } + + /// + /// Parses the nvelocity properties map using ObjectNamespaceParserHelper + /// and appends it to the properties dictionary + /// + /// root element of the map element + /// the parser context + /// the properties used to initialize the velocity engine + private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) { + IDictionary parsedProperties = ParseDictionaryElement(element, + TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); + foreach (DictionaryEntry entry in parsedProperties) { + properties.Add(Convert.ToString(entry.Key), entry.Value); + } + } + + /// + /// Gets the name of the object type for the specified element. + /// + /// The element. + /// The name of the object type. + private string GetTypeName(XmlElement element) { + string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute); + if (StringUtils.IsNullOrEmpty(typeName)) { + return TemplateTypePrefix + element.LocalName; + } + return typeName; + } + + /// + /// constructs an nvelocity style resource loader property in the format: + /// prefix.resource.loader.suffix + /// + /// the prefix + /// the suffix + /// a concatenated string like: prefix.resource.loader.suffix + public static string getResourceLoaderProperty(string type, string suffix) { + return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + + suffix; + } + + /// + /// This method is overriden from ObjectsNamespaceParser since when invoked on + /// sub-elements from the objets namespace (e.g., objects:objectMap for nvelocity + /// property map) the element.SelectNodes fails because it is in + /// the nvelocity custom namespace and not the object's namespace (http://www.springframwork.net) + /// to amend this the object's namespace is added to the provided XmlNamespaceManager + /// + /// The element to be searched in. + /// The name of the child nodes to look for. + /// + /// The child s of the supplied + /// with the supplied . + /// + /// + [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead")] + protected override XmlNodeList SelectNodes(XmlElement element, string childElementName) { + XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); + nsManager.AddNamespace(GetNamespacePrefix(element), Namespace); + return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager); + } + + private string GetNamespacePrefix(XmlElement element) { + return StringUtils.HasText(element.Prefix) ? element.Prefix : "spring"; + } + } + + + + #region Element & Attribute Name Constants + + /// + /// Template definition constants + /// + public class TemplateDefinitionConstants { + /// + /// Engine element definition + /// + public const string NVelocityElement = "engine"; + + /// + /// Spring resource loader element definition + /// + public const string Spring = "spring"; + + /// + /// Custom resource loader element definition + /// + public const string Custom = "custom"; + + /// + /// uri attribute of the spring element + /// + public const string AttributeUri = "uri"; + + /// + /// prefer-file-system-access attribute of the engine factory + /// + public const string AttributePreferFileSystemAccess = "prefer-file-system-access"; + + /// + /// config-file attribute of the engine factory + /// + public const string AttributeConfigFile = "config-file"; + + /// + /// override-logging attribute of the engine factory + /// + public const string AttributeOverrideLogging = "override-logging"; + + /// + /// template-caching attribute of the nvelocity engine + /// + public const string AttributeTemplateCaching = "template-caching"; + + /// + /// default-cache-size attribute of the nvelocity engine resource manager + /// + public const string AttributeDefaultCacheSize = "default-cache-size"; + + /// + /// modification-check-interval attribute of the nvelocity engine resource loader + /// + public const string AttributeModificationCheckInterval = "modification-check-interval"; + + /// + /// resource loader element + /// + public const string ElementResourceLoader = "resource-loader"; + + /// + /// nvelocity propeties element (map) + /// + public const string ElementNVelocityProperties = "nvelocity-properties"; + + /// + /// PreferFileSystemAccess property of the engine factory + /// + public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; + + /// + /// OverrideLogging property of the engine factory + /// + public const string PropertyOverrideLogging = "OverrideLogging"; + + /// + /// ConfigLocation property of the engine factory + /// + public const string PropertyConfigFile = "ConfigLocation"; + + /// + /// ResourceLoaderPaths property of the engine factory + /// + public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; + + /// + /// VelocityProperties property of the engine factory + /// + public const string PropertyVelocityProperties = "VelocityProperties"; + + /// + /// resource.loader.cache property of the resource loader configuration + /// + public const string PropertyResourceLoaderCaching = "resource.loader.cache"; + + /// + /// resource.loader.modificationCheckInterval property of the resource loader configuration + /// + public const string PropertyResourceLoaderModificationCheckInterval = "resource.loader.modificationCheckInterval"; + + /// + /// the type used for file resource loader + /// + public const string FileResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.FileResourceLoader; NVelocity"; + + /// + /// the type used for assembly resource loader + /// + public const string AssemblyResourceLoaderClass = "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader; NVelocity"; + + /// + /// the type used for spring resource loader + /// + public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity.Castle"; + } + #endregion +} \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs index 91172f8e..6a00cffd 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/Config/TemplateNamespaceParserTests.cs @@ -85,7 +85,7 @@ namespace Spring.Template.Velocity.Config { Assert.AreEqual(VelocityConstants.Assembly, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); Assert.AreEqual(TemplateDefinitionConstants.AssemblyResourceLoaderClass, getSingleProperty(velocityEngine, TemplateNamespaceParser.getResourceLoaderProperty(VelocityConstants.Assembly, VelocityConstants.Class)), "incorrect resource loader type"); - Assert.AreEqual("Spring.Template.Velocity.Tests", getSingleProperty(velocityEngine, + Assert.AreEqual("Spring.Template.Velocity.Castle.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), @@ -155,7 +155,7 @@ namespace Spring.Template.Velocity.Config { Assert.AreEqual(PropertyMyResourceLoader, getSingleProperty(velocityEngine, RuntimeConstants.RESOURCE_LOADER), "incorrect resource loader"); - Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Tests", + Assert.AreEqual("Spring.Template.Velocity.Config.TestCustomResourceLoader; Spring.Template.Velocity.Castle.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",