#region License

/*
 * Copyright © 2002-2005 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;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using Common.Logging;
using Spring.Context.Events;
using Spring.Core;
using Spring.Core.IO;
using Spring.Objects;
using Spring.Objects.Events;
using Spring.Objects.Events.Support;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
using Spring.Objects.Support;
using Spring.Util;

#endregion

namespace Spring.Context.Support
{
    /// <summary>
    /// Partial implementation of the
    /// <see cref="Spring.Context.IApplicationContext"/> interface.
    /// </summary>
    /// <remarks>
    /// <p>
    /// 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
    /// <see langword="abstract"/> methods.
    /// </p>
    /// <p>
    /// In contrast to a plain vanilla
    /// <see cref="Spring.Objects.Factory.IObjectFactory"/>, an
    /// <see cref="Spring.Context.IApplicationContext"/> is supposed
    /// to detect special objects defined in its object factory: therefore,
    /// this class automatically registers
    /// <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>s,
    /// <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>s
    /// and <see cref="Spring.Context.IApplicationEventListener"/>s that are
    /// defined as objects in the context.
    /// </p>
    /// <p>
    /// An <see cref="Spring.Context.IMessageSource"/> may be also supplied as
    /// an object in the context, with the special, well-known-name of
    /// <c>"messageSource"</c>. Else, message resolution is delegated to the
    /// parent context.
    /// </p>
    /// </remarks>
    /// <author>Rod Johnson</author>
    /// <author>Juergan Hoeller</author>
    /// <author>Griffin Caprio (.NET)</author>
    /// <seealso cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>
    /// <seealso cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>
    public abstract class AbstractApplicationContext
        : ConfigurableResourceLoader, IConfigurableApplicationContext, IObjectDefinitionRegistry
    {
        #region Constants

        /// <summary>
        /// Name of the .Net config section that contains Spring.Net context definition.
        /// </summary>
        public const string ContextSectionName = "spring/context";

        /// <summary>
        /// Default name of the root context.
        /// </summary>
        public const string DefaultRootContextName = "spring.root";

        #endregion

        #region Fields

        private const long TicksAtEpoch = 621355968000000000;

        /// <summary>
        /// The special, well-known-name of the default
        /// <see cref="Spring.Context.IMessageSource"/> in the context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// If no <see cref="Spring.Context.IMessageSource"/> can be found
        /// in the context using this lookup key, then message resolution
        /// will be delegated to the parent context (if any).
        /// </p>
        /// </remarks>
        public static readonly string MessageSourceObjectName = "messageSource";

        /// <summary>
        /// The special, well-known-name of the default
        /// <see cref="Spring.Objects.Events.IEventRegistry"/> in the context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// If no <see cref="Spring.Objects.Events.IEventRegistry"/> can be found
        /// in the context using this lookup key, then a default
        /// <see cref="Spring.Objects.Events.IEventRegistry"/> will be used.
        /// </p>
        /// </remarks>
        public static readonly string EventRegistryObjectName = "eventRegistry";

        /// <summary>
        /// The <see cref="Common.Logging.ILog"/> instance for this class.
        /// </summary>
        protected readonly ILog log;

        /// <summary>
        /// The <see cref="Spring.Context.IMessageSource"/> instance we delegate
        /// our implementation of said interface to.
        /// </summary>
        private IMessageSource _messageSource;

        /// <summary>
        /// The <see cref="Spring.Objects.Events.IEventRegistry"/> instance we
        /// delegate our implementation of said interface to.
        /// </summary>
        private IEventRegistry _eventRegistry;

        private IApplicationContext _parentApplicationContext;
        private readonly IList _objectFactoryPostProcessors;
        private readonly IList _defaultObjectPostProcessors;
        private string _name;
        private DateTime _startupDate;
        private readonly bool _isCaseSensitive;

        #endregion

        #region Constructor (s) / Destructor

        /// <summary>
        /// Creates a new instance of the <see cref="AbstractApplicationContext"/>
        /// with no parent context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This is an <see langword="abstract"/> class, and as such exposes
        /// no public constructors.
        /// </p>
        /// </remarks>
        protected AbstractApplicationContext()
            : this(null, true, null)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="AbstractApplicationContext"/>
        /// with no parent context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This is an <see langword="abstract"/> class, and as such exposes
        /// no public constructors.
        /// </p>
        /// </remarks>
        /// <param name="caseSensitive">Flag specifying whether to make this context case sensitive or not.</param>
        protected AbstractApplicationContext(bool caseSensitive)
            : this(null, caseSensitive, null)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="AbstractApplicationContext"/>
        /// with the supplied parent context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This is an <see langword="abstract"/> class, and as such exposes
        /// no public constructors.
        /// </p>
        /// </remarks>
        /// <param name="name">The application context name.</param>
        /// <param name="caseSensitive">Flag specifying whether to make this context case sensitive or not.</param>
        /// <param name="parentApplicationContext">The parent application context.</param>
        protected AbstractApplicationContext(string name, bool caseSensitive,
                                             IApplicationContext parentApplicationContext)
        {
            log = LogManager.GetLogger(this.GetType());

            _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name;
            _isCaseSensitive = caseSensitive;
            _parentApplicationContext = parentApplicationContext;
            _objectFactoryPostProcessors = new ArrayList();
            _defaultObjectPostProcessors = new ArrayList();
            AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker());
            AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this));
            AddDefaultObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue));
        }

        /// <summary>
        /// Adds the given <see cref="IObjectPostProcessor"/> to the list of standard
        /// processors being added to the underlying <see cref="IConfigurableObjectFactory"/>
        /// </summary>
        /// <remarks>
        /// Each time <see cref="Refresh()"/> is called on this context, the context ensures, that 
        /// all default <see cref="IObjectPostProcessor"/>s are registered with the underlying <see cref="IConfigurableObjectFactory"/>.
        /// </remarks>
        /// <param name="defaultObjectPostProcessor">The <see cref="IObjectPostProcessor"/> instance.</param>
        protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor)
        {
            _defaultObjectPostProcessors.Add(defaultObjectPostProcessor);
        }

        /// <summary>
        /// Closes this context and disposes of any resources (such as
        /// singleton objects in the wrapped
        /// <see cref="Spring.Objects.Factory.IObjectFactory"/>).
        /// </summary>
        public virtual void Dispose()
        {
            GC.SuppressFinalize(this);

            #region Instrumentation

            if (log.IsDebugEnabled)
            {
                log.Debug(string.Format(
                              CultureInfo.InvariantCulture,
                              "Closing application context [{0}].",
                              Name));
            }

            #endregion

            // TODO: any reason, why Closed event is raised before destroying objectfactory?
            new DefensiveEventRaiser().Raise(
                ContextEvent, this,
                new ContextEventArgs(ContextEventArgs.ContextEvent.Closed));
            ObjectFactory.Dispose();
        }

        #endregion

        #region Abstract Methods

        /// <summary>
        /// Subclasses must implement this method to perform the actual
        /// configuration loading.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method is invoked by
        /// <see cref="Spring.Context.Support.AbstractApplicationContext.Refresh()"/>,
        /// before any other initialization occurs.
        /// </p>
        /// </remarks>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// In the case of errors encountered while refreshing the object factory.
        /// </exception>
        protected abstract void RefreshObjectFactory();

        #endregion

        /// <summary>
        /// An object that can be used to synchronize access to the <see cref="AbstractXmlApplicationContext"/>
        /// </summary>
        public object SyncRoot
        {
            get { return this; }
        }

        /// <summary>
        /// The timestamp when this context was first loaded.
        /// </summary>
        /// <returns>
        /// The timestamp (milliseconds) when this context was first loaded.
        /// </returns>
        public long StartupDateMilliseconds
        {
            get { return (StartupDate.Ticks - TicksAtEpoch) / 10000; }
        }


        /// <summary>
        /// Gets a flag indicating whether context should be case sensitive.
        /// </summary>
        /// <value><c>true</c> if object lookups are case sensitive; otherwise, <c>false</c>.</value>
        public bool IsCaseSensitive
        {
            get { return _isCaseSensitive; }
        }

        /// <summary>
        /// The <see cref="Spring.Context.IMessageSource"/> for this context.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// If the context has not been initialized yet.
        /// </exception>
        public IMessageSource MessageSource
        {
            get
            {
                if (_messageSource == null)
                {
                    throw new InvalidOperationException(
                        "MessageSource not initialized - call 'Refresh()' " +
                        "before accessing messages via the context: " + this);
                }
                return _messageSource;
            }
        }

        /// <summary>
        /// The <see cref="Spring.Objects.Events.IEventRegistry"/> for this context.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// If the context has not been initialized yet.
        /// </exception>
        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;
            }
        }

        /// <summary>
        /// Returns the internal object factory of the parent context if it implements
        /// <see cref="Spring.Context.IConfigurableApplicationContext"/>; else,
        /// returns the parent context itself.
        /// </summary>
        /// <returns>
        /// The parent context's object factory, or the parent itself.
        /// </returns>
        protected IObjectFactory GetInternalParentObjectFactory()
        {
            IConfigurableApplicationContext configContext
                = _parentApplicationContext as IConfigurableApplicationContext;
            if (configContext != null)
            {
                return ((IConfigurableApplicationContext)
                        _parentApplicationContext).ObjectFactory;
            }
            else
            {
                return _parentApplicationContext;
            }
        }

        /// <summary>
        /// Raises an application context event.
        /// </summary>
        /// <param name="e">
        /// Any arguments to the event. May be <see langword="null"/>.
        /// </param>
        protected virtual void OnContextEvent(ApplicationEventArgs e)
        {
            OnContextEvent(this, e);
        }

        /// <summary>
        /// Raises an application context event.
        /// </summary>
        /// <param name="source">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// Any arguments to the event. May be <see langword="null"/>.
        /// </param>
        protected virtual void OnContextEvent(object source, ApplicationEventArgs e)
        {
            new DefensiveEventRaiser().Raise(ContextEvent, source, e);
        }

        /// <summary>
        /// Modify the application context's internal object factory after its standard
        /// initialization.
        /// </summary>
        /// <remarks>
        /// <p>
        /// All object definitions will have been loaded, but no objects
        /// will have been instantiated yet. This allows for the registration
        /// of special
        /// <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>s
        /// in certain
        /// <see cref="Spring.Context.IApplicationContext"/> implementations.
        /// </p>
        /// </remarks>
        /// <param name="objectFactory">
        /// The object factory used by the application context.
        /// </param>
        /// <exception cref="ObjectsException">
        /// In the case of errors.
        /// </exception>.
        protected virtual void PostProcessObjectFactory(
            IConfigurableListableObjectFactory objectFactory)
        {
        }

        /// <summary>
        /// Template method which can be overridden to add context-specific
        /// work before the underlying object factory gets refreshed.
        /// </summary>
        protected virtual void OnPreRefresh()
        {
        }

        /// <summary>
        /// Template method which can be overridden to add context-specific
        /// refresh work.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Called on initialization of special objects, before instantiation
        /// of singletons.
        /// </p>
        /// </remarks>
        protected virtual void OnRefresh()
        {
        }

        /// <summary>
        /// Template method which can be overridden to add context-specific
        /// work after the context was refreshed but before the <see cref="ContextEventArgs.ContextEvent.Refreshed"/>
        /// event gets raised.
        /// </summary>
        protected virtual void OnPostRefresh()
        {
        }

        /// <summary>
        /// Instantiate and invoke all registered
        /// <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>
        /// objects, respecting any explicit ordering.
        /// </summary>
        /// <remarks>
        /// <note type="caution">
        /// <b>Must</b> be called before singleton instantiation.
        /// </note>
        /// </remarks>
        /// <exception cref="ObjectsException">In the case of errors.</exception>
        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)
        {
            RefreshObjectPostProcessorChecker(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));
            }
        }

        /// <summary>
        /// Resets the well-known ObjectPostProcessorChecker 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.
        /// </summary>
        private void RefreshObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory)
        {
            int registeredObjectPostProcessorCount = GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length;
            int objectPostProcessorCount = ObjectFactory.ObjectPostProcessorCount + 1
                                           + registeredObjectPostProcessorCount;
            ((ObjectPostProcessorChecker)_defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount);
        }

        /// <summary>
        /// Initializes the default event registry for this context.
        /// </summary>
        private void InitEventRegistry()
        {
            if (ContainsLocalObject(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);
        }

        /// <summary>
        /// Returns the internal message source of the parent context if said
        /// parent context is an <see cref="AbstractApplicationContext"/>, else
        /// simply the parent context itself.
        /// </summary>
        /// <returns>
        /// The internal message source of the parent context if said
        /// parent context is an <see cref="AbstractApplicationContext"/>, else
        /// simply the parent context itself.
        /// </returns>
        protected virtual IMessageSource GetInternalParentMessageSource()
        {
            AbstractApplicationContext parent
                = ParentContext as AbstractApplicationContext;
            return parent == null ? ParentContext : parent._messageSource;
        }

        /// <summary>
        /// Initializes the default message source for this context.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Uses any parent context's message source if one is not available
        /// in this context.
        /// </p>
        /// </remarks>
        private void InitMessageSource()
        {
            if (ContainsLocalObject(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());
                ObjectFactory.RegisterSingleton(MessageSourceObjectName, _messageSource);

                #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();
                ObjectFactory.RegisterSingleton(MessageSourceObjectName, _messageSource);

                #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);
            }
        }

        /// <summary>
        /// Returns the list of the
        /// <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>s
        /// that will be applied to the objects created with this factory.
        /// </summary>
        /// <remarks>
        /// <p>
        /// The elements of this list are instances of implementations of the
        /// <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>
        /// interface.
        /// </p>
        /// </remarks>
        /// <value>
        /// The list of the
        /// <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>s
        /// that will be applied to the objects created with this factory.
        /// </value>
        private IList ObjectFactoryPostProcessors
        {
            get { return _objectFactoryPostProcessors; }
        }

        #region IConfigurableApplicationContext Members

        /// <summary>
        /// Return the internal object factory of this application context.
        /// </summary>
        public abstract IConfigurableListableObjectFactory ObjectFactory { get; }

        /// <summary>
        /// Add a new <see cref="Spring.Objects.Factory.Config.IObjectFactoryPostProcessor"/>
        /// that will get applied to the internal object factory of this application context
        /// on refresh, before any of the object definitions are evaluated.
        /// </summary>
        /// <param name="objectFactoryPostProcessor">
        /// The factory processor to register.
        /// </param>
        public void AddObjectFactoryPostProcessor(
            IObjectFactoryPostProcessor objectFactoryPostProcessor)
        {
            _objectFactoryPostProcessors.Add(objectFactoryPostProcessor);
        }

        /// <summary>
        /// Load or refresh the persistent representation of the configuration,
        /// which might an XML file, properties file, or relational database schema.
        /// </summary>
        /// <exception cref="Spring.Context.ApplicationContextException">
        /// If the configuration cannot be loaded.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object factory could not be initialized.
        /// </exception>
        public void Refresh()
        {
            lock (SyncRoot)
            {
                _startupDate = DateTime.Now;

                OnPreRefresh();

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Refreshing object factory "));
                }

                #endregion

                RefreshObjectFactory();

                IConfigurableListableObjectFactory objectFactory = ObjectFactory;

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Registering well-known processors and objects"));
                }

                #endregion

                PrepareObjectFactory(objectFactory);

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Custom post processing object factory"));
                }

                #endregion

                PostProcessObjectFactory(objectFactory);

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Post processing object factory using pre-registered processors"));
                }

                #endregion

                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

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Post processing object factory using defined processors"));
                }

                #endregion

                InvokeObjectFactoryPostProcessors();

                RegisterObjectPostProcessors(objectFactory);
                InitEventRegistry();
                InitMessageSource();
                OnRefresh();

                RefreshApplicationEventListeners();

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format("ApplicationContext Refresh: Preinstantiating singletons"));
                }

                #endregion

                objectFactory.PreInstantiateSingletons();

                OnPostRefresh();

                new DefensiveEventRaiser().Raise(
                    ContextEvent, this,
                    new ContextEventArgs(ContextEventArgs.ContextEvent.Refreshed));

                #region Instrumentation

                if (log.IsInfoEnabled)
                {
                    log.Info(string.Format("ApplicationContext Refresh: Completed"));
                }

                #endregion
            }
        }

        /// <summary>
        /// Registers well-known <see cref="IObjectPostProcessor"/>s and 
        /// preregisters well-known dependencies using <see cref="IConfigurableListableObjectFactory.RegisterResolvableDependency"/>
        /// </summary>
        /// <param name="objectFactory">the raw object factory as returned from <see cref="RefreshObjectFactory"/></param>
        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);
        }

        /// <summary>
        /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory
        /// </summary>
        /// <param name="objectFactory"></param>
        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]);
            }
        }

        /// <summary>
        /// Gets the parent context, or <see langword="null"/> if there is no
        /// parent context.
        /// </summary>
        /// <returns>
        /// The parent context, or <see langword="null"/>  if there is no
        /// parent.
        /// </returns>
        /// <seealso cref="Spring.Context.IApplicationContext.ParentContext"/>
        public virtual IApplicationContext ParentContext
        {
            get { return _parentApplicationContext; }
            set { _parentApplicationContext = value; }
        }

        #endregion

        #region ILifecycle Members

        /// <summary>
        /// Starts this component.
        /// </summary>
        /// <remarks>Should not throw an exception if the component is already running.
        /// In the case of a container, this will propagate the start signal
        /// to all components that apply.
        /// </remarks>
        public void Start()
        {
            IDictionary lifecycleObjects = LifeCycleObjects;
            foreach (DictionaryEntry dictionaryEntry in lifecycleObjects)
            {
                //TODO start dependencies of the lifecycle objects
                ILifecycle obj = dictionaryEntry.Value as ILifecycle;
                if (obj != null)
                {
                    if (!obj.IsRunning)
                    {
                        obj.Start();
                    }
                }
            }
        }

        /// <summary>
        /// Stops this component.
        /// </summary>
        /// <remarks>
        /// Should not throw an exception if the component isn't started yet.
        /// In the case of a container, this will propagate the stop signal
        /// to all components that apply.
        /// </remarks>
        public void Stop()
        {
            IDictionary lifecycleObjects = LifeCycleObjects;
            foreach (DictionaryEntry dictionaryEntry in lifecycleObjects)
            {
                //TODO stop dependencies of the lifecycle objects
                ILifecycle obj = dictionaryEntry.Value as ILifecycle;
                if (obj != null)
                {
                    if (obj.IsRunning)
                    {
                        obj.Stop();
                    }
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether this component is currently running.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this component is running; otherwise, <c>false</c>.
        /// </value>
        /// <remarks>
        /// In the case of a container, this will return <code>true</code>
        /// only if <i>all</i> components that apply are currently running.
        /// </remarks>
        public bool IsRunning
        {
            get
            {
                IDictionary lifecycleObjects = LifeCycleObjects;
                foreach (DictionaryEntry dictionaryEntry in lifecycleObjects)
                {
                    ILifecycle obj = dictionaryEntry.Value as ILifecycle;
                    if (obj != null)
                    {
                        if (!obj.IsRunning)
                        {
                            return false;
                        }
                    }
                }
                return true;
            }
        }

        /// <summary>
        /// Gets a dictionary of all singleton beans that implement the
        /// ILifecycle interface in this context.
        /// </summary>
        /// <value>A dictionary of ILifecycle objects with object name as key.</value>
        private IDictionary LifeCycleObjects
        {
            get
            {
                IConfigurableListableObjectFactory objectFactory = ObjectFactory;
                string[] objectNames = objectFactory.SingletonNames;
                IDictionary lifeCycleObjects = new Hashtable();
                foreach (string objectName in objectNames)
                {
                    object obj = objectFactory.GetSingleton(objectName);
                    if (obj is ILifecycle)
                    {
                        lifeCycleObjects[objectName] = obj;
                    }
                }
                return lifeCycleObjects;
            }
        }

        #endregion

        #region IApplicationContext Members

        /// <summary>
        /// Raised in response to an implementation-dependant application
        /// context event.
        /// </summary>
        public event ApplicationEventHandler ContextEvent;

        /// <summary>
        /// The date and time this context was first loaded.
        /// </summary>
        /// <returns>
        /// The <see cref="System.DateTime"/> representing when this context
        /// was first loaded.
        /// </returns>
        public DateTime StartupDate
        {
            get { return _startupDate; }
        }

        /// <summary>
        /// A name for this context.
        /// </summary>
        /// <returns>
        /// A name for this context.
        /// </returns>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }



        #endregion

        #region IListableObjectFactory Members

        /// <summary>
        /// Return the names of objects matching the given <see cref="System.Type"/>
        /// (including subclasses), judging from the object definitions.
        /// </summary>
        /// <param name="type">
        /// The <see cref="System.Type"/> (class or interface) to match, or <see langword="null"/>
        /// for all object names.
        /// </param>
        /// <returns>
        /// The names of all objects defined in this factory, or an empty array if none
        /// are defined.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectNamesForType(Type)"/>
        public string[] GetObjectNamesForType(Type type)
        {
            return ObjectFactory.GetObjectNamesForType(type);
        }

        /// <summary>
        /// Return the names of objects matching the given <see cref="System.Type"/>
        /// (including subclasses), judging from the object definitions.
        /// </summary>
        /// <param name="type">
        /// The <see cref="System.Type"/> (class or interface) to match, or <see langword="null"/>
        /// for all object names.
        /// </param>
        /// <param name="includePrototypes">
        /// Whether to include prototype objects too or just singletons (also applies to
        /// <see cref="Spring.Objects.Factory.IFactoryObject"/>s).
        /// </param>
        /// <param name="includeFactoryObjects">
        /// Whether to include <see cref="Spring.Objects.Factory.IFactoryObject"/>s too
        /// or just normal objects.
        /// </param>
        /// <returns>
        /// The names of all objects defined in this factory, or an empty array if none
        /// are defined.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectNamesForType(Type, bool, bool)"/>
        public string[] GetObjectNamesForType(
            Type type, bool includePrototypes, bool includeFactoryObjects)
        {
            return ObjectFactory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects);
        }

        /// <summary>
        /// Return the names of all objects defined in this factory.
        /// </summary>
        /// <returns>
        /// The names of all objects defined in this factory, or an empty array if none
        /// are defined.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectDefinitionNames()"/>
        public string[] GetObjectDefinitionNames()
        {
            return ObjectFactory.GetObjectDefinitionNames();
        }

        /// <summary>
        /// Return the registered
        /// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/> for the
        /// given object, allowing access to its property values and constructor
        /// argument values.
        /// </summary>
        /// <param name="name">The name of the object.</param>
        /// <returns>
        /// The registered
        /// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/>.
        /// </returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there is no object with the given name.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// In the case of errors.
        /// </exception>        
        public virtual IObjectDefinition GetObjectDefinition(string name)
        {
            return ObjectFactory.GetObjectDefinition(name);
        }


        /// <summary>
        /// Return the registered
        /// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/> for the
        /// given object, allowing access to its property values and constructor
        /// argument values.
        /// </summary>
        /// <param name="name">The name of the object.</param>
        /// <param name="includeAncestors">Whether to search parent object factories.</param>
        /// <returns>
        /// The registered
        /// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/>.
        /// </returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there is no object with the given name.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// In the case of errors.
        /// </exception>       
        public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
        {
            return ObjectFactory.GetObjectDefinition(name, includeAncestors);
        }

        /// <summary>
        /// Return the object instances that match the given object
        /// <see cref="System.Type"/> (including subclasses), judging from either object
        /// definitions or the value of
        /// <see cref="Spring.Objects.Factory.IFactoryObject.ObjectType"/> in the case of
        /// <see cref="Spring.Objects.Factory.IFactoryObject"/>s.
        /// </summary>
        /// <param name="type">
        /// The <see cref="System.Type"/> (class or interface) to match.
        /// </param>
        /// <returns>
        /// A <see cref="System.Collections.IDictionary"/> of the matching objects,
        /// containing the object names as keys and the corresponding object instances
        /// as values.
        /// </returns>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the objects could not be created.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectsOfType(Type)"/>
        public IDictionary GetObjectsOfType(Type type)
        {
            return GetObjectsOfType(type, true, true);
        }

        /// <summary>
        /// Return the object instances that match the given object
        /// <see cref="System.Type"/> (including subclasses), judging from either object
        /// definitions or the value of
        /// <see cref="Spring.Objects.Factory.IFactoryObject.ObjectType"/> in the case of
        /// <see cref="Spring.Objects.Factory.IFactoryObject"/>s.
        /// </summary>
        /// <param name="type">
        /// The <see cref="System.Type"/> (class or interface) to match.
        /// </param>
        /// <param name="includePrototypes">
        /// Whether to include prototype objects too or just singletons (also applies to
        /// <see cref="Spring.Objects.Factory.IFactoryObject"/>s).
        /// </param>
        /// <param name="includeFactoryObjects">
        /// Whether to include <see cref="Spring.Objects.Factory.IFactoryObject"/>s too
        /// or just normal objects.
        /// </param>
        /// <returns>
        /// A <see cref="System.Collections.IDictionary"/> of the matching objects,
        /// containing the object names as keys and the corresponding object instances
        /// as values.
        /// </returns>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the objects could not be created.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectsOfType(Type, bool, bool)"/>
        public IDictionary GetObjectsOfType(
            Type type, bool includePrototypes, bool includeFactoryObjects)
        {
            return ObjectFactory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
        }

        /// <summary>
        /// Return the number of objects defined in the factory.
        /// </summary>
        /// <value>
        /// The number of objects defined in the factory.
        /// </value>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.ObjectDefinitionCount"/>
        public int ObjectDefinitionCount
        {
            get { return ObjectFactory.ObjectDefinitionCount; }
        }

        /// <summary>
        /// Check if this object factory contains an object definition with the given name.
        /// </summary>
        /// <param name="name">The name of the object to look for.</param>
        /// <returns>
        /// True if this object factory contains an object definition with the given name.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IListableObjectFactory.ContainsObjectDefinition(string)"/>
        public bool ContainsObjectDefinition(string name)
        {
            return ObjectFactory.ContainsObjectDefinition(name);
        }

        #endregion

        #region IObjectFactory Members

        /// <summary>
        /// Return an instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <param name="name">The name of the object to return.</param>
        /// <returns>The instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string)"/>
        public object this[string name]
        {
            get { return ObjectFactory.GetObject(name); }
        }

        /// <summary>
        /// Does this object factory contain an object with the given name?
        /// </summary>
        /// <param name="name">The name of the object to query.</param>
        /// <returns>
        /// <see langword="true"/> if an object with the given name is defined.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.ContainsObject(string)"/>
        public bool ContainsObject(string name)
        {
            return ObjectFactory.ContainsObject(name);
        }

        /// <summary>
        /// Return the aliases for the given object name, if defined.
        /// </summary>
        /// <param name="name">The object name to check for aliases.</param>
        /// <returns>The aliases, or an empty array if none.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetAliases(string)"/>
        public string[] GetAliases(string name)
        {
            return ObjectFactory.GetAliases(name);
        }


        /// <summary>
        /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <param name="name">The name of the object to return.</param>
        /// <param name="requiredType">
        /// The <see cref="System.Type"/> the object may match. Can be an interface or
        /// superclass of the actual class. For example, if the value is the
        /// <see cref="System.Object"/> class, this method will succeed whatever the
        /// class of the returned instance.
        /// </param>
        /// <param name="arguments">
        /// The arguments to use if creating a prototype using explicit arguments to
        /// a <see lang="static"/> factory method. If there is no factory method and the
        /// supplied <paramref name="arguments"/> array is not <see lang="null"/>, then
        /// match the argument values by type and call the object's constructor.
        /// </param>
        /// <returns>The unconfigured(!) instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <exception cref="Spring.Objects.Factory.ObjectNotOfRequiredTypeException">
        /// If the object is not of the required type.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="IObjectFactory.CreateObject"/>
        /// <remarks>
        ///  This method will only <b>instantiate</b> the requested object. It does <b>NOT</b> inject any dependencies!
        /// </remarks>
        public object CreateObject(string name, Type requiredType, object[] arguments)
        {
            return ObjectFactory.CreateObject(name, requiredType, arguments);
        }

        /// <summary>
        /// Return an instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <param name="name">The name of the object to return.</param>
        /// <param name="requiredType">
        /// <see cref="System.Type"/> the object may match. Can be an interface or
        /// superclass of the actual class. For example, if the value is the
        /// <see cref="System.Object"/> class, this method will succeed whatever the
        /// class of the returned instance.
        /// </param>
        /// <returns>The instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <exception cref="Spring.Objects.Factory.ObjectNotOfRequiredTypeException">
        /// If the object is not of the required type.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string, Type)"/>
        public object GetObject(string name, Type requiredType)
        {
            return ObjectFactory.GetObject(name, requiredType);
        }

        /// <summary>
        /// Return an instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <param name="name">The name of the object to return.</param>
        /// <returns>The instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string)"/>
        public object GetObject(string name)
        {
            return ObjectFactory.GetObject(name);
        }

        /// <summary>
        /// Return an instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method allows an object factory to be used as a replacement for the
        /// Singleton or Prototype design pattern.
        /// </p>
        /// <p>
        /// 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.
        /// </p>
        /// <p>
        /// Will ask the parent factory if the object cannot be found in this factory
        /// instance.
        /// </p>
        /// </remarks>
        /// <param name="name">The name of the object to return.</param>
        /// <param name="arguments">
        /// 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.
        /// </param>
        /// <returns>The instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        public object GetObject(string name, object[] arguments)
        {
            return ObjectFactory.GetObject(name, arguments);
        }

        /// <summary>
        /// Return an instance (possibly shared or independent) of the given object name.
        /// </summary>
        /// <param name="name">The name of the object to return.</param>
        /// <param name="requiredType">
        /// The <see cref="System.Type"/> the object may match. Can be an interface or
        /// superclass of the actual class. For example, if the value is the
        /// <see cref="System.Object"/> class, this method will succeed whatever the
        /// class of the returned instance.
        /// </param>
        /// <param name="arguments">
        /// The arguments to use if creating a prototype using explicit arguments to
        /// a <see lang="static"/> factory method. If there is no factory method and the
        /// supplied <paramref name="arguments"/> array is not <see lang="null"/>, then
        /// match the argument values by type and call the object's constructor.
        /// </param>
        /// <returns>The instance of the object.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object could not be created.
        /// </exception>
        /// <exception cref="Spring.Objects.Factory.ObjectNotOfRequiredTypeException">
        /// If the object is not of the required type.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string, Type, object[])"/>
        public object GetObject(string name, Type requiredType, object[] arguments)
        {
            return ObjectFactory.GetObject(name, requiredType, arguments);
        }

        /// <summary>
        /// Is this object a singleton?
        /// </summary>
        /// <param name="name">The name of the object to query.</param>
        /// <returns>True if the named object is a singleton.</returns>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there's no such object definition.
        /// </exception>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.IsSingleton(string)"/>
        public bool IsSingleton(string name)
        {
            return ObjectFactory.IsSingleton(name);
        }

        /// <summary>
        /// Determines whether the specified object name is prototype.  That is, will GetObject
        /// always return independent instances?
        /// </summary>
        /// <param name="name">The name of the object to query</param>
        /// <returns>
        /// 	<c>true</c> if the specified object name will always deliver independent instances; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks>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.
        /// <para>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.
        /// </para>
        /// </remarks>
        /// <exception cref="NoSuchObjectDefinitionException">if there is no object with the given name.</exception>
        public bool IsPrototype(string name)
        {
            return ObjectFactory.IsPrototype(name);
        }


        /// <summary>
        /// Determines whether the object with the given name matches the specified type.
        /// </summary>
        /// <remarks>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.
        /// </remarks>
        /// <param name="name">The name of the object to query.</param>
        /// <param name="targetType">Type of the target to match against.</param>
        /// <returns>
        /// 	<c>true</c> if the object type matches; otherwise, <c>false</c>
        /// if it doesn't match or cannot be determined yet.
        /// </returns>
        /// <exception cref="NoSuchObjectDefinitionException">Ff there is no object with the given name
        /// </exception>
        public bool IsTypeMatch(string name, Type targetType)
        {
            return ObjectFactory.IsTypeMatch(name, targetType);
        }

        /// <summary>
        /// Determine the <see cref="System.Type"/>  of the object with the
        /// given name.
        /// </summary>
        /// <param name="name">The name of the object to query.</param>
        /// <returns>
        /// The <see cref="System.Type"/> of the object, or <see langword="null"/>
        /// if not determinable.
        /// </returns>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetType(string)"/>
        public Type GetType(string name)
        {
            return ObjectFactory.GetType(name);
        }

        /// <summary>
        /// Injects dependencies into the supplied <paramref name="target"/> instance
        /// using the named object definition.
        /// </summary>
        /// <param name="target">
        /// The object instance that is to be so configured.
        /// </param>
        /// <param name="name">
        /// The name of the object definition expressing the dependencies that are to
        /// be injected into the supplied <parameref name="target"/> instance.
        /// </param>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.ConfigureObject(object, string)"/>
        public object ConfigureObject(object target, string name)
        {
            return ObjectFactory.ConfigureObject(target, name);
        }

        /// <summary>
        /// Injects dependencies into the supplied <paramref name="target"/> instance
        /// using the supplied <paramref name="definition"/>.
        /// </summary>
        /// <param name="target">
        /// The object instance that is to be so configured.
        /// </param>
        /// <param name="name">
        /// The name of the object definition expressing the dependencies that are to
        /// be injected into the supplied <parameref name="target"/> instance.
        /// </param>
        /// <param name="definition">
        /// An object definition that should be used to configure object.
        /// </param>
        /// <seealso cref="Spring.Objects.Factory.IObjectFactory.ConfigureObject(object, string)"/>
        public object ConfigureObject(object target, string name, IObjectDefinition definition)
        {
            return ObjectFactory.ConfigureObject(target, name, definition);
        }

        #endregion

        #region IHierarchicalObjectFactory Members

        /// <summary>
        /// Return the parent object factory, or <see langword="null"/> if there is none.
        /// </summary>
        /// <value>
        /// The parent object factory, or <see langword="null"/> if there is none.
        /// </value>
        /// <seealso cref="Spring.Objects.Factory.IHierarchicalObjectFactory.ParentObjectFactory"/>
        public IObjectFactory ParentObjectFactory
        {
            get { return _parentApplicationContext; }
        }

        /// <summary>
        /// Determines whether the local object factory contains a bean of the given name,
        /// ignoring object defined in ancestor contexts.
        /// This is an alternative to <code>ContainsObject</code>, ignoring an object
        /// of the given name from an ancestor object factory.
        /// </summary>
        /// <remarks>
        /// 
        /// </remarks>
        /// <param name="name">The name of the object to query.</param>
        /// <returns>
        /// 	<c>true</c> if objects with the specified name is defined in the local factory; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsLocalObject(string name)
        {
            return ObjectFactory.ContainsLocalObject(name);
        }

        #endregion

        #region IObjectDefinitionRegistry Members

        /// <summary>
        /// Determine whether the given object name is already in use within this context, 
        /// i.e. whether there is a local object. May be override by subclasses, the default 
        /// implementation simply returns <see cref="ContainsLocalObject"/>
        /// </summary>
        public virtual bool IsObjectNameInUse(string objectName)
        {
            return ContainsLocalObject(objectName);
        }

        /// <summary>
        /// Register a new object definition with this registry.
        /// Must support
        /// <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>
        /// and <see cref="Spring.Objects.Factory.Support.ChildObjectDefinition"/>.
        /// </summary>
        /// <param name="name">The name of the object instance to register.</param>
        /// <param name="definition">The definition of the object instance to register.</param>
        /// <remarks>
        /// 	<p>
        /// Must support
        /// <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/> and
        /// <see cref="Spring.Objects.Factory.Support.ChildObjectDefinition"/>.
        /// </p>
        /// </remarks>
        /// <exception cref="Spring.Objects.ObjectsException">
        /// If the object definition is invalid.
        /// </exception>
        public virtual void RegisterObjectDefinition(string name, IObjectDefinition definition)
        {
            ObjectFactory.RegisterObjectDefinition(name, definition);
        }

        /// <summary>
        /// Given a object name, create an alias. We typically use this method to
        /// support names that are illegal within XML ids (used for object names).
        /// </summary>
        /// <param name="name">The name of the object.</param>
        /// <param name="theAlias">The alias that will behave the same as the object name.</param>
        /// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
        /// If there is no object with the given name.
        /// </exception>
        /// <exception cref="Spring.Objects.Factory.ObjectDefinitionStoreException">
        /// If the alias is already in use.
        /// </exception>
        public virtual void RegisterAlias(string name, string theAlias)
        {
            ObjectFactory.RegisterAlias(name, theAlias);
        }

        #endregion

        #region IMessageSource Members

        /// <summary>
        /// Resolve the message identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the message to resolve.</param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> that represents
        /// the culture for which the resource is localized.
        /// </param>
        /// <param name="arguments">
        /// The array of arguments that will be filled in for parameters within
        /// the message, or <see langword="null"/> 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
        /// <see cref="System.String.Format(string,object[])"/> method.
        /// </param>
        /// <returns>
        /// The resolved message if the lookup was successful (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If no message could be resolved.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string, CultureInfo, object[])"/>
        public string GetMessage(
            string name, CultureInfo culture, params object[] arguments)
        {
            return MessageSource.GetMessage(name, culture, arguments);
        }

        /// <summary>
        /// Resolve the message identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the message to resolve.</param>
        /// <param name="defaultMessage">The default message.</param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> that represents
        /// the culture for which the resource is localized.
        /// </param>
        /// <param name="arguments">
        /// The array of arguments that will be filled in for parameters within
        /// the message, or <see langword="null"/> 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
        /// <see cref="System.String.Format(string,object[])"/> method.
        /// </param>
        /// <returns>
        /// The resolved message if the lookup was successful (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If no message could be resolved.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string, CultureInfo, object[])"/>
        public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
        {
            return MessageSource.GetMessage(name, defaultMessage, culture, arguments);
        }

        /// <summary>
        /// Resolve the message identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the message to resolve.</param>
        /// <returns>
        /// The resolved message if the lookup was successful.
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If no message could be resolved.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string)"/>
        public string GetMessage(string name)
        {
            return MessageSource.GetMessage(name);
        }

        /// <summary>
        /// Resolve the message identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the message to resolve.</param>
        /// <param name="arguments">
        /// The array of arguments that will be filled in for parameters within
        /// the message, or <see langword="null"/> 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
        /// <see cref="System.String.Format(string,object[])"/> method.
        /// </param>
        /// <returns>
        /// The resolved message if the lookup was successful.
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If no message could be resolved.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string, object[])"/>
        public string GetMessage(string name, params object[] arguments)
        {
            return MessageSource.GetMessage(name, arguments);
        }

        /// <summary>
        /// Resolve the message identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the message to resolve.</param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> that represents
        /// the culture for which the resource is localized.
        /// </param>
        /// <returns>
        /// The resolved message if the lookup was successful (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If no message could be resolved.
        /// </exception>
        /// <exception cref="System.ArgumentNullException">
        /// If the supplied <paramref name="name"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string, CultureInfo)"/>
        public string GetMessage(string name, CultureInfo culture)
        {
            return MessageSource.GetMessage(name, culture);
        }

        /// <summary>
        /// Resolve the message using all of the attributes contained within
        /// the supplied <see cref="Spring.Context.IMessageSourceResolvable"/>
        /// argument.
        /// </summary>
        /// <param name="resolvable">
        /// The value object storing those attributes that are required to
        /// properly resolve a message.
        /// </param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> that represents
        /// the culture for which the resource is localized.
        /// </param>
        /// <returns>
        /// The resolved message if the lookup was successful (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If the message could not be resolved.
        /// </exception>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(IMessageSourceResolvable, CultureInfo)"/>
        public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
        {
            return MessageSource.GetMessage(resolvable, culture);
        }

        /// <summary>
        /// Gets a localized resource object identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">
        /// The name of the resource object to resolve.
        /// </param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.
        /// </param>
        /// <returns>
        /// The resolved object, or <see langword="null"/> if not found.
        /// </returns>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string, CultureInfo)"/>
        object IMessageSource.GetResourceObject(string name, CultureInfo culture)
        {
            return GetResourceObject(name, culture);
        }

        /// <summary>
        /// Gets a localized resource object identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">
        /// The name of the resource object to resolve.
        /// </param>
        /// <returns>
        /// The resolved object, or <see langword="null"/> if not found.
        /// </returns>
        /// <seealso cref="Spring.Context.IMessageSource.GetMessage(string)"/>
        object IMessageSource.GetResourceObject(string name)
        {
            return GetResourceObject(name);
        }

        /// <summary>
        /// Gets a localized resource object identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">
        /// The name of the resource object to resolve.
        /// </param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.
        /// </param>
        /// <returns>
        /// The resolved object, or <see langword="null"/> if not found.
        /// </returns>
        /// <seealso cref="Spring.Context.IMessageSource.GetResourceObject(string, CultureInfo)"/>
        public object GetResourceObject(string name, CultureInfo culture)
        {
            return MessageSource.GetResourceObject(name, culture);
        }

        /// <summary>
        /// Gets a localized resource object identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <param name="name">
        /// The name of the resource object to resolve.
        /// </param>
        /// <returns>
        /// The resolved object, or <see langword="null"/> if not found.
        /// </returns>
        /// <seealso cref="Spring.Context.IMessageSource.GetResourceObject(string)"/>
        public object GetResourceObject(string name)
        {
            return MessageSource.GetResourceObject(name);
        }

        /// <summary>
        /// Applies resources to object properties.
        /// </summary>
        /// <param name="value">
        /// An object that contains the property values to be applied.
        /// </param>
        /// <param name="objectName">
        /// The base name of the object to use for key lookup.
        /// </param>
        /// <param name="culture">
        /// The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.
        /// </param>
        /// <seealso cref="Spring.Context.IMessageSource.ApplyResources(object, string, CultureInfo)"/>
        public void ApplyResources(object value, string objectName, CultureInfo culture)
        {
            MessageSource.ApplyResources(value, objectName, culture);
        }

        #endregion

        #region IEventRegistry Members

        /// <summary>
        /// Publishes <b>all</b> events of the source object.
        /// </summary>
        /// <param name="sourceObject">
        /// The source object containing events to publish.
        /// </param>
        /// <seealso cref="Spring.Objects.Events.IEventRegistry.PublishEvents"/>
        public void PublishEvents(object sourceObject)
        {
            _eventRegistry.PublishEvents(sourceObject);
        }

        /// <summary>
        /// Subscribes to <b>all</b> events published, if the subscriber
        /// implements compatible handler methods.
        /// </summary>
        /// <param name="subscriber">The subscriber to use.</param>
        /// <seealso cref="Spring.Objects.Events.IEventRegistry.Subscribe(object)"/>
        public void Subscribe(object subscriber)
        {
            _eventRegistry.Subscribe(subscriber);
        }

        /// <summary>
        /// Subscribes to published events of a all objects of a given
        /// <see cref="System.Type"/>, if the subscriber implements
        /// compatible handler methods.
        /// </summary>
        /// <param name="subscriber">The subscriber to use.</param>
        /// <param name="targetSourceType">
        /// The target <see cref="System.Type"/> to subscribe to.
        /// </param>
        /// <seealso cref="Spring.Objects.Events.IEventRegistry.Subscribe(object, Type)"/>
        public void Subscribe(object subscriber, Type targetSourceType)
        {
            _eventRegistry.Subscribe(subscriber, targetSourceType);
        }


        /// <summary>
        /// Unsubscribes to <b>all</b> events published, if the subscriber
        /// implmenets compatible handler methods.
        /// </summary>
        /// <param name="subscriber">The subscriber to use</param>
        public void Unsubscribe(object subscriber)
        {
            _eventRegistry.Unsubscribe(subscriber);
        }

        /// <summary>
        /// Unsubscribes to the published events of all objects of a given
        /// <see cref="System.Type"/>, if the subscriber implements
        /// compatible handler methods.
        /// </summary>
        /// <param name="subscriber">The subscriber to use.</param>
        /// <param name="targetSourceType">
        /// The target <see cref="System.Type"/> to unsubscribe from
        /// </param>
        public void Unsubscribe(object subscriber, Type targetSourceType)
        {
            _eventRegistry.Unsubscribe(subscriber, targetSourceType);
        }

        #endregion

        #region IApplicationEventPublisher

        /// <summary>
        /// Publishes an application context event.
        /// </summary>
        /// <remarks>
        /// <p>
        /// 
        /// </p>
        /// </remarks>
        /// <param name="sender">
        /// The source of the event. May be <see langword="null"/>.
        /// </param>
        /// <param name="e">
        /// The event that is to be raised.
        /// </param>
        /// <seealso cref="Spring.Context.IApplicationEventPublisher.PublishEvent"/>
        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);
            }
        }

        #endregion

        #region IPostProcessor implementation

        private sealed class ObjectPostProcessorChecker : IObjectPostProcessor, IOrdered
        {
            private readonly ILog log;
            private int _objectPostProcessorTargetCount;
            private IConfigurableListableObjectFactory _objectFactory;


            public ObjectPostProcessorChecker()
            {
                log = LogManager.GetLogger(this.GetType());
            }

            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;
            }

            public int Order
            {
                get { return Int32.MinValue; }
            }
        }

        #endregion
    }
}