Added container accessor to Castle.Core
[castle.git] / InversionOfControl / Castle.MicroKernel / Handlers / AbstractHandler.cs
blob1eaa67621fdb4637d5d4946bd98f5894f54f33d6
1 // Copyright 2004-2007 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 customParameters = new HybridDictionary(true);
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);
411 if (state == HandlerState.Valid)
413 DisconnectEvents();
417 /// <summary>
418 /// Invoked by <see cref="EnsureDependenciesCanBeSatisfied"/>
419 /// in order to check if a dependency can be satisfied.
420 /// If not, the handler is set to a 'waiting dependency' state.
421 /// </summary>
422 /// <remarks>
423 /// This method registers the dependencies within the correct collection
424 /// or dictionary and changes the handler state to
425 /// <see cref="HandlerState.WaitingDependency"/>
426 /// </remarks>
427 /// <param name="dependency"></param>
428 protected void AddDependency(DependencyModel dependency)
430 if (Kernel.Resolver.CanResolve(null, this, model, dependency))
432 if (dependency.DependencyType == DependencyType.Service && dependency.TargetType != null)
434 IHandler depHandler = Kernel.GetHandler(dependency.TargetType);
436 if (depHandler != null)
438 AddGraphDependency(depHandler.ComponentModel);
441 else
443 IHandler depHandler = Kernel.GetHandler(dependency.DependencyKey);
445 if (depHandler != null)
447 AddGraphDependency(depHandler.ComponentModel);
451 return;
454 if (dependency.DependencyType == DependencyType.Service && dependency.TargetType != null)
456 if (DependenciesByService.Contains(dependency.TargetType))
458 return;
461 DependenciesByService.Add(dependency.TargetType, dependency);
463 else
465 DependenciesByKey.Add(dependency.DependencyKey, dependency);
468 if (state != HandlerState.WaitingDependency)
470 // This handler is considered invalid
471 // until dependencies are satisfied
472 SetNewState(HandlerState.WaitingDependency);
474 // Register itself on the kernel
475 // to be notified if the dependency is satified
476 Kernel.HandlerRegistered += new HandlerDelegate(DependencySatisfied);
478 // We also gonna pay attention for state
479 // changed within this very handler. The
480 // state can be changed by AddCustomDependencyValue and RemoveCustomDependencyValue
481 OnHandlerStateChanged += new HandlerStateDelegate(HandlerStateChanged);
485 /// <summary>
486 /// Invoked by the kernel
487 /// when one of registered dependencies were satisfied by
488 /// new components registered.
489 /// </summary>
490 /// <remarks>
491 /// Handler for the event <see cref="IKernelEvents.HandlerRegistered"/>
492 /// </remarks>
493 /// <param name="handler"></param>
494 /// <param name="stateChanged"></param>
495 protected void DependencySatisfied(IHandler handler, ref bool stateChanged)
497 // Check within the handler
499 if (customParameters != null && customParameters.Count != 0)
501 DependencyModel[] dependencies = Union(DependenciesByService.Values, DependenciesByKey.Values);
503 foreach (DependencyModel dependency in dependencies)
505 if (!HasCustomParameter(dependency.DependencyKey))
507 continue;
510 if (dependency.DependencyType == DependencyType.Service)
512 DependenciesByService.Remove(dependency.TargetType);
514 else
516 DependenciesByKey.Remove(dependency.DependencyKey);
521 // Check within the Kernel
523 Type[] services = new Type[DependenciesByService.Count];
524 DependenciesByService.Keys.CopyTo(services, 0);
526 foreach (Type service in services)
528 if (HasValidComponent(service))
530 DependenciesByService.Remove(service);
531 AddGraphDependency(kernel.GetHandler(service).ComponentModel);
535 String[] keys = new String[DependenciesByKey.Keys.Count];
536 DependenciesByKey.Keys.CopyTo(keys, 0);
538 foreach (String compKey in keys)
540 if (HasValidComponent(compKey) || HasCustomParameter(compKey))
542 DependenciesByKey.Remove(compKey);
543 AddGraphDependency(kernel.GetHandler(compKey).ComponentModel);
547 if (DependenciesByService.Count == 0 && DependenciesByKey.Count == 0)
549 SetNewState(HandlerState.Valid);
550 stateChanged = true;
552 DisconnectEvents();
554 // We don't need these anymore
556 dependenciesByKey = null;
557 dependenciesByService = null;
561 /// <summary>
562 /// Invoked when the container receives a parent container reference.
563 /// </summary>
564 /// <remarks>
565 /// This method implementation checks whether the parent container
566 /// is able to supply the dependencies for this handler.
567 /// </remarks>
568 /// <param name="sender"></param>
569 /// <param name="e"></param>
570 protected void OnAddedAsChildKernel(object sender, EventArgs e)
572 if (DependenciesByKey.Count == 0 && DependenciesByService.Count == 0)
574 return;
577 bool stateChanged = false;
579 Type[] services = new Type[DependenciesByService.Count];
581 DependenciesByService.Keys.CopyTo(services, 0);
583 foreach (Type service in services)
585 if (Kernel.Parent.HasComponent(service))
587 IHandler handler = Kernel.Parent.GetHandler(service);
588 DependencySatisfied(handler, ref stateChanged);
592 String[] keys = new String[DependenciesByKey.Count];
594 DependenciesByKey.Keys.CopyTo(services, 0);
596 foreach (String key in keys)
598 if (Kernel.Parent.HasComponent(key))
600 IHandler handler = Kernel.Parent.GetHandler(key);
601 DependencySatisfied(handler, ref stateChanged);
606 protected IKernel Kernel
608 get { return kernel; }
611 protected void SetNewState(HandlerState newState)
613 state = newState;
616 protected IDictionary DependenciesByService
620 if (dependenciesByService == null)
622 dependenciesByService = new HybridDictionary();
624 return dependenciesByService;
628 protected IDictionary DependenciesByKey
632 if (dependenciesByKey == null)
634 dependenciesByKey = new HybridDictionary();
636 return dependenciesByKey;
640 private bool HasValidComponent(Type service)
642 foreach (IHandler handler in kernel.GetHandlers(service))
644 if (IsValidHandlerState(handler))
646 return true;
649 return false;
652 private bool HasValidComponent(String key)
654 return IsValidHandlerState(kernel.GetHandler(key));
657 private bool IsValidHandlerState(IHandler handler)
659 if (handler == null)
661 return false;
664 return handler.CurrentState == HandlerState.Valid;
667 private void AddGraphDependency(ComponentModel model)
669 ComponentModel.AddDependent(model);
672 private DependencyModel[] Union(ICollection firstset, ICollection secondset)
674 DependencyModel[] result = new DependencyModel[firstset.Count + secondset.Count];
676 firstset.CopyTo(result, 0);
677 secondset.CopyTo(result, firstset.Count);
679 return result;
682 /// <summary>
683 /// Handler for the event <see cref="OnHandlerStateChanged"/>
684 /// </summary>
685 /// <param name="source"></param>
686 /// <param name="args"></param>
687 private void HandlerStateChanged(object source, EventArgs args)
689 Kernel.RaiseHandlerRegistered(this);
692 private void RaiseHandlerStateChanged()
694 if (OnHandlerStateChanged != null)
696 OnHandlerStateChanged(this, EventArgs.Empty);
700 private void DisconnectEvents()
702 Kernel.HandlerRegistered -= new HandlerDelegate(DependencySatisfied);
703 Kernel.AddedAsChildKernel -= new EventHandler(OnAddedAsChildKernel);
704 this.OnHandlerStateChanged -= new HandlerStateDelegate(HandlerStateChanged);