SPRNET-1536 merge code and tests from SPRNET-CODECONFIG project

This commit is contained in:
Steve Bohlen
2013-01-07 10:55:43 -05:00
parent 06ea2587b1
commit 9b50c40a6b
89 changed files with 7341 additions and 324 deletions

View File

@@ -0,0 +1,189 @@
#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 Spring.Objects.Factory.Support;
using Spring.Stereotype;
namespace Spring.Context.Attributes
{
/// <summary>
/// AssemblyTypeScanner that only accepts types that also meet the requirements of being ObjectDefintions.
/// </summary>
[Serializable]
public class AssemblyObjectDefinitionScanner : RequiredConstraintAssemblyTypeScanner
{
private readonly List<Predicate<Assembly>> _assemblyExclusionPredicates = new List<Predicate<Assembly>>();
private readonly IList<string> _springAssemblies = new List<string>()
{
"Spring.Core",
"Spring.Core.Configuration",
"Spring.Aop",
"Spring.Data",
"Spring.Services",
"Spring.Messaging",
"Spring.Messaging.Ems",
"Spring.Messaging.Nms",
"Spring.Template.Velocity",
"Spring.Messaging.Quartz",
"Spring.Testing.Microsoft",
"Spring.Testing.Nunit",
"Spring.Data.NHibernate12",
"Spring.Data.NHibernate21",
"Spring.Data.NHibernate20",
"Spring.Data.NHibernate30",
"Spring.Web",
"Spring.Web.Extensions",
"Spring.Web.Mvc",
};
private IObjectNameGenerator _objectNameGenerator = new AttributeObjectNameGenerator();
/// <summary>
/// Provides the name generator for all scanned objects.
/// Default is <see cref="AttributeObjectNameGenerator"/>
/// </summary>
public IObjectNameGenerator ObjectNameGenerator
{
get { return _objectNameGenerator; }
set { _objectNameGenerator = value; }
}
/// <summary>
/// Registers the defintions for types.
/// </summary>
/// <param name="registry">The registry.</param>
/// <param name="typesToRegister">The types to register.</param>
private void RegisterDefinitionsForTypes(IObjectDefinitionRegistry registry, IEnumerable<Type> typesToRegister)
{
foreach (Type type in typesToRegister)
{
var definition = new ScannedGenericObjectDefinition(type, Defaults);
string objectName = ObjectNameGenerator.GenerateObjectName(definition, registry);
registry.RegisterObjectDefinition(objectName, definition);
}
}
/// <summary>
/// Applies the assembly filters to the assembly candidates.
/// </summary>
/// <param name="assemblyCandidates">The assembly candidates.</param>
/// <returns></returns>
protected override IEnumerable<Assembly> ApplyAssemblyFiltersTo(IEnumerable<Assembly> assemblyCandidates)
{
return assemblyCandidates.Where(
delegate(Assembly candidate) { return IsIncludedAssembly(candidate) && !IsExcludedAssembly(candidate); });
}
/// <summary>
/// Determines whether the specified candidate is and excluded assembly.
/// </summary>
/// <param name="candidate">The candidate.</param>
/// <returns>
/// <c>true</c> if the specified candidate is an excluded assembly ; otherwise, <c>false</c>.
/// </returns>
protected virtual bool IsExcludedAssembly(Assembly candidate)
{
return _assemblyExclusionPredicates.Any(delegate(Predicate<Assembly> exclude) { return exclude(candidate); });
}
/// <summary>
/// Determines whether the required constraint is satisfied by the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if the required constraint is satisfied by the specified type; otherwise, <c>false</c>.
/// </returns>
protected override bool IsRequiredConstraintSatisfiedBy(Type type)
{
if (!type.Assembly.ReflectionOnly)
{
try
{
return Attribute.GetCustomAttribute(type, typeof(ComponentAttribute), true) != null &&
!type.IsAbstract;
}
catch (AmbiguousMatchException)
{
Logger.Error(m => m("Type {0} has more than one ComponentAttributes assigned to it.", type.FullName));
return false;
}
}
bool satisfied = false;
foreach (CustomAttributeData customAttributeData in CustomAttributeData.GetCustomAttributes(type))
{
if (customAttributeData.Constructor.DeclaringType.FullName == typeof(ComponentAttribute).FullName &&
!type.IsAbstract)
{
satisfied = true;
break;
}
}
return satisfied;
}
/// <summary>
/// Sets the default filters.
/// </summary>
protected override void SetDefaultFilters()
{
//set the built-in defaults
base.SetDefaultFilters();
//add the desired assembly exclusions to the list
_assemblyExclusionPredicates.Add(
delegate(Assembly a) { return _springAssemblies.Contains(a.GetName().Name); });
_assemblyExclusionPredicates.Add(delegate(Assembly a) { return a.GetName().Name.StartsWith("System."); });
_assemblyExclusionPredicates.Add(delegate(Assembly a) { return a.GetName().Name.StartsWith("Microsoft."); });
_assemblyExclusionPredicates.Add(delegate(Assembly a) { return a.GetName().Name == "mscorlib"; });
_assemblyExclusionPredicates.Add(delegate(Assembly a) { return a.GetName().Name == "System"; });
}
/// <summary>
/// Scans the and register types.
/// </summary>
/// <param name="registry">The registry within which to register the types.</param>
public virtual void ScanAndRegisterTypes(IObjectDefinitionRegistry registry)
{
IEnumerable<Type> configTypes = base.Scan();
RegisterDefinitionsForTypes(registry, configTypes);
}
/// <summary>
/// Initializes a new instance of the <see cref="AssemblyObjectDefinitionScanner"/> class.
/// </summary>
public AssemblyObjectDefinitionScanner()
{
AssemblyLoadExclusionPredicates.Add(delegate(string name) { return _springAssemblies.Contains(name); });
AssemblyLoadExclusionPredicates.Add(delegate(string name) { return name.StartsWith("System."); });
AssemblyLoadExclusionPredicates.Add(delegate(string name) { return name.StartsWith("Microsoft."); });
AssemblyLoadExclusionPredicates.Add(delegate(string name) { return name == "mscorlib"; });
AssemblyLoadExclusionPredicates.Add(delegate(string name) { return name == "System"; });
}
}
}

View File

@@ -0,0 +1,400 @@
#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.IO;
using System.Reflection;
using Common.Logging;
using Spring.Context.Attributes.TypeFilters;
using Spring.Util;
using Spring.Objects.Factory.Xml;
namespace Spring.Context.Attributes
{
/// <summary>
/// Scans Assebmlies for Types that satisfy a given set of constraints.
/// </summary>
[Serializable]
public abstract class AssemblyTypeScanner : IAssemblyTypeScanner
{
/// <summary>
/// Logger Instance.
/// </summary>
protected static readonly ILog Logger = LogManager.GetLogger<AssemblyTypeScanner>();
/// <summary>
/// Names of Assemblies to exclude from being loaded for scanning.
/// </summary>
protected IList<Predicate<string>> AssemblyLoadExclusionPredicates = new List<Predicate<string>>();
/// <summary>
/// Assembly Inclusion Predicates.
/// </summary>
protected readonly List<Predicate<Assembly>> AssemblyInclusionPredicates = new List<Predicate<Assembly>>();
/// <summary>
/// Type Exclusion Predicates.
/// </summary>
protected readonly List<Predicate<Type>> TypeExclusionPredicates = new List<Predicate<Type>>();
/// <summary>
/// Type Exclusion Predicates.
/// </summary>
protected readonly List<ITypeFilter> TypeExclusionTypeFilters = new List<ITypeFilter>();
/// <summary>
/// Type Inclusion Predicates.
/// </summary>
protected readonly List<Predicate<Type>> TypeInclusionPredicates = new List<Predicate<Type>>();
/// <summary>
/// Type Inclusion TypeFilters.
/// </summary>
protected readonly List<ITypeFilter> TypeInclusionTypeFilter = new List<ITypeFilter>();
/// <summary>
/// Assemblies to scan.
/// </summary>
protected readonly List<IEnumerable<Type>> TypeSources = new List<IEnumerable<Type>>();
/// <summary>
/// Stores the object default definitons defined in the XML configuration documnet
/// </summary>
protected DocumentDefaultsDefinition _defaults;
/// <summary>
/// Stores the object default definitons defined in the XML configuration documnet
/// </summary>
public DocumentDefaultsDefinition Defaults { get { return _defaults; } set { _defaults = value; } }
#region IAssemblyTypeScanner Members
/// <summary>
/// Assemblies the type of the having.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IAssemblyTypeScanner AssemblyHavingType<T>()
{
TypeSources.Add(new AssemblyTypeSource((typeof(T).Assembly)));
return this;
}
/// <summary>
/// Excludes the type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IAssemblyTypeScanner ExcludeType<T>()
{
TypeExclusionPredicates.Add(delegate(Type t) { return t.FullName == typeof(T).FullName; });
return this;
}
/// <summary>
/// Includes the type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IAssemblyTypeScanner IncludeType<T>()
{
TypeInclusionPredicates.Add(delegate(Type t) { return t.FullName == typeof(T).FullName; });
return this;
}
/// <summary>
/// Includes the types.
/// </summary>
/// <param name="typeSource">The type source.</param>
/// <returns></returns>
public IAssemblyTypeScanner IncludeTypes(IEnumerable<Type> typeSource)
{
AssertUtils.ArgumentNotNull(typeSource, "typeSource");
TypeSources.Add(typeSource);
TypeInclusionPredicates.Add(
delegate(Type t) { return typeSource.Any(delegate(Type t1) { return t1.FullName == t.FullName; }); });
return this;
}
/// <summary>
/// Performs the Scan, respecting all filter settings.
/// </summary>
/// <returns></returns>
public virtual IEnumerable<Type> Scan()
{
SetDefaultFilters();
IList<Type> types = new List<Type>();
foreach (Assembly assembly in GetAllMatchingAssemblies())
{
TypeSources.Add(new AssemblyTypeSource(assembly));
}
foreach (var typeSource in TypeSources)
{
foreach (Type type in typeSource)
{
if (IsCompoundPredicateSatisfiedBy(type))
{
types.Add(type);
}
}
}
return types;
}
/// <summary>
/// Adds the assembly filter.
/// </summary>
/// <param name="assemblyPredicate">The assembly predicate.</param>
/// <returns></returns>
public IAssemblyTypeScanner WithAssemblyFilter(Predicate<Assembly> assemblyPredicate)
{
AssemblyInclusionPredicates.Add(assemblyPredicate);
return this;
}
/// <summary>
/// Adds the exclude filter.
/// </summary>
/// <param name="predicate">The predicate.</param>
/// <returns></returns>
public IAssemblyTypeScanner WithExcludeFilter(Predicate<Type> predicate)
{
TypeExclusionPredicates.Add(predicate);
return this;
}
/// <summary>
/// Adds the exclude filter.
/// </summary>
/// <param name="filter">The type filter.</param>
/// <returns></returns>
public IAssemblyTypeScanner WithExcludeFilter(ITypeFilter filter)
{
if (filter != null)
TypeExclusionTypeFilters.Add(filter);
return this;
}
/// <summary>
/// Adds the include filter.
/// </summary>
/// <param name="predicate">The predicate.</param>
/// <returns></returns>
public IAssemblyTypeScanner WithIncludeFilter(Predicate<Type> predicate)
{
TypeInclusionPredicates.Add(predicate);
return this;
}
/// <summary>
/// Adds the include filter.
/// </summary>
/// <param name="filter">The filter type.</param>
/// <returns></returns>
public IAssemblyTypeScanner WithIncludeFilter(ITypeFilter filter)
{
if (filter != null)
TypeInclusionTypeFilter.Add(filter);
return this;
}
#endregion
private List<string> GetAllAssembliesInPath()
{
string folderPath = GetCurrentBinDirectoryPath();
var assemblies = new List<string>();
assemblies.AddRange(DiscoverAssemblies(folderPath, "*.dll"));
assemblies.AddRange(DiscoverAssemblies(folderPath, "*.exe"));
Logger.Debug(m => m("Assemblies to be scanned: {0}", StringUtils.ArrayToCommaDelimitedString(assemblies.ToArray())));
return assemblies;
}
private IEnumerable<Assembly> GetAllMatchingAssemblies()
{
IEnumerable<string> assemblyCandidates = GetAllAssembliesInPath();
IList<Assembly> assemblies = new List<Assembly>();
foreach (string assembly in assemblyCandidates)
{
if (!string.IsNullOrEmpty(assembly))
{
Assembly loadedAssembly = TryLoadAssemblyFromPath(assembly);
if (null != loadedAssembly)
{
assemblies.Add(loadedAssembly);
}
}
}
return ApplyAssemblyFiltersTo(assemblies);
}
private Assembly TryLoadAssemblyFromPath(string filename)
{
Assembly assembly = null;
try
{
assembly = Assembly.LoadFrom(filename);
}
catch (Exception ex)
{
//log and swallow everything that might go wrong here...
Logger.Debug(m => m("Failed to load assembly {0} to inspect for [Configuration] types!", filename), ex);
}
return assembly;
}
private string GetCurrentBinDirectoryPath()
{
return string.IsNullOrEmpty(AppDomain.CurrentDomain.DynamicDirectory)
? AppDomain.CurrentDomain.BaseDirectory
: AppDomain.CurrentDomain.DynamicDirectory;
}
/// <summary>
/// Applies the assembly filters to the assembly candidates.
/// </summary>
/// <param name="assemblyCandidates">The assembly candidates.</param>
/// <returns></returns>
protected virtual IEnumerable<Assembly> ApplyAssemblyFiltersTo(IEnumerable<Assembly> assemblyCandidates)
{
return
assemblyCandidates.Where(IsIncludedAssembly).
AsEnumerable();
}
/// <summary>
/// Determines whether the compound predicate is satisfied by the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if the compound predicate is satisfied by the specified type; otherwise, <c>false</c>.
/// </returns>
protected abstract bool IsCompoundPredicateSatisfiedBy(Type type);
/// <summary>
/// Determines whether [is excluded type] [the specified type].
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if [is excluded type] [the specified type]; otherwise, <c>false</c>.
/// </returns>
protected virtual bool IsExcludedType(Type type)
{
if (TypeExclusionPredicates.Count > 0 && TypeExclusionPredicates.Any(delegate(Predicate<Type> exclude) { return exclude(type); }))
return true;
foreach(var filter in TypeExclusionTypeFilters)
{
if (filter.Match(type))
return true;
}
return false;
}
/// <summary>
/// Determines whether [is included assembly] [the specified assembly].
/// </summary>
/// <param name="assembly">The assembly.</param>
/// <returns>
/// <c>true</c> if [is included assembly] [the specified assembly]; otherwise, <c>false</c>.
/// </returns>
protected virtual bool IsIncludedAssembly(Assembly assembly)
{
return AssemblyInclusionPredicates.Any(delegate(Predicate<Assembly> include) { return include(assembly); });
}
/// <summary>
/// Determines whether [is included type] [the specified type].
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if [is included type] [the specified type]; otherwise, <c>false</c>.
/// </returns>
protected virtual bool IsIncludedType(Type type)
{
if (TypeInclusionPredicates.Count > 0 && TypeInclusionPredicates.Any(delegate(Predicate<Type> include) { return include(type); }))
return true;
foreach(var filter in TypeInclusionTypeFilter)
{
if (filter.Match(type))
return true;
}
return false;
}
/// <summary>
/// Sets the default filters.
/// </summary>
protected virtual void SetDefaultFilters()
{
if (TypeInclusionPredicates.Count == 0 && TypeInclusionTypeFilter.Count == 0)
TypeInclusionPredicates.Add(delegate { return true; });
if (TypeExclusionPredicates.Count == 0 && TypeExclusionTypeFilters.Count == 0)
TypeExclusionPredicates.Add(delegate { return false; });
if (AssemblyInclusionPredicates.Count == 0)
AssemblyInclusionPredicates.Add(delegate { return true; });
}
/// <summary>
/// Loads the assemblies found.
/// </summary>
/// <param name="folderPath">The folder path.</param>
/// <param name="extension">The extension.</param>
private IList<string> DiscoverAssemblies(string folderPath, string extension)
{
IList<string> assemblies = new List<string>();
IEnumerable<string> files = Directory.GetFiles(folderPath, extension, SearchOption.AllDirectories);
foreach (string file in files)
{
string name = Path.GetFileNameWithoutExtension(file);
if (!AssemblyLoadExclusionPredicates.Any(delegate(Predicate<string> exclude) { return exclude(name); }))
{
assemblies.Add(file);
}
}
return assemblies;
}
}
}

