diff --git a/doc/reference/src/objects.xml b/doc/reference/src/objects.xml index c44dd277..ed0ad09a 100644 --- a/doc/reference/src/objects.xml +++ b/doc/reference/src/objects.xml @@ -5028,13 +5028,22 @@ cfg.PostProcessObjectFactory(factory); value will be used. <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core"> <property name="VariableSources"> <list> + <object type="Spring.Objects.Factory.Config.PropertyFileVariableSource, Spring.Core"> + <property name="Location" value="~\application.properties" /> + <property name="IgnoreMissingResources" value="true"/> + </object> <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core"> <property name="SectionNames" value="CryptedConfiguration" /> </object> </list> </property> </object> - The IVariableSource interface is shown below + + The use of the IgnoreMissingResources + property above will mean that if the property file is not found it + will be silently ignored and the resolution will continue to + ConfigSectionVariableSource. + The IVariableSource interface is shown below public interface IVariableSource { diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index a695ee88..ce8e612b 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -489,31 +489,57 @@ namespace Spring.Context.Support /// In the case of errors. private void InvokeObjectFactoryPostProcessors() { - // do NOT include IFactoryObjects; they (typically) need to be instantiated + // Do NOT include IFactoryObjects; they (typically) need to be instantiated // to determine the Type of object that they create, and if they are instantiated // then we won't be able to do any factory post processin' on 'em... - string[] factoryProcessorNames - = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); - ArrayList orderedFactoryProcessors = new ArrayList(); - IList nonOrderedFactoryProcessorNames = new ArrayList(); - for (int i = 0; i < factoryProcessorNames.Length; ++i) + ArrayList factoryProcessorNames = new ArrayList(); + string[] names = GetObjectNamesForType(typeof (IObjectFactoryPostProcessor), true, false); + foreach (string s in names) { - string processorName = factoryProcessorNames[i]; - object processor = GetObject(processorName); - if (typeof(IOrdered).IsAssignableFrom(GetType(processorName))) + factoryProcessorNames.Add(s); + } + + ArrayList priorityOrderedFactoryProcessors = new ArrayList(); + ArrayList orderedFactoryProcessorsNames = new ArrayList(); + ArrayList nonOrderedFactoryProcessorNames = new ArrayList(); + + for (int i = 0; i < factoryProcessorNames.Count; ++i) + { + string processorName = (string) factoryProcessorNames[i]; + if (IsTypeMatch(processorName, typeof(IPriorityOrdered))) { - orderedFactoryProcessors.Add(processor); + priorityOrderedFactoryProcessors.Add(ObjectFactory.GetObject(processorName, typeof(IObjectFactoryPostProcessor))); } + else if (IsTypeMatch(processorName, typeof(IOrdered))) + { + orderedFactoryProcessorsNames.Add(processorName); + } else { - nonOrderedFactoryProcessorNames.Add(processor); + nonOrderedFactoryProcessorNames.Add(processorName); } } - // first, invoke those IObjectFactoryPostProcessors that implement IOrdered... + // First, invoke the IObjectFactoryPostProcessors that implement IPriorityOrdered. + InvokePriorityOrderedObjectFactoryPostProcessors(factoryProcessorNames, priorityOrderedFactoryProcessors); + + // Second, invoke those IObjectFactoryPostProcessors that implement IOrdered... + ArrayList orderedFactoryProcessors = new ArrayList(); + foreach (string orderedFactoryProcessorsName in orderedFactoryProcessorsNames) + { + orderedFactoryProcessors.Add(ObjectFactory.GetObject(orderedFactoryProcessorsName, + typeof (IObjectFactoryPostProcessor))); + } orderedFactoryProcessors.Sort(new OrderComparator()); - ProcessObjectFactoryPostProcessors(orderedFactoryProcessors); + InvokeObjectFactoryPostProcessors(orderedFactoryProcessors, ObjectFactory); + // and then the unordered ones... - ProcessObjectFactoryPostProcessors(nonOrderedFactoryProcessorNames); + ArrayList nonOrderedPostProcessors = new ArrayList(); + foreach (string nonOrderedFactoryProcessorName in nonOrderedFactoryProcessorNames) + { + nonOrderedPostProcessors.Add(ObjectFactory.GetObject(nonOrderedFactoryProcessorName, + typeof (IObjectFactoryPostProcessor))); + } + InvokeObjectFactoryPostProcessors(nonOrderedPostProcessors, ObjectFactory); #region Instrumentation @@ -522,18 +548,42 @@ namespace Spring.Context.Support log.Debug(string.Format( CultureInfo.InvariantCulture, "processed {0} IFactoryObjectPostProcessors defined in application context [{1}].", - factoryProcessorNames.Length, + factoryProcessorNames.Count, Name)); } #endregion } - private void ProcessObjectFactoryPostProcessors(IList objectFactoryPostProcessors) + protected virtual void InvokePriorityOrderedObjectFactoryPostProcessors(ArrayList factoryProcessorNames, ArrayList priorityOrderedFactoryProcessors) + { + priorityOrderedFactoryProcessors.Sort(new OrderComparator()); + InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, ObjectFactory); + + // Now will find any additional IObjectFactoryPostProcessors that implement IPriorityOrdered that may have been + // resolved due to using TypeAlias + string[] factoryProcessorNamesAfterTypeAlias = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); + priorityOrderedFactoryProcessors.Clear(); + foreach (string factoryProcessorName in factoryProcessorNamesAfterTypeAlias) + { + if (!factoryProcessorNames.Contains(factoryProcessorName)) + { + if (IsTypeMatch(factoryProcessorName, typeof(IPriorityOrdered))) + { + priorityOrderedFactoryProcessors.Add(ObjectFactory.GetObject(factoryProcessorName, typeof(IObjectFactoryPostProcessor))); + } + } + } + // Second, invoke newly discovered IObjectFactoryPostProcessors that implement IPriorityOrdered. + priorityOrderedFactoryProcessors.Sort(new OrderComparator()); + InvokeObjectFactoryPostProcessors(priorityOrderedFactoryProcessors, ObjectFactory); + } + + private void InvokeObjectFactoryPostProcessors(IList objectFactoryPostProcessors, IConfigurableListableObjectFactory objectFactory) { foreach (IObjectFactoryPostProcessor processor in objectFactoryPostProcessors) { - processor.PostProcessObjectFactory(ObjectFactory); + processor.PostProcessObjectFactory(objectFactory); } } diff --git a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs index 20ff9f92..09203f0f 100644 --- a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs +++ b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2004 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + * Copyright 2002-2004 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #endregion diff --git a/src/Spring/Spring.Core/Core/IPriorityOrdered.cs b/src/Spring/Spring.Core/Core/IPriorityOrdered.cs new file mode 100644 index 00000000..6781bb3b --- /dev/null +++ b/src/Spring/Spring.Core/Core/IPriorityOrdered.cs @@ -0,0 +1,51 @@ +#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 + +using Spring.Context; +using Spring.Objects.Factory.Config; + +namespace Spring.Core +{ + /// + /// Extension of the interface, expressing a 'priority' + /// ordering: Order values expressed by IPriorityOrdered objects always + /// apply before order values of 'plain' Ordered values. + /// + /// + /// This is primarily a special-purpose interface, used for objects + /// where it is particularly important to determine 'prioritized' + /// objects first, without even obtaining the remaining objects. + /// A typical example: Prioritized post-processors in a Spring + /// + /// + /// IPriorityOrdered post-processor objects are initialized in + /// a special phase, ahead of other post-processor objects. + /// + /// Juergen Hoeller + /// Mark Pollack (.NET) + /// + /// + /// + public interface IPriorityOrdered : IOrdered + { + + } + +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs index 1db97716..c71cb191 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/AbstractConfigurer.cs @@ -31,7 +31,7 @@ namespace Spring.Objects.Factory.Config /// /// Mark Pollack [Serializable] - public abstract class AbstractConfigurer : IOrdered, IObjectFactoryPostProcessor + public abstract class AbstractConfigurer : IPriorityOrdered, IObjectFactoryPostProcessor { private int order = Int32.MaxValue; // default: same as non-Ordered diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs index e720f8f1..04f31f5c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/CommandLineArgsVariableSource.cs @@ -39,7 +39,9 @@ namespace Spring.Objects.Factory.Config private string valueSeparator = DEFAULT_VALUE_SEPARATOR; private string[] commandLineArgs; - private IDictionary arguments; + protected IDictionary arguments; + + private object objectMonitor = new object(); /// /// Default constructor. @@ -95,11 +97,14 @@ namespace Spring.Objects.Factory.Config /// true if the variable can be resolved, false otherwise public bool CanResolveVariable(string name) { - if (arguments == null) + lock (objectMonitor) { - InitArguments(); - } - return arguments.Contains(name); + if (arguments == null) + { + InitArguments(); + } + return arguments.Contains(name); + } } /// @@ -112,18 +117,21 @@ namespace Spring.Objects.Factory.Config /// The variable value if able to resolve, null otherwise. /// public string ResolveVariable(string name) - { - if (arguments == null) - { - InitArguments(); + { + lock (objectMonitor) + { + if (arguments == null) + { + InitArguments(); + } + return (string) this.arguments[name]; } - return (string) this.arguments[name]; } /// /// Initializes command line arguments dictionary. /// - private void InitArguments() + protected virtual void InitArguments() { this.arguments = CollectionsUtil.CreateCaseInsensitiveHashtable(commandLineArgs.Length); diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs index 02e44559..193dc4ab 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConfigSectionVariableSource.cs @@ -35,7 +35,8 @@ namespace Spring.Objects.Factory.Config public class ConfigSectionVariableSource : IVariableSource { private string[] sectionNames; - private NameValueCollection variables; + protected NameValueCollection variables; + private readonly object objectMonitor = new object(); /// /// Initializes a new instance of @@ -100,11 +101,15 @@ namespace Spring.Objects.Factory.Config /// true if the variable can be resolved, false otherwise public bool CanResolveVariable(string name) { - if (variables == null) + lock (objectMonitor) { - InitVariables(); - } - return CollectionUtils.Contains(variables.AllKeys, name); + if (variables == null) + { + variables = new NameValueCollection(); + InitVariables(); + } + return CollectionUtils.Contains(variables.AllKeys, name); + } } /// @@ -117,21 +122,24 @@ namespace Spring.Objects.Factory.Config /// The variable value if able to resolve, null otherwise. /// public string ResolveVariable(string name) - { - if (variables == null) - { - InitVariables(); - } - return variables.Get(name); + { + lock (objectMonitor) + { + if (variables == null) + { + variables = new NameValueCollection(); + InitVariables(); + } + return variables.Get(name); + } } /// /// Initializes properties based on the specified /// property file locations. /// - private void InitVariables() - { - variables = new NameValueCollection(); + protected virtual void InitVariables() + { foreach (string sectionName in sectionNames) { object section = ConfigurationUtils.GetSection(sectionName); diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs index e4267ed5..e487714b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/PropertyFileVariableSource.cs @@ -19,7 +19,6 @@ #endregion using System; -using System.Collections; using System.IO; using Spring.Core.IO; using Spring.Util; @@ -36,7 +35,9 @@ namespace Spring.Objects.Factory.Config public class PropertyFileVariableSource : IVariableSource { private IResource[] locations; - private Properties properties; + protected Properties properties; + private readonly object objectMonitor = new object(); + private bool ignoreMissingResources; /// /// Gets or sets the locations of the property files @@ -62,6 +63,18 @@ namespace Spring.Objects.Factory.Config public IResource Location { set { locations = new IResource[] { value} ;} + } + + /// + /// Sets a value indicating whether to ignore resource locations that do not exist. This will call + /// the Exists property. + /// + /// + /// true if one should ignore missing resources; otherwise, false. + /// + public bool IgnoreMissingResources + { + set { ignoreMissingResources = value; } } /// @@ -72,11 +85,15 @@ namespace Spring.Objects.Factory.Config /// true if the variable can be resolved, false otherwise public bool CanResolveVariable(string name) { - if (properties == null) + lock (objectMonitor) { - InitProperties(); - } - return properties.Contains(name); + if (properties == null) + { + properties = new Properties(); + InitProperties(); + } + return properties.Contains(name); + } } /// @@ -89,28 +106,36 @@ namespace Spring.Objects.Factory.Config /// The variable value if able to resolve, null otherwise. /// public string ResolveVariable(string name) - { - if (properties == null) - { - InitProperties(); + { + lock (objectMonitor) + { + if (properties == null) + { + properties = new Properties(); + InitProperties(); + } + return properties.GetProperty(name); } - return properties.GetProperty(name); } /// /// Initializes properties based on the specified /// property file locations. /// - private void InitProperties() - { - properties = new Properties(); - foreach (IResource location in locations) - { - using (Stream input = location.InputStream) - { - properties.Load(input); - } - } + protected virtual void InitProperties() + { + foreach (IResource location in locations) + { + bool exists = location.Exists; + if (!exists && ignoreMissingResources) + { + continue; + } + using (Stream input = location.InputStream) + { + properties.Load(input); + } + } } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs b/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs index 05c21b8b..326c4e96 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/RegistryVariableSource.cs @@ -69,7 +69,7 @@ namespace Spring.Objects.Factory.Config /// /// The variable value if able to resolve, null otherwise. /// - public string ResolveVariable(string name) + public virtual string ResolveVariable(string name) { object res = Key.GetValue(name); if (res is string) diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs index a4e75065..61f23a4b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/VariablePlaceholderConfigurer.cs @@ -62,7 +62,7 @@ namespace Spring.Objects.Factory.Config /// will be thrown. /// /// Mark Pollack - public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IOrdered + public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IPriorityOrdered { /// /// The default placeholder prefix. diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index 5b802c5d..11c5f49d 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -1025,7 +1025,7 @@ namespace Spring.Objects.Factory.Support } /// - /// Determines candidate constructors to use for the given bean, checking all registered + /// Determines candidate constructors to use for the given object, checking all registered /// /// /// Raw type of the object. diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorInstantiationInfo.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorInstantiationInfo.cs new file mode 100644 index 00000000..2eb85091 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorInstantiationInfo.cs @@ -0,0 +1,63 @@ +#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 + +using System.Reflection; + +namespace Spring.Objects.Factory.Support +{ + /// + /// Collects information on the constructor to use to create the instance and the argument instances to pass into the + /// constructor. + /// + public class ConstructorInstantiationInfo + { + private ConstructorInfo constructorInfo; + private object[] argInstances; + + /// + /// Initializes a new instance of the class. + /// + /// The constructor info. + /// The arg instances. + public ConstructorInstantiationInfo(ConstructorInfo constructorInfo, object[] argInstances) + { + this.constructorInfo = constructorInfo; + this.argInstances = argInstances; + } + + /// + /// Gets the constructor info. + /// + /// The constructor info. + public ConstructorInfo ConstructorInfo + { + get { return constructorInfo; } + } + + /// + /// Gets the arg instances. + /// + /// The arg instances. + public object[] ArgInstances + { + get { return argInstances; } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs index 4802736f..3bd97303 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs @@ -42,7 +42,7 @@ namespace Spring.Objects.Factory.Support /// /// Juergen Hoeller /// Mark Pollack - internal class ConstructorResolver + public class ConstructorResolver { private readonly ILog log = LogManager.GetLogger(typeof(ConstructorResolver)); @@ -89,8 +89,42 @@ namespace Spring.Objects.Factory.Support public IObjectWrapper AutowireConstructor(string objectName, RootObjectDefinition rod, ConstructorInfo[] chosenCtors, object[] explicitArgs) { + ObjectWrapper wrapper = new ObjectWrapper(); + ConstructorInstantiationInfo constructorInstantiationInfo = GetConstructorInstantiationInfo( + objectName, rod, chosenCtors, explicitArgs); + + wrapper.WrappedInstance = instantiationStrategy.Instantiate(rod, objectName, this.objectFactory, + constructorInstantiationInfo.ConstructorInfo, constructorInstantiationInfo.ArgInstances); + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", objectName, constructorInstantiationInfo.ConstructorInfo)); + } + + #endregion + + return wrapper; + } + + + /// + /// Gets the constructor instantiation info given the object definition. + /// + /// Name of the object. + /// The RootObjectDefinition + /// The explicitly chosen ctors. + /// The explicit chose ctor args. + /// A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or + /// one based on type matching. + public ConstructorInstantiationInfo GetConstructorInstantiationInfo(string objectName, RootObjectDefinition rod, + ConstructorInfo[] chosenCtors, object[] explicitArgs) + { + + ObjectWrapper wrapper = new ObjectWrapper(); ConstructorInfo constructorToUse = null; object[] argsToUse = null; @@ -198,19 +232,9 @@ namespace Spring.Objects.Factory.Support throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor."); } - wrapper.WrappedInstance = instantiationStrategy.Instantiate(rod, objectName, this.objectFactory, constructorToUse, argsToUse); - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", objectName, constructorToUse)); - } - - #endregion - - return wrapper; + return new ConstructorInstantiationInfo(constructorToUse, argsToUse); + } /// @@ -636,7 +660,5 @@ namespace Spring.Objects.Factory.Support } } } - - } diff --git a/src/Spring/Spring.Core/Spring.Core.2003.csproj b/src/Spring/Spring.Core/Spring.Core.2003.csproj index 19a35adc..38dcc43d 100644 --- a/src/Spring/Spring.Core/Spring.Core.2003.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2003.csproj @@ -342,6 +342,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + Code + Code @@ -253,6 +254,7 @@ Code + @@ -260,6 +262,7 @@ + @@ -681,6 +684,7 @@ + diff --git a/src/Spring/Spring.Core/Spring.Core.2008.csproj b/src/Spring/Spring.Core/Spring.Core.2008.csproj index eac21748..478fcb42 100644 --- a/src/Spring/Spring.Core/Spring.Core.2008.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2008.csproj @@ -274,6 +274,7 @@ + @@ -690,6 +691,7 @@ + diff --git a/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs b/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs index be040197..7cebdd51 100644 --- a/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs +++ b/src/Spring/Spring.Services/ServiceModel/ServiceExporter.cs @@ -27,7 +27,7 @@ using System.Reflection; using System.Reflection.Emit; using System.ServiceModel; using System.Net.Security; - +using Spring.Objects.Factory.Config; using Spring.Util; using Spring.Context; using Spring.Core.TypeResolution; @@ -76,7 +76,7 @@ namespace Spring.ServiceModel /// /// The owning factory. /// - protected IObjectFactory objectFactory; + protected DefaultListableObjectFactory objectFactory; /// /// The generated WCF service wrapper type. @@ -260,7 +260,17 @@ namespace Spring.ServiceModel /// public virtual IObjectFactory ObjectFactory { - set { this.objectFactory = value; } + set + { + if (value is DefaultListableObjectFactory) + { + this.objectFactory = (DefaultListableObjectFactory)value; + } else + { + //TODO verify type of exception thrown + throw new ArgumentException("ObjectFactory must of type DefaultListableObjectFactory"); + } + } } #endregion @@ -368,7 +378,7 @@ namespace Spring.ServiceModel { IProxyTypeBuilder builder = new ConfigurableServiceProxyTypeBuilder( TargetName, objectFactory.GetType(TargetName), this.objectName, _useServiceProxyTypeCache, - Name, Namespace, ConfigurationName, CallbackContract, ProtectionLevel, SessionMode); + Name, Namespace, ConfigurationName, CallbackContract, ProtectionLevel, SessionMode, this.objectFactory); if (ContractInterface != null) { @@ -397,12 +407,12 @@ namespace Spring.ServiceModel private sealed class ConfigurableServiceProxyTypeBuilder : ServiceProxyTypeBuilder { private CustomAttributeBuilder serviceContractAttribute; + private DefaultListableObjectFactory objectFactory; - public ConfigurableServiceProxyTypeBuilder(string targetName, Type targetType, string objectName, bool useServiceProxyTypeCache, - string name, string ns, string configurationName, Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode) + public ConfigurableServiceProxyTypeBuilder(string targetName, Type targetType, string objectName, bool useServiceProxyTypeCache, string name, string ns, string configurationName, Type callbackContract, ProtectionLevel protectionLevel, SessionMode sessionMode, DefaultListableObjectFactory objectFactory) : base(targetName, targetType, objectName, useServiceProxyTypeCache) { - + this.objectFactory = objectFactory; if (!StringUtils.HasText(configurationName)) { name = this.Interfaces[0].Name; @@ -499,6 +509,84 @@ namespace Spring.ServiceModel return proxiableInterfaces; } + + /// + /// Applies attributes to the proxy class. + /// + /// The type builder to use. + /// The proxied class. + /// + /// + protected override void ApplyTypeAttributes(TypeBuilder typeBuilder, Type targetType) + { + foreach (object attr in GetTypeAttributes(targetType)) + { + if (attr is CustomAttributeBuilder) + { + typeBuilder.SetCustomAttribute((CustomAttributeBuilder)attr); + } +#if NET_2_0 + else if (attr is CustomAttributeData) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((CustomAttributeData)attr)); + } +#endif + else if (attr is Attribute) + { + typeBuilder.SetCustomAttribute( + ReflectionUtils.CreateCustomAttribute((Attribute)attr)); + } + else if (attr is IObjectDefinition) + { + RootObjectDefinition objectDefinition = (RootObjectDefinition) attr; + + //TODO check that object definition is for an Attribute type. + + //Change object definition so it can be instantiated and make prototype scope. + objectDefinition.IsAbstract = false; + objectDefinition.IsSingleton = false; + string objectName = ObjectDefinitionReaderUtils.GenerateObjectName(objectDefinition, objectFactory); + objectFactory.RegisterObjectDefinition(objectName, objectDefinition); + + + //find constructor and constructor arg values to create this attribute. + ConstructorResolver constructorResolver = new ConstructorResolver(objectFactory, objectFactory, + new SimpleInstantiationStrategy(), + new ObjectDefinitionValueResolver(objectFactory)); + + + ConstructorInstantiationInfo ci = constructorResolver.GetConstructorInstantiationInfo(objectName, + objectDefinition, + null, null); + + if (objectDefinition.PropertyValues.PropertyValues.Length == 0) + { + CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, + ci.ArgInstances); + typeBuilder.SetCustomAttribute(cab); + } + else + { + object attributeInstance = objectFactory.GetObject(objectName); + IObjectWrapper wrappedAttributeInstance = new ObjectWrapper(attributeInstance); + PropertyInfo[] namedProperties = wrappedAttributeInstance.GetPropertyInfos(); + object[] propertyValues = new object[namedProperties.Length]; + for (int i = 0; i < namedProperties.Length; i++) + { + propertyValues[i] = + wrappedAttributeInstance.GetPropertyValue(namedProperties[i].Name); + } + CustomAttributeBuilder cab = new CustomAttributeBuilder(ci.ConstructorInfo, ci.ArgInstances, + namedProperties, propertyValues); + typeBuilder.SetCustomAttribute(cab); + } + + + } + + } + } } #endregion diff --git a/src/Spring/Spring.Web/Spring.Web.2003.csproj b/src/Spring/Spring.Web/Spring.Web.2003.csproj index 5a4c2d03..d9360320 100644 --- a/src/Spring/Spring.Web/Spring.Web.2003.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2003.csproj @@ -135,6 +135,11 @@ SubType = "Code" BuildAction = "Compile" /> + Code + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml index df95671a..90bdb50c 100644 --- a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Config/TypeAliases.xml @@ -6,10 +6,26 @@ + + + + + + + + + + + + + + + + @@ -20,6 +36,18 @@ + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml new file mode 100644 index 00000000..b44d63f1 --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Data/Spring/Objects/Factory/Xml/ctor-args.xml @@ -0,0 +1,19 @@ + + + + Tests for list and map handling in an XML object definition file. + + + + + + + + + + + + + + + diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs index 7b7f62ee..0309671e 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/PropertyFileVariableSourceTests.cs @@ -18,7 +18,7 @@ #endregion -#region Imports +#region using NUnit.Framework; using Spring.Core.IO; @@ -27,7 +27,7 @@ using Spring.Core.IO; namespace Spring.Objects.Factory.Config { - /// + /// /// Unit tests for the PropertyFileVariableSource class. /// /// Aleksandar Seovic @@ -50,17 +50,39 @@ namespace Spring.Objects.Factory.Config Assert.IsNull(vs.ResolveVariable("dummy")); } + [Test] + public void TestMissingResourceLocation() + { + PropertyFileVariableSource vs = new PropertyFileVariableSource(); + vs.IgnoreMissingResources = true; + vs.Locations = new IResource[] + { + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/non-existent.properties") + , + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties") + , + }; + + // existing vars + Assert.AreEqual("Aleks Seovic", vs.ResolveVariable("name")); + Assert.AreEqual("32", vs.ResolveVariable("age")); + } + + [Test] public void TestVariablesResolutionWithTwoLocations() { PropertyFileVariableSource vs = new PropertyFileVariableSource(); vs.Locations = new IResource[] - { - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties"), - new AssemblyResource( - "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/two.properties") - }; + { + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/one.properties") + , + new AssemblyResource( + "assembly://Spring.Core.Tests/Spring.Data.Spring.Objects.Factory.Config/two.properties") + }; // existing vars Assert.AreEqual("Aleksandar Seovic", vs.ResolveVariable("name")); // should be overriden by the second file @@ -71,4 +93,4 @@ namespace Spring.Objects.Factory.Config Assert.IsNull(vs.ResolveVariable("dummy")); } } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs index c4ed3aff..3e078070 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/TypeAliasConfigurerTests.cs @@ -108,8 +108,7 @@ namespace Spring.Objects.Factory.Config [Test] public void WithinApplicationContext() { - IApplicationContext ctx = new XmlApplicationContext( - "file://Spring/Objects/Factory/Config/typeAliases.xml"); + IApplicationContext ctx = new XmlApplicationContext("file://Spring/Objects/Factory/Config/typeAliases.xml"); object obj1 = ctx.GetObject("testObject1"); Assert.IsNotNull(obj1); @@ -131,6 +130,26 @@ namespace Spring.Objects.Factory.Config Assert.AreEqual(typeof(TestObject), obj4.GetType()); Assert.AreEqual("Bruno", ((TestObject)obj4).Name); Assert.AreEqual(30, ((TestObject)obj4).Age); + + + object obj6 = ctx.GetObject("testObject6"); + Assert.IsNotNull(obj6); + Assert.AreEqual(typeof(TestObject), obj6.GetType()); + Assert.AreEqual("name from section", ((TestObject)obj6).Name); + Assert.AreEqual(27, ((TestObject)obj6).Age); + + + object obj5 = ctx.GetObject("testObject5"); + Assert.IsNotNull(obj5); + Assert.AreEqual(typeof(TestObject), obj5.GetType()); + Assert.AreEqual("overide-name", ((TestObject)obj5).Name); + Assert.AreEqual(26, ((TestObject)obj5).Age); + + object vpc = ctx.GetObject("vpc"); + Assert.IsNotNull(vpc); + Assert.AreEqual(typeof(VariablePlaceholderConfigurer), vpc.GetType()); + + } private void CreateConfigurerAndTestLinkedList(IDictionary typeAliases) diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs index 36c32387..7c00612b 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlObjectCollectionTests.cs @@ -55,6 +55,29 @@ namespace Spring.Objects.Factory.Xml //XmlConfigurator.Configure(); } + [Test] + public void WalkThrough() + { + IResource resource = new ReadOnlyXmlTestResource("ctor-args.xml", GetType()); + XmlObjectFactory xof = new XmlObjectFactory(resource); + TestObject rod = (TestObject)xof.GetObject("rod"); + Assert.AreEqual(1, rod.Age); + + RootObjectDefinition def = (RootObjectDefinition) xof.GetObjectDefinition("rod"); + ConstructorResolver resolver = new ConstructorResolver(xof, xof, new SimpleInstantiationStrategy(), + new ObjectDefinitionValueResolver(xof)); + ConstructorInstantiationInfo ci = resolver.GetConstructorInstantiationInfo("rod", def, null, null); + + AbstractObjectDefinition objDef = (AbstractObjectDefinition)xof.GetObjectDefinition("foo"); + objDef.IsAbstract = false; + + TestObject foo = (TestObject) xof.GetObject("foo"); + + + Assert.AreEqual(2, foo.Age); + } + + [Test] public void RefSubelementsBuildCollection() { diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj index 018e0c24..e7e34207 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj @@ -821,6 +821,7 @@ + @@ -860,7 +861,9 @@ - + + Always + diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll-1.1.config b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll-1.1.config index ff0f0a9a..0699379e 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll-1.1.config +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll-1.1.config @@ -28,6 +28,9 @@ limitations under the License.
+ +
+
@@ -58,8 +61,13 @@ limitations under the License. + + + + + diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll.config b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll.config index 4ec38fa9..d5fd00d0 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll.config +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.dll.config @@ -19,7 +19,7 @@ limitations under the License.
- +
@@ -32,6 +32,9 @@ limitations under the License.
+ +
+
@@ -62,8 +65,13 @@ limitations under the License. + + + + + @@ -185,7 +193,7 @@ limitations under the License. - + diff --git a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs index e7ec90b1..6895ea55 100644 --- a/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Integration.Tests/Messaging/Nms/Core/NmsTemplateTests.cs @@ -18,7 +18,9 @@ #endregion +using System; using Apache.NMS; +using Apache.NMS.ActiveMQ; using NUnit.Framework; using Spring.Testing.NUnit; @@ -41,6 +43,14 @@ namespace Spring.Messaging.Nms.Core this.PopulateProtectedVariables = true; } + [Test] + public void ConnectionThrowException() + { + ConnectionFactory cf = new ConnectionFactory(); + cf.BrokerUri = new Uri("tcp://localaaahost:61616"); + IConnection c = cf.CreateConnection(); + } + [Test] public void ConvertAndSend() diff --git a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj index 0ed0f81d..226e0bd1 100644 --- a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj +++ b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj @@ -86,6 +86,7 @@ +