Added container accessor to Castle.Core
[castle.git] / InversionOfControl / Castle.MicroKernel / ComponentActivator / DefaultComponentActivator.cs
blob00ba52dae44d9d8d29850c3d31c68d7aa52102fe
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MicroKernel.ComponentActivator
17 using System;
18 using System.Reflection;
19 using System.Runtime.Remoting;
20 using Castle.Core;
21 using Castle.Core.Interceptor;
22 using Castle.MicroKernel.LifecycleConcerns;
24 /// <summary>
25 /// Standard implementation of <see cref="IComponentActivator"/>.
26 /// Handles the selection of the best constructor, fills the
27 /// writable properties the component exposes, run the commission
28 /// and decommission lifecycles, etc.
29 /// </summary>
30 /// <remarks>
31 /// Custom implementors can just override the <c>CreateInstance</c> method.
32 /// Please note however that the activator is responsible for the proxy creation
33 /// when needed.
34 /// </remarks>
35 [Serializable]
36 public class DefaultComponentActivator : AbstractComponentActivator
38 /// <summary>
39 /// Initializes a new instance of the <see cref="DefaultComponentActivator"/> class.
40 /// </summary>
41 /// <param name="model"></param>
42 /// <param name="kernel"></param>
43 /// <param name="onCreation"></param>
44 /// <param name="onDestruction"></param>
45 public DefaultComponentActivator(ComponentModel model, IKernel kernel,
46 ComponentInstanceDelegate onCreation,
47 ComponentInstanceDelegate onDestruction)
48 : base(model, kernel, onCreation, onDestruction)
52 #region AbstractComponentActivator Members
54 protected override object InternalCreate(CreationContext context)
56 object instance = Instantiate(context);
58 SetUpProperties(instance, context);
60 ApplyCommissionConcerns(instance);
62 return instance;
65 protected override void InternalDestroy(object instance)
67 ApplyDecommissionConcerns(instance);
70 #endregion
72 protected virtual object Instantiate(CreationContext context)
74 ConstructorCandidate candidate = SelectEligibleConstructor(context);
76 Type[] signature;
77 object[] arguments = CreateConstructorArguments(candidate, context, out signature);
79 return CreateInstance(context, arguments, signature);
82 protected virtual object CreateInstance(CreationContext context, object[] arguments, Type[] signature)
84 object instance = null;
86 Type implType = Model.Implementation;
88 bool createProxy = Model.Interceptors.HasInterceptors;
89 bool createInstance = true;
91 if (createProxy)
93 createInstance = Kernel.ProxyFactory.RequiresTargetInstance(Kernel, Model);
96 if (createInstance)
98 try
100 ConstructorInfo cinfo = implType.GetConstructor(
101 BindingFlags.Public | BindingFlags.Instance, null, signature, null);
103 instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(implType);
105 cinfo.Invoke(instance, arguments);
107 catch (Exception ex)
109 throw new ComponentActivatorException(
110 "ComponentActivator: could not instantiate " + Model.Implementation.FullName, ex);
114 if (createProxy)
118 instance = Kernel.ProxyFactory.Create(Kernel, instance, Model, arguments);
120 catch (Exception ex)
122 throw new ComponentActivatorException("ComponentActivator: could not proxy " + Model.Implementation.FullName, ex);
126 return instance;
129 protected virtual void ApplyCommissionConcerns(object instance)
131 instance = GetUnproxiedInstance(instance);
132 object[] steps = Model.LifecycleSteps.GetCommissionSteps();
133 ApplyConcerns(steps, instance);
136 protected virtual void ApplyDecommissionConcerns(object instance)
138 instance = GetUnproxiedInstance(instance);
139 object[] steps = Model.LifecycleSteps.GetDecommissionSteps();
140 ApplyConcerns(steps, instance);
143 protected virtual void ApplyConcerns(object[] steps, object instance)
145 foreach(ILifecycleConcern concern in steps)
147 concern.Apply(Model, instance);
151 protected virtual ConstructorCandidate SelectEligibleConstructor(CreationContext context)
153 if (Model.Constructors.Count == 0)
155 // This is required by some facilities
156 return null;
159 if (Model.Constructors.Count == 1)
161 return Model.Constructors.FewerArgumentsCandidate;
164 ConstructorCandidate winnerCandidate = null;
166 int winnerPoints = 0;
168 foreach(ConstructorCandidate candidate in Model.Constructors)
170 int candidatePoints = 0;
172 foreach(DependencyModel dep in candidate.Dependencies)
174 if (CanSatisfyDependency(context, dep))
176 candidatePoints += 2;
178 else
180 candidatePoints -= 2;
184 if (winnerCandidate == null || winnerPoints < candidatePoints)
186 winnerCandidate = candidate;
187 winnerPoints = candidatePoints;
191 if (winnerCandidate == null)
193 throw new ComponentActivatorException("Could not find eligible constructor for " + Model.Implementation.FullName);
196 return winnerCandidate;
199 protected virtual bool CanSatisfyDependency(CreationContext context, DependencyModel dep)
201 return Kernel.Resolver.CanResolve(context, context.Handler, Model, dep);
204 protected virtual object[] CreateConstructorArguments(
205 ConstructorCandidate constructor, CreationContext context, out Type[] signature)
207 signature = null;
209 if (constructor == null) return new object[0];
211 object[] arguments = new object[constructor.Constructor.GetParameters().Length];
212 signature = new Type[arguments.Length];
214 int index = 0;
216 foreach (DependencyModel dependency in constructor.Dependencies)
218 object value;
219 using (new DependencyTrackingScope(context, Model, constructor.Constructor, dependency))
221 value = Kernel.Resolver.Resolve(context, context.Handler, Model, dependency);
223 arguments[index] = value;
224 signature[index++] = dependency.TargetType;
227 return arguments;
230 protected virtual void SetUpProperties(object instance, CreationContext context)
232 instance = GetUnproxiedInstance(instance);
234 foreach (PropertySet property in Model.Properties)
236 object value = null;
238 using (new DependencyTrackingScope(context, Model, property.Property, property.Dependency))
240 if (Kernel.Resolver.CanResolve(context, context.Handler, Model, property.Dependency))
242 value = Kernel.Resolver.Resolve(context, context.Handler, Model, property.Dependency);
246 if (value == null) continue;
248 MethodInfo setMethod = property.Property.GetSetMethod();
252 setMethod.Invoke(instance, new object[] { value });
254 catch (Exception ex)
256 String message =
257 String.Format(
258 "Error setting property {0} on type {1}, Component id is {2}. See inner exception for more information.",
259 setMethod.Name, instance.GetType().FullName, Model.Name);
260 throw new ComponentActivatorException(message, ex);
265 private static object GetUnproxiedInstance(object instance)
267 if (!RemotingServices.IsTransparentProxy(instance))
269 IProxyTargetAccessor accessor = instance as IProxyTargetAccessor;
271 if (accessor != null)
273 instance = accessor.DynProxyGetTarget();
277 return instance;