Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / InversionOfControl / Castle.MicroKernel / ComponentActivator / DefaultComponentActivator.cs
blobbfe94e69e7bcce9602b1daa2d4fb4c5f4cb91421
1 // Copyright 2004-2008 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 System.Security;
21 using System.Security.Permissions;
22 using Castle.Core;
23 using Castle.Core.Interceptor;
24 using Castle.MicroKernel.LifecycleConcerns;
26 /// <summary>
27 /// Standard implementation of <see cref="IComponentActivator"/>.
28 /// Handles the selection of the best constructor, fills the
29 /// writable properties the component exposes, run the commission
30 /// and decommission lifecycles, etc.
31 /// </summary>
32 /// <remarks>
33 /// Custom implementors can just override the <c>CreateInstance</c> method.
34 /// Please note however that the activator is responsible for the proxy creation
35 /// when needed.
36 /// </remarks>
37 [Serializable]
38 public class DefaultComponentActivator : AbstractComponentActivator
40 private readonly bool useFastCreateInstance;
42 /// <summary>
43 /// Initializes a new instance of the <see cref="DefaultComponentActivator"/> class.
44 /// </summary>
45 /// <param name="model"></param>
46 /// <param name="kernel"></param>
47 /// <param name="onCreation"></param>
48 /// <param name="onDestruction"></param>
49 public DefaultComponentActivator(ComponentModel model, IKernel kernel,
50 ComponentInstanceDelegate onCreation,
51 ComponentInstanceDelegate onDestruction)
52 : base(model, kernel, onCreation, onDestruction)
54 useFastCreateInstance = !model.Implementation.IsContextful && SecurityManager.IsGranted(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
57 #region AbstractComponentActivator Members
59 protected override object InternalCreate(CreationContext context)
61 object instance = Instantiate(context);
63 SetUpProperties(instance, context);
65 ApplyCommissionConcerns(instance);
67 return instance;
70 protected override void InternalDestroy(object instance)
72 ApplyDecommissionConcerns(instance);
75 #endregion
77 protected virtual object Instantiate(CreationContext context)
79 ConstructorCandidate candidate = SelectEligibleConstructor(context);
81 Type[] signature;
82 object[] arguments = CreateConstructorArguments(candidate, context, out signature);
84 return CreateInstance(context, arguments, signature);
87 protected virtual object CreateInstance(CreationContext context, object[] arguments, Type[] signature)
89 object instance = null;
91 Type implType = Model.Implementation;
93 bool createProxy = Model.Interceptors.HasInterceptors;
94 bool createInstance = true;
96 if (createProxy)
98 createInstance = Kernel.ProxyFactory.RequiresTargetInstance(Kernel, Model);
101 if (createInstance)
105 if (useFastCreateInstance)
107 instance = FastCreateInstance(implType, arguments, signature);
109 else
111 instance = Activator.CreateInstance(implType, arguments);
114 catch(Exception ex)
116 throw new ComponentActivatorException(
117 "ComponentActivator: could not instantiate " + Model.Implementation.FullName, ex);
121 if (createProxy)
125 instance = Kernel.ProxyFactory.Create(Kernel, instance, Model, arguments);
127 catch(Exception ex)
129 throw new ComponentActivatorException("ComponentActivator: could not proxy " + Model.Implementation.FullName, ex);
133 return instance;
136 private static object FastCreateInstance(Type implType, object[] arguments, Type[] signature)
138 ConstructorInfo cinfo = implType.GetConstructor(
139 BindingFlags.Public | BindingFlags.Instance, null, signature, null);
141 object instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(implType);
143 cinfo.Invoke(instance, arguments);
144 return instance;
147 protected virtual void ApplyCommissionConcerns(object instance)
149 instance = GetUnproxiedInstance(instance);
150 object[] steps = Model.LifecycleSteps.GetCommissionSteps();
151 ApplyConcerns(steps, instance);
154 protected virtual void ApplyDecommissionConcerns(object instance)
156 instance = GetUnproxiedInstance(instance);
157 object[] steps = Model.LifecycleSteps.GetDecommissionSteps();
158 ApplyConcerns(steps, instance);
161 protected virtual void ApplyConcerns(object[] steps, object instance)
163 foreach(ILifecycleConcern concern in steps)
165 concern.Apply(Model, instance);
169 protected virtual ConstructorCandidate SelectEligibleConstructor(CreationContext context)
171 if (Model.Constructors.Count == 0)
173 // This is required by some facilities
174 return null;
177 if (Model.Constructors.Count == 1)
179 return Model.Constructors.FewerArgumentsCandidate;
182 ConstructorCandidate winnerCandidate = null;
184 int winnerPoints = 0;
186 foreach(ConstructorCandidate candidate in Model.Constructors)
188 int candidatePoints = 0;
190 foreach(DependencyModel dep in candidate.Dependencies)
192 if (CanSatisfyDependency(context, dep))
194 candidatePoints += 2;
196 else
198 candidatePoints -= 2;
202 if (winnerCandidate == null || winnerPoints < candidatePoints)
204 winnerCandidate = candidate;
205 winnerPoints = candidatePoints;
209 if (winnerCandidate == null)
211 throw new ComponentActivatorException("Could not find eligible constructor for " + Model.Implementation.FullName);
214 return winnerCandidate;
217 protected virtual bool CanSatisfyDependency(CreationContext context, DependencyModel dep)
219 return Kernel.Resolver.CanResolve(context, context.Handler, Model, dep);
222 protected virtual object[] CreateConstructorArguments(
223 ConstructorCandidate constructor, CreationContext context, out Type[] signature)
225 signature = null;
227 if (constructor == null) return new object[0];
229 object[] arguments = new object[constructor.Constructor.GetParameters().Length];
230 signature = new Type[arguments.Length];
232 int index = 0;
234 foreach (DependencyModel dependency in constructor.Dependencies)
236 object value;
237 using (new DependencyTrackingScope(context, Model, constructor.Constructor, dependency))
239 value = Kernel.Resolver.Resolve(context, context.Handler, Model, dependency);
241 arguments[index] = value;
242 signature[index++] = dependency.TargetType;
245 return arguments;
248 protected virtual void SetUpProperties(object instance, CreationContext context)
250 instance = GetUnproxiedInstance(instance);
252 foreach (PropertySet property in Model.Properties)
254 object value = null;
256 using (new DependencyTrackingScope(context, Model, property.Property, property.Dependency))
258 if (Kernel.Resolver.CanResolve(context, context.Handler, Model, property.Dependency))
260 value = Kernel.Resolver.Resolve(context, context.Handler, Model, property.Dependency);
264 if (value == null) continue;
266 MethodInfo setMethod = property.Property.GetSetMethod();
270 setMethod.Invoke(instance, new object[] { value });
272 catch (Exception ex)
274 String message =
275 String.Format(
276 "Error setting property {0} on type {1}, Component id is {2}. See inner exception for more information.",
277 setMethod.Name, instance.GetType().FullName, Model.Name);
278 throw new ComponentActivatorException(message, ex);
283 private static object GetUnproxiedInstance(object instance)
285 if (!RemotingServices.IsTransparentProxy(instance))
287 IProxyTargetAccessor accessor = instance as IProxyTargetAccessor;
289 if (accessor != null)
291 instance = accessor.DynProxyGetTarget();
295 return instance;