();
+ foreach (ConfigurationClassMethod method in _methods)
+ {
+ String dClassName = method.MethodMetadata.DeclaringType.FullName;
+ String methodName = method.MethodMetadata.Name;
+
+ string paramTypes = ParamTypesToString(method.MethodMetadata);
+
+ String fqMethodName = dClassName + hashDelim + methodName + paramTypes;
+ if (!methodNameCounts.ContainsKey(fqMethodName))
+ {
+ methodNameCounts.Add(fqMethodName, 1);
+ }
+ else
+ {
+ int currentCount = methodNameCounts[fqMethodName];
+ methodNameCounts.Add(fqMethodName, currentCount++);
+ }
+ }
+
+ foreach (String methodName in methodNameCounts.Keys)
+ {
+ int count = methodNameCounts[methodName];
+ if (count > 1)
+ {
+ String shortMethodName = methodName.Substring(methodName.IndexOf(hashDelim) + 1);
+ problemReporter.Error(new ObjectMethodOverloadingProblem(shortMethodName, count, Resource, ConfigurationClassType));
+ }
+ }
+
+ if (Attribute.GetCustomAttribute(_configurationClassType, typeof(ConfigurationAttribute)) != null)
+ {
+
+ if (ConfigurationClassType.IsSealed)
+ {
+ problemReporter.Error(new SealedConfigurationProblem(SimpleName, Resource, ConfigurationClassType));
+
+ }
+
+ foreach (ConfigurationClassMethod method in _methods)
+ {
+ method.Validate(problemReporter);
+ }
+ }
+ }
+
+ private string ParamTypesToString(MethodInfo methodMetadata)
+ {
+ var result = new StringBuilder();
+
+ foreach (var parameter in methodMetadata.GetParameters())
+ {
+ result.Append(parameter.ParameterType.ToString());
+ }
+
+ return result.ToString();
+ }
+
+ private class SealedConfigurationProblem : Problem
+ {
+ public SealedConfigurationProblem(string name, IResource resource, Type configurationClassType)
+ : base(String.Format("[Configuration] class '{0}' may not be sealed. Remove the sealed modifier to continue.", name), new Location(resource, configurationClassType))
+ { }
+
+ }
+
+ //This class is for future use when parameterized [ObjectDef] methods are supported in the future.
+ //Until then, the test for only permitting zero-param [ObjectDef] methods would fail first, previnting this error from ever being reported
+ private class ObjectMethodOverloadingProblem : Problem
+ {
+ public ObjectMethodOverloadingProblem(string methodName, int count, IResource resource, Type configurationClassType)
+ : base(String.Format("[Configuration] class '{0}' has {1} overloaded [Definiton] methods named '{2}'. " +
+ "Only one [ObjectDef] method of a given name is allowed within each [Configuration] class.", configurationClassType.Name, count, methodName), new Location(resource, configurationClassType))
+ { }
+
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs
new file mode 100644
index 00000000..5a93bf07
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassAssemblyResource.cs
@@ -0,0 +1,203 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.IO;
+using System.Reflection;
+using Spring.Core.IO;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Implementation of the IResource that represents an assembly containing one or more resources.
+ ///
+ public class ConfigurationClassAssemblyResource : IResource
+ {
+ private readonly string _containingAssemblyFileName;
+ private readonly Type _type;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type.
+ public ConfigurationClassAssemblyResource(Type type)
+ {
+ _type = type;
+ _containingAssemblyFileName = Assembly.GetAssembly(_type.GetType()).Location;
+ }
+
+ #region IResource Members
+
+ ///
+ /// Creates a resource relative to this resource.
+ ///
+ /// The path (always resolved as relative to this resource).
+ /// The relative resource.
+ ///
+ /// If the relative resource could not be created from the supplied
+ /// path.
+ ///
+ ///
+ /// If the resource does not support the notion of a relative path.
+ ///
+ public IResource CreateRelative(string relativePath)
+ {
+ throw new InvalidOperationException();
+ }
+
+ ///
+ /// Does this resource represent a handle with an open stream?
+ ///
+ ///
+ /// if this resource represents a handle with an
+ /// open stream.
+ ///
+ ///
+ ///
+ /// If , the
+ /// cannot be read multiple times, and must be read and then closed to
+ /// avoid resource leaks.
+ ///
+ ///
+ /// Will be for all usual resource descriptors.
+ ///
+ ///
+ ///
+ public bool IsOpen
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Returns the handle for this resource.
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// For safety, always check the value of the
+ /// property prior to
+ /// accessing this property; resources that cannot be exposed as
+ /// a will typically return
+ /// from a call to the
+ /// property.
+ ///
+ ///
+ ///
+ /// If the resource is not available or cannot be exposed as a
+ /// .
+ ///
+ ///
+ ///
+ public Uri Uri
+ {
+ get { return new Uri(_containingAssemblyFileName); }
+ }
+
+ ///
+ /// Returns a handle for this resource.
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ ///
+ /// For safety, always check the value of the
+ /// property prior to
+ /// accessing this property; resources that cannot be exposed as
+ /// a will typically return
+ /// from a call to the
+ /// property.
+ ///
+ ///
+ ///
+ /// If the resource is not available on a filesystem, or cannot be
+ /// exposed as a handle.
+ ///
+ ///
+ ///
+ public FileInfo File
+ {
+ get { return new FileInfo(_containingAssemblyFileName); }
+ }
+
+ ///
+ /// Returns a description for this resource.
+ ///
+ /// A description for this resource.
+ ///
+ ///
+ /// The description is typically used for diagnostics and other such
+ /// logging when working with the resource.
+ ///
+ ///
+ /// Implementations are also encouraged to return this value from their
+ /// method.
+ ///
+ ///
+ public string Description
+ {
+ get { return _type.FullName; }
+ }
+
+ ///
+ /// Does this resource actually exist in physical form?
+ ///
+ ///
+ /// if this resource actually exists in physical
+ /// form (for example on a filesystem).
+ ///
+ ///
+ ///
+ /// An example of a resource that physically exists would be a
+ /// file on a local filesystem. An example of a resource that does not
+ /// physically exist would be an in-memory stream.
+ ///
+ ///
+ ///
+ ///
+ public bool Exists
+ {
+ get { return System.IO.File.Exists(_containingAssemblyFileName); }
+ }
+
+ ///
+ /// Return an for this resource.
+ ///
+ /// An .
+ ///
+ ///
+ /// Clients of this interface must be aware that every access of this
+ /// property will create a fresh
+ /// ;
+ /// it is the responsibility of the calling code to close any such
+ /// .
+ ///
+ ///
+ ///
+ /// If the stream could not be opened.
+ ///
+ public Stream InputStream
+ {
+ get { throw new InvalidOperationException(); }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs
new file mode 100644
index 00000000..a33d612a
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassEnhancer.cs
@@ -0,0 +1,284 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Reflection;
+using System.Reflection.Emit;
+
+using Spring.Objects.Factory.Config;
+using Spring.Util;
+using Spring.Proxy;
+using Common.Logging;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Enhances Configuration classes by generating a dynamic proxy capable of
+ /// interacting with the Spring container to respect object semantics.
+ ///
+ /// Chris Beams
+ /// Juergen Hoeller
+ /// Bruno Baia (.NET)
+ ///
+ public class ConfigurationClassEnhancer
+ {
+ private IConfigurationClassInterceptor interceptor;
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ /// The supplied ObjectFactory to check for the existence of object definitions.
+ ///
+ public ConfigurationClassEnhancer(IConfigurableListableObjectFactory objectFactory)
+ {
+ AssertUtils.ArgumentNotNull(objectFactory, "objectFactory");
+
+ this.interceptor = new ConfigurationClassInterceptor(objectFactory);
+ }
+
+ ///
+ /// Generates a dynamic subclass of the specified Configuration class with a
+ /// container-aware interceptor capable of respecting scoping and other bean semantics.
+ ///
+ /// The Configuration class.
+ /// The enhanced subclass.
+ public Type Enhance(Type configClass)
+ {
+ ConfigurationClassProxyTypeBuilder proxyTypeBuilder = new ConfigurationClassProxyTypeBuilder(configClass, this.interceptor);
+ return proxyTypeBuilder.BuildProxyType();
+ }
+
+ ///
+ /// Intercepts the invocation of any -decorated methods in order
+ /// to ensure proper handling of object semantics such as scoping and AOP proxying.
+ ///
+ public interface IConfigurationClassInterceptor
+ {
+ ///
+ /// Process the -decorated method to check
+ /// for the existence of this object.
+ ///
+ /// The method providing the object definition.
+ /// When this method returns true, contains the object definition.
+ /// true if the object exists; otherwise, false.
+ bool ProcessDefinition(MethodInfo method, out object instance);
+ }
+
+ private sealed class ConfigurationClassInterceptor : IConfigurationClassInterceptor
+ {
+ #region Logging
+
+ private static readonly ILog Logger = LogManager.GetLogger();
+
+ #endregion
+
+ private readonly IConfigurableListableObjectFactory _configurableListableObjectFactory;
+
+ public ConfigurationClassInterceptor(IConfigurableListableObjectFactory configurableListableObjectFactory)
+ {
+ this._configurableListableObjectFactory = configurableListableObjectFactory;
+ }
+
+ public bool ProcessDefinition(MethodInfo method, out object instance)
+ {
+ instance = null;
+
+ string objectName = method.Name;
+
+ if (objectName.StartsWith("set_") || objectName.StartsWith("get_"))
+ {
+ return false;
+ }
+
+ object[] attribs = method.GetCustomAttributes(typeof(ObjectDefAttribute), true);
+ if (attribs.Length == 0)
+ {
+ return false;
+ }
+
+ if (this._configurableListableObjectFactory.IsCurrentlyInCreation(objectName))
+ {
+ Logger.Debug(m => m("Object '{0}' currently in creation, created one", objectName));
+
+ return false;
+ }
+
+ Logger.Debug(m => m("Object '{0}' not in creation, asked the application context for one", objectName));
+
+ instance = this._configurableListableObjectFactory.GetObject(objectName);
+ return true;
+ }
+ }
+
+ #region Proxy builder classes definition
+
+ private sealed class ConfigurationClassProxyTypeBuilder : InheritanceProxyTypeBuilder
+ {
+ private FieldBuilder interceptorField;
+ private IConfigurationClassInterceptor interceptor;
+
+ public ConfigurationClassProxyTypeBuilder(Type configurationClassType, IConfigurationClassInterceptor interceptor)
+ {
+ if (configurationClassType.IsSealed)
+ {
+ throw new ArgumentException(String.Format(
+ "[Configuration] classes '{0}' cannot be sealed [{0}].", configurationClassType.FullName));
+ }
+
+ this.Name = "ConfigurationClassProxy";
+ this.DeclaredMembersOnly = false;
+ this.BaseType = configurationClassType;
+ this.TargetType = configurationClassType;
+
+ this.interceptor = interceptor;
+ }
+
+ public override Type BuildProxyType()
+ {
+ IDictionary targetMethods = new Hashtable();
+
+ TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType);
+
+ // apply custom attributes to the proxy type.
+ //ApplyTypeAttributes(typeBuilder, BaseType);
+
+ // declare interceptor field
+ interceptorField = typeBuilder.DefineField("__Interceptor", typeof(IConfigurationClassInterceptor),
+ FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly);
+
+ // create constructors
+ ImplementConstructors(typeBuilder);
+
+ // proxy base virtual methods
+ InheritType(typeBuilder,
+ new ConfigurationClassProxyMethodBuilder(typeBuilder, this, false, targetMethods),
+ BaseType, this.DeclaredMembersOnly);
+
+ Type proxyType = typeBuilder.CreateType();
+
+ // set target method references
+ foreach (DictionaryEntry entry in targetMethods)
+ {
+ FieldInfo targetMethodFieldInfo = proxyType.GetField((string)entry.Key, BindingFlags.NonPublic | BindingFlags.Static);
+ targetMethodFieldInfo.SetValue(proxyType, entry.Value);
+ }
+
+ // set interceptor
+ FieldInfo interceptorFieldInfo = proxyType.GetField("__Interceptor", BindingFlags.NonPublic | BindingFlags.Static);
+ interceptorFieldInfo.SetValue(proxyType, this.interceptor);
+
+ return proxyType;
+ }
+
+ public void PushInterceptor(ILGenerator il)
+ {
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldfld, interceptorField);
+ }
+ }
+
+ private sealed class ConfigurationClassProxyMethodBuilder : AbstractProxyMethodBuilder
+ {
+ public static readonly MethodInfo ProcessDefinitionMethod =
+ typeof(IConfigurationClassInterceptor).GetMethod("ProcessDefinition", BindingFlags.Instance | BindingFlags.Public);
+
+ private ConfigurationClassProxyTypeBuilder customProxyGenerator;
+
+ private IDictionary targetMethods;
+
+ public ConfigurationClassProxyMethodBuilder(
+ TypeBuilder typeBuilder, ConfigurationClassProxyTypeBuilder proxyGenerator,
+ bool explicitImplementation, IDictionary targetMethods)
+ : base(typeBuilder, proxyGenerator, explicitImplementation)
+ {
+ this.customProxyGenerator = proxyGenerator;
+ this.targetMethods = targetMethods;
+ }
+
+ protected override void GenerateMethod(
+ ILGenerator il, MethodInfo method, MethodInfo interfaceMethod)
+ {
+ // Declare local variables
+ LocalBuilder interceptedReturnValue = il.DeclareLocal(typeof(Object));
+//#if DEBUG
+// interceptedReturnValue.SetLocalSymInfo("interceptedReturnValue");
+//#endif
+ LocalBuilder returnValue = null;
+ if (method.ReturnType != typeof(void))
+ {
+ returnValue = il.DeclareLocal(method.ReturnType);
+//#if DEBUG
+// returnValue.SetLocalSymInfo("returnValue");
+//#endif
+ }
+
+ // Declare static field that will cache base method
+ string methodId = "_m" + Guid.NewGuid().ToString("N");
+ targetMethods.Add(methodId, method);
+ FieldBuilder targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo),
+ FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly);
+
+ // Call IConfigurationClassInterceptor.TryGetObject method
+ il.Emit(OpCodes.Ldnull);
+ il.Emit(OpCodes.Stloc, interceptedReturnValue);
+ customProxyGenerator.PushInterceptor(il);
+ il.Emit(OpCodes.Ldsfld, targetMethodCacheField);
+ il.Emit(OpCodes.Ldloca_S, interceptedReturnValue);
+ il.EmitCall(OpCodes.Callvirt, ProcessDefinitionMethod, null);
+ Label jmpBaseCall = il.DefineLabel();
+ Label jmpEndIf = il.DefineLabel();
+ il.Emit(OpCodes.Brfalse_S, jmpBaseCall);
+
+ // if true
+ if (returnValue != null)
+ {
+ il.Emit(OpCodes.Ldloc, interceptedReturnValue);
+ if (method.ReturnType.IsValueType || method.ReturnType.IsGenericParameter)
+ {
+ il.Emit(OpCodes.Unbox_Any, method.ReturnType);
+ }
+ il.Emit(OpCodes.Stloc, returnValue);
+ il.Emit(OpCodes.Br, jmpEndIf);
+ }
+
+ // if false
+ il.MarkLabel(jmpBaseCall);
+ CallDirectBaseMethod(il, method);
+ if (returnValue != null)
+ {
+ il.Emit(OpCodes.Stloc, returnValue);
+ }
+
+ // end if
+ il.MarkLabel(jmpEndIf);
+
+ // return value
+ if (returnValue != null)
+ {
+ il.Emit(OpCodes.Ldloc, returnValue);
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs
new file mode 100644
index 00000000..305041e6
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassMethod.cs
@@ -0,0 +1,145 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Reflection;
+using Spring.Objects.Factory.Parsing;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Represents a class method marked with the .
+ ///
+ public class ConfigurationClassMethod
+ {
+ private readonly ConfigurationClass _configurationClass;
+
+ private readonly MethodInfo _methodInfo;
+
+ ///
+ /// Initializes a new instance of the ConfigurationClassMethod class.
+ ///
+ ///
+ ///
+ public ConfigurationClassMethod(MethodInfo methodInfo, ConfigurationClass configurationClass)
+ {
+ _methodInfo = methodInfo;
+ _configurationClass = configurationClass;
+ }
+
+ ///
+ /// Gets the configuration class.
+ ///
+ /// The configuration class.
+ public ConfigurationClass ConfigurationClass
+ {
+ get { return _configurationClass; }
+ }
+
+ ///
+ /// Gets the method metadata.
+ ///
+ /// The method metadata.
+ public MethodInfo MethodMetadata
+ {
+ get { return _methodInfo; }
+ }
+
+ ///
+ /// Gets the resource location.
+ ///
+ /// The resource location.
+ public Location ResourceLocation
+ {
+ get { return new Location(_configurationClass.Resource, _methodInfo); }
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString()
+ {
+ return string.Format("{0}:name={1},declaringClass={2}", GetType().Name, _methodInfo.Name,
+ _methodInfo.DeclaringType.FullName);
+ }
+
+ ///
+ /// Validates the specified problem reporter.
+ ///
+ /// The problem reporter.
+ public void Validate(IProblemReporter problemReporter)
+ {
+ //TODO: investigate whether this should be "if method has ObjectDef attribute" instead of "if class has Configuration attribute"
+ if (
+ Attribute.GetCustomAttribute(ConfigurationClass.ConfigurationClassType, typeof (ConfigurationAttribute)) !=
+ null)
+ {
+
+ if (MethodMetadata.IsStatic)
+ {
+ problemReporter.Error(new StaticMethodError(MethodMetadata.Name, ResourceLocation));
+ }
+
+ if (!MethodMetadata.IsVirtual)
+ {
+ problemReporter.Error(new NonVirtualMethodError(MethodMetadata.Name, ResourceLocation));
+ }
+
+ if (MethodMetadata.GetParameters().Length != 0)
+ {
+ problemReporter.Error(new MethodWithParametersError(MethodMetadata.Name, ResourceLocation));
+ }
+ }
+ }
+
+ private class MethodWithParametersError : Problem
+ {
+ public MethodWithParametersError(string methodName, Location location)
+ : base(
+ String.Format(
+ "Method '{0}' must not accept parameters; remove the method's parameters to continue.",
+ methodName), location)
+ {
+ }
+ }
+
+ private class NonVirtualMethodError : Problem
+ {
+ public NonVirtualMethodError(string methodName, Location location)
+ : base(String.Format("Method '{0}' must be public virtual; change the method's modifiers to continue.",
+ methodName), location)
+ {
+ }
+ }
+
+ private class StaticMethodError : Problem
+ {
+ public StaticMethodError(string methodName, Location location)
+ : base(
+ String.Format("Method '{0}' must not be static; remove the method's static modifier to continue.",
+ methodName), location)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs
new file mode 100644
index 00000000..a2d0a9f4
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs
@@ -0,0 +1,308 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+using Common.Logging;
+
+using Spring.Core.TypeResolution;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Parsing;
+using Spring.Objects.Factory.Support;
+using Spring.Stereotype;
+
+#endregion
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Reads the class with the applied and converts it into an instance.
+ ///
+ public class ConfigurationClassObjectDefinitionReader
+ {
+ private static readonly ILog Logger = LogManager.GetLogger();
+
+ private IProblemReporter _problemReporter;
+
+ private IObjectDefinitionRegistry _registry;
+
+ ///
+ /// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class.
+ ///
+ ///
+ ///
+ public ConfigurationClassObjectDefinitionReader(IObjectDefinitionRegistry registry,
+ IProblemReporter problemReporter)
+ {
+ _registry = registry;
+ _problemReporter = problemReporter;
+ }
+
+ private static bool HasAttributeOnMethods(Type objectType, Type attributeType)
+ {
+ Collections.Generic.ISet methods = ConfigurationClassParser.GetAllMethodsWithCustomAttributeForClass(objectType,
+ attributeType);
+ foreach (MethodInfo method in methods)
+ {
+ if (Attribute.GetCustomAttribute(method, attributeType) != null)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Loads the object definitions.
+ ///
+ /// The configuration model.
+ public void LoadObjectDefinitions(Collections.Generic.ISet configurationModel)
+ {
+ foreach (ConfigurationClass configClass in configurationModel)
+ {
+ LoadObjectDefinitionsForConfigurationClass(configClass);
+ }
+ }
+
+ private void LoadObjectDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass)
+ {
+ if (configClass.ObjectName != null)
+ {
+ // a Object definition already exists for this configuration class -> nothing to do
+ return;
+ }
+
+ // no Object definition exists yet -> this must be an imported configuration class ([Import]).
+ GenericObjectDefinition configObjectDef = new GenericObjectDefinition();
+ String className = configClass.ConfigurationClassType.Name;
+ configObjectDef.ObjectTypeName = className;
+ configObjectDef.ObjectType = configClass.ConfigurationClassType;
+ if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType))
+ {
+ String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configObjectDef,
+ _registry);
+ configClass.ObjectName = configObjectName;
+ Logger.Debug(m => m("Registered object definition for imported [Configuration] class {0}",
+ configObjectName));
+ }
+ }
+
+ ///
+ /// Checks the class to see if it is a candidate to be a source.
+ ///
+ /// The object definition.
+ ///
+ public static bool CheckConfigurationClassCandidate(IObjectDefinition objectDefinition)
+ {
+ Type objectType = null;
+ if (objectDefinition is AbstractObjectDefinition)
+ {
+ AbstractObjectDefinition definition = (AbstractObjectDefinition)objectDefinition;
+ if (definition.HasObjectType)
+ {
+ objectType = definition.ObjectType;
+ }
+ else
+ {
+ if (definition.ObjectTypeName != null && !definition.IsAbstract)
+ {
+ objectType = TypeResolutionUtils.ResolveType(definition.ObjectTypeName);
+ }
+ }
+ if (objectType != null)
+ {
+ if (Attribute.GetCustomAttribute(objectType, typeof(ConfigurationAttribute)) != null)
+ {
+ return true;
+ }
+ if (Attribute.GetCustomAttribute(objectType, typeof(ComponentAttribute)) != null ||
+ HasAttributeOnMethods(objectType, typeof(ObjectDefAttribute)))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool CheckConfigurationClassCandidate(Type type)
+ {
+ if (type != null)
+ {
+ return (Attribute.GetCustomAttribute(type, typeof(ConfigurationAttribute)) != null);
+ }
+
+ return false;
+ }
+
+ private void LoadObjectDefinitionsForConfigurationClass(ConfigurationClass configClass)
+ {
+ LoadObjectDefinitionForConfigurationClassIfNecessary(configClass);
+
+ foreach (ConfigurationClassMethod method in configClass.Methods)
+ {
+ LoadObjectDefinitionsForModelMethod(method);
+ }
+
+ LoadObjectDefinitionsFromImportedResources(configClass.ImportedResources);
+ }
+
+ private void LoadObjectDefinitionsForModelMethod(ConfigurationClassMethod method)
+ {
+ ConfigurationClass configClass = method.ConfigurationClass;
+ MethodInfo metadata = method.MethodMetadata;
+
+ RootObjectDefinition objDef = new ConfigurationClassObjectDefinition();
+
+ objDef.FactoryObjectName = configClass.ObjectName;
+ objDef.FactoryMethodName = metadata.Name;
+ objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor;
+
+ // consider name and any aliases
+ //Dictionary ObjectAttributes = metadata.getAnnotationAttributes(Object.class.getName());
+ object[] objectAttributes = metadata.GetCustomAttributes(typeof(ObjectDefAttribute), true);
+ List names = new List();
+ foreach (object t in objectAttributes)
+ {
+ string[] namesAndAliases = ((ObjectDefAttribute)t).NamesToArray;
+
+ if (namesAndAliases != null)
+ {
+ names.Add(metadata.Name);
+ }
+ else
+ {
+ namesAndAliases = new[] { metadata.Name };
+ }
+
+ names.AddRange(namesAndAliases);
+ }
+
+ string objectName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name);
+ for (int i = 1; i < names.Count; i++)
+ {
+ _registry.RegisterAlias(objectName, names[i]);
+ }
+
+ // has this already been overridden (e.g. via XML)?
+ if (_registry.ContainsObjectDefinition(objectName))
+ {
+ IObjectDefinition existingObjectDef = _registry.GetObjectDefinition(objectName);
+ // is the existing Object definition one that was created from a configuration class?
+ if (!(existingObjectDef is ConfigurationClassObjectDefinition))
+ {
+ // no -> then it's an external override, probably XML
+ // overriding is legal, return immediately
+ Logger.Debug(m => m("Skipping loading Object definition for {0}: a definition for object " +
+ "'{1}' already exists. This is likely due to an override in XML.", method,
+ objectName));
+ return;
+ }
+ }
+
+ //TODO: container does not presently support the concept of Primary object defintion for type resolution
+ //if (Attribute.GetCustomAttribute(metadata, typeof(PrimaryAttribute)) != null)
+ //{
+ // ObjectDef.isPrimary = true;
+ //}
+
+ // is this Object to be instantiated lazily?
+ if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) != null)
+ {
+ objDef.IsLazyInit =
+ (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) as LazyAttribute).LazyInitialize;
+ }
+
+ if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null)
+ {
+ objDef.DependsOn =
+ (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name;
+ }
+
+ //TODO: container does not presently support autowiring to the degree needed to support this feature as of yet
+ //Autowire autowire = (Autowire) ObjectAttributes.get("autowire");
+ //if (autowire.isAutowire()) {
+ // ObjectDef.setAutowireMode(autowire.value());
+ //}
+
+ if (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) != null)
+ {
+ objDef.InitMethodName =
+ (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute).
+ InitMethod;
+ objDef.DestroyMethodName =
+ (Attribute.GetCustomAttribute(metadata, typeof(ObjectDefAttribute)) as ObjectDefAttribute).
+ DestroyMethod;
+ }
+
+ // consider scoping
+ if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null)
+ {
+ objDef.Scope =
+ (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString();
+ }
+
+ Logger.Debug(m => m("Registering Object definition for [ObjectDef] method {0}.{1}()",
+ configClass.ConfigurationClassType.Name, objectName));
+
+ _registry.RegisterObjectDefinition(objectName, objDef);
+ }
+
+ private void LoadObjectDefinitionsFromImportedResources(IEnumerable> importedResources)
+ {
+ IDictionary readerInstanceCache =
+ new Dictionary();
+ foreach (KeyValuePair entry in importedResources)
+ {
+ String resource = entry.Key;
+ Type readerClass = entry.Value;
+
+ if (!readerInstanceCache.ContainsKey(readerClass))
+ {
+ try
+ {
+ IObjectDefinitionReader readerInstance =
+ (IObjectDefinitionReader)Activator.CreateInstance(readerClass, _registry);
+
+ readerInstanceCache.Add(readerClass, readerInstance);
+ }
+ catch (Exception)
+ {
+ throw new InvalidOperationException(
+ String.Format("Could not instantiate IObjectDefinitionReader class {0}",
+ readerClass.FullName));
+ }
+ }
+
+ IObjectDefinitionReader reader = readerInstanceCache[readerClass];
+
+ reader.LoadObjectDefinitions(resource);
+ }
+ }
+
+ private class ConfigurationClassObjectDefinition : RootObjectDefinition
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs
new file mode 100644
index 00000000..2385ec2d
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassParser.cs
@@ -0,0 +1,194 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using Spring.Objects.Factory.Parsing;
+using Spring.Collections.Generic;
+using System.Reflection;
+
+namespace Spring.Context.Attributes
+{
+
+ ///
+ /// Parses classes with the applied to them.
+ ///
+ public class ConfigurationClassParser
+ {
+ private Collections.Generic.ISet _configurationClasses = new HashedSet();
+
+ private Stack _importStack = new Stack();
+
+ private IProblemReporter _problemReporter;
+
+ ///
+ /// Initializes a new instance of the ConfigurationClassParser class.
+ ///
+ ///
+ public ConfigurationClassParser(IProblemReporter problemReporter)
+ {
+ _problemReporter = problemReporter;
+ }
+
+ ///
+ /// Gets the configuration classes.
+ ///
+ /// The configuration classes.
+ public Collections.Generic.ISet ConfigurationClasses
+ {
+ get { return _configurationClasses; }
+ }
+
+ ///
+ /// Parses the specified type.
+ ///
+ /// The type.
+ /// Name of the object.
+ public void Parse(Type type, string objectName)
+ {
+ ProcessConfigurationClass(new ConfigurationClass(objectName, type));
+ }
+
+ ///
+ /// Validates this instance.
+ ///
+ public void Validate()
+ {
+ foreach (ConfigurationClass configClass in ConfigurationClasses)
+ {
+ configClass.Validate(_problemReporter);
+ }
+ }
+
+ ///
+ /// Processes the configuration class.
+ ///
+ /// The configuration class.
+ protected void ProcessConfigurationClass(ConfigurationClass configurationClass)
+ {
+ DoProcessConfigurationClass(configurationClass);
+
+ if (ConfigurationClasses.Contains(configurationClass) && configurationClass.ObjectName != null)
+ {
+ // Explicit object definition found, probably replacing an import.
+ // Let's remove the old one and go with the new one.
+ ConfigurationClasses.Remove(configurationClass);
+ }
+ ConfigurationClasses.Add(configurationClass);
+ }
+
+ private void DoProcessConfigurationClass(ConfigurationClass configurationClass)
+ {
+
+ Attribute[] importAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportAttribute));
+
+ if (importAttributes.Length > 0)
+ {
+ foreach (Attribute importAttribute in importAttributes)
+ {
+ ImportAttribute attrib = importAttribute as ImportAttribute;
+
+ if (null != attrib)
+ {
+ ProcessImport(configurationClass, attrib.Types);
+ }
+ }
+ }
+
+ Attribute[] importResourceAttributes = Attribute.GetCustomAttributes(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute));
+
+ if (importResourceAttributes.Length > 0)
+ {
+ foreach (Attribute importResourceAttribute in importResourceAttributes)
+ {
+ ImportResourceAttribute attrib = importResourceAttribute as ImportResourceAttribute;
+
+ if (null != attrib)
+ {
+ foreach (string resource in attrib.Resources)
+ {
+ configurationClass.AddImportedResource(resource, attrib.DefinitionReader);
+ }
+ }
+ }
+ }
+
+ Collections.Generic.ISet definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(ObjectDefAttribute));
+ foreach (MethodInfo definitionMethod in definitionMethods)
+ {
+ configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass));
+
+ }
+ }
+
+ ///
+ /// Gets all methods with custom attribute for class.
+ ///
+ /// The class.
+ /// The custom attribute.
+ ///
+ public static Collections.Generic.ISet GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute)
+ {
+ Collections.Generic.ISet methods = new HashedSet();
+
+ foreach (MethodInfo method in theClass.GetMethods())
+ {
+ if (Attribute.GetCustomAttribute(method, customAttribute) != null)
+ {
+ methods.Add(method);
+ }
+ }
+
+ return methods;
+ }
+
+ private void ProcessImport(ConfigurationClass configClass, IEnumerable classesToImport)
+ {
+ if (_importStack.Contains(configClass))
+ {
+ _problemReporter.Error(new CircularImportProblem(configClass, _importStack, configClass.ConfigurationClassType));
+ }
+ else
+ {
+ _importStack.Push(configClass);
+ foreach (Type classToImport in classesToImport)
+ {
+ ProcessConfigurationClass(new ConfigurationClass(null, classToImport));
+ }
+ _importStack.Pop();
+ }
+ }
+
+ private class CircularImportProblem : Problem
+ {
+ public CircularImportProblem(ConfigurationClass configClass, Stack importStack, Type configurationClassType)
+ : base(String.Format("A circular [Import] has been detected: " +
+ "Illegal attempt by [Configuration] class '{0}' to import class '{1}' as '{2}' is " +
+ "already present in the current import stack [{3}]",
+ importStack.Peek().SimpleName, configClass.SimpleName,
+ configClass.SimpleName, importStack),
+ new Location(importStack.Peek().Resource, configurationClassType)
+ )
+ { }
+
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs
new file mode 100644
index 00000000..735891d2
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ConfigurationClassPostProcessor.cs
@@ -0,0 +1,192 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+
+using Common.Logging;
+
+using Spring.Core;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Parsing;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Config;
+using Spring.Collections.Generic;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Postprocesses the applied types registered with the .
+ ///
+ public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor, IOrdered
+ {
+ #region Logging
+
+ private static readonly ILog Logger = LogManager.GetLogger();
+
+ #endregion
+
+ private bool _postProcessObjectDefinitionRegistryCalled;
+
+ private bool _postProcessObjectFactoryCalled;
+
+ private IProblemReporter _problemReporter = new FailFastProblemReporter();
+
+ ///
+ /// Return the order value of this object, where a higher value means greater in
+ /// terms of sorting.
+ ///
+ ///
+ ///
+ ///
+ /// Normally starting with 0 or 1, with indicating
+ /// greatest. Same order values will result in arbitrary positions for the affected
+ /// objects.
+ ///
+ ///
+ /// Higher value can be interpreted as lower priority, consequently the first object
+ /// has highest priority.
+ ///
+ ///
+ /// The order value.
+ public int Order
+ {
+ get { return int.MinValue; }
+ }
+
+ ///
+ /// Sets the problem reporter.
+ ///
+ /// The problem reporter.
+ public IProblemReporter ProblemReporter
+ {
+ set { _problemReporter = (value ?? new FailFastProblemReporter()); }
+ }
+
+ ///
+ /// Postsprocesses the object definition registry.
+ ///
+ /// The registry.
+ public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry)
+ {
+ if (_postProcessObjectDefinitionRegistryCalled)
+ {
+ throw new InvalidOperationException("PostProcessObjectDefinitionRegistry already called for this post-processor");
+ }
+ if (_postProcessObjectFactoryCalled)
+ {
+ throw new InvalidOperationException("PostProcessObjectFactory already called for this post-processor");
+ }
+ _postProcessObjectDefinitionRegistryCalled = true;
+ ProcessConfigObjectDefinitions(registry);
+ }
+
+ ///
+ /// Postprocesses the object factory.
+ ///
+ /// The object factory.
+ public void PostProcessObjectFactory(IConfigurableListableObjectFactory objectFactory)
+ {
+ if (_postProcessObjectFactoryCalled)
+ {
+ throw new InvalidOperationException(
+ "PostProcessObjectFactory already called for this post-processor");
+ }
+ _postProcessObjectFactoryCalled = true;
+ if (!_postProcessObjectDefinitionRegistryCalled)
+ {
+ // ObjectDefinitionRegistryPostProcessor hook apparently not supported...
+ // Simply call processConfigObjectDefinitions lazily at this point then.
+ ProcessConfigObjectDefinitions((IObjectDefinitionRegistry)objectFactory);
+ }
+
+ EnhanceConfigurationClasses(objectFactory);
+ }
+
+ private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory)
+ {
+ ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(objectFactory);
+
+ IList objectNames = objectFactory.GetObjectDefinitionNames();
+
+ foreach (string name in objectNames)
+ {
+ IObjectDefinition objDef = objectFactory.GetObjectDefinition(name);
+
+ if (((AbstractObjectDefinition)objDef).HasObjectType)
+ {
+ if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null)
+ {
+ //TODO check type of object isn't infrastructure type.
+
+ Type configClass = objDef.ObjectType;
+ Type enhancedClass = enhancer.Enhance(configClass);
+
+ Logger.Debug(m => m("Replacing object definition '{0}' existing class '{1}' with enhanced class", name, configClass.FullName));
+
+ ((IConfigurableObjectDefinition)objDef).ObjectType = enhancedClass;
+ }
+ }
+ }
+ }
+
+ private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry)
+ {
+ Collections.Generic.ISet configCandidates = new HashedSet();
+ foreach (string objectName in registry.GetObjectDefinitionNames())
+ {
+ IObjectDefinition objectDef = registry.GetObjectDefinition(objectName);
+ if (ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(objectDef))
+ {
+ configCandidates.Add(new ObjectDefinitionHolder(objectDef, objectName));
+ }
+ }
+
+ //if nothing to process, bail out
+ if (configCandidates.Count == 0) { return; }
+
+ ConfigurationClassParser parser = new ConfigurationClassParser(_problemReporter);
+ foreach (ObjectDefinitionHolder holder in configCandidates)
+ {
+ IObjectDefinition bd = holder.ObjectDefinition;
+ try
+ {
+ if (bd is AbstractObjectDefinition && ((AbstractObjectDefinition)bd).HasObjectType)
+ {
+ parser.Parse(((AbstractObjectDefinition)bd).ObjectType, holder.ObjectName);
+ }
+ else
+ {
+ //parser.Parse(bd.ObjectTypeName, holder.ObjectName);
+ }
+ }
+ catch (ObjectDefinitionParsingException ex)
+ {
+ throw new ObjectDefinitionStoreException("Failed to load object class: " + bd.ObjectTypeName, ex);
+ }
+ }
+ parser.Validate();
+
+ // Read the model and create Object definitions based on its content
+ ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter);
+ reader.LoadObjectDefinitions(parser.ConfigurationClasses);
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs
new file mode 100644
index 00000000..9c4f5613
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/DependsOnAttribute.cs
@@ -0,0 +1,67 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// objects on which the current object depends. Any objects specified are guaranteed to be
+ /// created by the container before this object. Used infrequently in cases where a object
+ /// does not explicitly depend on another through properties or constructor arguments,
+ /// but rather depends on the side effects of another object's initialization.
+ /// Note: This attribute will not be inherited by child object definitions,
+ /// hence it needs to be specified per concrete object definition.
+ ///
+ /// Using at the class level has no effect unless component-scanning
+ /// is being used. If a -attributed class is declared via XML,
+ /// attribute metadata is ignored, and
+ /// <object depends-on="..."/> is respected instead.
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
+ public class DependsOnAttribute : Attribute
+ {
+ private string[] _name;
+
+ ///
+ /// Initializes a new instance of the DependsOn class.
+ ///
+ ///
+ public DependsOnAttribute(params string[] name)
+ {
+ _name = name;
+ }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ public string[] Name
+ {
+ get { return _name; }
+ set
+ {
+ _name = value;
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs b/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs
new file mode 100644
index 00000000..ff75cb14
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/IAssemblyTypeScanner.cs
@@ -0,0 +1,89 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using System.Reflection;
+
+namespace Spring.Context.Attributes
+{
+
+ ///
+ /// Scanner that can filter types from assemblies based on constraints.
+ ///
+ public interface IAssemblyTypeScanner
+ {
+ ///
+ /// Add the Assembly containing the specified .
+ ///
+ ///
+ ///
+ IAssemblyTypeScanner AssemblyHavingType();
+
+ ///
+ /// Adds the predicate to the assembly filter constraints.
+ ///
+ /// The assembly predicate.
+ ///
+ IAssemblyTypeScanner WithAssemblyFilter(Predicate assemblyPredicate);
+
+ ///
+ /// Adds the predicte to the include filter for .
+ ///
+ /// The predicate.
+ ///
+ IAssemblyTypeScanner WithIncludeFilter(Predicate predicate);
+
+ ///
+ /// Adds the predicte to the exclude filter for .
+ ///
+ /// The predicate.
+ ///
+ IAssemblyTypeScanner WithExcludeFilter(Predicate predicate);
+
+ ///
+ /// Includes the specific types.
+ ///
+ /// The types.
+ ///
+ IAssemblyTypeScanner IncludeTypes(IEnumerable typeSource);
+
+
+ ///
+ /// Includes the type.
+ ///
+ /// The to include.
+ ///
+ IAssemblyTypeScanner IncludeType();
+
+ ///
+ /// Excludes the type.
+ ///
+ /// The to exclude.
+ ///
+ IAssemblyTypeScanner ExcludeType();
+
+ ///
+ /// Perform the Scan, applying all provided
+ ///
+ ///
+ IEnumerable Scan();
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs
new file mode 100644
index 00000000..791f735b
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ImportAttribute.cs
@@ -0,0 +1,64 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Indicates one or more classes to import.
+ ///
+ /// Provides functionality equivalent to the <import/> element in Spring XML.
+ /// Only supported for actual -attributed classes.
+ ///
+ ///
+ /// If XML or other non- object definition resources need to be
+ /// imported, use
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class ImportAttribute : Attribute
+ {
+ private Type[] _types;
+
+ ///
+ /// Initializes a new instance of the Import class.
+ ///
+ ///
+ public ImportAttribute(params Type[] types)
+ {
+ _types = types;
+ }
+
+ ///
+ /// The class or classes to import.
+ ///
+ /// The type.
+ public Type[] Types
+ {
+ get { return _types; }
+ set
+ {
+ _types = value;
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs
new file mode 100644
index 00000000..70497763
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ImportResourceAttribute.cs
@@ -0,0 +1,99 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 Spring.Core.IO;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Util;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Supports providing one or more implementations to import when creating s.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class ImportResourceAttribute : Attribute
+ {
+ private Type _objectDefinitionReader = typeof(XmlObjectDefinitionReader);
+
+ private string[] _resources;
+
+ ///
+ /// Initializes a new instance of the ImportResourceAttribute class.
+ ///
+ ///
+ public ImportResourceAttribute(string[] resources)
+ {
+ if (resources ==null || resources.Length ==0)
+ throw new ArgumentException("resources cannot be null or empty!");
+
+ _resources = resources;
+ }
+
+
+ ///
+ /// Initializes a new instance of the ImportResourceAttribute class.
+ ///
+ ///
+ public ImportResourceAttribute(string resource)
+ {
+ if (StringUtils.IsNullOrEmpty(resource))
+ throw new ArgumentException("resource cannot be null or empty!");
+
+ _resources = new[] { resource };
+ }
+
+ ///
+ /// implementation to use when processing resources specified
+ /// by the attribute.
+ ///
+ /// The .
+ public Type DefinitionReader
+ {
+ get
+ {
+ return _objectDefinitionReader;
+ }
+ set
+ {
+ if (!((typeof(IObjectDefinitionReader).IsAssignableFrom(value))))
+ throw new ArgumentException(string.Format("DefinitionReader must be of type IObjectDefinitionReader but was of type {0}", value.Name));
+
+ _objectDefinitionReader = value;
+ }
+ }
+
+ ///
+ /// Resource paths to import. Resource-loading prefixes such as assembly:// and
+ /// file://, etc may be used.
+ ///
+ /// The resources.
+ public string[] Resources
+ {
+ get { return _resources; }
+ set
+ {
+ _resources = value;
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs
new file mode 100644
index 00000000..a15b997a
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/LazyAttribute.cs
@@ -0,0 +1,79 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Indicates whether a object is to be lazily initialized.
+ ///
+ /// If this attribute is not present on a Component or object definition, eager
+ /// initialization will occur. If present and set to true, the
+ /// object/Component will not be initialized until referenced by another object or
+ /// explicitly retrieved from the enclosing .
+ /// If present and set to false, the object will be instantiated on startup by object factories
+ /// that perform eager initialization of singletons.
+ ///
+ ///
+ /// If Lazy is present on a class, this indicates that all
+ /// methods within that should be lazily
+ /// initialized. If Lazy is present and false on a object method within a
+ /// Lazy-annotated Configuration class, this indicates overriding the 'default
+ /// lazy' behavior and that the object should be eagerly initialized.
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
+ public class LazyAttribute : Attribute
+ {
+ private bool _lazyInitialize = true;
+
+ ///
+ /// Initializes a new instance of the LazyAttribute class.
+ ///
+ ///
+ public LazyAttribute(bool lazyInitialize)
+ {
+ _lazyInitialize = lazyInitialize;
+ }
+
+ ///
+ /// Initializes a new instance of the LazyAttribute class.
+ ///
+ public LazyAttribute()
+ {
+
+ }
+
+ ///
+ /// Whether lazy initialization should occur.
+ ///
+ /// true if [lazy initialize]; otherwise, false .
+ public bool LazyInitialize
+ {
+ get { return _lazyInitialize; }
+ set
+ {
+ _lazyInitialize = value;
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/LinqExtensionMethods.cs b/src/Spring/Spring.Core/Context/Attributes/LinqExtensionMethods.cs
new file mode 100644
index 00000000..d30b0123
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/LinqExtensionMethods.cs
@@ -0,0 +1,110 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Limited extension methods reproducing the small subset of LINQ that is needed in the code; required b/c the project targets .NET 2.0 where LINQ is not available.
+ ///
+ internal static class LinqExtensionMethods
+ {
+ public static int Count(this IEnumerable source)
+ {
+ if (source == null) throw new ArgumentNullException("source");
+
+ int counter = 0;
+ foreach (TSource obj in source)
+ {
+ counter++;
+ }
+
+ return counter;
+ }
+
+ internal static bool Contains(this IEnumerable source, TSource value) where TSource : class
+ {
+ if (source == null) throw new ArgumentNullException("source");
+
+ foreach (TSource obj in source)
+ {
+ if (obj == value)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal static IEnumerable AsEnumerable(this IEnumerable source)
+ {
+ if (source == null) throw new ArgumentNullException("source");
+
+ IList results = new List();
+
+ foreach (TSource obj in source)
+ {
+ results.Add(obj);
+ }
+
+ return results;
+ }
+
+
+ internal static IEnumerable Where(this IEnumerable source,
+ Predicate predicate)
+ {
+ if (source == null) throw new ArgumentNullException("source");
+ if (predicate == null) throw new ArgumentNullException("predicate");
+
+ IList matching = new List();
+
+ foreach (TSource obj in source)
+ {
+ if (predicate(obj))
+ {
+ matching.Add(obj);
+ }
+ }
+
+ return matching;
+ }
+
+
+ internal static bool Any(this IEnumerable source, Predicate predicate)
+ {
+ if (source == null) throw new ArgumentNullException("source");
+ if (predicate == null) throw new ArgumentNullException("predicate");
+
+ foreach (TSource obj in source)
+ {
+ if (predicate(obj))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs
new file mode 100644
index 00000000..44bbaf86
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ObjectDefAttribute.cs
@@ -0,0 +1,122 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 Spring.Util;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Identifies the Method as providing and Object Definition.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ public class ObjectDefAttribute : Attribute
+ {
+ //private AutoWiringMode _autoWire = AutoWiringMode.No;
+
+ private string _destroyMethod;
+
+ private string _initMethod;
+
+ private string _names;
+
+ //TODO: constructor injection via factory methods is not presently supported by the container
+ /////
+ ///// Are dependencies to be injected via autowiring?
+ /////
+ ///// The auto wire.
+ //public AutoWiringMode AutoWire
+ //{
+ // get { return _autoWire; }
+ // set
+ // {
+ // _autoWire = value;
+ // }
+ //}
+
+ ///
+ /// The optional name of a method to call on the Object instance upon closing the
+ /// application context, for example a Close() method on a DataSource.
+ /// The method must have no arguments but may throw any exception.
+ ///
+ /// Note: Only invoked on objects whose lifecycle is under the full control of the
+ /// factory, which is always the case for singletons but not guaranteed
+ /// for any other scope.
+ ///
+ ///
+ ///
+ /// The destroy method.
+ public string DestroyMethod
+ {
+ get { return _destroyMethod; }
+ set
+ {
+ _destroyMethod = value;
+ }
+ }
+
+ ///
+ /// The optional name of a method to call on the object instance during initialization.
+ /// Not commonly used, given that the method may be called programmatically directly
+ /// within the body of a Object-annotated method.
+ ///
+ /// The init method.
+ public string InitMethod
+ {
+ get { return _initMethod; }
+ set
+ {
+ _initMethod = value;
+ }
+ }
+
+ ///
+ /// The name of this object, or if multiple, aliases for this object. If left unspecified
+ /// the name of the object is the name of the attributed method. If specified, the method
+ /// name is ignored.
+ ///
+ /// The name.
+ public string Names
+ {
+ get
+ {
+ return _names;
+ }
+ set
+ {
+ _names = value;
+ }
+ }
+
+ ///
+ /// Gets the comma-delimited list of names/aliases as an array.
+ ///
+ /// The array of names.
+ public string[] NamesToArray
+ {
+ get
+ {
+ return StringUtils.DelimitedListToStringArray(_names, ",");
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ReflectionOnlyUtils.cs b/src/Spring/Spring.Core/Context/Attributes/ReflectionOnlyUtils.cs
new file mode 100644
index 00000000..815bf61b
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ReflectionOnlyUtils.cs
@@ -0,0 +1,107 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using System.Reflection;
+using System.Security.Permissions;
+using System.Security.Policy;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// Utilities to provide support for manipulating ReflectionOnly types in the .
+ ///
+ public static class ReflectionOnlyUtils
+ {
+ ///
+ /// Load the into the ReflectionsOnly context based on its partial name.
+ ///
+ /// The partial name.
+ /// The matching
+ public static Assembly ReflectionOnlyLoadWithPartialName(string partialName)
+ {
+ return ReflectionOnlyLoadWithPartialName(partialName, null);
+ }
+
+ private static Assembly ReflectionOnlyLoadWithPartialName(string partialName, Evidence securityEvidence)
+ {
+ if (securityEvidence != null)
+ new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
+
+ AssemblyName fileName = new AssemblyName(partialName);
+
+ var assembly = nLoad(fileName, null, securityEvidence, null, null, false, true);
+
+ if (assembly != null)
+ return assembly;
+
+ var assemblyRef = EnumerateCache(fileName);
+
+ if (assemblyRef != null)
+ return InternalLoad(assemblyRef, securityEvidence, null, true);
+
+ return assembly;
+ }
+
+ private static Assembly nLoad(params object[] args)
+ {
+ return (Assembly)typeof(Assembly)
+ .GetMethod("nLoad", BindingFlags.NonPublic | BindingFlags.Static)
+ .Invoke(null, args);
+ }
+
+ private static AssemblyName EnumerateCache(params object[] args)
+ {
+ return (AssemblyName)typeof(Assembly)
+ .GetMethod("EnumerateCache", BindingFlags.NonPublic | BindingFlags.Static)
+ .Invoke(null, args);
+ }
+
+ private static Assembly InternalLoad(params object[] args)
+ {
+ // Easiest to query because the StackCrawlMark type is internal
+ /*
+ * TODO: cannot do it this way under .NET 2.0 b/c .First(...) relies on LINQ which we don't have (yet)
+ * (plan to eventually uncomment this impl once we move to .NET 3.5 or greater)
+ *
+ return (Assembly)
+ typeof(Assembly).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
+ .First(m => m.Name == "InternalLoad" &&
+ m.GetParameters()[0].ParameterType == typeof (AssemblyName))
+ .Invoke(null, args);
+ */
+ IEnumerable methods =
+ typeof(Assembly).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(
+ delegate(MethodInfo m)
+ {
+ return m.Name == "InternalLoad" &&
+ m.GetParameters()[0].ParameterType == typeof(AssemblyName);
+ });
+
+ foreach (MethodInfo methodInfo in methods)
+ {
+ return (Assembly)methodInfo.Invoke(null, args);
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs b/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs
new file mode 100644
index 00000000..bcf61b6a
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/RequiredConstraintAssemblyTypeScanner.cs
@@ -0,0 +1,54 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// AssemblyTypeScanner that provides for applying a final hard-coded Required Constraint to all types found in the the scanned assemblies
+ /// in addition to respecting the constraints passed to it during its configuration.
+ ///
+ [Serializable]
+ public abstract class RequiredConstraintAssemblyTypeScanner : AssemblyTypeScanner
+ {
+
+ ///
+ /// Determines whether the compound predicate is satisfied by the specified type.
+ ///
+ /// The type.
+ ///
+ /// true if the compound predicate is satisfied by the specified type; otherwise, false .
+ ///
+ protected override bool IsCompoundPredicateSatisfiedBy(Type type)
+ {
+ return IsRequiredConstraintSatisfiedBy(type) && IsIncludedType(type) && !IsExcludedType(type);
+ }
+
+ ///
+ /// Determines whether the required constraint is satisfied by the specified type.
+ ///
+ /// The type.
+ ///
+ /// true if the required constraint is satisfied by the specified type; otherwise, false .
+ ///
+ protected abstract bool IsRequiredConstraintSatisfiedBy(Type type);
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs b/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs
new file mode 100644
index 00000000..cdd5c80e
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ScannedGenericObjectDefinition.cs
@@ -0,0 +1,134 @@
+#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;
+using Spring.Objects;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Stereotype;
+using Spring.Objects.Factory.Attributes;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// A GenericObjectDefinition that provides attribute driven propulation
+ /// of properties like LazyInit, Scope or Qualifier
+ ///
+ public class ScannedGenericObjectDefinition : GenericObjectDefinition
+ {
+ ///
+ /// Name provided by the Component Attribute
+ ///
+ private string _componentName;
+
+ ///
+ /// Creates a GenericObjectDefinition that applies the default values provided
+ /// in the XML Spring config document. Additionally parses the specific class
+ /// attributesthat allows the definition of LazyInit, Scope or Qualifier
+ ///
+ /// Type of scanned component
+ /// Defualts provided in Spring Config document
+ public ScannedGenericObjectDefinition(Type typeOfObject, DocumentDefaultsDefinition defaults)
+ {
+ ObjectType = typeOfObject;
+
+ ParseName();
+ ApplyDefaults(defaults);
+ ParseScopeAttribute();
+ ParseLazyAttribute();
+ ParseQualifierAttribute();
+ }
+
+ private void ParseName()
+ {
+ var attr = Attribute.GetCustomAttribute(ObjectType, typeof (ComponentAttribute), true) as ComponentAttribute;
+ if (attr != null && !string.IsNullOrEmpty(attr.Name))
+ _componentName = attr.Name;
+ }
+
+ private void ApplyDefaults(DocumentDefaultsDefinition defaults)
+ {
+ if (defaults == null)
+ return;
+
+ bool lazyInit = false;
+ bool.TryParse(defaults.LazyInit, out lazyInit);
+ IsLazyInit = lazyInit;
+ }
+
+ private void ParseScopeAttribute()
+ {
+ var attr = Attribute.GetCustomAttribute(ObjectType, typeof(ScopeAttribute), true) as ScopeAttribute;
+ if (attr != null)
+ Scope = attr.ObjectScope.ToString().ToLower();
+ }
+
+ private void ParseLazyAttribute()
+ {
+ var attr = Attribute.GetCustomAttribute(ObjectType, typeof(LazyAttribute), true) as LazyAttribute;
+ if (attr != null)
+ IsLazyInit = attr.LazyInitialize;
+ }
+
+ private void ParseQualifierAttribute()
+ {
+ var attr = Attribute.GetCustomAttribute(ObjectType, typeof(QualifierAttribute), true) as QualifierAttribute;
+ if (attr != null)
+ {
+ var qualifier = new AutowireCandidateQualifier(attr.GetType());
+
+ if (!string.IsNullOrEmpty(attr.Value))
+ qualifier.SetAttribute(AutowireCandidateQualifier.VALUE_KEY, attr.Value);
+
+ ParseQualifierProperties(attr, qualifier);
+
+ AddQualifier(qualifier);
+ }
+ }
+
+ private void ParseQualifierProperties(QualifierAttribute attr, AutowireCandidateQualifier qualifier)
+ {
+ foreach (var property in attr.GetType().GetProperties())
+ {
+ if (!property.Name.Equals("TypeId") && !property.Name.Equals("Value"))
+ {
+ object value = property.GetValue(attr, null);
+ if (value != null)
+ {
+ var attribute = new ObjectMetadataAttribute(property.Name, value);
+ qualifier.AddMetadataAttribute(attribute);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Provides the name of the object scanned
+ ///
+ /// return the provided attribute name of the full object type name
+ public string ComponentName
+ {
+ get
+ {
+ return _componentName;
+ }
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs b/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs
new file mode 100644
index 00000000..3cb343da
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/ScopeAttribute.cs
@@ -0,0 +1,66 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes
+{
+ ///
+ /// When used as a type-level attribute, indicates the name of a scope to use
+ /// for instances of the attributed type.
+ ///
+ /// When used as a method-level attribute in conjunction with the
+ /// attribute, indicates the name of a scope to use for
+ /// the instance returned from the method.
+ ///
+ /// In this context, scope means the lifecycle of an instance, such as
+ /// singleton, prototype, and so forth.
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+ public class ScopeAttribute : Attribute
+ {
+ private ObjectScope _scope = ObjectScope.Singleton;
+
+ ///
+ /// Initializes a new instance of the Scope class.
+ ///
+ ///
+ public ScopeAttribute(ObjectScope scope)
+ {
+ _scope = scope;
+ }
+
+ ///
+ /// Specifies the scope to use for the annotated object.
+ ///
+ /// The scope.
+ public ObjectScope ObjectScope
+ {
+ get { return _scope; }
+ set
+ {
+ _scope = value;
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs
new file mode 100644
index 00000000..b0a17c59
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AbstractLoadTypeFilter.cs
@@ -0,0 +1,66 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 Spring.Core.TypeResolution;
+using Common.Logging;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+ ///
+ /// Abstract Type Filter that provides methods to load a required type from assembly.
+ ///
+ public abstract class AbstractLoadTypeFilter : ITypeFilter
+ {
+ private static readonly ILog Logger = LogManager.GetLogger();
+
+
+ ///
+ /// Required Type to compare against provided Type
+ ///
+ protected Type RequiredType;
+
+
+ ///
+ /// Determine a match based on the given type object.
+ ///
+ ///
+ /// true if there is a match; false is there is no match
+ public abstract bool Match(Type type);
+
+
+ ///
+ /// Is loading a Type from a string passed to method in the form [Type.FullName], [Assembly.Name]
+ ///
+ protected void GetRequiredType(string typeToLoad)
+ {
+ try
+ {
+ RequiredType = TypeResolutionUtils.ResolveType(typeToLoad);
+ }
+ catch (Exception)
+ {
+ RequiredType = null;
+ Logger.Error("Can't load type defined in exoression:" + typeToLoad);
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs
new file mode 100644
index 00000000..26919208
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AssignableTypeFilter.cs
@@ -0,0 +1,55 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+
+ ///
+ /// A simple filter which matches classes that are assignable to a given type.
+ ///
+ public class AssignableTypeFilter : AbstractLoadTypeFilter
+ {
+
+ ///
+ /// Create a Type Filter with required type
+ ///
+ /// type name including assembly name
+ public AssignableTypeFilter(string expression)
+ {
+ GetRequiredType(expression);
+ }
+
+ ///
+ /// Determine a match based on the given type object.
+ ///
+ /// Type to compare against
+ /// true if there is a match; false is there is no match
+ public override bool Match(Type type)
+ {
+ if (RequiredType == null)
+ return false;
+
+ return (type.GetInterfaces().Any(i => i.Equals(RequiredType)) || RequiredType.Equals(type.BaseType));
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs
new file mode 100644
index 00000000..22ad4642
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/AttributeTypeFilter.cs
@@ -0,0 +1,56 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+
+ ///
+ /// A simple filter which matches classes with a given attribute,
+ /// checking inherited annotations as well.
+ ///
+ public class AttributeTypeFilter : AbstractLoadTypeFilter
+ {
+
+ ///
+ /// Creates a Type Filter with required type attribute
+ ///
+ ///
+ public AttributeTypeFilter(string expression)
+ {
+ GetRequiredType(expression);
+ }
+
+ ///
+ /// Determine a match based on the given type object.
+ ///
+ /// Type to compare against
+ /// true if there is a match; false is there is no match
+ public override bool Match(Type type)
+ {
+ if (RequiredType == null)
+ return false;
+
+ return (Attribute.GetCustomAttribute(type, RequiredType) != null);
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs
new file mode 100644
index 00000000..45f7bc14
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/CustomTypeFactory.cs
@@ -0,0 +1,91 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 Common.Logging;
+using Spring.Core.TypeResolution;
+using Spring.Util;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+ ///
+ /// Creates a new instance of a givin type string
+ ///
+ public static class CustomTypeFactory
+ {
+ private static readonly ILog Logger = LogManager.GetLogger(typeof(CustomTypeFactory).FullName);
+
+ ///
+ /// Creates a new instance of given type filter type string
+ ///
+ /// Custom type filter to create
+ /// An instance of ITypeFilter or NULL if no instance can be created
+ public static ITypeFilter GetTypeFilter(string expression)
+ {
+ return GetCustomType(expression) as ITypeFilter;
+ }
+
+
+ ///
+ /// Creates a new instance of given name generator type string
+ ///
+ /// Custom type name generator string to create
+ /// An instance of IObjectNameGenerator or NULL if no instance can be created
+ public static IObjectNameGenerator GetNameGenerator(string expression)
+ {
+ return GetCustomType(expression) as IObjectNameGenerator;
+ }
+
+ private static object GetCustomType(string expression)
+ {
+ var customTypeFilterType = LoadType(expression);
+ if (customTypeFilterType == null)
+ return null;
+
+ try
+ {
+ var instance = ObjectUtils.InstantiateType(customTypeFilterType);
+ return instance;
+ }
+ catch
+ {
+ Logger.Error(string.Format("Can't instatiate {0}. Type needs to have a non arg constructor.", expression));
+ }
+
+ return null;
+ }
+
+
+ private static Type LoadType(string typeToLoad)
+ {
+ try
+ {
+ return TypeResolutionUtils.ResolveType(typeToLoad);
+ }
+ catch (Exception)
+ {
+ Logger.Error("Can't load type defined in exoression:" + typeToLoad);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs
new file mode 100644
index 00000000..58294a61
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/ITypeFilter.cs
@@ -0,0 +1,37 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+ ///
+ /// Represents the base interface for all component-scan type filters
+ ///
+ public interface ITypeFilter
+ {
+ ///
+ /// Determine a match based on the given type object.
+ ///
+ ///
+ /// true if there is a match; false is there is no match
+ bool Match(Type type);
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs
new file mode 100644
index 00000000..f4e5468b
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Attributes/TypeFilters/RegexPatternTypeFilter.cs
@@ -0,0 +1,53 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Text.RegularExpressions;
+
+namespace Spring.Context.Attributes.TypeFilters
+{
+ ///
+ /// A simple filter for matching a fully-qualified class name with a regex
+ ///
+ public class RegexPatternTypeFilter : ITypeFilter
+ {
+ private string _pattern;
+
+
+ ///
+ /// Creates a type filter with provided pattern
+ ///
+ /// Regex pattern
+ public RegexPatternTypeFilter(string pattern)
+ {
+ _pattern = pattern;
+ }
+
+ ///
+ /// Determine a match based on the given type object.
+ ///
+ /// Type to compare against
+ /// true if there is a match; false is there is no match
+ public bool Match(Type type)
+ {
+ return Regex.IsMatch(type.FullName, _pattern);
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs b/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs
new file mode 100644
index 00000000..e73eae91
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Config/AttributeConfigObjectDefinitionParser.cs
@@ -0,0 +1,61 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Xml;
+using Spring.Context.Attributes;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Util;
+
+namespace Spring.Context.Config
+{
+ ///
+ /// Object Defintion Parser for interpreting classes when primary configuration is peformed via XML.
+ ///
+ public class AttributeConfigObjectDefinitionParser : IObjectDefinitionParser
+ {
+ ///
+ /// Parse the specified XmlElement and register the resulting
+ /// ObjectDefinitions with the IObjectDefinitionRegistry
+ /// embedded in the supplied
+ ///
+ /// The element to be parsed.
+ /// TThe object encapsulating the current state of the parsing process.
+ /// Provides access to a IObjectDefinitionRegistry
+ /// The primary object definition.
+ ///
+ ///
+ /// This method is never invoked if the parser is namespace aware
+ /// and was called to process the root node.
+ ///
+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+ IObjectDefinitionRegistry registry = parserContext.ReaderContext.Registry;
+ AssertUtils.ArgumentNotNull(registry, "registry");
+
+ AttributeConfigUtils.RegisterAttributeConfigProcessors(registry);
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs b/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs
new file mode 100644
index 00000000..e63bae82
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Config/ComponentScanObjectDefinitionParser.cs
@@ -0,0 +1,159 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.ComponentModel;
+using System.Xml;
+using Common.Logging;
+using Spring.Context.Attributes;
+using Spring.Context.Attributes.TypeFilters;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Config
+{
+ ///
+ /// Parses ObjectDefinitions from classes identified by an .
+ ///
+ public class ComponentScanObjectDefinitionParser : IObjectDefinitionParser
+ {
+ private static readonly ILog Logger = LogManager.GetLogger();
+
+ private const string ATTRIBUTE_CONFIG_ATTRIBUTE = "attribute-config";
+
+ private const string NAME_GENERATOR_ATTRIBUTE = "name-generator";
+
+ private const string BASE_ASSEMBLIES_ATTRIBUTE = "base-assemblies";
+
+ private const string EXCLUDE_FILTER_ELEMENT = "exclude-filter";
+
+ private const string INCLUDE_FILTER_ELEMENT = "include-filter";
+
+
+ ///
+ /// Parse the specified XmlElement and register the resulting
+ /// ObjectDefinitions with the IObjectDefinitionRegistry
+ /// embedded in the supplied
+ ///
+ /// The element to be parsed.
+ /// TThe object encapsulating the current state of the parsing process.
+ /// Provides access to a IObjectDefinitionRegistry
+ /// The primary object definition.
+ ///
+ ///
+ /// This method is never invoked if the parser is namespace aware
+ /// and was called to process the root node.
+ ///
+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+ AssemblyObjectDefinitionScanner scanner = ConfigureScanner(parserContext, element);
+ IObjectDefinitionRegistry registry = parserContext.Registry;
+
+ // Actually scan for objects definitions and register them.
+ scanner.ScanAndRegisterTypes(registry);
+ RegisterComponents(element, registry);
+
+ return null;
+ }
+
+ ///
+ /// Configures the scanner.
+ ///
+ /// The parser context.
+ /// The element.
+ ///
+ protected virtual AssemblyObjectDefinitionScanner ConfigureScanner(ParserContext parserContext, XmlElement element)
+ {
+ var scanner = new AssemblyObjectDefinitionScanner();
+
+ ParseBaseAssembliesAttribute(scanner, element);
+ ParseNameGeneratorAttribute(scanner, element);
+ ParseTypeFilters(scanner, element);
+
+ scanner.Defaults = parserContext.ParserHelper.Defaults;
+
+ return scanner;
+ }
+
+ private void ParseBaseAssembliesAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element)
+ {
+ var baseAssemblies = element.GetAttribute(BASE_ASSEMBLIES_ATTRIBUTE);
+
+ if (string.IsNullOrEmpty(baseAssemblies))
+ return;
+
+ foreach (var baseAssembly in baseAssemblies.Split(','))
+ {
+ scanner.WithAssemblyFilter(assy => assy.FullName.StartsWith(baseAssembly));
+ }
+ }
+
+ private void ParseNameGeneratorAttribute(AssemblyObjectDefinitionScanner scanner, XmlElement element)
+ {
+ var nameGeneratorString = element.GetAttribute(NAME_GENERATOR_ATTRIBUTE);
+ var nameGenerator = CustomTypeFactory.GetNameGenerator(nameGeneratorString);
+ if (nameGenerator != null)
+ scanner.ObjectNameGenerator = nameGenerator;
+ }
+
+ private void ParseTypeFilters(AssemblyObjectDefinitionScanner scanner, XmlElement element)
+ {
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ if (node.Name.Contains(INCLUDE_FILTER_ELEMENT))
+ scanner.WithIncludeFilter(CreateTypeFilter(node));
+ else if (node.Name.Contains(EXCLUDE_FILTER_ELEMENT))
+ scanner.WithExcludeFilter(CreateTypeFilter(node));
+ }
+ }
+
+ private void RegisterComponents(XmlElement element, IObjectDefinitionRegistry registry)
+ {
+ bool attributeConfig = true;
+ var attr = element.GetAttribute(ATTRIBUTE_CONFIG_ATTRIBUTE);
+ if (attr != null)
+ bool.TryParse(attr, out attributeConfig);
+ if (attributeConfig)
+ AttributeConfigUtils.RegisterAttributeConfigProcessors(registry);
+ }
+
+ private ITypeFilter CreateTypeFilter(XmlNode node)
+ {
+ var type = node.Attributes["type"].Value;
+ var expression = node.Attributes["expression"].Value;
+
+ switch (type)
+ {
+ case "regex":
+ return new RegexPatternTypeFilter(expression);
+ case "attribute":
+ return new AttributeTypeFilter(expression);
+ case "assignable":
+ return new AssignableTypeFilter(expression);
+ case "custom":
+ return CustomTypeFactory.GetTypeFilter(expression);
+ default:
+ throw new InvalidEnumArgumentException(string.Format("Filter type {0} is not defined", type));
+ }
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs b/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs
new file mode 100644
index 00000000..37fd3592
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Config/ContextNamespaceParser.cs
@@ -0,0 +1,55 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Objects.Factory.Xml;
+
+namespace Spring.Context.Config
+{
+ ///
+ /// NamespaceParser allowing for the configuration of
+ /// declarative transaction management using either XML or using attributes.
+ /// This namespace handler is the central piece of functionality in the
+ /// Spring transaction management facilities and offers two appraoches
+ /// to declaratively manage transactions.
+ /// One approach uses transaction semantics defined in XML using the
+ /// <tx:advice> elements, the other uses attributes
+ /// in combination with the <tx:annotation-driven> element.
+ /// Both approached are detailed in the Spring reference manual.
+ ///
+ [
+ NamespaceParser(
+ Namespace = "http://www.springframework.net/context",
+ SchemaLocationAssemblyHint = typeof(ContextNamespaceParser),
+ SchemaLocation = "/Spring.Context.Config/spring-context-2.0.xsd"
+ )
+ ]
+ public class ContextNamespaceParser : NamespaceParserSupport
+ {
+ ///
+ /// Register the for the 'advice' and
+ /// 'attribute-driven' tags.
+ ///
+ public override void Init()
+ {
+ RegisterObjectDefinitionParser("attribute-config", new AttributeConfigObjectDefinitionParser());
+ RegisterObjectDefinitionParser("component-scan", new ComponentScanObjectDefinitionParser());
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd b/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd
new file mode 100644
index 00000000..a74947a8
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Config/spring-context-1.3.xsd
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd b/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd
new file mode 100644
index 00000000..cd35a59a
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Config/spring-context-2.0.xsd
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tag for that purpose.
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs b/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs
new file mode 100644
index 00000000..99c5789e
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Extension/GenericApplicationContextExtensions.cs
@@ -0,0 +1,110 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Reflection;
+using Spring.Context.Attributes;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Support
+{
+ ///
+ /// Extensions to enable scanning on any AbstractApplicationContext-derived type.
+ ///
+ public static class GenericApplicationContextExtensions
+ {
+ ///
+ /// Scans for types using the provided scanner.
+ ///
+ /// The context.
+ /// The scanner.
+ public static void Scan(this GenericApplicationContext context, AssemblyObjectDefinitionScanner scanner)
+ {
+ var registry = context.ObjectFactory as IObjectDefinitionRegistry;
+ scanner.ScanAndRegisterTypes(registry);
+
+ AttributeConfigUtils.RegisterAttributeConfigProcessors(registry);
+ }
+
+ ///
+ /// Scans for types that satisfy specified predicates located in the specified scan path.
+ ///
+ /// The context.
+ /// The assembly scan path.
+ /// The assembly predicate.
+ /// The type predicate.
+ public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Predicate assemblyPredicate,
+ Predicate typePredicate)
+ {
+ //create a scanner instance using the scan path
+ var scanner = new AssemblyObjectDefinitionScanner();
+
+ //configure the scanner per the provided constraints
+ scanner.WithAssemblyFilter(assemblyPredicate).WithIncludeFilter(typePredicate);
+
+ //pass the scanner to primary Scan method to actually do the work
+ Scan(context, scanner);
+ }
+
+ ///
+ /// Scans for types that satisfy specified predicates.
+ ///
+ /// The context.
+ /// The assembly predicate.
+ /// The type predicate.
+ public static void Scan(this GenericApplicationContext context, Predicate assemblyPredicate, Predicate typePredicate)
+ {
+ Scan(context, null, assemblyPredicate, typePredicate);
+ }
+
+ ///
+ /// Scans for types using the default scanner.
+ ///
+ /// The context.
+ public static void ScanAllAssemblies(this GenericApplicationContext context)
+ {
+ Scan(context, new AssemblyObjectDefinitionScanner());
+ }
+
+
+ ///
+ /// Scans the with assembly filter.
+ ///
+ /// The context.
+ /// The assembly predicate.
+ public static void ScanWithAssemblyFilter(this GenericApplicationContext context, Predicate assemblyPredicate)
+ {
+ Scan(context, null, assemblyPredicate, delegate { return true; });
+ }
+
+ ///
+ /// Scans the with type filter.
+ ///
+ /// The context.
+ /// The type predicate.
+ public static void ScanWithTypeFilter(this GenericApplicationContext context, Predicate typePredicate)
+ {
+ Scan(context, null, delegate { return true; }, typePredicate);
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs
new file mode 100644
index 00000000..633909bf
--- /dev/null
+++ b/src/Spring/Spring.Core/Context/Support/CodeConfigApplicationContext.cs
@@ -0,0 +1,92 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Objects.Factory.Support;
+
+namespace Spring.Context.Support
+{
+ ///
+ /// ApplicationContext that can scan to identify object definitions
+ ///
+ public class CodeConfigApplicationContext : GenericApplicationContext
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CodeConfigApplicationContext()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true names in the context are case sensitive.
+ public CodeConfigApplicationContext(bool caseSensitive)
+ : base(caseSensitive)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object factory instance to use for this context.
+ public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory)
+ : base(objectFactory)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The parent application context.
+ public CodeConfigApplicationContext(IApplicationContext parent)
+ : base(parent)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the application context. if set to true names in the context are case sensitive. The parent application context.
+ public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent)
+ : base(name, caseSensitive, parent)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object factory to use for this context The parent applicaiton context.
+ public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent)
+ : base(objectFactory, parent)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the application context. if set to true names in the context are case sensitive. The parent application context. The object factory to use for this context
+ public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent,
+ DefaultListableObjectFactory objectFactory)
+ : base(name, caseSensitive, parent, objectFactory)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Spring.Core.2010.csproj b/src/Spring/Spring.Core/Spring.Core.2010.csproj
index ac306901..2e67ede7 100644
--- a/src/Spring/Spring.Core/Spring.Core.2010.csproj
+++ b/src/Spring/Spring.Core/Spring.Core.2010.csproj
@@ -177,6 +177,39 @@
Code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Code
@@ -186,6 +219,7 @@
Code
+
Code
@@ -234,6 +268,7 @@
Code
+
Code
@@ -1239,6 +1274,12 @@
Code
+
+ Designer
+
+
+ Designer
+
diff --git a/src/Spring/Spring.Web.Conversation.NHibernate32/Spring.Web.Conversation.NHibernate32.xml b/src/Spring/Spring.Web.Conversation.NHibernate32/Spring.Web.Conversation.NHibernate32.xml
index 953538d6..6666fa98 100644
--- a/src/Spring/Spring.Web.Conversation.NHibernate32/Spring.Web.Conversation.NHibernate32.xml
+++ b/src/Spring/Spring.Web.Conversation.NHibernate32/Spring.Web.Conversation.NHibernate32.xml
@@ -128,62 +128,6 @@
Create a new session on demand
-
-
- Setting for
-
- Hailton de Castro
-
-
-
- Default value for property.
-
-
-
-
- Initialize a new instance of with default values.
-
-
- Calling this constructor from your derived class leaves
- uninitialized. See for more.
-
-
-
-
- Initialize a new instance of with the given values and references.
-
-
- Specify the to be set on each session provided by the instance.
-
-
- Specify the flushmode to be applied on each session provided by the instance.
-
-
- Calling this constructor marks all properties initialized.
-
-
-
-
- Override this method to resolve an instance according to your chosen strategy.
-
-
-
-
- Gets the configured instance to be used.
-
-
-
-
-
-
- Gets or Sets the flushmode to be applied on each newly created session.
-
-
- This property defaults to to ensure that modifying objects outside the boundaries
- of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation
- within a transaction.
-
-
Port to conversation. If the object is not found in the current
@@ -867,6 +811,62 @@
Returns the current context. Supports serialization and deserialization.
+
+
+ Setting for
+
+ Hailton de Castro
+
+
+
+ Default value for property.
+
+
+
+
+ Initialize a new instance of with default values.
+
+
+ Calling this constructor from your derived class leaves
+ uninitialized. See for more.
+
+
+
+
+ Initialize a new instance of with the given values and references.
+
+
+ Specify the to be set on each session provided by the instance.
+
+
+ Specify the flushmode to be applied on each session provided by the instance.
+
+
+ Calling this constructor marks all properties initialized.
+
+
+
+
+ Override this method to resolve an instance according to your chosen strategy.
+
+
+
+
+ Gets the configured instance to be used.
+
+
+
+
+
+
+ Gets or Sets the flushmode to be applied on each newly created session.
+
+
+ This property defaults to to ensure that modifying objects outside the boundaries
+ of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation
+ within a transaction.
+
+
This was made to stay under session scope.
diff --git a/src/Spring/Spring.Web.Conversation.NHibernate33/Spring.Web.Conversation.NHibernate33.XML b/src/Spring/Spring.Web.Conversation.NHibernate33/Spring.Web.Conversation.NHibernate33.XML
index 3e824e7c..39b80a8c 100644
--- a/src/Spring/Spring.Web.Conversation.NHibernate33/Spring.Web.Conversation.NHibernate33.XML
+++ b/src/Spring/Spring.Web.Conversation.NHibernate33/Spring.Web.Conversation.NHibernate33.XML
@@ -128,146 +128,6 @@
Create a new session on demand
-
-
- Setting for
-
- Hailton de Castro
-
-
-
- Default value for property.
-
-
-
-
- Initialize a new instance of with default values.
-
-
- Calling this constructor from your derived class leaves
- uninitialized. See for more.
-
-
-
-
- Initialize a new instance of with the given values and references.
-
-
- Specify the to be set on each session provided by the instance.
-
-
- Specify the flushmode to be applied on each session provided by the instance.
-
-
- Calling this constructor marks all properties initialized.
-
-
-
-
- Override this method to resolve an instance according to your chosen strategy.
-
-
-
-
- Gets the configured instance to be used.
-
-
-
-
-
-
- Gets or Sets the flushmode to be applied on each newly created session.
-
-
- This property defaults to to ensure that modifying objects outside the boundaries
- of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation
- within a transaction.
-
-
-
-
- manager for Conversations.
-
- Hailton de Castro
-
-
-
- Returns the conversation if it is still alive, otherwise it returns null.
-
-
-
-
-
-
- Ends all conversations with the timeout exceeded.
-
-
-
-
- Close IDbConnections for that
- use 'session-per-conversation'. It calls
- in all conversations.
-
-
-
-
- Release the ended conversations And removes them.
- If the conversation supports 'session-per-conversation', also close the session.
-
-
-
-
- Add conversation. If is null
- it resolves to 'this'.
-
-
-
- If already has another manager.
-
-
-
-
- Makes the 'root conversation' of
- the current active conversation and open/reopen the
- if
- the conversation supports 'session-per-conversation'. Close all
- the connection for all session before.
- If is true will end all
- paused conversations.
-
-
-
-
- Returns the active conversation if exists, otherwise returns null.
- It depends on
-
-
-
-
-
- If this is non-null run pattern 'session-per-conversation'.
- Must be the same SessionFactory of the managed conversations.
-
-
-
-
-
- Ends the "paused conversations" in call to .
- Important: Unexpected behavior may occur if there are nested conversations,
- as in only the current conversation and its parents
- are started, the 'conversations children' remain paused, so these will be ended.
- Defaul value: false .
-
-
- When it is true, "start/resume a conversation" will cause the other to be
- ended and cleaned up.
-
- This is useful to avoid memory leak where there are many conversations.
- This leak can be very considerable, as the conversation may keep a "NHibernate session"
- that can contain many objects in its cache from the database queries.
-
-
-
Port to conversation. If the object is not found in the current
@@ -423,6 +283,151 @@
Indicates that the conversation is paused.
+
+
+ manager for Conversations.
+
+ Hailton de Castro
+
+
+
+ Returns the conversation if it is still alive, otherwise it returns null.
+
+
+
+
+
+
+ Ends all conversations with the timeout exceeded.
+
+
+
+
+ Close IDbConnections for that
+ use 'session-per-conversation'. It calls
+ in all conversations.
+
+
+
+
+ Release the ended conversations And removes them.
+ If the conversation supports 'session-per-conversation', also close the session.
+
+
+
+
+ Add conversation. If is null
+ it resolves to 'this'.
+
+
+
+ If already has another manager.
+
+
+
+
+ Makes the 'root conversation' of
+ the current active conversation and open/reopen the
+ if
+ the conversation supports 'session-per-conversation'. Close all
+ the connection for all session before.
+ If is true will end all
+ paused conversations.
+
+
+
+
+ Returns the active conversation if exists, otherwise returns null.
+ It depends on
+
+
+
+
+
+ If this is non-null run pattern 'session-per-conversation'.
+ Must be the same SessionFactory of the managed conversations.
+
+
+
+
+
+ Ends the "paused conversations" in call to .
+ Important: Unexpected behavior may occur if there are nested conversations,
+ as in only the current conversation and its parents
+ are started, the 'conversations children' remain paused, so these will be ended.
+ Defaul value: false .
+
+
+ When it is true, "start/resume a conversation" will cause the other to be
+ ended and cleaned up.
+
+ This is useful to avoid memory leak where there are many conversations.
+ This leak can be very considerable, as the conversation may keep a "NHibernate session"
+ that can contain many objects in its cache from the database queries.
+
+
+
+
+
+ HttpModule for ending Conversations with Timeout exceeded.
+
+ Hailton de Castro
+
+
+
+ Add PostRequestHandlerExecute event to clear conversations with timeout exceeded.
+
+
+
+
+
+ Disposes of the resources (other than memory) used by the module that implements .
+
+
+
+
+ Handles the Unload event of the page control.
+
+ The source of the event.
+ The instance containing the event data.
+
+ Necessary for Redirect or Abort for any reason.
+
+
+
+
+ The Names of the s in the
+
+
+
+
+ Sets the that this
+ object runs in.
+
+
+
+
+ Used to obtain the instances of
+
+
+ Invoked after population of normal object properties but before an
+ init callback such as
+ 's
+
+ or a custom init-method. Invoked after the setting of any
+ 's
+
+ property.
+
+
+
+ In the case of application context initialization errors.
+
+
+ If thrown by any application context methods.
+
+
+
List that make validation for Circular Dependency for
@@ -590,93 +595,6 @@
-
-
- This was made to stay under session scope.
-
- Hailton de Castro
-
-
-
- Semaphore to synchronize writes to the dictionary.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Ends all conversations and Closes all their Session.
-
-
-
-
- Remove conversation.
-
-
-
-
-
-
-
-
-
-
- "SessionFactory" name in the current context.
- This approach is required to support serialization.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Returns the current context. Supports serialization and deserialization.
-
-
Implementation of conversation in the infrastructure of Spring.
@@ -893,66 +811,148 @@
Returns the current context. Supports serialization and deserialization.
-
+
- HttpModule for ending Conversations with Timeout exceeded.
+ Setting for
Hailton de Castro
-
+
- Add PostRequestHandlerExecute event to clear conversations with timeout exceeded.
-
-
-
-
-
- Disposes of the resources (other than memory) used by the module that implements .
+ Default value for property.
-
+
- Handles the Unload event of the page control.
+ Initialize a new instance of with default values.
- The source of the event.
- The instance containing the event data.
- Necessary for Redirect or Abort for any reason.
+ Calling this constructor from your derived class leaves
+ uninitialized. See for more.
-
+
- The Names of the s in the
+ Initialize a new instance of with the given values and references.
+
+
+ Specify the to be set on each session provided by the instance.
+
+
+ Specify the flushmode to be applied on each session provided by the instance.
+
+
+ Calling this constructor marks all properties initialized.
+
+
+
+
+ Override this method to resolve an instance according to your chosen strategy.
-
+
- Sets the that this
- object runs in.
+ Gets the configured instance to be used.
-
-
- Used to obtain the instances of
-
-
- Invoked after population of normal object properties but before an
- init callback such as
- 's
-
- or a custom init-method. Invoked after the setting of any
- 's
-
- property.
-
-
- In the case of application context initialization errors.
-
-
- If thrown by any application context methods.
-
-
+
+
+
+ Gets or Sets the flushmode to be applied on each newly created session.
+
+
+ This property defaults to to ensure that modifying objects outside the boundaries
+ of a transaction will not be persisted. It is recommended to not change this value but wrap any modifying operation
+ within a transaction.
+
+
+
+
+ This was made to stay under session scope.
+
+ Hailton de Castro
+
+
+
+ Semaphore to synchronize writes to the dictionary.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ends all conversations and Closes all their Session.
+
+
+
+
+ Remove conversation.
+
+
+
+
+
+
+
+
+
+
+ "SessionFactory" name in the current context.
+ This approach is required to support serialization.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Returns the current context. Supports serialization and deserialization.
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs
new file mode 100644
index 00000000..240d731b
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AbstractConfigurationClassPostProcessorTests.cs
@@ -0,0 +1,354 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Attributes
+{
+
+ public abstract class AbstractConfigurationClassPostProcessorTests
+ {
+ protected AbstractApplicationContext _ctx;
+
+ [SetUp]
+ public void _SetUp()
+ {
+ SingletonParent.InstanceCount = 0;
+ SingletonChild.InstanceCount = 0;
+ PrototypeParent.InstanceCount = 0;
+ PrototypeChild.InstanceCount = 0;
+ CreateApplicationContext();
+ }
+
+
+ protected abstract void CreateApplicationContext();
+
+
+ [Test]
+ public void Can_Assign_Init_And_Destroy_Methods()
+ {
+ IObjectDefinition def = _ctx.GetObjectDefinition(typeof(ObjectWithInitAndDestroyMethods).Name);
+
+ Assert.That(def, Is.Not.Null);
+ Assert.That(def.InitMethodName, Is.EqualTo("CallToInit"));
+ Assert.That(def.DestroyMethodName, Is.EqualTo("CallToDestroy"));
+ }
+
+ [Test]
+ public void Can_Import_Configurations_From_Additional_Classes()
+ {
+ Assert.That(_ctx.GetObject(typeof(AnImportedType).Name), Is.Not.Null);
+ }
+
+ [Test]
+ public void Can_Respect_Assigned_Aliases()
+ {
+ var firstObject = _ctx["TheFirstAlias"];
+ var secondObject = _ctx["TheSecondAlias"];
+ Assert.That(firstObject, Is.InstanceOf());
+ Assert.That(secondObject, Is.InstanceOf());
+ }
+
+ [Test]
+ public void Can_Respect_Assigned_Name()
+ {
+ var result = _ctx["TheName"];
+ Assert.That(result, Is.InstanceOf());
+ }
+
+ [Test]
+ public void Can_Respect_Default_Singleton_Scope()
+ {
+ var firstObject = (SingletonChild)_ctx[typeof(SingletonChild).Name];
+ var secondObject = (SingletonChild)_ctx[typeof(SingletonChild).Name];
+
+ Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1));
+ Assert.That(firstObject, Is.SameAs(secondObject));
+ }
+
+ [Test]
+ public void Can_Respect_Default_Singleton_Scope_With_Explicit_Prototype_Dependency()
+ {
+ var firstObject = (SingletonParent)_ctx[typeof(SingletonParent).Name];
+ var secondObject = (SingletonParent)_ctx[typeof(SingletonParent).Name];
+
+ Assert.That(SingletonParent.InstanceCount, Is.EqualTo(1));
+ //Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(2)); // Requires scoped proxies
+ Assert.That(firstObject, Is.SameAs(secondObject));
+ }
+
+ [Test]
+ public void Can_Respect_Explicit_Prototype_Scope()
+ {
+ var firstObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name];
+ var secondObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name];
+
+ Assert.That(PrototypeChild.InstanceCount, Is.EqualTo(3)); // One instance used by SingletonParent
+ Assert.That(firstObject, Is.Not.SameAs(secondObject));
+ }
+
+ [Test]
+ public void Can_Respect_Explicit_Prototype_Scope_With_Default_Singleton_Dependency()
+ {
+ var firstObject = (PrototypeParent)_ctx[typeof(PrototypeParent).Name];
+ var secondObject = (PrototypeParent)_ctx[typeof(PrototypeParent).Name];
+
+ Assert.That(PrototypeParent.InstanceCount, Is.EqualTo(2));
+ Assert.That(SingletonChild.InstanceCount, Is.EqualTo(1));
+ Assert.That(firstObject, Is.Not.SameAs(secondObject));
+ }
+
+ [Test]
+ public void Can_Respect_Lazy_Attribute()
+ {
+ Assert.That(_ctx.GetObjectDefinition(typeof(ImplicitLazyInitObject).Name).IsLazyInit, Is.True);
+ Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitLazyInitObject).Name).IsLazyInit, Is.True);
+ Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitNonLazyInitObject).Name).IsLazyInit, Is.False);
+ }
+
+ [Test]
+ public void Can_Retreive_Actual_Objects_From_Context()
+ {
+ Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf());
+ Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf());
+ }
+
+ [Test]
+ public void Can_Satisfy_Dependencies_Of_Objects()
+ {
+ Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null);
+ }
+
+
+ [Test]
+ public void Can_Respect_Imported_Resources()
+ {
+ Assert.That(_ctx["xmlRegisteredObject"], Is.Not.Null);
+ }
+ }
+
+ public class ObjectWithInitAndDestroyMethods
+ {
+ public void CallToDestroy() { }
+ public void CallToInit() { }
+ }
+
+
+
+
+ [Configuration]
+ [ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitions.xml", DefinitionReader = typeof(XmlObjectDefinitionReader))]
+ [ImportResource("assembly://Spring.Core.Tests/Spring.Context.Attributes/ObjectDefinitionsTwo.xml")]
+ public class TheImportedConfigurationClass
+ {
+ [ObjectDef]
+ public virtual AnImportedType AnImportedType()
+ {
+ return new AnImportedType();
+ }
+ }
+
+ [Configuration]
+ [Import(typeof(TheImportedConfigurationClass))]
+ public class TheConfigurationClass
+ {
+ [ObjectDef(Names = "TheName")]
+ public virtual SingleNamedObject NamedObject()
+ {
+ return new SingleNamedObject();
+ }
+
+ [ObjectDef(DestroyMethod = "CallToDestroy", InitMethod = "CallToInit")]
+ public virtual ObjectWithInitAndDestroyMethods ObjectWithInitAndDestroyMethods()
+ {
+ return new ObjectWithInitAndDestroyMethods();
+ }
+
+ [ObjectDef(Names = "TheFirstAlias,TheSecondAlias")]
+ public virtual ObjectWithAnAlias ObjectWithAnAlias()
+ {
+ return new ObjectWithAnAlias();
+ }
+
+ [ObjectDef]
+ [Scope(ObjectScope.Prototype)]
+ public virtual PrototypeParent PrototypeParent()
+ {
+ return new PrototypeParent(SingletonChild());
+ }
+
+ [ObjectDef]
+ [Scope(ObjectScope.Prototype)]
+ public virtual PrototypeChild PrototypeChild()
+ {
+ return new PrototypeChild();
+ }
+
+ [ObjectDef]
+ public virtual SingletonParent SingletonParent()
+ {
+ return new SingletonParent(PrototypeChild());
+ }
+
+ [ObjectDef]
+ public virtual SingletonChild SingletonChild()
+ {
+ return new SingletonChild();
+ }
+
+ [ObjectDef]
+ [Lazy]
+ public virtual ImplicitLazyInitObject ImplicitLazyInitObject()
+ {
+ return new ImplicitLazyInitObject();
+ }
+
+ [ObjectDef]
+ [Lazy(true)]
+ public virtual ExplicitLazyInitObject ExplicitLazyInitObject()
+ {
+ return new ExplicitLazyInitObject();
+ }
+
+ [ObjectDef]
+ [Lazy(false)]
+ public virtual ExplicitNonLazyInitObject ExplicitNonLazyInitObject()
+ {
+ return new ExplicitNonLazyInitObject();
+ }
+
+ }
+
+
+ [Configuration]
+ public class DerivedConfiguration : BaseConfigurationClass
+ {
+ [ObjectDef]
+ public virtual TestObject DerivedDefinition()
+ {
+ return new TestObject(BaseDefinition());
+ }
+ }
+
+ public class BaseConfigurationClass
+ {
+ [ObjectDef]
+ public virtual string BaseDefinition()
+ {
+ return Guid.NewGuid().ToString();
+ }
+ }
+
+ public class TypeRegisteredInXml { }
+
+ public class TypeRegisteredInXmlTwo { }
+
+ public class AnImportedType { }
+
+ public class ImplicitLazyInitObject { }
+
+ public class ExplicitLazyInitObject { }
+
+ public class ExplicitNonLazyInitObject { }
+
+ public class ObjectWithAnAlias { }
+
+ public class SingleNamedObject { }
+
+ public class SingletonParent
+ {
+ public static int InstanceCount = 0;
+ private PrototypeChild _child;
+
+ public SingletonParent(PrototypeChild child)
+ {
+ InstanceCount++;
+ _child = child;
+ }
+
+ public PrototypeChild Child
+ {
+ get
+ {
+ return _child;
+ }
+ }
+ }
+
+ public class SingletonChild
+ {
+ public static int InstanceCount = 0;
+
+ public SingletonChild()
+ {
+ InstanceCount++;
+ }
+ }
+
+ public class PrototypeParent
+ {
+ public static int InstanceCount = 0;
+ private SingletonChild _child;
+
+ public PrototypeParent(SingletonChild child)
+ {
+ InstanceCount++;
+ _child = child;
+ }
+
+ public SingletonChild Child
+ {
+ get
+ {
+ return _child;
+ }
+ }
+ }
+
+ public class PrototypeChild
+ {
+ public static int InstanceCount = 0;
+
+ public PrototypeChild()
+ {
+ InstanceCount++;
+ }
+ }
+
+ public class TestObject
+ {
+ private readonly string _value;
+
+ public TestObject(string value)
+ {
+ _value = value;
+ }
+
+ public string Value
+ {
+ get { return _value; }
+ }
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs
new file mode 100644
index 00000000..06fc43ce
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyObjectDefinitionScannerTests.cs
@@ -0,0 +1,30 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class AssemblyObjectDefinitionScannerTests
+ {
+
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs
new file mode 100644
index 00000000..df0396c0
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/AssemblyTypeScannerTests.cs
@@ -0,0 +1,133 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Spring.Core;
+using Spring.Util;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class AssemblyTypeScannerTests
+ {
+ #region Setup/Teardown
+
+ [SetUp]
+ public void _TestSetup()
+ {
+ _scanner = new AssemblyObjectDefinitionScanner();
+ }
+
+ #endregion
+
+ [Test]
+ public void AssemblyHavingType_T_Adds_Assembly()
+ {
+ _scanner.AssemblyHavingType();
+ Assert.That(TypeSources.Any(t => t.Contains(typeof (IOrdered))));
+ }
+
+ [Test]
+ public void IncludeType_T_Adds_Type()
+ {
+ _scanner.IncludeType();
+ _scanner.IncludeType();
+
+ IncludePredicates.Any(p => p(typeof (IOrdered)));
+ IncludePredicates.Any(p => p(typeof (IPriorityOrdered)));
+ }
+
+ [Test]
+ public void WithExcludeFilter_Excludes_Type()
+ {
+ //var scanner1 = new AssemblyObjectDefinitionScanner();
+
+ _scanner.IncludeType();
+ _scanner.IncludeType();
+ _scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported"));
+
+ IEnumerable types = _scanner.Scan();
+
+ //Assert.That(types.Any(t => t.Name == "TheConfigurationClass"));
+ //Assert.False(types.Any(t => t.Name == "TheImportedConfigurationClass"));
+
+ Assert.That(types, Contains.Item((typeof (TheConfigurationClass))));
+ Assert.False(types.Contains(typeof (TheImportedConfigurationClass)));
+ }
+
+ [Test]
+ public void WithIncludeFilter_Includes_Types()
+ {
+ _scanner.WithIncludeFilter(t => t.Name.Contains("ConfigurationClass"));
+
+ IEnumerable types = _scanner.Scan();
+
+ Assert.That(types, Contains.Item((typeof (TheConfigurationClass))));
+ Assert.That(types, Contains.Item((typeof (TheImportedConfigurationClass))));
+ Assert.That(types.Count(),Is.EqualTo(2));
+ }
+
+ [Serializable]
+ private class Scanner : AssemblyTypeScanner
+ {
+ protected override bool IsCompoundPredicateSatisfiedBy(Type type)
+ {
+ return IsIncludedType(type) && !IsExcludedType(type);
+ }
+ }
+
+ private AssemblyObjectDefinitionScanner _scanner;
+
+ private List> ExcludePredicates
+ {
+ get
+ {
+ //get at the collection of excludePredicates from the private field
+ //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!)
+ return
+ (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeExclusionPredicates"));
+ }
+ }
+
+ private List> IncludePredicates
+ {
+ get
+ {
+ //get at the collection of includePredicates from the private field
+ //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!)
+ return
+ (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeInclusionPredicates"));
+ }
+ }
+
+ private List> TypeSources
+ {
+ get
+ {
+ //get at the collection of typeSources from the private field
+ //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!)
+ return (List>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeSources"));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs
new file mode 100644
index 00000000..1424d899
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/CodeConfigApplicationContextTests.cs
@@ -0,0 +1,44 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Context.Support;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class CodeConfigApplicationContextTests : AbstractConfigurationClassPostProcessorTests
+ {
+
+ protected override void CreateApplicationContext()
+ {
+ GenericApplicationContext ctx = new GenericApplicationContext();
+
+ ctx.ScanAllAssemblies();
+
+ ctx.Refresh();
+
+ _ctx = ctx;
+ }
+
+ }
+
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs
new file mode 100644
index 00000000..92caff71
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassObjectDefinitionReaderTests.cs
@@ -0,0 +1,39 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ConfigurationClassObjectDefinitionReaderTests
+ {
+ [Test]
+ public void ShouldNotTryToResolveAbstractDefinitionsToType()
+ {
+ GenericObjectDefinition definition = new GenericObjectDefinition();
+ definition.ObjectTypeName = "~/Default.aspx";
+ definition.IsAbstract = true;
+ Assert.That(ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(definition), Is.False);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs
new file mode 100644
index 00000000..ee7dfa59
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassParserTests.cs
@@ -0,0 +1,74 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+
+using Spring.Context.Attributes;
+using Spring.Objects.Factory.Parsing;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ConfigurationClassParserTests
+ {
+ private ConfigurationClassParser _parser;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _parser = new ConfigurationClassParser(new FailFastProblemReporter());
+ }
+
+ [Test]
+ public void ShouldBeAbleToRegisterSameNamedConfigurationClassesFromDifferentNamespaces()
+ {
+ _parser.Parse(typeof(ConfigurationNameSpace1.SpringConfiguration), "1");
+ _parser.Parse(typeof(ConfigurationNameSpace2.SpringConfiguration), "2");
+
+ Assert.That(_parser.ConfigurationClasses.Count, Is.EqualTo(2), "Did not find two configuration classes");
+ }
+ }
+}
+
+namespace ConfigurationNameSpace1
+{
+ [Configuration]
+ public class SpringConfiguration
+ {
+ [ObjectDef]
+ public virtual string ConfigurationNameSpaceObjectA()
+ {
+ return "A";
+ }
+ }
+}
+
+namespace ConfigurationNameSpace2
+{
+ [Configuration]
+ public class SpringConfiguration
+ {
+ [ObjectDef]
+ public virtual string ConfigurationNameSpaceObjectB()
+ {
+ return "B";
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs
new file mode 100644
index 00000000..74463044
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs
@@ -0,0 +1,71 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests
+ {
+
+ protected override void CreateApplicationContext()
+ {
+ GenericApplicationContext ctx = new GenericApplicationContext();
+
+ var configDefinitionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass));
+ ctx.RegisterObjectDefinition(configDefinitionBuilder.ObjectDefinition.ObjectTypeName, configDefinitionBuilder.ObjectDefinition);
+
+ var postProcessorDefintionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor));
+ ctx.RegisterObjectDefinition(postProcessorDefintionBuilder.ObjectDefinition.ObjectTypeName, postProcessorDefintionBuilder.ObjectDefinition);
+
+ Assert.That(ctx.ObjectDefinitionCount, Is.EqualTo(2));
+
+ ctx.Refresh();
+
+ _ctx = ctx;
+ }
+
+
+ [Test]
+ public void ShouldAllowConfigurationClassInheritance()
+ {
+ var factory = new DefaultListableObjectFactory();
+ factory.RegisterObjectDefinition("DerivedConfiguration", new GenericObjectDefinition
+ {
+ ObjectType = typeof(DerivedConfiguration)
+ });
+
+ var processor = new ConfigurationClassPostProcessor();
+
+ processor.PostProcessObjectFactory(factory);
+
+ // we should get singleton instances only
+ TestObject testObject = (TestObject) factory.GetObject("DerivedDefinition");
+ string singletonParent = (string) factory.GetObject("BaseDefinition");
+
+
+ Assert.That(testObject.Value, Is.SameAs(singletonParent));
+ }
+ }
+
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/FailAssemblyObjectDefinitionScannerTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/FailAssemblyObjectDefinitionScannerTests.cs
new file mode 100644
index 00000000..f3ead625
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/FailAssemblyObjectDefinitionScannerTests.cs
@@ -0,0 +1,207 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Context.Support;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Parsing;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class FailAssemblyObjectDefinitionScannerTests
+ {
+ #region Setup/Teardown
+
+ [SetUp]
+ public void _SetUp()
+ {
+ _scanner = new AssemblyObjectDefinitionScanner();
+ _context = new CodeConfigApplicationContext();
+ }
+
+ #endregion
+
+ private void ScanForAndRegisterSingleType(Type type)
+ {
+ _scanner.WithIncludeFilter(t => t.Name == type.Name);
+ _scanner.ScanAndRegisterTypes(_context.DefaultListableObjectFactory);
+ AttributeConfigUtils.RegisterAttributeConfigProcessors((IObjectDefinitionRegistry)_context.ObjectFactory);
+ }
+
+ private CodeConfigApplicationContext _context;
+ private AssemblyObjectDefinitionScanner _scanner;
+
+ [Test]
+ public void Can_Ignore_Abstract_Configuration_Types()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassThatIsAbstract));
+ Assert.That(_context.GetObjectNamesForType(typeof(ConfigurationClassThatIsAbstract)).Count, Is.EqualTo(0), "Abstract Type erroneously registered with the Context.");
+ }
+
+ [Test]
+ public void Can_Prevent_Methods_With_Parameters()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassWithMethodHavingParameters));
+ Assert.Throws(_context.Refresh);
+ }
+
+ [Test]
+ public void Can_Prevent_Static_Methods()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassWithStaticMethod));
+ Assert.Throws(_context.Refresh);
+ }
+
+ [Test]
+ public void Can_Prevent_Non_Virtual_Methods()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassWithNonVirtualMethod));
+ Assert.Throws(_context.Refresh);
+ }
+
+ [Test]
+ public void Can_Prevent_Sealed_Configuration_Types()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassThatIsSealed));
+ Assert.Throws(_context.Refresh);
+ }
+
+ [Test]
+ public void Can_Prevent_Overloaded_Methods()
+ {
+ ScanForAndRegisterSingleType(typeof(ConfigurationClassWithOverloadedMethods));
+ Assert.Throws(_context.Refresh);
+ }
+
+ [Test]
+ public void Can_Prevent_Circular_ConfigurationClass_Refereces()
+ {
+ ScanForAndRegisterSingleType(typeof(FirstConfigurationClassWithCircularReference));
+
+ try
+ {
+ _context.Refresh();
+ }
+ catch (ObjectDefinitionStoreException ex)
+ {
+ Assert.That(ex.InnerException, Is.TypeOf(typeof(ObjectDefinitionParsingException)));
+ }
+ }
+
+ }
+
+ public class SomeType
+ {
+ }
+
+
+ [Configuration]
+ public class ConfigurationClassWithNonVirtualMethod
+ {
+ [ObjectDef]
+ public SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+
+ [Configuration]
+ public class ConfigurationClassWithStaticMethod
+ {
+ [ObjectDef]
+ public static SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+
+ [Configuration]
+ public class ConfigurationClassWithOverloadedMethods
+ {
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType(int i)
+ {
+ return new SomeType();
+ }
+ }
+
+ [Configuration]
+ [Import(typeof(SecondConfigurationClassWithCircularReference))]
+ public class FirstConfigurationClassWithCircularReference
+ {
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+
+ [Configuration]
+ [Import(typeof(FirstConfigurationClassWithCircularReference))]
+ public class SecondConfigurationClassWithCircularReference
+ {
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+
+
+ [Configuration]
+ public class ConfigurationClassWithMethodHavingParameters
+ {
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType(int i)
+ {
+ return new SomeType();
+ }
+ }
+
+
+ [Configuration]
+ public abstract class ConfigurationClassThatIsAbstract
+ {
+ [ObjectDef]
+ public virtual SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+
+ [Configuration]
+ public sealed class ConfigurationClassThatIsSealed
+ {
+ [ObjectDef]
+ public SomeType MethodThatRegistersSomeType()
+ {
+ return new SomeType();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs
new file mode 100644
index 00000000..14033be5
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ImportResourceAttributeTests.cs
@@ -0,0 +1,65 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Objects.Factory.Xml;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ImportResourceAttributeTests
+ {
+ [Test]
+ public void Uses_XmlObjectDefinitionReader_By_Default()
+ {
+ var attrib = new ImportResourceAttribute("the resource");
+
+ Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(XmlObjectDefinitionReader)));
+ }
+
+ [Test]
+ public void Can_Assign_NonDefault_DefinitionReader()
+ {
+ var attrib = new ImportResourceAttribute("the resource");
+ attrib.DefinitionReader = typeof(AbstractObjectDefinitionReader);
+
+ Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(AbstractObjectDefinitionReader)));
+ }
+
+ [Test]
+ public void DefinitionReader_Can_Prevent_Improper_Types()
+ {
+ ImportResourceAttribute attrib = new ImportResourceAttribute("the resource");
+
+ try
+ {
+ attrib.DefinitionReader = typeof(Object);// <--need to pass *anything* ensured *not* to implement IObjectDefinitionReader
+ Assert.Fail("Expected Exception of type ArgumentException not thrown!");
+ }
+ catch (ArgumentException)
+ {
+ //swallow the expected exception
+ }
+
+ }
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs
new file mode 100644
index 00000000..96ccf3f1
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefAttributeTests.cs
@@ -0,0 +1,54 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ObjectDefAttributeTests
+ {
+ [Test]
+ public void Can_Accept_Single_Name()
+ {
+ var def = new ObjectDefAttribute();
+
+ def.Names = "Steve";
+
+ Assert.That(def.NamesToArray[0], Is.EqualTo("Steve"));
+ }
+
+
+ [Test]
+ public void Can_Accept_Multiple_Names()
+ {
+ var def = new ObjectDefAttribute();
+ var names = "Name1,Name2,Name3";
+
+ def.Names = names;
+ Assert.That(def.NamesToArray[0], Is.EqualTo("Name1"));
+ Assert.That(def.NamesToArray[1], Is.EqualTo("Name2"));
+ Assert.That(def.NamesToArray[2], Is.EqualTo("Name3"));
+
+ }
+
+
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml
new file mode 100644
index 00000000..d6ef5c57
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitions.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml
new file mode 100644
index 00000000..26eae23a
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ObjectDefinitionsTwo.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs
new file mode 100644
index 00000000..213d2089
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/ScanningConfigurationClassPostProcessorTests.cs
@@ -0,0 +1,44 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Context.Config;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Attributes
+{
+ [TestFixture]
+ public class ScanningConfigurationClassPostProcessorTests : AbstractConfigurationClassPostProcessorTests
+ {
+ protected override void CreateApplicationContext()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ _ctx = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType()));
+
+ }
+
+ [Test]
+ public void ContextNotNull()
+ {
+ Assert.That(_ctx, Is.Not.Null);
+ }
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml
new file mode 100644
index 00000000..1e86ed12
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs
new file mode 100644
index 00000000..c034fe54
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Attributes/SimpleScanTests.cs
@@ -0,0 +1,92 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using NUnit.Framework;
+using Spring.Context.Config;
+using Spring.Context.Support;
+using Spring.Example.Scannable;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Attributes
+{
+
+ public class SimpleScanTests
+ {
+ private IApplicationContext _applicationContext;
+
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("SimpleScanTest.xml", GetType()));
+ }
+
+ //[Test]
+ public void FooService()
+ {
+
+ IFooService fooService = GetObject();
+
+ }
+
+ public T GetObject()
+ {
+ return (T)DoGetInstance(typeof(T), null);
+ }
+ public T GetObject(string name)
+ {
+ return (T)DoGetInstance(typeof(T), name);
+ }
+
+ protected object DoGetInstance(Type serviceType, string key)
+ {
+ if (key == null)
+ {
+ IEnumerator it = DoGetAllInstances(serviceType).GetEnumerator();
+ if (it.MoveNext())
+ {
+ return it.Current;
+ }
+ throw new ObjectCreationException(string.Format("no services of type '{0}' defined", serviceType.FullName));
+ }
+ return _applicationContext.GetObject(key, serviceType);
+ }
+
+ ///
+ /// Resolves service instances by type.
+ ///
+ /// Type of service requested.
+ ///
+ /// Sequence of service instance objects matching the .
+ ///
+ protected IEnumerable DoGetAllInstances(Type serviceType)
+ {
+ foreach (string objectName in _applicationContext.GetObjectNamesForType(serviceType))
+ {
+ yield return _applicationContext.GetObject(objectName);
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.cs
new file mode 100644
index 00000000..d34631a4
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/AttributeConfigObjectDefinitionParserTests.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 NUnit.Framework;
+using Spring.Context.Attributes;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Config
+{
+ [TestFixture]
+ public class AttributeConfigObjectDefinitionParserTests
+ {
+ private XmlApplicationContext _applicationContext;
+
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ }
+
+ [Test]
+ public void RegisteredComponents()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.AttributeConfigParser.xml", GetType()));
+ var objectDefintionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ }
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs
new file mode 100644
index 00000000..9e8a6c09
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserAssemblyFilterTests.cs
@@ -0,0 +1,49 @@
+using NUnit.Framework;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Config
+{
+ [TestFixture]
+ public class ComponentScanObjectDefinitionParserAssemblyFilterTests
+ {
+ private IApplicationContext _applicationContext;
+
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ }
+
+ [Test]
+ public void BaseAssembliesAttributeRequired()
+ {
+ Assert.That(delegate { _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestWithout.xml", GetType())); },
+ Throws.Exception);
+ }
+
+ [Test]
+ public void SingleAssemblyNameProvided()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestSingle.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0));
+ }
+
+ [Test]
+ public void MultipleAssemblyNameProvided()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestMultiple.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.GreaterThan(0));
+ }
+ [Test]
+ public void NegativeAssemblyNameProvided()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.BaseAssemblyTestNegative.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(4));
+ }
+
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs
new file mode 100644
index 00000000..3a175376
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTests.cs
@@ -0,0 +1,323 @@
+#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 NUnit.Framework;
+using Spring.Context.Attributes;
+using Spring.Context.Support;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Stereotype;
+using Spring.Objects.Factory.Attributes;
+using ComponentScan.Qualifier;
+
+namespace Spring.Context.Config
+{
+ [TestFixture]
+ public class ComponentScanObjectDefinitionParserTests
+ {
+ private XmlApplicationContext _applicationContext;
+
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ }
+
+ [Test]
+ public void ScanComponentsAndAddToContext()
+ {
+ var prefix = "ComponentScan.ScanComponentsAndAddToContext.";
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan1.xml", GetType()));
+ var objectDefinitionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefinitionNames.Count, Is.EqualTo(5+4));
+ Assert.That(_applicationContext.GetObject(prefix + "ComponentImpl"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject(prefix + "ServiceImpl"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject(prefix + "RepositoryImpl"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject(prefix + "ControllerImpl"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject(prefix + "ConfigurationImpl"), Is.Not.Null);
+ }
+
+ [Test]
+ public void ComponentsUseSpecifiedName()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan2.xml", GetType()));
+ var objectDefinitionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefinitionNames.Count, Is.EqualTo(5 + 4));
+ Assert.That(_applicationContext.GetObject("Component"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("Service"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("Repository"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("Controller"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("Configuration"), Is.Not.Null);
+ }
+
+ [Test]
+ public void UseSpecifiedObjectNameGenerator()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan3.xml", GetType()));
+ var objectDefinitionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefinitionNames.Contains("prototype"), Is.True);
+ }
+
+ [Test]
+ public void UseWrongObjectNameGeneratorTypeString()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan31.xml", GetType()));
+ var objectDefinitionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefinitionNames.Contains("prototype"), Is.False);
+ Assert.That(objectDefinitionNames.Contains("ComponentScan.NameGenerator.Prototype"), Is.True);
+ }
+ [Test]
+ public void ComponentsLazyLoaded()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan4.xml", GetType()));
+ var objectDefinition = _applicationContext.ObjectFactory.GetObjectDefinition("LazyInit");
+
+ Assert.That(objectDefinition.IsLazyInit, Is.True);
+ }
+
+ [Test]
+ public void ComponentsInDifferentScope()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan4.xml", GetType()));
+ var singletonDef = _applicationContext.ObjectFactory.GetObjectDefinition("Singleton");
+ var prototypeDef = _applicationContext.ObjectFactory.GetObjectDefinition("Prototype");
+
+ Assert.That(singletonDef.IsSingleton, Is.True);
+ Assert.That(singletonDef.Scope, Is.EqualTo(ObjectScope.Singleton.ToString().ToLower()));
+
+ Assert.That(prototypeDef.IsSingleton, Is.False);
+ Assert.That(prototypeDef.Scope, Is.EqualTo(ObjectScope.Prototype.ToString().ToLower()));
+ }
+
+ [Test]
+ public void ComponentsUseDefaults()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan5.xml", GetType()));
+ var prototypeDef = _applicationContext.ObjectFactory.GetObjectDefinition("Prototype");
+
+ Assert.That(prototypeDef.IsLazyInit, Is.True);
+ }
+
+ [Test]
+ public void ComponentWithQualifier()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan6.xml", GetType()));
+ var objectDef = _applicationContext.ObjectFactory.GetObjectDefinition("Prototype") as ScannedGenericObjectDefinition;
+
+ Assert.That(objectDef.HasQualifier(typeof(QualifierAttribute).Name), Is.True);
+
+ var attr = objectDef.GetQualifier(typeof (QualifierAttribute).Name).GetAttribute(AutowireCandidateQualifier.VALUE_KEY);
+ Assert.That(attr, Is.EqualTo("action"));
+ }
+
+ [Test]
+ public void ComponentWithQualifierAttributes()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScan6.xml", GetType()));
+ var objectDef = _applicationContext.ObjectFactory.GetObjectDefinition("Attribute") as ScannedGenericObjectDefinition;
+ var qualifier = objectDef.GetQualifier(typeof (MyQualifier).Name);
+
+ Assert.That(qualifier, Is.Not.Null);
+
+ var attr = qualifier.GetMetadataAttribute("Foo");
+ Assert.That(attr, Is.Not.Null);
+ Assert.That(attr.Value, Is.EqualTo("Funny"));
+ }
+
+ [Test]
+ public void DontRegisterAttributeConfig()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScanAttributeConfigFalse.xml", GetType()));
+ var objectDefintionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefintionNames.Count, Is.EqualTo(0));
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.False);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.False);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.False);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.False);
+ }
+
+ [Test]
+ public void RegisterAttributeConfig()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.ComponentScanAttributeConfigTrue.xml", GetType()));
+ var objectDefintionNames = _applicationContext.ObjectFactory.GetObjectDefinitionNames();
+
+ Assert.That(objectDefintionNames.Count, Is.EqualTo(4));
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ Assert.That(objectDefintionNames.Contains(AttributeConfigUtils.INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME), Is.True);
+ }
+
+ }
+}
+
+namespace ComponentScan.ScanComponentsAndAddToContext
+{
+ public interface IFoo
+ {
+ }
+
+ [Component]
+ public class ComponentImpl : IFoo
+ {
+ }
+
+ [Service]
+ public class ServiceImpl : IFoo
+ {
+ }
+
+ [Repository]
+ public class RepositoryImpl : IFoo
+ {
+ }
+
+ [Controller]
+ public class ControllerImpl : IFoo
+ {
+ }
+
+ [Configuration]
+ public class ConfigurationImpl : IFoo
+ {
+ }
+}
+
+namespace ComponentScan.ComponentsUseSpecifiedName
+{
+ public interface IFoo
+ {
+ }
+
+ [Component("Component")]
+ public class ComponentImpl : IFoo
+ {
+ }
+
+ [Service("Service")]
+ public class ServiceImpl : IFoo
+ {
+ }
+
+ [Repository("Repository")]
+ public class RepositoryImpl : IFoo
+ {
+ }
+
+ [Controller("Controller")]
+ public class ControllerImpl : IFoo
+ {
+ }
+
+ [Configuration("Configuration")]
+ public class ConfigurationImpl : IFoo
+ {
+ }
+}
+
+namespace ComponentScan.ComponentsAttributeLoad
+{
+ public interface IFoo
+ {
+ }
+
+ [Component("LazyInit")]
+ [Lazy]
+ public class LazyImpl : IFoo
+ {
+ }
+
+ [Component("Singleton")]
+ [Scope(ObjectScope.Singleton)]
+ public class SingletonImpl : IFoo
+ {
+ }
+
+ [Component("Prototype")]
+ [Scope(ObjectScope.Prototype)]
+ public class PrototypeImpl : IFoo
+ {
+ }
+}
+
+namespace ComponentScan.ComponentsUseDefaults
+{
+ public interface IFoo
+ {
+ }
+
+ [Component("Prototype")]
+ public class PrototypeImpl : IFoo
+ {
+ }
+}
+
+namespace ComponentScan.Qualifier
+{
+ public interface IFoo
+ {
+ }
+
+ public class MyQualifier : QualifierAttribute
+ {
+ public string Foo { get; set; }
+ }
+
+ [Component("Prototype")]
+ [Qualifier("action")]
+ public class PrototypeImpl : IFoo
+ {
+ }
+
+ [Component("Attribute")]
+ [MyQualifier(Foo="Funny")]
+ public class QualifierAttributeImpl : IFoo
+ {
+ }
+
+}
+
+namespace ComponentScan.NameGenerator
+{
+ public interface IFoo
+ {
+ }
+
+ public class MyGenerator : IObjectNameGenerator
+ {
+ public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry)
+ {
+ string typeName = definition.ObjectType.Name;
+ return typeName.ToLower();
+ }
+ }
+
+ [Component]
+ public class Prototype : IFoo
+ {
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs
new file mode 100644
index 00000000..f02885bd
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ComponentScanObjectDefinitionParserTypeFilterTests.cs
@@ -0,0 +1,224 @@
+#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;
+using NUnit.Framework;
+using Spring.Context.Attributes;
+using Spring.Context.Attributes.TypeFilters;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Xml;
+using Spring.Context.Support;
+using Spring.Stereotype;
+
+
+namespace Spring.Context.Config
+{
+ [TestFixture]
+ public class ComponentScanObjectDefinitionParserTypeFilterTests
+ {
+ private IApplicationContext _applicationContext;
+
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ }
+
+ [Test]
+ public void IncludeRegExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestRegExInclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(6));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeExcludeType"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void IncludeMultipleRegExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestRegExInclude2.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("SomeIncludeType2"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeExcludeType"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void ExcludeRegExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestRegExExclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeExcludeType"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void IncludeAttributeExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestAttributeInclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(6));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType2"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeExcludeType"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void ExcludeAttributeExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestAttributeExclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType2"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("SomeExcludeType"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeIncludeType1"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void IncludeAssignableExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestAssignableInclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("SomeIncludeType2"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeExcludeType"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void ExcludeAssignableExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestAssignableExclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("SomeExcludeType"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeIncludeType2"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void IncludeCustomExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestCustomInclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(6));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType1"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeIncludeType2"); }, Throws.Exception.TypeOf());
+ }
+
+ [Test]
+ public void ExcludeCustomExpressionFilter()
+ {
+ _applicationContext = new XmlApplicationContext(ReadOnlyXmlTestResource.GetFilePath("ConfigFiles.TypeScannerTestCustomExclude.xml", GetType()));
+
+ Assert.That(_applicationContext.GetObjectDefinitionNames().Count, Is.EqualTo(8));
+ Assert.That(_applicationContext.GetObject("SomeIncludeType2"), Is.Not.Null);
+ Assert.That(_applicationContext.GetObject("SomeExcludeType"), Is.Not.Null);
+ Assert.That(delegate { _applicationContext.GetObject("SomeIncludeType1"); }, Throws.Exception.TypeOf());
+ }
+
+ }
+}
+
+namespace XmlAssemblyTypeScanner.Test.Include1
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class DoNotIncludeAttribute : Attribute
+ {
+ }
+
+ [Configuration]
+ [DoNotInclude]
+ public class SomeIncludeConfiguration1 : IFunny
+ {
+ [ObjectDef]
+ public virtual SomeIncludeType1 SomeIncludeType1()
+ {
+ return new SomeIncludeType1();
+ }
+ }
+
+ public class SomeIncludeType1
+ {
+ }
+
+ public interface IFunny
+ {}
+
+
+ public class TestFilter : ITypeFilter
+ {
+ public bool Match(Type type)
+ {
+ return type.Name.Equals("SomeIncludeConfiguration1");
+ }
+ }
+
+}
+
+namespace XmlAssemblyTypeScanner.Test.Include2
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class DoIncludeAttribute : Attribute
+ {
+ }
+
+ [Configuration]
+ [DoInclude]
+ public class SomeIncludeConfiguration2 : FunnyAbstract
+ {
+ public override void Test() { }
+
+ [ObjectDef]
+ public virtual SomeIncludeType2 SomeIncludeType2()
+ {
+ return new SomeIncludeType2();
+ }
+ }
+
+ public class SomeIncludeType2
+ {
+ }
+
+ public abstract class FunnyAbstract
+ {
+ public abstract void Test();
+ }
+}
+
+namespace XmlAssemblyTypeScanner.Test.Include
+{
+ [Configuration]
+ public class SomeExcludeConfiguration3
+ {
+
+ [ObjectDef]
+ public virtual SomeExcludeType SomeExcludeType()
+ {
+ return new SomeExcludeType();
+ }
+ }
+
+ public class SomeExcludeType
+ {
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml
new file mode 100644
index 00000000..f4b24465
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/AttributeConfigParser.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml
new file mode 100644
index 00000000..f0fce716
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestMultiple.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml
new file mode 100644
index 00000000..bf2405fc
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestNegative.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml
new file mode 100644
index 00000000..ce45156c
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestSingle.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml
new file mode 100644
index 00000000..7d781430
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/BaseAssemblyTestWithout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml
new file mode 100644
index 00000000..a68cc463
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan1.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml
new file mode 100644
index 00000000..629573f8
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan2.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml
new file mode 100644
index 00000000..87c3cf85
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan3.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml
new file mode 100644
index 00000000..1162c903
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan31.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml
new file mode 100644
index 00000000..5946e407
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan4.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml
new file mode 100644
index 00000000..85eb51a7
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan5.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml
new file mode 100644
index 00000000..da0b4171
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScan6.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml
new file mode 100644
index 00000000..740a3e73
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigFalse.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml
new file mode 100644
index 00000000..fac0ba27
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/ComponentScanAttributeConfigTrue.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml
new file mode 100644
index 00000000..625a311b
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableExclude.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml
new file mode 100644
index 00000000..53a660e8
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAssignableInclude.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml
new file mode 100644
index 00000000..26458303
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeExclude.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml
new file mode 100644
index 00000000..bacd9861
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestAttributeInclude.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml
new file mode 100644
index 00000000..73a7710a
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomExclude.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml
new file mode 100644
index 00000000..8299fb19
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestCustomInclude.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml
new file mode 100644
index 00000000..096c39e8
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExExclude.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml
new file mode 100644
index 00000000..0e929860
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml
new file mode 100644
index 00000000..0727c5ed
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ConfigFiles/TypeScannerTestRegExInclude2.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs b/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs
new file mode 100644
index 00000000..9a638046
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Config/ContextNamespaceParserTests.cs
@@ -0,0 +1,42 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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 NUnit.Framework;
+using Spring.Objects.Factory.Xml;
+
+namespace Spring.Context.Config
+{
+ [TestFixture]
+ public class ContextNamespaceParserTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));
+ }
+
+ [Test]
+ public void Registered()
+ {
+ Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/context"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs
new file mode 100644
index 00000000..8e85f517
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Context/Support/CodeConfigApplicationContextTests.cs
@@ -0,0 +1,142 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Spring.Context.Attributes;
+
+namespace Spring.Context.Support
+{
+ [TestFixture]
+ public class CodeConfigApplicationContextTests
+ {
+ private CodeConfigApplicationContext _context;
+
+ [SetUp]
+ public void _TestSetup()
+ {
+ _context = new CodeConfigApplicationContext();
+ }
+
+ [Test]
+ public void Can_Filter_For_Assembly_Based_On_Assembly_Metadata()
+ {
+ _context.ScanWithAssemblyFilter(a => a.GetName().Name.StartsWith("Spring.Core."));
+ _context.Refresh();
+
+ AssertExpectedObjectsAreRegisteredWith(_context, 45);
+ }
+
+ [Test]
+ public void Can_Filter_For_Assembly_Containing_Specific_Type_But_Having_NO_Definitions()
+ {
+ //specifically filter assemblies for one that we *know* will result in NO [Configuration] types in it
+ _context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(Spring.Core.IOrdered).Name)));
+ _context.Refresh();
+
+ Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(4));
+ }
+
+ [Test]
+ public void Can_Filter_For_Assembly_Containing_Specific_Type()
+ {
+ _context.ScanWithAssemblyFilter(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(MarkerTypeForScannerToFind).Name)));
+ _context.Refresh();
+
+ AssertExpectedObjectsAreRegisteredWith(_context, 45);
+ }
+
+ [Test]
+ public void Can_Filter_For_Specific_Type()
+ {
+ _context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name));
+ _context.Refresh();
+
+ Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(8));
+ }
+
+ [Test]
+ public void Can_Filter_For_Specific_Types_With_Compound_Predicate()
+ {
+ _context.ScanWithTypeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name) || type.FullName.Contains(typeof(TheConfigurationClass).Name));
+ _context.Refresh();
+
+ AssertExpectedObjectsAreRegisteredWith(_context, 19);
+ }
+
+ [Test]
+ public void Can_Filter_For_Specific_Types_With_Multiple_Include_Filters()
+ {
+ var scanner = new AssemblyObjectDefinitionScanner();
+ scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheImportedConfigurationClass).Name));
+ scanner.WithIncludeFilter(type => type.FullName.Contains(typeof(TheConfigurationClass).Name));
+
+ _context.Scan(scanner);
+ _context.Refresh();
+
+ AssertExpectedObjectsAreRegisteredWith(_context, 19);
+ }
+
+ [Test]
+ public void Scanner()
+ {
+ AssemblyObjectDefinitionScanner scanner = new AssemblyObjectDefinitionScanner();
+ scanner.AssemblyHavingType();
+
+ }
+
+ [Test]
+ public void Can_Perform_Scan_With_No_Filtering()
+ {
+ _context.ScanAllAssemblies();
+ _context.Refresh();
+
+ AssertExpectedObjectsAreRegisteredWith(_context, 45);
+ }
+
+ private void AssertExpectedObjectsAreRegisteredWith(GenericApplicationContext context, int expectedDefinitionCount)
+ {
+ // only check names that are not part of configuration namespace test
+ List names = new List(context.DefaultListableObjectFactory.GetObjectDefinitionNames());
+ names.RemoveAll(x => x.StartsWith("ConfigurationNameSpace"));
+
+
+ if (names.Count != expectedDefinitionCount)
+ {
+ Console.WriteLine("Actual types registered with the container:");
+ foreach (var name in names)
+ {
+ Console.WriteLine(name);
+ }
+ }
+
+
+ Assert.That(names.Count, Is.EqualTo(expectedDefinitionCount));
+ }
+
+ }
+
+ public class MarkerTypeForScannerToFind
+ {
+
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs
new file mode 100644
index 00000000..9e4238ed
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Example/Scannable/FooService.cs
@@ -0,0 +1,51 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Stereotype;
+
+namespace Spring.Example.Scannable
+{
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ [Service]
+ public class FooService : IFooService
+ {
+ private string foo;
+
+ private bool initCalled;
+
+
+
+ public string Foo
+ {
+ get { return foo; }
+ set { foo = value; }
+ }
+
+ public bool InitCalled
+ {
+ get { return initCalled; }
+ set { initCalled = value; }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs
new file mode 100644
index 00000000..de78ead8
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooDao.cs
@@ -0,0 +1,32 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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
+
+namespace Spring.Example.Scannable
+{
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public interface IFooDao
+ {
+ string FindFoo(string id);
+ }
+
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs
new file mode 100644
index 00000000..8b0ed44d
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Example/Scannable/IFooService.cs
@@ -0,0 +1,35 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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
+
+namespace Spring.Example.Scannable
+{
+ ///
+ /// Simple service for testing of component scanning
+ ///
+ /// Mark Pollack
+ public interface IFooService
+ {
+ string Foo { get; set; }
+
+ bool InitCalled { get; set; }
+
+ }
+
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs b/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs
new file mode 100644
index 00000000..3d15ebbc
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Example/Scannable/StubFooDao.cs
@@ -0,0 +1,38 @@
+#region License
+
+/*
+ * Copyright © 2010-2011 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.Stereotype;
+
+namespace Spring.Example.Scannable
+{
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ [Repository]
+ public class StubFooDao : IFooDao
+ {
+ public string FindFoo(string id)
+ {
+ return "bar";
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2010.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2010.csproj
index 2cb48597..04a141ef 100644
--- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2010.csproj
+++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2010.csproj
@@ -152,9 +152,25 @@
Code
+
+
+
+
+
+
+
+
+
+
+
Code
+
+
+
+
+
Code
@@ -183,6 +199,7 @@
Code
+
Code
@@ -281,6 +298,10 @@
Code
+
+
+
+
@@ -804,6 +825,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+