1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Reflection
;
19 using System
.Runtime
.Remoting
;
20 using System
.Security
;
21 using System
.Security
.Permissions
;
23 using Castle
.Core
.Interceptor
;
24 using Castle
.MicroKernel
.LifecycleConcerns
;
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.
33 /// Custom implementors can just override the <c>CreateInstance</c> method.
34 /// Please note however that the activator is responsible for the proxy creation
38 public class DefaultComponentActivator
: AbstractComponentActivator
40 private readonly bool useFastCreateInstance
;
43 /// Initializes a new instance of the <see cref="DefaultComponentActivator"/> class.
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
);
70 protected override void InternalDestroy(object instance
)
72 ApplyDecommissionConcerns(instance
);
77 protected virtual object Instantiate(CreationContext context
)
79 ConstructorCandidate candidate
= SelectEligibleConstructor(context
);
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;
98 createInstance
= Kernel
.ProxyFactory
.RequiresTargetInstance(Kernel
, Model
);
105 if (useFastCreateInstance
)
107 instance
= FastCreateInstance(implType
, arguments
, signature
);
111 instance
= Activator
.CreateInstance(implType
, arguments
);
116 throw new ComponentActivatorException(
117 "ComponentActivator: could not instantiate " + Model
.Implementation
.FullName
, ex
);
125 instance
= Kernel
.ProxyFactory
.Create(Kernel
, instance
, Model
, arguments
);
129 throw new ComponentActivatorException("ComponentActivator: could not proxy " + Model
.Implementation
.FullName
, ex
);
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
);
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
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;
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
)
227 if (constructor
== null) return new object[0];
229 object[] arguments
= new object[constructor
.Constructor
.GetParameters().Length
];
230 signature
= new Type
[arguments
.Length
];
234 foreach (DependencyModel dependency
in constructor
.Dependencies
)
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
;
248 protected virtual void SetUpProperties(object instance
, CreationContext context
)
250 instance
= GetUnproxiedInstance(instance
);
252 foreach (PropertySet property
in Model
.Properties
)
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 }
);
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();