From: <jer...@us...> - 2009-06-03 16:21:06
|
Revision: 247 http://structuremap.svn.sourceforge.net/structuremap/?rev=247&view=rev Author: jeremydmiller Date: 2009-06-03 16:21:03 +0000 (Wed, 03 Jun 2009) Log Message: ----------- initial work on nested containers, some little syntactical sugar in the registry DSL Modified Paths: -------------- trunk/Source/StructureMap/BuildSession.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs trunk/Source/StructureMap/Configuration/DSL/Registry.cs trunk/Source/StructureMap/Container.cs trunk/Source/StructureMap/Diagnostics/ValidationBuildSession.cs trunk/Source/StructureMap/Graph/GenericsPluginGraph.cs trunk/Source/StructureMap/IContainer.cs trunk/Source/StructureMap/IInstanceFactory.cs trunk/Source/StructureMap/InstanceCache.cs trunk/Source/StructureMap/InstanceFactory.cs trunk/Source/StructureMap/Pipeline/BuildStack.cs trunk/Source/StructureMap/Pipeline/ConfiguredInstanceBase.cs trunk/Source/StructureMap/Pipeline/ProfileManager.cs trunk/Source/StructureMap/PipelineGraph.cs trunk/Source/StructureMap/StructureMap.csproj trunk/Source/StructureMap/Util/Cache.cs trunk/Source/StructureMap.Testing/BuildSessionTester.cs trunk/Source/StructureMap.Testing/Graph/InstanceFactoryTester.cs trunk/Source/StructureMap.Testing/Pipeline/ConfiguredInstanceTester.cs trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj trunk/Source/StructureMap.sln Added Paths: ----------- trunk/Source/StructureMap/Pipeline/ILifecycle.cs trunk/Source/StructureMap/Pipeline/IObjectCache.cs trunk/Source/StructureMap/Pipeline/Lifecycles.cs trunk/Source/StructureMap/Pipeline/MainObjectCache.cs trunk/Source/StructureMap/Pipeline/NulloObjectCache.cs trunk/Source/StructureMap/Pipeline/ObjectBuilder.cs trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs trunk/Source/StructureMap.Testing/Util/ trunk/Source/StructureMap.Testing/Util/CacheTester.cs Modified: trunk/Source/StructureMap/BuildSession.cs =================================================================== --- trunk/Source/StructureMap/BuildSession.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/BuildSession.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -8,18 +8,17 @@ { public class BuildSession : IContext { - private readonly BuildStack _buildStack = new BuildStack(); + private BuildStack _buildStack = new BuildStack(); private readonly InstanceCache _cache = new InstanceCache(); private readonly Cache<Type, Func<object>> _defaults; private readonly PipelineGraph _pipelineGraph; private readonly ObjectBuilder _builder; - public BuildSession(PipelineGraph pipelineGraph, InterceptorLibrary interceptorLibrary) + public BuildSession(PipelineGraph pipelineGraph, InterceptorLibrary interceptorLibrary, IObjectCache cache) { + _builder = new ObjectBuilder(pipelineGraph, interceptorLibrary, cache); _pipelineGraph = pipelineGraph; - _builder = new ObjectBuilder(_pipelineGraph, interceptorLibrary, new NulloObjectCache()); - _defaults = new Cache<Type, Func<object>>(t => { Instance instance = _pipelineGraph.GetDefault(t); @@ -34,7 +33,7 @@ } public BuildSession(PluginGraph graph) - : this(new PipelineGraph(graph), graph.InterceptorLibrary) + : this(new PipelineGraph(graph), graph.InterceptorLibrary, new NulloObjectCache()) { } @@ -43,6 +42,10 @@ { } + protected void clearBuildStack() + { + _buildStack = new BuildStack(); + } protected PipelineGraph pipelineGraph { Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -103,6 +103,16 @@ } /// <summary> + /// Shorthand way of saying TheDefaultIsConcreteType<> + /// </summary> + /// <typeparam name="CONCRETETYPE"></typeparam> + /// <returns></returns> + public CreatePluginFamilyExpression<PLUGINTYPE> Use<CONCRETETYPE>() where CONCRETETYPE : PLUGINTYPE + { + return TheDefaultIsConcreteType<CONCRETETYPE>(); + } + + /// <summary> /// Sets the object creation of the instances of the PluginType. For example: PerRequest, /// Singleton, ThreadLocal, HttpContext, or Hybrid /// </summary> Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -51,6 +51,16 @@ return instance; } + + /// <summary> + /// Shorter way to call TheDefaultIsConcreteType + /// </summary> + /// <param name="concreteType"></param> + /// <returns></returns> + public ConfiguredInstance Use(Type concreteType) + { + return TheDefaultIsConcreteType(concreteType); + } /// <summary> /// Shortcut method to add an additional Instance to this Plugin Type Modified: trunk/Source/StructureMap/Configuration/DSL/Registry.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -47,7 +47,20 @@ void SelectConstructor<T>(Expression<Func<T>> expression); } + public static class RegistryExtensions + { + public static CreatePluginFamilyExpression<PLUGINTYPE> For<PLUGINTYPE>(this IRegistry registry) + { + return registry.ForRequestedType<PLUGINTYPE>(); + } + public static GenericFamilyExpression For(this IRegistry registry, Type pluginType) + { + return registry.ForRequestedType(pluginType); + } + } + + /// <summary> /// A Registry class provides methods and grammars for configuring a Container or ObjectFactory. /// Using a Registry subclass is the recommended way of configuring a StructureMap Container. Modified: trunk/Source/StructureMap/Container.cs =================================================================== --- trunk/Source/StructureMap/Container.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Container.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -7,16 +7,15 @@ using StructureMap.Graph; using StructureMap.Interceptors; using StructureMap.Pipeline; -using System.Linq; namespace StructureMap { public class Container : TypeRules, IContainer { private InterceptorLibrary _interceptorLibrary; - private Model _model; private PipelineGraph _pipelineGraph; private PluginGraph _pluginGraph; + private IObjectCache _transientCache = new NulloObjectCache(); public Container(Action<ConfigurationExpression> action) { @@ -26,11 +25,13 @@ construct(expression.BuildGraph()); } - public Container(Registry registry) : this(registry.Build()) + public Container(Registry registry) + : this(registry.Build()) { } - public Container() : this(new PluginGraph()) + public Container() + : this(new PluginGraph()) { } @@ -44,25 +45,16 @@ construct(pluginGraph); } - protected MissingFactoryFunction onMissingFactory - { - set { _pipelineGraph.OnMissingFactory = value; } - } + protected MissingFactoryFunction onMissingFactory { set { _pipelineGraph.OnMissingFactory = value; } } + public PluginGraph PluginGraph { get { return _pluginGraph; } } + #region IContainer Members - public PluginGraph PluginGraph - { - get { return _pluginGraph; } - } - /// <summary> /// Provides queryable access to the configured PluginType's and Instances of this Container /// </summary> - public IModel Model - { - get { return _model; } - } + public IModel Model { get { return new Model(_pipelineGraph); } } /// <summary> /// Creates or finds the named instance of T @@ -110,30 +102,12 @@ public object GetInstance(Type pluginType, ExplicitArguments args) { Instance defaultInstance = _pipelineGraph.GetDefault(pluginType); - var requestedName = Plugin.DEFAULT; + string requestedName = Plugin.DEFAULT; return buildInstanceWithArgs(pluginType, defaultInstance, args, requestedName); } - private object buildInstanceWithArgs(Type pluginType, Instance defaultInstance, ExplicitArguments args, string requestedName) - { - if (defaultInstance == null && pluginType.IsConcrete()) - { - defaultInstance = new ConfiguredInstance(pluginType); - } - BasicInstance basicInstance = defaultInstance as BasicInstance; - - Instance instance = basicInstance == null ? defaultInstance : new ExplicitInstance(pluginType, args, basicInstance); - - BuildSession session = withNewSession(requestedName); - - args.RegisterDefaults(session); - - return session.CreateInstance(pluginType, instance); - } - - /// <summary> /// Gets all configured instances of type T using explicitly configured arguments from the "args" /// </summary> @@ -146,7 +120,7 @@ args.RegisterDefaults(session); - var instances = session.CreateInstanceArray(type, null); + Array instances = session.CreateInstanceArray(type, null); return new ArrayList(instances); } @@ -241,9 +215,9 @@ /// <returns></returns> public object TryGetInstance(Type pluginType, string instanceKey) { - return !_pipelineGraph.HasInstance(pluginType, instanceKey) - ? null - : GetInstance(pluginType, instanceKey); + return !_pipelineGraph.HasInstance(pluginType, instanceKey) + ? null + : GetInstance(pluginType, instanceKey); } /// <summary> @@ -253,9 +227,9 @@ /// <returns></returns> public object TryGetInstance(Type pluginType) { - return !_pipelineGraph.HasDefaultForPluginType(pluginType) - ? null - : GetInstance(pluginType); + return !_pipelineGraph.HasDefaultForPluginType(pluginType) + ? null + : GetInstance(pluginType); } /// <summary> @@ -265,7 +239,7 @@ /// <returns></returns> public T TryGetInstance<T>() { - return (T)(TryGetInstance(typeof (T)) ?? default(T)); + return (T) (TryGetInstance(typeof (T)) ?? default(T)); } /// <summary> @@ -276,11 +250,11 @@ /// <param name="target"></param> public void BuildUp(object target) { - var pluggedType = target.GetType(); - IConfiguredInstance instance = _pipelineGraph.GetDefault(pluggedType) as IConfiguredInstance - ?? new ConfiguredInstance(pluggedType); + Type pluggedType = target.GetType(); + IConfiguredInstance instance = _pipelineGraph.GetDefault(pluggedType) as IConfiguredInstance + ?? new ConfiguredInstance(pluggedType); - var builder = PluginCache.FindBuilder(pluggedType); + InstanceBuilder builder = PluginCache.FindBuilder(pluggedType); builder.BuildUp(instance, withNewSession(Plugin.DEFAULT), target); } @@ -291,7 +265,7 @@ /// <returns></returns> public T TryGetInstance<T>(string instanceKey) { - return (T)(TryGetInstance(typeof(T), instanceKey) ?? default(T)); + return (T) (TryGetInstance(typeof (T), instanceKey) ?? default(T)); } /// <summary> @@ -365,7 +339,7 @@ /// <returns></returns> public IList GetAllInstances(Type pluginType) { - var instances = withNewSession(Plugin.DEFAULT).CreateInstanceArray(pluginType, null); + Array instances = withNewSession(Plugin.DEFAULT).CreateInstanceArray(pluginType, null); return new ArrayList(instances); } @@ -434,15 +408,7 @@ return new ExplicitArgsExpression(this).With(argName); } - public ExplicitArgsExpression With(Action<ExplicitArgsExpression> action) - { - var expression = new ExplicitArgsExpression(this); - action(expression); - return expression; - } - - /// <summary> /// Use with caution! Does a full environment test of the configuration of this container. Will try to create every configured /// instance and afterward calls any methods marked with the [ValidationMethod] attribute @@ -467,8 +433,95 @@ _pipelineGraph.EjectAllInstancesOf<T>(); } + /// <summary> + /// Convenience method to request an object using an Open Generic + /// Type and its parameter Types + /// </summary> + /// <param name="templateType"></param> + /// <returns></returns> + /// <example> + /// IFlattener flattener1 = container.ForGenericType(typeof (IFlattener<>)) + /// .WithParameters(typeof (Address)).GetInstanceAs<IFlattener>(); + /// </example> + public OpenGenericTypeExpression ForGenericType(Type templateType) + { + return new OpenGenericTypeExpression(templateType, this); + } + + /// <summary> + /// Shortcut syntax for using an object to find a service that handles + /// that type of object by using an open generic type + /// </summary> + /// <example> + /// IHandler handler = container.ForObject(shipment) + /// .GetClosedTypeOf(typeof (IHandler<>)) + /// .As<IHandler>(); + /// </example> + /// <param name="subject"></param> + /// <returns></returns> + public CloseGenericTypeExpression ForObject(object subject) + { + return new CloseGenericTypeExpression(subject, this); + } + + /// <summary> + /// Starts a "Nested" Container for atomic, isolated access + /// </summary> + /// <returns></returns> + public IContainer GetNestedContainer() + { + return new Container() + { + _interceptorLibrary = _interceptorLibrary, + _pipelineGraph = _pipelineGraph.Clone(), + _transientCache = new MainObjectCache() + }; + } + + /// <summary> + /// Starts a new "Nested" Container for atomic, isolated service location. Opens + /// </summary> + /// <param name="profileName"></param> + /// <returns></returns> + public IContainer GetNestedContainer(string profileName) + { + var container = GetNestedContainer(); + container.SetDefaultsToProfile(profileName); + + return container; + } + #endregion + private object buildInstanceWithArgs(Type pluginType, Instance defaultInstance, ExplicitArguments args, + string requestedName) + { + if (defaultInstance == null && pluginType.IsConcrete()) + { + defaultInstance = new ConfiguredInstance(pluginType); + } + + var basicInstance = defaultInstance as BasicInstance; + + Instance instance = basicInstance == null + ? defaultInstance + : new ExplicitInstance(pluginType, args, basicInstance); + + BuildSession session = withNewSession(requestedName); + + args.RegisterDefaults(session); + + return session.CreateInstance(pluginType, instance); + } + + public ExplicitArgsExpression With(Action<ExplicitArgsExpression> action) + { + var expression = new ExplicitArgsExpression(this); + action(expression); + + return expression; + } + private void construct(PluginGraph pluginGraph) { _interceptorLibrary = pluginGraph.InterceptorLibrary; @@ -482,7 +535,6 @@ pluginGraph.Log.AssertFailures(); _pipelineGraph = new PipelineGraph(pluginGraph); - _model = new Model(_pipelineGraph); PluginCache.Compile(); @@ -492,7 +544,7 @@ private IList<T> getListOfTypeWithSession<T>(BuildSession session) { var list = new List<T>(); - foreach (T instance in session.CreateInstanceArray(typeof(T), null)) + foreach (T instance in session.CreateInstanceArray(typeof (T), null)) { list.Add(instance); } @@ -512,30 +564,27 @@ private BuildSession withNewSession(string name) { - return new BuildSession(_pipelineGraph, _interceptorLibrary){RequestedName = name}; + return new BuildSession(_pipelineGraph, _interceptorLibrary, _transientCache) + { + RequestedName = name + }; } - /// <summary> - /// Convenience method to request an object using an Open Generic - /// Type and its parameter Types - /// </summary> - /// <param name="templateType"></param> - /// <returns></returns> - /// <example> - /// IFlattener flattener1 = container.ForGenericType(typeof (IFlattener<>)) - /// .WithParameters(typeof (Address)).GetInstanceAs<IFlattener>(); - /// </example> - public OpenGenericTypeExpression ForGenericType(Type templateType) + #region Nested type: GetInstanceAsExpression + + public interface GetInstanceAsExpression { - return new OpenGenericTypeExpression(templateType, this); + T GetInstanceAs<T>(); } - + #endregion + #region Nested type: OpenGenericTypeExpression + public class OpenGenericTypeExpression : GetInstanceAsExpression { + private readonly Container _container; private readonly Type _templateType; - private readonly Container _container; private Type _pluginType; public OpenGenericTypeExpression(Type templateType, Container container) @@ -549,39 +598,22 @@ _container = container; } - public GetInstanceAsExpression WithParameters(params Type[] parameterTypes) - { - _pluginType = _templateType.MakeGenericType(parameterTypes); - return this; - } + #region GetInstanceAsExpression Members public T GetInstanceAs<T>() { return (T) _container.GetInstance(_pluginType); } - } - public interface GetInstanceAsExpression - { - T GetInstanceAs<T>(); + #endregion + + public GetInstanceAsExpression WithParameters(params Type[] parameterTypes) + { + _pluginType = _templateType.MakeGenericType(parameterTypes); + return this; + } } - /// <summary> - /// Shortcut syntax for using an object to find a service that handles - /// that type of object by using an open generic type - /// </summary> - /// <example> - /// IHandler handler = container.ForObject(shipment) - /// .GetClosedTypeOf(typeof (IHandler<>)) - /// .As<IHandler>(); - /// </example> - /// <param name="subject"></param> - /// <returns></returns> - public CloseGenericTypeExpression ForObject(object subject) - { - return new CloseGenericTypeExpression(subject, this); - } + #endregion } - - } \ No newline at end of file Modified: trunk/Source/StructureMap/Diagnostics/ValidationBuildSession.cs =================================================================== --- trunk/Source/StructureMap/Diagnostics/ValidationBuildSession.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Diagnostics/ValidationBuildSession.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -17,7 +17,7 @@ private List<IInstance> _explicitInstances; public ValidationBuildSession(PipelineGraph pipelineGraph, InterceptorLibrary interceptorLibrary) - : base(pipelineGraph, interceptorLibrary) + : base(pipelineGraph, interceptorLibrary, new NulloObjectCache()) { } @@ -47,6 +47,7 @@ try { + //clearBuildStack(); return base.CreateInstance(pluginType, instance); } catch (StructureMapException ex) Modified: trunk/Source/StructureMap/Graph/GenericsPluginGraph.cs =================================================================== --- trunk/Source/StructureMap/Graph/GenericsPluginGraph.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Graph/GenericsPluginGraph.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -7,13 +7,18 @@ { public class GenericsPluginGraph { - private readonly Cache<Type, PluginFamily> _families; + private Cache<Type, PluginFamily> _families; public GenericsPluginGraph() { _families = new Cache<Type, PluginFamily>(pluginType => new PluginFamily(pluginType)); } + public GenericsPluginGraph Clone() + { + return new GenericsPluginGraph(){_families = _families.Clone()}; + } + public int FamilyCount { get { return _families.Count; } Modified: trunk/Source/StructureMap/IContainer.cs =================================================================== --- trunk/Source/StructureMap/IContainer.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/IContainer.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -268,5 +268,23 @@ /// <param name="subject"></param> /// <returns></returns> CloseGenericTypeExpression ForObject(object subject); + + + + /// <summary> + /// Starts a "Nested" Container for atomic, isolated access + /// </summary> + /// <returns></returns> + IContainer GetNestedContainer(); + + /// <summary> + /// Starts a new "Nested" Container for atomic, isolated service location. Opens + /// </summary> + /// <param name="profileName"></param> + /// <returns></returns> + IContainer GetNestedContainer(string profileName); } + + + } \ No newline at end of file Modified: trunk/Source/StructureMap/IInstanceFactory.cs =================================================================== --- trunk/Source/StructureMap/IInstanceFactory.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/IInstanceFactory.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -12,19 +12,19 @@ public interface IInstanceFactory { Type PluginType { get; } - IEnumerable<IInstance> Instances { get; } - Instance MissingInstance { get; set; } + Instance MissingInstance { get; } + Instance[] AllInstances { get; } + // need to override this void AddInstance(Instance instance); - Instance AddType<T>(); + Instance FindInstance(string name); - void ImportFrom(PluginFamily family); [Obsolete("Kill!!!!")] @@ -32,6 +32,7 @@ ILifecycle Lifecycle {get; } + IInstanceFactory Clone(); + } - } } \ No newline at end of file Modified: trunk/Source/StructureMap/InstanceCache.cs =================================================================== --- trunk/Source/StructureMap/InstanceCache.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/InstanceCache.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -25,6 +25,16 @@ public object Get(Type pluginType, Instance instance) { + if (pluginType == null) + { + throw new ArgumentNullException("pluginType"); + } + + if (instance == null) + { + throw new ArgumentNullException("instance", "Trying to find an Instance of type " + pluginType.AssemblyQualifiedName); + } + Dictionary<Instance, object> cache = getCache(pluginType); if (cache.ContainsKey(instance)) { Modified: trunk/Source/StructureMap/InstanceFactory.cs =================================================================== --- trunk/Source/StructureMap/InstanceFactory.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/InstanceFactory.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -12,7 +12,7 @@ /// </summary> public class InstanceFactory : IInstanceFactory { - private readonly Cache<string, Instance> _instances = + private Cache<string, Instance> _instances = new Cache<string, Instance>(delegate { return null; }); private readonly Type _pluginType; @@ -82,11 +82,6 @@ get { return _pluginType; } } - public IEnumerable<IInstance> Instances - { - get { return _instances.GetAll(); } - } - public Instance[] AllInstances { get @@ -102,17 +97,6 @@ } - [Obsolete] - public Instance AddType<T>() - { - ConfiguredInstance instance = - new ConfiguredInstance(typeof (T)).WithName(TypePath.GetAssemblyQualifiedName(typeof (T))); - - AddInstance(instance); - - return instance; - } - public Instance FindInstance(string name) { return _instances[name] ?? MissingInstance; @@ -149,7 +133,18 @@ get { return _lifecycle; } set { _lifecycle = value; } } + + public IInstanceFactory Clone() + { + var factory = new InstanceFactory(_pluginType); + factory.MissingInstance = MissingInstance; + factory._lifecycle = _lifecycle; + factory._instances = _instances.Clone(); + + return factory; + } + #endregion } } \ No newline at end of file Modified: trunk/Source/StructureMap/Pipeline/BuildStack.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/BuildStack.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Pipeline/BuildStack.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -64,5 +64,10 @@ _current = _current.Detach(); if (_current == null) _root = null; } + + public void Clear() + { + _current = _root = null; + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Pipeline/ConfiguredInstanceBase.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ConfiguredInstanceBase.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Pipeline/ConfiguredInstanceBase.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -206,6 +206,15 @@ protected void setChildArray(string name, Instance[] array) { + for (int i = 0; i < array.Length; i++) + { + if (array[i] == null) + { + throw new ApplicationException("There is a null value in the array of child Instances"); + } + + } + _arrays.Add(name, array); } Added: trunk/Source/StructureMap/Pipeline/ILifecycle.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ILifecycle.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/ILifecycle.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,8 @@ +namespace StructureMap.Pipeline +{ + public interface ILifecycle + { + void EjectAll(); + IObjectCache FindCache(); + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Pipeline/IObjectCache.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/IObjectCache.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/IObjectCache.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,18 @@ +using System; + +namespace StructureMap.Pipeline +{ + public interface IObjectCache + { + object Locker { get; } + + int Count + { + get; + } + + object Get(Type pluginType, Instance instance); + void Set(Type pluginType, Instance instance, object value); + void DisposeAndClear(); + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Pipeline/Lifecycles.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/Lifecycles.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/Lifecycles.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,37 @@ +using System; +using StructureMap.Attributes; + +namespace StructureMap.Pipeline +{ + public static class Lifecycles + { + public static ILifecycle GetLifecycle(InstanceScope scope) + { + switch (scope) + { + case InstanceScope.PerRequest: + return null; + + case InstanceScope.Singleton: + return new SingletonLifecycle(); + + case InstanceScope.HttpContext: + return new HttpContextLifecycle(); + + case InstanceScope.ThreadLocal: + return new ThreadLocalStorageLifecycle(); + + case InstanceScope.Hybrid: + return new HybridLifecycle(); + + case InstanceScope.HttpSession: + return new HttpSessionLifecycle(); + + case InstanceScope.HybridHttpSession: + return new HybridSessionLifecycle(); + } + + throw new ArgumentOutOfRangeException("scope"); + } + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Pipeline/MainObjectCache.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/MainObjectCache.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/MainObjectCache.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace StructureMap.Pipeline +{ + public class MainObjectCache : IObjectCache + { + private readonly IDictionary<InstanceKey, object> _objects = new Dictionary<InstanceKey,object>(); + private readonly object _locker = new object(); + + public object Locker + { + get { return _locker; } + } + + public int Count + { + get { return _objects.Count; } + } + + public object Get(Type pluginType, Instance instance) + { + var key = new InstanceKey(instance, pluginType); + return _objects.ContainsKey(key) ? _objects[key] : null; + } + + public void Set(Type pluginType, Instance instance, object value) + { + var key = new InstanceKey(instance, pluginType); + _objects.Add(key, value); + } + + public void DisposeAndClear() + { + lock (Locker) + { + foreach (var @object in _objects.Values) + { + IDisposable disposable = @object as IDisposable; + if (disposable != null) + { + try + { + disposable.Dispose(); + } + catch (Exception) { } + } + } + + _objects.Clear(); + } + } + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Pipeline/NulloObjectCache.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/NulloObjectCache.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/NulloObjectCache.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,32 @@ +using System; + +namespace StructureMap.Pipeline +{ + public class NulloObjectCache : IObjectCache + { + public object Locker + { + get { return new object(); } + } + + public int Count + { + get { return 0; } + } + + public object Get(Type pluginType, Instance instance) + { + return null; + } + + public void Set(Type pluginType, Instance instance, object value) + { + // no-op + } + + public void DisposeAndClear() + { + // no-op + } + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Pipeline/ObjectBuilder.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ObjectBuilder.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/ObjectBuilder.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,69 @@ +using System; +using StructureMap.Interceptors; + +namespace StructureMap.Pipeline +{ + public class ObjectBuilder + { + private readonly PipelineGraph _pipeline; + private readonly InterceptorLibrary _library; + private readonly IObjectCache _defaultCache; + + public ObjectBuilder(PipelineGraph pipeline, InterceptorLibrary library, IObjectCache defaultCache) + { + if (pipeline == null) throw new ArgumentNullException("pipeline"); + + _pipeline = pipeline; + _library = library; + _defaultCache = defaultCache; + } + + public object Resolve(Type pluginType, Instance instance, BuildSession session) + { + var cache = FindCache(pluginType, instance, session); + lock (cache.Locker) + { + var returnValue = cache.Get(pluginType, instance); + if (returnValue == null) + { + returnValue = ConstructNew(pluginType, instance, session); + + + cache.Set(pluginType, instance, returnValue); + } + + return returnValue; + } + } + + public object ConstructNew(Type pluginType, Instance instance, BuildSession session) + { + object returnValue = instance.Build(pluginType, session); + return ApplyInterception(pluginType, returnValue, session, instance); + } + + public virtual object ApplyInterception(Type pluginType, object actualValue, BuildSession session, Instance instance) + { + if (actualValue == null) return null; + + try + { + return _library.FindInterceptor(actualValue.GetType()).Process(actualValue, session); + } + catch (Exception e) + { + throw new StructureMapException(308, e, instance.Name, actualValue.GetType()); + } + + + } + + public IObjectCache FindCache(Type pluginType, Instance instance, BuildSession session) + { + var lifecycle = _pipeline.ForType(pluginType).Lifecycle; + return lifecycle == null + ? _defaultCache + : lifecycle.FindCache(); + } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap/Pipeline/ProfileManager.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ProfileManager.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Pipeline/ProfileManager.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -224,6 +224,19 @@ CurrentProfile = CurrentProfile; } + public ProfileManager Clone() + { + var clone = new ProfileManager() + { + DefaultMachineProfileName = DefaultMachineProfileName, + DefaultProfileName = DefaultProfileName + }; + + clone.ImportFrom(this); + + return clone; + } + public void EjectAllInstancesOf<T>() { _currentProfile.Remove<T>(); Modified: trunk/Source/StructureMap/PipelineGraph.cs =================================================================== --- trunk/Source/StructureMap/PipelineGraph.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/PipelineGraph.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -41,6 +41,27 @@ } } + private PipelineGraph(ProfileManager profileManager, GenericsPluginGraph genericsGraph) + { + _profileManager = profileManager; + _genericsGraph = genericsGraph; + } + + public PipelineGraph Clone() + { + var clone = new PipelineGraph(_profileManager.Clone(), _genericsGraph.Clone()) + { + _missingFactory = _missingFactory + }; + + foreach (var pair in _factories) + { + clone._factories.Add(pair.Key, pair.Value); + } + + return clone; + } + public GraphLog Log { get { return _log; } @@ -76,7 +97,7 @@ Default = _profileManager.GetDefault(factory.PluginType), PluginType = factory.PluginType, Lifecycle = factory.Lifecycle, - Instances = factory.Instances + Instances = factory.AllInstances }; } } @@ -152,22 +173,12 @@ _profileManager.SetDefault(pluginType, instance); } - public Instance AddInstance<PLUGINTYPE, PLUGGEDTYPE>() - { - return ForType(typeof (PLUGINTYPE)).AddType<PLUGGEDTYPE>(); - } public void AddInstance<T>(Instance instance) { ForType(typeof (T)).AddInstance(instance); } - public void AddDefaultInstance<PLUGINTYPE, PLUGGEDTYPE>() - { - Instance instance = AddInstance<PLUGINTYPE, PLUGGEDTYPE>(); - _profileManager.SetDefault(typeof (PLUGINTYPE), instance); - } - public void Inject<PLUGINTYPE>(PLUGINTYPE instance) { var literalInstance = new LiteralInstance(instance); @@ -190,7 +201,7 @@ if (_factories.ContainsKey(pluginType)) { - return _factories[pluginType].Instances; + return _factories[pluginType].AllInstances; } return new IInstance[0]; @@ -202,7 +213,7 @@ foreach (var pair in _factories) { - list.AddRange(pair.Value.Instances); + list.AddRange(pair.Value.AllInstances); } return list; Modified: trunk/Source/StructureMap/StructureMap.csproj =================================================================== --- trunk/Source/StructureMap/StructureMap.csproj 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/StructureMap.csproj 2009-06-03 16:21:03 UTC (rev 247) @@ -404,7 +404,12 @@ <Compile Include="Pipeline\HttpLifecycleBase.cs" /> <Compile Include="Pipeline\HttpSessionLifecycle.cs" /> <Compile Include="Pipeline\HybridSessionLifecycle.cs" /> - <Compile Include="Pipeline\Lifecycle.cs" /> + <Compile Include="Pipeline\ILifecycle.cs" /> + <Compile Include="Pipeline\IObjectCache.cs" /> + <Compile Include="Pipeline\Lifecycles.cs" /> + <Compile Include="Pipeline\MainObjectCache.cs" /> + <Compile Include="Pipeline\NulloObjectCache.cs" /> + <Compile Include="Pipeline\ObjectBuilder.cs" /> <Compile Include="Pipeline\SessionWrapper.cs" /> <Compile Include="Pipeline\SingletonLifecycle.cs" /> <Compile Include="Pipeline\ThreadLocalStorageLifecycle.cs" /> Modified: trunk/Source/StructureMap/Util/Cache.cs =================================================================== --- trunk/Source/StructureMap/Util/Cache.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap/Util/Cache.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -9,8 +9,6 @@ private readonly object _locker = new object(); private readonly IDictionary<KEY, VALUE> _values; - private Func<VALUE, KEY> _getKey = delegate { throw new NotImplementedException(); }; - private Func<KEY, VALUE> _onMissing = delegate(KEY key) { string message = string.Format("Key '{0}' could not be found", key); @@ -38,22 +36,11 @@ _values = dictionary; } - public object Locker - { - get { return _locker; } - } - public Func<KEY, VALUE> OnMissing { set { _onMissing = value; } } - public Func<VALUE, KEY> GetKey - { - get { return _getKey; } - set { _getKey = value; } - } - public int Count { get { return _values.Count; } @@ -135,19 +122,6 @@ _values.Add(key, value); } - public bool TryRetrieve(KEY key, out VALUE value) - { - value = default(VALUE); - - if (_values.ContainsKey(key)) - { - value = _values[key]; - return true; - } - - return false; - } - public void Each(Action<VALUE> action) { lock (_locker) @@ -214,5 +188,13 @@ { _values.Clear(); } + + public Cache<KEY, VALUE> Clone() + { + var clone = new Cache<KEY, VALUE>(_onMissing); + Each((k, v) => clone[k] = v); + + return clone; + } } } Modified: trunk/Source/StructureMap.Testing/BuildSessionTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/BuildSessionTester.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap.Testing/BuildSessionTester.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -151,7 +151,7 @@ assertActionThrowsErrorCode(200, delegate { - var session = new BuildSession(graph, null); + var session = new BuildSession(graph, null, new NulloObjectCache()); session.CreateInstance(typeof (IGateway), "Gateway that is not configured"); }); } @@ -183,7 +183,7 @@ assertActionThrowsErrorCode(202, delegate { - var session = new BuildSession(graph, null); + var session = new BuildSession(graph, null, new NulloObjectCache()); session.CreateInstance(typeof (IGateway)); }); } Modified: trunk/Source/StructureMap.Testing/Graph/InstanceFactoryTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Graph/InstanceFactoryTester.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap.Testing/Graph/InstanceFactoryTester.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -71,7 +71,7 @@ factory.EjectAllInstances(); - factory.Instances.Count().ShouldEqual(0); + factory.AllInstances.Count().ShouldEqual(0); lifecycle.AssertWasCalled(x => x.EjectAll()); } @@ -143,4 +143,58 @@ } + + [TestFixture] + public class when_cloning_an_InstanceFactory + { + private InstanceFactory factory; + private IInstanceFactory clone; + + [SetUp] + public void SetUp() + { + factory = new InstanceFactory(typeof(IGateway)); + factory.AddInstance(new SmartInstance<DefaultGateway>()); + factory.AddInstance(new SmartInstance<DefaultGateway>()); + + var lifecycle = MockRepository.GenerateMock<ILifecycle>(); + factory.Lifecycle = lifecycle; + factory.MissingInstance = new SmartInstance<DefaultGateway>(); + + clone = factory.Clone(); + } + + [Test] + public void missing_instance_is_copied() + { + clone.MissingInstance.ShouldBeTheSameAs(factory.MissingInstance); + } + + [Test] + public void lifecycle_is_copied() + { + clone.Lifecycle.ShouldBeTheSameAs(factory.Lifecycle); + } + + [Test] + public void plugin_type_is_set_on_the_clone() + { + clone.PluginType.ShouldEqual(typeof (IGateway)); + } + + [Test] + public void the_instances_are_copied() + { + clone.AllInstances.Count().ShouldEqual(2); + } + + [Test] + public void the_instances_are_cloned_so_that_new_instances_are_NOT_injected_into_() + { + clone.AddInstance(new LiteralInstance(new DefaultGateway())); + + factory.AllInstances.Count().ShouldEqual(2); + clone.AllInstances.Count().ShouldEqual(3); + } + } } \ No newline at end of file Modified: trunk/Source/StructureMap.Testing/Pipeline/ConfiguredInstanceTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Pipeline/ConfiguredInstanceTester.cs 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap.Testing/Pipeline/ConfiguredInstanceTester.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -30,7 +30,7 @@ PluginGraph graph = registry.Build(); var pipelineGraph = new PipelineGraph(graph); - _session = new BuildSession(pipelineGraph, graph.InterceptorLibrary); + _session = new BuildSession(pipelineGraph, graph.InterceptorLibrary, new NulloObjectCache()); } #endregion Added: trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs (rev 0) +++ trunk/Source/StructureMap.Testing/Pipeline/NestedContainerSupportTester.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,131 @@ +using NUnit.Framework; +using StructureMap.Attributes; +using StructureMap.Configuration.DSL; +using StructureMap.Testing.GenericWidgets; +using StructureMap.Testing.Widget; + +namespace StructureMap.Testing.Pipeline +{ + [TestFixture] + public class NestedContainerSupportTester + { + [SetUp] + public void SetUp() + { + } + + [Test] + public void transient_service_in_the_parent_container_is_effectively_a_singleton_for_the_nested_container() + { + var parent = new Container(x => + { + x.For<IWidget>().Use<AWidget>(); + }); + + var child = parent.GetNestedContainer(); + + var childWidget1 = child.GetInstance<IWidget>(); + var childWidget2 = child.GetInstance<IWidget>(); + var childWidget3 = child.GetInstance<IWidget>(); + + var parentWidget = parent.GetInstance<IWidget>(); + + childWidget1.ShouldBeTheSameAs(childWidget2); + childWidget1.ShouldBeTheSameAs(childWidget3); + childWidget1.ShouldNotBeTheSameAs(parentWidget); + } + + [Test] + public void singleton_service_in_the_parent_is_found_by_the_child() + { + var parent = new Container(x => + { + x.ForSingletonOf<IWidget>().Use<AWidget>(); + }); + + var parentWidget = parent.GetInstance<IWidget>(); + + var child = parent.GetNestedContainer(); + + var childWidget1 = child.GetInstance<IWidget>(); + var childWidget2 = child.GetInstance<IWidget>(); + + parentWidget.ShouldBeTheSameAs(childWidget1); + parentWidget.ShouldBeTheSameAs(childWidget2); + } + + [Test] + public void transient_open_generics_service_in_the_parent_container_is_effectively_a_singleton_for_the_nested_container() + { + var parent = new Container(x => + { + x.For(typeof(IService<>)).Use(typeof(Service<>)); + }); + + var child = parent.GetNestedContainer(); + + var childWidget1 = child.GetInstance<IService<string>>(); + var childWidget2 = child.GetInstance<IService<string>>(); + var childWidget3 = child.GetInstance<IService<string>>(); + + var parentWidget = parent.GetInstance<IService<string>>(); + + childWidget1.ShouldBeTheSameAs(childWidget2); + childWidget1.ShouldBeTheSameAs(childWidget3); + childWidget1.ShouldNotBeTheSameAs(parentWidget); + } + + [Test] + public void singleton_service_from_open_type_in_the_parent_is_found_by_the_child() + { + var parent = new Container(x => + { + x.For(typeof(IService<>)).CacheBy(InstanceScope.Singleton).Use(typeof(Service<>)); + }); + + var child = parent.GetNestedContainer(); + + var childWidget1 = child.GetInstance<IService<string>>(); + var childWidget2 = child.GetInstance<IService<string>>(); + var childWidget3 = child.GetInstance<IService<string>>(); + + var parentWidget = parent.GetInstance<IService<string>>(); + + childWidget1.ShouldBeTheSameAs(childWidget2); + childWidget1.ShouldBeTheSameAs(childWidget3); + childWidget1.ShouldBeTheSameAs(parentWidget); + } + + [Test] + public void get_a_nested_container_for_a_profile() + { + var parent = new Container(x => + { + x.For<IWidget>().TheDefault.Is.OfConcreteType<ColorWidget>() + .WithCtorArg("color").EqualTo("red"); + + x.CreateProfile("green", o => + { + o.Type<IWidget>().Is.OfConcreteType<ColorWidget>() + .WithCtorArg("color").EqualTo("green"); + }); + + }); + + var child = parent.GetNestedContainer("green"); + + var childWidget1 = child.GetInstance<IWidget>(); + var childWidget2 = child.GetInstance<IWidget>(); + var childWidget3 = child.GetInstance<IWidget>(); + + var parentWidget = parent.GetInstance<IWidget>(); + + childWidget1.ShouldBeTheSameAs(childWidget2); + childWidget1.ShouldBeTheSameAs(childWidget3); + childWidget1.ShouldNotBeTheSameAs(parentWidget); + + parentWidget.ShouldBeOfType<ColorWidget>().Color.ShouldEqual("red"); + childWidget1.ShouldBeOfType<ColorWidget>().Color.ShouldEqual("green"); + } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj =================================================================== --- trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2009-06-03 16:21:03 UTC (rev 247) @@ -353,6 +353,7 @@ <Compile Include="Pipeline\InstanceTester.cs" /> <Compile Include="Pipeline\LiteralInstanceTester.cs" /> <Compile Include="Pipeline\MissingInstanceTester.cs" /> + <Compile Include="Pipeline\NestedContainerSupportTester.cs" /> <Compile Include="Pipeline\ObjectBuilderTester.cs" /> <Compile Include="Pipeline\OptionalSetterInjectionTester.cs" /> <Compile Include="Pipeline\ProfileManagerMergeTester.cs" /> @@ -383,6 +384,7 @@ <Compile Include="TestUtility.cs" /> <Compile Include="Diagnostics\ValidationBuildSessionTester.cs" /> <Compile Include="TypeExtensionsTester.cs" /> + <Compile Include="Util\CacheTester.cs" /> <Compile Include="XmlWriting\ElementChecker.cs"> <SubType>Code</SubType> </Compile> Added: trunk/Source/StructureMap.Testing/Util/CacheTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Util/CacheTester.cs (rev 0) +++ trunk/Source/StructureMap.Testing/Util/CacheTester.cs 2009-06-03 16:21:03 UTC (rev 247) @@ -0,0 +1,35 @@ +using NUnit.Framework; +using StructureMap.Testing.Widget; +using StructureMap.Util; + +namespace StructureMap.Testing.Util +{ + [TestFixture] + public class CacheTester + { + [SetUp] + public void SetUp() + { + } + + [Test] + public void cloning_test() + { + var cache = new Cache<string, IWidget>(x => new ColorWidget(x)); + + var red = cache["red"]; + var blue = cache["blue"]; + var green = cache["green"]; + + var clone = cache.Clone(); + + clone["red"].ShouldBeTheSameAs(red); + clone["blue"].ShouldBeTheSameAs(blue); + clone["green"].ShouldBeTheSameAs(green); + + clone["purple"].ShouldBeOfType<ColorWidget>().Color.ShouldEqual("purple"); + + clone["purple"].ShouldNotBeTheSameAs(cache["purple"]); + } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap.sln =================================================================== --- trunk/Source/StructureMap.sln 2009-06-03 03:04:58 UTC (rev 246) +++ trunk/Source/StructureMap.sln 2009-06-03 16:21:03 UTC (rev 247) @@ -4,7 +4,6 @@ ProjectSection(SolutionItems) = preProject ..\Docs\Attributes.htm = ..\Docs\Attributes.htm ..\Docs\Basic Architecture.htm = ..\Docs\Basic Architecture.htm - CommonAssemblyInfo.cs = CommonAssemblyInfo.cs ..\Docs\Concepts.htm = ..\Docs\Concepts.htm ..\Docs\Configuration.htm = ..\Docs\Configuration.htm ..\Docs\ConfigurationManagement.htm = ..\Docs\ConfigurationManagement.htm This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |