Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / InversionOfControl / Castle.MicroKernel / Resolvers / DefaultDependencyResolver.cs
blob75169f8fcc1064084a052316e3f01f140946bef1
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.Resolvers
17 using System;
18 using System.Collections;
19 using Castle.Core;
20 using Castle.MicroKernel.SubSystems.Conversion;
21 using Castle.MicroKernel.Util;
23 /// <summary>
24 /// Default implementation for <see cref="IDependencyResolver"/>.
25 /// This implementation is quite simple, but still should be useful
26 /// for 99% of situations.
27 /// </summary>
28 [Serializable]
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();
36 /// <summary>
37 /// Initializes a new instance of the <see cref="DefaultDependencyResolver"/> class.
38 /// </summary>
39 /// <param name="kernel">The kernel.</param>
40 public DefaultDependencyResolver(IKernel kernel)
42 this.kernel = kernel;
44 converter = (ITypeConverter)kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);
47 /// <summary>
48 /// Initializes this instance with the specified dependency delegate.
49 /// </summary>
50 /// <param name="dependencyDelegate">The dependency delegate.</param>
51 public void Initialize(DependencyDelegate dependencyDelegate)
53 dependencyResolvingDelegate = dependencyDelegate;
56 /// <summary>
57 /// Registers a sub resolver instance
58 /// </summary>
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);
67 /// <summary>
68 /// Unregisters a sub resolver instance previously registered
69 /// </summary>
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);
78 /// <summary>
79 /// Returns true if the resolver is able to satisfy the specified dependency.
80 /// </summary>
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
91 if (context != null)
93 if (context.CanResolve(context, parentResolver, model, dependency))
95 return true;
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))
107 return true;
111 // 3 - check within parent resolver, if present
113 if (parentResolver != null)
115 if (parentResolver.CanResolve(context, parentResolver, model, dependency))
117 return true;
121 // 4 - check within subresolvers
123 foreach (ISubDependencyResolver subResolver in subResolvers)
125 if (subResolver.CanResolve(context, parentResolver, model, dependency))
127 return true;
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);
138 else
140 return CanResolveParameterDependency(model, dependency);
144 /// <summary>
145 /// Try to resolve the dependency by checking the parameters in
146 /// the model or checking the Kernel for the requested service.
147 /// </summary>
148 /// <remarks>
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>
165 /// </list>
166 /// </remarks>
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)
175 object value = null;
177 bool resolved = false;
179 // 1 - check for the dependency on CreationContext, if present
181 if (context != null)
183 if (context.CanResolve(context, parentResolver, model, dependency))
185 value = context.Resolve(context, parentResolver, model, dependency);
186 resolved = true;
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);
199 resolved = true;
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);
210 resolved = true;
214 // 4 - check within subresolvers
216 if (!resolved)
218 foreach (ISubDependencyResolver subResolver in subResolvers)
220 if (subResolver.CanResolve(context, parentResolver, model, dependency))
222 value = subResolver.Resolve(context, parentResolver, model, dependency);
223 resolved = true;
224 break;
229 // 5 - normal flow, checking against the kernel
231 if (!resolved)
233 if (dependency.DependencyType == DependencyType.Service ||
234 dependency.DependencyType == DependencyType.ServiceOverride)
236 value = ResolveServiceDependency(context, model, dependency);
238 else
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);
262 return 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))
284 return true;
286 else
288 // Default behaviour
290 if (dependency.TargetType != null)
292 return HasComponentInValidState(context, dependency.TargetType);
294 else
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))
329 return kernel;
331 else
333 if (dependency.DependencyType == DependencyType.ServiceOverride)
335 handler = kernel.GetHandler(dependency.DependencyKey);
337 else
339 handler = TryGetHandlerFromKernel(dependency, context);
341 if (handler == null)
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)
366 return handler;
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;
377 break;
380 return handler;
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);
398 else
400 return converter.PerformConversion(parameter.ConfigValue, dependency.TargetType);
403 finally
405 converter.Context.PopModel();
409 return null;
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];
422 /// <summary>
423 /// Extracts the component name from the a ref strings which is
424 /// ${something}
425 /// </summary>
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);
463 return false;
466 private static bool IsHandlerInValidState(IHandler handler)
468 if (handler != null)
470 return handler.CurrentState == HandlerState.Valid;
473 return false;
476 /// <summary>
477 /// This method rebuild the context for the parameter type.
478 /// Naive implementation.
479 /// </summary>
480 private CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
482 if (parameterType.ContainsGenericParameters)
484 return current;
486 else
488 return new CreationContext(current.Handler, parameterType, current);