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
);
411 if (state
== HandlerState
.Valid
)
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.
423 /// This method registers the dependencies within the correct collection
424 /// or dictionary and changes the handler state to
425 /// <see cref="HandlerState.WaitingDependency"/>
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
);
443 IHandler depHandler
= Kernel
.GetHandler(dependency
.DependencyKey
);
445 if (depHandler
!= null)
447 AddGraphDependency(depHandler
.ComponentModel
);
454 if (dependency
.DependencyType
== DependencyType
.Service
&& dependency
.TargetType
!= null)
456 if (DependenciesByService
.Contains(dependency
.TargetType
))
461 DependenciesByService
.Add(dependency
.TargetType
, dependency
);
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
);
486 /// Invoked by the kernel
487 /// when one of registered dependencies were satisfied by
488 /// new components registered.
491 /// Handler for the event <see cref="IKernelEvents.HandlerRegistered"/>
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
))
510 if (dependency
.DependencyType
== DependencyType
.Service
)
512 DependenciesByService
.Remove(dependency
.TargetType
);
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
);
554 // We don't need these anymore
556 dependenciesByKey
= null;
557 dependenciesByService
= null;
562 /// Invoked when the container receives a parent container reference.
565 /// This method implementation checks whether the parent container
566 /// is able to supply the dependencies for this handler.
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)
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
)
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
))
652 private bool HasValidComponent(String key
)
654 return IsValidHandlerState(kernel
.GetHandler(key
));
657 private bool IsValidHandlerState(IHandler handler
)
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
);
683 /// Handler for the event <see cref="OnHandlerStateChanged"/>
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
);