View File

@@ -0,0 +1,63 @@
#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 System.Reflection;
using System.Runtime.InteropServices;
using Spring.Util;
namespace Spring.Context.Attributes
{
/// <summary>
/// Represents a collection of Types.
/// </summary>
[Serializable]
public class AssemblyTypeSource : IEnumerable<Type>
{
private readonly _Assembly _assembly;
/// <summary>
/// Initializes a new instance of the <see cref="AssemblyTypeSource"/> class.
/// </summary>
/// <param name="assembly">The assembly.</param>
public AssemblyTypeSource(Assembly assembly)
{
AssertUtils.ArgumentNotNull(assembly, "assembly");
this._assembly = assembly;
}
/// <summary>
/// Gets the enumerator.
/// </summary>
/// <returns></returns>
public IEnumerator<Type> GetEnumerator()
{
foreach (var type in _assembly.GetTypes())
yield return type;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -0,0 +1,104 @@
#region License
/*
* Copyright <20> 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.Attributes;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Context.Attributes
{
/// <summary>
/// Utility class that allows for convenient registration of common <see cref="IObjectPostProcessor"/>
/// and <see cref="IObjectFactoryPostProcessor"/> definitions for attribute based configuration
/// </summary>
/// <seealso cref="ConfigurationClassObjectDefinitionReader"/>
/// <seealso cref="RequiredAttributeObjectPostProcessor"/>
///
/// <author>Mark Pollack (.NET)</author>
/// <author>Mark Fisher</author>
/// <author>Juergen Hoeller</author>
/// <author>Chris Beams</author>
public class AttributeConfigUtils
{
/// <summary>
/// The object name of the internally managed Configuration attribute processor.
/// </summary>
public static readonly string CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME =
"Spring.Context.Attributes.InternalConfigurationClassPostProcessor";
/// <summary>
/// The object name of the internally managed Autowire attribute processor
/// </summary>
public static readonly string AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME =
"Spring.Context.Attributes.InternalAutowiredClassPostProcessor";
/// <summary>
///The object name of the internally managed Required attribute processor.
/// </summary>
public static readonly string REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME =
"Spring.Context.Attributes.InternalRequiredClassPostProcessor";
/// <summary>
///The object name of the internally managed InitDestroy attribute processor.
/// </summary>
public static readonly string INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME =
"Spring.Context.Attributes.InternalInitDestroyClassPostProcessor";
/// <summary>
/// Registers the attribute config processors.
/// </summary>
/// <param name="registry">The registry.</param>
public static void RegisterAttributeConfigProcessors(IObjectDefinitionRegistry registry)
{
if (!registry.ContainsObjectDefinition(CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME))
{
RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(ConfigurationClassPostProcessor));
RegisterPostProcessor(registry, objectDefinition, CONFIGURATION_ATTRIBUTE_PROCESSOR_OBJECT_NAME);
}
if (!registry.ContainsObjectDefinition(AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME))
{
RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(AutowiredAttributeObjectPostProcessor));
RegisterPostProcessor(registry, objectDefinition, AUTOWIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME);
}
if (!registry.ContainsObjectDefinition(REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME))
{
RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(RequiredAttributeObjectPostProcessor));
RegisterPostProcessor(registry, objectDefinition, REQUIRED_ATTRIBUTE_PROCESSOR_OBJECT_NAME);
}
if (!registry.ContainsObjectDefinition(INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME))
{
RootObjectDefinition objectDefinition = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor));
RegisterPostProcessor(registry, objectDefinition, INITDESTROY_ATTRIBUTE_PROCESSOR_OBJECT_NAME);
}
}
private static void RegisterPostProcessor(IObjectDefinitionRegistry registry, IConfigurableObjectDefinition objectDefinition, string objectName)
{
objectDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE;
registry.RegisterObjectDefinition(objectName, objectDefinition);
}
}
}

View File

@@ -0,0 +1,59 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
namespace Spring.Context.Attributes
{
/// <summary>
/// Default Name Generator for attribute driven component scan.
///
/// First choice is the provided name of the Component attribute.
/// Fallback is the short type name.
/// </summary>
public class AttributeObjectNameGenerator : IObjectNameGenerator
{
/// <summary>
/// Generates an object name for the given object definition.
/// </summary>
/// <param name="definition">The object definition to generate a name for.</param>
/// <param name="registry">The object definitions registry that the given definition is
/// supposed to be registerd with</param>
/// <returns>
/// the generated object name
/// </returns>
public string GenerateObjectName(IObjectDefinition definition, IObjectDefinitionRegistry registry)
{
if (definition is ScannedGenericObjectDefinition)
{
string objectName = ((ScannedGenericObjectDefinition) definition).ComponentName;
if (!string.IsNullOrEmpty(objectName))
return objectName;
}
return BuildDefaultObjectName(definition);
}
private string BuildDefaultObjectName(IObjectDefinition definition)
{
return definition.ObjectType.FullName;
}
}
}

View File

@@ -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 Spring.Stereotype;
namespace Spring.Context.Attributes
{
/// <summary>
/// Indicates that a class declares one or more <see cref="ObjectDefAttribute"/> methods and may be processed
/// by the Spring container to generate object definitions and service requests for those objects
/// at runtime.
///
/// <para>Configuration is meta-annotated as a <see cref="ComponentAttribute"/>, therefore Configuration
/// classes are candidates for component-scanning.
/// </para>
/// <para>May be used in conjunction with the <see cref="LazyAttribute"/> attribute to indicate that all object
/// methods declared within this class are by default lazily initialized.
///</para>
/// <h3>Constraints</h3>
/// <ul>
/// <li>Configuration classes must be non-sealed</li>
/// <li>Configuration classes must have a default/no-arg constructor</li>
/// </ul>
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ConfigurationAttribute : ComponentAttribute
{
/// <summary>
/// Initializes a new instance of the ConfigurationAttribute class.
/// </summary>
public ConfigurationAttribute()
{
}
/// <summary>
/// Initializes a new instance of the Configuration class.
/// </summary>
/// <param name="name"></param>
public ConfigurationAttribute(string name)
{
Name = name;
}
}
}

View File

@@ -0,0 +1,252 @@
#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.Text;
using Spring.Core.IO;
using Spring.Collections.Generic;
using Spring.Objects.Factory.Parsing;
namespace Spring.Context.Attributes
{
/// <summary>
/// Represents an instance of the metadata that has been parsed from a class with the <see cref="ConfigurationAttribute"/> applied to it.
/// </summary>
public class ConfigurationClass
{
private Type _configurationClassType;
private readonly IDictionary<string, Type> _importedResources = new Dictionary<string, Type>();
private readonly Collections.Generic.ISet<ConfigurationClassMethod> _methods = new HashedSet<ConfigurationClassMethod>();
private string _objectName;
private readonly IResource _resource;
/// <summary>
/// Initializes a new instance of the ConfigurationClass class.
/// </summary>
/// <param name="objectName"></param>
/// <param name="type"></param>
public ConfigurationClass(string objectName, Type type)
{
_objectName = objectName;
_configurationClassType = type;
_resource = new ConfigurationClassAssemblyResource(type);
}
/// <summary>
/// Gets the type of the configuration class.
/// </summary>
/// <value>The type of the configuration class.</value>
public Type ConfigurationClassType
{
get
{
return _configurationClassType;
}
}
/// <summary>
/// Gets the imported resources.
/// </summary>
/// <value>The imported resources.</value>
public IDictionary<string, Type> ImportedResources
{
get
{
return _importedResources;
}
}
/// <summary>
/// Gets the methods.
/// </summary>
/// <value>The methods.</value>
public Collections.Generic.ISet<ConfigurationClassMethod> Methods
{
get
{
return _methods;
}
}
/// <summary>
/// Gets or sets the name of the object.
/// </summary>
/// <value>The name of the object.</value>
public string ObjectName
{
get
{
return _objectName;
}
set
{
_objectName = value;
}
}
/// <summary>
/// Gets the resource.
/// </summary>
/// <value>The resource.</value>
public IResource Resource
{
get
{
return _resource;
}
}
/// <summary>
/// Gets the SimpleName of the object.
/// </summary>
/// <value>The simple name.</value>
public string SimpleName
{
get { return ConfigurationClassType.Name; }
}
/// <summary>
/// Adds the imported resource.
/// </summary>
/// <param name="importedResource">The imported resource.</param>
/// <param name="readerClass">The reader class capable of interpreting the imported resource.</param>
public void AddImportedResource(string importedResource, Type readerClass)
{
_importedResources.Add(importedResource, readerClass);
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="other">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object other)
{
return this == other || (other is ConfigurationClass && ConfigurationClassType == ((ConfigurationClass)other).ConfigurationClassType);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
return ConfigurationClassType.GetHashCode() * 14;
}
/// <summary>
/// Validates the specified <see cref="ConfigurationClass"/> and reports all discovered violations to the provided problem reporter for appropriate action.
/// </summary>
/// <param name="problemReporter">The problem reporter.</param>
public void Validate(IProblemReporter problemReporter)
{
// A [ObjectDef] method may only be overloaded through inheritance. No single
// [Configuration] class may declare two [ObjectDef] methods with the same name.
const char hashDelim = '#';
Dictionary<String, int> methodNameCounts = new Dictionary<String, int>();
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))
{ }
}
}
}

View File

@@ -0,0 +1,203 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Implementation of the IResource that represents an assembly containing one or more <see cref="ConfigurationClass"/> resources.
/// </summary>
public class ConfigurationClassAssemblyResource : IResource
{
private readonly string _containingAssemblyFileName;
private readonly Type _type;
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
/// </summary>
/// <param name="type">The type.</param>
public ConfigurationClassAssemblyResource(Type type)
{
_type = type;
_containingAssemblyFileName = Assembly.GetAssembly(_type.GetType()).Location;
}
#region IResource Members
/// <summary>
/// Creates a resource relative to this resource.
/// </summary>
/// <param name="relativePath">The path (always resolved as relative to this resource).</param>
/// <returns>The relative resource.</returns>
/// <exception cref="T:System.IO.IOException">
/// If the relative resource could not be created from the supplied
/// path.
/// </exception>
/// <exception cref="T:System.NotSupportedException">
/// If the resource does not support the notion of a relative path.
/// </exception>
public IResource CreateRelative(string relativePath)
{
throw new InvalidOperationException();
}
/// <summary>
/// Does this resource represent a handle with an open stream?
/// </summary>
/// <value>
/// <see langword="true"/> if this resource represents a handle with an
/// open stream.
/// </value>
/// <remarks>
/// <p>
/// If <see langword="true"/>, the <see cref="T:System.IO.Stream"/>
/// cannot be read multiple times, and must be read and then closed to
/// avoid resource leaks.
/// </p>
/// <p>
/// Will be <see langword="false"/> for all usual resource descriptors.
/// </p>
/// </remarks>
/// <seealso cref="P:Spring.Core.IO.IInputStreamSource.InputStream"/>
public bool IsOpen
{
get { return false; }
}
/// <summary>
/// Returns the <see cref="T:System.Uri"/> handle for this resource.
/// </summary>
/// <value>The <see cref="T:System.Uri"/> handle for this resource.</value>
/// <remarks>
/// <p>
/// For safety, always check the value of the
/// <see cref="P:Spring.Core.IO.IResource.Exists"/> property prior to
/// accessing this property; resources that cannot be exposed as
/// a <see cref="T:System.Uri"/> will typically return
/// <see langword="false"/> from a call to the
/// <see cref="P:Spring.Core.IO.IResource.Exists"/> property.
/// </p>
/// </remarks>
/// <exception cref="T:System.IO.IOException">
/// If the resource is not available or cannot be exposed as a
/// <see cref="T:System.Uri"/>.
/// </exception>
/// <seealso cref="T:Spring.Core.IO.IResource"/>
/// <seealso cref="P:Spring.Core.IO.IResource.Exists"/>
public Uri Uri
{
get { return new Uri(_containingAssemblyFileName); }
}
/// <summary>
/// Returns a <see cref="T:System.IO.FileInfo"/> handle for this resource.
/// </summary>
/// <value>
/// The <see cref="T:System.IO.FileInfo"/> handle for this resource.
/// </value>
/// <remarks>
/// <p>
/// For safety, always check the value of the
/// <see cref="P:Spring.Core.IO.IResource.Exists"/> property prior to
/// accessing this property; resources that cannot be exposed as
/// a <see cref="T:System.IO.FileInfo"/> will typically return
/// <see langword="false"/> from a call to the
/// <see cref="P:Spring.Core.IO.IResource.Exists"/> property.
/// </p>
/// </remarks>
/// <exception cref="T:System.IO.IOException">
/// If the resource is not available on a filesystem, or cannot be
/// exposed as a <see cref="T:System.IO.FileInfo"/> handle.
/// </exception>
/// <seealso cref="T:Spring.Core.IO.IResource"/>
/// <seealso cref="P:Spring.Core.IO.IResource.Exists"/>
public FileInfo File
{
get { return new FileInfo(_containingAssemblyFileName); }
}
/// <summary>
/// Returns a description for this resource.
/// </summary>
/// <value>A description for this resource.</value>
/// <remarks>
/// <p>
/// The description is typically used for diagnostics and other such
/// logging when working with the resource.
/// </p>
/// <p>
/// Implementations are also encouraged to return this value from their
/// <see cref="M:System.Object.ToString"/> method.
/// </p>
/// </remarks>
public string Description
{
get { return _type.FullName; }
}
/// <summary>
/// Does this resource actually exist in physical form?
/// </summary>
/// <value>
/// <see langword="true"/> if this resource actually exists in physical
/// form (for example on a filesystem).
/// </value>
/// <remarks>
/// <p>
/// 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.
/// </p>
/// </remarks>
/// <seealso cref="P:Spring.Core.IO.IResource.File"/>
/// <seealso cref="P:Spring.Core.IO.IResource.Uri"/>
public bool Exists
{
get { return System.IO.File.Exists(_containingAssemblyFileName); }
}
/// <summary>
/// Return an <see cref="T:System.IO.Stream"/> for this resource.
/// </summary>
/// <value>An <see cref="T:System.IO.Stream"/>.</value>
/// <remarks>
/// <note type="caution">
/// Clients of this interface must be aware that every access of this
/// property will create a <i>fresh</i>
/// <see cref="T:System.IO.Stream"/>;
/// it is the responsibility of the calling code to close any such
/// <see cref="T:System.IO.Stream"/>.
/// </note>
/// </remarks>
/// <exception cref="T:System.IO.IOException">
/// If the stream could not be opened.
/// </exception>
public Stream InputStream
{
get { throw new InvalidOperationException(); }
}
#endregion
}
}

View File

@@ -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
{
/// <summary>
/// Enhances Configuration classes by generating a dynamic proxy capable of
/// interacting with the Spring container to respect object semantics.
/// </summary>
/// <author>Chris Beams</author>
/// <author>Juergen Hoeller</author>
/// <author>Bruno Baia (.NET)</author>
/// <seealso cref="ConfigurationClassPostProcessor"/>
public class ConfigurationClassEnhancer
{
private IConfigurationClassInterceptor interceptor;
/// <summary>
/// Creates a new instance of the <see cref="ConfigurationClassEnhancer"/> class.
/// </summary>
/// <param name="objectFactory">
/// The supplied ObjectFactory to check for the existence of object definitions.
/// </param>
public ConfigurationClassEnhancer(IConfigurableListableObjectFactory objectFactory)
{
AssertUtils.ArgumentNotNull(objectFactory, "objectFactory");
this.interceptor = new ConfigurationClassInterceptor(objectFactory);
}
/// <summary>
/// Generates a dynamic subclass of the specified Configuration class with a
/// container-aware interceptor capable of respecting scoping and other bean semantics.
/// </summary>
/// <param name="configClass">The Configuration class.</param>
/// <returns>The enhanced subclass.</returns>
public Type Enhance(Type configClass)
{
ConfigurationClassProxyTypeBuilder proxyTypeBuilder = new ConfigurationClassProxyTypeBuilder(configClass, this.interceptor);
return proxyTypeBuilder.BuildProxyType();
}
/// <summary>
/// Intercepts the invocation of any <see cref="ObjectDefAttribute"/>-decorated methods in order
/// to ensure proper handling of object semantics such as scoping and AOP proxying.
/// </summary>
public interface IConfigurationClassInterceptor
{
/// <summary>
/// Process the <see cref="ObjectDefAttribute"/>-decorated method to check
/// for the existence of this object.
/// </summary>
/// <param name="method">The method providing the object definition.</param>
/// <param name="instance">When this method returns true, contains the object definition.</param>
/// <returns>true if the object exists; otherwise, false.</returns>
bool ProcessDefinition(MethodInfo method, out object instance);
}
private sealed class ConfigurationClassInterceptor : IConfigurationClassInterceptor
{
#region Logging
private static readonly ILog Logger = LogManager.GetLogger<ConfigurationClassInterceptor>();
#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
}
}

View File

@@ -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
{
/// <summary>
/// Represents a <see cref="ConfigurationAttribute"/> class method marked with the <see cref="ObjectDefAttribute"/>.
/// </summary>
public class ConfigurationClassMethod
{
private readonly ConfigurationClass _configurationClass;
private readonly MethodInfo _methodInfo;
/// <summary>
/// Initializes a new instance of the ConfigurationClassMethod class.
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="configurationClass"></param>
public ConfigurationClassMethod(MethodInfo methodInfo, ConfigurationClass configurationClass)
{
_methodInfo = methodInfo;
_configurationClass = configurationClass;
}
/// <summary>
/// Gets the configuration class.
/// </summary>
/// <value>The configuration class.</value>
public ConfigurationClass ConfigurationClass
{
get { return _configurationClass; }
}
/// <summary>
/// Gets the method metadata.
/// </summary>
/// <value>The method metadata.</value>
public MethodInfo MethodMetadata
{
get { return _methodInfo; }
}
/// <summary>
/// Gets the resource location.
/// </summary>
/// <value>The resource location.</value>
public Location ResourceLocation
{
get { return new Location(_configurationClass.Resource, _methodInfo); }
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return string.Format("{0}:name={1},declaringClass={2}", GetType().Name, _methodInfo.Name,
_methodInfo.DeclaringType.FullName);
}
/// <summary>
/// Validates the specified problem reporter.
/// </summary>
/// <param name="problemReporter">The problem reporter.</param>
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)
{
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Reads the class with the <see cref="ConfigurationAttribute"/> applied and converts it into an <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/> instance.
/// </summary>
public class ConfigurationClassObjectDefinitionReader
{
private static readonly ILog Logger = LogManager.GetLogger<ConfigurationClassObjectDefinitionReader>();
private IProblemReporter _problemReporter;
private IObjectDefinitionRegistry _registry;
/// <summary>
/// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class.
/// </summary>
/// <param name="registry"></param>
/// <param name="problemReporter"></param>
public ConfigurationClassObjectDefinitionReader(IObjectDefinitionRegistry registry,
IProblemReporter problemReporter)
{
_registry = registry;
_problemReporter = problemReporter;
}
private static bool HasAttributeOnMethods(Type objectType, Type attributeType)
{
Collections.Generic.ISet<MethodInfo> methods = ConfigurationClassParser.GetAllMethodsWithCustomAttributeForClass(objectType,
attributeType);
foreach (MethodInfo method in methods)
{
if (Attribute.GetCustomAttribute(method, attributeType) != null)
{
return true;
}
}
return false;
}
/// <summary>
/// Loads the object definitions.
/// </summary>
/// <param name="configurationModel">The configuration model.</param>
public void LoadObjectDefinitions(Collections.Generic.ISet<ConfigurationClass> 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));
}
}
/// <summary>
/// Checks the class to see if it is a candidate to be a <see cref="ConfigurationAttribute"/> source.
/// </summary>
/// <param name="objectDefinition">The object definition.</param>
/// <returns></returns>
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<String, Object> ObjectAttributes = metadata.getAnnotationAttributes(Object.class.getName());
object[] objectAttributes = metadata.GetCustomAttributes(typeof(ObjectDefAttribute), true);
List<string> names = new List<string>();
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<KeyValuePair<string, Type>> importedResources)
{
IDictionary<Type, IObjectDefinitionReader> readerInstanceCache =
new Dictionary<Type, IObjectDefinitionReader>();
foreach (KeyValuePair<string, Type> 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
{
}
}
}

View File

@@ -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
{
/// <summary>
/// Parses classes with the <see cref="ConfigurationAttribute"/> applied to them.
/// </summary>
public class ConfigurationClassParser
{
private Collections.Generic.ISet<ConfigurationClass> _configurationClasses = new HashedSet<ConfigurationClass>();
private Stack<ConfigurationClass> _importStack = new Stack<ConfigurationClass>();
private IProblemReporter _problemReporter;
/// <summary>
/// Initializes a new instance of the ConfigurationClassParser class.
/// </summary>
/// <param name="problemReporter"></param>
public ConfigurationClassParser(IProblemReporter problemReporter)
{
_problemReporter = problemReporter;
}
/// <summary>
/// Gets the configuration classes.
/// </summary>
/// <value>The configuration classes.</value>
public Collections.Generic.ISet<ConfigurationClass> ConfigurationClasses
{
get { return _configurationClasses; }
}
/// <summary>
/// Parses the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="objectName">Name of the object.</param>
public void Parse(Type type, string objectName)
{
ProcessConfigurationClass(new ConfigurationClass(objectName, type));
}
/// <summary>
/// Validates this instance.
/// </summary>
public void Validate()
{
foreach (ConfigurationClass configClass in ConfigurationClasses)
{
configClass.Validate(_problemReporter);
}
}
/// <summary>
/// Processes the configuration class.
/// </summary>
/// <param name="configurationClass">The configuration class.</param>
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<MethodInfo> definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(ObjectDefAttribute));
foreach (MethodInfo definitionMethod in definitionMethods)
{
configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass));
}
}
/// <summary>
/// Gets all methods with custom attribute for class.
/// </summary>
/// <param name="theClass">The class.</param>
/// <param name="customAttribute">The custom attribute.</param>
/// <returns></returns>
public static Collections.Generic.ISet<MethodInfo> GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute)
{
Collections.Generic.ISet<MethodInfo> methods = new HashedSet<MethodInfo>();
foreach (MethodInfo method in theClass.GetMethods())
{
if (Attribute.GetCustomAttribute(method, customAttribute) != null)
{
methods.Add(method);
}
}
return methods;
}
private void ProcessImport(ConfigurationClass configClass, IEnumerable<Type> 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<ConfigurationClass> 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)
)
{ }
}
}
}

View File

@@ -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
{
/// <summary>
/// Postprocesses the <see cref="ConfigurationAttribute"/> applied types registered with the <see cref="IApplicationContext"/>.
/// </summary>
public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor, IOrdered
{
#region Logging
private static readonly ILog Logger = LogManager.GetLogger<ConfigurationClassPostProcessor>();
#endregion
private bool _postProcessObjectDefinitionRegistryCalled;
private bool _postProcessObjectFactoryCalled;
private IProblemReporter _problemReporter = new FailFastProblemReporter();
/// <summary>
/// Return the order value of this object, where a higher value means greater in
/// terms of sorting.
/// </summary>
/// <value></value>
/// <remarks>
/// <p>
/// Normally starting with 0 or 1, with <see cref="F:System.Int32.MaxValue"/> indicating
/// greatest. Same order values will result in arbitrary positions for the affected
/// objects.
/// </p>
/// <p>
/// Higher value can be interpreted as lower priority, consequently the first object
/// has highest priority.
/// </p>
/// </remarks>
/// <returns>The order value.</returns>
public int Order
{
get { return int.MinValue; }
}
/// <summary>
/// Sets the problem reporter.
/// </summary>
/// <value>The problem reporter.</value>
public IProblemReporter ProblemReporter
{
set { _problemReporter = (value ?? new FailFastProblemReporter()); }
}
/// <summary>
/// Postsprocesses the object definition registry.
/// </summary>
/// <param name="registry">The registry.</param>
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);
}
/// <summary>
/// Postprocesses the object factory.
/// </summary>
/// <param name="objectFactory">The object factory.</param>
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<string> 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<ObjectDefinitionHolder> configCandidates = new HashedSet<ObjectDefinitionHolder>();
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);
}
}
}

View File

@@ -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
{
/// <summary>
/// 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.
/// <para>Note: This attribute will not be inherited by child object definitions,
/// hence it needs to be specified per concrete object definition.
/// </para>
/// <para>Using <see cref="DependsOnAttribute"/> at the class level has no effect unless component-scanning
/// is being used. If a <see cref="DependsOnAttribute"/>-attributed class is declared via XML,
/// <see cref="DependsOnAttribute"/> attribute metadata is ignored, and
/// &lt;object depends-on="..."/&gt; is respected instead.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class DependsOnAttribute : Attribute
{
private string[] _name;
/// <summary>
/// Initializes a new instance of the DependsOn class.
/// </summary>
/// <param name="name"></param>
public DependsOnAttribute(params string[] name)
{
_name = name;
}
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string[] Name
{
get { return _name; }
set
{
_name = value;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Scanner that can filter types from assemblies based on constraints.
/// </summary>
public interface IAssemblyTypeScanner
{
/// <summary>
/// Add the Assembly containing the specified <see cref="Type"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
IAssemblyTypeScanner AssemblyHavingType<T>();
/// <summary>
/// Adds the predicate to the assembly filter constraints.
/// </summary>
/// <param name="assemblyPredicate">The assembly predicate.</param>
/// <returns></returns>
IAssemblyTypeScanner WithAssemblyFilter(Predicate<Assembly> assemblyPredicate);
/// <summary>
/// Adds the predicte to the include filter for <see cref="Type"/>.
/// </summary>
/// <param name="predicate">The predicate.</param>
/// <returns></returns>
IAssemblyTypeScanner WithIncludeFilter(Predicate<Type> predicate);
/// <summary>
/// Adds the predicte to the exclude filter for <see cref="Type"/>.
/// </summary>
/// <param name="predicate">The predicate.</param>
/// <returns></returns>
IAssemblyTypeScanner WithExcludeFilter(Predicate<Type> predicate);
/// <summary>
/// Includes the specific types.
/// </summary>
/// <param name="typeSource">The types.</param>
/// <returns></returns>
IAssemblyTypeScanner IncludeTypes(IEnumerable<Type> typeSource);
/// <summary>
/// Includes the type.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> to include.</typeparam>
/// <returns></returns>
IAssemblyTypeScanner IncludeType<T>();
/// <summary>
/// Excludes the type.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> to exclude.</typeparam>
/// <returns></returns>
IAssemblyTypeScanner ExcludeType<T>();
/// <summary>
/// Perform the Scan, applying all provided
/// </summary>
/// <returns></returns>
IEnumerable<Type> Scan();
}
}

View File

@@ -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
{
/// <summary>
/// Indicates one or more <see cref="ConfigurationAttribute"/> classes to import.
///
/// <para>Provides functionality equivalent to the &lt;import/&gt; element in Spring XML.
/// Only supported for actual <see cref="ConfigurationAttribute"/>-attributed classes.
/// </para>
///
/// <para>If XML or other non-<see cref="ConfigurationAttribute"/> object definition resources need to be
/// imported, use <see cref="ImportResourceAttribute"/>
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ImportAttribute : Attribute
{
private Type[] _types;
/// <summary>
/// Initializes a new instance of the Import class.
/// </summary>
/// <param name="types"></param>
public ImportAttribute(params Type[] types)
{
_types = types;
}
/// <summary>
/// The <see cref="ConfigurationAttribute"/> class or classes to import.
/// </summary>
/// <value>The type.</value>
public Type[] Types
{
get { return _types; }
set
{
_types = value;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Supports providing one or more <see cref="IResource"/> implementations to import when creating <see cref="RootObjectDefinition"/>s.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ImportResourceAttribute : Attribute
{
private Type _objectDefinitionReader = typeof(XmlObjectDefinitionReader);
private string[] _resources;
/// <summary>
/// Initializes a new instance of the ImportResourceAttribute class.
/// </summary>
/// <param name="resources"></param>
public ImportResourceAttribute(string[] resources)
{
if (resources ==null || resources.Length ==0)
throw new ArgumentException("resources cannot be null or empty!");
_resources = resources;
}
/// <summary>
/// Initializes a new instance of the ImportResourceAttribute class.
/// </summary>
/// <param name="resource"></param>
public ImportResourceAttribute(string resource)
{
if (StringUtils.IsNullOrEmpty(resource))
throw new ArgumentException("resource cannot be null or empty!");
_resources = new[] { resource };
}
/// <summary>
/// <see cref="IObjectDefinitionReader"/> implementation to use when processing resources specified
/// by the <see cref="Resources"/> attribute.
/// </summary>
/// <value>The <see cref="IObjectDefinitionReader"/>.</value>
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;
}
}
/// <summary>
/// Resource paths to import. Resource-loading prefixes such as <code>assembly://</code> and
/// <code>file://</code>, etc may be used.
/// </summary>
/// <value>The resources.</value>
public string[] Resources
{
get { return _resources; }
set
{
_resources = value;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Indicates whether a object is to be lazily initialized.
///
/// <para>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 <see cref="Spring.Objects.Factory.IObjectFactory"/>.
/// If present and set to false, the object will be instantiated on startup by object factories
/// that perform eager initialization of singletons.
/// </para>
/// <para>
/// If Lazy is present on a <see cref="ConfigurationAttribute"/> class, this indicates that all
/// <see cref="ObjectDefAttribute"/> methods within that <see cref="ConfigurationAttribute"/> 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.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class LazyAttribute : Attribute
{
private bool _lazyInitialize = true;
/// <summary>
/// Initializes a new instance of the LazyAttribute class.
/// </summary>
/// <param name="lazyInitialize"></param>
public LazyAttribute(bool lazyInitialize)
{
_lazyInitialize = lazyInitialize;
}
/// <summary>
/// Initializes a new instance of the LazyAttribute class.
/// </summary>
public LazyAttribute()
{
}
/// <summary>
/// Whether lazy initialization should occur.
/// </summary>
/// <value><c>true</c> if [lazy initialize]; otherwise, <c>false</c>.</value>
public bool LazyInitialize
{
get { return _lazyInitialize; }
set
{
_lazyInitialize = value;
}
}
}
}

View File

@@ -0,0 +1,110 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// 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.
/// </summary>
internal static class LinqExtensionMethods
{
public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw new ArgumentNullException("source");
int counter = 0;
foreach (TSource obj in source)
{
counter++;
}
return counter;
}
internal static bool Contains<TSource>(this IEnumerable<TSource> 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<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw new ArgumentNullException("source");
IList<TSource> results = new List<TSource>();
foreach (TSource obj in source)
{
results.Add(obj);
}
return results;
}
internal static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Predicate<TSource> predicate)
{
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
IList<TSource> matching = new List<TSource>();
foreach (TSource obj in source)
{
if (predicate(obj))
{
matching.Add(obj);
}
}
return matching;
}
internal static bool Any<TSource>(this IEnumerable<TSource> source, Predicate<TSource> 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;
}
}
}

View File

@@ -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
{
/// <summary>
/// Identifies the Method as providing and Object Definition.
/// </summary>
[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
///// <summary>
///// Are dependencies to be injected via autowiring?
///// </summary>
///// <value>The auto wire.</value>
//public AutoWiringMode AutoWire
//{
// get { return _autoWire; }
// set
// {
// _autoWire = value;
// }
//}
/// <summary>
/// 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.
/// <para>
/// 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.
/// </para>
/// <see cref="Spring.Context.IConfigurableApplicationContext"/>
/// </summary>
/// <value>The destroy method.</value>
public string DestroyMethod
{
get { return _destroyMethod; }
set
{
_destroyMethod = value;
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The init method.</value>
public string InitMethod
{
get { return _initMethod; }
set
{
_initMethod = value;
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The name.</value>
public string Names
{
get
{
return _names;
}
set
{
_names = value;
}
}
/// <summary>
/// Gets the comma-delimited list of names/aliases as an array.
/// </summary>
/// <value>The array of names.</value>
public string[] NamesToArray
{
get
{
return StringUtils.DelimitedListToStringArray(_names, ",");
}
}
}
}

View File

@@ -0,0 +1,107 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Utilities to provide support for manipulating ReflectionOnly types in the <see cref="AppDomain"/>.
/// </summary>
public static class ReflectionOnlyUtils
{
/// <summary>
/// Load the <see cref="Assembly"/> into the ReflectionsOnly context based on its partial name.
/// </summary>
/// <param name="partialName">The partial name.</param>
/// <returns>The matching <see cref="Assembly"/></returns>
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<MethodInfo> 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;
}
}
}

View File

@@ -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
{
/// <summary>
/// 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.
/// </summary>
[Serializable]
public abstract class RequiredConstraintAssemblyTypeScanner : AssemblyTypeScanner
{
/// <summary>
/// Determines whether the compound predicate is satisfied by the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if the compound predicate is satisfied by the specified type; otherwise, <c>false</c>.
/// </returns>
protected override bool IsCompoundPredicateSatisfiedBy(Type type)
{
return IsRequiredConstraintSatisfiedBy(type) && IsIncludedType(type) && !IsExcludedType(type);
}
/// <summary>
/// Determines whether the required constraint is satisfied by the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// <c>true</c> if the required constraint is satisfied by the specified type; otherwise, <c>false</c>.
/// </returns>
protected abstract bool IsRequiredConstraintSatisfiedBy(Type type);
}
}

View File

@@ -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
{
/// <summary>
/// A GenericObjectDefinition that provides attribute driven propulation
/// of properties like LazyInit, Scope or Qualifier
/// </summary>
public class ScannedGenericObjectDefinition : GenericObjectDefinition
{
/// <summary>
/// Name provided by the Component Attribute
/// </summary>
private string _componentName;
/// <summary>
/// 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
/// </summary>
/// <param name="typeOfObject">Type of scanned component</param>
/// <param name="defaults">Defualts provided in Spring Config document</param>
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);
}
}
}
}
/// <summary>
/// Provides the name of the object scanned
/// </summary>
/// <returns>return the provided attribute name of the full object type name</returns>
public string ComponentName
{
get
{
return _componentName;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// When used as a type-level attribute, indicates the name of a scope to use
/// for instances of the attributed type.
///
/// <para>When used as a method-level attribute in conjunction with the
/// <see cref="ObjectDefAttribute"/> attribute, indicates the name of a scope to use for
/// the instance returned from the method.
/// </para>
/// <para>In this context, scope means the lifecycle of an instance, such as
/// <code>singleton</code>, <code>prototype</code>, and so forth.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ScopeAttribute : Attribute
{
private ObjectScope _scope = ObjectScope.Singleton;
/// <summary>
/// Initializes a new instance of the Scope class.
/// </summary>
/// <param name="scope"></param>
public ScopeAttribute(ObjectScope scope)
{
_scope = scope;
}
/// <summary>
/// Specifies the scope to use for the annotated object.
/// </summary>
/// <value>The scope.</value>
public ObjectScope ObjectScope
{
get { return _scope; }
set
{
_scope = value;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Abstract Type Filter that provides methods to load a required type from assembly.
/// </summary>
public abstract class AbstractLoadTypeFilter : ITypeFilter
{
private static readonly ILog Logger = LogManager.GetLogger<AbstractLoadTypeFilter>();
/// <summary>
/// Required Type to compare against provided Type
/// </summary>
protected Type RequiredType;
/// <summary>
/// Determine a match based on the given type object.
/// </summary>
/// <param name="type"></param>
/// <returns>true if there is a match; false is there is no match</returns>
public abstract bool Match(Type type);
/// <summary>
/// Is loading a Type from a string passed to method in the form [Type.FullName], [Assembly.Name]
/// </summary>
protected void GetRequiredType(string typeToLoad)
{
try
{
RequiredType = TypeResolutionUtils.ResolveType(typeToLoad);
}
catch (Exception)
{
RequiredType = null;
Logger.Error("Can't load type defined in exoression:" + typeToLoad);
}
}
}
}

View File

@@ -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
{
/// <summary>
/// A simple filter which matches classes that are assignable to a given type.
/// </summary>
public class AssignableTypeFilter : AbstractLoadTypeFilter
{
/// <summary>
/// Create a Type Filter with required type
/// </summary>
/// <param name="expression">type name including assembly name</param>
public AssignableTypeFilter(string expression)
{
GetRequiredType(expression);
}
/// <summary>
/// Determine a match based on the given type object.
/// </summary>
/// <param name="type">Type to compare against</param>
/// <returns>true if there is a match; false is there is no match</returns>
public override bool Match(Type type)
{
if (RequiredType == null)
return false;
return (type.GetInterfaces().Any(i => i.Equals(RequiredType)) || RequiredType.Equals(type.BaseType));
}
}
}

View File

@@ -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
{
/// <summary>
/// A simple filter which matches classes with a given attribute,
/// checking inherited annotations as well.
/// </summary>
public class AttributeTypeFilter : AbstractLoadTypeFilter
{
/// <summary>
/// Creates a Type Filter with required type attribute
/// </summary>
/// <param name="expression"></param>
public AttributeTypeFilter(string expression)
{
GetRequiredType(expression);
}
/// <summary>
/// Determine a match based on the given type object.
/// </summary>
/// <param name="type">Type to compare against</param>
/// <returns>true if there is a match; false is there is no match</returns>
public override bool Match(Type type)
{
if (RequiredType == null)
return false;
return (Attribute.GetCustomAttribute(type, RequiredType) != null);
}
}
}

View File

@@ -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
{
/// <summary>
/// Creates a new instance of a givin type string
/// </summary>
public static class CustomTypeFactory
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(CustomTypeFactory).FullName);
/// <summary>
/// Creates a new instance of given type filter type string
/// </summary>
/// <param name="expression">Custom type filter to create</param>
/// <returns>An instance of ITypeFilter or NULL if no instance can be created</returns>
public static ITypeFilter GetTypeFilter(string expression)
{
return GetCustomType(expression) as ITypeFilter;
}
/// <summary>
/// Creates a new instance of given name generator type string
/// </summary>
/// <param name="expression">Custom type name generator string to create</param>
/// <returns>An instance of IObjectNameGenerator or NULL if no instance can be created</returns>
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;
}
}
}

View File

@@ -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
{
/// <summary>
/// Represents the base interface for all component-scan type filters
/// </summary>
public interface ITypeFilter
{
/// <summary>
/// Determine a match based on the given type object.
/// </summary>
/// <param name="type"></param>
/// <returns>true if there is a match; false is there is no match</returns>
bool Match(Type type);
}
}

View File

@@ -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
{
/// <summary>
/// A simple filter for matching a fully-qualified class name with a regex
/// </summary>
public class RegexPatternTypeFilter : ITypeFilter
{
private string _pattern;
/// <summary>
/// Creates a type filter with provided pattern
/// </summary>
/// <param name="pattern">Regex pattern</param>
public RegexPatternTypeFilter(string pattern)
{
_pattern = pattern;
}
/// <summary>
/// Determine a match based on the given type object.
/// </summary>
/// <param name="type">Type to compare against</param>
/// <returns>true if there is a match; false is there is no match</returns>
public bool Match(Type type)
{
return Regex.IsMatch(type.FullName, _pattern);
}
}
}

View File

@@ -0,0 +1,61 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Object Defintion Parser for interpreting <see cref="ConfigurationAttribute"/> classes when primary configuration is peformed via XML.
/// </summary>
public class AttributeConfigObjectDefinitionParser : IObjectDefinitionParser
{
/// <summary>
/// Parse the specified XmlElement and register the resulting
/// ObjectDefinitions with the <see cref="P:Spring.Objects.Factory.Xml.ParserContext.Registry"/> IObjectDefinitionRegistry
/// embedded in the supplied <see cref="T:Spring.Objects.Factory.Xml.ParserContext"/>
/// </summary>
/// <param name="element">The element to be parsed.</param>
/// <param name="parserContext">TThe object encapsulating the current state of the parsing process.
/// Provides access to a IObjectDefinitionRegistry</param>
/// <returns>The primary object definition.</returns>
/// <remarks>
/// <p>
/// This method is never invoked if the parser is namespace aware
/// and was called to process the root node.
/// </p>
/// </remarks>
public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
{
IObjectDefinitionRegistry registry = parserContext.ReaderContext.Registry;
AssertUtils.ArgumentNotNull(registry, "registry");
AttributeConfigUtils.RegisterAttributeConfigProcessors(registry);
return null;
}
}
}

View File

@@ -0,0 +1,159 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Parses ObjectDefinitions from classes identified by an <see cref="AssemblyObjectDefinitionScanner"/>.
/// </summary>
public class ComponentScanObjectDefinitionParser : IObjectDefinitionParser
{
private static readonly ILog Logger = LogManager.GetLogger<ComponentScanObjectDefinitionParser>();
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";
/// <summary>
/// Parse the specified XmlElement and register the resulting
/// ObjectDefinitions with the <see cref="P:Spring.Objects.Factory.Xml.ParserContext.Registry"/> IObjectDefinitionRegistry
/// embedded in the supplied <see cref="T:Spring.Objects.Factory.Xml.ParserContext"/>
/// </summary>
/// <param name="element">The element to be parsed.</param>
/// <param name="parserContext">TThe object encapsulating the current state of the parsing process.
/// Provides access to a IObjectDefinitionRegistry</param>
/// <returns>The primary object definition.</returns>
/// <remarks>
/// <p>
/// This method is never invoked if the parser is namespace aware
/// and was called to process the root node.
/// </p>
/// </remarks>
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;
}
/// <summary>
/// Configures the scanner.
/// </summary>
/// <param name="parserContext">The parser context.</param>
/// <param name="element">The element.</param>
/// <returns></returns>
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));
}
}
}
}

View File

@@ -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
{
/// <summary>
/// <code>NamespaceParser</code> 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
/// <code>&lt;tx:advice&gt;</code> elements, the other uses attributes
/// in combination with the <code>&lt;tx:annotation-driven&gt;</code> element.
/// Both approached are detailed in the Spring reference manual.
/// </summary>
[
NamespaceParser(
Namespace = "http://www.springframework.net/context",
SchemaLocationAssemblyHint = typeof(ContextNamespaceParser),
SchemaLocation = "/Spring.Context.Config/spring-context-2.0.xsd"
)
]
public class ContextNamespaceParser : NamespaceParserSupport
{
/// <summary>
/// Register the <see cref="IObjectDefinitionParser"/> for the '<code>advice</code>' and
/// '<code>attribute-driven'</code> tags.
/// </summary>
public override void Init()
{
RegisterObjectDefinitionParser("attribute-config", new AttributeConfigObjectDefinitionParser());
RegisterObjectDefinitionParser("component-scan", new ComponentScanObjectDefinitionParser());
}
}
}

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.net/context"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:objects="http://www.springframework.net"
xmlns:tool="http://www.springframework.net/tool"
targetNamespace="http://www.springframework.net/context"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.net"/>
<xsd:import namespace="http://www.springframework.net/tool"/>
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Framework's application
context support. Effects the activation of various configuration styles
for the containing Spring ApplicationContext.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="code-config">
<xsd:annotation>
<xsd:documentation><![CDATA[
Scans assemblies for [Configuration] attributes that provide Spring object definitions.
]]></xsd:documentation>
</xsd:annotation>
<!--
<xsd:complexType>
<xsd:attribute name="assemblies" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The names of assemblies to be scanned.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
-->
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.net/context"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:objects="http://www.springframework.net"
xmlns:tool="http://www.springframework.net/tool"
targetNamespace="http://www.springframework.net/context"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.net"/>
<xsd:import namespace="http://www.springframework.net/tool"/>
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Framework's application
context support. Effects the activation of various configuration styles
for the containing Spring ApplicationContext.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="attribute-config">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Activates various attributes to be detected in object classes: Spring's [Required],
[Autowired], [Value] as well [PostConstruct], [PreDestroy]. Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Spring's [Transactional].
Consider the use of the <tx:annotation-driven> tag for that purpose.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="component-scan">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Scans assemblies for attributed components that will be auto-registered as
Spring objects. By default, the Spring-provided [Component], [Repository],
[Service], and [Controller] stereotypes will be detected.
Note: This tag implies the effects of the 'attribute-config' tag, activating [Required],
[Autowired], [PostConstruct], [PreDestroy]
attributes in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom ObjectPostProcessor definitions
for handling those annotations.
Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definition
being registered; Spring's PropertyPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="include-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Controls which eligible types to include for component scanning.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="exclude-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Controls which eligible types to exclude for component scanning.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="base-assemblies" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The comma-separated list of assemblies to scan for attributed components.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="attribute-config" type="xsd:boolean" default="true">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Indicates if attribte driven post processors will be registered, default is true.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name-generator" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The fully-qualified class name of the BeanNameGenerator to be used for naming detected components.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:expected-type type="java.lang.Class" />
<tool:assignable-to
type="org.springframework.beans.factory.support.BeanNameGenerator" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="filterType">
<xsd:attribute name="type" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Controls the type of filtering to apply to the expression.
"attribute" indicates an attribute to be present or excluded at the type level in target components;
"assignable" indicates a class (or interface) that the target components are assignable to (extend/implement);
"regex" indicates a regex expression to be matched by the target components' class names;
Note: This attribute will not be inherited by child bean definitions.
Hence, it needs to be specified per concrete bean definition.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="assignable" />
<xsd:enumeration value="attribute" />
<xsd:enumeration value="custom" />
<xsd:enumeration value="regex" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="expression" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Indicates the filter expression, the type of which is indicated by "type".
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:schema>

View File

@@ -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
{
/// <summary>
/// Extensions to enable scanning on any AbstractApplicationContext-derived type.
/// </summary>
public static class GenericApplicationContextExtensions
{
/// <summary>
/// Scans for types using the provided scanner.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="scanner">The scanner.</param>
public static void Scan(this GenericApplicationContext context, AssemblyObjectDefinitionScanner scanner)
{
var registry = context.ObjectFactory as IObjectDefinitionRegistry;
scanner.ScanAndRegisterTypes(registry);
AttributeConfigUtils.RegisterAttributeConfigProcessors(registry);
}
/// <summary>
/// Scans for types that satisfy specified predicates located in the specified scan path.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="assemblyScanPath">The assembly scan path.</param>
/// <param name="assemblyPredicate">The assembly predicate.</param>
/// <param name="typePredicate">The type predicate.</param>
public static void Scan(this GenericApplicationContext context, string assemblyScanPath, Predicate<Assembly> assemblyPredicate,
Predicate<Type> 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);
}
/// <summary>
/// Scans for types that satisfy specified predicates.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="assemblyPredicate">The assembly predicate.</param>
/// <param name="typePredicate">The type predicate.</param>
public static void Scan(this GenericApplicationContext context, Predicate<Assembly> assemblyPredicate, Predicate<Type> typePredicate)
{
Scan(context, null, assemblyPredicate, typePredicate);
}
/// <summary>
/// Scans for types using the default scanner.
/// </summary>
/// <param name="context">The context.</param>
public static void ScanAllAssemblies(this GenericApplicationContext context)
{
Scan(context, new AssemblyObjectDefinitionScanner());
}
/// <summary>
/// Scans the with assembly filter.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="assemblyPredicate">The assembly predicate.</param>
public static void ScanWithAssemblyFilter(this GenericApplicationContext context, Predicate<Assembly> assemblyPredicate)
{
Scan(context, null, assemblyPredicate, delegate { return true; });
}
/// <summary>
/// Scans the with type filter.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="typePredicate">The type predicate.</param>
public static void ScanWithTypeFilter(this GenericApplicationContext context, Predicate<Type> typePredicate)
{
Scan(context, null, delegate { return true; }, typePredicate);
}
}
}

View File

@@ -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
{
/// <summary>
/// ApplicationContext that can scan to identify object definitions
/// </summary>
public class CodeConfigApplicationContext : GenericApplicationContext
{
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
public CodeConfigApplicationContext()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="caseSensitive">if set to <c>true</c> names in the context are case sensitive.</param>
public CodeConfigApplicationContext(bool caseSensitive)
: base(caseSensitive)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="objectFactory">The object factory instance to use for this context.</param>
public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory)
: base(objectFactory)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="parent">The parent application context.</param>
public CodeConfigApplicationContext(IApplicationContext parent)
: base(parent)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="name">The name of the application context.</param><param name="caseSensitive">if set to <c>true</c> names in the context are case sensitive.</param><param name="parent">The parent application context.</param>
public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent)
: base(name, caseSensitive, parent)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="objectFactory">The object factory to use for this context</param><param name="parent">The parent applicaiton context.</param>
public CodeConfigApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent)
: base(objectFactory, parent)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Spring.Context.Support.GenericApplicationContext"/> class.
/// </summary>
/// <param name="name">The name of the application context.</param><param name="caseSensitive">if set to <c>true</c> names in the context are case sensitive.</param><param name="parent">The parent application context.</param><param name="objectFactory">The object factory to use for this context</param>
public CodeConfigApplicationContext(string name, bool caseSensitive, IApplicationContext parent,
DefaultListableObjectFactory objectFactory)
: base(name, caseSensitive, parent, objectFactory)
{
}
}
}

View File

@@ -177,6 +177,39 @@
<Compile Include="Context\ApplicationEventArgs.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Attributes\AssemblyObjectDefinitionScanner.cs" />
<Compile Include="Context\Attributes\AssemblyTypeScanner.cs" />
<Compile Include="Context\Attributes\AssemblyTypeSource.cs" />
<Compile Include="Context\Attributes\AttributeConfigUtils.cs" />
<Compile Include="Context\Attributes\AttributeObjectNameGenerator.cs" />
<Compile Include="Context\Attributes\ConfigurationAttribute.cs" />
<Compile Include="Context\Attributes\ConfigurationClass.cs" />
<Compile Include="Context\Attributes\ConfigurationClassAssemblyResource.cs" />
<Compile Include="Context\Attributes\ConfigurationClassEnhancer.cs" />
<Compile Include="Context\Attributes\ConfigurationClassMethod.cs" />
<Compile Include="Context\Attributes\ConfigurationClassObjectDefinitionReader.cs" />
<Compile Include="Context\Attributes\ConfigurationClassParser.cs" />
<Compile Include="Context\Attributes\ConfigurationClassPostProcessor.cs" />
<Compile Include="Context\Attributes\DependsOnAttribute.cs" />
<Compile Include="Context\Attributes\IAssemblyTypeScanner.cs" />
<Compile Include="Context\Attributes\ImportAttribute.cs" />
<Compile Include="Context\Attributes\ImportResourceAttribute.cs" />
<Compile Include="Context\Attributes\LazyAttribute.cs" />
<Compile Include="Context\Attributes\LinqExtensionMethods.cs" />
<Compile Include="Context\Attributes\ObjectDefAttribute.cs" />
<Compile Include="Context\Attributes\ReflectionOnlyUtils.cs" />
<Compile Include="Context\Attributes\RequiredConstraintAssemblyTypeScanner.cs" />
<Compile Include="Context\Attributes\ScannedGenericObjectDefinition.cs" />
<Compile Include="Context\Attributes\ScopeAttribute.cs" />
<Compile Include="Context\Attributes\TypeFilters\AbstractLoadTypeFilter.cs" />
<Compile Include="Context\Attributes\TypeFilters\AssignableTypeFilter.cs" />
<Compile Include="Context\Attributes\TypeFilters\AttributeTypeFilter.cs" />
<Compile Include="Context\Attributes\TypeFilters\CustomTypeFactory.cs" />
<Compile Include="Context\Attributes\TypeFilters\ITypeFilter.cs" />
<Compile Include="Context\Attributes\TypeFilters\RegexPatternTypeFilter.cs" />
<Compile Include="Context\Config\AttributeConfigObjectDefinitionParser.cs" />
<Compile Include="Context\Config\ComponentScanObjectDefinitionParser.cs" />
<Compile Include="Context\Config\ContextNamespaceParser.cs" />
<Compile Include="Context\EventListenerAttribute.cs">
<SubType>Code</SubType>
</Compile>
@@ -186,6 +219,7 @@
<Compile Include="Context\Events\ContextEventArgs.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Extension\GenericApplicationContextExtensions.cs" />
<Compile Include="Context\IApplicationContext.cs">
<SubType>Code</SubType>
</Compile>
@@ -234,6 +268,7 @@
<Compile Include="Context\Support\ApplicationObjectSupport.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Support\CodeConfigApplicationContext.cs" />
<Compile Include="Context\Support\ContextHandler.cs">
<SubType>Code</SubType>
</Compile>
@@ -1239,6 +1274,12 @@
<SubType>Code</SubType>
</Compile>
<None Include="ContextClassDiagram.cd" />
<EmbeddedResource Include="Context\Config\spring-context-1.3.xsd">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Context\Config\spring-context-2.0.xsd">
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="Expressions\Expression.g" />
<EmbeddedResource Include="Objects\Factory\Xml\spring-tool-1.1.xsd">
<SubType>

View File

@@ -128,62 +128,6 @@
Create a new session on demand
</summary>
</member>
<member name="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings">
<summary>
Setting for <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/>
</summary>
<author>Hailton de Castro</author>
</member>
<member name="F:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.FLUSHMODE_DEFAULT">
<summary>
Default value for <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode"/> property.
</summary>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionScopeSettings"/> with default values.
</summary>
<remarks>
Calling this constructor from your derived class leaves <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor"/>
uninitialized. See <see cref="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor"/> for more.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor(NHibernate.IInterceptor,NHibernate.FlushMode)">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings"/> with the given values and references.
</summary>
<param name="entityInterceptor">
Specify the <see cref="T:NHibernate.IInterceptor"/> to be set on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/> instance.
</param>
<param name="defaultFlushMode">
Specify the flushmode to be applied on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionScope"/> instance.
</param>
<remarks>
Calling this constructor marks all properties initialized.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor">
<summary>
Override this method to resolve an <see cref="T:NHibernate.IInterceptor"/> instance according to your chosen strategy.
</summary>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor">
<summary>
Gets the configured <see cref="T:NHibernate.IInterceptor"/> instance to be used.
</summary>
<remarks>
</remarks>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode">
<summary>
Gets or Sets the flushmode to be applied on each newly created session.
</summary>
<remarks>
This property defaults to <see cref="F:NHibernate.FlushMode.Never"/> 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.
</remarks>
</member>
<member name="T:Spring.Web.Conversation.IConversationState">
<summary>
Port to conversation. If the object is not found in the current
@@ -867,6 +811,62 @@
Returns the current context. Supports serialization and deserialization.
</summary>
</member>
<member name="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings">
<summary>
Setting for <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/>
</summary>
<author>Hailton de Castro</author>
</member>
<member name="F:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.FLUSHMODE_DEFAULT">
<summary>
Default value for <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode"/> property.
</summary>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionScopeSettings"/> with default values.
</summary>
<remarks>
Calling this constructor from your derived class leaves <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor"/>
uninitialized. See <see cref="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor"/> for more.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor(NHibernate.IInterceptor,NHibernate.FlushMode)">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings"/> with the given values and references.
</summary>
<param name="entityInterceptor">
Specify the <see cref="T:NHibernate.IInterceptor"/> to be set on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/> instance.
</param>
<param name="defaultFlushMode">
Specify the flushmode to be applied on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionScope"/> instance.
</param>
<remarks>
Calling this constructor marks all properties initialized.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor">
<summary>
Override this method to resolve an <see cref="T:NHibernate.IInterceptor"/> instance according to your chosen strategy.
</summary>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor">
<summary>
Gets the configured <see cref="T:NHibernate.IInterceptor"/> instance to be used.
</summary>
<remarks>
</remarks>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode">
<summary>
Gets or Sets the flushmode to be applied on each newly created session.
</summary>
<remarks>
This property defaults to <see cref="F:NHibernate.FlushMode.Never"/> 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.
</remarks>
</member>
<member name="T:Spring.Web.Conversation.WebConversationManager">
<summary>
This was made to stay under session scope.

View File

@@ -128,146 +128,6 @@
Create a new session on demand
</summary>
</member>
<member name="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings">
<summary>
Setting for <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/>
</summary>
<author>Hailton de Castro</author>
</member>
<member name="F:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.FLUSHMODE_DEFAULT">
<summary>
Default value for <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode"/> property.
</summary>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionScopeSettings"/> with default values.
</summary>
<remarks>
Calling this constructor from your derived class leaves <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor"/>
uninitialized. See <see cref="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor"/> for more.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor(NHibernate.IInterceptor,NHibernate.FlushMode)">
<summary>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings"/> with the given values and references.
</summary>
<param name="entityInterceptor">
Specify the <see cref="T:NHibernate.IInterceptor"/> to be set on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/> instance.
</param>
<param name="defaultFlushMode">
Specify the flushmode to be applied on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionScope"/> instance.
</param>
<remarks>
Calling this constructor marks all properties initialized.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor">
<summary>
Override this method to resolve an <see cref="T:NHibernate.IInterceptor"/> instance according to your chosen strategy.
</summary>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor">
<summary>
Gets the configured <see cref="T:NHibernate.IInterceptor"/> instance to be used.
</summary>
<remarks>
</remarks>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode">
<summary>
Gets or Sets the flushmode to be applied on each newly created session.
</summary>
<remarks>
This property defaults to <see cref="F:NHibernate.FlushMode.Never"/> 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.
</remarks>
</member>
<member name="T:Spring.Web.Conversation.IConversationManager">
<summary>
manager for Conversations.
</summary>
<author>Hailton de Castro</author>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.GetConversationById(System.String)">
<summary>
Returns the conversation if it is still alive, otherwise it returns null.
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.EndOnTimeOut">
<summary>
Ends all conversations with the timeout exceeded.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.PauseConversations">
<summary>
Close IDbConnections for <see cref="T:Spring.Web.Conversation.IConversationState"/> that
use 'session-per-conversation'. It calls
<see cref="M:Spring.Web.Conversation.IConversationState.PauseConversation"/> in all conversations.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.FreeEnded">
<summary>
Release the ended conversations And removes them.
If the conversation supports 'session-per-conversation', also close the session.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.AddConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Add conversation. If <see cref="T:Spring.Web.Conversation.IConversationManager"/> is null
it resolves to 'this'.
</summary>
<param name="conversation"></param>
<exception cref="T:System.InvalidOperationException">
If <paramref name="conversation"/> already has another manager.
</exception>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Makes the 'root conversation' of <paramref name="conversation"/>
the current active conversation and open/reopen the
<see cref="P:Spring.Web.Conversation.IConversationState.RootSessionPerConversation"/> if
the conversation supports 'session-per-conversation'. Close all
the connection for all session before.
If <see cref="P:Spring.Web.Conversation.IConversationManager.EndPaused"/> is <c>true</c> will end all
paused conversations.
</summary>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.ActiveConversation">
<summary>
Returns the active conversation if exists, otherwise returns null.
It depends on <see cref="M:Spring.Web.Conversation.IConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)"/>
</summary>
<returns></returns>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.SessionFactory">
<summary>
<para>If this is non-null run pattern 'session-per-conversation'.
Must be the same SessionFactory of the managed conversations.
</para>
</summary>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.EndPaused">
<summary>
Ends the "paused conversations" in call to <see cref="P:Spring.Web.Conversation.IConversationManager.ActiveConversation"/>.
Important: Unexpected behavior may occur if there are nested conversations,
as in <see cref="M:Spring.Web.Conversation.IConversationState.StartResumeConversation"/> only the current conversation and its parents
are started, the 'conversations children' remain paused, so these will be ended.
Defaul value: <c>false</c>.
</summary>
<remarks>
<para>When it is true, "start/resume a conversation" will cause the other to be
ended and cleaned up.
</para>
<para>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.
</para>
</remarks>
</member>
<member name="T:Spring.Web.Conversation.IConversationState">
<summary>
Port to conversation. If the object is not found in the current
@@ -423,6 +283,151 @@
Indicates that the conversation is paused.
</summary>
</member>
<member name="T:Spring.Web.Conversation.IConversationManager">
<summary>
manager for Conversations.
</summary>
<author>Hailton de Castro</author>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.GetConversationById(System.String)">
<summary>
Returns the conversation if it is still alive, otherwise it returns null.
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.EndOnTimeOut">
<summary>
Ends all conversations with the timeout exceeded.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.PauseConversations">
<summary>
Close IDbConnections for <see cref="T:Spring.Web.Conversation.IConversationState"/> that
use 'session-per-conversation'. It calls
<see cref="M:Spring.Web.Conversation.IConversationState.PauseConversation"/> in all conversations.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.FreeEnded">
<summary>
Release the ended conversations And removes them.
If the conversation supports 'session-per-conversation', also close the session.
</summary>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.AddConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Add conversation. If <see cref="T:Spring.Web.Conversation.IConversationManager"/> is null
it resolves to 'this'.
</summary>
<param name="conversation"></param>
<exception cref="T:System.InvalidOperationException">
If <paramref name="conversation"/> already has another manager.
</exception>
</member>
<member name="M:Spring.Web.Conversation.IConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Makes the 'root conversation' of <paramref name="conversation"/>
the current active conversation and open/reopen the
<see cref="P:Spring.Web.Conversation.IConversationState.RootSessionPerConversation"/> if
the conversation supports 'session-per-conversation'. Close all
the connection for all session before.
If <see cref="P:Spring.Web.Conversation.IConversationManager.EndPaused"/> is <c>true</c> will end all
paused conversations.
</summary>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.ActiveConversation">
<summary>
Returns the active conversation if exists, otherwise returns null.
It depends on <see cref="M:Spring.Web.Conversation.IConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)"/>
</summary>
<returns></returns>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.SessionFactory">
<summary>
<para>If this is non-null run pattern 'session-per-conversation'.
Must be the same SessionFactory of the managed conversations.
</para>
</summary>
</member>
<member name="P:Spring.Web.Conversation.IConversationManager.EndPaused">
<summary>
Ends the "paused conversations" in call to <see cref="P:Spring.Web.Conversation.IConversationManager.ActiveConversation"/>.
Important: Unexpected behavior may occur if there are nested conversations,
as in <see cref="M:Spring.Web.Conversation.IConversationState.StartResumeConversation"/> only the current conversation and its parents
are started, the 'conversations children' remain paused, so these will be ended.
Defaul value: <c>false</c>.
</summary>
<remarks>
<para>When it is true, "start/resume a conversation" will cause the other to be
ended and cleaned up.
</para>
<para>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.
</para>
</remarks>
</member>
<member name="T:Spring.Web.Conversation.HttpModule.ConversationModule">
<summary>
HttpModule for ending Conversations with Timeout exceeded.
</summary>
<author>Hailton de Castro</author>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.Init(System.Web.HttpApplication)">
<summary>
Add PostRequestHandlerExecute event to clear conversations with timeout exceeded.
</summary>
<param name="context"></param>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.Dispose">
<summary>
Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
</summary>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.page_Unload(System.Object,System.EventArgs)">
<summary>
Handles the Unload event of the page control.
</summary>
<param name="sender">The source of the event.</param>
<param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
<remarks>
Necessary for Redirect or Abort for any reason.
</remarks>
</member>
<member name="P:Spring.Web.Conversation.HttpModule.ConversationModule.ConversationManagerNameList">
<summary>
The Names of the <see cref="T:Spring.Web.Conversation.IConversationManager"/>s in the <see cref="T:Spring.Context.IApplicationContext"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.HttpModule.ConversationModule.ApplicationContext">
<summary>
Sets the <see cref="T:Spring.Context.IApplicationContext"/> that this
object runs in.
</summary>
<value></value>
<remarks>
<p>
Used to obtain the instances of <see cref="T:Spring.Web.Conversation.IConversationManager"/>
</p>
<p>
Invoked after population of normal object properties but before an
init callback such as
<see cref="T:Spring.Objects.Factory.IInitializingObject"/>'s
<see cref="M:Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
or a custom init-method. Invoked after the setting of any
<see cref="T:Spring.Context.IResourceLoaderAware"/>'s
<see cref="P:Spring.Context.IResourceLoaderAware.ResourceLoader"/>
property.
</p>
</remarks>
<exception cref="T:Spring.Context.ApplicationContextException">
In the case of application context initialization errors.
</exception>
<exception cref="T:Spring.Objects.ObjectsException">
If thrown by any application context methods.
</exception>
<exception cref="T:Spring.Objects.Factory.ObjectInitializationException"/>
</member>
<member name="T:Spring.Web.Conversation.InnerConversationList">
<summary>
List that make validation for Circular Dependency for <see cref="T:Spring.Web.Conversation.IConversationState"/>
@@ -590,93 +595,6 @@
<see cref="T:System.Collections.ICollection"/>
</summary>
</member>
<member name="T:Spring.Web.Conversation.WebConversationManager">
<summary>
This was made to stay under session scope.
</summary>
<author>Hailton de Castro</author>
</member>
<member name="F:Spring.Web.Conversation.WebConversationManager.mutexEditDic">
<summary>
Semaphore to synchronize writes to the dictionary.
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.GetConversationById(System.String)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.EndOnTimeOut">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.PauseConversations">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.FreeEnded">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.AddConversation(Spring.Web.Conversation.IConversationState)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="conversation"></param>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="conversation"></param>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.LoadActiveConversation">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.Dispose">
<summary>
Ends all conversations and Closes all their Session.
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.RemoveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Remove conversation.
</summary>
<param name="conversation"></param>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.ActiveConversation">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.SessionFactoryName">
<summary>
"SessionFactory" name in the current context.
This approach is required to support serialization.
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.SessionFactory">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.EndPaused">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.ApplicationContext">
<summary>
Returns the current context. Supports serialization and deserialization.
</summary>
</member>
<member name="T:Spring.Web.Conversation.WebConversationSpringState">
<summary>
Implementation of conversation in the infrastructure of Spring.
@@ -893,66 +811,148 @@
Returns the current context. Supports serialization and deserialization.
</summary>
</member>
<member name="T:Spring.Web.Conversation.HttpModule.ConversationModule">
<member name="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings">
<summary>
HttpModule for ending Conversations with Timeout exceeded.
Setting for <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/>
</summary>
<author>Hailton de Castro</author>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.Init(System.Web.HttpApplication)">
<member name="F:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.FLUSHMODE_DEFAULT">
<summary>
Add PostRequestHandlerExecute event to clear conversations with timeout exceeded.
</summary>
<param name="context"></param>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.Dispose">
<summary>
Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
Default value for <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode"/> property.
</summary>
</member>
<member name="M:Spring.Web.Conversation.HttpModule.ConversationModule.page_Unload(System.Object,System.EventArgs)">
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor">
<summary>
Handles the Unload event of the page control.
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionScopeSettings"/> with default values.
</summary>
<param name="sender">The source of the event.</param>
<param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
<remarks>
Necessary for Redirect or Abort for any reason.
Calling this constructor from your derived class leaves <see cref="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor"/>
uninitialized. See <see cref="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor"/> for more.
</remarks>
</member>
<member name="P:Spring.Web.Conversation.HttpModule.ConversationModule.ConversationManagerNameList">
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.#ctor(NHibernate.IInterceptor,NHibernate.FlushMode)">
<summary>
The Names of the <see cref="T:Spring.Web.Conversation.IConversationManager"/>s in the <see cref="T:Spring.Context.IApplicationContext"/>
Initialize a new instance of <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings"/> with the given values and references.
</summary>
<param name="entityInterceptor">
Specify the <see cref="T:NHibernate.IInterceptor"/> to be set on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionPerConversationScope"/> instance.
</param>
<param name="defaultFlushMode">
Specify the flushmode to be applied on each session provided by the <see cref="T:Spring.Data.NHibernate.Support.SessionScope"/> instance.
</param>
<remarks>
Calling this constructor marks all properties initialized.
</remarks>
</member>
<member name="M:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.ResolveEntityInterceptor">
<summary>
Override this method to resolve an <see cref="T:NHibernate.IInterceptor"/> instance according to your chosen strategy.
</summary>
</member>
<member name="P:Spring.Web.Conversation.HttpModule.ConversationModule.ApplicationContext">
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.EntityInterceptor">
<summary>
Sets the <see cref="T:Spring.Context.IApplicationContext"/> that this
object runs in.
Gets the configured <see cref="T:NHibernate.IInterceptor"/> instance to be used.
</summary>
<value></value>
<remarks>
<p>
Used to obtain the instances of <see cref="T:Spring.Web.Conversation.IConversationManager"/>
</p>
<p>
Invoked after population of normal object properties but before an
init callback such as
<see cref="T:Spring.Objects.Factory.IInitializingObject"/>'s
<see cref="M:Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
or a custom init-method. Invoked after the setting of any
<see cref="T:Spring.Context.IResourceLoaderAware"/>'s
<see cref="P:Spring.Context.IResourceLoaderAware.ResourceLoader"/>
property.
</p>
</remarks>
<exception cref="T:Spring.Context.ApplicationContextException">
In the case of application context initialization errors.
</exception>
<exception cref="T:Spring.Objects.ObjectsException">
If thrown by any application context methods.
</exception>
<exception cref="T:Spring.Objects.Factory.ObjectInitializationException"/>
</member>
<member name="P:Spring.Data.NHibernate.Support.SessionPerConversationScopeSettings.DefaultFlushMode">
<summary>
Gets or Sets the flushmode to be applied on each newly created session.
</summary>
<remarks>
This property defaults to <see cref="F:NHibernate.FlushMode.Never"/> 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.
</remarks>
</member>
<member name="T:Spring.Web.Conversation.WebConversationManager">
<summary>
This was made to stay under session scope.
</summary>
<author>Hailton de Castro</author>
</member>
<member name="F:Spring.Web.Conversation.WebConversationManager.mutexEditDic">
<summary>
Semaphore to synchronize writes to the dictionary.
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.GetConversationById(System.String)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.EndOnTimeOut">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.PauseConversations">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.FreeEnded">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.AddConversation(Spring.Web.Conversation.IConversationState)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="conversation"></param>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.SetActiveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
<param name="conversation"></param>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.LoadActiveConversation">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.Dispose">
<summary>
Ends all conversations and Closes all their Session.
</summary>
</member>
<member name="M:Spring.Web.Conversation.WebConversationManager.RemoveConversation(Spring.Web.Conversation.IConversationState)">
<summary>
Remove conversation.
</summary>
<param name="conversation"></param>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.ActiveConversation">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.SessionFactoryName">
<summary>
"SessionFactory" name in the current context.
This approach is required to support serialization.
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.SessionFactory">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.EndPaused">
<summary>
<see cref="T:Spring.Web.Conversation.IConversationManager"/>
</summary>
</member>
<member name="P:Spring.Web.Conversation.WebConversationManager.ApplicationContext">
<summary>
Returns the current context. Supports serialization and deserialization.
</summary>
</member>
</members>
</doc>

View File

@@ -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<ObjectWithAnAlias>());
Assert.That(secondObject, Is.InstanceOf<ObjectWithAnAlias>());
}
[Test]
public void Can_Respect_Assigned_Name()
{
var result = _ctx["TheName"];
Assert.That(result, Is.InstanceOf<SingleNamedObject>());
}
[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<SingletonParent>());
Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf<PrototypeChild>());
}
[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; }
}
}
}

View File

@@ -0,0 +1,30 @@
#region License
/*
* Copyright <20> 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
{
}
}

View File

@@ -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<IOrdered>();
Assert.That(TypeSources.Any(t => t.Contains(typeof (IOrdered))));
}
[Test]
public void IncludeType_T_Adds_Type()
{
_scanner.IncludeType<IOrdered>();
_scanner.IncludeType<IPriorityOrdered>();
IncludePredicates.Any(p => p(typeof (IOrdered)));
IncludePredicates.Any(p => p(typeof (IPriorityOrdered)));
}
[Test]
public void WithExcludeFilter_Excludes_Type()
{
//var scanner1 = new AssemblyObjectDefinitionScanner();
_scanner.IncludeType<TheConfigurationClass>();
_scanner.IncludeType<TheImportedConfigurationClass>();
_scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported"));
IEnumerable<Type> 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<Type> 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<Predicate<Type>> 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<Predicate<Type>>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeExclusionPredicates"));
}
}
private List<Predicate<Type>> 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<Predicate<Type>>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeInclusionPredicates"));
}
}
private List<IEnumerable<Type>> 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<IEnumerable<Type>>) (ReflectionUtils.GetInstanceFieldValue(_scanner, "TypeSources"));
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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";
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -0,0 +1,207 @@
#region License
/*
* Copyright <20> 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<ObjectDefinitionParsingException>(_context.Refresh);
}
[Test]
public void Can_Prevent_Static_Methods()
{
ScanForAndRegisterSingleType(typeof(ConfigurationClassWithStaticMethod));
Assert.Throws<ObjectDefinitionParsingException>(_context.Refresh);
}
[Test]
public void Can_Prevent_Non_Virtual_Methods()
{
ScanForAndRegisterSingleType(typeof(ConfigurationClassWithNonVirtualMethod));
Assert.Throws<ObjectDefinitionParsingException>(_context.Refresh);
}
[Test]
public void Can_Prevent_Sealed_Configuration_Types()
{
ScanForAndRegisterSingleType(typeof(ConfigurationClassThatIsSealed));
Assert.Throws<ObjectDefinitionParsingException>(_context.Refresh);
}
[Test]
public void Can_Prevent_Overloaded_Methods()
{
ScanForAndRegisterSingleType(typeof(ConfigurationClassWithOverloadedMethods));
Assert.Throws<ObjectDefinitionParsingException>(_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();
}
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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"));
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" >
<object id="xmlRegisteredObject" type="Spring.Context.Attributes.TypeRegisteredInXml, Spring.Core.Tests" />
</objects>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" >
<object id="xmlRegisteredObjectTwo" type="Spring.Context.Attributes.TypeRegisteredInXmlTwo, Spring.Core.Tests" />
</objects>

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies=""/>
</objects>

View File

@@ -0,0 +1,92 @@
#region License
/*
* Copyright <20> 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<IFooService>();
}
public T GetObject<T>()
{
return (T)DoGetInstance(typeof(T), null);
}
public T GetObject<T>(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);
}
/// <summary>
/// Resolves service instances by type.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>
/// Sequence of service instance objects matching the <paramref name="serviceType"/>.
/// </returns>
protected IEnumerable<object> DoGetAllInstances(Type serviceType)
{
foreach (string objectName in _applicationContext.GetObjectNamesForType(serviceType))
{
yield return _applicationContext.GetObject(objectName);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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
{
}
}

View File

@@ -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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
[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<NoSuchObjectDefinitionException>());
}
}
}
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
{
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:attribute-config />
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests,AnotherAssembly"/>
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="DoesNotExists"/>
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests"/>
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan />
</objects>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.ScanComponentsAndAddToContext.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.ComponentsUseSpecifiedName.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests"
name-generator="ComponentScan.NameGenerator.MyGenerator, Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.NameGenerator.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests"
name-generator="ComponentScan.NameGenerator.NotExistsGenerator, Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.NameGenerator.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.ComponentsAttributeLoad.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context"
default-lazy-init="true">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.ComponentsUseDefaults.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression="ComponentScan.Qualifier.*"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Configuration.Invalid" attribute-config="false" />
</objects>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Configuration.Invalid" />
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*"/>
<context:exclude-filter type="assignable" expression="XmlAssemblyTypeScanner.Test.Include2.FunnyAbstract, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<!-- to test type load exception -->
<context:include-filter type="assignable" expression="XmlAssemblyTypeScanner.Test.Include1.NotValid, Spring.Core.Tests"/>
<context:include-filter type="assignable" expression="XmlAssemblyTypeScanner.Test.Include1.IFunny, Spring.Core.Tests"/>
<context:include-filter type="assignable" expression="XmlAssemblyTypeScanner.Test.Include2.FunnyAbstract, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*"/>
<context:exclude-filter type="attribute" expression="XmlAssemblyTypeScanner.Test.Include1.DoNotIncludeAttribute, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<!-- to test type load exception -->
<context:include-filter type="attribute" expression="Spring.Stereotype.ServiceAttribute, notvalid"/>
<context:include-filter type="attribute" expression="XmlAssemblyTypeScanner.Test.Include2.DoIncludeAttribute, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*"/>
<context:exclude-filter type="custom" expression="XmlAssemblyTypeScanner.Test.Include1.TestFilter, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<!-- to test type load exception -->
<context:include-filter type="custom" expression="XmlAssemblyTypeScanner.Test.Include1.NotValid, Spring.Core.Tests"/>
<context:include-filter type="custom" expression="XmlAssemblyTypeScanner.Test.Include1.TestFilter, Spring.Core.Tests"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*"/>
<context:exclude-filter type="regex" expression=".*Test.*Exclude"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*Include1"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:context="http://www.springframework.net/context">
<context:component-scan base-assemblies="Spring.Core.Tests">
<context:include-filter type="regex" expression=".*Test.*Include1"/>
<context:include-filter type="regex" expression=".*Test.*Include2"/>
</context:component-scan>
</objects>

View File

@@ -0,0 +1,42 @@
#region License
/*
* Copyright <20> 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"));
}
}
}

View File

@@ -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<TheConfigurationClass>();
}
[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<string> names = new List<string>(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
{
}
}

View File

@@ -0,0 +1,51 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
///
/// </summary>
/// <author>Mark Pollack</author>
[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; }
}
}
}

View File

@@ -0,0 +1,32 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
///
/// </summary>
/// <author>Mark Pollack</author>
public interface IFooDao
{
string FindFoo(string id);
}
}

View File

@@ -0,0 +1,35 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Simple service for testing of component scanning
/// </summary>
/// <author>Mark Pollack</author>
public interface IFooService
{
string Foo { get; set; }
bool InitCalled { get; set; }
}
}

View File

@@ -0,0 +1,38 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
///
/// </summary>
/// <author>Mark Pollack</author>
[Repository]
public class StubFooDao : IFooDao
{
public string FindFoo(string id)
{
return "bar";
}
}
}

View File

@@ -152,9 +152,25 @@
<Compile Include="Context\ApplicationEventArgsTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Attributes\AbstractConfigurationClassPostProcessorTests.cs" />
<Compile Include="Context\Attributes\AssemblyObjectDefinitionScannerTests.cs" />
<Compile Include="Context\Attributes\AssemblyTypeScannerTests.cs" />
<Compile Include="Context\Attributes\CodeConfigApplicationContextTests.cs" />
<Compile Include="Context\Attributes\ConfigurationClassObjectDefinitionReaderTests.cs" />
<Compile Include="Context\Attributes\ConfigurationClassParserTests.cs" />
<Compile Include="Context\Attributes\ConfigurationClassPostProcessorTests.cs" />
<Compile Include="Context\Attributes\ImportResourceAttributeTests.cs" />
<Compile Include="Context\Attributes\ObjectDefAttributeTests.cs" />
<Compile Include="Context\Attributes\ScanningConfigurationClassPostProcessorTests.cs" />
<Compile Include="Context\Attributes\SimpleScanTests.cs" />
<Compile Include="Context\CommonTypes.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Config\AttributeConfigObjectDefinitionParserTests.cs" />
<Compile Include="Context\Config\ComponentScanObjectDefinitionParserAssemblyFilterTests.cs" />
<Compile Include="Context\Config\ComponentScanObjectDefinitionParserTests.cs" />
<Compile Include="Context\Config\ComponentScanObjectDefinitionParserTypeFilterTests.cs" />
<Compile Include="Context\Config\ContextNamespaceParserTests.cs" />
<Compile Include="Context\ContextExceptionTests.cs">
<SubType>Code</SubType>
</Compile>
@@ -183,6 +199,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Context\Support\Assembler.cs" />
<Compile Include="Context\Support\CodeConfigApplicationContextTests.cs" />
<Compile Include="Context\Support\ContextLocatorHandlerTests.cs">
<SubType>Code</SubType>
</Compile>
@@ -281,6 +298,10 @@
<Compile Include="CompilerOptionsTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Example\Scannable\FooService.cs" />
<Compile Include="Example\Scannable\IFooDao.cs" />
<Compile Include="Example\Scannable\IFooService.cs" />
<Compile Include="Example\Scannable\StubFooDao.cs" />
<Compile Include="ExceptionsTest.cs" />
<Compile Include="Expressions\ConstructorNodeTests.cs" />
<Compile Include="Expressions\ExpressionEvaluatorTests.cs">
@@ -804,6 +825,32 @@
<EmbeddedResource Include="Context\Support\innerObjectsWithPostProcessor.xml" />
<EmbeddedResource Include="Core\IO\ConfigSectionResourceTests_config1.xml" />
<EmbeddedResource Include="Context\Support\XmlApplicationContextTests-SPRNET1231.xml" />
<EmbeddedResource Include="Context\Attributes\ObjectDefinitions.xml" />
<EmbeddedResource Include="Context\Attributes\ObjectDefinitionsTwo.xml" />
<EmbeddedResource Include="Context\Attributes\SimpleScanTest.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\AttributeConfigParser.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\BaseAssemblyTestMultiple.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\BaseAssemblyTestNegative.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\BaseAssemblyTestSingle.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\BaseAssemblyTestWithout.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan1.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan2.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan3.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan31.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan4.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan5.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScan6.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScanAttributeConfigFalse.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\ComponentScanAttributeConfigTrue.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestAssignableExclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestAssignableInclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestAttributeExclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestAttributeInclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestCustomExclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestCustomInclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestRegExExclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestRegExInclude.xml" />
<EmbeddedResource Include="Context\Config\ConfigFiles\TypeScannerTestRegExInclude2.xml" />
<Content Include="Data\PathMatcher\EmptyPattern.test" />
<Content Include="Data\PathMatcher\Examples.test" />
<Content Include="Data\PathMatcher\InBetween.test" />