Fixing an issue with output parameters that are of type IntPtr
[castle.git] / InversionOfControl / Castle.MicroKernel / Handlers / AbstractHandler.cs
blobdd3bff5d75718771c62cafcfce6b5257f4fa4ba5
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.Handlers
17 using System;
18 using System.Collections;
19 using System.Collections.Specialized;
20 using System.Diagnostics;
21 using System.Text;
22 using Castle.Core;
23 using Castle.MicroKernel.Lifestyle;
25 /// <summary>
26 /// Implements the basis of <see cref="IHandler"/>
27 /// </summary>
28 [Serializable]
29 [DebuggerDisplay("Model: {ComponentModel.Service} / {ComponentModel.Implementation} ")]
30 public abstract class AbstractHandler : MarshalByRefObject, IHandler, IExposeDependencyInfo, IDisposable
32 private readonly ComponentModel model;
33 private IKernel kernel;
34 private HandlerState state;
36 /// <summary>
37 /// Dictionary of Type to a list of <see cref="DependencyModel"/>
38 /// </summary>
39 private IDictionary dependenciesByService;
41 /// <summary>
42 /// Dictionary of key (string) to <see cref="DependencyModel"/>
43 /// </summary>
44 private IDictionary dependenciesByKey;
46 /// <summary>
47 /// Custom dependencies values associated with the handler
48 /// </summary>
49 private IDictionary customParameters;
51 /// <summary>
52 /// Lifestyle manager instance
53 /// </summary>
54 protected ILifestyleManager lifestyleManager;
56 /// <summary>
57 /// Constructs and initializes the handler
58 /// </summary>
59 /// <param name="model"></param>
60 public AbstractHandler(ComponentModel model)
62 this.model = model;
63 state = HandlerState.Valid;
64 InitializeCustomDependencies();
67 #region IHandler Members
69 /// <summary>
70 /// Saves the kernel instance, subscribes to
71 /// <see cref="IKernelEvents.AddedAsChildKernel"/> event,
72 /// creates the lifestyle manager instance and computes
73 /// the handler state.
74 /// </summary>
75 /// <param name="kernel"></param>
76 public virtual void Init(IKernel kernel)
78 this.kernel = kernel;
79 this.kernel.AddedAsChildKernel += new EventHandler(OnAddedAsChildKernel);
81 IComponentActivator activator = kernel.CreateComponentActivator(ComponentModel);
83 lifestyleManager = CreateLifestyleManager(activator);
85 EnsureDependenciesCanBeSatisfied();
88 /// <summary>
89 /// Should be implemented by derived classes:
90 /// returns an instance of the component this handler
91 /// is responsible for
92 /// </summary>
93 /// <param name="context"></param>
94 /// <returns></returns>
95 public abstract object Resolve(CreationContext context);
97 /// <summary>
98 /// Should be implemented by derived classes:
99 /// disposes the component instance (or recycle it)
100 /// </summary>
101 /// <param name="instance"></param>
102 public abstract void Release(object instance);
104 /// <summary>
105 /// Gets the handler state.
106 /// </summary>
107 public HandlerState CurrentState
109 get { return state; }
112 /// <summary>
113 /// Gets the component model.
114 /// </summary>
115 public ComponentModel ComponentModel
117 get { return model; }
120 /// <summary>
121 /// TODO: Pendent
122 /// </summary>
123 /// <param name="key"></param>
124 /// <param name="value"></param>
125 public void AddCustomDependencyValue(string key, object value)
127 if (customParameters == null)
129 customParameters = new HybridDictionary(true);
132 customParameters[key] = value;
133 RaiseHandlerStateChanged();
136 /// <summary>
137 /// TODO: Pendent
138 /// </summary>
139 /// <param name="key"></param>
140 /// <returns></returns>
141 public bool HasCustomParameter(string key)
143 if (key == null)
145 return false;
148 if (customParameters != null)
150 return customParameters.Contains(key);
153 return false;
156 /// <summary>
157 /// TODO: Pendent
158 /// </summary>
159 /// <param name="key"></param>
160 public void RemoveCustomDependencyValue(string key)
162 if (customParameters != null)
164 customParameters.Remove(key);
165 RaiseHandlerStateChanged();
169 /// <summary>
170 ///
171 /// </summary>
172 public event HandlerStateDelegate OnHandlerStateChanged;
174 #endregion
176 #region ISubDependencyResolver Members
178 public virtual object Resolve(CreationContext context, ISubDependencyResolver parentResolver, ComponentModel model,
179 DependencyModel dependency)
181 return customParameters[dependency.DependencyKey];
184 public virtual bool CanResolve(CreationContext context, ISubDependencyResolver parentResolver, ComponentModel model,
185 DependencyModel dependency)
187 if (dependency.DependencyKey == null)
189 return false;
192 return HasCustomParameter(dependency.DependencyKey);
195 #endregion
197 #region IDisposable Members
199 public virtual void Dispose()
201 lifestyleManager.Dispose();
204 #endregion
206 #region IExposeDependencyInfo Members
208 /// <summary>
209 /// Returns human readable list of dependencies
210 /// this handler is waiting for.
211 /// </summary>
212 /// <returns></returns>
213 public String ObtainDependencyDetails(IList dependenciesChecked)
215 if (CurrentState == HandlerState.Valid)
217 return String.Empty;
220 if (dependenciesChecked.Contains(this))
222 return String.Empty;
225 dependenciesChecked.Add(this);
227 StringBuilder sb = new StringBuilder();
229 sb.AppendFormat("\r\n{0} is waiting for the following dependencies: \r\n", ComponentModel.Name);
231 if (DependenciesByService.Count != 0)
233 sb.Append("\r\nServices: \r\n");
235 foreach (Type type in DependenciesByService.Keys)
237 IHandler handler = Kernel.GetHandler(type);
239 if (handler == null)
241 sb.AppendFormat("- {0} which was not registered. \r\n", type.FullName);
243 else if (handler == this)
245 sb.AppendFormat("- {0}. \r\n A dependency cannot be satisfied by itself, " +
246 "did you forget to add a parameter name to differentiate between the " +
247 "two dependencies? \r\n", type.FullName);
249 else
251 sb.AppendFormat("- {0} which was registered but is also waiting for " +
252 "dependencies. \r\n", type.FullName);
254 IExposeDependencyInfo info = handler as IExposeDependencyInfo;
256 if (info != null)
258 sb.Append(info.ObtainDependencyDetails(dependenciesChecked));
264 if (DependenciesByKey.Count != 0)
266 sb.Append("\r\nKeys (components with specific keys)\r\n");
268 foreach (DictionaryEntry entry in DependenciesByKey)
270 String key = entry.Key.ToString();
272 IHandler handler = Kernel.GetHandler(key);
274 if (handler == null)
276 sb.AppendFormat("- {0} which was not registered. \r\n", key);
278 else
280 sb.AppendFormat("- {0} which was registered but is also " +
281 "waiting for dependencies. \r\n", key);
283 IExposeDependencyInfo info = handler as IExposeDependencyInfo;
285 if (info != null)
287 sb.Append(info.ObtainDependencyDetails(dependenciesChecked));
293 return sb.ToString();
296 #endregion
298 /// <summary>
299 /// Creates an implementation of <see cref="ILifestyleManager"/> based
300 /// on <see cref="LifestyleType"/> and invokes <see cref="ILifestyleManager.Init"/>
301 /// to initialize the newly created manager.
302 /// </summary>
303 /// <param name="activator"></param>
304 /// <returns></returns>
305 protected virtual ILifestyleManager CreateLifestyleManager(IComponentActivator activator)
307 ILifestyleManager manager = null;
309 LifestyleType type = ComponentModel.LifestyleType;
311 if (type == LifestyleType.Undefined || type == LifestyleType.Singleton)
313 manager = new SingletonLifestyleManager();
315 else if (type == LifestyleType.Thread)
317 manager = new PerThreadLifestyleManager();
319 else if (type == LifestyleType.Transient)
321 manager = new TransientLifestyleManager();
323 else if (type == LifestyleType.PerWebRequest)
325 manager = new PerWebRequestLifestyleManager();
327 else if (type == LifestyleType.Custom)
329 manager = (ILifestyleManager)
330 Activator.CreateInstance(ComponentModel.CustomLifestyle);
332 else if (type == LifestyleType.Pooled)
334 int initial = ExtendedPropertiesConstants.Pool_Default_InitialPoolSize;
335 int maxSize = ExtendedPropertiesConstants.Pool_Default_MaxPoolSize;
337 if (ComponentModel.ExtendedProperties.Contains(ExtendedPropertiesConstants.Pool_InitialPoolSize))
339 initial = (int)ComponentModel.ExtendedProperties[ExtendedPropertiesConstants.Pool_InitialPoolSize];
341 if (ComponentModel.ExtendedProperties.Contains(ExtendedPropertiesConstants.Pool_MaxPoolSize))
343 maxSize = (int)ComponentModel.ExtendedProperties[ExtendedPropertiesConstants.Pool_MaxPoolSize];
346 manager = new PoolableLifestyleManager(initial, maxSize);
349 manager.Init(activator, Kernel, model);
351 return manager;
354 /// <summary>
355 /// Checks if the handler is able to, at very least, satisfy
356 /// the dependencies for the constructor with less parameters
357 /// </summary>
358 /// <remarks>
359 /// For each non*optional dependency, the implementation will invoke
360 /// <see cref="AddDependency"/>
361 /// </remarks>
362 protected virtual void EnsureDependenciesCanBeSatisfied()
364 // Custom activators should deal with this case
365 if (ComponentModel.Constructors.Count == 0)
367 return;
370 // Property dependencies may not be optional
372 foreach (PropertySet property in ComponentModel.Properties)
374 DependencyModel dependency = property.Dependency;
376 if (!dependency.IsOptional &&
377 (dependency.DependencyType == DependencyType.Service ||
378 dependency.DependencyType == DependencyType.ServiceOverride))
380 AddDependency(dependency);
384 // The following dependencies were added by - for example -
385 // facilities, for some reason, and we need to satisfy the non-optional
387 foreach (DependencyModel dependency in ComponentModel.Dependencies)
389 if (!dependency.IsOptional &&
390 (dependency.DependencyType == DependencyType.Service ||
391 dependency.DependencyType == DependencyType.ServiceOverride))
393 AddDependency(dependency);
397 // We need to satisfy at least the constructor
398 // with fewer arguments
400 ConstructorCandidate candidate = ComponentModel.Constructors.FewerArgumentsCandidate;
402 foreach (DependencyModel dependency in candidate.Dependencies)
404 if (dependency.DependencyType == DependencyType.Service ||
405 dependency.DependencyType == DependencyType.ServiceOverride)
407 AddDependency(dependency);
409 else if (dependency.DependencyType == DependencyType.Parameter &&
410 !ComponentModel.Constructors.HasAmbiguousFewerArgumentsCandidate &&
411 !ComponentModel.Parameters.Contains(dependency.DependencyKey))
413 AddDependency(dependency);
417 if (state == HandlerState.Valid)
419 DisconnectEvents();
423 /// <summary>
424 /// Invoked by <see cref="EnsureDependenciesCanBeSatisfied"/>
425 /// in order to check if a dependency can be satisfied.
426 /// If not, the handler is set to a 'waiting dependency' state.
427 /// </summary>
428 /// <remarks>
429 /// This method registers the dependencies within the correct collection
430 /// or dictionary and changes the handler state to
431 /// <see cref="HandlerState.WaitingDependency"/>
432 /// </remarks>
433 /// <param name="dependency"></param>
434 protected void AddDependency(DependencyModel dependency)
436 if (HasValidComponentFromResolver(dependency))
438 if (dependency.DependencyType == DependencyType.Service && dependency.TargetType != null)
440 IHandler depHandler = Kernel.GetHandler(dependency.TargetType);
442 if (depHandler != null)
444 AddGraphDependency(depHandler.ComponentModel);
447 else
449 IHandler depHandler = Kernel.GetHandler(dependency.DependencyKey);
451 if (depHandler != null)
453 AddGraphDependency(depHandler.ComponentModel);
457 return;
460 if (dependency.DependencyType == DependencyType.Service && dependency.TargetType != null)
462 if (DependenciesByService.Contains(dependency.TargetType))
464 return;
467 DependenciesByService.Add(dependency.TargetType, dependency);
469 else if (!DependenciesByKey.Contains(dependency.DependencyKey))
471 DependenciesByKey.Add(dependency.DependencyKey, dependency);
474 if (state != HandlerState.WaitingDependency)
476 // This handler is considered invalid
477 // until dependencies are satisfied
478 SetNewState(HandlerState.WaitingDependency);
480 // Register itself on the kernel
481 // to be notified if the dependency is satified
482 Kernel.HandlerRegistered += new HandlerDelegate(DependencySatisfied);
484 // We also gonna pay attention for state
485 // changed within this very handler. The
486 // state can be changed by AddCustomDependencyValue and RemoveCustomDependencyValue
487 OnHandlerStateChanged += new HandlerStateDelegate(HandlerStateChanged);
491 /// <summary>
492 /// Invoked by the kernel
493 /// when one of registered dependencies were satisfied by
494 /// new components registered.
495 /// </summary>
496 /// <remarks>
497 /// Handler for the event <see cref="IKernelEvents.HandlerRegistered"/>
498 /// </remarks>
499 /// <param name="handler"></param>
500 /// <param name="stateChanged"></param>
501 protected void DependencySatisfied(IHandler handler, ref bool stateChanged)
503 // Check within the handler
505 if (customParameters != null && customParameters.Count != 0)
507 DependencyModel[] dependencies = Union(DependenciesByService.Values, DependenciesByKey.Values);
509 foreach (DependencyModel dependency in dependencies)
511 if (!HasCustomParameter(dependency.DependencyKey))
513 continue;
516 if (dependency.DependencyType == DependencyType.Service)
518 DependenciesByService.Remove(dependency.TargetType);
520 else
522 DependenciesByKey.Remove(dependency.DependencyKey);
527 // Check within the Kernel
529 foreach (DictionaryEntry kvp in new Hashtable(DependenciesByService))
531 Type service = (Type)kvp.Key;
532 DependencyModel dependencyModel = (DependencyModel)kvp.Value;
533 if (HasValidComponent(service, dependencyModel))
535 DependenciesByService.Remove(service);
536 IHandler dependingHandler = kernel.GetHandler(service);
537 if(dependingHandler!=null)//may not be real handler, if comes from resolver
538 AddGraphDependency(dependingHandler.ComponentModel);
542 foreach (DictionaryEntry kvp in new Hashtable(DependenciesByKey))
544 string compKey = (string)kvp.Key;
545 DependencyModel dependency = (DependencyModel)kvp.Value;
546 if (HasValidComponent(compKey, dependency) || HasCustomParameter(compKey))
548 DependenciesByKey.Remove(compKey);
549 IHandler dependingHandler = kernel.GetHandler(compKey);
550 if(dependingHandler!=null)//may not be real handler, if we are using sub resovler
551 AddGraphDependency(dependingHandler.ComponentModel);
555 if (DependenciesByService.Count == 0 && DependenciesByKey.Count == 0)
557 SetNewState(HandlerState.Valid);
558 stateChanged = true;
560 DisconnectEvents();
562 // We don't need these anymore
564 dependenciesByKey = null;
565 dependenciesByService = null;
569 /// <summary>
570 /// Invoked when the container receives a parent container reference.
571 /// </summary>
572 /// <remarks>
573 /// This method implementation checks whether the parent container
574 /// is able to supply the dependencies for this handler.
575 /// </remarks>
576 /// <param name="sender"></param>
577 /// <param name="e"></param>
578 protected void OnAddedAsChildKernel(object sender, EventArgs e)
580 if (DependenciesByKey.Count == 0 && DependenciesByService.Count == 0)
582 return;
585 bool stateChanged = false;
587 Type[] services = new Type[DependenciesByService.Count];
589 DependenciesByService.Keys.CopyTo(services, 0);
591 foreach (Type service in services)
593 if (Kernel.Parent.HasComponent(service))
595 IHandler handler = Kernel.Parent.GetHandler(service);
596 DependencySatisfied(handler, ref stateChanged);
600 String[] keys = new String[DependenciesByKey.Count];
602 DependenciesByKey.Keys.CopyTo(keys, 0);
604 foreach (String key in keys)
606 if (Kernel.Parent.HasComponent(key))
608 IHandler handler = Kernel.Parent.GetHandler(key);
609 DependencySatisfied(handler, ref stateChanged);
614 protected IKernel Kernel
616 get { return kernel; }
619 protected void SetNewState(HandlerState newState)
621 state = newState;
624 protected IDictionary DependenciesByService
628 if (dependenciesByService == null)
630 dependenciesByService = new HybridDictionary();
632 return dependenciesByService;
636 protected IDictionary DependenciesByKey
640 if (dependenciesByKey == null)
642 dependenciesByKey = new HybridDictionary();
644 return dependenciesByKey;
648 private void InitializeCustomDependencies()
650 customParameters = new HybridDictionary(true);
652 foreach (DictionaryEntry customParameter in model.CustomDependencies)
654 customParameters.Add(customParameter.Key, customParameter.Value);
658 private bool HasValidComponent(Type service, DependencyModel dependency)
660 foreach (IHandler handler in kernel.GetHandlers(service))
662 if (IsValidHandlerState(handler))
664 return true;
668 // could not find in kernel directly, check using resolvers
669 return HasValidComponentFromResolver(dependency);
672 private bool HasValidComponent(String key, DependencyModel dependency)
674 if (IsValidHandlerState(kernel.GetHandler(key)))
675 return true;
676 // could not find in kernel directly, check using resolvers
677 return HasValidComponentFromResolver(dependency);
681 private bool HasValidComponentFromResolver(DependencyModel dependency)
683 if (Kernel.Resolver.CanResolve(null, this, model, dependency))
684 return true;
685 return false;
688 private bool IsValidHandlerState(IHandler handler)
690 if (handler == null)
692 return false;
695 return handler.CurrentState == HandlerState.Valid;
698 private void AddGraphDependency(ComponentModel model)
700 ComponentModel.AddDependent(model);
703 private DependencyModel[] Union(ICollection firstset, ICollection secondset)
705 DependencyModel[] result = new DependencyModel[firstset.Count + secondset.Count];
707 firstset.CopyTo(result, 0);
708 secondset.CopyTo(result, firstset.Count);
710 return result;
713 /// <summary>
714 /// Handler for the event <see cref="OnHandlerStateChanged"/>
715 /// </summary>
716 /// <param name="source"></param>
717 /// <param name="args"></param>
718 private void HandlerStateChanged(object source, EventArgs args)
720 Kernel.RaiseHandlerRegistered(this);
723 private void RaiseHandlerStateChanged()
725 if (OnHandlerStateChanged != null)
727 OnHandlerStateChanged(this, EventArgs.Empty);
731 private void DisconnectEvents()
733 Kernel.HandlerRegistered -= new HandlerDelegate(DependencySatisfied);
734 Kernel.AddedAsChildKernel -= new EventHandler(OnAddedAsChildKernel);
735 this.OnHandlerStateChanged -= new HandlerStateDelegate(HandlerStateChanged);