1 // Copyright 2004-2007 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
;
21 using Castle
.Core
.Interceptor
;
22 using Castle
.MicroKernel
.LifecycleConcerns
;
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.
31 /// Custom implementors can just override the <c>CreateInstance</c> method.
32 /// Please note however that the activator is responsible for the proxy creation
36 public class DefaultComponentActivator
: AbstractComponentActivator
39 /// Initializes a new instance of the <see cref="DefaultComponentActivator"/> class.
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
);
65 protected override void InternalDestroy(object instance
)
67 ApplyDecommissionConcerns(instance
);
72 protected virtual object Instantiate(CreationContext context
)
74 ConstructorCandidate candidate
= SelectEligibleConstructor(context
);
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;
93 createInstance
= Kernel
.ProxyFactory
.RequiresTargetInstance(Kernel
, Model
);
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
);
109 throw new ComponentActivatorException(
110 "ComponentActivator: could not instantiate " + Model
.Implementation
.FullName
, ex
);
118 instance
= Kernel
.ProxyFactory
.Create(Kernel
, instance
, Model
, arguments
);
122 throw new ComponentActivatorException("ComponentActivator: could not proxy " + Model
.Implementation
.FullName
, ex
);
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
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;
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
)
209 if (constructor
== null) return new object[0];
211 object[] arguments
= new object[constructor
.Constructor
.GetParameters().Length
];
212 signature
= new Type
[arguments
.Length
];
216 foreach (DependencyModel dependency
in constructor
.Dependencies
)
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
;
230 protected virtual void SetUpProperties(object instance
, CreationContext context
)
232 instance
= GetUnproxiedInstance(instance
);
234 foreach (PropertySet property
in Model
.Properties
)
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 }
);
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();