SPRNET-1243

SPRNET-1167
This commit is contained in:
eeichinger
2009-07-29 20:59:47 +00:00
parent 20346f459f
commit 18b7d1eedd
21 changed files with 562 additions and 225 deletions

View File

@@ -87,6 +87,21 @@ namespace Spring.Objects.Factory.Config
set { valueSeparator = value; }
}
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
if (arguments == null)
{
InitArguments();
}
return arguments.Contains(name);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -92,6 +92,21 @@ namespace Spring.Objects.Factory.Config
set { sectionNames = new string[] { value }; }
}
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
if (variables == null)
{
InitVariables();
}
return CollectionUtils.Contains(variables.AllKeys, name);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -20,6 +20,7 @@
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using Spring.Util;
@@ -53,8 +54,24 @@ namespace Spring.Objects.Factory.Config
[Serializable]
public class ConnectionStringsVariableSource : IVariableSource
{
private NameValueCollection variables;
private Hashtable variables;
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
if (variables == null)
{
InitVariables();
}
return variables.Contains(name);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>
@@ -70,7 +87,7 @@ namespace Spring.Objects.Factory.Config
{
InitVariables();
}
return variables.Get(name);
return (string) variables[name];
}
/// <summary>
@@ -79,7 +96,7 @@ namespace Spring.Objects.Factory.Config
/// </summary>
private void InitVariables()
{
variables = new NameValueCollection();
variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
foreach (ConnectionStringSettings setting in settings)
{

View File

@@ -0,0 +1,135 @@
#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
using System;
using System.Collections;
using System.Collections.Specialized;
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// A very simple, hashtable-based implementation of <see cref="IVariableSource"/>
/// </summary>
/// <author>Erich Eichinger</author>
public class DictionaryVariableSource : IVariableSource
{
private readonly Hashtable variables;
/// <summary>
/// Creates a new, empty variable source
/// </summary>
public DictionaryVariableSource()
:this(null, true)
{
}
/// <summary>
/// Creates a new, empty and case-insensitive variable source
/// </summary>
public DictionaryVariableSource(bool ignoreCase)
:this(null, ignoreCase)
{
}
/// <summary>
/// Create a new variable source from a list of paired string values.
/// </summary>
/// <remarks>
/// <example>
/// The example below shows, how the dictionary is filled with { 'key1', 'value1' }, { 'key2', 'value2' } pairs:
/// <code>
/// new DictionaryVariableSource( new string[] { &quot;key1&quot;, &quot;value1&quot;, &quot;key2&quot;, &quot;value2&quot; } )
/// </code>
/// </example>
/// </remarks>
/// <param name="args">the argument list containing pairs, or <c>null</c></param>
public DictionaryVariableSource(params string[] args)
:this(true)
{
if (args != null)
{
for (int i = 0; i < args.Length; i += 2)
{
Add(args[i], args[i + 1]);
}
}
}
/// <summary>
/// Creates a new variable source, reading values from another dictionary
/// and converting them to strings if necessary
/// </summary>
public DictionaryVariableSource(IDictionary dictionary, bool ignoreCase)
{
if (ignoreCase)
{
variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
}
else
{
variables = new Hashtable();
}
if (dictionary != null)
{
foreach (DictionaryEntry entry in dictionary)
{
string key = "" + entry.Key;
string value = entry.Value != null ? "" + entry.Value : null;
variables[key] = value;
}
}
}
/// <summary>
/// Adds a key/value pair
/// </summary>
/// <returns>this dictionary. allows for fluent config</returns>
public DictionaryVariableSource Add(string key, string value)
{
variables.Add(key, value);
return this;
}
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
return variables.ContainsKey(name);
}
/// <summary>
/// Performs a variable name lookup
/// </summary>
public string ResolveVariable(string name)
{
if (!variables.ContainsKey(name))
{
throw new ArgumentException(string.Format("variable '{0}' cannot be resolved", name));
}
return (string)variables[name];
}
}
}

View File

