User: xtoff
Date: 2009/11/15 03:40 PM

Added:
 /InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
  LazyLoadingTestCase.cs
 /InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/
  ILazyComponentLoader.cs

Modified:
 /InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
  Castle.MicroKernel.Tests-vs2008.csproj
 /InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/
  MyLifestyleHandler.cs
 /InversionOfControl/trunk/src/Castle.MicroKernel/
  Castle.MicroKernel-vs2008.csproj, DefaultKernel.cs, DefaultKernel_Resolve.cs
 /InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/
  AbstractHandler.cs, DefaultHandler.cs

Log:
 - fixed IOC-ISSUE-161 - Add hook to allow resolution of unregistered 
components.

File Changes:

Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/
============================================================

File [modified]: Castle.MicroKernel-vs2008.csproj
Delta lines: +21 -9
===================================================================

--- InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel.cs    
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel.cs    
2009-11-15 22:40:29 UTC (rev 6335)
@@ -727,7 +727,7 @@
                /// <param name="serviceType">An object that specifies the type 
of service object to get. </param>
                public object GetService(Type serviceType)
                {
-                       if (!HasComponent(serviceType))
+                       if (!HasComponent(serviceType) && 
!LazyLoadComponent(null, serviceType))
                        {
                                return null;
                        }
@@ -744,14 +744,7 @@
                /// </returns>
                public T GetService<T>() where T : class
                {
-                       Type serviceType = typeof(T);
-
-                       if (!HasComponent(serviceType))
-                       {
-                               return null;
-                       }
-
-                       return (T)Resolve(serviceType);
+                       return (T)GetService(typeof(T));
                }
 
                #endregion
@@ -951,5 +944,24 @@
 #endif
 
                #endregion
+
+               private bool LazyLoadComponent(string key, Type service)
+               {
+                       if (key == null && service == null)
+                       {
+                               throw new ArgumentException("At least one - key 
or service must not be a null reference.");
+                       }
+
+                       foreach (var loader in 
ResolveAll<ILazyComponentLoader>())
+                       {
+                               var registration = loader.Load(key, service);
+                               if (registration != null)
+                               {
+                                       registration.Register(this);
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
        }

File [modified]: DefaultKernel.cs
Delta lines: +6 -6
===================================================================

--- InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel_Resolve.cs    
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/DefaultKernel_Resolve.cs    
2009-11-15 22:40:29 UTC (rev 6335)
@@ -91,7 +91,7 @@
                        {
                                if (key == null) throw new 
ArgumentNullException("key");
 
-                               if (!HasComponent(key))
+                               if (!HasComponent(key) && 
!LazyLoadComponent(key, null))
                                {
                                        throw new 
ComponentNotFoundException(key);
                                }
@@ -108,7 +108,7 @@
                        {
                                if (service == null) throw new 
ArgumentNullException("service");
 
-                               if (!HasComponent(service))
+                               if (!HasComponent(service) && 
!LazyLoadComponent(null, service))
                                {
                                        throw new 
ComponentNotFoundException(service);
                                }
@@ -219,7 +219,7 @@
                        if (service == null) throw new 
ArgumentNullException("service");
                        if (arguments == null) throw new 
ArgumentNullException("arguments");
 
-                       if (!HasComponent(service))
+                       if (!HasComponent(service) && !LazyLoadComponent(null, 
service))
                        {
                                throw new ComponentNotFoundException(service);
                        }
@@ -253,7 +253,7 @@
                        if (key == null) throw new ArgumentNullException("key");
                        if (arguments == null) throw new 
ArgumentNullException("arguments");
 
-                       if (!HasComponent(key))
+                       if (!HasComponent(key) && !LazyLoadComponent(key, null))
                        {
                                throw new ComponentNotFoundException(key);
                        }
@@ -286,7 +286,7 @@
                        if (key == null) throw new ArgumentNullException("key");
                        if (service == null) throw new 
ArgumentNullException("service");
 
-                       if (!HasComponent(key))
+                       if (!HasComponent(key) && !LazyLoadComponent(key, 
service))
                        {
                                throw new ComponentNotFoundException(key);
                        }
@@ -319,7 +319,7 @@
                        if (key == null) throw new ArgumentNullException("key");
                        if (service == null) throw new 
ArgumentNullException("service");
 
-                       if (!HasComponent(key))
+                       if (!HasComponent(key) && 
!LazyLoadComponent(key,service))
                        {
                                throw new ComponentNotFoundException(key);

File [modified]: DefaultKernel_Resolve.cs
Delta lines: +22 -21
===================================================================

--- InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/AbstractHandler.cs 
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/AbstractHandler.cs 
2009-11-15 22:40:29 UTC (rev 6335)
@@ -16,6 +16,7 @@
 {
        using System;
        using System.Collections;
+       using System.Collections.Generic;
        using System.Collections.Specialized;
        using System.Diagnostics;
        using System.Text;
@@ -36,12 +37,12 @@
                /// <summary>
                /// Dictionary of Type to a list of <see 
cref="DependencyModel"/>
                /// </summary>
-               private IDictionary dependenciesByService;
+               private IDictionary<Type, DependencyModel> 
dependenciesByService;
 
                /// <summary>
                /// Dictionary of key (string) to <see cref="DependencyModel"/>
                /// </summary>
-               private IDictionary dependenciesByKey;
+               private IDictionary<string, DependencyModel> dependenciesByKey;
 
                /// <summary>
                /// Custom dependencies values associated with the handler
@@ -292,9 +293,9 @@
                        {
                                sb.Append("\r\nKeys (components with specific 
keys)\r\n");
 
-                               foreach (DictionaryEntry entry in 
DependenciesByKey)
+                               foreach (var dependency in DependenciesByKey)
                                {
-                                       String key = entry.Key.ToString();
+                                       String key = dependency.Key;
 
                                        IHandler handler = 
Kernel.GetHandler(key);
 
@@ -486,14 +487,14 @@
 
                        if (dependency.DependencyType == DependencyType.Service 
&& dependency.TargetType != null)
                        {
-                               if 
(DependenciesByService.Contains(dependency.TargetType))
+                               if 
(DependenciesByService.ContainsKey(dependency.TargetType))
                                {
                                        return;
                                }
 
                                
DependenciesByService.Add(dependency.TargetType, dependency);
                        }
-                       else if 
(!DependenciesByKey.Contains(dependency.DependencyKey))
+                       else if 
(!DependenciesByKey.ContainsKey(dependency.DependencyKey))
                        {
                                DependenciesByKey.Add(dependency.DependencyKey, 
dependency);
                        }
@@ -552,11 +553,11 @@
 
                        // Check within the Kernel
 
-                       foreach (DictionaryEntry kvp in new 
Hashtable(DependenciesByService))
+                       foreach (var pair in new 
Dictionary<Type,DependencyModel>(DependenciesByService))
                        {
-                               Type service = (Type)kvp.Key;
-                               DependencyModel dependencyModel = 
(DependencyModel)kvp.Value;
-                               if (HasValidComponent(service, dependencyModel))
+                               Type service = pair.Key;
+                               DependencyModel dependency = pair.Value;
+                               if (HasValidComponent(service, dependency))
                                {
                                        DependenciesByService.Remove(service);
                                        IHandler dependingHandler = 
kernel.GetHandler(service);
@@ -565,14 +566,14 @@
                                }
                        }
 
-                       foreach (DictionaryEntry kvp in new 
Hashtable(DependenciesByKey))
+                       foreach (var pair in new 
Dictionary<string,DependencyModel>(DependenciesByKey))
                        {
-                               string compKey = (string)kvp.Key;
-                               DependencyModel dependency = 
(DependencyModel)kvp.Value;
-                               if (HasValidComponent(compKey, dependency) || 
HasCustomParameter(compKey))
+                               string key = pair.Key;
+                               DependencyModel dependency = pair.Value;
+                               if (HasValidComponent(key, dependency) || 
HasCustomParameter(key))
                                {
-                                       DependenciesByKey.Remove(compKey);
-                                       IHandler dependingHandler = 
kernel.GetHandler(compKey);
+                                       DependenciesByKey.Remove(key);
+                                       IHandler dependingHandler = 
kernel.GetHandler(key);
                                        if(dependingHandler!=null)//may not be 
real handler, if we are using sub resovler
                                                
AddGraphDependency(dependingHandler.ComponentModel);
                                }
@@ -648,25 +649,25 @@
                        state = newState;
                }
 
-               protected IDictionary DependenciesByService
+               protected IDictionary<Type,DependencyModel> 
DependenciesByService
                {
                        get
                        {
                                if (dependenciesByService == null)
                                {
-                                       dependenciesByService = new 
HybridDictionary();
+                                       dependenciesByService = new 
Dictionary<Type, DependencyModel>();
                                }
                                return dependenciesByService;
                        }
                }
 
-               protected IDictionary DependenciesByKey
+               protected IDictionary<string, DependencyModel> DependenciesByKey
                {
                        get
                        {
                                if (dependenciesByKey == null)
                                {
-                                       dependenciesByKey = new 
HybridDictionary();
+                                       dependenciesByKey = new 
Dictionary<string, DependencyModel>();
                                }
                                return dependenciesByKey;
                        }
@@ -727,7 +728,7 @@
                        ComponentModel.AddDependent(model);
                }
 
-               private DependencyModel[] Union(ICollection firstset, 
ICollection secondset)
+               private DependencyModel[] Union(ICollection<DependencyModel> 
firstset, ICollection<DependencyModel> secondset)
                {
                        DependencyModel[] result = new 
DependencyModel[firstset.Count + secondset.Count];

Directory: /InversionOfControl/trunk/src/Castle.MicroKernel.Tests/
==================================================================

File [modified]: Castle.MicroKernel.Tests-vs2008.csproj
Delta lines: +139 -0
===================================================================

--- 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/LazyLoadingTestCase.cs    
                            (rev 0)
+++ 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/LazyLoadingTestCase.cs    
    2009-11-15 22:40:29 UTC (rev 6335)
@@ -0,0 +1,139 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// 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.
+
+namespace Castle.MicroKernel.Tests
+{
+       using System;
+
+       using Castle.MicroKernel.Registration;
+       using Castle.MicroKernel.Resolvers;
+
+       using NUnit.Framework;
+
+       [TestFixture]
+       public class LazyLoadingTestCase
+       {
+               private IKernel kernel;
+
+               [SetUp]
+               public void SetUp()
+               {
+                       kernel = new DefaultKernel();
+                       
kernel.AddComponent<Loader>(typeof(ILazyComponentLoader));
+               }
+
+               [Test]
+               public void Can_Lazily_resolve_component()
+               {
+
+                       var service = kernel.Resolve("foo", 
typeof(IHasDefaultImplementation));
+                       Assert.IsNotNull(service);
+                       Assert.IsInstanceOf<Implementation>(service);
+               }
+
+               [Test]
+               public void Can_lazily_resolve_dependency()
+               {
+                       kernel.AddComponent<UsingLazyComponent>();
+                       var component = kernel.Resolve<UsingLazyComponent>();
+                       Assert.IsNotNull(component.Dependency);
+               }
+
+               [Test]
+               [Ignore("Not sure how to do this in an elegant way... plus I 
don't think it's the right place for this anyway.")]
+               public void Can_lazily_resolve_parameters()
+               {
+                       kernel.AddComponent<UsingString>();
+                       var component = kernel.Resolve<UsingString>();
+                       Assert.AreEqual("Foo", component.Parameter);
+               }
+       }
+
+       public class Loader : ILazyComponentLoader
+       {
+
+               public IRegistration Load(string key, Type service)
+               {
+                       if (!Attribute.IsDefined(service, 
typeof(DefaultImplementationAttribute)))
+                       {
+                               return null;
+                       }
+
+                       var attributes = 
service.GetCustomAttributes(typeof(DefaultImplementationAttribute), false);
+                       var attribute = attributes[0] as 
DefaultImplementationAttribute;
+                       return 
Component.For(service).ImplementedBy(attribute.Implementation).Named(key);
+               }
+       }
+
+       public class UsingString
+       {
+               private readonly string parameter;
+
+               public UsingString(string parameter)
+               {
+                       this.parameter = parameter;
+               }
+
+               public string Parameter
+               {
+                       get { return parameter; }
+               }
+       }
+
+
+       public class UsingLazyComponent
+       {
+               private IHasDefaultImplementation dependency;
+
+               public UsingLazyComponent(IHasDefaultImplementation dependency)
+               {
+                       this.dependency = dependency;
+               }
+
+               public IHasDefaultImplementation Dependency
+               {
+                       get { return dependency; }
+               }
+       }
+
+       [DefaultImplementation(typeof(Implementation))]
+       public interface IHasDefaultImplementation
+       {
+               void Foo();
+       }
+
+       public class Implementation : IHasDefaultImplementation
+       {
+               public void Foo()
+               {
+                       
+               }
+       }
+
+       [AttributeUsage(AttributeTargets.Interface,AllowMultiple = false)]
+       public class DefaultImplementationAttribute:Attribute
+       {
+               private readonly Type implementation;
+
+               public DefaultImplementationAttribute(Type implementation)
+               {
+                       this.implementation = implementation;
+               }
+
+               public Type Implementation
+               {
+                       get { return implementation; }
+               }
+       }
+}

File [added]: LazyLoadingTestCase.cs
Delta lines: +4 -0
===================================================================

--- 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/MyLifestyleHandler.cs
    2009-11-15 22:33:44 UTC (rev 6334)
+++ 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/MyLifestyleHandler.cs
    2009-11-15 22:40:29 UTC (rev 6335)
@@ -18,6 +18,10 @@
 
        public class MyLifestyleHandler : AbstractLifestyleManager
        {
+               public MyLifestyleHandler()
+               {
+               }
+
                public override void Dispose()
                {

Directory: 
/InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Lifestyle/Components/
=======================================================================================

File [modified]: MyLifestyleHandler.cs
Delta lines: +0 -0
===================================================================

Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/
=====================================================================

File [modified]: AbstractHandler.cs
Delta lines: +33 -4
===================================================================

--- InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/DefaultHandler.cs  
2009-11-15 22:33:44 UTC (rev 6334)
+++ InversionOfControl/trunk/src/Castle.MicroKernel/Handlers/DefaultHandler.cs  
2009-11-15 22:40:29 UTC (rev 6335)
@@ -16,7 +16,11 @@
 {
        using System;
        using System.Collections;
+       using System.Linq;
+
        using Castle.Core;
+       using Castle.MicroKernel.Resolvers;
+       using Castle.MicroKernel.SubSystems.Naming;
 
        /// <summary>
        /// Summary description for DefaultHandler.
@@ -66,18 +70,24 @@
                        if (context.HandlerIsCurrentlyBeingResolved(this))
                                return false;
 
-            foreach (Type service in DependenciesByService.Keys)
+                       foreach (var dependency in 
DependenciesByService.Values.ToArray())
                        {
                                // a self-dependency is not allowed
-                               var handler = Kernel.GetHandler(service);
+                               var handler = 
Kernel.GetHandler(dependency.TargetType);
                                if (handler == this)
                                        return false;
 
                                // ask the kernel
-                               if (!Kernel.HasComponent(service))
+                               if (Kernel.HasComponent(dependency.TargetType)) 
continue;
+
+                               // let's try to lazy load the dependency...
+                               if 
(!LazyLoadComponent(dependency.DependencyKey, dependency.TargetType))
                                        return false;
+                               // and see if we can have it this time around
+                               // if the previous call returned true we always 
should
+                               if (!Kernel.HasComponent(dependency.TargetType))
+                                       return false;
                        }
-                       
                        return DependenciesByKey.Count == 0;
                }
 
@@ -102,5 +112,24 @@
                                throw new HandlerException(message);
                        }
                }
+
+               private bool LazyLoadComponent(string dependencyKey, Type 
targetType)
+               {
+                       if (dependencyKey == null && targetType == null)
+                       {
+                               throw new ArgumentException("At least one - 
dependencyKey or targetType must not be a null reference.");
+                       }
+
+                       foreach (var loader in 
Kernel.ResolveAll<ILazyComponentLoader>())
+                       {
+                               var registration = loader.Load(dependencyKey, 
targetType);
+                               if (registration != null)
+                               {
+                                       registration.Register(Kernel);
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
        }

File [modified]: DefaultHandler.cs
Delta lines: +45 -0
===================================================================

--- 
InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/ILazyComponentLoader.cs
                           (rev 0)
+++ 
InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/ILazyComponentLoader.cs
   2009-11-15 22:40:29 UTC (rev 6335)
@@ -0,0 +1,45 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// 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.
+
+namespace Castle.MicroKernel.Resolvers
+{
+       using System;
+
+       using Castle.MicroKernel.Registration;
+
+       /// <summary>
+       /// Provides lazy registration capabilities to the container.
+       /// </summary>
+       /// <remarks>
+       /// When a component is requested from a container, that has not been 
registered
+       /// container loads up all the implementers of this interface and asks 
them in turn
+       /// whethere they can provide that component, until it finds one that 
will.
+       /// </remarks>
+       public interface ILazyComponentLoader
+       {
+               /// <summary>
+               /// Used by container to allow the loader gister component for 
given <paramref name="key"/> and <paramref name="service"/> to the container at 
the time when it is requested
+               /// </summary>
+               /// <param name="key">Key of the requested component or 
null</param>
+               /// <param name="service">Type of requested service or 
null</param>
+               /// <returns>Registration that registers component for given 
key and/or service or null.</returns>
+               /// <remarks>
+               /// While both key and service can be null reference it is 
guaranteed that at least one of them will not be null.
+               /// When implementer opts in to provide the requested component 
(by returning not-null registration) it is required
+               /// to register component for requested key/service combination 
(when one of the elements is null, it should be ignored as well).
+               /// When implementer does not want to register the requested 
component it nust return null.
+               /// </remarks>
+               IRegistration Load(string key, Type service);
+       }
+}

Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/Resolvers/
======================================================================

File [added]: ILazyComponentLoader.cs
Delta lines: +1 -0
===================================================================

--- 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Castle.MicroKernel.Tests-vs2008.csproj
        2009-11-15 22:33:44 UTC (rev 6334)
+++ 
InversionOfControl/trunk/src/Castle.MicroKernel.Tests/Castle.MicroKernel.Tests-vs2008.csproj
        2009-11-15 22:40:29 UTC (rev 6335)
@@ -229,6 +229,7 @@
     <Compile Include="GraphTestCase.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="LazyLoadingTestCase.cs" />
     <Compile Include="Lifecycle\Components\HttpFakeServer.cs">
       <SubType>Code</SubType>

--

You received this message because you are subscribed to the Google Groups 
"Castle Project Commits" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/castle-project-commits?hl=.


Reply via email to