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
.Resolvers
18 using System
.Collections
;
20 using Castle
.MicroKernel
.SubSystems
.Conversion
;
21 using Castle
.MicroKernel
.Util
;
24 /// Default implementation for <see cref="IDependencyResolver"/>.
25 /// This implementation is quite simple, but still should be useful
26 /// for 99% of situations.
29 public class DefaultDependencyResolver
: IDependencyResolver
31 private readonly IKernel kernel
;
32 private readonly ITypeConverter converter
;
33 private DependencyDelegate dependencyResolvingDelegate
;
34 private IList subResolvers
= new ArrayList();
37 /// Initializes a new instance of the <see cref="DefaultDependencyResolver"/> class.
39 /// <param name="kernel">The kernel.</param>
40 public DefaultDependencyResolver(IKernel kernel
)
44 converter
= (ITypeConverter
)kernel
.GetSubSystem(SubSystemConstants
.ConversionManagerKey
);
48 /// Initializes this instance with the specified dependency delegate.
50 /// <param name="dependencyDelegate">The dependency delegate.</param>
51 public void Initialize(DependencyDelegate dependencyDelegate
)
53 dependencyResolvingDelegate
= dependencyDelegate
;
57 /// Registers a sub resolver instance
59 /// <param name="subResolver">The subresolver instance</param>
60 public void AddSubResolver(ISubDependencyResolver subResolver
)
62 if (subResolver
== null) throw new ArgumentNullException("subResolver");
64 subResolvers
.Add(subResolver
);
68 /// Unregisters a sub resolver instance previously registered
70 /// <param name="subResolver">The subresolver instance</param>
71 public void RemoveSubResolver(ISubDependencyResolver subResolver
)
73 if (subResolver
== null) throw new ArgumentNullException("subResolver");
75 subResolvers
.Remove(subResolver
);
79 /// Returns true if the resolver is able to satisfy the specified dependency.
81 /// <param name="context">Creation context, which is a resolver itself</param>
82 /// <param name="parentResolver">Parent resolver</param>
83 /// <param name="model">Model of the component that is requesting the dependency</param>
84 /// <param name="dependency">The dependency model</param>
85 /// <returns><c>true</c> if the dependency can be satisfied</returns>
86 public bool CanResolve(CreationContext context
, ISubDependencyResolver parentResolver
, ComponentModel model
,
87 DependencyModel dependency
)
89 // 1 - check for the dependency on CreationContext, if present
93 if (context
.CanResolve(context
, parentResolver
, model
, dependency
))
99 // 2 - check with the model's handler, if not the same as the parent resolver
101 IHandler handler
= kernel
.GetHandler(model
.Name
);
103 if (handler
!= null && handler
!= parentResolver
)
105 if (handler
.CanResolve(context
, parentResolver
, model
, dependency
))
111 // 3 - check within parent resolver, if present
113 if (parentResolver
!= null)
115 if (parentResolver
.CanResolve(context
, parentResolver
, model
, dependency
))
121 // 4 - check within subresolvers
123 foreach (ISubDependencyResolver subResolver
in subResolvers
)
125 if (subResolver
.CanResolve(context
, parentResolver
, model
, dependency
))
131 // 5 - normal flow, checking against the kernel
133 if (dependency
.DependencyType
== DependencyType
.Service
||
134 dependency
.DependencyType
== DependencyType
.ServiceOverride
)
136 return CanResolveServiceDependency(context
, model
, dependency
);
140 return CanResolveParameterDependency(model
, dependency
);
145 /// Try to resolve the dependency by checking the parameters in
146 /// the model or checking the Kernel for the requested service.
149 /// The dependency resolver has the following precedence order:
150 /// <list type="bullet">
151 /// <item><description>
152 /// The dependency is checked within the <see cref="CreationContext"/>
153 /// </description></item>
154 /// <item><description>
155 /// The dependency is checked within the <see cref="IHandler"/> instance for the component
156 /// </description></item>
157 /// <item><description>
158 /// The dependency is checked within the registered <see cref="ISubDependencyResolver"/>s
159 /// </description></item>
160 /// <item><description>
161 /// Finally the resolver tries the normal flow
162 /// which is using the configuration
163 /// or other component to satisfy the dependency
164 /// </description></item>
167 /// <param name="context">Creation context, which is a resolver itself</param>
168 /// <param name="parentResolver">Parent resolver</param>
169 /// <param name="model">Model of the component that is requesting the dependency</param>
170 /// <param name="dependency">The dependency model</param>
171 /// <returns>The dependency resolved value or null</returns>
172 public object Resolve(CreationContext context
, ISubDependencyResolver parentResolver
, ComponentModel model
,
173 DependencyModel dependency
)
177 bool resolved
= false;
179 // 1 - check for the dependency on CreationContext, if present
183 if (context
.CanResolve(context
, parentResolver
, model
, dependency
))
185 value = context
.Resolve(context
, parentResolver
, model
, dependency
);
190 // 2 - check with the model's handler, if not the same as the parent resolver
192 IHandler handler
= kernel
.GetHandler(model
.Name
);
194 if (!resolved
&& handler
!= parentResolver
)
196 if (handler
.CanResolve(context
, parentResolver
, model
, dependency
))
198 value = handler
.Resolve(context
, parentResolver
, model
, dependency
);
203 // 3 - check within parent resolver, if present
205 if (!resolved
&& parentResolver
!= null)
207 if (parentResolver
.CanResolve(context
, parentResolver
, model
, dependency
))
209 value = parentResolver
.Resolve(context
, parentResolver
, model
, dependency
);
214 // 4 - check within subresolvers
218 foreach (ISubDependencyResolver subResolver
in subResolvers
)
220 if (subResolver
.CanResolve(context
, parentResolver
, model
, dependency
))
222 value = subResolver
.Resolve(context
, parentResolver
, model
, dependency
);
229 // 5 - normal flow, checking against the kernel
233 if (dependency
.DependencyType
== DependencyType
.Service
||
234 dependency
.DependencyType
== DependencyType
.ServiceOverride
)
236 value = ResolveServiceDependency(context
, model
, dependency
);
240 value = ResolveParameterDependency(context
, model
, dependency
);
244 if (value == null && !dependency
.IsOptional
)
246 String implementation
= String
.Empty
;
248 if (model
.Implementation
!= null)
250 implementation
= model
.Implementation
.FullName
;
253 String message
= String
.Format(
254 "Could not resolve non-optional dependency for '{0}' ({1}). Parameter '{2}' type '{3}'",
255 model
.Name
, implementation
, dependency
.DependencyKey
, dependency
.TargetType
.FullName
);
257 throw new DependencyResolverException(message
);
260 RaiseDependencyResolving(model
, dependency
, value);
265 protected virtual bool CanResolveServiceDependency(CreationContext context
, ComponentModel model
, DependencyModel dependency
)
267 if (dependency
.DependencyType
== DependencyType
.ServiceOverride
)
269 return HasComponentInValidState(dependency
.DependencyKey
);
272 ParameterModel parameter
= ObtainParameterModelMatchingDependency(dependency
, model
);
274 if (parameter
!= null)
276 // User wants to override
278 String
value = ExtractComponentKey(parameter
.Value
, parameter
.Name
);
280 return HasComponentInValidState(value);
282 else if (dependency
.TargetType
== typeof(IKernel
))
290 if (dependency
.TargetType
!= null)
292 return HasComponentInValidState(context
, dependency
.TargetType
);
296 return HasComponentInValidState(dependency
.DependencyKey
);
301 protected virtual bool CanResolveParameterDependency(ComponentModel model
, DependencyModel dependency
)
303 ParameterModel parameter
= ObtainParameterModelMatchingDependency(dependency
, model
);
305 return parameter
!= null;
308 protected virtual object ResolveServiceDependency(CreationContext context
, ComponentModel model
,
309 DependencyModel dependency
)
311 IHandler handler
= null;
313 if (dependency
.DependencyType
== DependencyType
.Service
)
315 ParameterModel parameter
= ObtainParameterModelMatchingDependency(dependency
, model
);
317 if (parameter
!= null)
319 // User wants to override, we then
320 // change the type to ServiceOverride
322 dependency
.DependencyKey
= ExtractComponentKey(parameter
.Value
, parameter
.Name
);
323 dependency
.DependencyType
= DependencyType
.ServiceOverride
;
327 if (dependency
.TargetType
== typeof(IKernel
))
333 if (dependency
.DependencyType
== DependencyType
.ServiceOverride
)
335 handler
= kernel
.GetHandler(dependency
.DependencyKey
);
339 handler
= TryGetHandlerFromKernel(dependency
, context
);
343 throw new DependencyResolverException(
344 "Cycle detected in configuration.\r\n" +
345 "Component " + model
.Name
+ " has a dependency on " +
346 dependency
.TargetType
+ ", but it doesn't provide an override.\r\n" +
347 "You must provide an override if a component " +
348 "has a dependency on a service that it - itself - provides");
353 if (handler
== null) return null;
355 context
= RebuildContextForParameter(context
, dependency
.TargetType
);
357 return handler
.Resolve(context
);
360 private IHandler
TryGetHandlerFromKernel(DependencyModel dependency
, CreationContext context
)
362 // we are doing it in two stages because it is likely to be faster to a lookup
363 // by key than a linear search
364 IHandler handler
= kernel
.GetHandler(dependency
.TargetType
);
365 if (context
.HandlerIsCurrentlyBeingResolved(handler
) == false)
368 // make a best effort to find another one that fit
370 IHandler
[] handlers
= kernel
.GetHandlers(dependency
.TargetType
);
372 foreach (IHandler maybeCorrectHandler
in handlers
)
374 if (context
.HandlerIsCurrentlyBeingResolved(maybeCorrectHandler
) == false)
376 handler
= maybeCorrectHandler
;
383 protected virtual object ResolveParameterDependency(CreationContext context
, ComponentModel model
,
384 DependencyModel dependency
)
386 ParameterModel parameter
= ObtainParameterModelMatchingDependency(dependency
, model
);
388 if (parameter
!= null)
390 converter
.Context
.PushModel(model
);
394 if (parameter
.Value
!= null || parameter
.ConfigValue
== null)
396 return converter
.PerformConversion(parameter
.Value
, dependency
.TargetType
);
400 return converter
.PerformConversion(parameter
.ConfigValue
, dependency
.TargetType
);
405 converter
.Context
.PopModel();
412 protected virtual ParameterModel
ObtainParameterModelMatchingDependency(DependencyModel dependency
,
413 ComponentModel model
)
415 String key
= dependency
.DependencyKey
;
417 if (key
== null) return null;
419 return model
.Parameters
[key
];
423 /// Extracts the component name from the a ref strings which is
426 /// <param name="name"></param>
427 /// <param name="keyValue"></param>
428 /// <returns></returns>
429 protected virtual String
ExtractComponentKey(String keyValue
, String name
)
431 if (!ReferenceExpressionUtil
.IsReference(keyValue
))
433 throw new DependencyResolverException(
434 String
.Format("Key invalid for parameter {0}. " +
435 "Thus the kernel was unable to override the service dependency", name
));
438 return ReferenceExpressionUtil
.ExtractComponentKey(keyValue
);
441 private void RaiseDependencyResolving(ComponentModel model
, DependencyModel dependency
, object value)
443 dependencyResolvingDelegate(model
, dependency
, value);
446 private bool HasComponentInValidState(string key
)
448 IHandler handler
= kernel
.GetHandler(key
);
450 return IsHandlerInValidState(handler
);
453 private bool HasComponentInValidState(CreationContext context
, Type service
)
455 IHandler
[] handlers
= kernel
.GetHandlers(service
);
457 foreach (IHandler handler
in handlers
)
459 if (context
== null || context
.HandlerIsCurrentlyBeingResolved(handler
) == false)
460 return IsHandlerInValidState(handler
);
466 private static bool IsHandlerInValidState(IHandler handler
)
470 return handler
.CurrentState
== HandlerState
.Valid
;
477 /// This method rebuild the context for the parameter type.
478 /// Naive implementation.
480 private CreationContext
RebuildContextForParameter(CreationContext current
, Type parameterType
)
482 if (parameterType
.ContainsGenericParameters
)
488 return new CreationContext(current
.Handler
, parameterType
, current
);