- /// Does not mandate the type of storage used for configuration, but does
- /// implement common functionality. Uses the Template Method design
- /// pattern, requiring concrete subclasses to implement
- /// methods.
- ///
- ///
- /// In contrast to a plain vanilla
- /// , an
- /// is supposed
- /// to detect special objects defined in its object factory: therefore,
- /// this class automatically registers
- /// s,
- /// s
- /// and s that are
- /// defined as objects in the context.
- ///
- ///
- /// An may be also supplied as
- /// an object in the context, with the special, well-known-name of
- /// "messageSource". Else, message resolution is delegated to the
- /// parent context.
- ///
- ///
- /// Rod Johnson
- /// Juergan Hoeller
- /// Griffin Caprio (.NET)
- ///
- ///
- public abstract class AbstractApplicationContext
- : ConfigurableResourceLoader, IConfigurableApplicationContext
- {
- #region Constants
-
- ///
- /// Name of the .Net config section that contains Spring.Net context definition.
- ///
- public const string ContextSectionName = "spring/context";
-
- ///
- /// Default name of the root context.
- ///
- public const string DefaultRootContextName = "spring.root";
-
- #endregion
-
- #region Fields
-
- private const long TicksAtEpoch = 621355968000000000;
-
- ///
- /// The special, well-known-name of the default
- /// in the context.
- ///
- ///
- ///
- /// If no can be found
- /// in the context using this lookup key, then message resolution
- /// will be delegated to the parent context (if any).
- ///
- ///
- public static readonly string MessageSourceObjectName = "messageSource";
-
- ///
- /// The special, well-known-name of the default
- /// in the context.
- ///
- ///
- ///
- /// If no can be found
- /// in the context using this lookup key, then a default
- /// will be used.
- ///
- ///
- public static readonly string EventRegistryObjectName = "eventRegistry";
-
- ///
- /// The instance for this class.
- ///
- private static readonly ILog log = LogManager.GetLogger(typeof(AbstractApplicationContext));
-
- ///
- /// The instance we delegate
- /// our implementation of said interface to.
- ///
- private IMessageSource _messageSource;
-
- ///
- /// The instance we
- /// delegate our implementation of said interface to.
- ///
- private IEventRegistry _eventRegistry;
-
- private IApplicationContext _parentApplicationContext;
- private readonly IList _objectFactoryPostProcessors;
- private IList _defaultObjectPostProcessors;
- private string _name;
- private DateTime _startupDate;
- private readonly bool _caseSensitive;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// with no parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- protected AbstractApplicationContext() : this(null, true, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// with no parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- /// Flag specifying whether to make this context case sensitive or not.
- protected AbstractApplicationContext(bool caseSensitive) : this(null, caseSensitive, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// with the supplied parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- /// The application context name.
- /// Flag specifying whether to make this context case sensitive or not.
- /// The parent application context.
- protected AbstractApplicationContext(string name, bool caseSensitive,
- IApplicationContext parentApplicationContext)
- {
- _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name;
- _caseSensitive = caseSensitive;
- _parentApplicationContext = parentApplicationContext;
- _objectFactoryPostProcessors = new ArrayList();
- _defaultObjectPostProcessors = new ArrayList();
- AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker());
- AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this));
- }
-
- ///
- /// Adds the given to the list of standard
- /// processors being added to the underlying
- ///
- ///
- /// Each time is called on this context, the context ensures, that
- /// all default s are registered with the underlying .
- ///
- /// The instance.
- protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor)
- {
- _defaultObjectPostProcessors.Add(defaultObjectPostProcessor);
- }
-
- ///
- /// Closes this context and disposes of any resources (such as
- /// singleton objects in the wrapped
- /// ).
- ///
- public virtual void Dispose()
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Closing application context [{0}].",
- Name));
- }
-
- #endregion
-
- new DefensiveEventRaiser().Raise(
- ContextEvent, this,
- new ContextEventArgs(ContextEventArgs.ContextEvent.Closed));
- ObjectFactory.Dispose();
- }
-
- #endregion
-
- #region Abstract Methods
-
- ///
- /// Subclasses must implement this method to perform the actual
- /// configuration loading.
- ///
- ///
- ///
- /// This method is invoked by
- /// ,
- /// before any other initialization occurs.
- ///
- ///
- ///
- /// In the case of errors encountered while refreshing the object factory.
- ///
- protected abstract void RefreshObjectFactory();
-
- #endregion
-
- ///
- /// An object that can be used to synchronize access to the
- ///
- public object SyncRoot
- {
- get { return this; }
- }
-
- ///
- /// The timestamp when this context was first loaded.
- ///
- ///
- /// The timestamp (milliseconds) when this context was first loaded.
- ///
- public long StartupDateMilliseconds
- {
- get { return (StartupDate.Ticks - TicksAtEpoch)/10000; }
- }
-
-
- ///
- /// Gets a flag indicating whether context should be case sensitive.
- ///
- /// true if object lookups are case sensitive; otherwise, false.
- protected bool CaseSensitive
- {
- get { return _caseSensitive; }
- }
-
- ///
- /// The for this context.
- ///
- ///
- /// If the context has not been initialized yet.
- ///
- public IMessageSource MessageSource
- {
- get
- {
- if (_messageSource == null)
- {
- throw new InvalidOperationException(
- "MessageSource not initialized - call 'Refresh()' " +
- "before accessing messages via the context: " + this);
- }
- return _messageSource;
- }
- }
-
- ///
- /// The for this context.
- ///
- ///
- /// If the context has not been initialized yet.
- ///
- public IEventRegistry EventRegistry
- {
- get
- {
- if (_eventRegistry == null)
- {
- throw new InvalidOperationException(
- "EventRegistry not initialized - call 'Refresh()' " +
- "before accessing the event registry via the context: " + this);
- }
- return _eventRegistry;
- }
- }
-
- ///
- /// Returns the internal object factory of the parent context if it implements
- /// ; else,
- /// returns the parent context itself.
- ///
- ///
- /// The parent context's object factory, or the parent itself.
- ///
- protected IObjectFactory GetInternalParentObjectFactory()
- {
- IConfigurableApplicationContext configContext
- = _parentApplicationContext as IConfigurableApplicationContext;
- if (configContext != null)
- {
- return ((IConfigurableApplicationContext)
- _parentApplicationContext).ObjectFactory;
- }
- else
- {
- return _parentApplicationContext;
- }
- }
-
- ///
- /// Raises an application context event.
- ///
- ///
- /// Any arguments to the event. May be .
- ///
- protected virtual void OnContextEvent(ApplicationEventArgs e)
- {
- OnContextEvent(this, e);
- }
-
- ///
- /// Raises an application context event.
- ///
- ///
- /// The source of the event.
- ///
- ///
- /// Any arguments to the event. May be .
- ///
- protected virtual void OnContextEvent(object source, ApplicationEventArgs e)
- {
- new DefensiveEventRaiser().Raise(ContextEvent, source, e);
- }
-
- ///
- /// Modify the application context's internal object factory after its standard
- /// initialization.
- ///
- ///
- ///
- /// All object definitions will have been loaded, but no objects
- /// will have been instantiated yet. This allows for the registration
- /// of special
- /// s
- /// in certain
- /// implementations.
- ///
- ///
- ///
- /// The object factory used by the application context.
- ///
- ///
- /// In the case of errors.
- /// .
- protected virtual void PostProcessObjectFactory(
- IConfigurableListableObjectFactory objectFactory)
- {
- }
-
- ///
- /// Template method which can be overridden to add context-specific
- /// refresh work.
- ///
- ///
- ///
- /// Called on initialization of special objects, before instantiation
- /// of singletons.
- ///
- ///
- protected virtual void OnRefresh()
- {
- }
-
- ///
- /// Instantiate and invoke all registered
- ///
- /// objects, respecting any explicit ordering.
- ///
- ///
- ///
- /// Must be called before singleton instantiation.
- ///
- ///
- /// In the case of errors.
- private void InvokeObjectFactoryPostProcessors()
- {
- // do NOT include IFactoryObjects; they (typically) need to be instantiated
- // to determine the Type of object that they create, and if they are instantiated
- // then we won't be able to do any factory post processin' on 'em...
- string[] factoryProcessorNames
- = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false);
- ArrayList orderedFactoryProcessors = new ArrayList();
- IList nonOrderedFactoryProcessorNames = new ArrayList();
- for (int i = 0; i < factoryProcessorNames.Length; ++i)
- {
- string processorName = factoryProcessorNames[i];
- object processor = GetObject(processorName);
- if (typeof(IOrdered).IsAssignableFrom(GetType(processorName)))
- {
- orderedFactoryProcessors.Add(processor);
- }
- else
- {
- nonOrderedFactoryProcessorNames.Add(processor);
- }
- }
- // first, invoke those IObjectFactoryPostProcessors that implement IOrdered...
- orderedFactoryProcessors.Sort(new OrderComparator());
- ProcessObjectFactoryPostProcessors(orderedFactoryProcessors);
- // and then the unordered ones...
- ProcessObjectFactoryPostProcessors(nonOrderedFactoryProcessorNames);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "processed {0} IFactoryObjectPostProcessors defined in application context [{1}].",
- factoryProcessorNames.Length,
- Name));
- }
-
- #endregion
- }
-
- private void ProcessObjectFactoryPostProcessors(IList orderedFactoryProcessors)
- {
- foreach (IObjectFactoryPostProcessor processor in orderedFactoryProcessors)
- {
- processor.PostProcessObjectFactory(ObjectFactory);
- }
- }
-
- private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
- {
- RegisterObjectPostProcessorChecker(objectFactory);
- IDictionary dict = GetObjectsOfType(typeof(IObjectPostProcessor), true, false);
- ArrayList objectProcessors = new ArrayList(dict.Values);
- objectProcessors.Sort(new OrderComparator());
- foreach (IObjectPostProcessor objectPostProcessor in objectProcessors)
- {
- ObjectFactory.AddObjectPostProcessor(objectPostProcessor);
- }
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "processed {0} IObjectPostProcessors defined in application context [{1}].",
- objectProcessors.Count,
- Name));
- }
- }
-
- ///
- /// Register an IObjectPostProcessorChecker that logs an info
- /// message when an object is created during IObjectPostProcessor
- /// instantiation, i.e. when an object is not eligible for being
- /// processed by all IObjectPostProcessors.
- ///
- private void RegisterObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory)
- {
- int objectPostProcessorCount
- = ObjectFactory.ObjectPostProcessorCount + 1
- + GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length;
-// ObjectFactory.AddObjectPostProcessor(
-// new ObjectPostProcessorChecker(objectFactory, objectPostProcessorCount));
- ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount);
- }
-
- ///
- /// Initializes the default event registry for this context.
- ///
- private void InitEventRegistry()
- {
- if (ContainsObject(EventRegistryObjectName))
- {
- object candidateRegistry = GetObject(EventRegistryObjectName);
- if (candidateRegistry is IEventRegistry)
- {
- _eventRegistry = (IEventRegistry) candidateRegistry;
-
- #region Instrumentation
-
- log.Debug(StringUtils.Surround(
- "Using IEventRegistry [", EventRegistry, "]"));
-
- #endregion
- }
- else
- {
- _eventRegistry = new EventRegistry();
-
- #region Instrumentation
-
- if (log.IsWarnEnabled)
- {
- log.Warn(string.Format(
- "Found object in context named '{0}' : this name " +
- "is typically reserved for IEventRegistry objects. " +
- "Falling back to default '{1}'.",
- EventRegistryObjectName, EventRegistry));
- }
-
- #endregion
- }
- }
- else
- {
- _eventRegistry = new EventRegistry();
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No IEventRegistry found with name '{0}' : using default '{1}'.",
- EventRegistryObjectName, EventRegistry));
- }
-
- #endregion
- }
- ICollection interestedParties
- = GetObjectsOfType(typeof(IEventRegistryAware), true, false).Values;
- foreach (IEventRegistryAware party in interestedParties)
- {
- party.EventRegistry = EventRegistry;
- }
- EventRegistry.PublishEvents(this);
- }
-
- ///
- /// Returns the internal message source of the parent context if said
- /// parent context is an , else
- /// simply the parent context itself.
- ///
- ///
- /// The internal message source of the parent context if said
- /// parent context is an , else
- /// simply the parent context itself.
- ///
- protected virtual IMessageSource GetInternalParentMessageSource()
- {
- AbstractApplicationContext parent
- = ParentContext as AbstractApplicationContext;
- return parent == null ? ParentContext : parent._messageSource;
- }
-
- ///
- /// Initializes the default message source for this context.
- ///
- ///
- ///
- /// Uses any parent context's message source if one is not available
- /// in this context.
- ///
- ///
- private void InitMessageSource()
- {
- if (ContainsObject(MessageSourceObjectName))
- {
- object candidateSource = GetObject(MessageSourceObjectName);
- if (candidateSource is IMessageSource)
- {
- _messageSource
- = (IMessageSource) GetObject(MessageSourceObjectName);
-
- // make IMessageSource aware of any parent IMessageSource...
- if (ParentContext != null)
- {
- IHierarchicalMessageSource hierSource
- = MessageSource as IHierarchicalMessageSource;
- if (hierSource != null)
- {
- IMessageSource parentMessageSource
- = GetInternalParentMessageSource();
- hierSource.ParentMessageSource = parentMessageSource;
- }
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(StringUtils.Surround(
- "Using MessageSource [", MessageSource, "]"));
- }
-
- #endregion
- }
- else
- {
- _messageSource = new DelegatingMessageSource(
- GetInternalParentMessageSource());
-
- #region Instrumentation
-
- if (log.IsWarnEnabled)
- {
- log.Warn(string.Format(
- "Found object in context named '{0}' : this name " +
- "is typically reserved for IMessageSource objects. " +
- "Falling back to default '{1}'.",
- MessageSourceObjectName, MessageSource));
- }
-
- #endregion
- }
- }
- else if (ParentContext != null)
- {
- _messageSource = new DelegatingMessageSource(
- GetInternalParentMessageSource());
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No message source found in the current context: using parent context's message source '{0}'.",
- MessageSource));
- }
-
- #endregion
- }
- else
- {
- _messageSource = new StaticMessageSource();
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No IMessageSource found with name '{0}' : using default '{1}'.",
- MessageSourceObjectName, MessageSource));
- }
-
- #endregion
- }
- }
-
- private void RefreshApplicationEventListeners()
- {
- ICollection listeners
- = GetObjectsOfType(
- typeof(IApplicationEventListener), true, false).Values;
- foreach (IApplicationEventListener applicationListener in listeners)
- {
- EventRegistry.Subscribe(applicationListener);
- }
- }
-
- ///
- /// Returns the list of the
- /// s
- /// that will be applied to the objects created with this factory.
- ///
- ///
- ///
- /// The elements of this list are instances of implementations of the
- ///
- /// interface.
- ///
+ /// Does not mandate the type of storage used for configuration, but does
+ /// implement common functionality. Uses the Template Method design
+ /// pattern, requiring concrete subclasses to implement
+ /// methods.
+ ///
+ ///
+ /// In contrast to a plain vanilla
+ /// , an
+ /// is supposed
+ /// to detect special objects defined in its object factory: therefore,
+ /// this class automatically registers
+ /// s,
+ /// s
+ /// and s that are
+ /// defined as objects in the context.
+ ///
+ ///
+ /// An may be also supplied as
+ /// an object in the context, with the special, well-known-name of
+ /// "messageSource". Else, message resolution is delegated to the
+ /// parent context.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergan Hoeller
+ /// Griffin Caprio (.NET)
+ ///
+ ///
+ public abstract class AbstractApplicationContext
+ : ConfigurableResourceLoader, IConfigurableApplicationContext
+ {
+ #region Constants
+
+ ///
+ /// Name of the .Net config section that contains Spring.Net context definition.
+ ///
+ public const string ContextSectionName = "spring/context";
+
+ ///
+ /// Default name of the root context.
+ ///
+ public const string DefaultRootContextName = "spring.root";
+
+ #endregion
+
+ #region Fields
+
+ private const long TicksAtEpoch = 621355968000000000;
+
+ ///
+ /// The special, well-known-name of the default
+ /// in the context.
+ ///
+ ///
+ ///
+ /// If no can be found
+ /// in the context using this lookup key, then message resolution
+ /// will be delegated to the parent context (if any).
+ ///
+ ///
+ public static readonly string MessageSourceObjectName = "messageSource";
+
+ ///
+ /// The special, well-known-name of the default
+ /// in the context.
+ ///
+ ///
+ ///
+ /// If no can be found
+ /// in the context using this lookup key, then a default
+ /// will be used.
+ ///
+ ///
+ public static readonly string EventRegistryObjectName = "eventRegistry";
+
+ ///
+ /// The instance for this class.
+ ///
+ private static readonly ILog log = LogManager.GetLogger(typeof(AbstractApplicationContext));
+
+ ///
+ /// The instance we delegate
+ /// our implementation of said interface to.
+ ///
+ private IMessageSource _messageSource;
+
+ ///
+ /// The instance we
+ /// delegate our implementation of said interface to.
+ ///
+ private IEventRegistry _eventRegistry;
+
+ private IApplicationContext _parentApplicationContext;
+ private readonly IList _objectFactoryPostProcessors;
+ private IList _defaultObjectPostProcessors;
+ private string _name;
+ private DateTime _startupDate;
+ private readonly bool _caseSensitive;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// with no parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ protected AbstractApplicationContext() : this(null, true, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// with no parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this context case sensitive or not.
+ protected AbstractApplicationContext(bool caseSensitive) : this(null, caseSensitive, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// with the supplied parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ /// The application context name.
+ /// Flag specifying whether to make this context case sensitive or not.
+ /// The parent application context.
+ protected AbstractApplicationContext(string name, bool caseSensitive,
+ IApplicationContext parentApplicationContext)
+ {
+ _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name;
+ _caseSensitive = caseSensitive;
+ _parentApplicationContext = parentApplicationContext;
+ _objectFactoryPostProcessors = new ArrayList();
+ _defaultObjectPostProcessors = new ArrayList();
+ AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker());
+ AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this));
+ }
+
+ ///
+ /// Adds the given to the list of standard
+ /// processors being added to the underlying
+ ///
+ ///
+ /// Each time is called on this context, the context ensures, that
+ /// all default s are registered with the underlying .
+ ///
+ /// The instance.
+ protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor)
+ {
+ _defaultObjectPostProcessors.Add(defaultObjectPostProcessor);
+ }
+
+ ///
+ /// Closes this context and disposes of any resources (such as
+ /// singleton objects in the wrapped
+ /// ).
+ ///
+ public virtual void Dispose()
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Closing application context [{0}].",
+ Name));
+ }
+
+ #endregion
+
+ new DefensiveEventRaiser().Raise(
+ ContextEvent, this,
+ new ContextEventArgs(ContextEventArgs.ContextEvent.Closed));
+ ObjectFactory.Dispose();
+ }
+
+ #endregion
+
+ #region Abstract Methods
+
+ ///
+ /// Subclasses must implement this method to perform the actual
+ /// configuration loading.
+ ///
+ ///
+ ///
+ /// This method is invoked by
+ /// ,
+ /// before any other initialization occurs.
+ ///
+ ///
+ ///
+ /// In the case of errors encountered while refreshing the object factory.
+ ///
+ protected abstract void RefreshObjectFactory();
+
+ #endregion
+
+ ///
+ /// An object that can be used to synchronize access to the
+ ///
+ public object SyncRoot
+ {
+ get { return this; }
+ }
+
+ ///
+ /// The timestamp when this context was first loaded.
+ ///
+ ///
+ /// The timestamp (milliseconds) when this context was first loaded.
+ ///
+ public long StartupDateMilliseconds
+ {
+ get { return (StartupDate.Ticks - TicksAtEpoch)/10000; }
+ }
+
+
+ ///
+ /// Gets a flag indicating whether context should be case sensitive.
+ ///
+ /// true if object lookups are case sensitive; otherwise, false.
+ protected bool CaseSensitive
+ {
+ get { return _caseSensitive; }
+ }
+
+ ///
+ /// The for this context.
+ ///
+ ///
+ /// If the context has not been initialized yet.
+ ///
+ public IMessageSource MessageSource
+ {
+ get
+ {
+ if (_messageSource == null)
+ {
+ throw new InvalidOperationException(
+ "MessageSource not initialized - call 'Refresh()' " +
+ "before accessing messages via the context: " + this);
+ }
+ return _messageSource;
+ }
+ }
+
+ ///
+ /// The for this context.
+ ///
+ ///
+ /// If the context has not been initialized yet.
+ ///
+ public IEventRegistry EventRegistry
+ {
+ get
+ {
+ if (_eventRegistry == null)
+ {
+ throw new InvalidOperationException(
+ "EventRegistry not initialized - call 'Refresh()' " +
+ "before accessing the event registry via the context: " + this);
+ }
+ return _eventRegistry;
+ }
+ }
+
+ ///
+ /// Returns the internal object factory of the parent context if it implements
+ /// ; else,
+ /// returns the parent context itself.
+ ///
+ ///
+ /// The parent context's object factory, or the parent itself.
+ ///
+ protected IObjectFactory GetInternalParentObjectFactory()
+ {
+ IConfigurableApplicationContext configContext
+ = _parentApplicationContext as IConfigurableApplicationContext;
+ if (configContext != null)
+ {
+ return ((IConfigurableApplicationContext)
+ _parentApplicationContext).ObjectFactory;
+ }
+ else
+ {
+ return _parentApplicationContext;
+ }
+ }
+
+ ///
+ /// Raises an application context event.
+ ///
+ ///
+ /// Any arguments to the event. May be .
+ ///
+ protected virtual void OnContextEvent(ApplicationEventArgs e)
+ {
+ OnContextEvent(this, e);
+ }
+
+ ///
+ /// Raises an application context event.
+ ///
+ ///
+ /// The source of the event.
+ ///
+ ///
+ /// Any arguments to the event. May be .
+ ///
+ protected virtual void OnContextEvent(object source, ApplicationEventArgs e)
+ {
+ new DefensiveEventRaiser().Raise(ContextEvent, source, e);
+ }
+
+ ///
+ /// Modify the application context's internal object factory after its standard
+ /// initialization.
+ ///
+ ///
+ ///
+ /// All object definitions will have been loaded, but no objects
+ /// will have been instantiated yet. This allows for the registration
+ /// of special
+ /// s
+ /// in certain
+ /// implementations.
+ ///
+ ///
+ ///
+ /// The object factory used by the application context.
+ ///
+ ///
+ /// In the case of errors.
+ /// .
+ protected virtual void PostProcessObjectFactory(
+ IConfigurableListableObjectFactory objectFactory)
+ {
+ }
+
+ ///
+ /// Template method which can be overridden to add context-specific
+ /// refresh work.
+ ///
+ ///
+ ///
+ /// Called on initialization of special objects, before instantiation
+ /// of singletons.
+ ///
+ ///
+ protected virtual void OnRefresh()
+ {
+ }
+
+ ///
+ /// Instantiate and invoke all registered
+ ///
+ /// objects, respecting any explicit ordering.
+ ///
+ ///
+ ///
+ /// Must be called before singleton instantiation.
+ ///
+ ///
+ /// In the case of errors.
+ private void InvokeObjectFactoryPostProcessors()
+ {
+ // do NOT include IFactoryObjects; they (typically) need to be instantiated
+ // to determine the Type of object that they create, and if they are instantiated
+ // then we won't be able to do any factory post processin' on 'em...
+ string[] factoryProcessorNames
+ = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false);
+ ArrayList orderedFactoryProcessors = new ArrayList();
+ IList nonOrderedFactoryProcessorNames = new ArrayList();
+ for (int i = 0; i < factoryProcessorNames.Length; ++i)
+ {
+ string processorName = factoryProcessorNames[i];
+ object processor = GetObject(processorName);
+ if (typeof(IOrdered).IsAssignableFrom(GetType(processorName)))
+ {
+ orderedFactoryProcessors.Add(processor);
+ }
+ else
+ {
+ nonOrderedFactoryProcessorNames.Add(processor);
+ }
+ }
+ // first, invoke those IObjectFactoryPostProcessors that implement IOrdered...
+ orderedFactoryProcessors.Sort(new OrderComparator());
+ ProcessObjectFactoryPostProcessors(orderedFactoryProcessors);
+ // and then the unordered ones...
+ ProcessObjectFactoryPostProcessors(nonOrderedFactoryProcessorNames);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "processed {0} IFactoryObjectPostProcessors defined in application context [{1}].",
+ factoryProcessorNames.Length,
+ Name));
+ }
+
+ #endregion
+ }
+
+ private void ProcessObjectFactoryPostProcessors(IList orderedFactoryProcessors)
+ {
+ foreach (IObjectFactoryPostProcessor processor in orderedFactoryProcessors)
+ {
+ processor.PostProcessObjectFactory(ObjectFactory);
+ }
+ }
+
+ private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
+ {
+ RegisterObjectPostProcessorChecker(objectFactory);
+ IDictionary dict = GetObjectsOfType(typeof(IObjectPostProcessor), true, false);
+ ArrayList objectProcessors = new ArrayList(dict.Values);
+ objectProcessors.Sort(new OrderComparator());
+ foreach (IObjectPostProcessor objectPostProcessor in objectProcessors)
+ {
+ ObjectFactory.AddObjectPostProcessor(objectPostProcessor);
+ }
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "processed {0} IObjectPostProcessors defined in application context [{1}].",
+ objectProcessors.Count,
+ Name));
+ }
+ }
+
+ ///
+ /// Register an IObjectPostProcessorChecker that logs an info
+ /// message when an object is created during IObjectPostProcessor
+ /// instantiation, i.e. when an object is not eligible for being
+ /// processed by all IObjectPostProcessors.
+ ///
+ private void RegisterObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory)
+ {
+ int objectPostProcessorCount
+ = ObjectFactory.ObjectPostProcessorCount + 1
+ + GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length;
+// ObjectFactory.AddObjectPostProcessor(
+// new ObjectPostProcessorChecker(objectFactory, objectPostProcessorCount));
+ ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount);
+ }
+
+ ///
+ /// Initializes the default event registry for this context.
+ ///
+ private void InitEventRegistry()
+ {
+ if (ContainsObject(EventRegistryObjectName))
+ {
+ object candidateRegistry = GetObject(EventRegistryObjectName);
+ if (candidateRegistry is IEventRegistry)
+ {
+ _eventRegistry = (IEventRegistry) candidateRegistry;
+
+ #region Instrumentation
+
+ log.Debug(StringUtils.Surround(
+ "Using IEventRegistry [", EventRegistry, "]"));
+
+ #endregion
+ }
+ else
+ {
+ _eventRegistry = new EventRegistry();
+
+ #region Instrumentation
+
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(string.Format(
+ "Found object in context named '{0}' : this name " +
+ "is typically reserved for IEventRegistry objects. " +
+ "Falling back to default '{1}'.",
+ EventRegistryObjectName, EventRegistry));
+ }
+
+ #endregion
+ }
+ }
+ else
+ {
+ _eventRegistry = new EventRegistry();
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No IEventRegistry found with name '{0}' : using default '{1}'.",
+ EventRegistryObjectName, EventRegistry));
+ }
+
+ #endregion
+ }
+ ICollection interestedParties
+ = GetObjectsOfType(typeof(IEventRegistryAware), true, false).Values;
+ foreach (IEventRegistryAware party in interestedParties)
+ {
+ party.EventRegistry = EventRegistry;
+ }
+ EventRegistry.PublishEvents(this);
+ }
+
+ ///
+ /// Returns the internal message source of the parent context if said
+ /// parent context is an , else
+ /// simply the parent context itself.
+ ///
+ ///
+ /// The internal message source of the parent context if said
+ /// parent context is an , else
+ /// simply the parent context itself.
+ ///
+ protected virtual IMessageSource GetInternalParentMessageSource()
+ {
+ AbstractApplicationContext parent
+ = ParentContext as AbstractApplicationContext;
+ return parent == null ? ParentContext : parent._messageSource;
+ }
+
+ ///
+ /// Initializes the default message source for this context.
+ ///
+ ///
+ ///
+ /// Uses any parent context's message source if one is not available
+ /// in this context.
+ ///
+ ///
+ private void InitMessageSource()
+ {
+ if (ContainsObject(MessageSourceObjectName))
+ {
+ object candidateSource = GetObject(MessageSourceObjectName);
+ if (candidateSource is IMessageSource)
+ {
+ _messageSource
+ = (IMessageSource) GetObject(MessageSourceObjectName);
+
+ // make IMessageSource aware of any parent IMessageSource...
+ if (ParentContext != null)
+ {
+ IHierarchicalMessageSource hierSource
+ = MessageSource as IHierarchicalMessageSource;
+ if (hierSource != null)
+ {
+ IMessageSource parentMessageSource
+ = GetInternalParentMessageSource();
+ hierSource.ParentMessageSource = parentMessageSource;
+ }
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(StringUtils.Surround(
+ "Using MessageSource [", MessageSource, "]"));
+ }
+
+ #endregion
+ }
+ else
+ {
+ _messageSource = new DelegatingMessageSource(
+ GetInternalParentMessageSource());
+
+ #region Instrumentation
+
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(string.Format(
+ "Found object in context named '{0}' : this name " +
+ "is typically reserved for IMessageSource objects. " +
+ "Falling back to default '{1}'.",
+ MessageSourceObjectName, MessageSource));
+ }
+
+ #endregion
+ }
+ }
+ else if (ParentContext != null)
+ {
+ _messageSource = new DelegatingMessageSource(
+ GetInternalParentMessageSource());
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No message source found in the current context: using parent context's message source '{0}'.",
+ MessageSource));
+ }
+
+ #endregion
+ }
+ else
+ {
+ _messageSource = new StaticMessageSource();
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No IMessageSource found with name '{0}' : using default '{1}'.",
+ MessageSourceObjectName, MessageSource));
+ }
+
+ #endregion
+ }
+ }
+
+ private void RefreshApplicationEventListeners()
+ {
+ ICollection listeners
+ = GetObjectsOfType(
+ typeof(IApplicationEventListener), true, false).Values;
+ foreach (IApplicationEventListener applicationListener in listeners)
+ {
+ EventRegistry.Subscribe(applicationListener);
+ }
+ }
+
+ ///
+ /// Returns the list of the
+ /// s
+ /// that will be applied to the objects created with this factory.
+ ///
+ ///
+ ///
+ /// The elements of this list are instances of implementations of the
+ ///
+ /// interface.
+ ///
+ ///
+ ///
+ /// The list of the
+ /// s
+ /// that will be applied to the objects created with this factory.
+ ///
+ private IList ObjectFactoryPostProcessors
+ {
+ get { return _objectFactoryPostProcessors; }
+ }
+
+ #region IConfigurableApplicationContext Members
+
+ ///
+ /// Return the internal object factory of this application context.
+ ///
+ public abstract IConfigurableListableObjectFactory ObjectFactory { get; }
+
+ ///
+ /// Add a new
+ /// that will get applied to the internal object factory of this application context
+ /// on refresh, before any of the object definitions are evaluated.
+ ///
+ ///
+ /// The factory processor to register.
+ ///
+ public void AddObjectFactoryPostProcessor(
+ IObjectFactoryPostProcessor objectFactoryPostProcessor)
+ {
+ _objectFactoryPostProcessors.Add(objectFactoryPostProcessor);
+ }
+
+ ///
+ /// Load or refresh the persistent representation of the configuration,
+ /// which might an XML file, properties file, or relational database schema.
+ ///
+ ///
+ /// If the configuration cannot be loaded.
+ ///
+ ///
+ /// If the object factory could not be initialized.
+ ///
+ public virtual void Refresh()
+ {
+ lock (SyncRoot)
+ {
+
+
+ _startupDate = DateTime.Now;
+
+ RefreshObjectFactory();
+ IConfigurableListableObjectFactory objectFactory = ObjectFactory;
+
+ PrepareObjectFactory(objectFactory);
+
+ PostProcessObjectFactory(objectFactory);
+ foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors)
+ {
+ factoryProcessor.PostProcessObjectFactory(objectFactory);
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} objects defined in application context [{1}].",
+ ObjectDefinitionCount == 0 ? "No" : ObjectDefinitionCount.ToString(),
+ Name));
+ }
+
+ #endregion
+
+ InvokeObjectFactoryPostProcessors();
+ RegisterObjectPostProcessors(objectFactory);
+ InitEventRegistry();
+ InitMessageSource();
+ OnRefresh();
+ RefreshApplicationEventListeners();
+
+ objectFactory.PreInstantiateSingletons();
+
+ new DefensiveEventRaiser().Raise(
+ ContextEvent, this,
+ new ContextEventArgs(ContextEventArgs.ContextEvent.Refreshed));
+ }
+ }
+
+ private void PrepareObjectFactory(IConfigurableListableObjectFactory objectFactory)
+ {
+ EnsureKnownObjectPostProcessors(objectFactory);
+ objectFactory.IgnoreDependencyType(typeof(IResourceLoader));
+ objectFactory.IgnoreDependencyType(typeof(IApplicationContext));
+
+ objectFactory.RegisterResolvableDependency(typeof(IObjectFactory), objectFactory);
+ objectFactory.RegisterResolvableDependency(typeof(IResourceLoader), this);
+ objectFactory.RegisterResolvableDependency(typeof(IApplicationEventPublisher), this);
+ objectFactory.RegisterResolvableDependency(typeof(IApplicationContext), this);
+ objectFactory.RegisterResolvableDependency(typeof(IEventRegistry), this);
+
+ }
+
+ ///
+ /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory
+ ///
+ ///
+ protected void EnsureKnownObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
+ {
+ // index 0 contains the ObjectPostProcessorChecker that is handled separately!
+ for (int i = 1; i < _defaultObjectPostProcessors.Count; i++)
+ {
+ objectFactory.AddObjectPostProcessor((IObjectPostProcessor) this._defaultObjectPostProcessors[i]);
+ }
+ }
+
+ ///
+ /// Gets the parent context, or if there is no
+ /// parent context.
+ ///
+ ///
+ /// The parent context, or if there is no
+ /// parent.
+ ///
+ ///
+ public virtual IApplicationContext ParentContext
+ {
+ get { return _parentApplicationContext; }
+ set { _parentApplicationContext = value; }
+ }
+
#endregion
#region ILifecycle Members
@@ -953,908 +951,923 @@ namespace Spring.Context.Support
#endregion
- #region IApplicationContext Members
-
- ///
- /// Raised in response to an implementation-dependant application
- /// context event.
- ///
- public event ApplicationEventHandler ContextEvent;
-
- ///
- /// The date and time this context was first loaded.
- ///
- ///
- /// The representing when this context
- /// was first loaded.
- ///
- public DateTime StartupDate
- {
- get { return _startupDate; }
- }
-
- ///
- /// A name for this context.
- ///
- ///
- /// A name for this context.
- ///
- public string Name
- {
- get { return _name; }
- set { _name = value; }
- }
-
-
-
- #endregion
-
- #region IListableObjectFactory Members
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectNamesForType(Type type)
- {
- return ObjectFactory.GetObjectNamesForType(type);
- }
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s).
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectNamesForType(
- Type type, bool includePrototypes, bool includeFactoryObjects)
- {
- return ObjectFactory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects);
- }
-
- ///
- /// Return the names of all objects defined in this factory.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectDefinitionNames()
- {
- return ObjectFactory.GetObjectDefinitionNames();
- }
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public virtual IObjectDefinition GetObjectDefinition(string name)
- {
- return ObjectFactory.GetObjectDefinition(name);
- }
-
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- /// Whether to search parent object factories.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
- {
- return ObjectFactory.GetObjectDefinition(name, includeAncestors);
- }
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- /// The (class or interface) to match.
- ///
- ///
- /// A of the matching objects,
- /// containing the object names as keys and the corresponding object instances
- /// as values.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- public IDictionary GetObjectsOfType(Type type)
- {
- return GetObjectsOfType(type, true, true);
- }
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- /// The (class or interface) to match.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s).
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// A of the matching objects,
- /// containing the object names as keys and the corresponding object instances
- /// as values.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- public IDictionary GetObjectsOfType(
- Type type, bool includePrototypes, bool includeFactoryObjects)
- {
- return ObjectFactory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
- }
-
- ///
- /// Return the number of objects defined in the factory.
- ///
- ///
- /// The number of objects defined in the factory.
- ///
- ///
- public int ObjectDefinitionCount
- {
- get { return ObjectFactory.ObjectDefinitionCount; }
- }
-
- ///
- /// Check if this object factory contains an object definition with the given name.
- ///
- /// The name of the object to look for.
- ///
- /// True if this object factory contains an object definition with the given name.
- ///
- ///
- public bool ContainsObjectDefinition(string name)
- {
- return ObjectFactory.ContainsObjectDefinition(name);
- }
-
- #endregion
-
- #region IObjectFactory Members
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- public object this[string name]
- {
- get { return ObjectFactory.GetObject(name); }
- }
-
- ///
- /// Does this object factory contain an object with the given name?
- ///
- /// The name of the object to query.
- ///
- /// if an object with the given name is defined.
- ///
- ///
- public bool ContainsObject(string name)
- {
- return ObjectFactory.ContainsObject(name);
- }
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- /// The object name to check for aliases.
- /// The aliases, or an empty array if none.
- ///
- /// If there's no such object definition.
- ///
- ///
- public string[] GetAliases(string name)
- {
- return ObjectFactory.GetAliases(name);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- public object GetObject(string name, Type requiredType)
- {
- return ObjectFactory.GetObject(name, requiredType);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- public object GetObject(string name)
- {
- return ObjectFactory.GetObject(name);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. If there is no factory method and the
- /// arguments are not null, then match the argument values by type and
- /// call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the supplied is .
- ///
- public object GetObject(string name, object[] arguments)
- {
- return ObjectFactory.GetObject(name, arguments);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public object GetObject(string name, Type requiredType, object[] arguments)
- {
- return ObjectFactory.GetObject(name, requiredType, arguments);
- }
-
- ///
- /// Is this object a singleton?
- ///
- /// The name of the object to query.
- /// True if the named object is a singleton.
- ///
- /// If there's no such object definition.
- ///
- ///
- public bool IsSingleton(string name)
- {
- return ObjectFactory.IsSingleton(name);
- }
-
- ///
- /// Determines whether the specified object name is prototype. That is, will GetObject
- /// always return independent instances?
- ///
- /// The name of the object to query
- ///
- /// true if the specified object name will always deliver independent instances; otherwise, false.
- ///
- /// This method returning false does not clearly indicate a singleton object.
- /// It indicated non-independent instances, which may correspond to a scoped object as
- /// well. use the IsSingleton property to explicitly check for a shared
- /// singleton instance.
- /// Translates aliases back to the corresponding canonical object name. Will ask the
- /// parent factory if the object can not be found in this factory instance.
- ///
- ///
- /// if there is no object with the given name.
- public bool IsPrototype(string name)
- {
- return ObjectFactory.IsPrototype(name);
- }
-
-
- ///
- /// Determines whether the object with the given name matches the specified type.
- ///
- /// More specifically, check whether a GetObject call for the given name
- /// would return an object that is assignable to the specified target type.
- /// Translates aliases back to the corresponding canonical bean name.
- /// Will ask the parent factory if the bean cannot be found in this factory instance.
- ///
- /// The name of the object to query.
- /// Type of the target to match against.
- ///
- /// true if the object type matches; otherwise, false
- /// if it doesn't match or cannot be determined yet.
- ///
- /// Ff there is no object with the given name
- ///
- public bool IsTypeMatch(string name, Type targetType)
- {
- return ObjectFactory.IsTypeMatch(name, targetType);
- }
-
- ///
- /// Determine the of the object with the
- /// given name.
- ///
- /// The name of the object to query.
- ///
- /// The of the object, or
- /// if not determinable.
- ///
- ///
- public Type GetType(string name)
- {
- return ObjectFactory.GetType(name);
- }
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the named object definition.
- ///
- ///
- /// The object instance that is to be so configured.
- ///
- ///
- /// The name of the object definition expressing the dependencies that are to
- /// be injected into the supplied instance.
- ///
- ///
- public object ConfigureObject(object target, string name)
- {
- return ObjectFactory.ConfigureObject(target, name);
- }
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the supplied .
- ///
- ///
- /// The object instance that is to be so configured.
- ///
- ///
- /// The name of the object definition expressing the dependencies that are to
- /// be injected into the supplied instance.
- ///
- ///
- /// An object definition that should be used to configure object.
- ///
- ///
- public object ConfigureObject(object target, string name, IObjectDefinition definition)
- {
- return ObjectFactory.ConfigureObject(target, name, definition);
- }
-
- #endregion
-
- #region IHierarchicalObjectFactory Members
-
- ///
- /// Return the parent object factory, or if there is none.
- ///
- ///
- /// The parent object factory, or if there is none.
- ///
- ///
- public IObjectFactory ParentObjectFactory
- {
- get { return _parentApplicationContext; }
- }
-
- #endregion
-
- #region IMessageSource Members
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(
- string name, CultureInfo culture, params object[] arguments)
- {
- return MessageSource.GetMessage(name, culture, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The default message.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
- {
- return MessageSource.GetMessage(name, defaultMessage, culture, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The resolved message if the lookup was successful.
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- public string GetMessage(string name)
- {
- return MessageSource.GetMessage(name);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful.
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, params object[] arguments)
- {
- return MessageSource.GetMessage(name, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, CultureInfo culture)
- {
- return MessageSource.GetMessage(name, culture);
- }
-
- ///
- /// Resolve the message using all of the attributes contained within
- /// the supplied
- /// argument.
- ///
- ///
- /// The value object storing those attributes that are required to
- /// properly resolve a message.
- ///
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If the message could not be resolved.
- ///
- ///
- public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
- {
- return MessageSource.GetMessage(resolvable, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- object IMessageSource.GetResourceObject(string name, CultureInfo culture)
- {
- return GetResourceObject(name, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- object IMessageSource.GetResourceObject(string name)
- {
- return GetResourceObject(name);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- public object GetResourceObject(string name, CultureInfo culture)
- {
- return MessageSource.GetResourceObject(name, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- public object GetResourceObject(string name)
- {
- return MessageSource.GetResourceObject(name);
- }
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- public void ApplyResources(object value, string objectName, CultureInfo culture)
- {
- MessageSource.ApplyResources(value, objectName, culture);
- }
-
- #endregion
-
- #region IEventRegistry Members
-
- ///
- /// Publishes all events of the source object.
- ///
- ///
- /// The source object containing events to publish.
- ///
- ///
- public void PublishEvents(object sourceObject)
- {
- _eventRegistry.PublishEvents(sourceObject);
- }
-
- ///
- /// Subscribes to all events published, if the subscriber
- /// implements compatible handler methods.
- ///
- /// The subscriber to use.
- ///
- public void Subscribe(object subscriber)
- {
- _eventRegistry.Subscribe(subscriber);
- }
-
- ///
- /// Subscribes to published events of a all objects of a given
- /// , if the subscriber implements
- /// compatible handler methods.
- ///
- /// The subscriber to use.
- ///
- /// The target to subscribe to.
- ///
- ///
- public void Subscribe(object subscriber, Type targetSourceType)
- {
- _eventRegistry.Subscribe(subscriber, targetSourceType);
- }
-
- #endregion
-
- ///
- /// Publishes an application context event.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// The source of the event. May be .
- ///
- ///
- /// The event that is to be raised.
- ///
- ///
- public void PublishEvent(object sender, ApplicationEventArgs e)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Publishing event in context [{0}] : {1}",
- Name, e));
- }
-
- #endregion
-
- OnContextEvent(sender, e);
-
- if (ParentContext != null)
- {
- ParentContext.PublishEvent(sender, e);
- }
- }
-
- #region IPostProcessor implementation
-
- private sealed class ObjectPostProcessorChecker : IObjectPostProcessor
- {
- private int _objectPostProcessorTargetCount;
- private IConfigurableListableObjectFactory _objectFactory;
-
-
- public ObjectPostProcessorChecker()
- {
- }
-
-// public ObjectPostProcessorChecker(
-// IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount)
-// {
-// _objectFactory = objectFactory;
-// _objectPostProcessorTargetCount = objectPostProcessorTargetCount;
-// }
-
- public void Reset(IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount)
- {
- _objectFactory = objectFactory;
- _objectPostProcessorTargetCount = objectPostProcessorTargetCount;
- }
-
- public object PostProcessBeforeInitialization(object obj, string name)
- {
- return obj;
- }
-
- public object PostProcessAfterInitialization(object obj, string objectName)
- {
- if (_objectFactory.ObjectPostProcessorCount < _objectPostProcessorTargetCount)
- {
- #region Instrumentation
-
- if (log.IsInfoEnabled)
- {
- log.Info(string.Format(
- "Object '{0}' is not eligible for being processed by all " +
- "IObjectPostProcessors (for example: not eligible for auto-proxying).", objectName));
- }
-
- #endregion
- }
- return obj;
- }
- }
-
- #endregion
- }
+ #region IApplicationContext Members
+
+ ///
+ /// Raised in response to an implementation-dependant application
+ /// context event.
+ ///
+ public event ApplicationEventHandler ContextEvent;
+
+ ///
+ /// The date and time this context was first loaded.
+ ///
+ ///
+ /// The representing when this context
+ /// was first loaded.
+ ///
+ public DateTime StartupDate
+ {
+ get { return _startupDate; }
+ }
+
+ ///
+ /// A name for this context.
+ ///
+ ///
+ /// A name for this context.
+ ///
+ public string Name
+ {
+ get { return _name; }
+ set { _name = value; }
+ }
+
+
+
+ #endregion
+
+ #region IListableObjectFactory Members
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectNamesForType(Type type)
+ {
+ return ObjectFactory.GetObjectNamesForType(type);
+ }
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s).
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectNamesForType(
+ Type type, bool includePrototypes, bool includeFactoryObjects)
+ {
+ return ObjectFactory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects);
+ }
+
+ ///
+ /// Return the names of all objects defined in this factory.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectDefinitionNames()
+ {
+ return ObjectFactory.GetObjectDefinitionNames();
+ }
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public virtual IObjectDefinition GetObjectDefinition(string name)
+ {
+ return ObjectFactory.GetObjectDefinition(name);
+ }
+
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ /// Whether to search parent object factories.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
+ {
+ return ObjectFactory.GetObjectDefinition(name, includeAncestors);
+ }
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ /// The (class or interface) to match.
+ ///
+ ///
+ /// A of the matching objects,
+ /// containing the object names as keys and the corresponding object instances
+ /// as values.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ public IDictionary GetObjectsOfType(Type type)
+ {
+ return GetObjectsOfType(type, true, true);
+ }
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ /// The (class or interface) to match.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s).
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// A of the matching objects,
+ /// containing the object names as keys and the corresponding object instances
+ /// as values.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ public IDictionary GetObjectsOfType(
+ Type type, bool includePrototypes, bool includeFactoryObjects)
+ {
+ return ObjectFactory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
+ }
+
+ ///
+ /// Return the number of objects defined in the factory.
+ ///
+ ///
+ /// The number of objects defined in the factory.
+ ///
+ ///
+ public int ObjectDefinitionCount
+ {
+ get { return ObjectFactory.ObjectDefinitionCount; }
+ }
+
+ ///
+ /// Check if this object factory contains an object definition with the given name.
+ ///
+ /// The name of the object to look for.
+ ///
+ /// True if this object factory contains an object definition with the given name.
+ ///
+ ///
+ public bool ContainsObjectDefinition(string name)
+ {
+ return ObjectFactory.ContainsObjectDefinition(name);
+ }
+
+ #endregion
+
+ #region IObjectFactory Members
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ public object this[string name]
+ {
+ get { return ObjectFactory.GetObject(name); }
+ }
+
+ ///
+ /// Does this object factory contain an object with the given name?
+ ///
+ /// The name of the object to query.
+ ///
+ /// if an object with the given name is defined.
+ ///
+ ///
+ public bool ContainsObject(string name)
+ {
+ return ObjectFactory.ContainsObject(name);
+ }
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ /// The object name to check for aliases.
+ /// The aliases, or an empty array if none.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ public string[] GetAliases(string name)
+ {
+ return ObjectFactory.GetAliases(name);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ public object GetObject(string name, Type requiredType)
+ {
+ return ObjectFactory.GetObject(name, requiredType);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ public object GetObject(string name)
+ {
+ return ObjectFactory.GetObject(name);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. If there is no factory method and the
+ /// arguments are not null, then match the argument values by type and
+ /// call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public object GetObject(string name, object[] arguments)
+ {
+ return ObjectFactory.GetObject(name, arguments);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public object GetObject(string name, Type requiredType, object[] arguments)
+ {
+ return ObjectFactory.GetObject(name, requiredType, arguments);
+ }
+
+ ///
+ /// Is this object a singleton?
+ ///
+ /// The name of the object to query.
+ /// True if the named object is a singleton.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ public bool IsSingleton(string name)
+ {
+ return ObjectFactory.IsSingleton(name);
+ }
+
+ ///
+ /// Determines whether the specified object name is prototype. That is, will GetObject
+ /// always return independent instances?
+ ///
+ /// The name of the object to query
+ ///
+ /// true if the specified object name will always deliver independent instances; otherwise, false.
+ ///
+ /// This method returning false does not clearly indicate a singleton object.
+ /// It indicated non-independent instances, which may correspond to a scoped object as
+ /// well. use the IsSingleton property to explicitly check for a shared
+ /// singleton instance.
+ /// Translates aliases back to the corresponding canonical object name. Will ask the
+ /// parent factory if the object can not be found in this factory instance.
+ ///
+ ///
+ /// if there is no object with the given name.
+ public bool IsPrototype(string name)
+ {
+ return ObjectFactory.IsPrototype(name);
+ }
+
+
+ ///
+ /// Determines whether the object with the given name matches the specified type.
+ ///
+ /// More specifically, check whether a GetObject call for the given name
+ /// would return an object that is assignable to the specified target type.
+ /// Translates aliases back to the corresponding canonical bean name.
+ /// Will ask the parent factory if the bean cannot be found in this factory instance.
+ ///
+ /// The name of the object to query.
+ /// Type of the target to match against.
+ ///
+ /// true if the object type matches; otherwise, false
+ /// if it doesn't match or cannot be determined yet.
+ ///
+ /// Ff there is no object with the given name
+ ///
+ public bool IsTypeMatch(string name, Type targetType)
+ {
+ return ObjectFactory.IsTypeMatch(name, targetType);
+ }
+
+ ///
+ /// Determine the of the object with the
+ /// given name.
+ ///
+ /// The name of the object to query.
+ ///
+ /// The of the object, or
+ /// if not determinable.
+ ///
+ ///
+ public Type GetType(string name)
+ {
+ return ObjectFactory.GetType(name);
+ }
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the named object definition.
+ ///
+ ///
+ /// The object instance that is to be so configured.
+ ///
+ ///
+ /// The name of the object definition expressing the dependencies that are to
+ /// be injected into the supplied instance.
+ ///
+ ///
+ public object ConfigureObject(object target, string name)
+ {
+ return ObjectFactory.ConfigureObject(target, name);
+ }
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the supplied .
+ ///
+ ///
+ /// The object instance that is to be so configured.
+ ///
+ ///
+ /// The name of the object definition expressing the dependencies that are to
+ /// be injected into the supplied instance.
+ ///
+ ///
+ /// An object definition that should be used to configure object.
+ ///
+ ///
+ public object ConfigureObject(object target, string name, IObjectDefinition definition)
+ {
+ return ObjectFactory.ConfigureObject(target, name, definition);
+ }
+
+ #endregion
+
+ #region IHierarchicalObjectFactory Members
+
+ ///
+ /// Return the parent object factory, or if there is none.
+ ///
+ ///
+ /// The parent object factory, or if there is none.
+ ///
+ ///
+ public IObjectFactory ParentObjectFactory
+ {
+ get { return _parentApplicationContext; }
+ }
+
+ ///
+ /// Determines whether the local object factory contains a bean of the given name,
+ /// ignoring object defined in ancestor contexts.
+ /// This is an alternative to ContainsObject, ignoring an object
+ /// of the given name from an ancestor object factory.
+ ///
+ /// The name of the object to query.
+ ///
+ /// true if objects with the specified name is defined in the local factory; otherwise, false.
+ ///
+ public bool ContainsLocalObject(string name)
+ {
+ return ObjectFactory.ContainsLocalObject(name);
+ }
+
+ #endregion
+
+ #region IMessageSource Members
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(
+ string name, CultureInfo culture, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The default message.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, defaultMessage, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ public string GetMessage(string name)
+ {
+ return MessageSource.GetMessage(name);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, CultureInfo culture)
+ {
+ return MessageSource.GetMessage(name, culture);
+ }
+
+ ///
+ /// Resolve the message using all of the attributes contained within
+ /// the supplied
+ /// argument.
+ ///
+ ///
+ /// The value object storing those attributes that are required to
+ /// properly resolve a message.
+ ///
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
+ {
+ return MessageSource.GetMessage(resolvable, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ object IMessageSource.GetResourceObject(string name, CultureInfo culture)
+ {
+ return GetResourceObject(name, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ object IMessageSource.GetResourceObject(string name)
+ {
+ return GetResourceObject(name);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name, CultureInfo culture)
+ {
+ return MessageSource.GetResourceObject(name, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name)
+ {
+ return MessageSource.GetResourceObject(name);
+ }
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ /// An object that contains the property values to be applied.
+ ///
+ ///
+ /// The base name of the object to use for key lookup.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ public void ApplyResources(object value, string objectName, CultureInfo culture)
+ {
+ MessageSource.ApplyResources(value, objectName, culture);
+ }
+
+ #endregion
+
+ #region IEventRegistry Members
+
+ ///
+ /// Publishes all events of the source object.
+ ///
+ ///
+ /// The source object containing events to publish.
+ ///
+ ///
+ public void PublishEvents(object sourceObject)
+ {
+ _eventRegistry.PublishEvents(sourceObject);
+ }
+
+ ///
+ /// Subscribes to all events published, if the subscriber
+ /// implements compatible handler methods.
+ ///
+ /// The subscriber to use.
+ ///
+ public void Subscribe(object subscriber)
+ {
+ _eventRegistry.Subscribe(subscriber);
+ }
+
+ ///
+ /// Subscribes to published events of a all objects of a given
+ /// , if the subscriber implements
+ /// compatible handler methods.
+ ///
+ /// The subscriber to use.
+ ///
+ /// The target to subscribe to.
+ ///
+ ///
+ public void Subscribe(object subscriber, Type targetSourceType)
+ {
+ _eventRegistry.Subscribe(subscriber, targetSourceType);
+ }
+
+ #endregion
+
+ ///
+ /// Publishes an application context event.
+ ///
+ ///
+ ///
- /// The returned object instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The existing object instance.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The object instance to use, either the original or a wrapped one.
- ///
- ///
- /// If any post-processing failed.
- ///
- ///
- object ApplyObjectPostProcessorsBeforeInitialization (
- object instance, string name);
-
- ///
- /// Apply s
- /// to the given existing object instance, invoking their
- ///
- /// methods.
- ///
- ///
- ///
- /// The returned object instance may be a wrapper around the original.
- ///
+ /// The returned object instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The existing object instance.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The object instance to use, either the original or a wrapped one.
+ ///
+ ///
+ /// If any post-processing failed.
+ ///
+ ///
+ object ApplyObjectPostProcessorsBeforeInitialization (
+ object instance, string name);
+
+ ///
+ /// Apply s
+ /// to the given existing object instance, invoking their
+ ///
+ /// methods.
+ ///
+ ///
+ ///
+ /// The returned object instance may be a wrapper around the original.
+ ///
- /// This is just a minimal interface: the main intention is to allow
- ///
- /// (like PropertyPlaceholderConfigurer) to access and modify property values.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- public interface IObjectDefinition
- {
- ///
- /// Return the property values to be applied to a new instance of the object.
- ///
- MutablePropertyValues PropertyValues { get; }
-
- ///
- /// Return the constructor argument values for this object.
- ///
- ConstructorArgumentValues ConstructorArgumentValues { get; }
-
- ///
- /// Return the event handlers for any events exposed by this object.
- ///
- EventValues EventHandlerValues { get; }
-
- ///
- /// Return a description of the resource that this object definition
- /// came from (for the purpose of showing context in case of errors).
- ///
- string ResourceDescription { get; }
-
- ///
- /// Is this object definition a "template", i.e. not meant to be instantiated
- /// itself but rather just serving as an object definition for configuration
- /// templates used by .
- ///
- ///
- /// if this object definition is a "template".
- ///
- bool IsTemplate { get; }
-
- ///
- /// Is this object definition "abstract", i.e. not meant to be instantiated
- /// itself but rather just serving as parent for concrete child object
- /// definitions.
- ///
- ///
- /// if this object definition is "abstract".
- ///
- bool IsAbstract { get; }
-
- ///
- /// Return whether this a Singleton, with a single, shared instance
- /// returned on all calls.
- ///
- ///
- ///
- /// If , an object factory will apply the Prototype
- /// design pattern, with each caller requesting an instance getting an
- /// independent instance. How this is defined will depend on the
- /// object factory implementation. Singletons are the commoner type.
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup by object factories
- /// that perform eager initialization of singletons.
- ///
- ///
- bool IsLazyInit { get; }
-
- ///
- /// Returns the of the object definition (if any).
- ///
- ///
- /// A resolved object .
- ///
- ///
- /// If the of the object definition is not a
- /// resolved or .
- ///
- Type ObjectType { get; }
-
- ///
- /// Returns the of the
- /// of the object definition.
- ///
- /// Note that this does not have to be the actual type name used at runtime,
- /// in case of a child definition overrding/inheriting the the type name from its
- /// parent. It can be modifed during object factory post-processing, typically
- /// replacing the original class name with a parsed variant of it.
- /// Hence, do not consider this to be the definitive bean type at runtime
- /// but rather only use it for parsing purposes at the individual object
- /// definition level.
- ///
- string ObjectTypeName { get; set;}
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. Default is
- /// ,
- /// which means there's no autowire.
- ///
- ///
- AutoWiringMode AutowireMode { get; }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before.
- ///
- ///
- /// Note that dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies like statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- string[] DependsOn { get; }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default is , in which case there is no initializer method.
- ///
- ///
- string InitMethodName { get; }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default is , in which case there is no destroy method.
- ///
- ///
- string DestroyMethodName { get; }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The static method will be invoked on
- /// the specified .
- ///
+ /// This is just a minimal interface: the main intention is to allow
+ ///
+ /// (like PropertyPlaceholderConfigurer) to access and modify property values.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IObjectDefinition
+ {
+ ///
+ /// Return the property values to be applied to a new instance of the object.
+ ///
+ MutablePropertyValues PropertyValues { get; }
+
+ ///
+ /// Return the constructor argument values for this object.
+ ///
+ ConstructorArgumentValues ConstructorArgumentValues { get; }
+
+ ///
+ /// Return the event handlers for any events exposed by this object.
+ ///
+ EventValues EventHandlerValues { get; }
+
+ ///
+ /// Return a description of the resource that this object definition
+ /// came from (for the purpose of showing context in case of errors).
+ ///
+ string ResourceDescription { get; }
+
+ ///
+ /// Is this object definition a "template", i.e. not meant to be instantiated
+ /// itself but rather just serving as an object definition for configuration
+ /// templates used by .
+ ///
+ ///
+ /// if this object definition is a "template".
+ ///
+ bool IsTemplate { get; }
+
+ ///
+ /// Is this object definition "abstract", i.e. not meant to be instantiated
+ /// itself but rather just serving as parent for concrete child object
+ /// definitions.
+ ///
+ ///
+ /// if this object definition is "abstract".
+ ///
+ bool IsAbstract { get; }
+
+ ///
+ /// Return whether this a Singleton, with a single, shared instance
+ /// returned on all calls.
+ ///
+ ///
+ ///
+ /// If , an object factory will apply the Prototype
+ /// design pattern, with each caller requesting an instance getting an
+ /// independent instance. How this is defined will depend on the
+ /// object factory implementation. Singletons are the commoner type.
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup by object factories
+ /// that perform eager initialization of singletons.
+ ///
+ ///
+ bool IsLazyInit { get; }
+
+ ///
+ /// Returns the of the object definition (if any).
+ ///
+ ///
+ /// A resolved object .
+ ///
+ ///
+ /// If the of the object definition is not a
+ /// resolved or .
+ ///
+ Type ObjectType { get; }
+
+ ///
+ /// Returns the of the
+ /// of the object definition.
+ ///
+ /// Note that this does not have to be the actual type name used at runtime,
+ /// in case of a child definition overrding/inheriting the the type name from its
+ /// parent. It can be modifed during object factory post-processing, typically
+ /// replacing the original class name with a parsed variant of it.
+ /// Hence, do not consider this to be the definitive bean type at runtime
+ /// but rather only use it for parsing purposes at the individual object
+ /// definition level.
+ ///
+ string ObjectTypeName { get; set;}
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. Default is
+ /// ,
+ /// which means there's no autowire.
+ ///
+ ///
+ AutoWiringMode AutowireMode { get; }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before.
+ ///
+ ///
+ /// Note that dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies like statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ string[] DependsOn { get; }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no initializer method.
+ ///
+ ///
+ string InitMethodName { get; }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no destroy method.
+ ///
+ ///
+ string DestroyMethodName { get; }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The static method will be invoked on
+ /// the specified .
+ ///
- /// The nesting hierarchy of an object factory is taken into account by the various methods
- /// exposed by this class.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- public sealed class ObjectFactoryUtils
- {
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly visible
- /// constructors.
- ///
- ///
- private ObjectFactoryUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// Used to dereference an
- /// and distinguish it from managed objects created by the factory.
- ///
- ///
- ///
- /// For example, if the managed object identified as foo is a
- /// factory, getting &foo will return the factory, not the
- /// instance returned by the factory.
- ///
- ///
- public const string FactoryObjectPrefix = "&";
-
- ///
- /// Count all object definitions in any hierarchy in which this
- /// factory participates.
- ///
- ///
- ///
- /// Includes counts of ancestor object factories.
- ///
- ///
- /// Objects that are "overridden" (specified in a descendant factory
- /// with the same name) are counted only once.
- ///
- ///
- /// The object factory.
- ///
- /// The count of objects including those defined in ancestor factories.
- ///
- public static int CountObjectsIncludingAncestors(IListableObjectFactory factory)
- {
- return ObjectNamesIncludingAncestors(factory).Length;
- }
-
- ///
- /// Return all object names in the factory, including ancestor factories.
- ///
- /// The object factory.
- /// The array of object names, or an empty array if none.
- public static string[] ObjectNamesIncludingAncestors(IListableObjectFactory factory)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectDefinitionNames());
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesIncludingAncestors(pof);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- private static string[] ToArrayOfObjectNames(Set result)
- {
- Array resultArray = Array.CreateInstance(typeof (string), result.Count);
- result.CopyTo(resultArray, 0);
- return (string[]) resultArray;
- }
-
- ///
- /// Get all object names for the given type, including those defined in ancestor
- /// factories.
- ///
- ///
- ///
- /// Will return unique names in case of overridden object definitions.
- ///
- ///
- /// Does consider objects created by s
- /// if is set to true,
- /// which means that s will get initialized.
- ///
- ///
- ///
- /// If this isn't also an
- /// ,
- /// this method will return the same as it's own
- ///
- /// method.
- ///
- ///
- /// The that objects must match.
- ///
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// The array of object names, or an empty array if none.
- ///
- public static string[] ObjectNamesForTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects));
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- ///
- /// Get all object names for the given type, including those defined in ancestor
- /// factories.
- ///
- ///
- ///
- /// Will return unique names in case of overridden object definitions.
- ///
- ///
- /// Does consider objects created by s,
- /// or rather it considers the type of objects created by
- /// (which means that
- /// s will be instantiated).
- ///
- ///
- ///
- /// If this isn't also an
- /// ,
- /// this method will return the same as it's own
- ///
- /// method.
- ///
- ///
- /// The that objects must match.
- ///
- ///
- /// The array of object names, or an empty array if none.
- ///
- public static string[] ObjectNamesForTypeIncludingAncestors(
- IListableObjectFactory factory, Type type)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectNamesForType(type));
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- private static IListableObjectFactory GetParentFactoryIfAny(IListableObjectFactory factory)
- {
- IHierarchicalObjectFactory hierFactory = factory as IHierarchicalObjectFactory;
- if (hierFactory != null)
- {
- return
- hierFactory.ParentObjectFactory as IListableObjectFactory;
- }
- return null;
- }
-
- ///
- /// Return all objects of the given type or subtypes, also picking up objects
- /// defined in ancestor object factories if the current object factory is an
- /// .
- ///
- ///
- ///
- /// The return list will only contain objects of this type.
- /// Useful convenience method when we don't care about object names.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- /// The of object instances, or an
- /// empty if none.
- ///
- public static IDictionary ObjectsOfTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- Hashtable result = new Hashtable();
- foreach (DictionaryEntry entry in
- factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects))
- {
- result.Add(entry.Key, entry.Value);
- }
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- IDictionary parentResult
- = ObjectsOfTypeIncludingAncestors(
- pof, type, includePrototypes, includeFactoryObjects);
- foreach (object instance in parentResult.Keys)
- {
- if (!result.ContainsKey(instance))
- {
- result.Add(instance, parentResult[instance]);
- }
- }
- }
- return result;
- }
-
- ///
- /// Return a single object of the given type or subtypes, also picking up objects defined
- /// in ancestor object factories if the current object factory is an
- /// .
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If more than one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- IDictionary objectsOfType
- = ObjectsOfTypeIncludingAncestors(
- factory, type, includePrototypes, includeFactoryObjects);
- return GrabTheOnlyObject(objectsOfType, type);
- }
-
- private static object GrabTheOnlyObject(IDictionary objectsOfType, Type type)
- {
- if (objectsOfType.Count == 1)
- {
- return ObjectUtils.EnumerateFirstElement(objectsOfType.Values);
- }
- else
- {
- throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count);
- }
- }
-
- ///
- /// Return a single object of the given type or subtypes, not looking in
- /// ancestor factories.
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If not exactly one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfType(IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- IDictionary objectsOfType
- = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
- return GrabTheOnlyObject(objectsOfType, type);
- }
-
- ///
- /// Return a single object of the given type or subtypes, not looking in
- /// ancestor factories.
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- /// This version of ObjectOfType automatically includes prototypes and
- /// instances.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// If the object could not be created.
- ///
- ///
- /// If not exactly one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfType(IListableObjectFactory factory, Type type)
- {
- return ObjectOfType(factory, type, true, true);
- }
-
- ///
- /// Return the object name, stripping out the factory dereference prefix if necessary.
- ///
- /// The name of the object.
- /// The object name sans any factory dereference prefix.
- public static string TransformedObjectName(string name)
- {
- AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null.");
- if (!ObjectFactoryUtils.IsFactoryDereference(name))
- {
- return name;
- }
-
- string objectName = name.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length);
- return objectName;
- }
-
- ///
- /// Given an (object) name, builds a corresponding factory object name such that
- /// the return value can be used as a lookup name for a factory object.
- ///
- ///
- /// The name to be used to build the resulting factory object name.
- ///
- ///
- /// The transformed into its factory object name
- /// equivalent.
- ///
- ///
- ///
- public static string BuildFactoryObjectName(string objectName)
- {
- return ObjectFactoryUtils.FactoryObjectPrefix + objectName;
- }
-
- ///
- /// Is the supplied a factory dereference?
- ///
- ///
- ///
- /// That is, does the supplied begin with
- /// the
- /// ?
- ///
+ /// The nesting hierarchy of an object factory is taken into account by the various methods
+ /// exposed by this class.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public sealed class ObjectFactoryUtils
+ {
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible
+ /// constructors.
+ ///
+ ///
+ private ObjectFactoryUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// Used to dereference an
+ /// and distinguish it from managed objects created by the factory.
+ ///
+ ///
+ ///
+ /// For example, if the managed object identified as foo is a
+ /// factory, getting &foo will return the factory, not the
+ /// instance returned by the factory.
+ ///
+ ///
+ public const string FactoryObjectPrefix = "&";
+
+ ///
+ /// The string used as a separator in the generation of synthetic id's
+ /// for those object definitions explicitly that aren't assigned one.
+ ///
+ ///
+ ///
+ /// If a name or parent object definition
+ /// name is not unique, "#1", "#2" etc will be appended, until such
+ /// time that the name becomes unique.
+ ///
+ ///
+ public const string GENERATED_OBJECT_NAME_SEPARATOR = "#";
+
+ ///
+ /// Count all object definitions in any hierarchy in which this
+ /// factory participates.
+ ///
+ ///
+ ///
+ /// Includes counts of ancestor object factories.
+ ///
+ ///
+ /// Objects that are "overridden" (specified in a descendant factory
+ /// with the same name) are counted only once.
+ ///
+ ///
+ /// The object factory.
+ ///
+ /// The count of objects including those defined in ancestor factories.
+ ///
+ public static int CountObjectsIncludingAncestors(IListableObjectFactory factory)
+ {
+ return ObjectNamesIncludingAncestors(factory).Length;
+ }
+
+ ///
+ /// Return all object names in the factory, including ancestor factories.
+ ///
+ /// The object factory.
+ /// The array of object names, or an empty array if none.
+ public static string[] ObjectNamesIncludingAncestors(IListableObjectFactory factory)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectDefinitionNames());
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesIncludingAncestors(pof);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ private static string[] ToArrayOfObjectNames(Set result)
+ {
+ Array resultArray = Array.CreateInstance(typeof (string), result.Count);
+ result.CopyTo(resultArray, 0);
+ return (string[]) resultArray;
+ }
+
+ ///
+ /// Get all object names for the given type, including those defined in ancestor
+ /// factories.
+ ///
+ ///
+ ///
+ /// Will return unique names in case of overridden object definitions.
+ ///
+ ///
+ /// Does consider objects created by s
+ /// if is set to true,
+ /// which means that s will get initialized.
+ ///
+ ///
+ ///
+ /// If this isn't also an
+ /// ,
+ /// this method will return the same as it's own
+ ///
+ /// method.
+ ///
+ ///
+ /// The that objects must match.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// The array of object names, or an empty array if none.
+ ///
+ public static string[] ObjectNamesForTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects));
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ ///
+ /// Get all object names for the given type, including those defined in ancestor
+ /// factories.
+ ///
+ ///
+ ///
+ /// Will return unique names in case of overridden object definitions.
+ ///
+ ///
+ /// Does consider objects created by s,
+ /// or rather it considers the type of objects created by
+ /// (which means that
+ /// s will be instantiated).
+ ///
+ ///
+ ///
+ /// If this isn't also an
+ /// ,
+ /// this method will return the same as it's own
+ ///
+ /// method.
+ ///
+ ///
+ /// The that objects must match.
+ ///
+ ///
+ /// The array of object names, or an empty array if none.
+ ///
+ public static string[] ObjectNamesForTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectNamesForType(type));
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ private static IListableObjectFactory GetParentFactoryIfAny(IListableObjectFactory factory)
+ {
+ IHierarchicalObjectFactory hierFactory = factory as IHierarchicalObjectFactory;
+ if (hierFactory != null)
+ {
+ return
+ hierFactory.ParentObjectFactory as IListableObjectFactory;
+ }
+ return null;
+ }
+
+ ///
+ /// Return all objects of the given type or subtypes, also picking up objects
+ /// defined in ancestor object factories if the current object factory is an
+ /// .
+ ///
+ ///
+ ///
+ /// The return list will only contain objects of this type.
+ /// Useful convenience method when we don't care about object names.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ /// The of object instances, or an
+ /// empty if none.
+ ///
+ public static IDictionary ObjectsOfTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ Hashtable result = new Hashtable();
+ foreach (DictionaryEntry entry in
+ factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects))
+ {
+ result.Add(entry.Key, entry.Value);
+ }
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ IDictionary parentResult
+ = ObjectsOfTypeIncludingAncestors(
+ pof, type, includePrototypes, includeFactoryObjects);
+ foreach (object instance in parentResult.Keys)
+ {
+ if (!result.ContainsKey(instance))
+ {
+ result.Add(instance, parentResult[instance]);
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, also picking up objects defined
+ /// in ancestor object factories if the current object factory is an
+ /// .
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If more than one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ IDictionary objectsOfType
+ = ObjectsOfTypeIncludingAncestors(
+ factory, type, includePrototypes, includeFactoryObjects);
+ return GrabTheOnlyObject(objectsOfType, type);
+ }
+
+ private static object GrabTheOnlyObject(IDictionary objectsOfType, Type type)
+ {
+ if (objectsOfType.Count == 1)
+ {
+ return ObjectUtils.EnumerateFirstElement(objectsOfType.Values);
+ }
+ else
+ {
+ throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count);
+ }
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, not looking in
+ /// ancestor factories.
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If not exactly one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfType(IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ IDictionary objectsOfType
+ = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
+ return GrabTheOnlyObject(objectsOfType, type);
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, not looking in
+ /// ancestor factories.
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ /// This version of ObjectOfType automatically includes prototypes and
+ /// instances.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If not exactly one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfType(IListableObjectFactory factory, Type type)
+ {
+ return ObjectOfType(factory, type, true, true);
+ }
+
+ ///
+ /// Return the object name, stripping out the factory dereference prefix if necessary.
+ ///
+ /// The name of the object.
+ /// The object name sans any factory dereference prefix.
+ public static string TransformedObjectName(string name)
+ {
+ AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null.");
+ if (!ObjectFactoryUtils.IsFactoryDereference(name))
+ {
+ return name;
+ }
+
+ string objectName = name.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length);
+ return objectName;
+ }
+
+ ///
+ /// Given an (object) name, builds a corresponding factory object name such that
+ /// the return value can be used as a lookup name for a factory object.
+ ///
+ ///
+ /// The name to be used to build the resulting factory object name.
+ ///
+ ///
+ /// The transformed into its factory object name
+ /// equivalent.
+ ///
+ ///
+ ///
+ public static string BuildFactoryObjectName(string objectName)
+ {
+ return ObjectFactoryUtils.FactoryObjectPrefix + objectName;
+ }
+
+ ///
+ /// Is the supplied a factory dereference?
+ ///
+ ///
+ ///
+ /// That is, does the supplied begin with
+ /// the
+ /// ?
+ ///
- /// Provides object creation, initialization and wiring, supporting
- /// autowiring and constructor resolution. Handles runtime object
- /// references, managed collections, and object destruction.
- ///
- ///
- /// The main template method to be implemented by subclasses is
- /// ,
- /// used for autowiring by type. Note that this class does not implement object
- /// definition registry capabilities
- /// (
- /// does).
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- [Serializable]
- public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory
- {
- #region Constants
-
- ///
- /// The used during the invocation and
- /// searching for of methods.
- ///
- protected const BindingFlags MethodResolutionFlags =
- BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase;
-
- #endregion
-
- ///
- /// The instance for this class.
- ///
- private readonly ILog log = LogManager.GetLogger(typeof(AbstractAutowireCapableObjectFactory));
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- protected AbstractAutowireCapableObjectFactory(bool caseSensitive)
- : this(caseSensitive, null)
- { }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- /// The parent object factory, or if none.
- protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
- : base(caseSensitive, parentFactory)
- {
- this.IgnoreDependencyInterface(typeof(IObjectFactoryAware));
- this.IgnoreDependencyInterface(typeof(IObjectNameAware));
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The
- /// implementation to be used to instantiate managed objects.
- ///
- protected IInstantiationStrategy InstantiationStrategy
- {
- get { return instantiationStrategy; }
- set { instantiationStrategy = value; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Predict the eventual object type (of the processed object instance) for the
- /// specified object.
- ///
- /// Name of the object.
- /// The merged object definition to determine the type for.
- ///
- /// The type of the object, or null if not predictable
- ///
- protected override Type PredictObjectType(string objectName, RootObjectDefinition mod)
- {
- Type objectType;
- if (StringUtils.HasText(mod.FactoryMethodName))
- {
- objectType = GetTypeForFactoryMethod(objectName, mod);
- }
- else
- {
- objectType = ResolveObjectType(mod, objectName);
- }
- return objectType;
- }
-
- ///
- /// Determines the of the object defined
- /// by the supplied object .
- ///
- ///
- /// The name associated with the supplied object .
- ///
- ///
- /// The
- /// that the is to be determined for.
- ///
- ///
- /// The of the object defined by the supplied
- /// object ; or if the
- /// cannot be determined.
- ///
- protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
- {
- if (StringUtils.HasText(definition.FactoryObjectName) && definition.IsSingleton && !definition.IsLazyInit)
- {
- return GetObject(objectName).GetType();
- }
-
- Type factoryType = null;
- bool isStatic = true;
-
- if (StringUtils.HasText(definition.FactoryObjectName))
- {
- // check declared factory method return type on factory type...
- factoryType = GetType(definition.FactoryObjectName);
- isStatic = false;
- }
- else
- {
- factoryType = ResolveObjectType(definition, objectName);
- }
- if (factoryType == null)
- {
- return null;
- }
-
- // If all factory methods have the same return type, return that type.
- // Can't clearly figure out exact method due to type converting / autowiring!
- int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count;
- MethodInfo[] candidates = factoryType.GetMethods();
- ISet returnTypes = new HybridSet();
- foreach (MethodInfo factoryMethod in candidates)
- {
-#if NET_2_0
- GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
- if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName)
- && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs
- && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length)
- {
- if (genericArgsInfo.ContainsGenericArguments)
- {
- string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
- Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
- for (int j = 0; j < unresolvedGenericArgs.Length; j++)
- {
- genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
- }
- returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType);
- }
- else
- {
- returnTypes.Add(factoryMethod.ReturnType);
- }
- }
-#else
- if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(definition.FactoryMethodName)
- && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs)
- {
- returnTypes.Add(factoryMethod.ReturnType);
- }
-#endif
- }
- if (returnTypes.Count == 1)
- {
- // clear return type found: all factory methods return same type...
- return (Type)ObjectUtils.EnumerateFirstElement(returnTypes);
- }
- else
- {
- // ambiguous return types found: return null to indicate "not determinable"...
- return null;
- }
- }
-
- ///
- /// Apply the property values of the object definition with the supplied
- /// to the supplied .
- ///
- ///
- /// The existing object that the property values for the named object will
- /// be applied to.
- ///
- ///
- /// The name of the object definition associated with the property values that are
- /// to be applied.
- ///
- public override void ApplyObjectPropertyValues(object instance, string name)
- {
- RootObjectDefinition definition = GetMergedObjectDefinition(name, true);
- if (definition != null)
- {
- log.Debug(string.Format("configuring object '{0}' using definition '{1}'", instance, name));
- ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues);
- }
- }
-
- ///
- /// Apply any
- /// s.
- ///
- ///
- ///
- /// The returned instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The of the object that is to be
- /// instantiated.
- ///
- ///
- /// The name of the object that is to be instantiated.
- ///
- ///
- /// An instance to use in place of the original instance.
- ///
- ///
- /// In case of errors.
- ///
- protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("Invoking IInstantiationAwareObjectPostProcessors before " + "the instantiation of '{0}'.", objectName));
- }
-
- #endregion
-
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- object theObject = inProc.PostProcessBeforeInstantiation(objectType, objectName);
- if (theObject != null)
- {
- return theObject;
- }
- }
- }
- return null;
- }
-
- ///
- /// Apply the given property values, resolving any runtime references
- /// to other objects in this object factory.
- ///
- ///
- /// The object name passed for better exception information.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- ///
- /// The new property values.
- ///
- ///
- ///
- /// Must use deep copy, so that we don't permanently modify this property.
- ///
- ///
- protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
- {
- if (properties == null || properties.PropertyValues.Length == 0)
- {
- return;
- }
- MutablePropertyValues deepCopy = new MutablePropertyValues(properties);
- PropertyValue[] copiedProperties = deepCopy.PropertyValues;
- for (int i = 0; i < copiedProperties.Length; ++i)
- {
- PropertyValue copiedProperty = copiedProperties[i];
- object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value);
- PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression);
- // update mutable copy...
- deepCopy.SetPropertyValueAt(propertyValue, i);
- }
- // set the (possibly resolved) deep copy properties...
- try
- {
- wrapper.SetPropertyValues(deepCopy);
- }
- catch (ObjectsException ex)
- {
- // improve the message by showing the context...
- throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex);
- }
- }
-
- ///
- /// Return an array of object-type property names that are unsatisfied.
- ///
- ///
- ///
- /// These are probably unsatisfied references to other objects in the
- /// factory. Does not include simple properties like primitives or
- /// s.
- ///
- ///
- ///
- /// An array of object-type property names that are unsatisfied.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected string[] UnsatisfiedObjectProperties(RootObjectDefinition definition, IObjectWrapper wrapper)
- {
- ArrayList result = new ArrayList();
- ISet ignoredTypes = IgnoredDependencyTypes;
- PropertyInfo[] properties = wrapper.GetPropertyInfos();
- foreach (PropertyInfo property in properties)
- {
- string name = property.Name;
- if (property.CanWrite && !ignoredTypes.Contains(property.PropertyType) && !result.Contains(name)
- && !ObjectUtils.IsSimpleProperty(property.PropertyType))
- {
- result.Add(name);
- }
- }
- return (string[])result.ToArray(typeof(string));
- }
-
- ///
- /// Destroy all cached singletons in this factory.
- ///
- ///
- ///
- /// To be called on shutdown of a factory.
- ///
- ///
- public override void Dispose()
- {
- base.Dispose();
- foreach (object o in _disposableInnerObjects)
- {
- DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o);
- }
- _disposableInnerObjects.Clear();
- }
-
- ///
- /// Populate the object instance in the given
- /// with the property values from the
- /// object definition.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper)
- {
- // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
- // state of the bean before properties are set. This can be used, for example,
- // to support styles of field injection.
- bool continueWithPropertyPopulation = true;
-
- if (HasInstantiationAwareBeanPostProcessors)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name))
- {
- continueWithPropertyPopulation = false;
- break;
- }
- }
- }
- }
- if (!continueWithPropertyPopulation)
- {
- return;
- }
-
- IPropertyValues properties = definition.PropertyValues;
-
- if (wrapper == null)
- {
- if (properties.PropertyValues.Length > 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription,
- name, "Cannot apply property values to null instance.");
- }
- else
- {
- // skip property population phase for null instance
- return;
- }
- }
-
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType)
- {
- MutablePropertyValues mpvs = new MutablePropertyValues(properties);
- // add property values based on autowire by name if it's applied
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByName)
- {
- AutowireByName(name, definition, wrapper, mpvs);
- }
- // add property values based on autowire by type if it's applied
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByType)
- {
- AutowireByType(name, definition, wrapper, mpvs);
- }
- properties = mpvs;
- }
- //DependencyCheck(name, definition, wrapper, properties);
-
-
- bool hasInstAwareOpps = HasInstantiationAwareBeanPostProcessors;
- bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None);
-
-
- if (hasInstAwareOpps || needsDepCheck)
- {
- PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
- if (hasInstAwareOpps)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor =
- processor as IInstantiationAwareObjectPostProcessor;
- if (instantiationAwareObjectPostProcessor != null)
- {
- properties =
- instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance,
- name);
- if (properties == null)
- {
- return;
- }
- }
- }
- }
-
- if (needsDepCheck)
- {
- CheckDependencies(name, definition, filteredPropInfo, properties);
- }
-
- }
-
- ApplyPropertyValues(name, definition, wrapper, properties);
- }
-
- ///
- /// Wires up any exposed events in the object instance in the given
- /// with any event handler
- /// values from the .
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper)
- {
- foreach (string eventName in definition.EventHandlerValues.Events)
- {
- foreach (IEventHandlerValue handlerValue
- in definition.EventHandlerValues[eventName])
- {
- object handler = null;
- if (handlerValue.Source is RuntimeObjectReference)
- {
- RuntimeObjectReference roref = (RuntimeObjectReference)handlerValue.Source;
- handler = ResolveReference(definition, name, eventName, roref);
- }
- else if (handlerValue.Source is Type)
- {
- // a static Type event is being wired up; simply pass on the Type
- handler = handlerValue.Source;
- }
- else if (handlerValue.Source is string)
- {
- // a static Type event is being wired up; we need to resolve the Type
- handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string);
- }
- else
- {
- throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources.");
- }
- handlerValue.Wire(handler, wrapper.WrappedInstance);
- }
- }
- }
-
- ///
- /// Fills in any missing property values with references to
- /// other objects in this factory if autowire is set to
- /// .
- ///
- ///
- /// The object name to be autowired by .
- ///
- ///
- /// The definition of the named object to update through autowiring.
- ///
- ///
- /// The wrapping the target object (and
- /// from which we can rip out information concerning the object).
- ///
- ///
- /// The property values to register wired objects with.
- ///
- protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
- {
- string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
- foreach (string propertyName in propertyNames)
- {
- // look for a matching type
- if (ContainsObject(propertyName))
- {
- object o = GetObject(propertyName);
- properties.Add(propertyName, o);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name,
- propertyName));
- }
-
- #endregion
- }
- else
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name));
- }
-
- #endregion
- }
- }
- }
-
- ///
- /// Defines "autowire by type" (object properties by type) behavior.
- ///
- ///
- ///
- /// This is like PicoContainer default, in which there must be exactly one object
- /// of the property type in the object factory. This makes object factories simple
- /// to configure for small namespaces, but doesn't work as well as standard Spring
- /// behavior for bigger applications.
- ///
- ///
- ///
- /// The object name to be autowired by .
- ///
- ///
- /// The definition of the named object to update through autowiring.
- ///
- ///
- /// The wrapping the target object (and
- /// from which we can rip out information concerning the object).
- ///
- ///
- /// The property values to register wired objects with.
- ///
- protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
- {
- string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
- foreach (string propertyName in propertyNames)
- {
- // look for a matching type
- Type requiredType = wrapper.GetPropertyType(propertyName);
- IDictionary matchingObjects = FindMatchingObjects(requiredType);
- if (matchingObjects != null && matchingObjects.Count == 1)
- {
- properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values));
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name,
- propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys)));
- }
-
- #endregion
- }
- else if (matchingObjects != null && matchingObjects.Count > 1)
- {
- throw new UnsatisfiedDependencyException(string.Empty, name, propertyName,
- string.Format(CultureInfo.InvariantCulture,
- "There are {0} objects of Type [{1}] for autowire by "
- + "type, when there should have been just 1 to be able to "
- + "autowire property '{2}' of object '{3}'.", matchingObjects.Count,
- requiredType, propertyName, name));
- }
- else
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.",
- propertyName, name));
- }
-
- #endregion
- }
- }
- }
-
- ///
- /// Ignore the given dependency type for autowiring
- ///
- ///
- /// This will typically be used by application contexts to register
- /// dependencies that are resolved in other ways, like IOjbectFactory through
- /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware.
- /// By default, IObjectFactoryAware and IObjectName interfaces are ignored.
- /// For further types to ignore, invoke this method for each type.
- ///
- /// .
- public void IgnoreDependencyInterface(Type type)
- {
- ignoredDependencyInterfaces.Add(type);
- }
-
- ///
- /// Create an object instance for the given object definition.
- ///
- /// The name of the object.
- ///
- /// The object definition for the object that is to be instantiated.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. It is invalid to use a non- arguments value
- /// in any other case.
- ///
- ///
- /// A new instance of the object.
- ///
- ///
- /// In case of errors.
- ///
- ///
- ///
- /// Delegates to the
- ///
- /// method version with the allowEagerCaching parameter set to true.
- ///
- ///
- /// The object definition will already have been merged with the parent
- /// definition in case of a child definition.
- ///
- ///
- /// All the other methods in this class invoke this method, although objects
- /// may be cached after being instantiated by this method. All object
- /// instantiation within this class is performed by this method.
- ///
- ///
- protected override object CreateObject(string name, RootObjectDefinition definition, object[] arguments)
- {
- return CreateObject(name, definition, arguments, true);
- }
-
- ///
- /// Create an object instance for the given object definition.
- ///
- /// The name of the object.
- ///
- /// The object definition for the object that is to be instantiated.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. It is invalid to use a non- arguments value
- /// in any other case.
- ///
- ///
- /// Whether eager caching of singletons is allowed... typically true for
- /// singlton objects, but never true for inner object definitions.
- ///
- ///
- /// A new instance of the object.
- ///
- ///
- /// In case of errors.
- ///
- ///
- ///
- /// The object definition will already have been merged with the parent
- /// definition in case of a child definition.
- ///
- ///
- /// All the other methods in this class invoke this method, although objects
- /// may be cached after being instantiated by this method. All object
- /// instantiation within this class is performed by this method.
- ///
- ///
- protected virtual object CreateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching)
- {
- // guarantee the initialization of objects that the current one depends on..
- if (definition.DependsOn != null && definition.DependsOn.Length > 0)
- {
- foreach (string dependant in definition.DependsOn)
- {
- GetObject(dependant);
- }
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Creating instance of Object '{0}' with merged definition [{1}].", name, definition));
- }
-
- #endregion
-
- // Make sure object type is actually resolved at this point.
- ResolveObjectType(definition, name);
-
- try
- {
- definition.PrepareMethodOverrides();
- }
- catch (ObjectDefinitionValidationException ex)
- {
- throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
- "Validation of method overrides failed. " + ex.Message, ex);
- }
-
- // return IObjectDefinition instance itself for an abstract object-definition
- if (definition.IsTemplate)
- {
- return definition;
- }
-
-
-
- object instance = null;
-
-
- IObjectWrapper instanceWrapper = null;
- bool eagerlyCached = false;
- try
- {
- // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance....
- if (definition.HasObjectType)
- {
- instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name);
- if (instance != null)
- {
- return instance;
- }
- }
-
-
- instanceWrapper = CreateObjectInstance(name, definition, arguments);
- instance = instanceWrapper.WrappedInstance;
-
- // eagerly cache singletons to be able to resolve circular references
- // even when triggered by lifecycle interfaces like IObjectFactoryAware.
- if (allowEagerCaching && definition.IsSingleton)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("Eagerly caching object '" + name + "' to allow for resolving potential circular references");
- }
- AddEagerlyCachedSingleton(name, definition, instance);
- eagerlyCached = true;
- }
-
- instance = ConfigureObject(name, definition, instanceWrapper);
- }
- catch (ObjectCreationException)
- {
- if (eagerlyCached)
- {
- RemoveEagerlyCachedSingleton(name, definition);
- }
- throw;
- }
- catch (Exception ex)
- {
- if (eagerlyCached)
- {
- RemoveEagerlyCachedSingleton(name, definition);
- }
- throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex);
- }
- return instance;
- }
-
- ///
- /// Add the created, but yet unpopulated singleton to the singleton cache
- /// to be able to resolve circular references
- ///
- /// the name of the object to add to the cache.
- /// the definition used to create and populated the object.
- /// the raw object instance.
- ///
- /// Derived classes may override this method to select the right cache based on the object definition.
- ///
- protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance)
- {
- base.AddSingleton(objectName, rawSingletonInstance);
- }
-
- ///
- /// Remove the specified singleton from the singleton cache that has
- /// been added before by a call to
- ///
- /// the name of the object to remove from the cache.
- /// the definition used to create and populated the object.
- ///
- /// Derived classes may override this method to select the right cache based on the object definition.
- ///
- protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition)
- {
- base.RemoveSingleton(objectName);
- }
-
- ///
- /// Creates an instance from the passed in
- /// using constructor
- ///
- /// The name of the object to create - used for error messages.
- /// The describing the object to be created.
- /// optional arguments to pass to the constructor
- /// An wrapping the already instantiated object
- protected IObjectWrapper CreateObjectInstance(string name, RootObjectDefinition definition, object[] arguments)
- {
- IObjectWrapper instanceWrapper;
- if (StringUtils.HasText(definition.FactoryMethodName))
- {
- instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments);
- }
- //Handle case when arguments are passed in explicitly.
- else if (arguments != null && arguments.Length > 0)
- {
- instanceWrapper = AutowireConstructor(name, definition, arguments);
- }
- else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor ||
- definition.HasConstructorArgumentValues)
- {
- instanceWrapper = AutowireConstructor(name, definition);
- }
- else
- {
- instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this));
- InitObjectWrapper(instanceWrapper);
- }
- return instanceWrapper;
- }
-
- ///
- /// Instantiate an object instance using a named factory method.
- ///
- ///
- ///
- /// The method may be static, if the
- /// parameter specifies a class, rather than a
- /// instance, or an
- /// instance variable on a factory object itself configured using Dependency
- /// Injection.
- ///
- ///
- /// Implementation requires iterating over the static or instance methods
- /// with the name specified in the supplied
- /// (the method may be overloaded) and trying to match with the parameters.
- /// We don't have the types attached to constructor args, so trial and error
- /// is the only way to go here.
- ///
- ///
- ///
- /// The name associated with the supplied .
- ///
- ///
- /// The definition describing the instance that is to be instantiated.
- ///
- ///
- /// Any arguments to the factory method that is to be invoked.
- ///
- ///
- /// The result of the factory method invocation (the instance).
- ///
- protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
- {
- ConstructorArgumentValues cargs = definition.ConstructorArgumentValues;
- ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
- int expectedArgCount = 0;
-
- // we don't have arguments passed in programmatically, so we need to resolve the
- // arguments specified in the constructor arguments held in the object definition...
- if (arguments == null || arguments.Length == 0)
- {
- expectedArgCount = cargs.ArgumentCount;
- ResolveConstructorArguments(name, definition, resolvedValues);
- }
- else
- {
- // if we have constructor args, don't need to resolve them...
- expectedArgCount = arguments.Length;
- }
- ObjectWrapper wrapper = new ObjectWrapper();
- InitObjectWrapper(wrapper);
- bool isStatic = true;
- Type factoryClass = null;
- if (StringUtils.HasText(definition.FactoryObjectName))
- {
- // it's an instance method on the factory object's class...
- factoryClass = GetObject(definition.FactoryObjectName).GetType();
- isStatic = false;
- }
- else
- {
- // it's a static factory method on the object class...
- factoryClass = definition.ObjectType;
- }
-
-#if NET_2_0
- GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
-
- MethodInfo[] factoryMethods = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass);
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- // try all matching methods to see if they match the constructor arguments...
- for (int i = 0; i < factoryMethods.Length; i++)
- {
- unsatisfiedDependencyExceptionData = null;
- MethodInfo factoryMethod = factoryMethods[i];
-
- if (genericArgsInfo.ContainsGenericArguments)
- {
- string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
- if (factoryMethod.GetGenericArguments().Length != unresolvedGenericArgs.Length)
- continue;
-
- Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
- for (int j = 0; j < unresolvedGenericArgs.Length; j++)
- {
- genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
- }
- factoryMethod = factoryMethod.MakeGenericMethod(genericArgs);
- }
-#else
- MethodInfo[] factoryMethods = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass);
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- // try all matching methods to see if they match the constructor arguments...
- foreach(MethodInfo factoryMethod in factoryMethods)
- {
-#endif
- if (arguments == null || arguments.Length == 0)
- {
- // try to create the required arguments...
- arguments = CreateArgumentArray(name, definition, resolvedValues, factoryMethod, out unsatisfiedDependencyExceptionData);
- if (arguments == null)
- {
- // if we failed to match this method, keep
- // trying new overloaded factory methods...
- continue;
- }
- }
- // if we get here, we found a factory method...
-
- if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethod }, arguments) == null)
- {
- continue;
- }
-
-
- object objectInstance = InstantiationStrategy.Instantiate(definition, name, this, factoryMethod, arguments);
- wrapper.WrappedInstance = objectInstance;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethod));
- }
-
- #endregion
-
- return wrapper;
- }
-
-
-
- // if we get here, we didn't match any method...
- throw new ObjectDefinitionStoreException(
- string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName,
- factoryClass));
- }
-
- ///
- /// Returns an array of all of those
- /// methods exposed on the
- /// that match the supplied criteria.
- ///
- ///
- /// Methods that have this name (can be in the form of a regular expression).
- ///
- ///
- /// Methods that have exactly this many arguments.
- ///
- ///
- /// Methods that are static / instance.
- ///
- ///
- /// The on which the methods (if any) are to be found.
- ///
- ///
- /// An array of all of those
- /// methods exposed on the
- /// that match the supplied criteria.
- ///
- private static MethodInfo[] FindMethods(string methodName, int expectedArgumentCount, bool isStatic, Type searchType)
- {
- ComposedCriteria methodCriteria = new ComposedCriteria();
- methodCriteria.Add(new MethodNameMatchCriteria(methodName));
- methodCriteria.Add(new MethodParametersCountCriteria(expectedArgumentCount));
- BindingFlags methodFlags = BindingFlags.Public | BindingFlags.IgnoreCase | (isStatic ? BindingFlags.Static : BindingFlags.Instance);
- MemberInfo[] methods =
- searchType.FindMembers(MemberTypes.Method, methodFlags, new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- methodCriteria);
- return (MethodInfo[])ArrayList.Adapter(methods).ToArray(typeof(MethodInfo));
- }
-
- ///
- /// Create an array of arguments to invoke a constructor or static factory method,
- /// given the resolved constructor arguments values.
- ///
- /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
- /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using
- /// exceptions for flow control as in the original implementation.
- private object[] CreateArgumentArray(string name, RootObjectDefinition definition,
- ConstructorArgumentValues resolvedValues, MethodBase methodOrCtor, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
- {
- string methodType = (methodOrCtor is ConstructorInfo) ? "constructor" : "factory method";
- unsatisfiedDependencyExceptionData = null;
- ParameterInfo[] argTypes = methodOrCtor.GetParameters();
- object[] args = new object[argTypes.Length];
- ISet alreadyUsedValues = new HybridSet();
- for (int j = 0; j < argTypes.Length; ++j)
- {
- Type parameterType = argTypes[j].ParameterType;
- string parameterName = argTypes[j].Name;
- ConstructorArgumentValues.ValueHolder valueHolder = null;
- if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
- {
- valueHolder = resolvedValues.GetArgumentValue(parameterName, parameterType, alreadyUsedValues);
- }
- else
- {
- valueHolder = resolvedValues.GetArgumentValue(j, parameterType, alreadyUsedValues);
- }
- if (valueHolder != null)
- {
- try
- {
- args[j] = TypeConversionUtils.ConvertValueIfNecessary(parameterType, valueHolder.Value, null);
- alreadyUsedValues.Add(valueHolder);
- }
- catch (TypeMismatchException ex)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
- methodType, valueHolder.Value,
- parameterType, ex.Message);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
-
- return null;
- }
- }
- else
- {
- if (definition.ResolvedAutowireMode != AutoWiringMode.Constructor)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "Ambiguous {0} argument types - " +
- "Did you specify the correct object references as {0} arguments?",
- methodType);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
- return null;
- }
- IDictionary matchingObjects = FindMatchingObjects(parameterType);
- if (matchingObjects == null || matchingObjects.Count != 1)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "There are '{0}' objects of type [{1}] for autowiring "
- +
- "{2}. There should have been exactly 1 to be able to "
- +
- "autowire the '{3}' argument on the {2} of object '{4}'.",
- (matchingObjects == null
- ? 0
- : matchingObjects.Count),
- parameterType, methodType,
- parameterName, name);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
- return null;
- }
- DictionaryEntry entry = (DictionaryEntry)ObjectUtils.EnumerateFirstElement(matchingObjects);
- args[j] = entry.Value;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Autowiring '{0}' argument by type from object name '{1}' via {2} to "
- + "object named '{3}'.", parameterName, name, methodType, entry.Key));
- }
-
- #endregion
- }
- }
-
- return args;
- }
-
- ///
- /// Explicitly construct the object using the supplied constructor arguments.
- /// Constructor arguments are matched by type.
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- /// Array of constructor argument values.
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, object[] args)
- {
- ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
- for (int i = 0; i < args.Length; i++)
- {
- //This is assigning ctor arguments by type.
- resolvedValues.AddGenericArgumentValue(args[i]);
- }
- return AutowireConstructor(name, definition, resolvedValues);
- }
-
- ///
- /// "autowire constructor" (with constructor arguments by type) behaviour.
- ///
- /// Passes an empty collection of constructor argument values
- /// to overloaded method.
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition)
- {
- return AutowireConstructor(name, definition, new ConstructorArgumentValues());
- }
-
- ///
- /// "autowire constructor" (with constructor arguments by type) behaviour.
- ///
- ///
- ///
- /// Also applied if explicit constructor argument values are specified,
- /// matching all remaining arguments with objects from the object factory.
- ///
- ///
- /// This corresponds to constructor injection: in this mode, a Spring.NET
- /// object factory is able to host components that expect constructor-based
- /// dependency resolution.
- ///
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- ///
- /// The collection on constructor argument values.
- ///
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorArgumentValues argumentValues)
- {
- int minNrOfArgs = ResolveConstructorArguments(name, definition, argumentValues);
- ConstructorInfo[] constructors = AutowireUtils.GetConstructors(definition, minNrOfArgs);
- if (constructors == null || constructors.Length == 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- string.Format(CultureInfo.InvariantCulture,
- "'{0}' constructor arguments specified but no matching constructor found "
- + "in object '{1}' (hint: specify argument indexes, names, or "
- + "types to avoid ambiguities).", minNrOfArgs, name));
- }
- ObjectWrapper wrapper = new ObjectWrapper();
- InitObjectWrapper(wrapper);
- ConstructorInfo constructorToUse = null;
- object[] argsToUse = null;
- int weighting = Int32.MaxValue;
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- for (int i = 0; i < constructors.Length; ++i)
- {
- unsatisfiedDependencyExceptionData = null;
- ConstructorInfo constructor = constructors[i];
- if (constructorToUse != null &&
- constructorToUse.GetParameters().Length > constructor.GetParameters().Length)
- {
- // already found greedy constructor that can be satisfied, so
- // don't look any further, there are only less greedy constructors left...
- break;
- }
-
- object[] args = CreateArgumentArray(name, definition, argumentValues, constructor, out unsatisfiedDependencyExceptionData);
- if (args == null)
- {
- if (i == constructors.Length - 1 && constructorToUse == null)
- {
- throw new UnsatisfiedDependencyException(definition.ResourceDescription,
- name,
- unsatisfiedDependencyExceptionData.ParameterIndex,
- unsatisfiedDependencyExceptionData.ParameterType,
- unsatisfiedDependencyExceptionData.ErrorMessage);
- }
- // try next constructor...
- continue;
- }
-
- int typeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(constructor.GetParameters(), args);
- if (typeDiffWeight < weighting)
- {
- constructorToUse = constructor;
- argsToUse = args;
- weighting = typeDiffWeight;
- }
- }
-
- if (constructorToUse == null)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name, "Could not resolve matching constructor.");
- }
- wrapper.WrappedInstance = InstantiationStrategy.Instantiate(definition, name, this, constructorToUse, argsToUse);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", name, constructorToUse));
- }
-
- #endregion
-
- return wrapper;
- }
-
- ///
- /// Resolves the
- /// of the supplied .
- ///
- ///
- ///
- /// 'Resolve' can be taken to mean that all of the s
- /// constructor arguments is resolved into a concrete object that can be plugged
- /// into one of the s constructors. Runtime object
- /// references to other objects in this (or a parent) factory are resolved,
- /// type conversion is performed, etc.
- ///
- ///
- /// These resolved values are plugged into the supplied
- /// object, because we wouldn't want to touch
- /// the s constructor arguments in case it (or any of
- /// its constructor arguments) is a prototype object definition.
- ///
- ///
- /// This method is also used for handling invocations of static factory methods.
- ///
- ///
- ///
- /// The name of the object that is being resolved by this factory.
- ///
- ///
- /// The definition associated with the above .
- ///
- ///
- /// Where the resolved constructor arguments will be placed.
- ///
- ///
- /// The minimum number of arguments that any constructor for the supplied
- /// must have.
- ///
- private int ResolveConstructorArguments(string name, RootObjectDefinition definition, ConstructorArgumentValues resolvedValues)
- {
- int minNrOfArgs = 0;
- if (definition.ConstructorArgumentValues != null)
- {
- minNrOfArgs = definition.ConstructorArgumentValues.ArgumentCount;
- foreach (DictionaryEntry de in definition.ConstructorArgumentValues.IndexedArgumentValues)
- {
- int index = (int)de.Key;
- if (index < 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name, "Invalid constructor argument index: " + index);
- }
- if (index > minNrOfArgs)
- {
- minNrOfArgs = index + 1;
- }
- string argName = "constructor argument with index " + index;
- ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)de.Value;
- object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
- resolvedValues.AddIndexedArgumentValue(index, resolvedValue,
- StringUtils.HasText(valueHolder.Type)
- ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
- : null);
- }
- foreach (ConstructorArgumentValues.ValueHolder valueHolder in definition.ConstructorArgumentValues.GenericArgumentValues)
- {
- string argName = "constructor argument";
- object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
- resolvedValues.AddGenericArgumentValue(resolvedValue,
- StringUtils.HasText(valueHolder.Type)
- ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
- : null);
- }
- foreach (DictionaryEntry namedArgumentEntry in definition.ConstructorArgumentValues.NamedArgumentValues)
- {
- string argumentName = (string)namedArgumentEntry.Key;
- string syntheticArgumentName = "constructor argument with name " + argumentName;
- ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)namedArgumentEntry.Value;
- object resolvedValue = ResolveValueIfNecessary(name, definition, syntheticArgumentName, valueHolder.Value);
- resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue);
- }
- }
- return minNrOfArgs;
- }
-
- ///
- /// Perform a dependency check that all properties exposed have been set, if desired.
- ///
- ///
- ///
- /// Dependency checks can be objects (collaborating objects), simple (primitives
- /// and ), or all (both).
- ///
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- ///
- /// The property values to be checked.
- ///
- ///
- /// If all of the checked dependencies were not satisfied.
- ///
- protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
- {
- DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
- if (dependencyCheck == DependencyCheckingMode.None)
- {
- return;
- }
-
- PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
- if (HasInstantiationAwareBeanPostProcessors)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- properties =
- inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name);
- if (properties == null)
- {
- return;
- }
- }
- }
- }
-
-
- CheckDependencies(name, definition, filteredPropInfo, properties);
- }
-
- private static void CheckDependencies(string name, IConfigurableObjectDefinition definition, PropertyInfo[] filteredPropInfo, IPropertyValues properties)
- {
- DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
- foreach (PropertyInfo property in filteredPropInfo)
- {
- if (property.CanWrite && properties.GetPropertyValue(property.Name) == null)
- {
- bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType);
- bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple)
- || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects);
- if (unsatisfied)
- {
- throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, property.Name,
- "Set this property value or disable dependency checking for this object.");
- }
- }
- }
- }
-
- ///
- /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding
- /// ignored dependency types.
- ///
- /// The object wrapper the object was created with.
- /// The filtered PropertyInfos
- private PropertyInfo[] FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper)
- {
- lock (filteredPropertyDescriptorsCache)
- {
- PropertyInfo[] filtered = (PropertyInfo[])filteredPropertyDescriptorsCache[wrapper.WrappedType];
- if (filtered == null)
- {
-
- ArrayList list = new ArrayList(wrapper.GetPropertyInfos());
- for (int i = list.Count - 1; i >= 0; i--)
- {
- PropertyInfo pi = (PropertyInfo)list[i];
- if (IsExcludedFromDependencyCheck(pi))
- {
- list.RemoveAt(i);
- }
- }
-
- filtered = (PropertyInfo[])list.ToArray(typeof(PropertyInfo));
- filteredPropertyDescriptorsCache.Add(wrapper.WrappedType, filtered);
- }
- return filtered;
- }
-
- }
-
- private bool IsExcludedFromDependencyCheck(PropertyInfo pi)
- {
- bool b1 = !pi.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi);
- bool b2 = IgnoredDependencyTypes.Contains(pi.PropertyType);
- bool b3 = AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
- return b1 || b2 || b3;
- /*
- return AutowireUtils.IsExcludedFromDependencyCheck(pi) ||
- IgnoredDependencyTypes.Contains(pi.PropertyType) ||
- AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
- */
- }
-
- ///
- /// Give an object a chance to react now all its properties are set,
- /// and a chance to know about its owning object factory (this object).
- ///
- ///
- ///
- /// This means checking whether the object implements
- /// and / or
- /// , and invoking the
- /// necessary callback(s) if it does.
- ///
- ///
- /// Custom init methods are resolved in a case-insensitive manner.
- ///
- ///
- ///
- /// The new object instance we may need to initialise.
- ///
- ///
- /// The name the object has in the factory. Used for logging output.
- ///
- ///
- /// The definition of the target object instance.
- ///
- protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition)
- {
- if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name));
- }
-
- #endregion
-
- ((IInitializingObject)target).AfterPropertiesSet();
- }
- if (StringUtils.HasText(definition.InitMethodName))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.",
- definition.InitMethodName, name));
- }
-
- #endregion
-
- try
- {
- MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null);
- if (targetMethod == null)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Could not find the named initialization method '" + definition.InitMethodName + "'.");
- }
- targetMethod.Invoke(target, ObjectUtils.EmptyObjects);
- }
- catch (TargetInvocationException ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException());
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex);
- }
- }
- }
-
- ///
- /// Invoke the specified custom destroy method on the given object.
- ///
- ///
- ///
- /// This implementation invokes a no-arg method if found, else checking
- /// for a method with a single boolean argument (passing in "true",
- /// assuming a "force" parameter), else logging an error.
- ///
- ///
- /// Can be overridden in subclasses for custom resolution of destroy
- /// methods with arguments.
- ///
- ///
- /// Custom destroy methods are resolved in a case-insensitive manner.
- ///
- /// Must destroy objects that depend on the given object before the object itself.
- /// Should not throw any exceptions.
- ///
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The target object instance to destroyed.
- ///
- protected override void DestroyObject(string name, object target)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Destroying dependant objects for object '" + name + "'");
- }
-
- #endregion
-
- DestroyDependantObjects(name);
- if (target is IDisposable)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling Dispose () on object with name '{0}'.", name));
- }
-
- #endregion
-
- try
- {
- ((IDisposable)target).Dispose();
- }
- catch (Exception ex)
- {
- #region Instrumentation
-
- log.Error("Destroy() on object with name '" + name + "' threw an exception.", ex);
-
- #endregion
- }
- }
- RootObjectDefinition rootDefinition = GetMergedObjectDefinition(name, false);
- if (rootDefinition != null && StringUtils.HasText(rootDefinition.DestroyMethodName))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Calling custom destroy method '" + rootDefinition.DestroyMethodName + "' on object with name '" + name + "'.");
- }
-
- #endregion
-
- InvokeCustomDestroyMethod(name, target, rootDefinition.DestroyMethodName);
- }
- }
-
- ///
- /// Destroys all of the objects registered as dependant on the
- /// object (definition) identified by the supplied .
- ///
- ///
- /// The name of the root object (definition) that is itself being destroyed.
- ///
- private void DestroyDependantObjects(string name)
- {
- string[] dependingObjects = GetDependingObjectNames(name);
- foreach (string doName in dependingObjects)
- {
- DestroySingleton(doName);
- }
- }
-
- ///
- /// Given a property value, return a value, resolving any references to other
- /// objects in the factory if necessary.
- ///
- ///
- ///
- /// The value could be :
- ///
- ///
- ///
- /// An ,
- /// which leads to the creation of a corresponding new object instance.
- /// Singleton flags and names of such "inner objects" are always ignored: inner objects
- /// are anonymous prototypes.
- ///
- ///
- ///
- ///
- /// A , which must
- /// be resolved.
- ///
- ///
- ///
- ///
- /// An . This is a
- /// special placeholder collection that may contain
- /// s or
- /// collections that will need to be resolved.
- ///
- ///
- ///
- ///
- /// An ordinary object or , in which case it's left alone.
- ///
- ///
- ///
- ///
- ///
- ///
- /// The name of the object that is having the value of one of its properties resolved.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The value of the property that is being resolved.
- ///
- protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue)
- {
- object resolvedValue = null;
- // we must check the argument value to see whether it requires a runtime
- // reference to another object to be resolved.
- // if it does, we'll attempt to instantiate the object and set the reference.
- if (argumentValue is ObjectDefinitionHolder)
- {
- // contains an IObjectDefinition with name and aliases...
- ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue;
- resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton);
- }
- else if (argumentValue is IObjectDefinition)
- {
- // resolve plain IObjectDefinition, without contained name: use dummy name...
- IObjectDefinition def = (IObjectDefinition)argumentValue;
- resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton);
-
- }
- else if (argumentValue is RuntimeObjectReference)
- {
- RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue;
- resolvedValue = ResolveReference(definition, name, argumentName, roref);
- }
- else if (argumentValue is ExpressionHolder)
- {
- ExpressionHolder expHolder = (ExpressionHolder)argumentValue;
- object context = null;
- IDictionary variables = null;
-
- if (expHolder.Properties != null)
- {
- PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context");
- context = contextProperty == null
- ? null
- : ResolveValueIfNecessary(name, definition, "Context",
- contextProperty.Value);
- PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables");
- object vars = (variablesProperty == null
- ? null
- : ResolveValueIfNecessary(name, definition, "Variables",
- variablesProperty.Value));
- if (vars is IDictionary)
- {
- variables = (IDictionary)vars;
- }
- else
- {
- if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary");
- }
- }
-
- if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
- // add 'this' objectfactory reference to variables
- variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this);
-
- resolvedValue = expHolder.Expression.GetValue(context, variables);
- }
- else if (argumentValue is IManagedCollection)
- {
- resolvedValue =
- ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName,
- new ManagedCollectionElementResolver(ResolveValueIfNecessary));
- }
- else if (argumentValue is TypedStringValue)
- {
- TypedStringValue tsv = (TypedStringValue)argumentValue;
- try
- {
- Type resolvedTargetType = ResolveTargetType(tsv);
- if (resolvedTargetType != null)
- {
- resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null);
- }
- else
- {
- resolvedValue = tsv.Value;
- }
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Error converted typed String value for " + argumentName, ex);
- }
-
- }
- else
- {
- // no need to resolve value...
- resolvedValue = argumentValue;
- }
- return resolvedValue;
- }
-
- ///
- /// Resolve the target type of the passed .
- ///
- /// The who's target type is to be resolved
- /// The resolved target type, if any. otherwise.
- protected virtual Type ResolveTargetType(TypedStringValue value)
- {
- if (value.HasTargetType)
- {
- return value.TargetType;
- }
- else
- {
- return null;
- }
- }
- ///
- /// Resolves an inner object definition.
- ///
- ///
- /// The name of the object that surrounds this inner object definition.
- ///
- ///
- /// The name of the inner object definition... note: this is a synthetic
- /// name assigned by the factory (since it makes no sense for inner object
- /// definitions to have names).
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The definition of the inner object that is to be resolved.
- ///
- ///
- /// if the owner of the property is a singleton.
- ///
- ///
- /// The resolved object as defined by the inner object definition.
- ///
- protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition,
- bool singletonOwner)
- {
- RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition);
- mod.IsSingleton = singletonOwner;
- object instance;
- object result;
- try
- {
- instance = CreateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false);
- result = GetObjectForInstance(innerObjectName, instance);
- }
- catch (ObjectsException ex)
- {
- throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName);
- }
- if (singletonOwner && instance is IDisposable)
- {
- // keep a reference to the inner object instance, to be able to destroy
- // it on factory shutdown...
- _disposableInnerObjects.Add(instance);
- }
- return result;
- }
-
- ///
- /// Resolve a reference to another object in the factory.
- ///
- ///
- /// The name of the object that is having the value of one of its properties resolved.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The runtime reference containing the value of the property.
- ///
- /// A reference to another object in the factory.
- protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.",
- argumentName, name, reference.ObjectName));
- }
-
- #endregion
-
- try
- {
- if (reference.IsToParent)
- {
- if (null == ParentObjectFactory)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- string.Format(
- "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.",
- reference.ObjectName));
- }
- return ParentObjectFactory.GetObject(reference.ObjectName);
- }
- return GetObject(reference.ObjectName);
- }
- catch (ObjectsException ex)
- {
- throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName);
- }
- }
-
- ///
- /// Find object instances that match the required .
- ///
- ///
- ///
- /// Called by autowiring. If a subclass cannot obtain information about object
- /// names by , a corresponding exception should be thrown.
- ///
+ /// Provides object creation, initialization and wiring, supporting
+ /// autowiring and constructor resolution. Handles runtime object
+ /// references, managed collections, and object destruction.
+ ///
+ ///
+ /// The main template method to be implemented by subclasses is
+ /// ,
+ /// used for autowiring by type. Note that this class does not implement object
+ /// definition registry capabilities
+ /// (
+ /// does).
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [Serializable]
+ public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory
+ {
+ #region Constants
+
+ ///
+ /// The used during the invocation and
+ /// searching for of methods.
+ ///
+ protected const BindingFlags MethodResolutionFlags =
+ BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase;
+
+ #endregion
+
+ ///
+ /// The instance for this class.
+ ///
+ private readonly ILog log = LogManager.GetLogger(typeof(AbstractAutowireCapableObjectFactory));
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ protected AbstractAutowireCapableObjectFactory(bool caseSensitive)
+ : this(caseSensitive, null)
+ { }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ /// The parent object factory, or if none.
+ protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
+ : base(caseSensitive, parentFactory)
+ {
+ this.IgnoreDependencyInterface(typeof(IObjectFactoryAware));
+ this.IgnoreDependencyInterface(typeof(IObjectNameAware));
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The
+ /// implementation to be used to instantiate managed objects.
+ ///
+ protected IInstantiationStrategy InstantiationStrategy
+ {
+ get { return instantiationStrategy; }
+ set { instantiationStrategy = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Predict the eventual object type (of the processed object instance) for the
+ /// specified object.
+ ///
+ /// Name of the object.
+ /// The merged object definition to determine the type for.
+ ///
+ /// The type of the object, or null if not predictable
+ ///
+ protected override Type PredictObjectType(string objectName, RootObjectDefinition mod)
+ {
+ Type objectType;
+ if (StringUtils.HasText(mod.FactoryMethodName))
+ {
+ objectType = GetTypeForFactoryMethod(objectName, mod);
+ }
+ else
+ {
+ objectType = ResolveObjectType(mod, objectName);
+ }
+ return objectType;
+ }
+
+ ///
+ /// Determines the of the object defined
+ /// by the supplied object .
+ ///
+ ///
+ /// The name associated with the supplied object .
+ ///
+ ///
+ /// The
+ /// that the is to be determined for.
+ ///
+ ///
+ /// The of the object defined by the supplied
+ /// object ; or if the
+ /// cannot be determined.
+ ///
+ protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
+ {
+ if (StringUtils.HasText(definition.FactoryObjectName) && definition.IsSingleton && !definition.IsLazyInit)
+ {
+ return GetObject(objectName).GetType();
+ }
+
+ Type factoryType = null;
+ bool isStatic = true;
+
+ if (StringUtils.HasText(definition.FactoryObjectName))
+ {
+ // check declared factory method return type on factory type...
+ factoryType = GetType(definition.FactoryObjectName);
+ isStatic = false;
+ }
+ else
+ {
+ factoryType = ResolveObjectType(definition, objectName);
+ }
+ if (factoryType == null)
+ {
+ return null;
+ }
+
+ // If all factory methods have the same return type, return that type.
+ // Can't clearly figure out exact method due to type converting / autowiring!
+ int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count;
+ MethodInfo[] candidates = factoryType.GetMethods();
+ ISet returnTypes = new HybridSet();
+ foreach (MethodInfo factoryMethod in candidates)
+ {
+#if NET_2_0
+ GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
+ if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName)
+ && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs
+ && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length)
+ {
+ if (genericArgsInfo.ContainsGenericArguments)
+ {
+ string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
+ Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
+ for (int j = 0; j < unresolvedGenericArgs.Length; j++)
+ {
+ genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
+ }
+ returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType);
+ }
+ else
+ {
+ returnTypes.Add(factoryMethod.ReturnType);
+ }
+ }
+#else
+ if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(definition.FactoryMethodName)
+ && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs)
+ {
+ returnTypes.Add(factoryMethod.ReturnType);
+ }
+#endif
+ }
+ if (returnTypes.Count == 1)
+ {
+ // clear return type found: all factory methods return same type...
+ return (Type)ObjectUtils.EnumerateFirstElement(returnTypes);
+ }
+ else
+ {
+ // ambiguous return types found: return null to indicate "not determinable"...
+ return null;
+ }
+ }
+
+ ///
+ /// Apply the property values of the object definition with the supplied
+ /// to the supplied .
+ ///
+ ///
+ /// The existing object that the property values for the named object will
+ /// be applied to.
+ ///
+ ///
+ /// The name of the object definition associated with the property values that are
+ /// to be applied.
+ ///
+ public override void ApplyObjectPropertyValues(object instance, string name)
+ {
+ RootObjectDefinition definition = GetMergedObjectDefinition(name, true);
+ if (definition != null)
+ {
+ log.Debug(string.Format("configuring object '{0}' using definition '{1}'", instance, name));
+ ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues);
+ }
+ }
+
+ ///
+ /// Apply any
+ /// s.
+ ///
+ ///
+ ///
+ /// The returned instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The of the object that is to be
+ /// instantiated.
+ ///
+ ///
+ /// The name of the object that is to be instantiated.
+ ///
+ ///
+ /// An instance to use in place of the original instance.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("Invoking IInstantiationAwareObjectPostProcessors before " + "the instantiation of '{0}'.", objectName));
+ }
+
+ #endregion
+
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ object theObject = inProc.PostProcessBeforeInstantiation(objectType, objectName);
+ if (theObject != null)
+ {
+ return theObject;
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Apply the given property values, resolving any runtime references
+ /// to other objects in this object factory.
+ ///
+ ///
+ /// The object name passed for better exception information.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ ///
+ /// The new property values.
+ ///
+ ///
+ ///
+ /// Must use deep copy, so that we don't permanently modify this property.
+ ///
+ ///
+ protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
+ {
+ if (properties == null || properties.PropertyValues.Length == 0)
+ {
+ return;
+ }
+ ObjectDefinitionValueResolver valueResolver = new ObjectDefinitionValueResolver(this, name, definition);
+
+ MutablePropertyValues deepCopy = new MutablePropertyValues(properties);
+ PropertyValue[] copiedProperties = deepCopy.PropertyValues;
+ for (int i = 0; i < copiedProperties.Length; ++i)
+ {
+ PropertyValue copiedProperty = copiedProperties[i];
+ //(string name, RootObjectDefinition definition, string argumentName, object argumentValue)
+ object value = valueResolver.ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value );
+ // object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value);
+ PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression);
+ // update mutable copy...
+ deepCopy.SetPropertyValueAt(propertyValue, i);
+ }
+ // set the (possibly resolved) deep copy properties...
+ try
+ {
+ wrapper.SetPropertyValues(deepCopy);
+ }
+ catch (ObjectsException ex)
+ {
+ // improve the message by showing the context...
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex);
+ }
+ }
+
+ ///
+ /// Return an array of object-type property names that are unsatisfied.
+ ///
+ ///
+ ///
+ /// These are probably unsatisfied references to other objects in the
+ /// factory. Does not include simple properties like primitives or
+ /// s.
+ ///
+ ///
+ ///
+ /// An array of object-type property names that are unsatisfied.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected string[] UnsatisfiedObjectProperties(RootObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ ArrayList result = new ArrayList();
+ ISet ignoredTypes = IgnoredDependencyTypes;
+ PropertyInfo[] properties = wrapper.GetPropertyInfos();
+ foreach (PropertyInfo property in properties)
+ {
+ string name = property.Name;
+ if (property.CanWrite && !ignoredTypes.Contains(property.PropertyType) && !result.Contains(name)
+ && !ObjectUtils.IsSimpleProperty(property.PropertyType))
+ {
+ result.Add(name);
+ }
+ }
+ return (string[])result.ToArray(typeof(string));
+ }
+
+ ///
+ /// Destroy all cached singletons in this factory.
+ ///
+ ///
+ ///
+ /// To be called on shutdown of a factory.
+ ///
+ ///
+ public override void Dispose()
+ {
+ base.Dispose();
+ foreach (object o in DisposableInnerObjects)
+ {
+ DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o);
+ }
+ DisposableInnerObjects.Clear();
+ }
+
+ ///
+ /// Populate the object instance in the given
+ /// with the property values from the
+ /// object definition.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
+ // state of the bean before properties are set. This can be used, for example,
+ // to support styles of field injection.
+ bool continueWithPropertyPopulation = true;
+
+ if (HasInstantiationAwareBeanPostProcessors)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name))
+ {
+ continueWithPropertyPopulation = false;
+ break;
+ }
+ }
+ }
+ }
+ if (!continueWithPropertyPopulation)
+ {
+ return;
+ }
+
+ IPropertyValues properties = definition.PropertyValues;
+
+ if (wrapper == null)
+ {
+ if (properties.PropertyValues.Length > 0)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription,
+ name, "Cannot apply property values to null instance.");
+ }
+ else
+ {
+ // skip property population phase for null instance
+ return;
+ }
+ }
+
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType)
+ {
+ MutablePropertyValues mpvs = new MutablePropertyValues(properties);
+ // add property values based on autowire by name if it's applied
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByName)
+ {
+ AutowireByName(name, definition, wrapper, mpvs);
+ }
+ // add property values based on autowire by type if it's applied
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByType)
+ {
+ AutowireByType(name, definition, wrapper, mpvs);
+ }
+ properties = mpvs;
+ }
+ //DependencyCheck(name, definition, wrapper, properties);
+
+
+ bool hasInstAwareOpps = HasInstantiationAwareBeanPostProcessors;
+ bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None);
+
+
+ if (hasInstAwareOpps || needsDepCheck)
+ {
+ PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
+ if (hasInstAwareOpps)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor =
+ processor as IInstantiationAwareObjectPostProcessor;
+ if (instantiationAwareObjectPostProcessor != null)
+ {
+ properties =
+ instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance,
+ name);
+ if (properties == null)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ if (needsDepCheck)
+ {
+ CheckDependencies(name, definition, filteredPropInfo, properties);
+ }
+
+ }
+
+ ApplyPropertyValues(name, definition, wrapper, properties);
+ }
+
+ ///
+ /// Wires up any exposed events in the object instance in the given
+ /// with any event handler
+ /// values from the .
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ foreach (string eventName in definition.EventHandlerValues.Events)
+ {
+ foreach (IEventHandlerValue handlerValue
+ in definition.EventHandlerValues[eventName])
+ {
+ object handler = null;
+ if (handlerValue.Source is RuntimeObjectReference)
+ {
+ RuntimeObjectReference roref = (RuntimeObjectReference)handlerValue.Source;
+ handler = ResolveReference(definition, name, eventName, roref);
+ }
+ else if (handlerValue.Source is Type)
+ {
+ // a static Type event is being wired up; simply pass on the Type
+ handler = handlerValue.Source;
+ }
+ else if (handlerValue.Source is string)
+ {
+ // a static Type event is being wired up; we need to resolve the Type
+ handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string);
+ }
+ else
+ {
+ throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources.");
+ }
+ handlerValue.Wire(handler, wrapper.WrappedInstance);
+ }
+ }
+ }
+
+ ///
+ /// Fills in any missing property values with references to
+ /// other objects in this factory if autowire is set to
+ /// .
+ ///
+ ///
+ /// The object name to be autowired by .
+ ///
+ ///
+ /// The definition of the named object to update through autowiring.
+ ///
+ ///
+ /// The wrapping the target object (and
+ /// from which we can rip out information concerning the object).
+ ///
+ ///
+ /// The property values to register wired objects with.
+ ///
+ protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
+ {
+ string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
+ foreach (string propertyName in propertyNames)
+ {
+ // look for a matching type
+ if (ContainsObject(propertyName))
+ {
+ object o = GetObject(propertyName);
+ properties.Add(propertyName, o);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name,
+ propertyName));
+ }
+
+ #endregion
+ }
+ else
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name));
+ }
+
+ #endregion
+ }
+ }
+ }
+
+ ///
+ /// Defines "autowire by type" (object properties by type) behavior.
+ ///
+ ///
+ ///
+ /// This is like PicoContainer default, in which there must be exactly one object
+ /// of the property type in the object factory. This makes object factories simple
+ /// to configure for small namespaces, but doesn't work as well as standard Spring
+ /// behavior for bigger applications.
+ ///
+ ///
+ ///
+ /// The object name to be autowired by .
+ ///
+ ///
+ /// The definition of the named object to update through autowiring.
+ ///
+ ///
+ /// The wrapping the target object (and
+ /// from which we can rip out information concerning the object).
+ ///
+ ///
+ /// The property values to register wired objects with.
+ ///
+ protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
+ {
+ string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
+ foreach (string propertyName in propertyNames)
+ {
+ // look for a matching type
+ Type requiredType = wrapper.GetPropertyType(propertyName);
+ IDictionary matchingObjects = FindMatchingObjects(requiredType);
+ if (matchingObjects != null && matchingObjects.Count == 1)
+ {
+ properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values));
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name,
+ propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys)));
+ }
+
+ #endregion
+ }
+ else if (matchingObjects != null && matchingObjects.Count > 1)
+ {
+ throw new UnsatisfiedDependencyException(string.Empty, name, propertyName,
+ string.Format(CultureInfo.InvariantCulture,
+ "There are {0} objects of Type [{1}] for autowire by "
+ + "type, when there should have been just 1 to be able to "
+ + "autowire property '{2}' of object '{3}'.", matchingObjects.Count,
+ requiredType, propertyName, name));
+ }
+ else
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.",
+ propertyName, name));
+ }
+
+ #endregion
+ }
+ }
+ }
+
+ ///
+ /// Ignore the given dependency type for autowiring
+ ///
+ ///
+ /// This will typically be used by application contexts to register
+ /// dependencies that are resolved in other ways, like IOjbectFactory through
+ /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware.
+ /// By default, IObjectFactoryAware and IObjectName interfaces are ignored.
+ /// For further types to ignore, invoke this method for each type.
+ ///
+ /// .
+ public void IgnoreDependencyInterface(Type type)
+ {
+ ignoredDependencyInterfaces.Add(type);
+ }
+
+ ///
+ /// Create an object instance for the given object definition.
+ ///
+ /// The name of the object.
+ ///
+ /// The object definition for the object that is to be instantiated.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. It is invalid to use a non- arguments value
+ /// in any other case.
+ ///
+ ///
+ /// A new instance of the object.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ ///
+ ///
+ /// Delegates to the
+ ///
+ /// method version with the allowEagerCaching parameter set to true.
+ ///
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
+ ///
+ protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ return CreateObject(name, definition, arguments, true);
+ }
+
+ ///
+ /// Create an object instance for the given object definition.
+ ///
+ /// The name of the object.
+ ///
+ /// The object definition for the object that is to be instantiated.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. It is invalid to use a non- arguments value
+ /// in any other case.
+ ///
+ ///
+ /// Whether eager caching of singletons is allowed... typically true for
+ /// singlton objects, but never true for inner object definitions.
+ ///
+ ///
+ /// A new instance of the object.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ ///
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
+ ///
+ protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching)
+ {
+ // guarantee the initialization of objects that the current one depends on..
+ if (definition.DependsOn != null && definition.DependsOn.Length > 0)
+ {
+ foreach (string dependant in definition.DependsOn)
+ {
+ GetObject(dependant);
+ }
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Creating instance of Object '{0}' with merged definition [{1}].", name, definition));
+ }
+
+ #endregion
+
+ // Make sure object type is actually resolved at this point.
+ ResolveObjectType(definition, name);
+
+ try
+ {
+ definition.PrepareMethodOverrides();
+ }
+ catch (ObjectDefinitionValidationException ex)
+ {
+ throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
+ "Validation of method overrides failed. " + ex.Message, ex);
+ }
+
+ // return IObjectDefinition instance itself for an abstract object-definition
+ if (definition.IsTemplate)
+ {
+ return definition;
+ }
+
+
+
+ object instance = null;
+
+
+ IObjectWrapper instanceWrapper = null;
+ bool eagerlyCached = false;
+ try
+ {
+ // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance....
+ if (definition.HasObjectType)
+ {
+ instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name);
+ if (instance != null)
+ {
+ return instance;
+ }
+ }
+
+
+ instanceWrapper = CreateObjectInstance(name, definition, arguments);
+ instance = instanceWrapper.WrappedInstance;
+
+ // eagerly cache singletons to be able to resolve circular references
+ // even when triggered by lifecycle interfaces like IObjectFactoryAware.
+ if (allowEagerCaching && definition.IsSingleton)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Eagerly caching object '" + name + "' to allow for resolving potential circular references");
+ }
+ AddEagerlyCachedSingleton(name, definition, instance);
+ eagerlyCached = true;
+ }
+
+ instance = ConfigureObject(name, definition, instanceWrapper);
+ }
+ catch (ObjectCreationException)
+ {
+ if (eagerlyCached)
+ {
+ RemoveEagerlyCachedSingleton(name, definition);
+ }
+ throw;
+ }
+ catch (Exception ex)
+ {
+ if (eagerlyCached)
+ {
+ RemoveEagerlyCachedSingleton(name, definition);
+ }
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex);
+ }
+ return instance;
+ }
+
+ ///
+ /// Add the created, but yet unpopulated singleton to the singleton cache
+ /// to be able to resolve circular references
+ ///
+ /// the name of the object to add to the cache.
+ /// the definition used to create and populated the object.
+ /// the raw object instance.
+ ///
+ /// Derived classes may override this method to select the right cache based on the object definition.
+ ///
+ protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance)
+ {
+ base.AddSingleton(objectName, rawSingletonInstance);
+ }
+
+ ///
+ /// Remove the specified singleton from the singleton cache that has
+ /// been added before by a call to
+ ///
+ /// the name of the object to remove from the cache.
+ /// the definition used to create and populated the object.
+ ///
+ /// Derived classes may override this method to select the right cache based on the object definition.
+ ///
+ protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition)
+ {
+ base.RemoveSingleton(objectName);
+ }
+
+ ///
+ /// Creates an instance from the passed in
+ /// using constructor
+ ///
+ /// The name of the object to create - used for error messages.
+ /// The describing the object to be created.
+ /// optional arguments to pass to the constructor
+ /// An wrapping the already instantiated object
+ protected IObjectWrapper CreateObjectInstance(string objectName, RootObjectDefinition objectDefinition, object[] arguments)
+ {
+ // Make sure object class is actually resolved at this point.
+ Type objectType = ResolveObjectType(objectDefinition, objectName);
+ if (StringUtils.HasText(objectDefinition.FactoryMethodName))
+ {
+ return InstantiateUsingFactoryMethod(objectName, objectDefinition, arguments);
+ }
+
+ //TODO perf optimization when creating the same object
+
+ ConstructorInfo[] ctors = DetermineConstructorsFromObjectPostProcessors(objectType, objectName);
+ if (ctors != null ||
+ objectDefinition.ResolvedAutowireMode == AutoWiringMode.Constructor ||
+ objectDefinition.HasConstructorArgumentValues || !ObjectUtils.IsEmpty(arguments))
+ {
+ return AutowireConstructor(objectName, objectDefinition, ctors, arguments);
+ }
+
+ // No special handling: simply use no-arg constructor.
+ return InstantiateObject(objectName, objectDefinition);
+
+ /*
+ IObjectWrapper instanceWrapper;
+ if (StringUtils.HasText(definition.FactoryMethodName))
+ {
+ instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments);
+ }
+ //Handle case when arguments are passed in explicitly.
+ else if (arguments != null && arguments.Length > 0)
+ {
+ instanceWrapper = AutowireConstructor(name, definition, arguments);
+ }
+ else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor ||
+ definition.HasConstructorArgumentValues)
+ {
+ instanceWrapper = AutowireConstructor(name, definition);
+ }
+ else
+ {
+ instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this));
+ InitObjectWrapper(instanceWrapper);
+ }
+ return instanceWrapper;
+
+ */
+ }
+
+ ///
+ /// Instantiates the given object using its default constructor
+ ///
+ /// Name of the object.
+ /// The definition.
+ /// IObjectWrapper for the new instance
+ protected virtual IObjectWrapper InstantiateObject(string objectName, RootObjectDefinition definition)
+ {
+ return new ObjectWrapper(InstantiationStrategy.Instantiate(definition, objectName, this));
+ }
+
+ ///
+ /// Determines candidate constructors to use for the given bean, checking all registered
+ ///
+ ///
+ /// Raw type of the object.
+ /// Name of the object.
+ /// the candidate constructors, or null if none specified
+ /// In case of errors
+ ///
+ protected virtual ConstructorInfo[] DetermineConstructorsFromObjectPostProcessors(Type objectType, string objectName)
+ {
+ if (HasInstantiationAwareBeanPostProcessors)
+ {
+ foreach (IObjectPostProcessor objectPostProcessor in ObjectPostProcessors)
+ {
+ if (ObjectUtils.IsAssignable(typeof(SmartInstantiationAwareObjectPostProcessor), objectPostProcessor))
+ {
+ SmartInstantiationAwareObjectPostProcessor iop =
+ (SmartInstantiationAwareObjectPostProcessor) objectPostProcessor;
+ ConstructorInfo[] ctors = iop.DetermineCandidateConstructors(objectType, objectName);
+ if (ctors != null)
+ {
+ return ctors;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Instantiate an object instance using a named factory method.
+ ///
+ ///
+ ///
+ /// The method may be static, if the
+ /// parameter specifies a class, rather than a
+ /// instance, or an
+ /// instance variable on a factory object itself configured using Dependency
+ /// Injection.
+ ///
+ ///
+ /// Implementation requires iterating over the static or instance methods
+ /// with the name specified in the supplied
+ /// (the method may be overloaded) and trying to match with the parameters.
+ /// We don't have the types attached to constructor args, so trial and error
+ /// is the only way to go here.
+ ///
+ ///
+ ///
+ /// The name associated with the supplied .
+ ///
+ ///
+ /// The definition describing the instance that is to be instantiated.
+ ///
+ ///
+ /// Any arguments to the factory method that is to be invoked.
+ ///
+ ///
+ /// The result of the factory method invocation (the instance).
+ ///
+ protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ ConstructorResolver constructorResolver =
+ new ConstructorResolver(this, this, InstantiationStrategy);
+ return constructorResolver.InstantiateUsingFactoryMethod(name, definition, arguments);
+ }
+
+ ///
+ /// "autowire constructor" (with constructor arguments by type) behaviour.
+ ///
+ /// The name of the object to autowire by type.
+ /// The object definition to update through autowiring.
+ /// The chosen candidate constructors.
+ /// The argument values passed in programmatically via the GetObject method,
+ /// or null if none (-> use constructor argument values from object definition)
+ ///
+ /// An for the new instance.
+ ///
+ ///
+ ///
+ /// Also applied if explicit constructor argument values are specified,
+ /// matching all remaining arguments with objects from the object factory.
+ ///
+ ///
+ /// This corresponds to constructor injection: in this mode, a Spring.NET
+ /// object factory is able to host components that expect constructor-based
+ /// dependency resolution.
+ ///
+ ///
+ protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorInfo[] ctors, object[] explicitArgs)
+ {
+ ConstructorResolver constructorResolver =
+ new ConstructorResolver(this, this, InstantiationStrategy);
+ return constructorResolver.AutowireConstructor(name, definition, ctors, explicitArgs);
+
+ }
+
+ ///
+ /// Perform a dependency check that all properties exposed have been set, if desired.
+ ///
+ ///
+ ///
+ /// Dependency checks can be objects (collaborating objects), simple (primitives
+ /// and ), or all (both).
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ ///
+ /// The property values to be checked.
+ ///
+ ///
+ /// If all of the checked dependencies were not satisfied.
+ ///
+ protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
+ {
+ DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
+ if (dependencyCheck == DependencyCheckingMode.None)
+ {
+ return;
+ }
+
+ PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
+ if (HasInstantiationAwareBeanPostProcessors)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ properties =
+ inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name);
+ if (properties == null)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+
+ CheckDependencies(name, definition, filteredPropInfo, properties);
+ }
+
+ private static void CheckDependencies(string name, IConfigurableObjectDefinition definition, PropertyInfo[] filteredPropInfo, IPropertyValues properties)
+ {
+ DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
+ foreach (PropertyInfo property in filteredPropInfo)
+ {
+ if (property.CanWrite && properties.GetPropertyValue(property.Name) == null)
+ {
+ bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType);
+ bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple)
+ || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects);
+ if (unsatisfied)
+ {
+ throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, property.Name,
+ "Set this property value or disable dependency checking for this object.");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding
+ /// ignored dependency types.
+ ///
+ /// The object wrapper the object was created with.
+ /// The filtered PropertyInfos
+ private PropertyInfo[] FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper)
+ {
+ lock (filteredPropertyDescriptorsCache)
+ {
+ PropertyInfo[] filtered = (PropertyInfo[])filteredPropertyDescriptorsCache[wrapper.WrappedType];
+ if (filtered == null)
+ {
+
+ ArrayList list = new ArrayList(wrapper.GetPropertyInfos());
+ for (int i = list.Count - 1; i >= 0; i--)
+ {
+ PropertyInfo pi = (PropertyInfo)list[i];
+ if (IsExcludedFromDependencyCheck(pi))
+ {
+ list.RemoveAt(i);
+ }
+ }
+
+ filtered = (PropertyInfo[])list.ToArray(typeof(PropertyInfo));
+ filteredPropertyDescriptorsCache.Add(wrapper.WrappedType, filtered);
+ }
+ return filtered;
+ }
+
+ }
+
+ private bool IsExcludedFromDependencyCheck(PropertyInfo pi)
+ {
+ bool b1 = !pi.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi);
+ bool b2 = IgnoredDependencyTypes.Contains(pi.PropertyType);
+ bool b3 = AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
+ return b1 || b2 || b3;
+ /*
+ return AutowireUtils.IsExcludedFromDependencyCheck(pi) ||
+ IgnoredDependencyTypes.Contains(pi.PropertyType) ||
+ AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
+ */
+ }
+
+ ///
+ /// Give an object a chance to react now all its properties are set,
+ /// and a chance to know about its owning object factory (this object).
+ ///
+ ///
+ ///
+ /// This means checking whether the object implements
+ /// and / or
+ /// , and invoking the
+ /// necessary callback(s) if it does.
+ ///
+ ///
+ /// Custom init methods are resolved in a case-insensitive manner.
+ ///
+ ///
+ ///
+ /// The new object instance we may need to initialise.
+ ///
+ ///
+ /// The name the object has in the factory. Used for logging output.
+ ///
+ ///
+ /// The definition of the target object instance.
+ ///
+ protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition)
+ {
+ if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name));
+ }
+
+ #endregion
+
+ ((IInitializingObject)target).AfterPropertiesSet();
+ }
+ if (StringUtils.HasText(definition.InitMethodName))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.",
+ definition.InitMethodName, name));
+ }
+
+ #endregion
+
+ try
+ {
+ MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null);
+ if (targetMethod == null)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Could not find the named initialization method '" + definition.InitMethodName + "'.");
+ }
+ targetMethod.Invoke(target, ObjectUtils.EmptyObjects);
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException());
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex);
+ }
+ }
+ }
+
+ ///
+ /// Invoke the specified custom destroy method on the given object.
+ ///
+ ///
+ ///
+ /// This implementation invokes a no-arg method if found, else checking
+ /// for a method with a single boolean argument (passing in "true",
+ /// assuming a "force" parameter), else logging an error.
+ ///
+ ///
+ /// Can be overridden in subclasses for custom resolution of destroy
+ /// methods with arguments.
+ ///
+ ///
+ /// Custom destroy methods are resolved in a case-insensitive manner.
+ ///
+ /// Must destroy objects that depend on the given object before the object itself.
+ /// Should not throw any exceptions.
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The target object instance to destroyed.
+ ///
+ protected override void DestroyObject(string name, object target)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Destroying dependant objects for object '" + name + "'");
+ }
+
+ #endregion
+
+ DestroyDependantObjects(name);
+ if (target is IDisposable)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling Dispose () on object with name '{0}'.", name));
+ }
+
+ #endregion
+
+ try
+ {
+ ((IDisposable)target).Dispose();
+ }
+ catch (Exception ex)
+ {
+ #region Instrumentation
+
+ log.Error("Destroy() on object with name '" + name + "' threw an exception.", ex);
+
+ #endregion
+ }
+ }
+ RootObjectDefinition rootDefinition = GetMergedObjectDefinition(name, false);
+ if (rootDefinition != null && StringUtils.HasText(rootDefinition.DestroyMethodName))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Calling custom destroy method '" + rootDefinition.DestroyMethodName + "' on object with name '" + name + "'.");
+ }
+
+ #endregion
+
+ InvokeCustomDestroyMethod(name, target, rootDefinition.DestroyMethodName);
+ }
+ }
+
+ ///
+ /// Destroys all of the objects registered as dependant on the
+ /// object (definition) identified by the supplied .
+ ///
+ ///
+ /// The name of the root object (definition) that is itself being destroyed.
+ ///
+ private void DestroyDependantObjects(string name)
+ {
+ string[] dependingObjects = GetDependingObjectNames(name);
+ foreach (string doName in dependingObjects)
+ {
+ DestroySingleton(doName);
+ }
+ }
+
+ ///
+ /// Given a property value, return a value, resolving any references to other
+ /// objects in the factory if necessary.
+ ///
+ ///
+ ///
+ /// The value could be :
+ ///
+ ///
+ ///
+ /// An ,
+ /// which leads to the creation of a corresponding new object instance.
+ /// Singleton flags and names of such "inner objects" are always ignored: inner objects
+ /// are anonymous prototypes.
+ ///
+ ///
+ ///
+ ///
+ /// A , which must
+ /// be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An . This is a
+ /// special placeholder collection that may contain
+ /// s or
+ /// collections that will need to be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An ordinary object or , in which case it's left alone.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The name of the object that is having the value of one of its properties resolved.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The value of the property that is being resolved.
+ ///
+ protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue)
+ {
+ object resolvedValue = null;
+ // we must check the argument value to see whether it requires a runtime
+ // reference to another object to be resolved.
+ // if it does, we'll attempt to instantiate the object and set the reference.
+ if (argumentValue is ObjectDefinitionHolder)
+ {
+ // contains an IObjectDefinition with name and aliases...
+ ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue;
+ resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton);
+ }
+ else if (argumentValue is IObjectDefinition)
+ {
+ // resolve plain IObjectDefinition, without contained name: use dummy name...
+ IObjectDefinition def = (IObjectDefinition)argumentValue;
+ resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton);
+
+ }
+ else if (argumentValue is RuntimeObjectReference)
+ {
+ RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue;
+ resolvedValue = ResolveReference(definition, name, argumentName, roref);
+ }
+ else if (argumentValue is ExpressionHolder)
+ {
+ ExpressionHolder expHolder = (ExpressionHolder)argumentValue;
+ object context = null;
+ IDictionary variables = null;
+
+ if (expHolder.Properties != null)
+ {
+ PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context");
+ context = contextProperty == null
+ ? null
+ : ResolveValueIfNecessary(name, definition, "Context",
+ contextProperty.Value);
+ PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables");
+ object vars = (variablesProperty == null
+ ? null
+ : ResolveValueIfNecessary(name, definition, "Variables",
+ variablesProperty.Value));
+ if (vars is IDictionary)
+ {
+ variables = (IDictionary)vars;
+ }
+ else
+ {
+ if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary");
+ }
+ }
+
+ if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
+ // add 'this' objectfactory reference to variables
+ variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this);
+
+ resolvedValue = expHolder.Expression.GetValue(context, variables);
+ }
+ else if (argumentValue is IManagedCollection)
+ {
+ resolvedValue =
+ ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName,
+ new ManagedCollectionElementResolver(ResolveValueIfNecessary));
+ }
+ else if (argumentValue is TypedStringValue)
+ {
+ TypedStringValue tsv = (TypedStringValue)argumentValue;
+ try
+ {
+ Type resolvedTargetType = ResolveTargetType(tsv);
+ if (resolvedTargetType != null)
+ {
+ resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null);
+ }
+ else
+ {
+ resolvedValue = tsv.Value;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Error converted typed String value for " + argumentName, ex);
+ }
+
+ }
+ else
+ {
+ // no need to resolve value...
+ resolvedValue = argumentValue;
+ }
+ return resolvedValue;
+ }
+
+ ///
+ /// Resolve the target type of the passed .
+ ///
+ /// The who's target type is to be resolved
+ /// The resolved target type, if any. otherwise.
+ protected virtual Type ResolveTargetType(TypedStringValue value)
+ {
+ if (value.HasTargetType)
+ {
+ return value.TargetType;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ ///
+ /// Resolves an inner object definition.
+ ///
+ ///
+ /// The name of the object that surrounds this inner object definition.
+ ///
+ ///
+ /// The name of the inner object definition... note: this is a synthetic
+ /// name assigned by the factory (since it makes no sense for inner object
+ /// definitions to have names).
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The definition of the inner object that is to be resolved.
+ ///
+ ///
+ /// if the owner of the property is a singleton.
+ ///
+ ///
+ /// The resolved object as defined by the inner object definition.
+ ///
+ protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition,
+ bool singletonOwner)
+ {
+ RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition);
+ mod.IsSingleton = singletonOwner;
+ object instance;
+ object result;
+ try
+ {
+ instance = CreateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false);
+ result = GetObjectForInstance(innerObjectName, instance);
+ }
+ catch (ObjectsException ex)
+ {
+ throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName);
+ }
+ if (singletonOwner && instance is IDisposable)
+ {
+ // keep a reference to the inner object instance, to be able to destroy
+ // it on factory shutdown...
+ DisposableInnerObjects.Add(instance);
+ }
+ return result;
+ }
+
+ ///
+ /// Resolve a reference to another object in the factory.
+ ///
+ ///
+ /// The name of the object that is having the value of one of its properties resolved.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The runtime reference containing the value of the property.
+ ///
+ /// A reference to another object in the factory.
+ protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.",
+ argumentName, name, reference.ObjectName));
+ }
+
+ #endregion
+
+ try
+ {
+ if (reference.IsToParent)
+ {
+ if (null == ParentObjectFactory)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ string.Format(
+ "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.",
+ reference.ObjectName));
+ }
+ return ParentObjectFactory.GetObject(reference.ObjectName);
+ }
+ return GetObject(reference.ObjectName);
+ }
+ catch (ObjectsException ex)
+ {
+ throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName);
+ }
+ }
+
+ ///
+ /// Find object instances that match the required .
+ ///
+ ///
+ ///
+ /// Called by autowiring. If a subclass cannot obtain information about object
+ /// names by , a corresponding exception should be thrown.
+ ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition() : this(null, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties)
- {
- constructorArgumentValues =
- (arguments != null) ? arguments : new ConstructorArgumentValues();
- propertyValues =
- (properties != null) ? properties : new MutablePropertyValues();
- eventHandlerValues = new EventValues();
- DependsOn = StringUtils.EmptyStrings;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The object definition used to initialise the member fields of this
- /// instance.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition(IObjectDefinition other)
- {
- AssertUtils.ArgumentNotNull(other, "other");
- AbstractObjectDefinition aod = other as AbstractObjectDefinition;
- if (aod != null)
- {
- if (aod.HasObjectType)
- {
- ObjectType = other.ObjectType;
- }
- else
- {
- ObjectTypeName = other.ObjectTypeName;
- }
- MethodOverrides = new MethodOverrides(aod.MethodOverrides);
- DependencyCheck = aod.DependencyCheck;
- }
- IsAbstract = other.IsAbstract;
- IsSingleton = other.IsSingleton;
- IsLazyInit = other.IsLazyInit;
- ConstructorArgumentValues
- = new ConstructorArgumentValues(other.ConstructorArgumentValues);
- PropertyValues = new MutablePropertyValues(other.PropertyValues);
- EventHandlerValues = new EventValues(other.EventHandlerValues);
-
- InitMethodName = other.InitMethodName;
- DestroyMethodName = other.DestroyMethodName;
- DependsOn = new string[other.DependsOn.Length];
- Array.Copy(other.DependsOn, DependsOn, other.DependsOn.Length);
- FactoryMethodName = other.FactoryMethodName;
- FactoryObjectName = other.FactoryObjectName;
- AutowireMode = other.AutowireMode;
- ResourceDescription = other.ResourceDescription;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The property values that are to be applied to the object
- /// upon creation.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned to the property value.
- ///
- ///
- ///
- /// The property values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public MutablePropertyValues PropertyValues
- {
- get { return propertyValues; }
- set { propertyValues = value == null ? new MutablePropertyValues() : value; }
- }
-
- ///
- /// Does this definition have any
- /// ?
- ///
- ///
- /// if this definition has at least one
- /// .
- ///
- public bool HasMethodOverrides
- {
- get { return !MethodOverrides.IsEmpty; }
- }
-
- ///
- /// The constructor argument values for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned.
- ///
- ///
- ///
- /// The constructor argument values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public ConstructorArgumentValues ConstructorArgumentValues
- {
- get { return constructorArgumentValues; }
- set { constructorArgumentValues = value == null ? new ConstructorArgumentValues() : value; }
- }
-
- ///
- /// The event handler values for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned.
- ///
- ///
- ///
- /// The event handler values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public EventValues EventHandlerValues
- {
- get { return eventHandlerValues; }
- set { eventHandlerValues = value == null ? new EventValues() : value; }
- }
-
- ///
- /// The method overrides (if any) for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned to the property value.
- ///
- ///
- ///
- /// The method overrides (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public MethodOverrides MethodOverrides
- {
- get { return methodOverrides; }
- set { methodOverrides = value == null ? new MethodOverrides() : value; }
- }
-
- ///
- /// Is this definition a singleton, with
- /// a single, shared instance returned on all calls to an enclosing
- /// container (typically an
- /// or
- /// ).
- ///
- ///
- ///
- /// If , an object factory will apply the
- /// prototype design pattern, with each caller requesting an
- /// instance getting an independent instance. How this is defined
- /// will depend on the object factory implementation. singletons
- /// are the commoner type.
- ///
- ///
- ///
- public virtual bool IsSingleton
- {
- get { return isSingleton; }
- set
- {
- isSingleton = value;
- isPrototype = !value;
- }
- }
-
- ///
- /// Gets a value indicating whether this instance is prototype, with an independent instance
- /// returned for each call.
- ///
- ///
- /// true if this instance is prototype; otherwise, false.
- ///
- public virtual bool IsPrototype
- {
- get { return isPrototype; }
- }
-
- ///
- /// Is this object lazily initialized?
- ///
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup
- /// by object factories that perform eager initialization of
- /// singletons.
- ///
- ///
- public bool IsLazyInit
- {
- get { return isLazyInit; }
- set { isLazyInit = value; }
- }
-
- ///
- /// Is this object definition a "template", i.e. not meant to be instantiated
- /// itself but rather just serving as an object definition for configuration
- /// templates used by .
- ///
- ///
- /// if this object definition is a "template".
- ///
- public bool IsTemplate
- {
- get
- {
- return (
- isAbstract ||
- (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName))
- );
- }
- }
-
- ///
- /// Is this object definition "abstract", i.e. not meant to be
- /// instantiated itself but rather just serving as a parent for concrete
- /// child object definitions.
- ///
- ///
- /// if this object definition is "abstract".
- ///
- public bool IsAbstract
- {
- get { return isAbstract; }
- set { isAbstract = value; }
- }
-
- ///
- /// The of the object definition (if any).
- ///
- ///
- /// A resolved object .
- ///
- ///
- /// If the of the object definition is not a
- /// resolved or .
- ///
- ///
- public Type ObjectType
- {
- get
- {
- if (!HasObjectType)
- {
- throw new ApplicationException(
- "Object definition does not carry a resolved System.Type");
- }
- return (Type) objectType;
- }
- set { objectType = value; }
- }
-
- ///
- /// Is the of the object definition a resolved
- /// ?
- ///
- public bool HasObjectType
- {
- get { return objectType is Type; }
- }
-
- ///
- /// Returns the of the
- /// of the object definition (if any).
- ///
- public string ObjectTypeName
- {
- get
- {
- if (objectType is Type)
- {
- return ((Type) objectType).FullName;
- }
- else
- {
- return objectType as string;
- }
- }
- set { objectType = value; }
- }
-
- ///
- /// A description of the resource that this object definition
- /// came from (for the purpose of showing context in case of errors).
- ///
- public string ResourceDescription
- {
- get { return resourceDescription; }
- set { resourceDescription = value; }
- }
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. The default is
- /// ,
- /// which means that no autowiring will be performed.
- ///
- ///
- public AutoWiringMode AutowireMode
- {
- get { return autowireMode; }
- set { autowireMode = value; }
- }
-
- ///
- /// Gets the resolved autowire mode.
- ///
- ///
- ///
- /// This resolves
- ///
- /// to one of
- ///
- /// or
- /// .
- ///
- ///
- public AutoWiringMode ResolvedAutowireMode
- {
- get
- {
- if (AutowireMode == AutoWiringMode.AutoDetect)
- {
- // Work out whether to apply setter autowiring or constructor autowiring.
- // If it has a no-arg constructor it's deemed to be setter autowiring,
- // otherwise we'll try constructor autowiring.
- ConstructorInfo[] constructors =
- ObjectType.GetConstructors();
- foreach (ConstructorInfo ctor in constructors)
- {
- if (ctor.GetParameters().Length == 0)
- {
- return AutoWiringMode.ByType;
- }
- }
- return AutoWiringMode.Constructor;
- }
- else
- {
- return AutowireMode;
- }
- }
- }
-
- ///
- /// The dependency checking mode.
- ///
- ///
- ///
- /// The default is
- /// .
- ///
- ///
- public DependencyCheckingMode DependencyCheck
- {
- get { return dependencyCheck; }
- set { dependencyCheck = value; }
- }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before this object definition.
- ///
- ///
- /// Dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies such as statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- public string[] DependsOn
- {
- get { return dependsOn; }
- set { dependsOn = value == null ? StringUtils.EmptyStrings : value; }
- }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default value is the constant,
- /// in which case there is no initializer method.
- ///
- ///
- public string InitMethodName
- {
- get { return initMethodName; }
- set { initMethodName = value; }
- }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default value is the constant,
- /// in which case there is no destroy method.
- ///
- ///
- public string DestroyMethodName
- {
- get { return destroyMethodName; }
- set { destroyMethodName = value; }
- }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The
- /// method will be invoked on the specified
- /// .
- ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition() : this(null, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ {
+ constructorArgumentValues =
+ (arguments != null) ? arguments : new ConstructorArgumentValues();
+ propertyValues =
+ (properties != null) ? properties : new MutablePropertyValues();
+ eventHandlerValues = new EventValues();
+ DependsOn = StringUtils.EmptyStrings;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The object definition used to initialise the member fields of this
+ /// instance.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition(IObjectDefinition other)
+ {
+ AssertUtils.ArgumentNotNull(other, "other");
+ AbstractObjectDefinition aod = other as AbstractObjectDefinition;
+ if (aod != null)
+ {
+ if (aod.HasObjectType)
+ {
+ ObjectType = other.ObjectType;
+ }
+ else
+ {
+ ObjectTypeName = other.ObjectTypeName;
+ }
+ MethodOverrides = new MethodOverrides(aod.MethodOverrides);
+ DependencyCheck = aod.DependencyCheck;
+ }
+ IsAbstract = other.IsAbstract;
+ IsSingleton = other.IsSingleton;
+ IsLazyInit = other.IsLazyInit;
+ ConstructorArgumentValues
+ = new ConstructorArgumentValues(other.ConstructorArgumentValues);
+ PropertyValues = new MutablePropertyValues(other.PropertyValues);
+ EventHandlerValues = new EventValues(other.EventHandlerValues);
+
+ InitMethodName = other.InitMethodName;
+ DestroyMethodName = other.DestroyMethodName;
+ DependsOn = new string[other.DependsOn.Length];
+ IsAutowireCandidate = other.IsAutowireCandidate;
+ Array.Copy(other.DependsOn, DependsOn, other.DependsOn.Length);
+ FactoryMethodName = other.FactoryMethodName;
+ FactoryObjectName = other.FactoryObjectName;
+ AutowireMode = other.AutowireMode;
+ ResourceDescription = other.ResourceDescription;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The property values that are to be applied to the object
+ /// upon creation.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned to the property value.
+ ///
+ ///
+ ///
+ /// The property values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public MutablePropertyValues PropertyValues
+ {
+ get { return propertyValues; }
+ set { propertyValues = value == null ? new MutablePropertyValues() : value; }
+ }
+
+ ///
+ /// Does this definition have any
+ /// ?
+ ///
+ ///
+ /// if this definition has at least one
+ /// .
+ ///
+ public bool HasMethodOverrides
+ {
+ get { return !MethodOverrides.IsEmpty; }
+ }
+
+ ///
+ /// The constructor argument values for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned.
+ ///
+ ///
+ ///
+ /// The constructor argument values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public ConstructorArgumentValues ConstructorArgumentValues
+ {
+ get { return constructorArgumentValues; }
+ set { constructorArgumentValues = value == null ? new ConstructorArgumentValues() : value; }
+ }
+
+ ///
+ /// The event handler values for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned.
+ ///
+ ///
+ ///
+ /// The event handler values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public EventValues EventHandlerValues
+ {
+ get { return eventHandlerValues; }
+ set { eventHandlerValues = value == null ? new EventValues() : value; }
+ }
+
+ ///
+ /// The method overrides (if any) for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned to the property value.
+ ///
+ ///
+ ///
+ /// The method overrides (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public MethodOverrides MethodOverrides
+ {
+ get { return methodOverrides; }
+ set { methodOverrides = value == null ? new MethodOverrides() : value; }
+ }
+
+ ///
+ /// Is this definition a singleton, with
+ /// a single, shared instance returned on all calls to an enclosing
+ /// container (typically an
+ /// or
+ /// ).
+ ///
+ ///
+ ///
+ /// If , an object factory will apply the
+ /// prototype design pattern, with each caller requesting an
+ /// instance getting an independent instance. How this is defined
+ /// will depend on the object factory implementation. singletons
+ /// are the commoner type.
+ ///
+ ///
+ ///
+ public virtual bool IsSingleton
+ {
+ get { return isSingleton; }
+ set
+ {
+ isSingleton = value;
+ isPrototype = !value;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this instance is prototype, with an independent instance
+ /// returned for each call.
+ ///
+ ///
+ /// true if this instance is prototype; otherwise, false.
+ ///
+ public virtual bool IsPrototype
+ {
+ get { return isPrototype; }
+ }
+
+ ///
+ /// Is this object lazily initialized?
+ ///
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup
+ /// by object factories that perform eager initialization of
+ /// singletons.
+ ///
+ ///
+ public bool IsLazyInit
+ {
+ get { return isLazyInit; }
+ set { isLazyInit = value; }
+ }
+
+ ///
+ /// Is this object definition a "template", i.e. not meant to be instantiated
+ /// itself but rather just serving as an object definition for configuration
+ /// templates used by .
+ ///
+ ///
+ /// if this object definition is a "template".
+ ///
+ public bool IsTemplate
+ {
+ get
+ {
+ return (
+ isAbstract ||
+ (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName))
+ );
+ }
+ }
+
+ ///
+ /// Is this object definition "abstract", i.e. not meant to be
+ /// instantiated itself but rather just serving as a parent for concrete
+ /// child object definitions.
+ ///
+ ///
+ /// if this object definition is "abstract".
+ ///
+ public bool IsAbstract
+ {
+ get { return isAbstract; }
+ set { isAbstract = value; }
+ }
+
+ ///
+ /// The of the object definition (if any).
+ ///
+ ///
+ /// A resolved object .
+ ///
+ ///
+ /// If the of the object definition is not a
+ /// resolved or .
+ ///
+ ///
+ public Type ObjectType
+ {
+ get
+ {
+ if (!HasObjectType)
+ {
+ throw new ApplicationException(
+ "Object definition does not carry a resolved System.Type");
+ }
+ return (Type) objectType;
+ }
+ set { objectType = value; }
+ }
+
+ ///
+ /// Is the of the object definition a resolved
+ /// ?
+ ///
+ public bool HasObjectType
+ {
+ get { return objectType is Type; }
+ }
+
+ ///
+ /// Returns the of the
+ /// of the object definition (if any).
+ ///
+ public string ObjectTypeName
+ {
+ get
+ {
+ if (objectType is Type)
+ {
+ return ((Type) objectType).FullName;
+ }
+ else
+ {
+ return objectType as string;
+ }
+ }
+ set { objectType = value; }
+ }
+
+ ///
+ /// A description of the resource that this object definition
+ /// came from (for the purpose of showing context in case of errors).
+ ///
+ public string ResourceDescription
+ {
+ get { return resourceDescription; }
+ set { resourceDescription = value; }
+ }
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. The default is
+ /// ,
+ /// which means that no autowiring will be performed.
+ ///
+ ///
+ public AutoWiringMode AutowireMode
+ {
+ get { return autowireMode; }
+ set { autowireMode = value; }
+ }
+
+ ///
+ /// Gets the resolved autowire mode.
+ ///
+ ///
+ ///
+ /// This resolves
+ ///
+ /// to one of
+ ///
+ /// or
+ /// .
+ ///
+ ///
+ public AutoWiringMode ResolvedAutowireMode
+ {
+ get
+ {
+ if (AutowireMode == AutoWiringMode.AutoDetect)
+ {
+ // Work out whether to apply setter autowiring or constructor autowiring.
+ // If it has a no-arg constructor it's deemed to be setter autowiring,
+ // otherwise we'll try constructor autowiring.
+ ConstructorInfo[] constructors =
+ ObjectType.GetConstructors();
+ foreach (ConstructorInfo ctor in constructors)
+ {
+ if (ctor.GetParameters().Length == 0)
+ {
+ return AutoWiringMode.ByType;
+ }
+ }
+ return AutoWiringMode.Constructor;
+ }
+ else
+ {
+ return AutowireMode;
+ }
+ }
+ }
+
+ ///
+ /// The dependency checking mode.
+ ///
+ ///
+ ///
+ /// The default is
+ /// .
+ ///
+ ///
+ public DependencyCheckingMode DependencyCheck
+ {
+ get { return dependencyCheck; }
+ set { dependencyCheck = value; }
+ }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before this object definition.
+ ///
+ ///
+ /// Dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies such as statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ public string[] DependsOn
+ {
+ get { return dependsOn; }
+ set { dependsOn = value == null ? StringUtils.EmptyStrings : value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether this instance a candidate for getting autowired into some other
+ /// object.
+ ///
+ ///
+ /// true if this instance is autowire candidate; otherwise, false.
+ ///
+ public bool IsAutowireCandidate
+ {
+ get { return autowireCandidate; }
+ set { autowireCandidate = value;}
+ }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default value is the constant,
+ /// in which case there is no initializer method.
+ ///
+ ///
+ public string InitMethodName
+ {
+ get { return initMethodName; }
+ set { initMethodName = value; }
+ }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default value is the constant,
+ /// in which case there is no destroy method.
+ ///
+ ///
+ public string DestroyMethodName
+ {
+ get { return destroyMethodName; }
+ set { destroyMethodName = value; }
+ }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The
+ /// method will be invoked on the specified
+ /// .
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
- /// This is a utility class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- private AutowireUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// Gets those s
- /// that are applicable for autowiring the supplied .
- ///
- ///
- /// The
- /// (definition) that is being autowired by constructor.
- ///
- ///
- /// The absolute minimum number of arguments that any returned constructor
- /// must have. If this parameter is equal to zero (0), then all constructors
- /// are valid (regardless of their argument count), including any default
- /// constructor.
- ///
- ///
- /// Those s
- /// that are applicable for autowiring the supplied .
- ///
- public static ConstructorInfo[] GetConstructors(
- IObjectDefinition definition, int minimumArgumentCount)
- {
- const BindingFlags flags =
- BindingFlags.Public | BindingFlags.NonPublic
- | BindingFlags.Instance | BindingFlags.DeclaredOnly;
- ConstructorInfo[] constructors = null;
- if (minimumArgumentCount > 0)
- {
- MemberInfo[] ctors = definition.ObjectType.FindMembers(
- MemberTypes.Constructor,
- flags,
- new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- new MinimumArgumentCountCriteria(minimumArgumentCount));
- constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof (ConstructorInfo));
- }
- else
- {
- constructors = definition.ObjectType.GetConstructors(flags);
- }
- AutowireUtils.SortConstructors(constructors);
- return constructors;
- }
-
- ///
- /// Determine a weight that represents the class hierarchy difference between types and
- /// arguments.
- ///
- ///
- ///
- /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase
- /// the result - all direct matches means weight zero (0). A match between the argument type
- /// and a MyInteger instance argument would increase the weight by
- /// 1, due to the superclass () being one (1) steps up in the
- /// class hierarchy being the last one that still matches the required type.
- ///
- ///
- /// Therefore, with an argument of type , a
- /// constructor taking a argument would be
- /// preferred to a constructor taking an argument
- /// which would be preferred to a constructor taking an
- /// argument which would in turn be preferred
- /// to a constructor taking an argument.
- ///
- ///
- /// All argument weights get accumulated.
- ///
- ///
- ///
- /// The argument s to match.
- ///
- /// The arguments to match.
- /// The accumulated weight for all arguments.
- public static int GetTypeDifferenceWeight(ParameterInfo[] argTypes, object[] args)
- {
- if (argTypes.Length != args.Length)
- {
- throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths.");
- }
- int result = 0;
- for (int i = 0; i < argTypes.Length; i++)
- {
- Type theParameterType = argTypes[i].ParameterType;
- if (!ObjectUtils.IsAssignable(theParameterType, args[i]))
- {
- return Int32.MaxValue;
- }
- if (args[i] != null
- && !(args[i].GetType().Equals(theParameterType)))
- {
- Type superType = args[i].GetType().BaseType;
- while (superType != null)
- {
- if (theParameterType.IsAssignableFrom(superType))
- {
- ++result;
- superType = superType.BaseType;
- }
- else
- {
- superType = null;
- }
- }
- }
- }
- return result;
- }
-
- ///
- /// Determines whether the given object property is excluded from dependency checks.
- ///
- /// The PropertyInfo of the object property.
- ///
- /// true if is excluded from dependency check; otherwise, false.
- ///
- public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi)
- {
- return (pi.GetSetMethod() == null) ? false : true;
- }
-
- ///
- /// Sorts the supplied , preferring
- /// public constructors and "greedy" ones (that have lots of arguments).
- ///
- ///
- ///
- /// The result will contain public constructors first, with a decreasing number
- /// of arguments, then non-public constructors, again with a decreasing number
- /// of arguments.
- ///
+ /// This is a utility class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ private AutowireUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// Gets those s
+ /// that are applicable for autowiring the supplied .
+ ///
+ ///
+ /// The
+ /// (definition) that is being autowired by constructor.
+ ///
+ ///
+ /// The absolute minimum number of arguments that any returned constructor
+ /// must have. If this parameter is equal to zero (0), then all constructors
+ /// are valid (regardless of their argument count), including any default
+ /// constructor.
+ ///
+ ///
+ /// Those s
+ /// that are applicable for autowiring the supplied .
+ ///
+ public static ConstructorInfo[] GetConstructors(
+ IObjectDefinition definition, int minimumArgumentCount)
+ {
+ const BindingFlags flags =
+ BindingFlags.Public | BindingFlags.NonPublic
+ | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+ ConstructorInfo[] constructors = null;
+ if (minimumArgumentCount > 0)
+ {
+ MemberInfo[] ctors = definition.ObjectType.FindMembers(
+ MemberTypes.Constructor,
+ flags,
+ new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ new MinimumArgumentCountCriteria(minimumArgumentCount));
+ constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof (ConstructorInfo));
+ }
+ else
+ {
+ constructors = definition.ObjectType.GetConstructors(flags);
+ }
+ AutowireUtils.SortConstructors(constructors);
+ return constructors;
+ }
+
+ ///
+ /// Determine a weight that represents the class hierarchy difference between types and
+ /// arguments.
+ ///
+ ///
+ ///
+ /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase
+ /// the result - all direct matches means weight zero (0). A match between the argument type
+ /// and a MyInteger instance argument would increase the weight by
+ /// 1, due to the superclass () being one (1) steps up in the
+ /// class hierarchy being the last one that still matches the required type.
+ ///
+ ///
+ /// Therefore, with an argument of type , a
+ /// constructor taking a argument would be
+ /// preferred to a constructor taking an argument
+ /// which would be preferred to a constructor taking an
+ /// argument which would in turn be preferred
+ /// to a constructor taking an argument.
+ ///
+ ///
+ /// All argument weights get accumulated.
+ ///
+ ///
+ ///
+ /// The argument s to match.
+ ///
+ /// The arguments to match.
+ /// The accumulated weight for all arguments.
+ public static int GetTypeDifferenceWeightOld(ParameterInfo[] argTypes, object[] args)
+ {
+ if (argTypes.Length != args.Length)
+ {
+ throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths.");
+ }
+ int result = 0;
+ for (int i = 0; i < argTypes.Length; i++)
+ {
+ Type theParameterType = argTypes[i].ParameterType;
+ if (!ObjectUtils.IsAssignable(theParameterType, args[i]))
+ {
+ return Int32.MaxValue;
+ }
+ if (args[i] != null
+ && !(args[i].GetType().Equals(theParameterType)))
+ {
+ Type superType = args[i].GetType().BaseType;
+ while (superType != null)
+ {
+ if (theParameterType.IsAssignableFrom(superType))
+ {
+ ++result;
+ superType = superType.BaseType;
+ }
+ else
+ {
+ superType = null;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Algorithm that judges the match between the declared parameter types of a candidate method
+ /// and a specific list of arguments that this method is supposed to be invoked with.
+ ///
+ ///
+ /// Determines a weight that represents the class hierarchy difference between types and
+ /// arguments. The following a an example based on the Java class hierarchy for Integer.
+ /// A direct match, i.e. type Integer -> arg of class Integer, does not increase
+ /// the result - all direct matches means weight 0. A match between type Object and arg of
+ /// class Integer would increase the weight by 2, due to the superclass 2 steps up in the
+ /// hierarchy (i.e. Object) being the last one that still matches the required type Object.
+ /// Type Number and class Integer would increase the weight by 1 accordingly, due to the
+ /// superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number.
+ /// Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a
+ /// constructor (Number) which would in turn be preferred to a constructor (Object).
+ /// All argument weights get accumulated.
+ ///
+ /// The param types.
+ /// The args.
+ ///
+ public static int GetTypeDifferenceWeight(Type[] paramTypes, object[] args)
+ {
+ int result = 0;
+ for (int i = 0; i < paramTypes.Length; i++)
+ {
+ if (!ObjectUtils.IsAssignable(paramTypes[i], args[i]))
+ {
+ return Int32.MaxValue;
+ }
+ if (args[i] != null)
+ {
+ Type paramType = paramTypes[i];
+ Type superType = args[i].GetType().BaseType;
+ while (superType != null)
+ {
+ if (paramType.Equals(superType))
+ {
+ result = result + 2;
+ superType = null;
+ }
+ if (paramType.IsAssignableFrom(superType))
+ {
+ result = result + 2;
+ superType = superType.BaseType;
+ }
+ else
+ {
+ superType = null;
+ }
+ }
+ if (paramType.IsInterface)
+ {
+ result = result + 1;
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Determines whether the given object property is excluded from dependency checks.
+ ///
+ /// The PropertyInfo of the object property.
+ ///
+ /// true if is excluded from dependency check; otherwise, false.
+ ///
+ public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi)
+ {
+ return (pi.GetSetMethod() == null) ? false : true;
+ }
+
+ ///
+ /// Sorts the supplied , preferring
+ /// public constructors and "greedy" ones (that have lots of arguments).
+ ///
+ ///
+ ///
+ /// The result will contain public constructors first, with a decreasing number
+ /// of arguments, then non-public constructors, again with a decreasing number
+ /// of arguments.
+ ///
+ ///
+ ///
+ /// The array to be sorted.
+ ///
+ public static void SortConstructors(ConstructorInfo[] constructors)
+ {
+ if (constructors != null
+ && constructors.Length > 0)
+ {
+ Array.Sort(constructors, new ConstructorComparer());
+ }
+ }
+
+ #region Inner Class : ConstructorComparer
+
+ private sealed class ConstructorComparer : IComparer
+ {
+ public int Compare(object lhs, object rhs)
+ {
+ ConstructorInfo lhsCtor = (ConstructorInfo) lhs;
+ ConstructorInfo rhsCtor = (ConstructorInfo) rhs;
+ if (lhsCtor.IsPublic != rhsCtor.IsPublic)
+ {
+ return (lhsCtor.IsPublic ? -1 : 1);
+ }
+ int lhsParams = lhsCtor.GetParameters().Length;
+ int rhsParams = rhsCtor.GetParameters().Length;
+
+ if (lhsParams < rhsParams)
+ {
+ return 1;
+ }
+ else if (lhsParams > rhsParams)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Inner Class : MinimumArgumentCountCriteria
+
+ private sealed class MinimumArgumentCountCriteria : ICriteria
+ {
+ public MinimumArgumentCountCriteria(int minimumArgumentCount)
+ {
+ _minimumArgumentCount = minimumArgumentCount;
+ }
+
+ public bool IsSatisfied(object datum)
+ {
+ bool satisfied = false;
+ satisfied = ((MethodBase) datum).GetParameters().Length >= _minimumArgumentCount;
+ return satisfied;
+ }
+
+ private int _minimumArgumentCount;
+ }
+
+ #endregion
+
+ ///
+ /// Determines whether the setter property is defined in any of the given interfaces.
+ ///
+ /// The PropertyInfo of the object property
+ /// The ISet of interfaces.
+ ///
+ /// true if setter property is defined in interface; otherwise, false.
+ ///
+ public static bool IsSetterDefinedInInterface(PropertyInfo propertyInfo, ISet interfaces)
+ {
+ MethodInfo setter = propertyInfo.GetSetMethod();
+ if (setter != null)
+ {
+ Type targetType = setter.DeclaringType;
+ foreach (Type interfaceType in interfaces)
+ {
+ if (interfaceType.IsAssignableFrom(targetType) &&
+ ReflectionUtils.GetMethod(interfaceType, setter.Name, ReflectionUtils.GetParameterTypes(setter)) != null)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Creates the autowire candidate resolver.
+ ///
+ /// A SimpleAutowireCandidateResolver
+ public static IAutowireCandidateResolver CreateAutowireCandidateResolver()
+ {
+ return new SimpleAutowireCandidateResolver();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs
new file mode 100644
index 00000000..30c25c6c
--- /dev/null
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs
@@ -0,0 +1,639 @@
+#region License
+
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Reflection;
+using Common.Logging;
+using Spring.Collections;
+using Spring.Core;
+using Spring.Core.TypeConversion;
+using Spring.Core.TypeResolution;
+using Spring.Objects.Factory.Config;
+using Spring.Util;
+
+namespace Spring.Objects.Factory.Support
+{
+ ///
+ /// Helper class for resolving constructors and factory methods.
+ /// Performs constructor resolution through argument matching.
+ ///
+ ///
+ /// Operates on a and an .
+ /// Used by .
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack
+ internal class ConstructorResolver
+ {
+ private readonly ILog log = LogManager.GetLogger(typeof(ConstructorResolver));
+
+ private readonly AbstractObjectFactory objectFactory;
+
+ private readonly IAutowireCapableObjectFactory autowireFactory;
+
+ private readonly IInstantiationStrategy instantiationStrategy;
+
+ ///
+ /// Initializes a new instance of the class for the given factory
+ /// and instantiation strategy.
+ ///
+ /// The object factory to work with.
+ /// The object factory as IAutowireCapableObjectFactory.
+ /// The instantiation strategy for creating objects.
+ public ConstructorResolver(AbstractObjectFactory objectFactory, IAutowireCapableObjectFactory autowireFactory,
+ IInstantiationStrategy instantiationStrategy)
+ {
+ this.objectFactory = objectFactory;
+ this.autowireFactory = autowireFactory;
+ this.instantiationStrategy = instantiationStrategy;
+ }
+
+ ///
+ /// "autowire constructor" (with constructor arguments by type) behavior.
+ /// Also applied if explicit constructor argument values are specified,
+ /// matching all remaining arguments with objects from the object factory.
+ ///
+ ///
+ /// This corresponds to constructor injection: In this mode, a Spring
+ /// object factory is able to host components that expect constructor-based
+ /// dependency resolution.
+ ///
+ /// Name of the object.
+ /// The merged object definition for the object.
+ /// The chosen chosen candidate constructors (or null if none).
+ /// The explicit argument values passed in programmatically via the getBean method,
+ /// or null if none (-> use constructor argument values from object definition)
+ /// An IObjectWrapper for the new instance
+ public IObjectWrapper AutowireConstructor(string objectName, RootObjectDefinition rod,
+ ConstructorInfo[] chosenCtors, object[] explicitArgs)
+ {
+ ObjectWrapper wrapper = new ObjectWrapper();
+
+
+ ConstructorInfo constructorToUse = null;
+ object[] argsToUse = null;
+
+ if (explicitArgs != null)
+ {
+ argsToUse = explicitArgs;
+ }
+ else
+ {
+ //TODO performance optmization on cached ctors.
+ }
+
+
+ // Need to resolve the constructor.
+ bool autowiring = (chosenCtors != null ||
+ rod.ResolvedAutowireMode == AutoWiringMode.Constructor);
+ ConstructorArgumentValues resolvedValues = null;
+
+ int minNrOfArgs = 0;
+ if (explicitArgs != null)
+ {
+ minNrOfArgs = explicitArgs.Length;
+ }
+ else
+ {
+ ConstructorArgumentValues cargs = rod.ConstructorArgumentValues;
+ resolvedValues = new ConstructorArgumentValues();
+ minNrOfArgs = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues);
+ }
+ // Take specified constructors, if any.
+ ConstructorInfo[] candidates = (chosenCtors != null
+ ? chosenCtors
+ : AutowireUtils.GetConstructors(rod, 0));
+ AutowireUtils.SortConstructors(candidates);
+ int minTypeDiffWeight = Int32.MaxValue;
+
+ for (int i = 0; i < candidates.Length; i++)
+ {
+ ConstructorInfo candidate = candidates[i];
+ Type[] paramTypes = ReflectionUtils.GetParameterTypes(candidate.GetParameters());
+ if (constructorToUse != null && argsToUse.Length > paramTypes.Length)
+ {
+ // already found greedy constructor that can be satisfied, so
+ // don't look any further, there are only less greedy constructors left...
+ break;
+ }
+ if (paramTypes.Length < minNrOfArgs)
+ {
+ throw new ObjectCreationException(rod.ResourceDescription, objectName,
+ string.Format(CultureInfo.InvariantCulture,
+ "'{0}' constructor arguments specified but no matching constructor found "
+ + "in object '{1}' (hint: specify argument indexes, names, or "
+ + "types to avoid ambiguities).", minNrOfArgs, objectName));
+ }
+ ArgumentsHolder args = null;
+
+ if (resolvedValues != null)
+ {
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ // Try to resolve arguments for current constructor
+
+ //need to check for null as indicator of no ctor arg match instead of using exceptions for flow
+ //control as in the Java implementation
+ args = CreateArgumentArray(objectName, rod, resolvedValues, wrapper, paramTypes, candidate,
+ autowiring, out unsatisfiedDependencyExceptionData);
+ if (args == null)
+ {
+ if (i == candidates.Length -1 && constructorToUse == null)
+ {
+ throw new UnsatisfiedDependencyException(rod.ResourceDescription,
+ objectName,
+ unsatisfiedDependencyExceptionData.ParameterIndex,
+ unsatisfiedDependencyExceptionData.ParameterType,
+ unsatisfiedDependencyExceptionData.ErrorMessage);
+ }
+ // try next constructor...
+ continue;
+ }
+ } else
+ {
+ // Explicit arguments given -> arguments length must match exactly
+ if (paramTypes.Length != explicitArgs.Length)
+ {
+ continue;
+ }
+ args = new ArgumentsHolder(explicitArgs);
+
+ }
+ int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes);
+ // Choose this constructor if it represents the closest match.
+ if (typeDiffWeight < minTypeDiffWeight)
+ {
+ constructorToUse = candidate;
+ argsToUse = args.arguments;
+ minTypeDiffWeight = typeDiffWeight;
+ }
+
+ }
+
+
+ if (constructorToUse == null)
+ {
+ throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor.");
+ }
+
+ wrapper.WrappedInstance = instantiationStrategy.Instantiate(rod, objectName, this.objectFactory, constructorToUse, argsToUse);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", objectName, constructorToUse));
+ }
+
+ #endregion
+
+ return wrapper;
+
+ }
+
+ ///
+ /// Instantiate an object instance using a named factory method.
+ ///
+ ///
+ ///
+ /// The method may be static, if the
+ /// parameter specifies a class, rather than a
+ /// instance, or an
+ /// instance variable on a factory object itself configured using Dependency
+ /// Injection.
+ ///
+ ///
+ /// Implementation requires iterating over the static or instance methods
+ /// with the name specified in the supplied
+ /// (the method may be overloaded) and trying to match with the parameters.
+ /// We don't have the types attached to constructor args, so trial and error
+ /// is the only way to go here.
+ ///
+ ///
+ ///
+ /// The name associated with the supplied .
+ ///
+ ///
+ /// The definition describing the instance that is to be instantiated.
+ ///
+ ///
+ /// Any arguments to the factory method that is to be invoked.
+ ///
+ ///
+ /// The result of the factory method invocation (the instance).
+ ///
+ public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ ObjectWrapper wrapper = new ObjectWrapper();
+ Type factoryClass = null;
+ bool isStatic = true;
+
+
+ ConstructorArgumentValues cargs = definition.ConstructorArgumentValues;
+ ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
+ int expectedArgCount = 0;
+
+ // we don't have arguments passed in programmatically, so we need to resolve the
+ // arguments specified in the constructor arguments held in the object definition...
+ if (arguments == null || arguments.Length == 0)
+ {
+ expectedArgCount = cargs.ArgumentCount;
+ ResolveConstructorArguments(name, definition, wrapper, cargs, resolvedValues);
+ }
+ else
+ {
+ // if we have constructor args, don't need to resolve them...
+ expectedArgCount = arguments.Length;
+ }
+
+
+ if (StringUtils.HasText(definition.FactoryObjectName))
+ {
+ // it's an instance method on the factory object's class...
+ factoryClass = objectFactory.GetObject(definition.FactoryObjectName).GetType();
+ isStatic = false;
+ }
+ else
+ {
+ // it's a static factory method on the object class...
+ factoryClass = definition.ObjectType;
+ }
+
+ bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor);
+#if NET_2_0
+ GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
+
+ MethodInfo[] factoryMethods = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass);
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ // try all matching methods to see if they match the constructor arguments...
+ for (int i = 0; i < factoryMethods.Length; i++)
+ {
+ unsatisfiedDependencyExceptionData = null;
+ MethodInfo factoryMethod = factoryMethods[i];
+ Type[] paramTypes = new Type[] { };
+ if (genericArgsInfo.ContainsGenericArguments)
+ {
+ string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
+ if (factoryMethod.GetGenericArguments().Length != unresolvedGenericArgs.Length)
+ continue;
+
+ paramTypes = new Type[unresolvedGenericArgs.Length];
+ for (int j = 0; j < unresolvedGenericArgs.Length; j++)
+ {
+ paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
+ }
+ factoryMethod = factoryMethod.MakeGenericMethod(paramTypes);
+ }
+#else
+ MethodInfo[] factoryMethods = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass);
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ // try all matching methods to see if they match the constructor arguments...
+ foreach(MethodInfo factoryMethod in factoryMethods)
+ {
+#endif
+ if (arguments == null || arguments.Length == 0)
+ {
+ paramTypes = ReflectionUtils.GetParameterTypes(factoryMethod.GetParameters());
+ // try to create the required arguments...
+ ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper,
+ paramTypes, factoryMethod, autowiring, out unsatisfiedDependencyExceptionData);
+ if (args == null)
+ {
+ arguments = null;
+ // if we failed to match this method, keep
+ // trying new overloaded factory methods...
+ continue;
+ }
+ else
+ {
+ arguments = args.arguments;
+ }
+ }
+ // if we get here, we found a factory method...
+ //arguments = (arguments.Length == 0 ? null : arguments);
+ if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethod }, arguments) == null)
+ {
+ continue;
+ }
+
+
+ object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethod, arguments);
+ wrapper.WrappedInstance = objectInstance;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethod));
+ }
+
+ #endregion
+
+ return wrapper;
+ }
+
+
+
+ // if we get here, we didn't match any method...
+ throw new ObjectDefinitionStoreException(
+ string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName,
+ factoryClass));
+ }
+
+ ///
+ /// Create an array of arguments to invoke a constructor or static factory method,
+ /// given the resolved constructor arguments values.
+ ///
+ /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
+ /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using
+ /// exceptions for flow control as in the original implementation.
+ private ArgumentsHolder CreateArgumentArray(string objectName, RootObjectDefinition rod, ConstructorArgumentValues resolvedValues, ObjectWrapper wrapper, Type[] paramTypes, MethodBase methodOrCtorInfo, bool autowiring, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
+ {
+ string methodType = (methodOrCtorInfo is ConstructorInfo) ? "constructor" : "factory method";
+ unsatisfiedDependencyExceptionData = null;
+
+ ArgumentsHolder args = new ArgumentsHolder(paramTypes.Length);
+ ISet usedValueHolders = new HybridSet();
+ IList autowiredObjectNames = new LinkedList();
+ bool resolveNecessary = false;
+
+ ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters();
+
+ for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++)
+ {
+ Type paramType = paramTypes[paramIndex];
+
+ string parameterName = argTypes[paramIndex].Name;
+ // If we couldn't find a direct match and are not supposed to autowire,
+ // let's try the next generic, untyped argument value as fallback:
+ // it could match after type conversion (for example, String -> int).
+ ConstructorArgumentValues.ValueHolder valueHolder = null;
+ if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
+ {
+ valueHolder = resolvedValues.GetArgumentValue(parameterName, paramType, usedValueHolders);
+ }
+ else
+ {
+ valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders);
+ }
+
+
+ if (valueHolder == null && !autowiring)
+ {
+ valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders);
+ }
+ if (valueHolder != null)
+ {
+ // We found a potential match - let's give it a try.
+ // Do not consider the same value definition multiple times!
+ usedValueHolders.Add(valueHolder);
+ args.rawArguments[paramIndex] = valueHolder.Value;
+ try
+ {
+ object originalValue = valueHolder.Value;
+ object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null);
+ args.arguments[paramIndex] = convertedValue;
+
+ //?
+ args.preparedArguments[paramIndex] = convertedValue;
+ } catch (TypeMismatchException ex)
+ {
+ //To avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created.
+ string errorMessage = String.Format(CultureInfo.InvariantCulture,
+ "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
+ methodType, valueHolder.Value,
+ paramType, ex.Message);
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);
+ return null;
+ }
+ } else
+ {
+ // No explicit match found: we're either supposed to autowire or
+ // have to fail creating an argument array for the given constructor.
+ if (!autowiring)
+ {
+ string errorMessage = String.Format(CultureInfo.InvariantCulture,
+ "Ambiguous {0} argument types - " +
+ "Did you specify the correct object references as {0} arguments?",
+ methodType);
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);
+
+ return null;
+ }
+ try
+ {
+ MethodParameter param = MethodParameter.ForMethodOrConstructor(methodOrCtorInfo, paramIndex);
+ object autowiredArgument = ResolveAutoWiredArgument(param, objectName, autowiredObjectNames);
+ args.rawArguments[paramIndex] = autowiredArgument;
+ args.arguments[paramIndex] = autowiredArgument;
+ args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
+ resolveNecessary = true;
+ } catch (ObjectsException ex)
+ {
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message);
+
+ return null;
+ }
+
+ }
+ }
+ foreach (string autowiredObjectName in autowiredObjectNames)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Autowiring by type from object name '" + objectName +
+ "' via " + methodType + " to object named '" + autowiredObjectName + "'");
+ }
+ }
+
+
+ return args;
+
+ }
+
+ private class AutowiredArgumentMarker
+ {
+ }
+
+ private object ResolveAutoWiredArgument(MethodParameter methodParameter, string objectName, IList autowiredObjectNames)
+ {
+ return
+ this.autowireFactory.ResolveDependency(new DependencyDescriptor(methodParameter, true), objectName,
+ autowiredObjectNames);
+ }
+
+ ///
+ /// Resolves the
+ /// of the supplied .
+ ///
+ /// The name of the object that is being resolved by this factory.
+ /// The rod.
+ /// The wrapper.
+ /// The cargs.
+ /// Where the resolved constructor arguments will be placed.
+ ///
+ /// The minimum number of arguments that any constructor for the supplied
+ /// must have.
+ ///
+ ///
+ ///
+ /// 'Resolve' can be taken to mean that all of the s
+ /// constructor arguments is resolved into a concrete object that can be plugged
+ /// into one of the s constructors. Runtime object
+ /// references to other objects in this (or a parent) factory are resolved,
+ /// type conversion is performed, etc.
+ ///
+ ///
+ /// These resolved values are plugged into the supplied
+ /// object, because we wouldn't want to touch
+ /// the s constructor arguments in case it (or any of
+ /// its constructor arguments) is a prototype object definition.
+ ///
+ ///
+ /// This method is also used for handling invocations of static factory methods.
+ ///
- /// If , an object factory will apply the Prototype
- /// design pattern, with each caller requesting an instance getting an
- /// independent instance. How this is defined will depend on the
- /// object factory implementation. Singletons are the commoner type.
- ///
- ///
- new bool IsSingleton { get; set; }
-
- ///
- /// Is this object lazily initialized?
- ///
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup by object factories
- /// that perform eager initialization of singletons.
- ///
- ///
- new bool IsLazyInit { get; set; }
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. Default is
- /// ,
- /// which means there's no autowire.
- ///
- ///
- new AutoWiringMode AutowireMode { get; set; }
-
- ///
- /// The dependency check code.
- ///
- DependencyCheckingMode DependencyCheck { get; set; }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before.
- ///
- ///
- /// Note that dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies like statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- new string[] DependsOn { get; set; }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default is , in which case there is no initializer method.
- ///
- ///
- new string InitMethodName { get; set; }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default is , in which case there is no destroy method.
- ///
- ///
- new string DestroyMethodName { get; set; }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The static method will be invoked on
- /// the specified .
- ///
+ /// If , an object factory will apply the Prototype
+ /// design pattern, with each caller requesting an instance getting an
+ /// independent instance. How this is defined will depend on the
+ /// object factory implementation. Singletons are the commoner type.
+ ///
+ ///
+ new bool IsSingleton { get; set; }
+
+ ///
+ /// Is this object lazily initialized?
+ ///
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup by object factories
+ /// that perform eager initialization of singletons.
+ ///
+ ///
+ new bool IsLazyInit { get; set; }
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. Default is
+ /// ,
+ /// which means there's no autowire.
+ ///
+ ///
+ new AutoWiringMode AutowireMode { get; set; }
+
+ ///
+ /// The dependency check code.
+ ///
+ DependencyCheckingMode DependencyCheck { get; set; }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before.
+ ///
+ ///
+ /// Note that dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies like statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ new string[] DependsOn { get; set; }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no initializer method.
+ ///
+ ///
+ new string InitMethodName { get; set; }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no destroy method.
+ ///
+ ///
+ new string DestroyMethodName { get; set; }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The static method will be invoked on
+ /// the specified .
+ ///
- /// If a name or parent object definition
- /// name is not unique, "#1", "#2" etc will be appended, until such
- /// time that the name becomes unique.
- ///
- ///
- public const string GeneratedObjectIdSeparator = "#";
-
- ///
- /// Registers the supplied with the
- /// supplied .
- ///
- ///
- ///
- /// This is a convenience method that registers the
- ///
- /// of the supplied under the
- ///
- /// property value of said . If the
- /// supplied has any
- /// ,
- /// then those aliases will also be registered with the supplied
- /// .
- ///
- ///
- ///
- /// The object definition holder containing the
- /// that
- /// is to be registered.
- ///
- ///
- /// The registry that the supplied
- /// is to be registered with.
- ///
- ///
- /// If either of the supplied arguments is .
- ///
- ///
- /// If the could not be registered
- /// with the .
- ///
- public static void RegisterObjectDefinition(
- ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry)
- {
- AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
- AssertUtils.ArgumentNotNull(registry, "registry");
-
- registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition);
- string[] aliases = objectDefinition.Aliases;
- for (int i = 0; i < aliases.Length; ++i)
- {
- string alias = aliases[i];
- registry.RegisterAlias(objectDefinition.ObjectName, alias);
- }
- }
-
- ///
- /// Generates an object definition name for the supplied
- /// that is guaranteed to be unique
- /// within the scope of the supplied .
- ///
- ///
- /// The
- /// that requires a generated name.
- ///
- ///
- /// The
- ///
- /// that the supplied is to be
- /// registered with (needed so that the uniqueness of any generated
- /// name can be guaranteed).
- ///
- ///
- /// An object definition name for the supplied
- /// that is guaranteed to be unique
- /// within the scope of the supplied and
- /// never .
- ///
- ///
- /// If either of the or
- /// arguments is .
- ///
- ///
- /// If a unique name cannot be generated.
- ///
- public static string GenerateObjectName(
- IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry)
- {
- AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
- AssertUtils.ArgumentNotNull(registry, "registry");
-
- string starterName = objectDefinition.ObjectTypeName;
- if (StringUtils.IsNullOrEmpty(starterName))
- {
- if (objectDefinition is ChildObjectDefinition)
- {
- starterName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child";
- }
- else if (objectDefinition.FactoryObjectName != null)
- {
- starterName = objectDefinition.FactoryObjectName + "$created";
- }
- }
- if (StringUtils.IsNullOrEmpty(starterName))
- {
- throw new ObjectDefinitionStoreException(
- objectDefinition.ResourceDescription, String.Empty,
- "Unnamed object definition specifies neither 'Type' nor 'Parent' " +
- "nor 'FactoryObject' property values so a unique name cannot be generated.");
- }
- String generatedName = starterName;
- int counter = 0;
- while (registry.ContainsObjectDefinition(generatedName))
- {
- generatedName = new StringBuilder(starterName)
- .Append(GeneratedObjectIdSeparator).Append(++counter).ToString();
- }
- return generatedName;
- }
-
- ///
- /// Factory method for getting concrete
- /// instances.
- ///
- ///
- /// The name of the event handler method. This may be straight text, a regular
- /// expression, , or empty.
- ///
- ///
- /// The name of the event being wired. This too may be straight text, a regular
- /// expression, , or empty.
- ///
- ///
- /// A concrete
- /// instance.
- ///
- public static IEventHandlerValue CreateEventHandlerValue(
- string methodName, string eventName)
- {
- bool weAreAutowiring = false;
- if (StringUtils.HasText(eventName))
- {
- // does the value contain regular expression characters? mmm, totally trent...
- if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+"))
- {
- // wildcarded event name
- weAreAutowiring = true;
- }
- }
- else
- {
- // we're definitely autowiring based on the event name
- weAreAutowiring = true;
- }
- if (!weAreAutowiring)
- {
- if (StringUtils.HasText(methodName))
- {
- // does the value contain the string ${event}?
- if (methodName.IndexOf("${event}") >= 0)
- {
- // wildcarded method name
- weAreAutowiring = true;
- }
- }
- else
- {
- // we're definitely autowiring based on the method name
- weAreAutowiring = true;
- }
- }
- IEventHandlerValue myHandler;
- if (weAreAutowiring)
- {
- myHandler = new AutoWiringEventHandlerValue();
- }
- else
- {
- myHandler = new InstanceEventHandlerValue();
- }
- myHandler.EventName = eventName;
- myHandler.MethodName = methodName;
- return myHandler;
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
+ /// If a name or parent object definition
+ /// name is not unique, "#1", "#2" etc will be appended, until such
+ /// time that the name becomes unique.
+ ///
+ ///
+ public const string GENERATED_OBJECT_NAME_SEPARATOR = ObjectFactoryUtils.GENERATED_OBJECT_NAME_SEPARATOR;
+
+ ///
+ /// Registers the supplied with the
+ /// supplied .
+ ///
+ ///
+ ///
+ /// This is a convenience method that registers the
+ ///
+ /// of the supplied under the
+ ///
+ /// property value of said . If the
+ /// supplied has any
+ /// ,
+ /// then those aliases will also be registered with the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// The object definition holder containing the
+ /// that
+ /// is to be registered.
+ ///
+ ///
+ /// The registry that the supplied
+ /// is to be registered with.
+ ///
+ ///
+ /// If either of the supplied arguments is .
+ ///
+ ///
+ /// If the could not be registered
+ /// with the .
+ ///
+ public static void RegisterObjectDefinition(
+ ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry)
+ {
+ AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
+ AssertUtils.ArgumentNotNull(registry, "registry");
+
+ registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition);
+ string[] aliases = objectDefinition.Aliases;
+ for (int i = 0; i < aliases.Length; ++i)
+ {
+ string alias = aliases[i];
+ registry.RegisterAlias(objectDefinition.ObjectName, alias);
+ }
+ }
+
+ ///
+ /// Generates an object definition name for the supplied
+ /// that is guaranteed to be unique
+ /// within the scope of the supplied .
+ ///
+ /// The
+ /// that requires a generated name.
+ /// The
+ ///
+ /// that the supplied is to be
+ /// registered with (needed so that the uniqueness of any generated
+ /// name can be guaranteed).
+ /// if set to true if the given object
+ /// definition will be registed as an inner object or as a top level objener objects
+ /// verses top level objects.
+ ///
+ /// An object definition name for the supplied
+ /// that is guaranteed to be unique
+ /// within the scope of the supplied and
+ /// never .
+ ///
+ ///
+ /// If either of the or
+ /// arguments is .
+ ///
+ ///
+ /// If a unique name cannot be generated.
+ ///
+ public static string GenerateObjectName(
+ IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry, bool isInnerObject)
+ {
+ AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
+ AssertUtils.ArgumentNotNull(registry, "registry");
+
+ string generatedObjectName = objectDefinition.ObjectTypeName;
+ if (StringUtils.IsNullOrEmpty(generatedObjectName))
+ {
+ if (objectDefinition is ChildObjectDefinition)
+ {
+ generatedObjectName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child";
+ }
+ else if (objectDefinition.FactoryObjectName != null)
+ {
+ generatedObjectName = objectDefinition.FactoryObjectName + "$created";
+ }
+ }
+ if (StringUtils.IsNullOrEmpty(generatedObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ objectDefinition.ResourceDescription, String.Empty,
+ "Unnamed object definition specifies neither 'Type' nor 'Parent' " +
+ "nor 'FactoryObject' property values so a unique name cannot be generated.");
+ }
+ String id = generatedObjectName;
+ if (isInnerObject)
+ {
+ id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + ObjectUtils.GetIdentityHexString(objectDefinition);
+ } else
+ {
+ int counter = -1;
+ while (counter == -1 && registry.ContainsObjectDefinition(id))
+ {
+ counter++;
+ id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + counter;
+ }
+ }
+
+ return id;
+ }
+
+ ///
+ /// Generates the name of the object for a top-level object definition unique within the given object factory.
+ ///
+ /// The object definition to generate an object name for.
+ /// The registry to check for existing names.
+ /// The generated object name
+ /// if no unique name can be generated for the given
+ /// object definition
+ public static string GenerateObjectName(IConfigurableObjectDefinition definition, IObjectDefinitionRegistry registry)
+ {
+ return GenerateObjectName(definition, registry, false);
+ }
+
+ ///
+ /// Factory method for getting concrete
+ /// instances.
+ ///
+ ///
+ /// The name of the event handler method. This may be straight text, a regular
+ /// expression, , or empty.
+ ///
+ ///
+ /// The name of the event being wired. This too may be straight text, a regular
+ /// expression, , or empty.
+ ///
+ ///
+ /// A concrete
+ /// instance.
+ ///
+ public static IEventHandlerValue CreateEventHandlerValue(
+ string methodName, string eventName)
+ {
+ bool weAreAutowiring = false;
+ if (StringUtils.HasText(eventName))
+ {
+ // does the value contain regular expression characters? mmm, totally trent...
+ if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+"))
+ {
+ // wildcarded event name
+ weAreAutowiring = true;
+ }
+ }
+ else
+ {
+ // we're definitely autowiring based on the event name
+ weAreAutowiring = true;
+ }
+ if (!weAreAutowiring)
+ {
+ if (StringUtils.HasText(methodName))
+ {
+ // does the value contain the string ${event}?
+ if (methodName.IndexOf("${event}") >= 0)
+ {
+ // wildcarded method name
+ weAreAutowiring = true;
+ }
+ }
+ else
+ {
+ // we're definitely autowiring based on the method name
+ weAreAutowiring = true;
+ }
+ }
+ IEventHandlerValue myHandler;
+ if (weAreAutowiring)
+ {
+ myHandler = new AutoWiringEventHandlerValue();
+ }
+ else
+ {
+ myHandler = new InstanceEventHandlerValue();
+ }
+ myHandler.EventName = eventName;
+ myHandler.MethodName = methodName;
+ return myHandler;
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
+ ///
+ private ObjectDefinitionReaderUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs
new file mode 100644
index 00000000..e8ab0622
--- /dev/null
+++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs
@@ -0,0 +1,353 @@
+#region License
+
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using Spring.Core.TypeConversion;
+using Spring.Core.TypeResolution;
+using Spring.Expressions;
+using Spring.Objects.Factory.Config;
+using Spring.Util;
+
+namespace Spring.Objects.Factory.Support
+{
+ ///
+ /// Helper class for use in object factory implementations,
+ /// resolving values contained in object definition objects
+ /// into the actual values applied to the target object instance.
+ ///
+ ///
+ /// Used by .
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ public class ObjectDefinitionValueResolver
+ {
+ private readonly AbstractObjectFactory objectFactory;
+ private readonly string objectName;
+ private readonly IObjectDefinition objectDefinition;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object factory.
+ /// Name of the object.
+ /// The object definition.
+ public ObjectDefinitionValueResolver(AbstractObjectFactory objectFactory, string objectName,
+ IObjectDefinition objectDefinition)
+ {
+ this.objectFactory = objectFactory;
+ this.objectName = objectName;
+ this.objectDefinition = objectDefinition;
+ }
+
+ ///
+ /// Given a property value, return a value, resolving any references to other
+ /// objects in the factory if necessary.
+ ///
+ ///
+ ///
+ /// The value could be :
+ ///
+ ///
+ ///
+ /// An ,
+ /// which leads to the creation of a corresponding new object instance.
+ /// Singleton flags and names of such "inner objects" are always ignored: inner objects
+ /// are anonymous prototypes.
+ ///
+ ///
+ ///
+ ///
+ /// A , which must
+ /// be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An . This is a
+ /// special placeholder collection that may contain
+ /// s or
+ /// collections that will need to be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An ordinary object or , in which case it's left alone.
+ ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- [
- NamespaceParser(
- Namespace = "http://www.springframework.net",
- SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser),
- SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-1.1.xsd"
- )
- ]
- public class ObjectsNamespaceParser : INamespaceParser
- {
- ///
- /// The namespace URI for the standard Spring.NET object definition schema.
- ///
- public const string Namespace = "http://www.springframework.net";
-
- ///
- /// The shared instance for this class (and derived classes).
- ///
- protected static readonly ILog log =
- LogManager.GetLogger(typeof(ObjectsNamespaceParser));
-
- #region IXmlObjectDefinitionParser Members
-
- ///
- /// Invoked by after construction but before any
- /// elements have been parsed.
- ///
- /// This is a NoOp
- public void Init()
- {
-
- }
-
- #endregion
-
-
- ///
- /// Parse the specified element and register any resulting
- /// IObjectDefinitions with the IObjectDefinitionRegistry that is
- /// embedded in the supplied ParserContext.
- ///
- /// The element to be parsed into one or more IObjectDefinitions
- /// The object encapsulating the current state of the parsing
- /// process.
- ///
- /// The primary IObjectDefinition (can be null as explained above)
- ///
- ///
- /// Implementations should return the primary IObjectDefinition
- /// that results from the parse phase if they wish to used nested
- /// inside (for example) a <property> tag.
- /// Implementations may return null if they will not
- /// be used in a nested scenario.
- ///
- ///
- public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
- {
-
- if (element.LocalName == ObjectDefinitionConstants.ImportElement)
- {
- ImportObjectDefinitionResource(element, parserContext);
- }
- else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
- {
- ParseAlias(element, parserContext.ReaderContext.Registry);
- }
- else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
- {
- RegisterObjectDefinition(element, parserContext);
- }
-
- return null;
- }
-
-
- ///
- /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder,
- /// returning the decorated definition.
- ///
- /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on
- /// whether a custom attribute or element is being parsed.
- /// Implementations may choose to return a completely new definition,
- /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory.
- ///
- /// The supplied ParserContext can be used to register any additional objects needed to support
- /// the main definition.
- ///
- /// The source element or attribute that is to be parsed.
- /// The current object definition.
- /// The object encapsulating the current state of the parsing
- /// process.
- /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory),
- /// or simply the original object definition if no decoration is required. A null value is strickly
- /// speaking invalid, but will leniently treated like the case where the original object definition
- /// gets returned.
- public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition,
- ParserContext parserContext)
- {
- return null;
- }
-
- private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
- {
- string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
- registry.RegisterAlias(name, alias);
- }
-
-
-
-
- ///
- /// Loads external XML object definitions from the resource described by the supplied
- /// .
- ///
- /// The XML element describing the resource.
- /// The parser context.
- ///
- /// If the resource could not be imported.
- ///
- protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext)
- {
- string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
- try
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Attempting to import object definitions from '{0}'.", location));
- }
-
- #endregion
-
- IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location);
- parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource);
- }
- catch (IOException ex)
- {
- parserContext.ReaderContext.ReportException(resource, null, string.Format(
- CultureInfo.InvariantCulture,
- "Invalid relative resource location '{0}' to import object definitions from.",
- location), ex);
- }
- }
-
-
- /// Parses an event listener definition.
- ///
- /// The name associated with the object that the event handler is being defined on.
- ///
- /// The events being populated.
- ///
- /// The element containing the event listener definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual void ParseEventListenerDefinition(
- string name, EventValues events, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- // get an appropriate IEventHandlerValue instance based upon the
- // attribute values of the listener element...
- IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue(
- element.GetAttribute(ObjectDefinitionConstants.ListenerMethodAttribute),
- element.GetAttribute(ObjectDefinitionConstants.ListenerEventAttribute));
-
- // and then get the source of the event (another managed object instance
- // or a Type reference (i.e. a static event exposed on a class)...
- XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement;
-
- XmlAttribute sourceAtt = sourceElement.Attributes[0];
- if (StringUtils.IsNullOrEmpty(sourceAtt.Value))
- {
- parserHelper.ReaderContext.ReportFatalException(sourceElement, string.Format(
- CultureInfo.InvariantCulture,
- "The single attribute of the <{0}/> element cannot be empty. Specify the " +
- "object id (alias) or the full, assembly qualified Type name that is the " +
- "source of the event.",
- ObjectDefinitionConstants.RefElement));
- return;
- }
- switch (sourceAtt.LocalName)
- {
- case ObjectDefinitionConstants.LocalRefAttribute:
- case ObjectDefinitionConstants.ObjectRefAttribute:
- // we're wiring up to an event exposed on another managed object (instance)
- RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value);
- myHandler.Source = ror;
- break;
- case ObjectDefinitionConstants.TypeAttribute:
- // we're wiring up to a static event exposed on a Type (class)
- myHandler.Source = parserHelper.ReaderContext.Reader.Domain == null ?
- (object) sourceAtt.Value :
- (object)TypeResolutionUtils.ResolveType(sourceAtt.Value);
- break;
- }
- events.AddHandler(myHandler);
- }
-
-
-
- ///
- /// Parse an object definition and register it with the object factory..
- ///
- /// The element containing the object definition.
- /// The parser context.
- ///
- protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext)
- {
- ObjectDefinitionHolder holder = null;
- try
- {
- holder = ParseObjectDefinition(element, parserContext);
- if (holder == null)
- {
- return;
- }
- }
- catch (Exception ex)
- {
- throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
- }
-
-
- holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(
- CultureInfo.InvariantCulture,
- "Registering object definition with id '{0}'.", holder.ObjectName));
- }
-
- #endregion
-
- ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry);
- }
-
-
- ///
- /// Parse a standard object definition into a
- /// ,
- /// including object name and aliases.
- ///
- /// The element containing the object definition.
- /// The parser context.
- ///
- /// The object (definition) wrapped within an
- ///
- /// instance.
- ///
- ///
- ///
- /// Object elements specify their canonical name via the "id" attribute
- /// and their aliases as a delimited "name" attribute.
- ///
- ///
- /// If no "id" is specified, uses the first name in the "name" attribute
- /// as the canonical name, registering all others as aliases.
- ///
- ///
- protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext)
- {
- string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
- string name = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- ArrayList aliases = new ArrayList();
- if (StringUtils.HasText(name))
- {
- aliases.AddRange(GetObjectNames(name));
- }
- // if we ain't got an id, check if object is page definition or assign any existing (first) alias...
- if (StringUtils.IsNullOrEmpty(id))
- {
- id = CalculateId(element, aliases);
- }
-
-
- IConfigurableObjectDefinition definition = ParseObjectDefinition(element, id, parserContext.ParserHelper);
- if (StringUtils.IsNullOrEmpty(id))
- {
- id = ObjectDefinitionReaderUtils.GenerateObjectName(definition, parserContext.Registry);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "Neither XML '{0}' nor '{1}' specified - using object " +
- "class name [{2}] as the id.",
- id, ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute));
- }
-
- #endregion
- }
- string[] aliasesArray = (string[]) aliases.ToArray(typeof(string));
- return new ObjectDefinitionHolder(definition, id, aliasesArray);
- }
-
- ///
- /// Calculates an id for an object definition.
- ///
- ///
- ///
- /// Called when an object definition has not been explicitly defined
- /// with an id.
- ///
- ///
- ///
- /// The element containing the object definition.
- ///
- ///
- /// The list of names defined for the object; may be
- /// or even empty.
- ///
- ///
- /// A calculated object definition id.
- ///
- protected virtual string CalculateId(XmlElement element, ArrayList aliases)
- {
- string id = null;
- if (aliases.Count > 0)
- {
- string firstAlias = aliases[0] as string;
- aliases.RemoveAt(0);
- id = firstAlias;
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- StringBuilder buffer = new StringBuilder();
- foreach (string alias in aliases)
- {
- buffer.Append(alias).Append(",");
- }
- log.Debug(string.Format("No XML 'id' specified - using '{0}' as the id and '{1}' as aliases.",
- id, buffer.ToString()));
- }
-
- #endregion
-
- return id;
- }
-
- ///
- /// Parse a standard object definition.
- ///
- /// The element containing the object definition.
- /// The id of the object definition.
- /// parsing state holder
- /// The object (definition).
- protected virtual IConfigurableObjectDefinition ParseObjectDefinition(
- XmlElement element, string id, ObjectDefinitionParserHelper parserHelper)
- {
- string typeName = null;
- try
- {
- if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute))
- {
- typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- if (StringUtils.IsNullOrEmpty(typeName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, id,
- "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + typeName + "'.");
- }
- }
- string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
-
-
- AbstractObjectDefinition od
- = parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
- typeName, parent, parserHelper.ReaderContext.Reader.Domain);
-
-
- MutablePropertyValues pvs = GetPropertyValueSubElements(id, element, parserHelper);
- ConstructorArgumentValues arguments
- = GetConstructorArgSubElements(id, element, parserHelper);
- EventValues events = GetEventHandlerSubElements(id, element, parserHelper);
- MethodOverrides methodOverrides = GetMethodOverrideSubElements(id, element, parserHelper);
-
- bool isPage = StringUtils.HasText(typeName) && typeName!= null && typeName.ToLower().EndsWith(".aspx");
- if (!isPage)
- {
- od.ConstructorArgumentValues = arguments;
- }
-
- od.PropertyValues = pvs;
- od.MethodOverrides = methodOverrides;
- od.EventHandlerValues = events;
- if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute))
- {
- string dependsOn = element.GetAttribute(ObjectDefinitionConstants.DependsOnAttribute);
- od.DependsOn = GetObjectNames(dependsOn);
- }
- od.FactoryMethodName = element.GetAttribute(ObjectDefinitionConstants.FactoryMethodAttribute);
- od.FactoryObjectName = element.GetAttribute(ObjectDefinitionConstants.FactoryObjectAttribute);
- string dependencyCheck = element.GetAttribute(ObjectDefinitionConstants.DependencyCheckAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck))
- {
- dependencyCheck = parserHelper.Defaults.DependencyCheck;
- }
- od.DependencyCheck = GetDependencyCheck(dependencyCheck);
- string autowire = element.GetAttribute(ObjectDefinitionConstants.AutowireAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(autowire))
- {
- autowire = parserHelper.Defaults.Autowire;
- }
- od.AutowireMode = GetAutowireMode(autowire);
- string initMethodName = element.GetAttribute(ObjectDefinitionConstants.InitMethodAttribute);
- if (StringUtils.HasText(initMethodName))
- {
- od.InitMethodName = initMethodName;
- }
- string destroyMethodName = element.GetAttribute(ObjectDefinitionConstants.DestroyMethodAttribute);
- if (StringUtils.HasText(destroyMethodName))
- {
- od.DestroyMethodName = destroyMethodName;
- }
- if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute))
- {
- od.IsSingleton = IsTrueStringValue(element.GetAttribute(ObjectDefinitionConstants.SingletonAttribute).ToLower(CultureInfo.CurrentCulture));
- }
- string lazyInit = element.GetAttribute(ObjectDefinitionConstants.LazyInitAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton)
- {
- // just apply default to singletons, as lazy-init has no meaning for prototypes...
- lazyInit = parserHelper.Defaults.LazyInit;
- }
- od.IsLazyInit = IsTrueStringValue(lazyInit);
-
- // try to get the line info
- string resourceDescription = parserHelper.ReaderContext.Resource.Description;
- if (StringUtils.HasText(resourceDescription))
- {
- int line = ConfigurationUtils.GetLineNumber(element);
- if (line > 0)
- {
- resourceDescription += " line " + line;
- }
- }
- od.ResourceDescription = resourceDescription;
-
- string isAbstract = element.GetAttribute(ObjectDefinitionConstants.AbstractAttribute);
- if (StringUtils.HasText(isAbstract))
- {
- od.IsAbstract = IsTrueStringValue(isAbstract);
- }
- return od;
- }
- catch (TypeLoadException ex)
- {
- parserHelper.ReaderContext.ReportException(
- element,
- id,
- string.Format(
- "Object class [{0}] not found.",
- typeName),
- ex);
- }
- catch (ApplicationException ex)
- {
- parserHelper.ReaderContext.ReportException(element, id, string.Empty, ex);
- }
- return null;
- }
-
- ///
- /// Parse method override argument subelements of the given object element.
- ///
- protected MethodOverrides GetMethodOverrideSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- MethodOverrides overrides = new MethodOverrides();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement))
- {
- ParseLookupMethodElement(name, overrides, (XmlElement) node, parserHelper);
- }
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement))
- {
- ParseReplacedMethodElement(name, overrides, (XmlElement) node, parserHelper);
- }
- return overrides;
- }
-
- ///
- /// Parse element and add parsed element to
- ///
- protected void ParseLookupMethodElement(
- string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string methodName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodNameAttribute);
- string targetObjectName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodObjectNameAttribute);
- if (StringUtils.IsNullOrEmpty(methodName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
- }
- if (StringUtils.IsNullOrEmpty(targetObjectName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
- }
- overrides.Add(new LookupMethodOverride(methodName, targetObjectName));
- }
-
- ///
- /// Parse element and add parsed element to
- ///
- protected void ParseReplacedMethodElement(
- string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string methodName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodNameAttribute);
- string targetReplacerObjectName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute);
- if (StringUtils.IsNullOrEmpty(methodName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
- }
- if (StringUtils.IsNullOrEmpty(targetReplacerObjectName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
- }
- ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName);
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement))
- {
- XmlElement argElement = (XmlElement) node;
- string match = argElement.GetAttribute(ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute);
- if (StringUtils.IsNullOrEmpty(match))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement));
- }
- theOverride.AddTypeIdentifier(match);
- }
- overrides.Add(theOverride);
- }
-
- ///
- /// Parse constructor argument subelements of the given object element.
- ///
- protected ConstructorArgumentValues GetConstructorArgSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- ConstructorArgumentValues arguments = new ConstructorArgumentValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement))
- {
- ParseConstructorArgElement(name, arguments, (XmlElement) node, parserHelper);
- }
- return arguments;
- }
-
- ///
- /// Parse event handler subelements of the given object element.
- ///
- protected EventValues GetEventHandlerSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- EventValues events = new EventValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement))
- {
- ParseEventListenerDefinition(name, events, (XmlElement) node, parserHelper);
- }
- return events;
- }
-
- ///
- /// Parse property value subelements of the given object element.
- ///
- ///
- /// The name of the object (definition) associated with the property element (s)
- ///
- ///
- /// The element containing the top level object definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- ///
- /// The property (s) associated with the object (definition).
- ///
- protected virtual MutablePropertyValues GetPropertyValueSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- MutablePropertyValues properties = new MutablePropertyValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement))
- {
- ParsePropertyElement(name, properties, (XmlElement) node, parserHelper);
- }
- return properties;
- }
-
- ///
- /// Parse a constructor-arg element.
- ///
- ///
- /// The name of the object (definition) associated with the ctor arg.
- ///
- ///
- /// The list of constructor args associated with the object (definition).
- ///
- ///
- /// The name of the element containing the ctor arg definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual void ParseConstructorArgElement(
- string name, ConstructorArgumentValues arguments, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- object val = GetPropertyValue(element, name, parserHelper);
- string indexAttr = element.GetAttribute(ObjectDefinitionConstants.IndexAttribute);
- string typeAttr = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- string nameAttr = element.GetAttribute(ObjectDefinitionConstants.ArgumentNameAttribute);
-
- // only one of the 'index' or 'name' attributes can be present
- if (StringUtils.HasText(indexAttr)
- && StringUtils.HasText(nameAttr))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "Only one of the 'index' or 'name' attributes can be present per constructor argument.");
- }
- if (StringUtils.HasText(indexAttr))
- {
- try
- {
- int index = int.Parse(indexAttr, CultureInfo.CurrentCulture);
- if (index < 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "'index' cannot be lower than 0");
- }
- if (StringUtils.HasText(typeAttr))
- {
- arguments.AddIndexedArgumentValue(index, val, typeAttr);
- }
- else
- {
- arguments.AddIndexedArgumentValue(index, val);
- }
- }
- catch (FormatException)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "Attribute 'index' of tag 'constructor-arg' must be an integer value.");
- }
- }
- else if (StringUtils.HasText(nameAttr))
- {
- if (StringUtils.HasText(typeAttr))
- {
- if (log.IsWarnEnabled)
- {
- log.Warn("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element.");
- }
- }
- arguments.AddNamedArgumentValue(nameAttr, val);
- }
- else
- {
- if (StringUtils.HasText(typeAttr))
- {
- arguments.AddGenericArgumentValue(val, typeAttr);
- }
- else
- {
- arguments.AddGenericArgumentValue(val);
- }
- }
- }
-
- ///
- /// Parse a property element.
- ///
- ///
- /// The name of the object (definition) associated with the property.
- ///
- ///
- /// The list of properties associated with the object (definition).
- ///
- ///
- /// The name of the element containing the property definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected void ParsePropertyElement(
- string name, MutablePropertyValues properties, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string propertyName = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- if (StringUtils.IsNullOrEmpty(propertyName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "The 'property' element must have a 'name' attribute");
- }
- object val = GetPropertyValue(element, name, parserHelper);
- properties.Add(new PropertyValue(propertyName, val));
- }
-
- ///
- /// Get the value of a property element (may be a list).
- ///
- ///
- /// Please note that even though this method is named GetPropertyValue,
- /// it is called by both the property and constructor argument element
- /// handlers.
- ///
- ///
- /// The property element.
- ///
- /// The name of the object associated with the property.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual object GetPropertyValue(
- XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute];
- if (inlineValueAtt != null)
- {
- return inlineValueAtt.Value;
- }
- XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute];
- if (inlineRefAtt != null)
- {
- return new RuntimeObjectReference(inlineRefAtt.Value);
- }
- XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
- if (inlineExpressionAtt != null)
- {
- return new ExpressionHolder(inlineExpressionAtt.Value);
- }
-
- // should only have one element child: value, ref, collection...
- XmlNodeList nodes = element.ChildNodes;
- XmlElement valueRefOrCollectionElement = null;
- for (int i = 0; i < nodes.Count; ++i)
- {
- XmlElement candidateEle = nodes.Item(i) as XmlElement;
- if (candidateEle != null)
- {
- if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name))
- {
- // keep going: we don't use this value for now...
- }
- else
- {
- // child element is what we're looking for...
- valueRefOrCollectionElement = candidateEle;
- }
- }
- }
- if (valueRefOrCollectionElement == null)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "The '' element must have a subelement such as 'value' or 'ref'.");
- }
- return ParsePropertySubElement(valueRefOrCollectionElement, name, parserHelper);
- }
-
- ///
- /// Parse a value, ref or collection subelement of a property element.
- ///
- ///
- /// Subelement of property element; we don't know which yet.
- ///
- ///
- /// The name of the object (definition) associated with the top level property.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual object ParsePropertySubElement(
- XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- if (element.Name.Equals(ObjectDefinitionConstants.ObjectElement))
- {
- return ParseObjectDefinition(element, "(inner object definition)", parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.RefElement))
- {
- return GetReference(element, parserHelper, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.IdRefElement))
- {
- return GetObjectReference(element, parserHelper, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ListElement))
- {
- return GetList(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.SetElement))
- {
- return GetSet(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.DictionaryElement))
- {
- return GetDictionary(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.NameValuesElement))
- {
- return GetNameValues(element, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ValueElement))
- {
- return GetValue(element, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ExpressionElement))
- {
- return GetExpression(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.NullElement))
- {
- // it's a distinguished null value...
- return null;
- }
- else
- {
- // it may match another Parser
- INamespaceParser otherParser = GetParser(element.NamespaceURI);
- if (otherParser != null)
- {
- // The other parser uses nestings tags and thus returns the definition
- // of the parsed object.
- return otherParser.ParseElement(element, new ParserContext(parserHelper.ReaderContext, parserHelper));
- }
- }
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Unknown subelement of : <" + element.Name + ">");
- }
-
- private static INamespaceParser GetParser(string nspace)
- {
- // finds the configuration parser for the given namespace
- try
- {
- return NamespaceParserRegistry.GetParser(nspace);
- }
- catch (Exception)
- {
- // The parser for the given namespace is not found
- return null;
- }
- }
-
- private static object GetObjectReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
- {
- // a generic reference to any name of any object
- string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // a reference to the id of another object in the same XML file
- objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Either 'object' or 'local' is required for an idref");
- }
- }
- return objectRef;
- }
-
- private object GetReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
- {
- // is it a generic reference to any name of any object?
- string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // is it a reference to the id of another object in the same XML file?
- objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // is it a reference to the id of another object in a parent context?
- objectRef = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Either 'object' or 'local' is required for a reference");
- }
- return new RuntimeObjectReference(objectRef, true);
- }
- }
- return new RuntimeObjectReference(objectRef);
- }
-
- private object GetValue(XmlElement element, string name)
- {
- string valueType = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- if (StringUtils.IsNullOrEmpty(valueType))
- {
- return GetTextValue(element, name);
- }
- else
- {
- Type resolvedValueType = TypeResolutionUtils.ResolveType(valueType);
- if (resolvedValueType == typeof(string))
- {
- return GetTextValue(element, name);
- }
- else
- {
- return new TypedStringValue(GetTextValue(element, name), resolvedValueType);
- }
- }
- }
-
- private object GetExpression(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- string expression = element.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
- ExpressionHolder holder = new ExpressionHolder(expression);
- holder.Properties = GetPropertyValueSubElements(name, element, parserHelper);
- return holder;
- }
-
- ///
- /// Gets a list definition.
- ///
- ///
- /// The element describing the list definition.
- ///
- ///
- /// The name of the object (definition) associated with the list definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The list definition.
- protected virtual IList GetList(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedList list = new ManagedList();
-
- string elementTypeName = element.GetAttribute("element-type");
- if (StringUtils.HasText(elementTypeName))
- {
- list.ElementTypeName = elementTypeName;
- }
-
- foreach (XmlNode node in element.ChildNodes)
- {
- XmlElement ele = node as XmlElement;
- if (ele != null)
- {
- list.Add(ParsePropertySubElement(ele, name, parserHelper));
- }
- }
- return list;
- }
-
- ///
- /// Gets a set definition.
- ///
- ///
- /// The element describing the set definition.
- ///
- ///
- /// The name of the object (definition) associated with the set definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The set definition.
- protected Set GetSet(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedSet theSet = new ManagedSet();
- string elementTypeName = element.GetAttribute("element-type");
- if (StringUtils.HasText(elementTypeName))
- {
- theSet.ElementTypeName = elementTypeName;
- }
- foreach (XmlNode node in element.ChildNodes)
- {
- XmlElement ele = node as XmlElement;
- if (ele != null)
- {
- object sub = ParsePropertySubElement(ele, name, parserHelper);
- theSet.Add(sub);
- }
- }
- return theSet;
- }
-
- ///
- /// Gets a dictionary definition.
- ///
- ///
- /// The element describing the dictionary definition.
- ///
- ///
- /// The name of the object (definition) associated with the dictionary definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The dictionary definition.
- protected IDictionary GetDictionary(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedDictionary dictionary = new ManagedDictionary();
- string keyTypeName = element.GetAttribute("key-type");
- string valueTypeName = element.GetAttribute("value-type");
- if (StringUtils.HasText(keyTypeName))
- {
- dictionary.KeyTypeName = keyTypeName;
- }
- if (StringUtils.HasText(valueTypeName))
- {
- dictionary.ValueTypeName = valueTypeName;
- }
-
- XmlNodeList entryElements = SelectNodes(element, ObjectDefinitionConstants.EntryElement);
- foreach (XmlElement entryEle in entryElements)
- {
- #region Key
-
- object key = null;
-
- XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute];
- if (keyAtt != null)
- {
- key = keyAtt.Value;
- }
- else
- {
- // ok, we're not using the 'key' attribute; lets check for the ref shortcut...
- XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute];
- if (keyRefAtt != null)
- {
- key = new RuntimeObjectReference(keyRefAtt.Value);
- }
- else
- {
- // so check for the 'key' element...
- XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
- if (keyNode == null)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " +
- "is required for the <{3}/> element.",
- ObjectDefinitionConstants.KeyElement,
- ObjectDefinitionConstants.KeyAttribute,
- ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute,
- ObjectDefinitionConstants.EntryElement));
- }
- XmlElement keyElement = (XmlElement) keyNode;
- XmlNodeList keyNodes = keyElement.GetElementsByTagName("*");
- if (keyNodes == null || keyNodes.Count == 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("Malformed <{0}/> element... the value of the key must be " +
- "specified as a child value-style element.",
- ObjectDefinitionConstants.KeyElement));
- }
- key = ParsePropertySubElement((XmlElement) keyNodes.Item(0), name, parserHelper);
- }
- }
-
- #endregion
-
- #region Value
-
- XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute];
- if (inlineValueAtt != null)
- {
- // ok, we're using the value attribute shortcut...
- dictionary[key] = inlineValueAtt.Value;
- }
- else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null)
- {
- // ok, we're using the value-ref attribute shortcut...
- XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute];
- RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value);
- dictionary[key] = ror;
- }
- else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null)
- {
- // ok, we're using the expression attribute shortcut...
- XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
- ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value);
- dictionary[key] = expHolder;
- }
- else
- {
- XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
- if (keyNode != null)
- {
- entryEle.RemoveChild(keyNode);
- }
- // ok, we're using the original full-on value element...
- XmlNodeList valueElements = entryEle.GetElementsByTagName("*");
- if (valueElements == null || valueElements.Count == 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " +
- "is required for the <{2}/> element.",
- ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement));
- }
- dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserHelper);
- }
-
- #endregion
- }
- return dictionary;
- }
-
- ///
- /// Selects sub-elements with a given
- /// name.
- ///
- ///
- ///
- /// Uses a namespace manager if necessary.
- ///
- ///
- ///
- /// The element to be searched in.
- ///
- ///
- /// The name of the child nodes to look for.
- ///
- ///
- /// The child s of the supplied
- /// with the supplied
- /// .
- ///
- protected XmlNodeList SelectNodes(XmlElement element, string childElementName)
- {
- XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
- nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
- return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
- }
-
- ///
- /// Selects a single sub-element with a given
- /// name.
- ///
- ///
- ///
- /// Uses a namespace manager if necessary.
- ///
- ///
- ///
- /// The element to be searched in.
- ///
- ///
- /// The name of the child node to look for.
- ///
- ///
- /// The first child of the supplied
- /// with the supplied
- /// .
- ///
- protected XmlNode SelectSingleNode(XmlElement element, string childElementName)
- {
- XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
- nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
- return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
- }
-
- ///
- /// Gets a name value collection mapping definition.
- ///
- ///
- /// The element describing the name value collection mapping definition.
- ///
- ///
- /// The name of the object (definition) associated with the
- /// name value collection mapping definition.
- ///
- /// The name value collection definition.
- protected NameValueCollection GetNameValues(XmlElement element, string name)
- {
- NameValueCollection nvc = new NameValueCollection();
- XmlNodeList addElements = element.GetElementsByTagName(ObjectDefinitionConstants.AddElement);
- foreach (XmlElement addElement in addElements)
- {
- string key = addElement.GetAttribute(ObjectDefinitionConstants.KeyAttribute);
- string value = addElement.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
- string delimiters = addElement.GetAttribute(ObjectDefinitionConstants.DelimitersAttribute);
-
- if (StringUtils.HasText(delimiters))
- {
- string[] values = value.Split(delimiters.ToCharArray());
- foreach (string v in values)
- {
- nvc.Add(key, v);
- }
- }
- else
- {
- nvc[key] = value;
- }
- }
- return nvc;
- }
-
- ///
- /// Returns the text of the supplied ,
- /// or the empty string value if said is empty.
- ///
- ///
- ///
- /// If the supplied is ,
- /// then the empty string value will be returned.
- ///
- ///
- protected string GetTextValue(XmlElement element, string name)
- {
- if (element == null || StringUtils.IsNullOrEmpty(element.InnerText))
- {
- return String.Empty;
- }
- return element.InnerText;
- }
-
- ///
- /// Strips the dependency check value out of the supplied string.
- ///
- ///
- ///
- /// If the supplied is an invalid dependency
- /// checking mode, the invalid value will be logged and this method will
- /// return the value.
- /// No exception will be raised.
- ///
- /// If the supplied is an invalid autowiring mode,
- /// the invalid value will be logged and this method will return the
- /// value. No exception will be raised.
- ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [
+ NamespaceParser(
+ Namespace = "http://www.springframework.net",
+ SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser),
+ SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-1.1.xsd"
+ )
+ ]
+ public class ObjectsNamespaceParser : INamespaceParser
+ {
+ ///
+ /// The namespace URI for the standard Spring.NET object definition schema.
+ ///
+ public const string Namespace = "http://www.springframework.net";
+
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ protected static readonly ILog log =
+ LogManager.GetLogger(typeof(ObjectsNamespaceParser));
+
+ #region IXmlObjectDefinitionParser Members
+
+ ///
+ /// Invoked by after construction but before any
+ /// elements have been parsed.
+ ///
+ /// This is a NoOp
+ public void Init()
+ {
+
+ }
+
+ #endregion
+
+
+ ///
+ /// Parse the specified element and register any resulting
+ /// IObjectDefinitions with the IObjectDefinitionRegistry that is
+ /// embedded in the supplied ParserContext.
+ ///
+ /// The element to be parsed into one or more IObjectDefinitions
+ /// The object encapsulating the current state of the parsing
+ /// process.
+ ///
+ /// The primary IObjectDefinition (can be null as explained above)
+ ///
+ ///
+ /// Implementations should return the primary IObjectDefinition
+ /// that results from the parse phase if they wish to used nested
+ /// inside (for example) a <property> tag.
+ /// Implementations may return null if they will not
+ /// be used in a nested scenario.
+ ///
+ ///
+ public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+
+ if (element.LocalName == ObjectDefinitionConstants.ImportElement)
+ {
+ ImportObjectDefinitionResource(element, parserContext);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
+ {
+ ParseAlias(element, parserContext.ReaderContext.Registry);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
+ {
+ RegisterObjectDefinition(element, parserContext);
+ }
+
+ return null;
+ }
+
+
+ ///
+ /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder,
+ /// returning the decorated definition.
+ ///
+ /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on
+ /// whether a custom attribute or element is being parsed.
+ /// Implementations may choose to return a completely new definition,
+ /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory.
+ ///
+ /// The supplied ParserContext can be used to register any additional objects needed to support
+ /// the main definition.
+ ///
+ /// The source element or attribute that is to be parsed.
+ /// The current object definition.
+ /// The object encapsulating the current state of the parsing
+ /// process.
+ /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory),
+ /// or simply the original object definition if no decoration is required. A null value is strickly
+ /// speaking invalid, but will leniently treated like the case where the original object definition
+ /// gets returned.
+ public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition,
+ ParserContext parserContext)
+ {
+ return null;
+ }
+
+ private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
+ {
+ string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
+ registry.RegisterAlias(name, alias);
+ }
+
+
+
+
+ ///
+ /// Loads external XML object definitions from the resource described by the supplied
+ /// .
+ ///
+ /// The XML element describing the resource.
+ /// The parser context.
+ ///
+ /// If the resource could not be imported.
+ ///
+ protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext)
+ {
+ string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
+ try
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Attempting to import object definitions from '{0}'.", location));
+ }
+
+ #endregion
+
+ IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location);
+ parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource);
+ }
+ catch (IOException ex)
+ {
+ parserContext.ReaderContext.ReportException(resource, null, string.Format(
+ CultureInfo.InvariantCulture,
+ "Invalid relative resource location '{0}' to import object definitions from.",
+ location), ex);
+ }
+ }
+
+
+ /// Parses an event listener definition.
+ ///
+ /// The name associated with the object that the event handler is being defined on.
+ ///
+ /// The events being populated.
+ ///
+ /// The element containing the event listener definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual void ParseEventListenerDefinition(
+ string name, EventValues events, XmlElement element, ParserContext parserContext)
+ {
+ // get an appropriate IEventHandlerValue instance based upon the
+ // attribute values of the listener element...
+ IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue(
+ element.GetAttribute(ObjectDefinitionConstants.ListenerMethodAttribute),
+ element.GetAttribute(ObjectDefinitionConstants.ListenerEventAttribute));
+
+ // and then get the source of the event (another managed object instance
+ // or a Type reference (i.e. a static event exposed on a class)...
+ XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement;
+
+ XmlAttribute sourceAtt = sourceElement.Attributes[0];
+ if (StringUtils.IsNullOrEmpty(sourceAtt.Value))
+ {
+ parserContext.ReaderContext.ReportFatalException(sourceElement, string.Format(
+ CultureInfo.InvariantCulture,
+ "The single attribute of the <{0}/> element cannot be empty. Specify the " +
+ "object id (alias) or the full, assembly qualified Type name that is the " +
+ "source of the event.",
+ ObjectDefinitionConstants.RefElement));
+ return;
+ }
+ switch (sourceAtt.LocalName)
+ {
+ case ObjectDefinitionConstants.LocalRefAttribute:
+ case ObjectDefinitionConstants.ObjectRefAttribute:
+ // we're wiring up to an event exposed on another managed object (instance)
+ RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value);
+ myHandler.Source = ror;
+ break;
+ case ObjectDefinitionConstants.TypeAttribute:
+ // we're wiring up to a static event exposed on a Type (class)
+ myHandler.Source = parserContext.ReaderContext.Reader.Domain == null ?
+ (object) sourceAtt.Value :
+ (object)TypeResolutionUtils.ResolveType(sourceAtt.Value);
+ break;
+ }
+ events.AddHandler(myHandler);
+ }
+
+
+
+ ///
+ /// Parse an object definition and register it with the object factory..
+ ///
+ /// The element containing the object definition.
+ /// The parser context.
+ ///
+ protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext)
+ {
+ ObjectDefinitionHolder holder = null;
+ try
+ {
+ holder = ParseObjectDefinition(element, parserContext, false);
+ if (holder == null)
+ {
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
+ }
+
+
+ holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Registering object definition with id '{0}'.", holder.ObjectName));
+ }
+
+ #endregion
+
+ ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry);
+ }
+
+
+ ///
+ /// Parse a standard object definition into a
+ /// ,
+ /// including object name and aliases.
+ ///
+ /// The element containing the object definition.
+ /// The parser context.
+ /// if set to true if we are processing an inner
+ /// object definition.
+ ///
+ /// The object (definition) wrapped within an
+ ///
+ /// instance.
+ ///
+ ///
+ ///
+ /// Object elements specify their canonical name via the "id" attribute
+ /// and their aliases as a delimited "name" attribute.
+ ///
+ ///
+ /// If no "id" is specified, uses the first name in the "name" attribute
+ /// as the canonical name, registering all others as aliases.
+ ///
+ ///
+ protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext, bool nestedDefinition)
+ {
+ string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
+ string nameAttr = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ ArrayList aliases = new ArrayList();
+ if (StringUtils.HasText(nameAttr))
+ {
+ aliases.AddRange(GetObjectNames(nameAttr));
+ }
+
+ // if we ain't got an id, check if object is page definition or assign any existing (first) alias...
+ string objectName = id;
+ if (StringUtils.IsNullOrEmpty(objectName))
+ {
+ objectName = CalculateId(element, aliases);
+ }
+
+
+ IConfigurableObjectDefinition definition = ParseObjectDefinition(element, objectName, parserContext);
+ if (definition != null)
+ {
+ if (StringUtils.IsNullOrEmpty(objectName))
+ {
+ if (nestedDefinition)
+ {
+ objectName =
+ ObjectDefinitionReaderUtils.GenerateObjectName(definition, parserContext.Registry, true);
+ }
+ else
+ {
+ objectName = ObjectDefinitionReaderUtils.GenerateObjectName(definition, parserContext.Registry);
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "Neither XML '{0}' nor '{1}' specified - using object " +
+ "class name [{2}] as the id.",
+ id, ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute));
+ }
+
+ #endregion
+ }
+ string[] aliasesArray = (string[]) aliases.ToArray(typeof (string));
+ return new ObjectDefinitionHolder(definition, objectName, aliasesArray);
+ }
+ return null;
+ }
+
+ ///
+ /// Calculates an id for an object definition.
+ ///
+ ///
+ ///
+ /// Called when an object definition has not been explicitly defined
+ /// with an id.
+ ///
+ ///
+ ///
+ /// The element containing the object definition.
+ ///
+ ///
+ /// The list of names defined for the object; may be
+ /// or even empty.
+ ///
+ ///
+ /// A calculated object definition id.
+ ///
+ protected virtual string CalculateId(XmlElement element, ArrayList aliases)
+ {
+ string id = null;
+ if (aliases.Count > 0)
+ {
+ string firstAlias = aliases[0] as string;
+ aliases.RemoveAt(0);
+ id = firstAlias;
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ StringBuilder buffer = new StringBuilder();
+ foreach (string alias in aliases)
+ {
+ buffer.Append(alias).Append(",");
+ }
+ log.Debug(string.Format("No XML 'id' specified - using '{0}' as the id and '{1}' as aliases.",
+ id, buffer.ToString()));
+ }
+
+ #endregion
+
+ return id;
+ }
+
+ ///
+ /// Parse a standard object definition.
+ ///
+ /// The element containing the object definition.
+ /// The id of the object definition.
+ /// parsing state holder
+ /// The object (definition).
+ protected virtual IConfigurableObjectDefinition ParseObjectDefinition(
+ XmlElement element, string id, ParserContext parserContext)
+ {
+ string typeName = null;
+ try
+ {
+ if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute))
+ {
+ typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ if (StringUtils.IsNullOrEmpty(typeName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, id,
+ "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + typeName + "'.");
+ }
+ }
+ string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
+
+
+ AbstractObjectDefinition od
+ = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
+ typeName, parent, parserContext.ReaderContext.Reader.Domain);
+
+
+ MutablePropertyValues pvs = GetPropertyValueSubElements(id, element, parserContext);
+ ConstructorArgumentValues arguments
+ = GetConstructorArgSubElements(id, element, parserContext);
+ EventValues events = GetEventHandlerSubElements(id, element, parserContext);
+ MethodOverrides methodOverrides = GetMethodOverrideSubElements(id, element, parserContext);
+
+ bool isPage = StringUtils.HasText(typeName) && typeName!= null && typeName.ToLower().EndsWith(".aspx");
+ if (!isPage)
+ {
+ od.ConstructorArgumentValues = arguments;
+ }
+
+ od.PropertyValues = pvs;
+ od.MethodOverrides = methodOverrides;
+ od.EventHandlerValues = events;
+ if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute))
+ {
+ string dependsOn = element.GetAttribute(ObjectDefinitionConstants.DependsOnAttribute);
+ od.DependsOn = GetObjectNames(dependsOn);
+ }
+ od.FactoryMethodName = element.GetAttribute(ObjectDefinitionConstants.FactoryMethodAttribute);
+ od.FactoryObjectName = element.GetAttribute(ObjectDefinitionConstants.FactoryObjectAttribute);
+ string dependencyCheck = element.GetAttribute(ObjectDefinitionConstants.DependencyCheckAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck))
+ {
+ dependencyCheck = parserContext.ParserHelper.Defaults.DependencyCheck;
+ }
+ od.DependencyCheck = GetDependencyCheck(dependencyCheck);
+ string autowire = element.GetAttribute(ObjectDefinitionConstants.AutowireAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(autowire))
+ {
+ autowire = parserContext.ParserHelper.Defaults.Autowire;
+ }
+ od.AutowireMode = GetAutowireMode(autowire);
+ string initMethodName = element.GetAttribute(ObjectDefinitionConstants.InitMethodAttribute);
+ if (StringUtils.HasText(initMethodName))
+ {
+ od.InitMethodName = initMethodName;
+ }
+ string destroyMethodName = element.GetAttribute(ObjectDefinitionConstants.DestroyMethodAttribute);
+ if (StringUtils.HasText(destroyMethodName))
+ {
+ od.DestroyMethodName = destroyMethodName;
+ }
+ if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute))
+ {
+ od.IsSingleton = IsTrueStringValue(element.GetAttribute(ObjectDefinitionConstants.SingletonAttribute).ToLower(CultureInfo.CurrentCulture));
+ }
+ string lazyInit = element.GetAttribute(ObjectDefinitionConstants.LazyInitAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton)
+ {
+ // just apply default to singletons, as lazy-init has no meaning for prototypes...
+ lazyInit = parserContext.ParserHelper.Defaults.LazyInit;
+ }
+ od.IsLazyInit = IsTrueStringValue(lazyInit);
+
+ // try to get the line info
+ string resourceDescription = parserContext.ParserHelper.ReaderContext.Resource.Description;
+ if (StringUtils.HasText(resourceDescription))
+ {
+ int line = ConfigurationUtils.GetLineNumber(element);
+ if (line > 0)
+ {
+ resourceDescription += " line " + line;
+ }
+ }
+ od.ResourceDescription = resourceDescription;
+
+ string isAbstract = element.GetAttribute(ObjectDefinitionConstants.AbstractAttribute);
+ if (StringUtils.HasText(isAbstract))
+ {
+ od.IsAbstract = IsTrueStringValue(isAbstract);
+ }
+ return od;
+ }
+ catch (TypeLoadException ex)
+ {
+ parserContext.ReaderContext.ReportException(
+ element,
+ id,
+ string.Format(
+ "Object class [{0}] not found.",
+ typeName),
+ ex);
+ }
+ catch (ApplicationException ex)
+ {
+ parserContext.ReaderContext.ReportException(element, id, string.Empty, ex);
+ }
+ return null;
+ }
+
+ ///
+ /// Parse method override argument subelements of the given object element.
+ ///
+ protected MethodOverrides GetMethodOverrideSubElements(
+ string name, XmlElement element, ParserContext parserContext)
+ {
+ MethodOverrides overrides = new MethodOverrides();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement))
+ {
+ ParseLookupMethodElement(name, overrides, (XmlElement)node, parserContext);
+ }
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement))
+ {
+ ParseReplacedMethodElement(name, overrides, (XmlElement)node, parserContext);
+ }
+ return overrides;
+ }
+
+ ///
+ /// Parse element and add parsed element to
+ ///
+ protected void ParseLookupMethodElement(
+ string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext)
+ {
+ string methodName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodNameAttribute);
+ string targetObjectName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodObjectNameAttribute);
+ if (StringUtils.IsNullOrEmpty(methodName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
+ }
+ if (StringUtils.IsNullOrEmpty(targetObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
+ }
+ overrides.Add(new LookupMethodOverride(methodName, targetObjectName));
+ }
+
+ ///
+ /// Parse element and add parsed element to
+ ///
+ protected void ParseReplacedMethodElement(
+ string name, MethodOverrides overrides, XmlElement element, ParserContext parserContext)
+ {
+ string methodName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodNameAttribute);
+ string targetReplacerObjectName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute);
+ if (StringUtils.IsNullOrEmpty(methodName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
+ }
+ if (StringUtils.IsNullOrEmpty(targetReplacerObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
+ }
+ ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName);
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement))
+ {
+ XmlElement argElement = (XmlElement) node;
+ string match = argElement.GetAttribute(ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute);
+ if (StringUtils.IsNullOrEmpty(match))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement));
+ }
+ theOverride.AddTypeIdentifier(match);
+ }
+ overrides.Add(theOverride);
+ }
+
+ ///
+ /// Parse constructor argument subelements of the given object element.
+ ///
+ protected ConstructorArgumentValues GetConstructorArgSubElements(
+ string name, XmlElement element, ParserContext parserContext)
+ {
+ ConstructorArgumentValues arguments = new ConstructorArgumentValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement))
+ {
+ ParseConstructorArgElement(name, arguments, (XmlElement)node, parserContext);
+ }
+ return arguments;
+ }
+
+ ///
+ /// Parse event handler subelements of the given object element.
+ ///
+ protected EventValues GetEventHandlerSubElements(
+ string name, XmlElement element, ParserContext parserContext)
+ {
+ EventValues events = new EventValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement))
+ {
+ ParseEventListenerDefinition(name, events, (XmlElement)node, parserContext);
+ }
+ return events;
+ }
+
+ ///
+ /// Parse property value subelements of the given object element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the property element (s)
+ ///
+ ///
+ /// The element containing the top level object definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ ///
+ /// The property (s) associated with the object (definition).
+ ///
+ protected virtual MutablePropertyValues GetPropertyValueSubElements(
+ string name, XmlElement element, ParserContext parserContext)
+ {
+ MutablePropertyValues properties = new MutablePropertyValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement))
+ {
+ ParsePropertyElement(name, properties, (XmlElement) node, parserContext);
+ }
+ return properties;
+ }
+
+ ///
+ /// Parse a constructor-arg element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the ctor arg.
+ ///
+ ///
+ /// The list of constructor args associated with the object (definition).
+ ///
+ ///
+ /// The name of the element containing the ctor arg definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual void ParseConstructorArgElement(
+ string name, ConstructorArgumentValues arguments, XmlElement element, ParserContext parserContext)
+ {
+ object val = GetPropertyValue(element, name, parserContext);
+ string indexAttr = element.GetAttribute(ObjectDefinitionConstants.IndexAttribute);
+ string typeAttr = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ string nameAttr = element.GetAttribute(ObjectDefinitionConstants.ArgumentNameAttribute);
+
+ // only one of the 'index' or 'name' attributes can be present
+ if (StringUtils.HasText(indexAttr)
+ && StringUtils.HasText(nameAttr))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ "Only one of the 'index' or 'name' attributes can be present per constructor argument.");
+ }
+ if (StringUtils.HasText(indexAttr))
+ {
+ try
+ {
+ int index = int.Parse(indexAttr, CultureInfo.CurrentCulture);
+ if (index < 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ "'index' cannot be lower than 0");
+ }
+ if (StringUtils.HasText(typeAttr))
+ {
+ arguments.AddIndexedArgumentValue(index, val, typeAttr);
+ }
+ else
+ {
+ arguments.AddIndexedArgumentValue(index, val);
+ }
+ }
+ catch (FormatException)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ "Attribute 'index' of tag 'constructor-arg' must be an integer value.");
+ }
+ }
+ else if (StringUtils.HasText(nameAttr))
+ {
+ if (StringUtils.HasText(typeAttr))
+ {
+ if (log.IsWarnEnabled)
+ {
+ log.Warn("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element.");
+ }
+ }
+ arguments.AddNamedArgumentValue(nameAttr, val);
+ }
+ else
+ {
+ if (StringUtils.HasText(typeAttr))
+ {
+ arguments.AddGenericArgumentValue(val, typeAttr);
+ }
+ else
+ {
+ arguments.AddGenericArgumentValue(val);
+ }
+ }
+ }
+
+ ///
+ /// Parse a property element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the property.
+ ///
+ ///
+ /// The list of properties associated with the object (definition).
+ ///
+ ///
+ /// The name of the element containing the property definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected void ParsePropertyElement(
+ string name, MutablePropertyValues properties, XmlElement element, ParserContext parserContext)
+ {
+ string propertyName = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ if (StringUtils.IsNullOrEmpty(propertyName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource,
+ name,
+ "The 'property' element must have a 'name' attribute");
+ }
+ object val = GetPropertyValue(element, name, parserContext);
+ properties.Add(new PropertyValue(propertyName, val));
+ }
+
+ ///
+ /// Get the value of a property element (may be a list).
+ ///
+ ///
+ /// Please note that even though this method is named GetPropertyValue,
+ /// it is called by both the property and constructor argument element
+ /// handlers.
+ ///
+ ///
+ /// The property element.
+ ///
+ /// The name of the object associated with the property.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual object GetPropertyValue(
+ XmlElement element, string name, ParserContext parserContext)
+ {
+ XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute];
+ if (inlineValueAtt != null)
+ {
+ return inlineValueAtt.Value;
+ }
+ XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute];
+ if (inlineRefAtt != null)
+ {
+ return new RuntimeObjectReference(inlineRefAtt.Value);
+ }
+ XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
+ if (inlineExpressionAtt != null)
+ {
+ return new ExpressionHolder(inlineExpressionAtt.Value);
+ }
+
+ // should only have one element child: value, ref, collection...
+ XmlNodeList nodes = element.ChildNodes;
+ XmlElement valueRefOrCollectionElement = null;
+ for (int i = 0; i < nodes.Count; ++i)
+ {
+ XmlElement candidateEle = nodes.Item(i) as XmlElement;
+ if (candidateEle != null)
+ {
+ if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name))
+ {
+ // keep going: we don't use this value for now...
+ }
+ else
+ {
+ // child element is what we're looking for...
+ valueRefOrCollectionElement = candidateEle;
+ }
+ }
+ }
+ if (valueRefOrCollectionElement == null)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource,
+ name,
+ "The '' element must have a subelement such as 'value' or 'ref'.");
+ }
+ return ParsePropertySubElement(valueRefOrCollectionElement, name, parserContext);
+ }
+
+ ///
+ /// Parse a value, ref or collection subelement of a property element.
+ ///
+ ///
+ /// Subelement of property element; we don't know which yet.
+ ///
+ ///
+ /// The name of the object (definition) associated with the top level property.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual object ParsePropertySubElement(
+ XmlElement element, string name, ParserContext parserContext)
+ {
+ if (element.Name.Equals(ObjectDefinitionConstants.ObjectElement))
+ {
+ return ParseObjectDefinition(element, parserContext, true);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.RefElement))
+ {
+ return GetReference(element, parserContext.ParserHelper, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.IdRefElement))
+ {
+ return GetObjectReference(element, parserContext.ParserHelper, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ListElement))
+ {
+ return GetList(element, name, parserContext);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.SetElement))
+ {
+ return GetSet(element, name, parserContext);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.DictionaryElement))
+ {
+ return GetDictionary(element, name, parserContext);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.NameValuesElement))
+ {
+ return GetNameValues(element, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ValueElement))
+ {
+ return GetValue(element, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ExpressionElement))
+ {
+ return GetExpression(element, name, parserContext);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.NullElement))
+ {
+ // it's a distinguished null value...
+ return null;
+ }
+ else
+ {
+ // it may match another Parser
+ INamespaceParser otherParser = GetParser(element.NamespaceURI);
+ if (otherParser != null)
+ {
+ // The other parser uses nestings tags and thus returns the definition
+ // of the parsed object.
+ return otherParser.ParseElement(element, new ParserContext(parserContext.ReaderContext, parserContext.ParserHelper));
+ }
+ }
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource,
+ name,
+ "Unknown subelement of : <" + element.Name + ">");
+ }
+
+ private static INamespaceParser GetParser(string nspace)
+ {
+ // finds the configuration parser for the given namespace
+ try
+ {
+ return NamespaceParserRegistry.GetParser(nspace);
+ }
+ catch (Exception)
+ {
+ // The parser for the given namespace is not found
+ return null;
+ }
+ }
+
+ private static object GetObjectReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
+ {
+ // a generic reference to any name of any object
+ string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // a reference to the id of another object in the same XML file
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "Either 'object' or 'local' is required for an idref");
+ }
+ }
+ return objectRef;
+ }
+
+ private object GetReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
+ {
+ // is it a generic reference to any name of any object?
+ string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // is it a reference to the id of another object in the same XML file?
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // is it a reference to the id of another object in a parent context?
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "Either 'object' or 'local' is required for a reference");
+ }
+ return new RuntimeObjectReference(objectRef, true);
+ }
+ }
+ return new RuntimeObjectReference(objectRef);
+ }
+
+ private object GetValue(XmlElement element, string name)
+ {
+ string valueType = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ if (StringUtils.IsNullOrEmpty(valueType))
+ {
+ return GetTextValue(element, name);
+ }
+ else
+ {
+ Type resolvedValueType = TypeResolutionUtils.ResolveType(valueType);
+ if (resolvedValueType == typeof(string))
+ {
+ return GetTextValue(element, name);
+ }
+ else
+ {
+ return new TypedStringValue(GetTextValue(element, name), resolvedValueType);
+ }
+ }
+ }
+
+ private object GetExpression(XmlElement element, string name, ParserContext parserContext)
+ {
+ string expression = element.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
+ ExpressionHolder holder = new ExpressionHolder(expression);
+ holder.Properties = GetPropertyValueSubElements(name, element, parserContext);
+ return holder;
+ }
+
+ ///
+ /// Gets a list definition.
+ ///
+ ///
+ /// The element describing the list definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the list definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The list definition.
+ protected virtual IList GetList(XmlElement element, string name, ParserContext parserContext)
+ {
+ ManagedList list = new ManagedList();
+
+ string elementTypeName = element.GetAttribute("element-type");
+ if (StringUtils.HasText(elementTypeName))
+ {
+ list.ElementTypeName = elementTypeName;
+ }
+
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ XmlElement ele = node as XmlElement;
+ if (ele != null)
+ {
+ list.Add(ParsePropertySubElement(ele, name, parserContext));
+ }
+ }
+ return list;
+ }
+
+ ///
+ /// Gets a set definition.
+ ///
+ ///
+ /// The element describing the set definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the set definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The set definition.
+ protected Set GetSet(XmlElement element, string name, ParserContext parserContext)
+ {
+ ManagedSet theSet = new ManagedSet();
+ string elementTypeName = element.GetAttribute("element-type");
+ if (StringUtils.HasText(elementTypeName))
+ {
+ theSet.ElementTypeName = elementTypeName;
+ }
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ XmlElement ele = node as XmlElement;
+ if (ele != null)
+ {
+ object sub = ParsePropertySubElement(ele, name, parserContext);
+ theSet.Add(sub);
+ }
+ }
+ return theSet;
+ }
+
+ ///
+ /// Gets a dictionary definition.
+ ///
+ ///
+ /// The element describing the dictionary definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the dictionary definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The dictionary definition.
+ protected IDictionary GetDictionary(XmlElement element, string name, ParserContext parserContext)
+ {
+ ManagedDictionary dictionary = new ManagedDictionary();
+ string keyTypeName = element.GetAttribute("key-type");
+ string valueTypeName = element.GetAttribute("value-type");
+ if (StringUtils.HasText(keyTypeName))
+ {
+ dictionary.KeyTypeName = keyTypeName;
+ }
+ if (StringUtils.HasText(valueTypeName))
+ {
+ dictionary.ValueTypeName = valueTypeName;
+ }
+
+ XmlNodeList entryElements = SelectNodes(element, ObjectDefinitionConstants.EntryElement);
+ foreach (XmlElement entryEle in entryElements)
+ {
+ #region Key
+
+ object key = null;
+
+ XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute];
+ if (keyAtt != null)
+ {
+ key = keyAtt.Value;
+ }
+ else
+ {
+ // ok, we're not using the 'key' attribute; lets check for the ref shortcut...
+ XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute];
+ if (keyRefAtt != null)
+ {
+ key = new RuntimeObjectReference(keyRefAtt.Value);
+ }
+ else
+ {
+ // so check for the 'key' element...
+ XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
+ if (keyNode == null)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " +
+ "is required for the <{3}/> element.",
+ ObjectDefinitionConstants.KeyElement,
+ ObjectDefinitionConstants.KeyAttribute,
+ ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute,
+ ObjectDefinitionConstants.EntryElement));
+ }
+ XmlElement keyElement = (XmlElement) keyNode;
+ XmlNodeList keyNodes = keyElement.GetElementsByTagName("*");
+ if (keyNodes == null || keyNodes.Count == 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("Malformed <{0}/> element... the value of the key must be " +
+ "specified as a child value-style element.",
+ ObjectDefinitionConstants.KeyElement));
+ }
+ key = ParsePropertySubElement((XmlElement)keyNodes.Item(0), name, parserContext);
+ }
+ }
+
+ #endregion
+
+ #region Value
+
+ XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute];
+ if (inlineValueAtt != null)
+ {
+ // ok, we're using the value attribute shortcut...
+ dictionary[key] = inlineValueAtt.Value;
+ }
+ else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null)
+ {
+ // ok, we're using the value-ref attribute shortcut...
+ XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute];
+ RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value);
+ dictionary[key] = ror;
+ }
+ else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null)
+ {
+ // ok, we're using the expression attribute shortcut...
+ XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
+ ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value);
+ dictionary[key] = expHolder;
+ }
+ else
+ {
+ XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
+ if (keyNode != null)
+ {
+ entryEle.RemoveChild(keyNode);
+ }
+ // ok, we're using the original full-on value element...
+ XmlNodeList valueElements = entryEle.GetElementsByTagName("*");
+ if (valueElements == null || valueElements.Count == 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserContext.ReaderContext.Resource, name,
+ string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " +
+ "is required for the <{2}/> element.",
+ ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement));
+ }
+ dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserContext);
+ }
+
+ #endregion
+ }
+ return dictionary;
+ }
+
+ ///
+ /// Selects sub-elements with a given
+ /// name.
+ ///
+ ///
+ ///
+ /// Uses a namespace manager if necessary.
+ ///
+ ///
+ ///
+ /// The element to be searched in.
+ ///
+ ///
+ /// The name of the child nodes to look for.
+ ///
+ ///
+ /// The child s of the supplied
+ /// with the supplied
+ /// .
+ ///
+ protected XmlNodeList SelectNodes(XmlElement element, string childElementName)
+ {
+ XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
+ nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
+ return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
+ }
+
+ ///
+ /// Selects a single sub-element with a given
+ /// name.
+ ///
+ ///
+ ///
+ /// Uses a namespace manager if necessary.
+ ///
+ ///
+ ///
+ /// The element to be searched in.
+ ///
+ ///
+ /// The name of the child node to look for.
+ ///
+ ///
+ /// The first child of the supplied
+ /// with the supplied
+ /// .
+ ///
+ protected XmlNode SelectSingleNode(XmlElement element, string childElementName)
+ {
+ XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
+ nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
+ return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
+ }
+
+ ///
+ /// Gets a name value collection mapping definition.
+ ///
+ ///
+ /// The element describing the name value collection mapping definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the
+ /// name value collection mapping definition.
+ ///
+ /// The name value collection definition.
+ protected NameValueCollection GetNameValues(XmlElement element, string name)
+ {
+ NameValueCollection nvc = new NameValueCollection();
+ XmlNodeList addElements = element.GetElementsByTagName(ObjectDefinitionConstants.AddElement);
+ foreach (XmlElement addElement in addElements)
+ {
+ string key = addElement.GetAttribute(ObjectDefinitionConstants.KeyAttribute);
+ string value = addElement.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
+ string delimiters = addElement.GetAttribute(ObjectDefinitionConstants.DelimitersAttribute);
+
+ if (StringUtils.HasText(delimiters))
+ {
+ string[] values = value.Split(delimiters.ToCharArray());
+ foreach (string v in values)
+ {
+ nvc.Add(key, v);
+ }
+ }
+ else
+ {
+ nvc[key] = value;
+ }
+ }
+ return nvc;
+ }
+
+ ///
+ /// Returns the text of the supplied ,
+ /// or the empty string value if said is empty.
+ ///
+ ///
+ ///
+ /// If the supplied is ,
+ /// then the empty string value will be returned.
+ ///
+ ///
+ protected string GetTextValue(XmlElement element, string name)
+ {
+ if (element == null || StringUtils.IsNullOrEmpty(element.InnerText))
+ {
+ return String.Empty;
+ }
+ return element.InnerText;
+ }
+
+ ///
+ /// Strips the dependency check value out of the supplied string.
+ ///
+ ///
+ ///
+ /// If the supplied is an invalid dependency
+ /// checking mode, the invalid value will be logged and this method will
+ /// return the value.
+ /// No exception will be raised.
+ ///
+ /// If the supplied is an invalid autowiring mode,
+ /// the invalid value will be logged and this method will return the
+ /// value. No exception will be raised.
+ ///
- /// Raising events defensively means that as the raised event is passed to each handler,
- /// any thrown by a handler will be caught and silently
- /// ignored.
- ///
- ///
- /// Rick Evans
- public class DefensiveEventRaiser : EventRaiser
- {
- ///
- /// Defensively invokes the supplied , passing the
- /// supplied to the sink.
- ///
- /// The sink to be invoked.
- /// The arguments to the sink.
- protected override void Invoke (Delegate sink, object [] arguments)
- {
- try
- {
- sink.DynamicInvoke (arguments);
- }
- catch
- {
- }
- }
- }
-}
+ throw ReflectionUtils.UnwrapTargetInvocationException(ex);
+ }
+ }
+ }
+
+ ///
+ /// Raises events defensively.
+ ///
+ ///
+ ///
+ /// Raising events defensively means that as the raised event is passed to each handler,
+ /// any thrown by a handler will be caught and silently
+ /// ignored.
+ ///
+ ///
+ /// Rick Evans
+ public class DefensiveEventRaiser : EventRaiser
+ {
+ ///
+ /// Defensively invokes the supplied , passing the
+ /// supplied to the sink.
+ ///
+ /// The sink to be invoked.
+ /// The arguments to the sink.
+ protected override void Invoke (Delegate sink, object [] arguments)
+ {
+ try
+ {
+ sink.DynamicInvoke (arguments);
+ }
+ catch
+ {
+ }
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Util/ObjectUtils.cs b/src/Spring/Spring.Core/Util/ObjectUtils.cs
index 1ee6992f..937ccc2c 100644
--- a/src/Spring/Spring.Core/Util/ObjectUtils.cs
+++ b/src/Spring/Spring.Core/Util/ObjectUtils.cs
@@ -57,8 +57,15 @@ namespace Spring.Util
///
public static readonly object[] EmptyObjects = new object[] { };
+ private static MethodInfo GetHashCodeMethodInfo = null;
+
#endregion
+ static ObjectUtils()
+ {
+ Type type = typeof(object);
+ GetHashCodeMethodInfo = type.GetMethod("GetHashCode");
+ }
#region Constructor (s) / Destructor
// CLOVER:OFF
@@ -507,5 +514,32 @@ namespace Spring.Util
AssertUtils.ArgumentNotNull(method, "method", "MethodInfo must not be null");
return method.DeclaringType.FullName + "." + method.Name;
}
+
+ ///
+ /// Return a String representation of an object's overall identity.
+ ///
+ /// The object (may be null).
+ /// The object's identity as String representation,
+ /// or an empty String if the object was null
+ ///
+ public static object IdentityToString(object obj)
+ {
+ if (obj == null)
+ {
+ return string.Empty;
+ }
+ return obj.GetType().FullName + "@" + GetIdentityHexString(obj);
+ }
+
+ ///
+ /// Gets a hex String form of an object's identity hash code.
+ ///
+ /// The obj.
+ /// The object's identity code in hex notation
+ public static string GetIdentityHexString(object obj)
+ {
+ int hashcode = (int)GetHashCodeMethodInfo.Invoke(obj, null);
+ return hashcode.ToString("X6");
+ }
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs b/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs
index c5eb9ea0..a63748c0 100644
--- a/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs
+++ b/src/Spring/Spring.Core/Validation/Config/ValidationNamespaceParser.cs
@@ -1,382 +1,381 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System.Collections;
-using System.Xml;
-
-using Spring.Core.TypeResolution;
-using Spring.Context.Support;
-using Spring.Expressions;
-using Spring.Objects;
-using Spring.Objects.Factory;
-using Spring.Objects.Factory.Config;
-using Spring.Objects.Factory.Support;
-using Spring.Objects.Factory.Xml;
-using Spring.Threading;
-using Spring.Util;
-
-#endregion
-
-namespace Spring.Validation.Config
-{
- ///
- /// Implementation of the custom configuration parser for validator definitions.
- ///
- /// Aleksandar Seovic
- [
- NamespaceParser(
- Namespace = "http://www.springframework.net/validation",
- SchemaLocationAssemblyHint = typeof(ValidationNamespaceParser),
- SchemaLocation = "/Spring.Validation.Config/spring-validation-1.1.xsd")
- ]
- public sealed class ValidationNamespaceParser : ObjectsNamespaceParser
- {
- private const string ValidatorTypePrefix = "validator: ";
-
-// [ThreadStatic]
-// private int definitionCount = 0;
- private readonly string key_DefinitionCount;
- private int definitionCount
- {
- get
- {
- object tmp = LogicalThreadContext.GetData(key_DefinitionCount);
- if (tmp != null) return (int)tmp;
- LogicalThreadContext.SetData(key_DefinitionCount, 0);
- return 0;
- }
- set
- {
- LogicalThreadContext.SetData(key_DefinitionCount, value);
- }
- }
-
- static ValidationNamespaceParser()
- {
- TypeRegistry.RegisterType(ValidatorTypePrefix + "group", typeof(ValidatorGroup));
- TypeRegistry.RegisterType(ValidatorTypePrefix + "any", typeof(AnyValidatorGroup));
- TypeRegistry.RegisterType(ValidatorTypePrefix + "exclusive", typeof(ExclusiveValidatorGroup));
-
-
- TypeRegistry.RegisterType(ValidatorTypePrefix + "collection", typeof(CollectionValidator));
- TypeRegistry.RegisterType(ValidatorTypePrefix + "required", typeof(RequiredValidator));
- TypeRegistry.RegisterType(ValidatorTypePrefix + "condition", typeof(ConditionValidator));
- TypeRegistry.RegisterType(ValidatorTypePrefix + "regex", typeof(RegularExpressionValidator));
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ValidationNamespaceParser()
- {
- // generate unique key for instance field to be stored in LogicalThreadContext
- string FIELDPREFIX = typeof(ValidationNamespaceParser).FullName + base.GetHashCode();
- key_DefinitionCount = FIELDPREFIX + ".definitionCount";
- }
-
-
- ///
- /// Parse the specified element and register any resulting
- /// IObjectDefinitions with the IObjectDefinitionRegistry that is
- /// embedded in the supplied ParserContext.
- ///
- /// The element to be parsed into one or more IObjectDefinitions
- /// The object encapsulating the current state of the parsing
- /// process.
- ///
- /// The primary IObjectDefinition (can be null as explained above)
- ///
- ///
- /// Implementations should return the primary IObjectDefinition
- /// that results from the parse phase if they wish to used nested
- /// inside (for example) a <property> tag.
- /// Implementations may return null if they will not
- /// be used in a nested scenario.
- ///
- ///
- public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
- {
- if (!element.HasAttribute("id"))
- {
- throw new ObjectDefinitionStoreException(parserContext.ReaderContext.Resource, "validator", "Top-level validator element must have an 'id' attribute defined.");
- }
- this.definitionCount = 0;
-
- //TODO pass down parserContext...
- ParseAndRegisterValidator(element, parserContext.ParserHelper);
-
- return null;
- //return definitionCount;
- }
-
- ///
- /// Parses the validator definition.
- ///
- /// Validator's identifier.
- /// The element to parse.
- /// The parser helper.
- /// Validator object definition.
- private IObjectDefinition ParseValidator(string id, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string typeName = GetTypeName(element);
- string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
- string test = element.GetAttribute(ValidatorDefinitionConstants.TestAttribute);
- string when = element.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
- string validateAll = element.GetAttribute(ValidatorDefinitionConstants.CollectionValidateAllAttribute);
- string context = element.GetAttribute(ValidatorDefinitionConstants.CollectionContextAttribute);
- string includeElementsErrors = element.GetAttribute(ValidatorDefinitionConstants.CollectionIncludeElementsErrors);
-
- string name = "validator: " + (StringUtils.HasText(id) ? id : this.definitionCount.ToString());
- MutablePropertyValues properties = new MutablePropertyValues();
- if (StringUtils.HasText(test))
- {
- properties.Add("Test", test);
- }
- if (StringUtils.HasText(when))
- {
- properties.Add("When", when);
- }
- if (StringUtils.HasText(validateAll))
- {
- properties.Add("ValidateAll", validateAll);
- }
- if (StringUtils.HasText(validateAll))
- {
- properties.Add("Context", context);
- }
- if (StringUtils.HasText(includeElementsErrors))
- {
- properties.Add("IncludeElementErrors", includeElementsErrors);
- }
-
-
- ManagedList nestedValidators = new ManagedList();
- ManagedList actions = new ManagedList();
- foreach (XmlNode node in element.ChildNodes)
- {
- XmlElement child = node as XmlElement;
- if (child != null)
- {
- switch (child.LocalName)
- {
- case ValidatorDefinitionConstants.PropertyElement:
- string propertyName = child.GetAttribute(ValidatorDefinitionConstants.PropertyNameAttribute);
- properties.Add(propertyName, base.GetPropertyValue(child, name, parserHelper));
- break;
- case ValidatorDefinitionConstants.MessageElement:
- actions.Add(ParseErrorMessageAction(child, parserHelper));
- break;
- case ValidatorDefinitionConstants.ActionElement:
- actions.Add(ParseGenericAction(child, parserHelper));
- break;
- case ValidatorDefinitionConstants.ReferenceElement:
- nestedValidators.Add(ParseValidatorReference(child, parserHelper));
- break;
- default:
- nestedValidators.Add(ParseAndRegisterValidator(child, parserHelper));
- break;
- }
- }
- }
- if (nestedValidators.Count > 0)
- {
- properties.Add("Validators", nestedValidators);
- }
- if (actions.Count > 0)
- {
- properties.Add("Actions", actions);
- }
-
- IConfigurableObjectDefinition od
- = parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
- typeName, parent, parserHelper.ReaderContext.Reader.Domain);
-
- od.PropertyValues = properties;
- od.IsSingleton = true;
- od.IsLazyInit = true;
-
- return od;
- }
-
- ///
- /// Parses and potentially registers a validator.
- ///
- ///
- /// Only validators that have id attribute specified are registered
- /// as separate object definitions within application context.
- ///
- /// Validator XML element.
- /// The parser helper.
- /// Validator object definition.
- private IObjectDefinition ParseAndRegisterValidator(XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
- IObjectDefinition validator = ParseValidator(id, element, parserHelper);
- if (StringUtils.HasText(id))
- {
- parserHelper.ReaderContext.Registry.RegisterObjectDefinition(id, validator);
- this.definitionCount++;
- }
- return validator;
- }
-
- ///
- /// Gets the name of the object type for the specified element.
- ///
- /// The element.
- /// The name of the object type.
- private string GetTypeName(XmlElement element)
- {
- string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- if (StringUtils.IsNullOrEmpty(typeName))
- {
- return ValidatorTypePrefix + element.LocalName;
- }
- return typeName;
- }
-
- ///
- /// Creates an error message action based on the specified message element.
- ///
- /// The message element.
- /// The parser helper.
- /// The error message action definition.
- private static IObjectDefinition ParseErrorMessageAction(XmlElement message, ObjectDefinitionParserHelper parserHelper)
- {
- string messageId = message.GetAttribute(MessageConstants.IdAttribute);
- string[] providers = message.GetAttribute(MessageConstants.ProvidersAttribute).Split(',');
- ArrayList parameters = new ArrayList();
-
- foreach (XmlElement param in message.ChildNodes)
- {
- IExpression paramExpression = Expression.Parse(param.GetAttribute(MessageConstants.ParameterValueAttribute));
- parameters.Add(paramExpression);
- }
-
- string typeName = "Spring.Validation.Actions.ErrorMessageAction, Spring.Core";
- ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues();
- ctorArgs.AddGenericArgumentValue(messageId);
- ctorArgs.AddGenericArgumentValue(providers);
-
- string when = message.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
- MutablePropertyValues properties = new MutablePropertyValues();
- if (StringUtils.HasText(when))
- {
- properties.Add("When", when);
- }
- if (parameters.Count > 0)
- {
- properties.Add("Parameters", parameters.ToArray(typeof(IExpression)));
- }
-
- IConfigurableObjectDefinition action =
- parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserHelper.ReaderContext.Reader.Domain);
- action.ConstructorArgumentValues = ctorArgs;
- action.PropertyValues = properties;
-
- return action;
- }
-
- ///
- /// Creates a generic action based on the specified element.
- ///
- /// The action definition element.
- /// The parser helper.
- /// Generic validation action definition.
- private IObjectDefinition ParseGenericAction(XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- string when = element.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
- MutablePropertyValues properties = base.GetPropertyValueSubElements("validator:action", element, parserHelper);
- if (StringUtils.HasText(when))
- {
- properties.Add("When", when);
- }
-
- IConfigurableObjectDefinition action =
- parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserHelper.ReaderContext.Reader.Domain);
- action.PropertyValues = properties;
-
- return action;
- }
-
- ///
- /// Creates object definition for the validator reference.
- ///
- /// The action definition element.
- /// The parser helper.
- /// Generic validation action definition.
- private IObjectDefinition ParseValidatorReference(XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string typeName = "Spring.Validation.ValidatorReference, Spring.Core";
- string name = element.GetAttribute(ValidatorDefinitionConstants.ReferenceNameAttribute);
- string context = element.GetAttribute(ValidatorDefinitionConstants.ReferenceContextAttribute);
-
- MutablePropertyValues properties = new MutablePropertyValues();
- properties.Add("Name", name);
- if (StringUtils.HasText(context))
- {
- properties.Add("Context", context);
- }
-
- IConfigurableObjectDefinition reference =
- parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserHelper.ReaderContext.Reader.Domain);
- reference.PropertyValues = properties;
- return reference;
- }
-
- #region Element & Attribute Name Constants
-
- private class ValidatorDefinitionConstants
- {
- public const string PropertyElement = "property";
- public const string MessageElement = "message";
- public const string ActionElement = "action";
- public const string ReferenceElement = "ref";
-
- public const string TypeAttribute = "type";
- public const string TestAttribute = "test";
- public const string NameAttribute = "name";
- public const string WhenAttribute = "when";
-
- public const string PropertyNameAttribute = "name";
-
- public const string ReferenceNameAttribute = "name";
- public const string ReferenceContextAttribute = "context";
-
- public const string CollectionValidateAllAttribute = "validate-all";
- public const string CollectionContextAttribute = "context";
- public const string CollectionIncludeElementsErrors = "include-element-errors";
- }
-
- private class MessageConstants
- {
- public const string ParamElement = "param";
-
- public const string IdAttribute = "id";
- public const string ProvidersAttribute = "providers";
- public const string ParameterValueAttribute = "value";
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System.Collections;
+using System.Xml;
+
+using Spring.Core.TypeResolution;
+using Spring.Context.Support;
+using Spring.Expressions;
+using Spring.Objects;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Threading;
+using Spring.Util;
+
+#endregion
+
+namespace Spring.Validation.Config
+{
+ ///
+ /// Implementation of the custom configuration parser for validator definitions.
+ ///
+ /// Aleksandar Seovic
+ [
+ NamespaceParser(
+ Namespace = "http://www.springframework.net/validation",
+ SchemaLocationAssemblyHint = typeof(ValidationNamespaceParser),
+ SchemaLocation = "/Spring.Validation.Config/spring-validation-1.1.xsd")
+ ]
+ public sealed class ValidationNamespaceParser : ObjectsNamespaceParser
+ {
+ private const string ValidatorTypePrefix = "validator: ";
+
+// [ThreadStatic]
+// private int definitionCount = 0;
+ private readonly string key_DefinitionCount;
+ private int definitionCount
+ {
+ get
+ {
+ object tmp = LogicalThreadContext.GetData(key_DefinitionCount);
+ if (tmp != null) return (int)tmp;
+ LogicalThreadContext.SetData(key_DefinitionCount, 0);
+ return 0;
+ }
+ set
+ {
+ LogicalThreadContext.SetData(key_DefinitionCount, value);
+ }
+ }
+
+ static ValidationNamespaceParser()
+ {
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "group", typeof(ValidatorGroup));
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "any", typeof(AnyValidatorGroup));
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "exclusive", typeof(ExclusiveValidatorGroup));
+
+
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "collection", typeof(CollectionValidator));
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "required", typeof(RequiredValidator));
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "condition", typeof(ConditionValidator));
+ TypeRegistry.RegisterType(ValidatorTypePrefix + "regex", typeof(RegularExpressionValidator));
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ValidationNamespaceParser()
+ {
+ // generate unique key for instance field to be stored in LogicalThreadContext
+ string FIELDPREFIX = typeof(ValidationNamespaceParser).FullName + base.GetHashCode();
+ key_DefinitionCount = FIELDPREFIX + ".definitionCount";
+ }
+
+
+ ///
+ /// Parse the specified element and register any resulting
+ /// IObjectDefinitions with the IObjectDefinitionRegistry that is
+ /// embedded in the supplied ParserContext.
+ ///
+ /// The element to be parsed into one or more IObjectDefinitions
+ /// The object encapsulating the current state of the parsing
+ /// process.
+ ///
+ /// The primary IObjectDefinition (can be null as explained above)
+ ///
+ ///
+ /// Implementations should return the primary IObjectDefinition
+ /// that results from the parse phase if they wish to used nested
+ /// inside (for example) a <property> tag.
+ /// Implementations may return null if they will not
+ /// be used in a nested scenario.
+ ///
+ ///
+ public override IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+ if (!element.HasAttribute("id"))
+ {
+ throw new ObjectDefinitionStoreException(parserContext.ReaderContext.Resource, "validator", "Top-level validator element must have an 'id' attribute defined.");
+ }
+ this.definitionCount = 0;
+
+ ParseAndRegisterValidator(element, parserContext);
+
+ return null;
+ //return definitionCount;
+ }
+
+ ///
+ /// Parses the validator definition.
+ ///
+ /// Validator's identifier.
+ /// The element to parse.
+ /// The parser helper.
+ /// Validator object definition.
+ private IObjectDefinition ParseValidator(string id, XmlElement element, ParserContext parserContext)
+ {
+ string typeName = GetTypeName(element);
+ string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
+ string test = element.GetAttribute(ValidatorDefinitionConstants.TestAttribute);
+ string when = element.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
+ string validateAll = element.GetAttribute(ValidatorDefinitionConstants.CollectionValidateAllAttribute);
+ string context = element.GetAttribute(ValidatorDefinitionConstants.CollectionContextAttribute);
+ string includeElementsErrors = element.GetAttribute(ValidatorDefinitionConstants.CollectionIncludeElementsErrors);
+
+ string name = "validator: " + (StringUtils.HasText(id) ? id : this.definitionCount.ToString());
+ MutablePropertyValues properties = new MutablePropertyValues();
+ if (StringUtils.HasText(test))
+ {
+ properties.Add("Test", test);
+ }
+ if (StringUtils.HasText(when))
+ {
+ properties.Add("When", when);
+ }
+ if (StringUtils.HasText(validateAll))
+ {
+ properties.Add("ValidateAll", validateAll);
+ }
+ if (StringUtils.HasText(validateAll))
+ {
+ properties.Add("Context", context);
+ }
+ if (StringUtils.HasText(includeElementsErrors))
+ {
+ properties.Add("IncludeElementErrors", includeElementsErrors);
+ }
+
+
+ ManagedList nestedValidators = new ManagedList();
+ ManagedList actions = new ManagedList();
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ XmlElement child = node as XmlElement;
+ if (child != null)
+ {
+ switch (child.LocalName)
+ {
+ case ValidatorDefinitionConstants.PropertyElement:
+ string propertyName = child.GetAttribute(ValidatorDefinitionConstants.PropertyNameAttribute);
+ properties.Add(propertyName, base.GetPropertyValue(child, name, parserContext));
+ break;
+ case ValidatorDefinitionConstants.MessageElement:
+ actions.Add(ParseErrorMessageAction(child, parserContext));
+ break;
+ case ValidatorDefinitionConstants.ActionElement:
+ actions.Add(ParseGenericAction(child, parserContext));
+ break;
+ case ValidatorDefinitionConstants.ReferenceElement:
+ nestedValidators.Add(ParseValidatorReference(child, parserContext));
+ break;
+ default:
+ nestedValidators.Add(ParseAndRegisterValidator(child, parserContext));
+ break;
+ }
+ }
+ }
+ if (nestedValidators.Count > 0)
+ {
+ properties.Add("Validators", nestedValidators);
+ }
+ if (actions.Count > 0)
+ {
+ properties.Add("Actions", actions);
+ }
+
+ IConfigurableObjectDefinition od
+ = parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
+ typeName, parent, parserContext.ReaderContext.Reader.Domain);
+
+ od.PropertyValues = properties;
+ od.IsSingleton = true;
+ od.IsLazyInit = true;
+
+ return od;
+ }
+
+ ///
+ /// Parses and potentially registers a validator.
+ ///
+ ///
+ /// Only validators that have id attribute specified are registered
+ /// as separate object definitions within application context.
+ ///
+ /// Validator XML element.
+ /// The parser helper.
+ /// Validator object definition.
+ private IObjectDefinition ParseAndRegisterValidator(XmlElement element, ParserContext parserContext)
+ {
+ string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
+ IObjectDefinition validator = ParseValidator(id, element, parserContext);
+ if (StringUtils.HasText(id))
+ {
+ parserContext.ReaderContext.Registry.RegisterObjectDefinition(id, validator);
+ this.definitionCount++;
+ }
+ return validator;
+ }
+
+ ///
+ /// Gets the name of the object type for the specified element.
+ ///
+ /// The element.
+ /// The name of the object type.
+ private string GetTypeName(XmlElement element)
+ {
+ string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ if (StringUtils.IsNullOrEmpty(typeName))
+ {
+ return ValidatorTypePrefix + element.LocalName;
+ }
+ return typeName;
+ }
+
+ ///
+ /// Creates an error message action based on the specified message element.
+ ///
+ /// The message element.
+ /// The parser helper.
+ /// The error message action definition.
+ private static IObjectDefinition ParseErrorMessageAction(XmlElement message, ParserContext parserContext)
+ {
+ string messageId = message.GetAttribute(MessageConstants.IdAttribute);
+ string[] providers = message.GetAttribute(MessageConstants.ProvidersAttribute).Split(',');
+ ArrayList parameters = new ArrayList();
+
+ foreach (XmlElement param in message.ChildNodes)
+ {
+ IExpression paramExpression = Expression.Parse(param.GetAttribute(MessageConstants.ParameterValueAttribute));
+ parameters.Add(paramExpression);
+ }
+
+ string typeName = "Spring.Validation.Actions.ErrorMessageAction, Spring.Core";
+ ConstructorArgumentValues ctorArgs = new ConstructorArgumentValues();
+ ctorArgs.AddGenericArgumentValue(messageId);
+ ctorArgs.AddGenericArgumentValue(providers);
+
+ string when = message.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
+ MutablePropertyValues properties = new MutablePropertyValues();
+ if (StringUtils.HasText(when))
+ {
+ properties.Add("When", when);
+ }
+ if (parameters.Count > 0)
+ {
+ properties.Add("Parameters", parameters.ToArray(typeof(IExpression)));
+ }
+
+ IConfigurableObjectDefinition action =
+ parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain);
+ action.ConstructorArgumentValues = ctorArgs;
+ action.PropertyValues = properties;
+
+ return action;
+ }
+
+ ///
+ /// Creates a generic action based on the specified element.
+ ///
+ /// The action definition element.
+ /// The parser helper.
+ /// Generic validation action definition.
+ private IObjectDefinition ParseGenericAction(XmlElement element, ParserContext parserContext)
+ {
+ string typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ string when = element.GetAttribute(ValidatorDefinitionConstants.WhenAttribute);
+ MutablePropertyValues properties = base.GetPropertyValueSubElements("validator:action", element, parserContext);
+ if (StringUtils.HasText(when))
+ {
+ properties.Add("When", when);
+ }
+
+ IConfigurableObjectDefinition action =
+ parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain);
+ action.PropertyValues = properties;
+
+ return action;
+ }
+
+ ///
+ /// Creates object definition for the validator reference.
+ ///
+ /// The action definition element.
+ /// The parser helper.
+ /// Generic validation action definition.
+ private IObjectDefinition ParseValidatorReference(XmlElement element, ParserContext parserContext)
+ {
+ string typeName = "Spring.Validation.ValidatorReference, Spring.Core";
+ string name = element.GetAttribute(ValidatorDefinitionConstants.ReferenceNameAttribute);
+ string context = element.GetAttribute(ValidatorDefinitionConstants.ReferenceContextAttribute);
+
+ MutablePropertyValues properties = new MutablePropertyValues();
+ properties.Add("Name", name);
+ if (StringUtils.HasText(context))
+ {
+ properties.Add("Context", context);
+ }
+
+ IConfigurableObjectDefinition reference =
+ parserContext.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(typeName, null, parserContext.ReaderContext.Reader.Domain);
+ reference.PropertyValues = properties;
+ return reference;
+ }
+
+ #region Element & Attribute Name Constants
+
+ private class ValidatorDefinitionConstants
+ {
+ public const string PropertyElement = "property";
+ public const string MessageElement = "message";
+ public const string ActionElement = "action";
+ public const string ReferenceElement = "ref";
+
+ public const string TypeAttribute = "type";
+ public const string TestAttribute = "test";
+ public const string NameAttribute = "name";
+ public const string WhenAttribute = "when";
+
+ public const string PropertyNameAttribute = "name";
+
+ public const string ReferenceNameAttribute = "name";
+ public const string ReferenceContextAttribute = "context";
+
+ public const string CollectionValidateAllAttribute = "validate-all";
+ public const string CollectionContextAttribute = "context";
+ public const string CollectionIncludeElementsErrors = "include-element-errors";
+ }
+
+ private class MessageConstants
+ {
+ public const string ParamElement = "param";
+
+ public const string IdAttribute = "id";
+ public const string ProvidersAttribute = "providers";
+ public const string ParameterValueAttribute = "value";
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs b/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs
index 3c0c12d5..5cf5f683 100644
--- a/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs
+++ b/src/Spring/Spring.Services/Remoting/Config/RemotingNamespaceParser.cs
@@ -233,7 +233,7 @@ namespace Spring.Remoting.Config
switch (child.LocalName)
{
case CaoFactoryObjectConstants.ConstructorArgumentsElement:
- properties.Add("ConstructorArguments", base.GetList(child, name, parserContext.ParserHelper));
+ properties.Add("ConstructorArguments", base.GetList(child, name, parserContext));
break;
}
}
@@ -277,7 +277,7 @@ namespace Spring.Remoting.Config
ParseLifeTime(properties, child, parserContext);
break;
case InterfacesConstants.InterfacesElement:
- properties.Add("Interfaces", base.GetList(child, name, parserContext.ParserHelper));
+ properties.Add("Interfaces", base.GetList(child, name, parserContext));
break;
}
}
@@ -331,7 +331,7 @@ namespace Spring.Remoting.Config
ParseLifeTime(properties, child, parserContext);
break;
case InterfacesConstants.InterfacesElement:
- properties.Add("Interfaces", base.GetList(child, name, parserContext.ParserHelper));
+ properties.Add("Interfaces", base.GetList(child, name, parserContext));
break;
}
}
@@ -374,7 +374,7 @@ namespace Spring.Remoting.Config
ParseLifeTime(properties, child, parserContext);
break;
case InterfacesConstants.InterfacesElement:
- properties.Add("Interfaces", base.GetList(child, name, parserContext.ParserHelper));
+ properties.Add("Interfaces", base.GetList(child, name, parserContext));
break;
}
}
diff --git a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectsNamespaceParser.cs b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectsNamespaceParser.cs
index ce2ba041..9e78e0be 100644
--- a/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectsNamespaceParser.cs
+++ b/src/Spring/Spring.Web/Objects/Factory/Xml/WebObjectsNamespaceParser.cs
@@ -69,7 +69,7 @@ namespace Spring.Objects.Factory.Xml
///
/// The object definition element.
/// The id / name of the object definition.
- /// the parser helper
+ /// the parser helper
/// The object (definition).
///
///