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
.Handlers
18 using System
.Collections
;
19 using System
.Collections
.Specialized
;
20 using System
.Diagnostics
;
23 using Castle
.MicroKernel
.Lifestyle
;
26 /// Implements the basis of <see cref="IHandler"/>
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
;
37 /// Dictionary of Type to a list of <see cref="DependencyModel"/>
39 private IDictionary dependenciesByService
;
42 /// Dictionary of key (string) to <see cref="DependencyModel"/>
44 private IDictionary dependenciesByKey
;
47 /// Custom dependencies values associated with the handler
49 private IDictionary customParameters
;
52 /// Lifestyle manager instance
54 protected ILifestyleManager lifestyleManager
;
57 /// Constructs and initializes the handler
59 /// <param name="model"></param>
60 public AbstractHandler(ComponentModel model
)
63 state
= HandlerState
.Valid
;
64 customParameters
= new HybridDictionary(true);
67 #region IHandler Members
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.
75 /// <param name="kernel"></param>
76 public virtual void Init(IKernel kernel
)
79 this.kernel
.AddedAsChildKernel
+= new EventHandler(OnAddedAsChildKernel
);
81 IComponentActivator activator
= kernel
.CreateComponentActivator(ComponentModel
);
83 lifestyleManager
= CreateLifestyleManager(activator
);
85 EnsureDependenciesCanBeSatisfied();
89 /// Should be implemented by derived classes:
90 /// returns an instance of the component this handler
91 /// is responsible for
93 /// <param name="context"></param>
94 /// <returns></returns>
95 public abstract object Resolve(CreationContext context
);
98 /// Should be implemented by derived classes:
99 /// disposes the component instance (or recycle it)
101 /// <param name="instance"></param>
102 public abstract void Release(object instance
);
105 /// Gets the handler state.
107 public HandlerState CurrentState
109 get { return state; }
113 /// Gets the component model.
115 public ComponentModel ComponentModel
117 get { return model; }
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();
139 /// <param name="key"></param>
140 /// <returns></returns>
141 public bool HasCustomParameter(string key
)
148 if (customParameters
!= null)
150 return customParameters
.Contains(key
);
159 /// <param name="key"></param>
160 public void RemoveCustomDependencyValue(string key
)
162 if (customParameters
!= null)
164 customParameters
.Remove(key
);
165 RaiseHandlerStateChanged();
172 public event HandlerStateDelegate OnHandlerStateChanged
;
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)
192 return HasCustomParameter(dependency
.DependencyKey
);
197 #region IDisposable Members
199 public virtual void Dispose()
201 lifestyleManager
.Dispose();
206 #region IExposeDependencyInfo Members
209 /// Returns human readable list of dependencies
210 /// this handler is waiting for.
212 /// <returns></returns>
213 public String
ObtainDependencyDetails(IList dependenciesChecked
)
215 if (CurrentState
== HandlerState
.Valid
)
220 if (dependenciesChecked
.Contains(this))
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
);
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
);
251 sb
.AppendFormat("- {0} which was registered but is also waiting for " +
252 "dependencies. \r\n", type
.FullName
);
254 IExposeDependencyInfo info
= handler
as IExposeDependencyInfo
;
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
);
276 sb
.AppendFormat("- {0} which was not registered. \r\n", key
);
280 sb
.AppendFormat("- {0} which was registered but is also " +
281 "waiting for dependencies. \r\n", key
);
283 IExposeDependencyInfo info
= handler
as IExposeDependencyInfo
;
287 sb
.Append(info
.ObtainDependencyDetails(dependenciesChecked
));
293 return sb
.ToString();
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.
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
);
355 /// Checks if the handler is able to, at very least, satisfy
356 /// the dependencies for the constructor with less parameters
359 /// For each non*optional dependency, the implementation will invoke
360 /// <see cref="AddDependency"/>
362 protected virtual void EnsureDependenciesCanBeSatisfied()
364 // Custom activators should deal with this case
365 if (ComponentModel
.Constructors
.Count
== 0)
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
)
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.
429 /// This method registers the dependencies within the correct collection
430 /// or dictionary and changes the handler state to
431 /// <see cref="HandlerState.WaitingDependency"/>
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
);
449 IHandler depHandler
= Kernel
.GetHandler(dependency
.DependencyKey
);
451 if (depHandler
!= null)
453 AddGraphDependency(depHandler
.ComponentModel
);
460 if (dependency
.DependencyType
== DependencyType
.Service
&& dependency
.TargetType
!= null)
462 if (DependenciesByService
.Contains(dependency
.TargetType
))
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
);
492 /// Invoked by the kernel
493 /// when one of registered dependencies were satisfied by
494 /// new components registered.
497 /// Handler for the event <see cref="IKernelEvents.HandlerRegistered"/>
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
))
516 if (dependency
.DependencyType
== DependencyType
.Service
)
518 DependenciesByService
.Remove(dependency
.TargetType
);
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
);
562 // We don't need these anymore
564 dependenciesByKey
= null;
565 dependenciesByService
= null;
570 /// Invoked when the container receives a parent container reference.
573 /// This method implementation checks whether the parent container
574 /// is able to supply the dependencies for this handler.
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)
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
)
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 bool HasValidComponent(Type service
, DependencyModel dependency
)
650 foreach (IHandler handler
in kernel
.GetHandlers(service
))
652 if (IsValidHandlerState(handler
))
658 // could not find in kernel directly, check using resolvers
659 return HasValidComponentFromResolver(dependency
);
662 private bool HasValidComponent(String key
, DependencyModel dependency
)
664 if (IsValidHandlerState(kernel
.GetHandler(key
)))
666 // could not find in kernel directly, check using resolvers
667 return HasValidComponentFromResolver(dependency
);
671 private bool HasValidComponentFromResolver(DependencyModel dependency
)
673 if (Kernel
.Resolver
.CanResolve(null, this, model
, dependency
))
678 private bool IsValidHandlerState(IHandler handler
)
685 return handler
.CurrentState
== HandlerState
.Valid
;
688 private void AddGraphDependency(ComponentModel model
)
690 ComponentModel
.AddDependent(model
);
693 private DependencyModel
[] Union(ICollection firstset
, ICollection secondset
)
695 DependencyModel
[] result
= new DependencyModel
[firstset
.Count
+ secondset
.Count
];
697 firstset
.CopyTo(result
, 0);
698 secondset
.CopyTo(result
, firstset
.Count
);
704 /// Handler for the event <see cref="OnHandlerStateChanged"/>
706 /// <param name="source"></param>
707 /// <param name="args"></param>
708 private void HandlerStateChanged(object source
, EventArgs args
)
710 Kernel
.RaiseHandlerRegistered(this);
713 private void RaiseHandlerStateChanged()
715 if (OnHandlerStateChanged
!= null)
717 OnHandlerStateChanged(this, EventArgs
.Empty
);
721 private void DisconnectEvents()
723 Kernel
.HandlerRegistered
-= new HandlerDelegate(DependencySatisfied
);
724 Kernel
.AddedAsChildKernel
-= new EventHandler(OnAddedAsChildKernel
);
725 this.OnHandlerStateChanged
-= new HandlerStateDelegate(HandlerStateChanged
);