User: xtoff
Date: 2009/12/23 10:11 AM
Added:
/InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/
DefaultTypedFactoryComponentSelector.cs, Dispose.cs,
ITypedFactoryComponentSelector.cs, ITypedFactoryMethod.cs, Release.cs,
Resolve.cs, TypedFactoryInterceptor.cs, TypedFactoryRegistrationExtensions.cs
/InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/
TypedFactoryFacilityTake2TestCase.cs
Modified:
/InversionOfControl/trunk/src/Castle.MicroKernel/
Castle.MicroKernel-vs2008.csproj
/InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/
Empty.cs, FactoryEntry.cs, TypedFactoryFacility.cs
/InversionOfControl/trunk/src/Castle.Windsor.Tests/
Castle.Windsor.Tests-vs2008.csproj
/InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/
ExternalConfigurationTestCase.cs, TypedFactoryTestCase.cs,
typedFactory_castle_config.xml
Log:
- added some new features to TypedFactoryFacility:
- Access to fluent registration API (via AsFactory() extension method).
- XML registration is still supported (using existing fallback
mechanism or new one, if no creation/destruction method is explicitly specified)
- Any non-void method is 'creation' method, all it's arguments are
passed as named parameters to kernel.
- Any void method is 'destruction' method, releasing all it's non-null
arguments.
- by default compoments to resolve are matched by type (method's return
type). When method is named GetSOMETHIG, SOMETHING will be used as component's
name.
- default matching may be changed by registering custom implementation
of ITypedFactoryComponentSelector.
- when factory implements IDisposable, Dispose will dispose inner
container used by the factory, and all transient components along with it.
Any feedback on this is appreciated.
File Changes:
Directory: /InversionOfControl/trunk/src/Castle.MicroKernel/
============================================================
File [modified]: Castle.MicroKernel-vs2008.csproj
Delta lines: +36 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/DefaultTypedFactoryComponentSelector.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/DefaultTypedFactoryComponentSelector.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,36 @@
+// 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.Facilities.TypedFactory
+{
+ using System;
+ using System.Reflection;
+
+ using Castle.Core;
+
+ public class DefaultTypedFactoryComponentSelector :
ITypedFactoryComponentSelector
+ {
+ public Pair<string, Type> SelectComponent(MethodInfo method,
Type type)
+ {
+ string componentName = null;
+ if (method.Name.StartsWith("Get"))
+ {
+ componentName =
method.Name.Substring("get".Length);
+ }
+ var componentType = method.ReturnType;
+
+ return new Pair<string,
Type>(componentName,componentType);
+ }
+ }
+}
Directory: /InversionOfControl/trunk/src/Castle.Windsor.Tests/
==============================================================
File [modified]: Castle.Windsor.Tests-vs2008.csproj
Delta lines: +26 -12
===================================================================
---
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/ExternalConfigurationTestCase.cs
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/ExternalConfigurationTestCase.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -27,31 +27,31 @@
[TestFixture]
public class ExternalConfigurationTestCase
{
- private IWindsorContainer _container;
+ private IWindsorContainer container;
[SetUp]
public void Init()
{
- _container = new
WindsorContainer(ConfigHelper.ResolveConfigPath("Facilities/TypedFactory/typedFactory_castle_config.xml"));
+ container = new
WindsorContainer(ConfigHelper.ResolveConfigPath("Facilities/TypedFactory/typedFactory_castle_config.xml"));
- _container.AddFacility( "typedfactory", new
TypedFactoryFacility() );
+ container.AddFacility( "typedfactory", new
TypedFactoryFacility() );
- _container.AddComponent( "miranda",
typeof(IProtocolHandler), typeof(MirandaProtocolHandler) );
- _container.AddComponent( "messenger",
typeof(IProtocolHandler), typeof(MessengerProtocolHandler) );
- _container.AddComponent( "comp1",
typeof(IDummyComponent), typeof(Component1) );
- _container.AddComponent( "comp2",
typeof(IDummyComponent), typeof(Component2) );
+ container.AddComponent( "miranda",
typeof(IProtocolHandler), typeof(MirandaProtocolHandler) );
+ container.AddComponent( "messenger",
typeof(IProtocolHandler), typeof(MessengerProtocolHandler) );
+ container.AddComponent( "comp1",
typeof(IDummyComponent), typeof(Component1) );
+ container.AddComponent( "comp2",
typeof(IDummyComponent), typeof(Component2) );
}
[TearDown]
public void Finish()
{
- _container.Dispose();
+ container.Dispose();
}
[Test]
public void Factory1()
{
- var factory = (IProtocolHandlerFactory1)
_container["protocolFac1"];
+ var factory = (IProtocolHandlerFactory1)
container["protocolFac1"];
Assert.IsNotNull( factory );
@@ -65,7 +65,7 @@
[Test]
public void Factory2()
{
- var factory = (IProtocolHandlerFactory2)
_container["protocolFac2"];
+ var factory = (IProtocolHandlerFactory2)
container["protocolFac2"];
Assert.IsNotNull( factory );
@@ -83,7 +83,7 @@
[Test]
public void Factory3()
{
- var factory = (IComponentFactory1)
_container["compFactory1"];
+ var factory = (IComponentFactory1)
container["compFactory1"];
Assert.IsNotNull( factory );
@@ -97,7 +97,7 @@
[Test]
public void Factory4()
{
- var factory = (IComponentFactory2)
_container["compFactory2"];
+ var factory = (IComponentFactory2)
container["compFactory2"];
Assert.IsNotNull( factory );
var comp1 = (IDummyComponent)factory.Construct("comp1");
@@ -108,6 +108,20 @@
Assert.IsTrue( comp2 is Component2 );
Assert.IsNotNull( comp2 );
}
+
+ [Test]
+ public void No_Creation_Or_Destruction_methods_defined()
+ {
+ var factory =
(IComponentFactory1)container["NoCreationOrDestructionDefined"];
+
+ Assert.IsNotNull(factory);
+
+ var comp1 = factory.Construct();
+ Assert.IsNotNull(comp1);
+
+ var comp2 = factory.Construct();
+ Assert.IsNotNull(comp2);
+ }
}
}
Directory:
/InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/
====================================================================================
File [added]: DefaultTypedFactoryComponentSelector.cs
Delta lines: +35 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Dispose.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Dispose.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,35 @@
+// 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.Facilities.TypedFactory
+{
+ using System;
+
+ using Castle.Core.Interceptor;
+
+ public class Dispose : ITypedFactoryMethod
+ {
+ private readonly Action disposeCallback;
+
+ public Dispose(Action disposeCallback)
+ {
+ this.disposeCallback = disposeCallback;
+ }
+
+ public void Invoke(IInvocation invocation)
+ {
+ disposeCallback();
+ }
+ }
+}
File [added]: Dispose.cs
Delta lines: +0 -2
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Empty.cs
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Empty.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -14,8 +14,6 @@
namespace Castle.Facilities.TypedFactory
{
- using System;
-
public class Empty
{
File [modified]: Empty.cs
Delta lines: +14 -14
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/FactoryEntry.cs
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/FactoryEntry.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -18,42 +18,42 @@
public class FactoryEntry
{
- private String _id;
- private String _creationMethod;
- private String _destructionMethod;
- private Type _factoryInterface;
+ private readonly String id;
+ private readonly String creationMethod;
+ private readonly String destructionMethod;
+ private readonly Type factoryInterface;
public FactoryEntry(String id, Type factoryInterface, String
creationMethod, String destructionMethod)
{
- if (id == null || id.Length == 0) throw new
ArgumentNullException("id");
+ if (string.IsNullOrEmpty(id)) throw new
ArgumentNullException("id");
if (factoryInterface == null) throw new
ArgumentNullException("factoryInterface");
if (!factoryInterface.IsInterface) throw new
ArgumentException("factoryInterface must be an interface");
- if (creationMethod == null || creationMethod.Length ==
0) throw new ArgumentNullException("creationMethod");
+ if (string.IsNullOrEmpty(creationMethod)) throw new
ArgumentNullException("creationMethod");
- _id = id;
- _factoryInterface = factoryInterface;
- _creationMethod = creationMethod;
- _destructionMethod = destructionMethod;
+ this.id = id;
+ this.factoryInterface = factoryInterface;
+ this.creationMethod = creationMethod;
+ this.destructionMethod = destructionMethod;
}
public String Id
{
- get { return _id; }
+ get { return id; }
}
public Type FactoryInterface
{
- get { return _factoryInterface; }
+ get { return factoryInterface; }
}
public String CreationMethod
{
- get { return _creationMethod; }
+ get { return creationMethod; }
}
public String DestructionMethod
{
- get { return _destructionMethod; }
+ get { return destructionMethod; }
}
}
File [modified]: FactoryEntry.cs
Delta lines: +37 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/ITypedFactoryComponentSelector.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/ITypedFactoryComponentSelector.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,37 @@
+// 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.Facilities.TypedFactory
+{
+ using System;
+ using System.Reflection;
+
+ using Castle.Core;
+
+ public interface ITypedFactoryComponentSelector
+ {
+ /// <summary>
+ /// Selects one or both of component name and type, for given
method
+ /// called on given typed factory type.
+ /// When component should be requested by type only,
+ /// name (first argument of returned pair) should be null.
+ /// When component should be requested by name only,
+ /// type (second argument of returned pair) should be null.
+ /// </summary>
+ /// <param name="method"></param>
+ /// <param name="type"></param>
+ /// <returns></returns>
+ Pair<string, Type> SelectComponent(MethodInfo method, Type
type);
+ }
+}
File [added]: ITypedFactoryComponentSelector.cs
Delta lines: +27 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/ITypedFactoryMethod.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/ITypedFactoryMethod.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,27 @@
+// 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.Facilities.TypedFactory
+{
+ using Castle.Core.Interceptor;
+
+ public interface ITypedFactoryMethod
+ {
+ /// <summary>
+ /// Performs actual invocation of typed factory method.
+ /// </summary>
+ /// <param name="invocation"></param>
+ void Invoke(IInvocation invocation);
+ }
+}
File [added]: ITypedFactoryMethod.cs
Delta lines: +41 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Release.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Release.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,41 @@
+// 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.Facilities.TypedFactory
+{
+ using Castle.Core.Interceptor;
+
+ /// <summary>
+ /// Releases components passed as arguments from the container.
+ /// </summary>
+ public class Release : ITypedFactoryMethod
+ {
+ private readonly IKernel kernel;
+
+ public Release(IKernel kernel)
+ {
+ this.kernel = kernel;
+ }
+
+ public void Invoke(IInvocation invocation)
+ {
+ foreach (var argument in invocation.Arguments)
+ {
+ if(argument==null) continue;
+
+ kernel.ReleaseComponent(argument);
+ }
+ }
+ }
+}
File [added]: Release.cs
Delta lines: +64 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Resolve.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/Resolve.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,64 @@
+// 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.Facilities.TypedFactory
+{
+ using System.Collections.Generic;
+
+ using Castle.Core.Interceptor;
+
+ /// <summary>
+ /// resolves componet selected by given <see
cref="ITypedFactoryComponentSelector"/> from the container
+ /// </summary>
+ public class Resolve : ITypedFactoryMethod
+ {
+ private readonly IKernel kernel;
+ private readonly ITypedFactoryComponentSelector selector;
+ public Resolve(IKernel kernel, ITypedFactoryComponentSelector
selector)
+ {
+ this.kernel = kernel;
+ this.selector = selector;
+ }
+
+ public void Invoke(IInvocation invocation)
+ {
+ var component =
selector.SelectComponent(invocation.Method, invocation.TargetType);
+ var arguments = GetArguments(invocation);
+ if (component.First == null)
+ {
+ invocation.ReturnValue =
kernel.Resolve(component.Second, arguments);
+ return;
+ }
+
+ if (component.Second == null)
+ {
+ invocation.ReturnValue =
kernel.Resolve(component.First, arguments);
+ return;
+ }
+
+ invocation.ReturnValue =
kernel.Resolve(component.First, component.Second, arguments);
+ }
+
+ private Dictionary<string, object> GetArguments(IInvocation
invocation)
+ {
+ var arguments = new Dictionary<string, object>();
+ var parameters = invocation.Method.GetParameters();
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ arguments.Add(parameters[i].Name,
invocation.GetArgumentValue(i));
+ }
+ return arguments;
+ }
+ }
+}
File [added]: Resolve.cs
Delta lines: +53 -27
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryFacility.cs
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryFacility.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -1,4 +1,3 @@
-
// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,28 +27,36 @@
/// </summary>
public class TypedFactoryFacility : AbstractFacility
{
- public void AddTypedFactoryEntry( FactoryEntry entry )
+ internal static readonly string InterceptorKey =
"Castle.TypedFactory.Interceptor";
+
+ [Obsolete("This method is obsolete. Use AsFactory() extension
method on fluent registration API instead.")]
+ public void AddTypedFactoryEntry(FactoryEntry entry)
{
- ComponentModel model =
- new ComponentModel(entry.Id,
entry.FactoryInterface, typeof(Empty));
-
- model.LifestyleType = LifestyleType.Singleton;
+ var model = new ComponentModel(entry.Id,
entry.FactoryInterface, typeof(Empty)) { LifestyleType =
LifestyleType.Singleton };
+
model.ExtendedProperties["typed.fac.entry"] = entry;
- model.Interceptors.Add( new InterceptorReference(
typeof(FactoryInterceptor) ) );
+ model.Interceptors.Add(new
InterceptorReference(typeof(FactoryInterceptor)));
- ProxyOptions proxyOptions =
ProxyUtil.ObtainProxyOptions(model, true);
+ var proxyOptions = ProxyUtil.ObtainProxyOptions(model,
true);
proxyOptions.OmitTarget = true;
- Kernel.AddCustomComponent( model );
+ Kernel.AddCustomComponent(model);
}
protected override void Init()
{
- Kernel.AddComponent( "typed.fac.interceptor",
typeof(FactoryInterceptor) );
+ Kernel.AddComponent(InterceptorKey,
typeof(TypedFactoryInterceptor), LifestyleType.Transient);
- ITypeConverter converter = (ITypeConverter)
- Kernel.GetSubSystem(
SubSystemConstants.ConversionManagerKey );
+ LegacyInit();
+ }
+ private void LegacyInit()
+ {
+ Kernel.AddComponent("typed.fac.interceptor",
typeof(FactoryInterceptor));
+
+ var converter = (ITypeConverter)
+
Kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);
+
AddFactories(FacilityConfig, converter);
}
@@ -57,28 +64,47 @@
{
if (facilityConfig != null)
{
- foreach(IConfiguration config in
facilityConfig.Children["factories"].Children)
+ foreach (IConfiguration config in
facilityConfig.Children["factories"].Children)
{
- String id = config.Attributes["id"];
- String creation =
config.Attributes["creation"];
- String destruction =
config.Attributes["destruction"];
+ var id = config.Attributes["id"];
+ var creation =
config.Attributes["creation"];
+ var destruction =
config.Attributes["destruction"];
- Type factoryType = (Type)
- converter.PerformConversion(
config.Attributes["interface"], typeof(Type) );
-
- try
+ var factoryType =
(Type)converter.PerformConversion(config.Attributes["interface"], typeof(Type));
+ if(string.IsNullOrEmpty(creation))
{
- AddTypedFactoryEntry(
- new FactoryEntry(id,
factoryType, creation, destruction) );
+ RegisterFactory(id,
factoryType);
+ continue;
}
- catch(Exception)
- {
- string message = "Invalid
factory entry in configuration";
- throw new Exception(message);
- }
+ RegisterFactoryLegacy(creation, id,
factoryType, destruction);
}
}
}
+
+ private void RegisterFactory(string id, Type type)
+ {
+ var model = new ComponentModel(id, type, type) {
LifestyleType = LifestyleType.Singleton };
+ model.Interceptors.Add(new
InterceptorReference(typeof(TypedFactoryInterceptor)));
+ ProxyUtil.ObtainProxyOptions(model, true).OmitTarget =
true;
+
+ Kernel.AddCustomComponent(model);
+ }
+
+ private void RegisterFactoryLegacy(string creation, string id,
Type factoryType, string destruction)
+ {
+ try
+ {
+#pragma warning disable 0618 //call to obsolete method
+ AddTypedFactoryEntry(new FactoryEntry(id,
factoryType, creation, destruction));
+#pragma warning restore
+ }
+ catch (Exception)
+ {
+ string message = "Invalid factory entry in
configuration";
+
+ throw new Exception(message);
+ }
+ }
}
File [modified]: TypedFactoryFacility.cs
Delta lines: +111 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryInterceptor.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryInterceptor.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,111 @@
+// 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.Facilities.TypedFactory
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reflection;
+
+ using Castle.Core;
+ using Castle.Core.Interceptor;
+ using Castle.MicroKernel;
+ using Castle.MicroKernel.Facilities.TypedFactory;
+
+ public class TypedFactoryInterceptor : IInterceptor, IOnBehalfAware,
IDisposable
+ {
+ private readonly IKernel kernel;
+
+ private readonly IDictionary<MethodInfo, ITypedFactoryMethod>
methods =
+ new Dictionary<MethodInfo, ITypedFactoryMethod>();
+
+ private ComponentModel target;
+ private bool disposed;
+
+ public TypedFactoryInterceptor(IKernel parent)
+ : this(parent, new
DefaultTypedFactoryComponentSelector())
+ {
+ // if no selector is registered, we'll use the default
+ }
+
+ public TypedFactoryInterceptor(IKernel parent,
ITypedFactoryComponentSelector componentSelector)
+ {
+ ComponentSelector = componentSelector;
+ kernel = new DefaultKernel();
+ parent.AddChildKernel(kernel);
+ }
+
+ public ITypedFactoryComponentSelector ComponentSelector { get;
set; }
+
+
+ public void Dispose()
+ {
+ disposed = true;
+ kernel.Dispose();
+ }
+ public void Intercept(IInvocation invocation)
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException("this", "The
factory was disposed and can no longer be used.");
+ }
+
+ var method = methods[invocation.Method];
+ method.Invoke(invocation);
+ }
+
+ public void SetInterceptedComponentModel(ComponentModel target)
+ {
+ this.target = target;
+ BuildHandlersMap();
+ }
+
+ protected virtual void BuildHandlersMap()
+ {
+ MethodInfo dispose = GetDisposeMethod();
+
+ foreach (MethodInfo method in
target.Service.GetMethods())
+ {
+ if (method == dispose)
+ {
+ methods.Add(method, new
Dispose(Dispose));
+ continue;
+ }
+ if (IsReleaseMethod(method))
+ {
+ methods.Add(method, new
Release(kernel));
+ continue;
+ }
+ //TODO: had collection handling
+ methods.Add(method, new Resolve(kernel,
ComponentSelector));
+ }
+ }
+
+ private MethodInfo GetDisposeMethod()
+ {
+ if
(!typeof(IDisposable).IsAssignableFrom(target.Service))
+ {
+ return null;
+ }
+
+ return
target.Service.GetInterfaceMap(typeof(IDisposable)).TargetMethods.Single();
+ }
+
+ private bool IsReleaseMethod(MethodInfo methodInfo)
+ {
+ return methodInfo.ReturnType == typeof(void);
+ }
+ }
+}
File [added]: TypedFactoryInterceptor.cs
Delta lines: +69 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryRegistrationExtensions.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.MicroKernel/Facilities/TypedFactory/TypedFactoryRegistrationExtensions.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,69 @@
+// 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.Facilities.TypedFactory
+{
+ using System;
+ using System.Linq;
+
+ using Castle.Core;
+ using Castle.Core.Interceptor;
+ using Castle.MicroKernel;
+ using Castle.MicroKernel.Registration;
+
+ public static class TypedFactoryRegistrationExtensions
+ {
+ /// <summary>
+ /// Marks the component as typed factory.
+ /// </summary>
+ /// <typeparam name="S"></typeparam>
+ /// <param name="registration"></param>
+ /// <returns></returns>
+ /// <remarks>
+ /// Only interfaces are legal to use as typed factories.
Methods with out parameters are not allowed.
+ /// When registering component as typed factory no
implementation should be provided (in case there is any it will be ignored).
+ /// Typed factories rely on <see cref="IInterceptorSelector"/>
set internally, so users should not set interceptor selectors explicitly;
+ /// otherwise the factory will not function correctly.
+ /// </remarks>
+ public static ComponentRegistration<S> AsFactory<S>(this
ComponentRegistration<S> registration)
+ {
+ if( registration == null )
+ {
+ throw new ArgumentNullException( "registration"
);
+ }
+
+ if (registration.ServiceType.IsInterface == false)
+ {
+ throw new ComponentRegistrationException(
+ string.Format("Type {0} is not an
interface. Only interfaces may be used as typed factories.",
+
registration.ServiceType));
+ }
+
+ if(HasOutArguments(registration.ServiceType))
+ {
+ throw new ComponentRegistrationException(
+ string.Format("Type {0} can not be used
as typed factory because it has methods with 'out' arguments.",
+
registration.ServiceType));
+ }
+
+ return registration.Interceptors( new
InterceptorReference( TypedFactoryFacility.InterceptorKey ) ).Last;
+
+ }
+
+ private static bool HasOutArguments(Type serviceType)
+ {
+ return serviceType.GetMethods().Any(m =>
m.GetParameters().Any(p => p.IsOut));
+ }
+ }
+}
File [added]: TypedFactoryRegistrationExtensions.cs
Delta lines: +1 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.Windsor.Tests/Castle.Windsor.Tests-vs2008.csproj
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.Windsor.Tests/Castle.Windsor.Tests-vs2008.csproj
2009-12-23 17:11:42 UTC (rev 6529)
@@ -284,6 +284,7 @@
<Compile Include="Facilities\TypedFactory\Factories\IComponentFactory.cs"
/>
<Compile
Include="Facilities\TypedFactory\Factories\IProtocolHandlerFactory.cs" />
<Compile Include="Facilities\TypedFactory\TypedFactoryTestCase.cs" />
+ <Compile
Include="Facilities\TypedFactory\TypedFactoryFacilityTake2TestCase.cs" />
<Compile Include="InterceptorSelectorTestCase.cs" />
<Compile Include="OpenGenericsTestCase.cs" />
Directory:
/InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/
======================================================================================
File [modified]: ExternalConfigurationTestCase.cs
Delta lines: +103 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/TypedFactoryFacilityTake2TestCase.cs
(rev 0)
+++
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/TypedFactoryFacilityTake2TestCase.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -0,0 +1,103 @@
+// 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.Facilities.TypedFactory.Tests
+{
+ using System;
+ using System.Reflection;
+
+ using Castle.Core;
+ using Castle.Facilities.TypedFactory.Tests.Components;
+ using Castle.MicroKernel.Facilities.TypedFactory;
+ using Castle.MicroKernel.Registration;
+ using Castle.Windsor;
+
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class TypedFactoryFacilityTake2TestCase
+ {
+ private WindsorContainer container;
+
+ [SetUp]
+ public void SetUp()
+ {
+ container = new WindsorContainer();
+ container.AddFacility<TypedFactoryFacility>();
+ container.AddComponentLifeStyle<IDummyComponent,
Component1>(LifestyleType.Transient);
+ }
+
+ [Test]
+ public void Can_resolve_component()
+ {
+
container.Register(Component.For<DummyComponentFactory>().AsFactory());
+ var factory =
container.Resolve<DummyComponentFactory>();
+
+ var component = factory.CreateDummyComponent();
+ Assert.IsNotNull(component);
+ }
+
+ [Test]
+ public void
Can_resolve_component_by_name_with_default_selector()
+ {
+ container.Register(
+ Component.For<IDummyComponent>()
+ .ImplementedBy<Component2>()
+ .Named("SecondComponent")
+ .LifeStyle.Transient,
+ Component.For<DummyComponentFactory>()
+ .AsFactory());
+ var factory =
container.Resolve<DummyComponentFactory>();
+
+ var component = factory.GetSecondComponent();
+ Assert.IsNotNull(component);
+ Assert.IsInstanceOf<Component2>(component);
+ }
+
+ [Test]
+ public void Can_use_non_default_selector()
+ {
+ container.Register(
+ Component.For<IDummyComponent>()
+ .ImplementedBy<Component2>()
+ .Named("foo")
+ .LifeStyle.Transient,
+ Component.For<DummyComponentFactory>()
+ .AsFactory(),
+ Component.For<ITypedFactoryComponentSelector>()
+ .ImplementedBy<FooSelector>());
+ var factory =
container.Resolve<DummyComponentFactory>();
+
+ var component = factory.GetSecondComponent();
+ Assert.IsInstanceOf<Component2>(component);
+
+ component = factory.CreateDummyComponent();
+ Assert.IsInstanceOf<Component2>(component);
+ }
+ }
+
+ public interface DummyComponentFactory
+ {
+ IDummyComponent CreateDummyComponent();
+ IDummyComponent GetSecondComponent();
+ }
+
+ public class FooSelector:ITypedFactoryComponentSelector
+ {
+ public Pair<string, Type> SelectComponent(MethodInfo method,
Type type)
+ {
+ return new Pair<string, Type>("foo", null);
+ }
+ }
+}
File [added]: TypedFactoryFacilityTake2TestCase.cs
Delta lines: +10 -7
===================================================================
---
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/TypedFactoryTestCase.cs
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/TypedFactoryTestCase.cs
2009-12-23 17:11:42 UTC (rev 6529)
@@ -14,8 +14,6 @@
namespace Castle.Facilities.TypedFactory.Tests
{
- using System;
-
using Castle.Windsor;
using Castle.MicroKernel.SubSystems.Configuration;
@@ -51,10 +49,11 @@
[Test]
public void Factory1()
{
+#pragma warning disable 0618 //call to obsolete method
_facility.AddTypedFactoryEntry(
new FactoryEntry(
- "protocolHandlerFactory",
typeof(IProtocolHandlerFactory1), "Create", "Release") );
-
+ "protocolHandlerFactory",
typeof(IProtocolHandlerFactory1), "Create", "Release"));
+#pragma warning restore
_container.AddComponent( "miranda",
typeof(IProtocolHandler), typeof(MirandaProtocolHandler) );
_container.AddComponent( "messenger",
typeof(IProtocolHandler), typeof(MessengerProtocolHandler) );
@@ -73,10 +72,11 @@
[Test]
public void Factory2()
{
+#pragma warning disable 0618 //call to obsolete method
_facility.AddTypedFactoryEntry(
new FactoryEntry(
"protocolHandlerFactory",
typeof(IProtocolHandlerFactory2), "Create", "Release") );
-
+#pragma warning restore
_container.AddComponent( "miranda",
typeof(IProtocolHandler), typeof(MirandaProtocolHandler) );
_container.AddComponent( "messenger",
typeof(IProtocolHandler), typeof(MessengerProtocolHandler) );
@@ -99,10 +99,11 @@
[Test]
public void Factory3()
{
+#pragma warning disable 0618 //call to obsolete method
_facility.AddTypedFactoryEntry(
new FactoryEntry(
"compFactory", typeof(IComponentFactory1),
"Construct", "") );
-
+#pragma warning restore
_container.AddComponent( "comp1",
typeof(IDummyComponent), typeof(Component1) );
_container.AddComponent( "comp2",
typeof(IDummyComponent), typeof(Component2) );
@@ -121,9 +122,11 @@
[Test]
public void Factory4()
{
+#pragma warning disable 0618 //call to obsolete method
_facility.AddTypedFactoryEntry(
new FactoryEntry(
- "compFactory", typeof(IComponentFactory2),
"Construct", "") );
+ "compFactory", typeof(IComponentFactory2),
"Construct", ""));
+#pragma warning restore
_container.AddComponent( "comp1",
typeof(IDummyComponent), typeof(Component1) );
File [modified]: TypedFactoryTestCase.cs
Delta lines: +3 -0
===================================================================
---
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/typedFactory_castle_config.xml
2009-12-23 05:23:04 UTC (rev 6528)
+++
InversionOfControl/trunk/src/Castle.Windsor.Tests/Facilities/TypedFactory/typedFactory_castle_config.xml
2009-12-23 17:11:42 UTC (rev 6529)
@@ -18,6 +18,9 @@
<factory id="protocolFac2"
interface="Castle.Facilities.TypedFactory.Tests.Factories.IProtocolHandlerFactory2,
Castle.Windsor.Tests"
creation="Create" destruction="Release" />
+
+ <factory id="NoCreationOrDestructionDefined"
+
interface="Castle.Facilities.TypedFactory.Tests.Factories.IComponentFactory1,
Castle.Windsor.Tests" />
</factories>
</facility>
File [modified]: typedFactory_castle_config.xml
Delta lines: +0 -0
===================================================================
--
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=en.