hammett 2004/03/30 19:45:08
Modified: avalon-net/Castle/MicroKernel
Apache.Avalon.Castle.MicroKernel.csproj
AssemblyInfo.cs AssertUtil.cs BaseKernel.cs
ConstructionInfo.cs
avalon-net/Castle/MicroKernel/Factory
SimpleComponentFactory.cs
avalon-net/Castle/MicroKernel/Handlers SimpleHandler.cs
avalon-net/Castle/MicroKernel/MicroKernelTest
AssemblyInfo.cs MicroKernelTest.csproj
SimpleComponentFactoryTestCase.cs
Added: avalon-net/Castle/MicroKernel/Handlers AbstractHandler.cs
avalon-net/Castle/MicroKernel/MicroKernelTest/Components
ICustomerManager.cs IMailMarketingService.cs
SimpleCustomerManager.cs
SimpleMailMarketingService.cs
Log:
Added "dependency injection" through set methods (properties)
Revision Changes Path
1.2 +5 -0
avalon-sandbox/avalon-net/Castle/MicroKernel/Apache.Avalon.Castle.MicroKernel.csproj
Index: Apache.Avalon.Castle.MicroKernel.csproj
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/Apache.Avalon.Castle.MicroKernel.csproj,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Apache.Avalon.Castle.MicroKernel.csproj 31 Mar 2004 00:43:30 -0000 1.1
+++ Apache.Avalon.Castle.MicroKernel.csproj 31 Mar 2004 03:45:08 -0000 1.2
@@ -174,6 +174,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "Handlers\AbstractHandler.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "Handlers\SimpleHandler.cs"
SubType = "Code"
BuildAction = "Compile"
1.2 +1 -1 avalon-sandbox/avalon-net/Castle/MicroKernel/AssemblyInfo.cs
Index: AssemblyInfo.cs
===================================================================
RCS file: /home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/AssemblyInfo.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AssemblyInfo.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ AssemblyInfo.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -1,4 +1,4 @@
-// Copyright 2004 Apache Software Foundation
+// Copyright 2004 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
1.2 +3 -1 avalon-sandbox/avalon-net/Castle/MicroKernel/AssertUtil.cs
Index: AssertUtil.cs
===================================================================
RCS file: /home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/AssertUtil.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AssertUtil.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ AssertUtil.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -29,7 +29,9 @@
{
if (argValue == null)
{
- throw new ArgumentNullException(argName,
String.Format("Argument {0} can't be null", argName) );
+ throw new ArgumentNullException(
+ argName,
+ String.Format("Argument {0} can't be null",
argName) );
}
}
}
1.2 +2 -0 avalon-sandbox/avalon-net/Castle/MicroKernel/BaseKernel.cs
Index: BaseKernel.cs
===================================================================
RCS file: /home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/BaseKernel.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- BaseKernel.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ BaseKernel.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -221,6 +221,8 @@
DependencyListenerDelegate del =
(DependencyListenerDelegate) m_dependencyToSatisfy[ service ];
del( service, handler );
+
+ m_dependencyToSatisfy.Remove( service );
}
}
}
1.2 +17 -0 avalon-sandbox/avalon-net/Castle/MicroKernel/ConstructionInfo.cs
Index: ConstructionInfo.cs
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/ConstructionInfo.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ConstructionInfo.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ ConstructionInfo.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -27,8 +27,12 @@
private Hashtable m_service2handler;
+ private PropertyInfo[] m_properties = new PropertyInfo[0];
+
public ConstructionInfo(ConstructorInfo constructor, Hashtable
service2handler)
{
+ AssertUtil.ArgumentNotNull( constructor, "constructor" );
+
m_constructor = constructor;
m_service2handler = service2handler;
}
@@ -38,6 +42,19 @@
get
{
return m_constructor;
+ }
+ }
+
+ public PropertyInfo[] Properties
+ {
+ get
+ {
+ return m_properties;
+ }
+ set
+ {
+ AssertUtil.ArgumentNotNull( value, "value" );
+ m_properties = value;
}
}
1.2 +6 -0
avalon-sandbox/avalon-net/Castle/MicroKernel/Factory/SimpleComponentFactory.cs
Index: SimpleComponentFactory.cs
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/Factory/SimpleComponentFactory.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SimpleComponentFactory.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ SimpleComponentFactory.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -62,6 +62,12 @@
new AspectInvocationHandler( m_before,
m_after, instance ) );
}
+ foreach( PropertyInfo property in m_info.Properties )
+ {
+ IHandler handler = m_info[
property.PropertyType ];
+ property.SetValue( instance,
handler.Resolve(), null);
+ }
+
return instance;
}
catch(Exception ex)
1.2 +69 -68
avalon-sandbox/avalon-net/Castle/MicroKernel/Handlers/SimpleHandler.cs
Index: SimpleHandler.cs
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/Handlers/SimpleHandler.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SimpleHandler.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ SimpleHandler.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -21,44 +21,43 @@
/// <summary>
/// Summary description for SimpleHandler.
/// </summary>
- public class SimpleHandler : IHandler
+ public class SimpleHandler : AbstractHandler
{
- protected Type m_service;
-
- protected Type m_implementation;
-
- protected Kernel m_kernel;
-
- private State m_state = State.Valid;
-
private ConstructorInfo m_constructor;
-
- private ArrayList m_dependencies = new ArrayList();
-
- private Hashtable m_serv2handler = new Hashtable();
-
- private ILifestyleManager m_lifestyleManager;
+
+ private ArrayList m_properties = new ArrayList();
/// <summary>
///
/// </summary>
/// <param name="service"></param>
/// <param name="implementation"></param>
- public SimpleHandler(Type service, Type implementation)
+ public SimpleHandler(Type service, Type implementation) :
base(service, implementation)
{
- AssertUtil.ArgumentNotNull( service, "service" );
- AssertUtil.ArgumentNotNull( implementation, "implementation" );
-
- m_service = service;
- m_implementation = implementation;
}
#region IHandler Members
- public void Init( Kernel kernel )
+ public override void Init( Kernel kernel )
{
- m_kernel = kernel;
+ base.Init(kernel);
+
+ InspectConstructors();
+ InspectSetMethods();
+
+ // Now we check with the kernel if
+ // we have the necessary implementations
+ // for the services requested by the constructor
+
+ EnsureHaveRequiredImplementations();
+
+ CreateComponentFactoryAndLifestyleManager();
+ }
+ #endregion
+
+ protected void InspectConstructors()
+ {
ConstructorInfo[] constructors =
m_implementation.GetConstructors();
// TODO: Try to sort the array
@@ -80,50 +79,35 @@
throw new HandlerException(
String.Format("Handler could not find an
eligible constructor for type {0}", m_implementation.FullName) );
}
-
- // Now we check with the kernel if
- // we have the necessary implementations
- // for the services requested by the constructor
-
- EnsureHaveRequiredImplementations();
-
- CreateComponentFactoryAndLifestyleManager();
}
- public object Resolve()
+ protected void InspectSetMethods()
{
- if (m_state == State.WaitingDependency)
- {
- throw new HandlerException("Can't Resolve component.
It has dependencies to be satisfied.");
- }
+ PropertyInfo[] properties = m_service.GetProperties();
- try
+ foreach(PropertyInfo property in properties)
{
- return m_lifestyleManager.Resolve();
- }
- catch(Exception ex)
- {
- throw new HandlerException("Exception while attempting
to instantiate type", ex);
+ if (IsEligible( property ))
+ {
+ AddDependency( property.PropertyType );
+
+ m_properties.Add( property );
+ }
}
}
- public void Release()
+ protected bool IsEligible( PropertyInfo property )
{
- m_lifestyleManager.Release();
- }
+ // TODO: An attribute could say to use
+ // that the property is optional.
- /// <summary>
- ///
- /// </summary>
- public State ActualState
- {
- get
+ if (!property.CanWrite || !property.PropertyType.IsInterface)
{
- return m_state;
+ return false;
}
- }
- #endregion
+ return true;
+ }
protected bool IsEligible( ConstructorInfo constructor )
{
@@ -132,11 +116,10 @@
foreach(ParameterInfo parameter in parameters)
{
if (parameter.ParameterType == typeof(String) &&
- !parameter.Name.Equals("contextdir")) // Just
as sample
+ !parameter.Name.Equals("contextdir")) // Just
a sample
{
return false;
}
-
if (!parameter.ParameterType.IsInterface)
{
return false;
@@ -154,22 +137,39 @@
{
if (parameter.ParameterType.IsInterface)
{
- if (m_kernel.HasService(
parameter.ParameterType ))
- {
-
m_serv2handler[parameter.ParameterType] =
- m_kernel.GetHandlerForService(
parameter.ParameterType );
- }
- else
- {
- m_kernel.AddDependencyListener(
parameter.ParameterType, new DependencyListenerDelegate(DependencySatisfied) );
-
- m_state = State.WaitingDependency;
- m_dependencies.Add(
parameter.ParameterType );
- }
+ AddDependency( parameter.ParameterType );
}
}
}
+ protected void AddDependency( Type service )
+ {
+ if (m_kernel.HasService( service ))
+ {
+ m_serv2handler[ service ] =
m_kernel.GetHandlerForService( service );
+ }
+ else
+ {
+ // This is handler is considered invalid
+ // until dependencies are satisfied
+ m_state = State.WaitingDependency;
+ m_dependencies.Add( service );
+
+ // Register ourself in the kernel
+ // to be notified if the dependency is satified
+ m_kernel.AddDependencyListener(
+ service,
+ new
DependencyListenerDelegate(DependencySatisfied) );
+ }
+ }
+
+ /// <summary>
+ /// Delegate implementation invoked by kernel
+ /// when one of registered dependencies were satisfied by
+ /// new components registered.
+ /// </summary>
+ /// <param name="service"></param>
+ /// <param name="handler"></param>
private void DependencySatisfied( Type service, IHandler handler )
{
m_serv2handler[ service ] = handler;
@@ -185,6 +185,7 @@
private void CreateComponentFactoryAndLifestyleManager()
{
ConstructionInfo info = new ConstructionInfo( m_constructor,
m_serv2handler );
+ info.Properties = (PropertyInfo[]) m_properties.ToArray(
typeof(PropertyInfo) );
IComponentFactory factory = new
Factory.SimpleComponentFactory(
m_service, m_implementation,
1.1
avalon-sandbox/avalon-net/Castle/MicroKernel/Handlers/AbstractHandler.cs
Index: AbstractHandler.cs
===================================================================
// Copyright 2004 The Apache Software Foundation
//
// 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 Apache.Avalon.Castle.MicroKernel.Handlers
{
using System;
using System.Collections;
/// <summary>
/// Summary description for AbstractHandler.
/// </summary>
public abstract class AbstractHandler : IHandler
{
protected Type m_service;
protected Type m_implementation;
protected Kernel m_kernel;
protected State m_state = State.Valid;
protected ArrayList m_dependencies = new ArrayList();
protected Hashtable m_serv2handler = new Hashtable();
protected ILifestyleManager m_lifestyleManager;
/// <summary>
///
/// </summary>
/// <param name="service"></param>
/// <param name="implementation"></param>
public AbstractHandler(Type service, Type implementation)
{
AssertUtil.ArgumentNotNull( service, "service" );
AssertUtil.ArgumentNotNull( implementation, "implementation" );
m_service = service;
m_implementation = implementation;
}
#region IHandler Members
public virtual void Init( Kernel kernel )
{
m_kernel = kernel;
}
public virtual object Resolve()
{
if (m_state == State.WaitingDependency)
{
throw new HandlerException("Can't Resolve component.
It has dependencies to be satisfied.");
}
try
{
return m_lifestyleManager.Resolve();
}
catch(Exception ex)
{
throw new HandlerException("Exception while attempting
to instantiate type", ex);
}
}
public virtual void Release()
{
m_lifestyleManager.Release();
}
/// <summary>
///
/// </summary>
public virtual State ActualState
{
get
{
return m_state;
}
}
#endregion
}
}
1.2 +1 -1
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/AssemblyInfo.cs
Index: AssemblyInfo.cs
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/AssemblyInfo.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AssemblyInfo.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ AssemblyInfo.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -1,4 +1,4 @@
-// Copyright 2004 Apache Software Foundation
+// Copyright 2004 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
1.2 +20 -0
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/MicroKernelTest.csproj
Index: MicroKernelTest.csproj
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/MicroKernelTest.csproj,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MicroKernelTest.csproj 31 Mar 2004 00:43:30 -0000 1.1
+++ MicroKernelTest.csproj 31 Mar 2004 03:45:08 -0000 1.2
@@ -124,12 +124,32 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "Components\ICustomerManager.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Components\IMailMarketingService.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "Components\IMailService.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Components\ISpamService.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Components\SimpleCustomerManager.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Components\SimpleMailMarketingService.cs"
SubType = "Code"
BuildAction = "Compile"
/>
1.2 +41 -0
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/SimpleComponentFactoryTestCase.cs
Index: SimpleComponentFactoryTestCase.cs
===================================================================
RCS file:
/home/cvs/avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/SimpleComponentFactoryTestCase.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SimpleComponentFactoryTestCase.cs 31 Mar 2004 00:43:30 -0000 1.1
+++ SimpleComponentFactoryTestCase.cs 31 Mar 2004 03:45:08 -0000 1.2
@@ -92,5 +92,46 @@
factory.Etherialize();
}
+
+ [Test]
+ public void DependencyInSetMethods()
+ {
+ Type service = typeof( IMailMarketingService );
+ Type implementation = typeof( SimpleMailMarketingService );
+ Type serviceDep1 = typeof( IMailService );
+ Type implementationDep1 = typeof( SimpleMailService );
+ Type serviceDep2 = typeof( ICustomerManager );
+ Type implementationDep2 = typeof( SimpleCustomerManager );
+
+ kernel.AddComponent( "a", service, implementation );
+ kernel.AddComponent( "b", serviceDep1, implementationDep1 );
+ kernel.AddComponent( "c", serviceDep2, implementationDep2 );
+
+ ConstructorInfo constructor =
+ implementation.GetConstructor( Type.EmptyTypes );
+
+ Hashtable serv2Handler = new Hashtable();
+ serv2Handler[ serviceDep1 ] = kernel.GetHandlerForService(
serviceDep1 );
+ serv2Handler[ serviceDep2 ] = kernel.GetHandlerForService(
serviceDep2 );
+
+ ConstructionInfo info = new ConstructionInfo( constructor,
serv2Handler );
+ info.Properties = service.GetProperties();
+
+ SimpleComponentFactory factory = new SimpleComponentFactory(
+ service, implementation, new IAspect[0], new
IAspect[0], info );
+
+ Object instance = factory.Incarnate();
+
+ AssertNotNull( instance );
+ AssertNotNull( instance as IMailMarketingService );
+
+ SimpleMailMarketingService mailMarketing =
(SimpleMailMarketingService) instance;
+ AssertNotNull( mailMarketing.m_mailService );
+ AssertNotNull( mailMarketing.m_customerManager );
+
+ mailMarketing.AnnoyMillionsOfPeople( "Say something" );
+
+ factory.Etherialize();
+ }
}
}
1.1
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/Components/ICustomerManager.cs
Index: ICustomerManager.cs
===================================================================
// Copyright 2004 The Apache Software Foundation
//
// 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 Apache.Avalon.Castle.MicroKernel.Test.Components
{
using System;
/// <summary>
/// Summary description for ICustomerManager.
/// </summary>
public interface ICustomerManager
{
object[] Customers
{
get;
}
}
}
1.1
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/Components/IMailMarketingService.cs
Index: IMailMarketingService.cs
===================================================================
// Copyright 2004 The Apache Software Foundation
//
// 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 Apache.Avalon.Castle.MicroKernel.Test.Components
{
using System;
/// <summary>
/// Summary description for IMailMarketingService.
/// </summary>
public interface IMailMarketingService
{
ICustomerManager CustomerManager
{
get;
set;
}
IMailService MailService
{
get;
set;
}
void AnnoyMillionsOfPeople(String message);
}
}
1.1
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/Components/SimpleCustomerManager.cs
Index: SimpleCustomerManager.cs
===================================================================
// Copyright 2004 The Apache Software Foundation
//
// 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 Apache.Avalon.Castle.MicroKernel.Test.Components
{
using System;
/// <summary>
/// Summary description for SimpleCustomerManager.
/// </summary>
public class SimpleCustomerManager : ICustomerManager
{
public SimpleCustomerManager()
{
}
#region ICustomerManager Members
public object[] Customers
{
get
{
return null;
}
}
#endregion
}
}
1.1
avalon-sandbox/avalon-net/Castle/MicroKernel/MicroKernelTest/Components/SimpleMailMarketingService.cs
Index: SimpleMailMarketingService.cs
===================================================================
// Copyright 2004 The Apache Software Foundation
//
// 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 Apache.Avalon.Castle.MicroKernel.Test.Components
{
using System;
/// <summary>
/// Summary description for SimpleMailMarketingService.
/// </summary>
public class SimpleMailMarketingService : IMailMarketingService
{
public IMailService m_mailService;
public ICustomerManager m_customerManager;
public SimpleMailMarketingService()
{
}
#region IMailMarketingService Members
public ICustomerManager CustomerManager
{
get
{
return m_customerManager;
}
set
{
m_customerManager = value;
}
}
public IMailService MailService
{
get
{
return m_mailService;
}
set
{
m_mailService = value;
}
}
public void AnnoyMillionsOfPeople(String message)
{
if (MailService == null)
{
throw new NullReferenceException("IMailService wasn't
supplied.");
}
if (CustomerManager == null)
{
throw new NullReferenceException("ICustomerManager
wasn't supplied.");
}
}
#endregion
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]