From f2d6955c8cee1e4bd568493e0c1abcb366ebf0b7 Mon Sep 17 00:00:00 2001 From: erezmazor Date: Mon, 3 Aug 2009 06:54:08 +0000 Subject: [PATCH] SPRNET-1237: TemplateNamespaceParser cleanup: extends ObjectsNamespaceParser instead of AbstractSingleObjectDefinitionParser to gain access to dictionary parsing. Made SelectNodes method in ObjectsNamespaceParser virtual to allow extending classes to override this method (provides ability to parse nested definitions from the objects namespace, e.g., objectMap, in other namespaces by adding the objects default namespace to the bound XmlNamespaceManager) --- .../Factory/Xml/ObjectsNamespaceParser.cs | 2 +- .../Config/TemplateNamespaceParser.cs | 405 +++++++----------- 2 files changed, 164 insertions(+), 243 deletions(-) diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs index 9b00a66c..3d4c5174 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Xml/ObjectsNamespaceParser.cs @@ -1247,7 +1247,7 @@ namespace Spring.Objects.Factory.Xml /// . /// [Obsolete("not used anymore - ObjectsNamespaceParser will be dropped with 2.x, use ObjectDefinitionParserHelper instead", false)] - protected XmlNodeList SelectNodes(XmlElement element, string childElementName) + protected virtual XmlNodeList SelectNodes(XmlElement element, string childElementName) { XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI); diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs index 510fac7b..789aec00 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/Config/TemplateNamespaceParser.cs @@ -27,6 +27,7 @@ using System.Xml; using NVelocity.Runtime; using NVelocity.Runtime.Resource.Loader; using Spring.Core.TypeResolution; +using Spring.Objects; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; @@ -39,17 +40,19 @@ using Spring.Util; 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 sealed class TemplateNamespaceParser : AbstractSingleObjectDefinitionParser { + public class TemplateNamespaceParser : ObjectsNamespaceParser { private const string TemplateTypePrefix = "template: "; - private static readonly ObjectNamespaceParserHelper objectNamespaceParserHelper = new ObjectNamespaceParserHelper(); static TemplateNamespaceParser() { TypeRegistry.RegisterType(TemplateTypePrefix + TemplateDefinitionConstants.NVelocityElement, typeof(VelocityEngineFactoryObject)); @@ -61,18 +64,27 @@ namespace Spring.Template.Velocity.Config { 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; + } + /// - /// Parses single object definition for the templating namespace + /// Parse a template definition from the templating namespace /// - /// the current XmlElement to parse + /// the root element defining the templating object /// the parser context - /// the ObjectDefinitionBuilder used to configure this object - /// - protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) { + /// + private IConfigurableObjectDefinition ParseTemplateDefinition(XmlElement element, ParserContext parserContext) { switch (element.LocalName) { case TemplateDefinitionConstants.NVelocityElement: - ParseNVelocityEngine(element, parserContext, builder); - return; + return ParseNVelocityEngine(element, parserContext); default: throw new ArgumentException(string.Format("undefined element for templating namespace: {0}", element.LocalName)); } @@ -84,28 +96,34 @@ namespace Spring.Template.Velocity.Config { /// /// the root element defining the velocity engine /// the parser context - /// the ObjectDefinitionBuilder used to configure this object - private void ParseNVelocityEngine(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder) { + 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)) { - builder.AddPropertyValue(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyPreferFileSystemAccess, preferFileSystemAccess); } if (StringUtils.HasText(overrideLogging)) { - builder.AddPropertyValue(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyOverrideLogging, overrideLogging); } if (StringUtils.HasText(configFile)) { - builder.AddPropertyValue(TemplateDefinitionConstants.PropertyConfigFile, configFile); + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyConfigFile, configFile); } XmlNodeList childElements = element.ChildNodes; if (childElements.Count > 0) { - ParseChildDefinitions(childElements, parserContext, builder); + ParseChildDefinitions(childElements, parserContext, objectDefinitionProperties); } + configurableObjectDefinition.PropertyValues = objectDefinitionProperties; + return configurableObjectDefinition; } /// @@ -113,14 +131,14 @@ namespace Spring.Template.Velocity.Config { /// /// the XmlNodeList representing the child configuration of the root NVelocity engine element /// the parser context - /// the ObjectDefinitionBuilder used to configure this object - private void ParseChildDefinitions(XmlNodeList childElements, ParserContext parserContext, ObjectDefinitionBuilder builder) { + /// 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, builder, properties); + ParseResourceLoader(element, objectDefinitionProperties, properties); break; case TemplateDefinitionConstants.ElementNVelocityProperties: ParseNVelocityProperties(element, parserContext, properties); @@ -129,7 +147,7 @@ namespace Spring.Template.Velocity.Config { } if (properties.Count > 0) { - builder.AddPropertyValue(TemplateDefinitionConstants.PropertyVelocityProperties, properties); + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyVelocityProperties, properties); } } @@ -137,9 +155,9 @@ namespace Spring.Template.Velocity.Config { /// Configures the NVelocity resource loader definitions from the xml definition /// /// the root resource loader element - /// the ObjectDefinitionBuilder used to configure this object + /// the MutablePropertyValues used to configure this object /// the properties used to initialize the velocity engine - private void ParseResourceLoader(XmlElement element, ObjectDefinitionBuilder builder, IDictionary properties) { + 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); @@ -160,7 +178,7 @@ namespace Spring.Template.Velocity.Config { AppendResourceLoaderGlobalProperties(properties, VelocityConstants.Assembly, caching, null); break; case TemplateDefinitionConstants.Spring: - AppendResourceLoaderPaths(loaderElements, builder); + AppendResourceLoaderPaths(loaderElements, objectDefinitionProperties); AppendResourceLoaderGlobalProperties(properties, TemplateDefinitionConstants.Spring, caching, null); break; case TemplateDefinitionConstants.Custom: @@ -239,14 +257,14 @@ namespace Spring.Template.Velocity.Config { /// attribute). /// /// list of resource loader path elements - /// the object definiton builder to set the property for the engine factory - private void AppendResourceLoaderPaths(XmlNodeList elements, ObjectDefinitionBuilder builder) { + /// 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); } - builder.AddPropertyValue(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); + objectDefinitionProperties.Add(TemplateDefinitionConstants.PropertyResourceLoaderPaths, paths); } /// @@ -274,7 +292,7 @@ namespace Spring.Template.Velocity.Config { /// the parser context /// the properties used to initialize the velocity engine private void ParseNVelocityProperties(XmlElement element, ParserContext parserContext, IDictionary properties) { - IDictionary parsedProperties = objectNamespaceParserHelper.ParseDictionaryElementInternal(element, + IDictionary parsedProperties = ParseDictionaryElement(element, TemplateDefinitionConstants.ElementNVelocityProperties, parserContext); foreach (DictionaryEntry entry in parsedProperties) { properties.Add(Convert.ToString(entry.Key), entry.Value); @@ -282,11 +300,16 @@ namespace Spring.Template.Velocity.Config { } /// - /// construct the element type name (e.g, nv:engine, nv:resource-loader) + /// Gets the name of the object type for the specified element. /// - /// the current xml element - protected override string GetObjectTypeName(XmlElement element) { - return TemplateTypePrefix + element.LocalName; + /// 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; } /// @@ -300,253 +323,151 @@ namespace Spring.Template.Velocity.Config { return type + VelocityConstants.Separator + RuntimeConstants.RESOURCE_LOADER + VelocityConstants.Separator + suffix; } - } - - - /// - /// Helper class to access the ParseDictionaryElement of the ObjectsNamespaceParser - /// todo: remove this and externalize the logic in ObjectsNamespaceParser.ParseDictionaryElement - /// - internal class ObjectNamespaceParserHelper : ObjectsNamespaceParser { /// - /// Gets a dictionary definition. + /// 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 describing the dictionary definition. - /// The name of the object (definition) associated with the dictionary definition. - /// The namespace-aware parser. - /// The dictionary definition. - public IDictionary ParseDictionaryElementInternal(XmlElement mapEle, string name, ParserContext parserContext) { - ManagedDictionary dictionary = new ManagedDictionary(); - string keyTypeName = GetAttributeValue(mapEle, "key-type"); - string valueTypeName = GetAttributeValue(mapEle, "value-type"); - if (StringUtils.HasText(keyTypeName)) { - dictionary.KeyTypeName = keyTypeName; - } - if (StringUtils.HasText(valueTypeName)) { - dictionary.ValueTypeName = valueTypeName; - } - dictionary.MergeEnabled = ParseMergeAttribute(mapEle, parserContext.ParserHelper); - - XmlNodeList entryElements = SelectNodes(mapEle, ObjectDefinitionConstants.EntryElement); - foreach (XmlElement entryEle in entryElements) { - #region Key - - object key = null; - - XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute]; - if (keyAtt != null) { - key = keyAtt.Value; - } else { - // ok, we're not using the 'key' attribute; lets check for the ref shortcut... - XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute]; - if (keyRefAtt != null) { - key = new RuntimeObjectReference(keyRefAtt.Value); - } else { - // so check for the 'key' element... - XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement); - if (keyNode == null) { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " + - "is required for the <{3}/> element.", - ObjectDefinitionConstants.KeyElement, - ObjectDefinitionConstants.KeyAttribute, - ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute, - ObjectDefinitionConstants.EntryElement)); - } - XmlElement keyElement = (XmlElement)keyNode; - XmlNodeList keyNodes = keyElement.GetElementsByTagName("*"); - if (keyNodes == null || keyNodes.Count == 0) { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("Malformed <{0}/> element... the value of the key must be " + - "specified as a child value-style element.", - ObjectDefinitionConstants.KeyElement)); - } - key = ParsePropertySubElement((XmlElement)keyNodes.Item(0), name, parserContext); - } - } - - #endregion - - #region Value - - XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute]; - if (inlineValueAtt != null) { - // ok, we're using the value attribute shortcut... - dictionary[key] = inlineValueAtt.Value; - } else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null) { - // ok, we're using the value-ref attribute shortcut... - XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute]; - RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value); - dictionary[key] = ror; - } else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null) { - // ok, we're using the expression attribute shortcut... - XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute]; - ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value); - dictionary[key] = expHolder; - } else { - XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement); - if (keyNode != null) { - entryEle.RemoveChild(keyNode); - } - // ok, we're using the original full-on value element... - XmlNodeList valueElements = entryEle.GetElementsByTagName("*"); - if (valueElements == null || valueElements.Count == 0) { - throw new ObjectDefinitionStoreException( - parserContext.ReaderContext.Resource, name, - string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " + - "is required for the <{2}/> element.", - ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement)); - } - dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserContext); - } - - #endregion - } - return dictionary; - } - private bool ParseMergeAttribute(XmlElement collectionElement, ObjectDefinitionParserHelper helper) { - string val = collectionElement.GetAttribute(ObjectDefinitionConstants.MergeAttribute); - if (ObjectDefinitionConstants.DefaultValue.Equals(val)) { - val = helper.Defaults.Merge; - } - return ObjectDefinitionConstants.TrueValue.Equals(val); - } - - /// - /// This method overrides SelectNodes from ObjectsNamespaceParser because the original method - /// picks up the NamespaceURI from the nvelocity which causes element.SelectNodes to return an empty - /// list. Consider removing. - /// - protected new XmlNodeList SelectNodes(XmlElement element, string childElementName) { + /// 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 { /// - /// Template definition constants + /// Engine element definition /// - public class TemplateDefinitionConstants { - /// - /// Engine element definition - /// - public const string NVelocityElement = "engine"; + public const string NVelocityElement = "engine"; - /// - /// Spring resource loader element definition - /// - public const string Spring = "spring"; + /// + /// Spring resource loader element definition + /// + public const string Spring = "spring"; - /// - /// Custom resource loader element definition - /// - public const string Custom = "custom"; + /// + /// Custom resource loader element definition + /// + public const string Custom = "custom"; - /// - /// uri attribute of the spring element - /// - public const string AttributeUri = "uri"; + /// + /// 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"; + /// + /// 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"; + /// + /// 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"; + /// + /// 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"; + /// + /// 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"; + /// + /// 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"; + /// + /// 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"; + /// + /// resource loader element + /// + public const string ElementResourceLoader = "resource-loader"; - /// - /// nvelocity propeties element (map) - /// - public const string ElementNVelocityProperties = "nvelocity-properties"; + /// + /// nvelocity propeties element (map) + /// + public const string ElementNVelocityProperties = "nvelocity-properties"; - /// - /// PreferFileSystemAccess property of the engine factory - /// - public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; + /// + /// PreferFileSystemAccess property of the engine factory + /// + public const string PropertyPreferFileSystemAccess = "PreferFileSystemAccess"; - /// - /// OverrideLogging property of the engine factory - /// - public const string PropertyOverrideLogging = "OverrideLogging"; + /// + /// OverrideLogging property of the engine factory + /// + public const string PropertyOverrideLogging = "OverrideLogging"; - /// - /// ConfigLocation property of the engine factory - /// - public const string PropertyConfigFile = "ConfigLocation"; + /// + /// ConfigLocation property of the engine factory + /// + public const string PropertyConfigFile = "ConfigLocation"; - /// - /// ResourceLoaderPaths property of the engine factory - /// - public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; + /// + /// ResourceLoaderPaths property of the engine factory + /// + public const string PropertyResourceLoaderPaths = "ResourceLoaderPaths"; - /// - /// VelocityProperties property of the engine factory - /// - public const string PropertyVelocityProperties = "VelocityProperties"; + /// + /// 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.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"; + /// + /// 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 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 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"; - } - #endregion + /// + /// the type used for spring resource loader + /// + public const string SpringResourceLoaderClass = "Spring.Template.Velocity.SpringResourceLoader; Spring.Template.Velocity"; + } + #endregion } \ No newline at end of file