@@ -30,6 +30,17 @@ namespace Spring.Objects.Factory.Config
[Serializable]
public class EnvironmentVariableSource : IVariableSource
{
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
return (Environment.GetEnvironmentVariable(name) != null);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -34,7 +34,7 @@ namespace Spring.Objects.Factory.Config
/// <p>
/// Users can always write their own variable sources implementations,
/// that will allow them to load variable values from the database or
/// other proprietary data source.</p>
/// other proprietary data source.</p>
/// </remarks>
/// <seealso cref="ConfigSectionVariableSource"/>
/// <seealso cref="PropertyFileVariableSource"/>
@@ -45,6 +45,14 @@ namespace Spring.Objects.Factory.Config
/// <author>Aleksandar Seovic</author>
public interface IVariableSource
{
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
bool CanResolveVariable(string name);
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -44,17 +44,18 @@ namespace Spring.Objects.Factory.Config
/// <author>Mark Pollack</author>
public class ObjectDefinitionVisitor
{
private IVariableSource variableSource;
public delegate string ResolveHandler(string rawStringValue);
private readonly ResolveHandler resolveHandler;
/// <summary>
/// Initializes a new instance of the <see cref="ObjectDefinitionVisitor"/> class,
/// applying the specified IVariableSource to all object metadata values.
/// </summary>
/// <param name="variableSource">The variable source.</param>
public ObjectDefinitionVisitor(IVariableSource variableSource)
/// <param name="resolveHandler">The handler to be called for resolving variables contained in a string.</param>
public ObjectDefinitionVisitor(ResolveHandler resolveHandler)
{
this.variableSource = variableSource;
this.resolveHandler = resolveHandler;
}
/// <summary>
@@ -95,7 +96,7 @@ namespace Spring.Objects.Factory.Config
string objectTypeName = objectDefinition.ObjectTypeName;
if (objectTypeName != null)
{
string resolvedName = ResolveStringValue(objectTypeName).ToString();
string resolvedName = ResolveStringValue(objectTypeName);
if (!objectTypeName.Equals(resolvedName))
{
objectDefinition.ObjectTypeName = resolvedName;
@@ -197,7 +198,7 @@ namespace Spring.Objects.Factory.Config
{
RuntimeObjectReference ror = (RuntimeObjectReference)value;
//name has to be of string type.
string newObjectName = ResolveStringValue(ror.ObjectName).ToString();
string newObjectName = ResolveStringValue(ror.ObjectName);
if (!newObjectName.Equals(ror.ObjectName))
{
return new RuntimeObjectReference(newObjectName);
@@ -225,7 +226,7 @@ namespace Spring.Objects.Factory.Config
String stringValue = typedStringValue.Value;
if (stringValue != null)
{
String visitedString = ResolveStringValue(stringValue).ToString();
String visitedString = ResolveStringValue(stringValue);
typedStringValue.Value = visitedString;
}
}
@@ -236,7 +237,7 @@ namespace Spring.Objects.Factory.Config
else if (value is ExpressionHolder)
{
ExpressionHolder holder = (ExpressionHolder)value;
string newExpressionString = ResolveStringValue(holder.ExpressionString).ToString();
string newExpressionString = ResolveStringValue(holder.ExpressionString);
return new ExpressionHolder(newExpressionString);
}
return value;
@@ -251,7 +252,7 @@ namespace Spring.Objects.Factory.Config
string elementTypeName = listVal.ElementTypeName;
if (elementTypeName != null)
{
string resolvedName = ResolveStringValue(elementTypeName).ToString();
string resolvedName = ResolveStringValue(elementTypeName);
if (!elementTypeName.Equals(resolvedName))
{
listVal.ElementTypeName = resolvedName;
@@ -278,7 +279,7 @@ namespace Spring.Objects.Factory.Config
string elementTypeName = setVal.ElementTypeName;
if (elementTypeName != null)
{
string resolvedName = ResolveStringValue(elementTypeName).ToString();
string resolvedName = ResolveStringValue(elementTypeName);
if (!elementTypeName.Equals(resolvedName))
{
setVal.ElementTypeName = resolvedName;
@@ -306,7 +307,7 @@ namespace Spring.Objects.Factory.Config
string keyTypeName = dictVal.KeyTypeName;
if (keyTypeName != null)
{
string resolvedName = ResolveStringValue(keyTypeName).ToString();
string resolvedName = ResolveStringValue(keyTypeName);
if (!keyTypeName.Equals(resolvedName))
{
dictVal.KeyTypeName = resolvedName;
@@ -316,7 +317,7 @@ namespace Spring.Objects.Factory.Config
string valueTypeName = dictVal.ValueTypeName;
if (valueTypeName != null)
{
string resolvedName = ResolveStringValue(valueTypeName).ToString();
string resolvedName = ResolveStringValue(valueTypeName);
if (!valueTypeName.Equals(resolvedName))
{
dictVal.ValueTypeName = resolvedName;
@@ -357,23 +358,20 @@ namespace Spring.Objects.Factory.Config
}
/// <summary>
/// Looks up the value of the given variable name in the configured <see cref="IVariableSource"/>.
/// </summary>
/// <param name="variableName">The name of the variable to be looked up</param>
/// <returns>
/// The value of this variable, as returned from the <see cref="IVariableSource"/> passed
/// into the constructor <see cref="ObjectDefinitionVisitor(IVariableSource)"/>
/// </returns>
/// <exception cref="InvalidOperationException">If no <see cref="IVariableSource"/> has been configured.</exception>
protected virtual object ResolveStringValue(string variableName)
/// calls the <see cref="ResolveHandler"/> to resolve any variables contained in the raw string.
/// </summary>
/// <param name="rawStringValue">the raw string value containing variable placeholders to be resolved</param>
/// <exception cref="InvalidOperationException">If no <see cref="IVariableSource"/> has been configured.</exception>
/// <returns>the resolved string, having variables being replaced, if any</returns>
protected virtual string ResolveStringValue(string rawStringValue)
{
if (variableSource == null)
if (resolveHandler == null)
{
throw new InvalidOperationException("No IVariableSource specified - pass an instance " +
"of this object into the constructor or override the 'ResolveStringValue' method");
}
return variableSource.ResolveVariable(variableName);
throw new InvalidOperationException("No resolveHandler specified - pass an instance " +
"into the constructor or override the 'ResolveStringValue' method");
}
return resolveHandler(rawStringValue);
}
}
}

View File

@@ -64,6 +64,21 @@ namespace Spring.Objects.Factory.Config
set { locations = new IResource[] { value} ;}
}
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
if (properties == null)
{
InitProperties();
}
return properties.Contains(name);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -225,11 +225,10 @@ namespace Spring.Objects.Factory.Config
/// <exception cref="Spring.Objects.ObjectsException">
/// If an error occured.
/// </exception>
protected override void ProcessProperties(
IConfigurableListableObjectFactory factory, NameValueCollection props)
{
IVariableSource variableSource = new PlaceholderResolvingStringVariableSource(this, props);
ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(variableSource);
protected override void ProcessProperties(IConfigurableListableObjectFactory factory, NameValueCollection props)
{
PlaceholderResolveHandlerAdapter resolveAdapter = new PlaceholderResolveHandlerAdapter(this, props);
ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(resolveAdapter.ParseAndResolveVariables));
string[] objectDefinitionNames = factory.GetObjectDefinitionNames();
for (int i = 0; i < objectDefinitionNames.Length; ++i)
@@ -397,26 +396,26 @@ namespace Spring.Objects.Factory.Config
{
return props[placeholder];
}
}
#region Helper class
#region Helper class
internal class PlaceholderResolvingStringVariableSource : IVariableSource
{
private PropertyPlaceholderConfigurer ppc;
private NameValueCollection props;
public PlaceholderResolvingStringVariableSource(PropertyPlaceholderConfigurer outerPPC, NameValueCollection props)
private class PlaceholderResolveHandlerAdapter
{
ppc = outerPPC;
this.props = props;
private readonly PropertyPlaceholderConfigurer ppc;
private readonly NameValueCollection props;
public PlaceholderResolveHandlerAdapter(PropertyPlaceholderConfigurer outerPPC, NameValueCollection props)
{
ppc = outerPPC;
this.props = props;
}
public string ParseAndResolveVariables(string name)
{
return ppc.ParseString(props, name, new HashedSet());
}
}
public string ResolveVariable(string name)
{
return ppc.ParseString(props, name, new HashedSet());
}
}
#endregion
#endregion
}
}

View File

@@ -30,6 +30,7 @@ namespace Spring.Objects.Factory.Config
/// <author>Aleksandar Seovic</author>
public class RegistryVariableSource : IVariableSource
{
private static readonly object NULL = new object();
private RegistryKey key;
/// <summary>
@@ -44,6 +45,17 @@ namespace Spring.Objects.Factory.Config
set { key = value; }
}
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
return (key != null && key.GetValue(name, NULL) != NULL);
}
/// <summary>
/// Resolves variable value for the specified variable name.
/// </summary>

View File

@@ -31,6 +31,17 @@ namespace Spring.Objects.Factory.Config
[Serializable]
public class SpecialFolderVariableSource : IVariableSource
{
/// <summary>
/// Before requesting a variable resolution, a client should
/// ask, whether the source can resolve a particular variable name.
/// </summary>
/// <param name="name">the name of the variable to resolve</param>
/// <returns><c>true</c> if the variable can be resolved, <c>false</c> otherwise</returns>
public bool CanResolveVariable(string name)
{
return ResolveVariable(name) != null;
}
/// <summary>
/// Resolves specified special folder to its full path.
/// </summary>

View File

@@ -774,7 +774,11 @@ namespace Spring.Objects.Factory.Config
/// </returns>
public string GetString(string name, string defaultValue)
{
string value = (variableSource == null) ? defaultValue : variableSource.ResolveVariable(name);
string value = null;
if (variableSource != null && variableSource.CanResolveVariable(name))
{
value = variableSource.ResolveVariable(name);
}
if (!StringUtils.HasLength(value))
{

View File

@@ -24,6 +24,7 @@ using System.Globalization;
using Common.Logging;
using Spring.Collections;
using Spring.Core;
using Spring.Util;
namespace Spring.Objects.Factory.Config
{
@@ -66,12 +67,12 @@ namespace Spring.Objects.Factory.Config
/// <summary>
/// The default placeholder prefix.
/// </summary>
public const string DefaultPlaceholderPrefix = "${";
public static readonly string DefaultPlaceholderPrefix = "${";
/// <summary>
/// The default placeholder suffix.
/// </summary>
public const string DefaultPlaceholderSuffix = "}";
public static readonly string DefaultPlaceholderSuffix = "}";
#region Fields
@@ -81,10 +82,33 @@ namespace Spring.Objects.Factory.Config
private string placeholderPrefix = DefaultPlaceholderPrefix;
private string placeholderSuffix = DefaultPlaceholderSuffix;
private IList variableSourceList;
private IList variableSourceList = new ArrayList();
#endregion
/// <summary>
/// Create a new instance without any variable sources
/// </summary>
public VariablePlaceholderConfigurer()
{}
/// <summary>
/// Create a new instance and initialize with the given variable source
/// </summary>
/// <param name="variableSource"></param>
public VariablePlaceholderConfigurer(IVariableSource variableSource)
{
this.VariableSource = variableSource;
}
/// <summary>
/// Create a new instance and initialize with the given list of variable sources
/// </summary>
public VariablePlaceholderConfigurer(IList variableSources)
{
this.VariableSources = variableSources;
}
#region Properties
/// <summary>
@@ -156,6 +180,17 @@ namespace Spring.Objects.Factory.Config
/// </exception>
public void PostProcessObjectFactory( IConfigurableListableObjectFactory factory )
{
if (CollectionUtils.IsEmpty(variableSourceList))
{
throw new ArgumentException("No VariableSources configured");
}
ICollection filtered = CollectionUtils.FindValuesOfType(this.variableSourceList, typeof (IVariableSource));
if (filtered.Count != this.variableSourceList.Count)
{
throw new ArgumentException("'VariableSources' must contain IVariableSource elements only", "VariableSources");
}
try
{
ProcessProperties( factory );
@@ -206,11 +241,9 @@ namespace Spring.Objects.Factory.Config
/// </exception>
protected virtual void ProcessProperties( IConfigurableListableObjectFactory factory )
{
IVariableSource compositeVariableSource = new PlaceholderResolvingCompositeVariableSource( placeholderPrefix
, placeholderSuffix
, variableSourceList
, ignoreUnresolvablePlaceholders );
ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor( compositeVariableSource );
CompositeVariableSource compositeVariableSource = new CompositeVariableSource(variableSourceList);
TextProcessor tp = new TextProcessor(this, compositeVariableSource);
ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(tp.ParseAndResolveVariables));
string[] objectDefinitionNames = factory.GetObjectDefinitionNames();
for (int i = 0; i < objectDefinitionNames.Length; ++i)
@@ -231,84 +264,86 @@ namespace Spring.Objects.Factory.Config
#region Helper class
private class PlaceholderResolvingCompositeVariableSource : IVariableSource
private class TextProcessor
{
private readonly ILog logger = LogManager.GetLogger( typeof( PlaceholderResolvingCompositeVariableSource ) );
private readonly ILog logger = LogManager.GetLogger(typeof(TextProcessor));
private readonly VariablePlaceholderConfigurer owner;
private readonly IVariableSource variableSource;
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 )
public TextProcessor(VariablePlaceholderConfigurer owner, IVariableSource variableSource)
{
this.placeholderPrefix = placeholderPrefix;
this.placeholderSuffix = placeholderSuffix;
this.variableSourceList = variableSourceList;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
this.owner = owner;
this.variableSource = variableSource;
}
#region IVariableSource Members
public string ResolveVariable( string rawStringValue )
public string ParseAndResolveVariables(string rawStringValue)
{
return ParseAndResolveVariable( rawStringValue, new HashedSet() );
return ParseAndResolveVariables(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 )
private string ParseAndResolveVariables(string strVal, ISet visitedPlaceholders)
{
int startIndex = strVal.IndexOf( placeholderPrefix );
if (strVal == null)
{
return null;
}
int startIndex = strVal.IndexOf(owner.placeholderPrefix);
while (startIndex != -1)
{
int endIndex = strVal.IndexOf(
placeholderSuffix, startIndex + placeholderPrefix.Length );
owner.placeholderSuffix, startIndex + owner.placeholderPrefix.Length);
if (endIndex != -1)
{
int pos = startIndex + placeholderPrefix.Length;
string placeholder = strVal.Substring( pos, endIndex - pos );
if (visitedPlaceholders.Contains( placeholder ))
int pos = startIndex + owner.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 ) );
placeholder));
}
visitedPlaceholders.Add( placeholder );
string resolvedValue = ResolvePlaceholderVariable( placeholder );
if (resolvedValue != null)
visitedPlaceholders.Add(placeholder);
if (variableSource.CanResolveVariable(placeholder))
{
resolvedValue = ParseAndResolveVariable( resolvedValue, visitedPlaceholders );
string resolvedValue = variableSource.ResolveVariable(placeholder);
resolvedValue = ParseAndResolveVariables(resolvedValue, visitedPlaceholders);
#region Instrumentation
if (logger.IsDebugEnabled)
{
logger.Debug( string.Format(
logger.Debug(string.Format(
CultureInfo.InvariantCulture,
"Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue ) );
"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);
if (resolvedValue == null
&& startIndex == 0
&& strVal.Length <= endIndex + owner.placeholderSuffix.Length)
{
return null;
}
strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + owner.placeholderSuffix.Length);
startIndex = strVal.IndexOf(owner.placeholderPrefix, startIndex + (resolvedValue == null ? 0 : resolvedValue.Length));
}
else if (ignoreUnresolvablePlaceholders)
else if (owner.ignoreUnresolvablePlaceholders)
{
// simply return the unprocessed value...
return strVal;
}
else
{
throw new ObjectDefinitionStoreException( string.Format(
throw new ObjectDefinitionStoreException(string.Format(
CultureInfo.InvariantCulture,
"Could not resolve placeholder '{0}'.", placeholder ) );
"Could not resolve placeholder '{0}'.", placeholder));
}
visitedPlaceholders.Remove( placeholder );
visitedPlaceholders.Remove(placeholder);
}
else
{
@@ -316,34 +351,38 @@ namespace Spring.Objects.Factory.Config
}
}
return strVal;
}
}
private class CompositeVariableSource : IVariableSource
{
private readonly IList variableSourceList;
public CompositeVariableSource( IList variableSourceList )
{
this.variableSourceList = variableSourceList;
}
private string ResolvePlaceholderVariable( string variableName )
public string ResolveVariable( string variableName )
{
foreach (IVariableSource variableSource in variableSourceList)
{
//TODO handle resolved values at are not strings?
if (!variableSource.CanResolveVariable(variableName)) continue;
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 variableSource.ResolveVariable( variableName );
}
return null;
throw new ArgumentException(string.Format("cannot resolve variable '{0}'", variableName));
}
#endregion
public bool CanResolveVariable(string variableName)
{
foreach (IVariableSource variableSource in variableSourceList)
{
if (variableSource.CanResolveVariable(variableName))
return true;
}
return false;
}
}
#endregion

View File

@@ -666,6 +666,7 @@
<Compile Include="Objects\Factory\Config\ConfigSectionVariableSource.cs" />
<Compile Include="Objects\Factory\Config\ConnectionStringsVariableSource.cs" />
<Compile Include="Objects\Factory\Config\DependencyDescriptor.cs" />
<Compile Include="Objects\Factory\Config\DictionaryVariableSource.cs" />
<Compile Include="Objects\Factory\Config\IConfigurableFactoryObject.cs" />
<Compile Include="Objects\Factory\Config\InstantiationAwareObjectPostProcessorAdapter.cs" />
<Compile Include="Objects\Factory\Config\ISingletonObjectRegistry.cs" />

View File

@@ -70,20 +70,36 @@ namespace Spring.Util
/// <param name="collection">The collection to check.</param>
/// <param name="element">The object to locate in the collection.</param>
/// <returns><see lang="true"/> if the element is in the collection, <see lang="false"/> otherwise.</returns>
public static bool Contains(ICollection collection, Object element)
public static bool Contains(IEnumerable collection, Object element)
{
// TODO (EE): does not match Spring/J behavior. Change to IEnumerable and enumerable may be null
if (collection == null)
{
throw new ArgumentNullException("collection", "Collection cannot be null.");
return false;
}
MethodInfo method;
method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
if (null == method)
if (collection is IList)
{
throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Contains() method.");
return ((IList) collection).Contains(element);
}
return (bool)method.Invoke(collection, new Object[] { element });
if (collection is IDictionary)
{
return ((IDictionary) collection).Contains(element);
}
MethodInfo method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
if (null != method)
{
return (bool)method.Invoke(collection, new Object[] { element });
}
foreach (object item in collection)
{
if (object.Equals(item, element))
{
return true;
}
}
return false;
}
/// <summary>

View File

@@ -723,6 +723,18 @@ namespace Spring.Expressions
Assert.IsTrue((bool)ExpressionEvaluator.GetValue(tesla, "T(System.DateTime) == DOB.GetType()"));
}
/// <summary>
/// Tests type node
/// </summary>
[Test]
public void TestTypeNodeWithArrays()
{
Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[])"));
Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,])"));
Assert.AreEqual(typeof(DateTime[]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[], mscorlib)"));
Assert.AreEqual(typeof(DateTime[,]), ExpressionEvaluator.GetValue(null, "T(System.DateTime[,], mscorlib)"));
}
/// <summary>
/// Tests type node
/// </summary>

View File

@@ -18,10 +18,8 @@
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
using NUnit.Framework;
using Spring.Objects.Factory.Support;
@@ -34,14 +32,22 @@ namespace Spring.Objects.Factory.Config
[TestFixture]
public class ObjectDefinitionVisitorTests
{
private NameValueCollectionVariableSource variableSource;
private Hashtable properties;
[SetUp]
public void SetUp()
{
NameValueCollection nvc = new NameValueCollection();
nvc.Add("Property", "Value");
variableSource = new NameValueCollectionVariableSource(nvc);
properties = CollectionsUtil.CreateCaseInsensitiveHashtable();
properties.Add("Property", "Value");
}
private string ParseAndResolveVariables(string rawText)
{
if (rawText.StartsWith("$"))
{
return (string) properties[rawText.Substring(1)];
}
return rawText;
}
[Test]
@@ -50,7 +56,7 @@ namespace Spring.Objects.Factory.Config
IObjectDefinition od = new RootObjectDefinition();
od.ObjectTypeName = "$Property";
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
Assert.AreEqual("Value", od.ObjectTypeName);
@@ -62,7 +68,7 @@ namespace Spring.Objects.Factory.Config
IObjectDefinition od = new RootObjectDefinition();
od.PropertyValues.Add("PropertyName", "$Property");
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
Assert.AreEqual("Value", od.PropertyValues.GetPropertyValue("PropertyName").Value);
@@ -78,7 +84,7 @@ namespace Spring.Objects.Factory.Config
ml.Add("$Property");
od.PropertyValues.Add("PropertyName", ml);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
ManagedList list = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedList;
@@ -96,7 +102,7 @@ namespace Spring.Objects.Factory.Config
ms.Add("$Property");
od.PropertyValues.Add("PropertyName", ms);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
ManagedSet set = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedSet;
@@ -117,7 +123,7 @@ namespace Spring.Objects.Factory.Config
md.Add("Key", "$Property");
od.PropertyValues.Add("PropertyName", md);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
ManagedDictionary dictionary = od.PropertyValues.GetPropertyValue("PropertyName").Value as ManagedDictionary;
@@ -135,7 +141,7 @@ namespace Spring.Objects.Factory.Config
nvc["Key"] = "$Property";
od.PropertyValues.Add("PropertyName", nvc);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(variableSource);
ObjectDefinitionVisitor odv = new ObjectDefinitionVisitor(new ObjectDefinitionVisitor.ResolveHandler(ParseAndResolveVariables));
odv.VisitObjectDefinition(od);
NameValueCollection visitedNvc =
@@ -143,31 +149,5 @@ namespace Spring.Objects.Factory.Config
Assert.AreEqual("Value", visitedNvc["Key"]);
}
#region Helper class
public class NameValueCollectionVariableSource : IVariableSource
{
private NameValueCollection properties;
public NameValueCollectionVariableSource(NameValueCollection properties)
{
this.properties = properties;
}
public string ResolveVariable(string name)
{
if (name.StartsWith("$"))
{
return properties[name.Substring(1)];
}
else
{
return name;
}
}
}
#endregion
}
}

View File

@@ -41,23 +41,7 @@ namespace Spring.Objects.Factory.Config
private static readonly DateTime TESTDATETIME = new DateTime(2007, 07, 06, 11, 12, 13);
private static readonly DateTime TESTDATETIME_DEFAULT = TESTDATETIME.AddDays(-1);
private class NameValueCollectionVariableSource : IVariableSource
{
private readonly NameValueCollection nameValues = new NameValueCollection();
public NameValueCollectionVariableSource Add(string name, string value)
{
nameValues.Add(name, value);
return this;
}
public string ResolveVariable(string name)
{
return nameValues.Get(name);
}
}
private readonly IVariableSource _testVariableSource = new NameValueCollectionVariableSource()
private readonly IVariableSource _testVariableSource = new DictionaryVariableSource(null, true)
.Add("ValidString", "String")
.Add("EmptyString", "")
.Add("ValidChar", "c")

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <20> 2002-2007 the original author or authors.
* Copyright <20> 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.
@@ -18,45 +18,49 @@
#endregion
#region Imports
using System;
using System.Collections;
using NUnit.Framework;
using Spring.Context.Support;
#endregion
using Spring.Objects.Factory.Support;
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// This calss contains tests for
/// This class contains tests for
/// </summary>
/// <author>Mark Pollack</author>
[TestFixture]
public class VariablePlaceholderConfigurerTests
{
private class DictionaryVariableSource : IVariableSource
[Test]
public void ThrowsOnMissingVariableSources()
{
private Hashtable variables = new Hashtable();
public DictionaryVariableSource(params string[] args)
StaticApplicationContext ac = new StaticApplicationContext();
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer();
try
{
for(int i=0;i<args.Length;i+=2)
{
variables[args[i]] = args[i+1];
}
}
public string ResolveVariable(string name)
{
return (string) variables[name];
vphc.PostProcessObjectFactory(ac.ObjectFactory);
Assert.Fail();
}
catch (ArgumentException)
{}
}
[SetUp]
public void Setup()
[Test]
public void ThrowsOnInvalidVariableSourcesElement()
{
StaticApplicationContext ac = new StaticApplicationContext();
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer();
vphc.VariableSources = new ArrayList( new object[] { new object() } );
try
{
vphc.PostProcessObjectFactory(ac.ObjectFactory);
Assert.Fail();
}
catch (ArgumentException)
{}
}
[Test]
@@ -119,7 +123,85 @@ namespace Spring.Objects.Factory.Config
}
[Test]
[Ignore("Does not work yet because IVariableSource cannot differentiate between invalid key and key with a null value")]
public void MultiResolution()
{
DefaultListableObjectFactory of = new DefaultListableObjectFactory();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.Add("Greeting", "Hello ${firstname} ${lastname}!");
of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs));
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "firstname", "FirstName" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "lastname", "LastName"}));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
Assert.AreEqual("Hello FirstName LastName!", rod.PropertyValues.GetPropertyValue("Greeting").Value);
}
[Test]
public void NestedResolution()
{
DefaultListableObjectFactory of = new DefaultListableObjectFactory();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.Add("NameProperty", "${name}");
of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs));
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "${nickname}" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
Assert.AreEqual("nickname-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value);
}
[Test]
public void ChainedResolution()
{
StaticApplicationContext ac = new StaticApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.Add("name", "${name}");
pvs.Add("nickname", "${nickname}");
ac.RegisterSingleton("tb1", typeof(TestObject), pvs);
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
ac.AddObjectFactoryPostProcessor(vphc);
ac.Refresh();
TestObject tb1 = (TestObject)ac.GetObject("tb1");
Assert.AreEqual("name-value", tb1.Name);
Assert.AreEqual("nickname-value", tb1.Nickname);
}
[Test]
public void ChainedResolutionWithNullValues()
{
DefaultListableObjectFactory of = new DefaultListableObjectFactory();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.Add("NameProperty", "${name}");
pvs.Add("NickNameProperty", "${nickname}");
of.RegisterObjectDefinition("tb1", new RootObjectDefinition("typename", null, pvs));
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value", "nickname", null }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
Assert.AreEqual("name-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value);
Assert.AreEqual(null, rod.PropertyValues.GetPropertyValue("NickNameProperty").Value);
}
[Test]
public void WhitespaceHandling()
{
StaticApplicationContext ac = new StaticApplicationContext();

View File

@@ -64,7 +64,6 @@ namespace Spring.Util
}
}
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ContainsNullCollection()
{
CollectionUtils.Contains(null, null);
@@ -77,12 +76,12 @@ namespace Spring.Util
Assert.IsTrue(CollectionUtils.Contains(list, null));
}
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void ContainsCollectionDoesNotImplementContains()
public void ContainsCollectionThatDoesNotImplementContains()
{
NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection();
NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection();
CollectionUtils.Contains(noAddCollection, new object());
}
[Test]
public void ContainsValidElement()
{

View File

@@ -39,22 +39,6 @@ namespace Spring.Data.NHibernate.Support
[TestFixture]
public class ConfigSectionSessionScopeSettingsTests
{
private class NameValueCollectionVariableSource : IVariableSource
{
private readonly NameValueCollection nameValuePairs = new NameValueCollection();
public NameValueCollectionVariableSource Add(string key, string value)
{
nameValuePairs.Add(key, value);
return this;
}
public string ResolveVariable(string name)
{
return nameValuePairs[name];
}
}
[Test]
public void CanCreateWithDefaults()
{
@@ -104,7 +88,7 @@ namespace Spring.Data.NHibernate.Support
// simulate config section
string thisTypeName = this.GetType().FullName;
NameValueCollectionVariableSource variableSource = new NameValueCollectionVariableSource()
DictionaryVariableSource variableSource = new DictionaryVariableSource()
.Add(thisTypeName + ".SessionFactoryObjectName", SESSIONFACTORY_OBJECTNAME)
.Add(thisTypeName + ".EntityInterceptorObjectName", ENTITYINTERCEPTOR_OBJECTNAME)
.Add(thisTypeName + ".SingleSession", expectedSingleSession.ToString().ToLower() ) // case insensitive!