From 027206c53c368f43b8f473b2fa2b6aa10ad58623 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Sun, 19 Oct 2008 12:20:29 +0000 Subject: [PATCH] resolved SPRNET-1035 --- .../Config/VariablePlaceholderConfigurer.cs | 636 +++++++++--------- .../VariablePlaceholderConfigurerTests.cs | 45 +- 2 files changed, 380 insertions(+), 301 deletions(-) diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs index 596d10c0..7ac85308 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright 2002-2007 the original author or authors. * @@ -14,302 +14,338 @@ * 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 - -using System; -using System.Collections; -using System.Globalization; -using Common.Logging; -using Spring.Collections; -using Spring.Core; - -namespace Spring.Objects.Factory.Config -{ - /// - /// Resolves placeholder values in one or more object definitions - /// - /// - /// The placeholder syntax follows the NAnt style: ${...}. - /// Placeholders values are resolved against a list of - /// s. In case of multiple definitions - /// for the same property placeholder name, the first one in the - /// list is used. - /// Variable substitution is performed on simple property values, - /// lists, dictionaries, sets, constructor - /// values, object type name, and object names in - /// runtime object references ( - /// ). - /// Furthermore, placeholder values can also cross-reference other - /// placeholders, in the manner of the following example where the - /// rootPath property is cross-referenced by the subPath - /// property. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// If a configurer cannot resolve a placeholder, and the value of the - /// - /// property is currently set to , an - /// - /// will be thrown. - /// - /// Mark Pollack - public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IOrdered - { - #region Fields - private int order = Int32.MaxValue; // default: same as non-Ordered - - private bool ignoreUnresolvablePlaceholders; - - private IList variableSourceList; - #endregion - - #region Properties - - /// - /// Sets the list of s that will be used to resolve placeholder names. - /// - /// A list of s. - public IList VariableSources - { - set { variableSourceList = value; } - } - - /// - /// Sets that will be used to resolve placeholder names. - /// - /// A instance. - public IVariableSource VariableSource - { - set - { - variableSourceList = new ArrayList(); - variableSourceList.Add(value); - } - } - - /// - /// Indicates whether unresolved placeholders should be ignored. - /// - public bool IgnoreUnresolvablePlaceholders - { - set { ignoreUnresolvablePlaceholders = value; } - } - - #endregion - - #region IObjectFactoryPostProcessor Members - - /// - /// Modify the application context's internal object factory after its - /// standard initialization. - /// - /// The object factory used by the application context. - /// - ///

- /// All object definitions will have been loaded, but no objects will have - /// been instantiated yet. This allows for overriding or adding properties - /// even to eager-initializing objects. - ///

- ///
- /// - /// In case of errors. - /// - public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory) - { - try - { - ProcessProperties(factory); - } - catch (Exception ex) - { - if (typeof (ObjectsException).IsInstanceOfType(ex)) - { - throw; - } - else - { - throw new ObjectsException( - "Errored while postprocessing an object factory.", ex); - } - } - } - - #endregion - - #region IOrdered Members - - /// - /// Return the order value of this object, where a higher value means greater in - /// terms of sorting. - /// - /// The order value. - /// - public int Order - { - get { return order; } - set { order = value; } - } - - #endregion - - /// - /// Apply the property replacement using the specified s for all - /// object in the supplied - /// . - /// - /// - /// The - /// used by the application context. - /// - /// - /// If an error occured. - /// - protected virtual void ProcessProperties(IConfigurableListableObjectFactory factory) - { - IVariableSource compositeVariableSource = - new PlaceholderResolvingCompositeVariableSource(variableSourceList, ignoreUnresolvablePlaceholders); - ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(compositeVariableSource); - - string[] objectDefinitionNames = factory.GetObjectDefinitionNames(); - for (int i = 0; i < objectDefinitionNames.Length; ++i) - { - string name = objectDefinitionNames[i]; - IObjectDefinition definition = factory.GetObjectDefinition(name); - try - { - visitor.VisitObjectDefinition(definition); - } - catch (ObjectDefinitionStoreException ex) - { - throw new ObjectDefinitionStoreException( - definition.ResourceDescription, name, ex.Message); - } - } - } - } - - #region Helper class - internal class PlaceholderResolvingCompositeVariableSource : IVariableSource - { - private string placeholderPrefix = "${"; - private string placeholderSuffix = "}"; - private bool ignoreUnresolvablePlaceholders; - - private ILog logger = LogManager.GetLogger(typeof (PlaceholderResolvingCompositeVariableSource)); - - private IList variableSourceList; - - public PlaceholderResolvingCompositeVariableSource(IList variableSourceList, bool ignoreUnresolvablePlaceholders) - { - this.variableSourceList = variableSourceList; - this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; - } - - #region IVariableSource Members - - public string ResolveVariable(string rawStringValue) - { - return ParseAndResolveVariable(rawStringValue, new HashedSet()); - } - - - //TODO handle resolved values at are not string - identify this case as only 1 placeholder present? - - private string ParseAndResolveVariable(string strVal, ISet visitedPlaceholders) - { - int startIndex = strVal.IndexOf(placeholderPrefix); - while (startIndex != -1) - { - int endIndex = strVal.IndexOf( - placeholderSuffix, startIndex + placeholderPrefix.Length); - if (endIndex != -1) - { - int pos = startIndex + placeholderPrefix.Length; - string placeholder = strVal.Substring(pos, endIndex - pos); - if (visitedPlaceholders.Contains(placeholder)) - { - throw new ObjectDefinitionStoreException( - string.Format( - CultureInfo.InvariantCulture, - "Circular placeholder reference '{0}' detected. ", - placeholder)); - } - visitedPlaceholders.Add(placeholder); - string resolvedValue = ResolvePlaceholderVariable(placeholder); - if (resolvedValue != null) - { - resolvedValue = ParseAndResolveVariable(resolvedValue, visitedPlaceholders); - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug(string.Format( - CultureInfo.InvariantCulture, - "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue)); - } - - #endregion - - strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1); - startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length); - } - else if (ignoreUnresolvablePlaceholders) - { - // simply return the unprocessed value... - return strVal; - } - else - { - throw new ObjectDefinitionStoreException(string.Format( - CultureInfo.InvariantCulture, - "Could not resolve placeholder '{0}'.", placeholder)); - } - visitedPlaceholders.Remove(placeholder); - } - else - { - startIndex = -1; - } - } - return strVal; - } - - private string ResolvePlaceholderVariable(string variableName) - { - foreach (IVariableSource variableSource in variableSourceList) - { - //TODO handle resolved values at are not strings? - - object resolvedValue = variableSource.ResolveVariable(variableName); - if (resolvedValue is string) - { - } - if (resolvedValue != null) - { - if (resolvedValue is string) - { - return resolvedValue as string; - } - else - { - logger.Warn("Placeholder " + variableSource + " resolved to object type [" + resolvedValue.GetType() + "]. Only string type currently supported"); - } - } - } - return null; - } - - #endregion - } - - #endregion + */ + +#endregion + +using System; +using System.Collections; +using System.Globalization; +using Common.Logging; +using Spring.Collections; +using Spring.Core; + +namespace Spring.Objects.Factory.Config +{ + /// + /// Resolves placeholder values in one or more object definitions + /// + /// + /// The placeholder syntax follows the NAnt style: ${...}. + /// Placeholders values are resolved against a list of + /// s. In case of multiple definitions + /// for the same property placeholder name, the first one in the + /// list is used. + /// Variable substitution is performed on simple property values, + /// lists, dictionaries, sets, constructor + /// values, object type name, and object names in + /// runtime object references ( + /// ). + /// Furthermore, placeholder values can also cross-reference other + /// placeholders, in the manner of the following example where the + /// rootPath property is cross-referenced by the subPath + /// property. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// If a configurer cannot resolve a placeholder, and the value of the + /// + /// property is currently set to , an + /// + /// will be thrown. + /// + /// Mark Pollack + public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IOrdered + { + /// + /// The default placeholder prefix. + /// + public const string DefaultPlaceholderPrefix = "${"; + + /// + /// The default placeholder suffix. + /// + public const string DefaultPlaceholderSuffix = "}"; + + #region Fields + + private int order = Int32.MaxValue; // default: same as non-Ordered + + private bool ignoreUnresolvablePlaceholders; + private string placeholderPrefix = DefaultPlaceholderPrefix; + private string placeholderSuffix = DefaultPlaceholderSuffix; + + private IList variableSourceList; + + #endregion + + #region Properties + + /// + /// Sets the list of s that will be used to resolve placeholder names. + /// + /// A list of s. + public IList VariableSources + { + set { variableSourceList = value; } + } + + /// + /// Sets that will be used to resolve placeholder names. + /// + /// A instance. + public IVariableSource VariableSource + { + set + { + variableSourceList = new ArrayList(); + variableSourceList.Add( value ); + } + } + + /// + /// The placeholder prefix (the default is ${). + /// + /// + public string PlaceholderPrefix + { + set { placeholderPrefix = value; } + } + + /// + /// The placeholder suffix (the default is }) + /// + /// + public string PlaceholderSuffix + { + set { placeholderSuffix = value; } + } + + /// + /// Indicates whether unresolved placeholders should be ignored. + /// + public bool IgnoreUnresolvablePlaceholders + { + set { ignoreUnresolvablePlaceholders = value; } + } + + #endregion + + #region IObjectFactoryPostProcessor Members + + /// + /// Modify the application context's internal object factory after its + /// standard initialization. + /// + /// The object factory used by the application context. + /// + ///

+ /// All object definitions will have been loaded, but no objects will have + /// been instantiated yet. This allows for overriding or adding properties + /// even to eager-initializing objects. + ///

+ ///
+ /// + /// In case of errors. + /// + public void PostProcessObjectFactory( IConfigurableListableObjectFactory factory ) + { + try + { + ProcessProperties( factory ); + } + catch (Exception ex) + { + if (typeof( ObjectsException ).IsInstanceOfType( ex )) + { + throw; + } + else + { + throw new ObjectsException( + "Errored while postprocessing an object factory.", ex ); + } + } + } + + #endregion + + #region IOrdered Members + + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// The order value. + /// + public int Order + { + get { return order; } + set { order = value; } + } + + #endregion + + /// + /// Apply the property replacement using the specified s for all + /// object in the supplied + /// . + /// + /// + /// The + /// used by the application context. + /// + /// + /// If an error occured. + /// + protected virtual void ProcessProperties( IConfigurableListableObjectFactory factory ) + { + IVariableSource compositeVariableSource = new PlaceholderResolvingCompositeVariableSource( placeholderPrefix + , placeholderSuffix + , variableSourceList + , ignoreUnresolvablePlaceholders ); + ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor( compositeVariableSource ); + + string[] objectDefinitionNames = factory.GetObjectDefinitionNames(); + for (int i = 0; i < objectDefinitionNames.Length; ++i) + { + string name = objectDefinitionNames[i]; + IObjectDefinition definition = factory.GetObjectDefinition( name ); + try + { + visitor.VisitObjectDefinition( definition ); + } + catch (ObjectDefinitionStoreException ex) + { + throw new ObjectDefinitionStoreException( + definition.ResourceDescription, name, ex.Message ); + } + } + } + + #region Helper class + + private class PlaceholderResolvingCompositeVariableSource : IVariableSource + { + private readonly ILog logger = LogManager.GetLogger( typeof( PlaceholderResolvingCompositeVariableSource ) ); + + private readonly string placeholderPrefix; + private readonly string placeholderSuffix; + private readonly bool ignoreUnresolvablePlaceholders; + private readonly IList variableSourceList; + + public PlaceholderResolvingCompositeVariableSource( string placeholderPrefix, string placeholderSuffix, IList variableSourceList, bool ignoreUnresolvablePlaceholders ) + { + this.placeholderPrefix = placeholderPrefix; + this.placeholderSuffix = placeholderSuffix; + this.variableSourceList = variableSourceList; + this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; + } + + #region IVariableSource Members + + public string ResolveVariable( string rawStringValue ) + { + return ParseAndResolveVariable( rawStringValue, new HashedSet() ); + } + + + //TODO handle resolved values at are not string - identify this case as only 1 placeholder present? + + private string ParseAndResolveVariable( string strVal, ISet visitedPlaceholders ) + { + int startIndex = strVal.IndexOf( placeholderPrefix ); + while (startIndex != -1) + { + int endIndex = strVal.IndexOf( + placeholderSuffix, startIndex + placeholderPrefix.Length ); + if (endIndex != -1) + { + int pos = startIndex + placeholderPrefix.Length; + string placeholder = strVal.Substring( pos, endIndex - pos ); + if (visitedPlaceholders.Contains( placeholder )) + { + throw new ObjectDefinitionStoreException( + string.Format( + CultureInfo.InvariantCulture, + "Circular placeholder reference '{0}' detected. ", + placeholder ) ); + } + visitedPlaceholders.Add( placeholder ); + string resolvedValue = ResolvePlaceholderVariable( placeholder ); + if (resolvedValue != null) + { + resolvedValue = ParseAndResolveVariable( resolvedValue, visitedPlaceholders ); + + #region Instrumentation + + if (logger.IsDebugEnabled) + { + logger.Debug( string.Format( + CultureInfo.InvariantCulture, + "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue ) ); + } + + #endregion + + strVal = strVal.Substring( 0, startIndex ) + resolvedValue + strVal.Substring( endIndex + placeholderSuffix.Length ); + startIndex = strVal.IndexOf( placeholderPrefix, startIndex + resolvedValue.Length); + } + else if (ignoreUnresolvablePlaceholders) + { + // simply return the unprocessed value... + return strVal; + } + else + { + throw new ObjectDefinitionStoreException( string.Format( + CultureInfo.InvariantCulture, + "Could not resolve placeholder '{0}'.", placeholder ) ); + } + visitedPlaceholders.Remove( placeholder ); + } + else + { + startIndex = -1; + } + } + return strVal; + } + + private string ResolvePlaceholderVariable( string variableName ) + { + foreach (IVariableSource variableSource in variableSourceList) + { + //TODO handle resolved values at are not strings? + + object resolvedValue = variableSource.ResolveVariable( variableName ); + if (resolvedValue is string) + { + } + if (resolvedValue != null) + { + if (resolvedValue is string) + { + return resolvedValue as string; + } + else + { + logger.Warn( "Placeholder " + variableSource + " resolved to object type [" + resolvedValue.GetType() + "]. Only string type currently supported" ); + } + } + } + return null; + } + + #endregion + } + + #endregion + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs index 2f4a4499..fe91ceb7 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/VariablePlaceholderConfigurerTests.cs @@ -35,6 +35,24 @@ namespace Spring.Objects.Factory.Config [TestFixture] public class VariablePlaceholderConfigurerTests { + private class DictionaryVariableSource : IVariableSource + { + private Hashtable variables = new Hashtable(); + + public DictionaryVariableSource(params string[] args) + { + for(int i=0;i