ContextHandler.cs :  » Inversion-of-Control-Dependency-Injection » Spring.net » Spring » Context » Support » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Inversion of Control Dependency Injection » Spring.net 
Spring.net » Spring » Context » Support » ContextHandler.cs
#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.Configuration;
using System.Reflection;
using System.Xml;

using Common.Logging;
using Spring.Core;
using Spring.Core.TypeResolution;
using Spring.Objects;
using Spring.Reflection.Dynamic;
using Spring.Util;

#endregion

namespace Spring.Context.Support{
  /// <summary>
  /// Creates an <see cref="Spring.Context.IApplicationContext"/> instance
  /// using context definitions supplied in a custom configuration and
  /// configures the <see cref="ContextRegistry"/> with that instance.
  /// </summary>
  /// <remarks>
  /// Implementations of the <see cref="Spring.Context.IApplicationContext"/>
  /// interface <b>must</b> provide the following two constructors:
  /// <list type="number">
  /// <item>
  /// <description>
  /// A constructor that takes a string array of resource locations.
  /// </description>
  /// </item>
  /// <item>
  /// <description>
  /// A constructor that takes a reference to a parent application context
  /// and a string array of resource locations (and in that order).
  /// </description>
  /// </item>
  /// </list>
  /// <p>
  /// Note that if the <c>type</c> attribute is not present in the declaration
  /// of a particular context, then a default
  /// <see cref="Spring.Context.IApplicationContext"/> <see cref="System.Type"/>
  /// is assumed. This default
  /// <see cref="Spring.Context.IApplicationContext"/> <see cref="System.Type"/>
  /// is currently the <see cref="Spring.Context.Support.XmlApplicationContext"/>
  /// <see cref="System.Type"/>; please note the exact <see cref="System.Type"/>
  /// of this default <see cref="Spring.Context.IApplicationContext"/> is an
  /// implementation detail, that, while unlikely, may do so in the future.
  /// to
  /// </p>
  /// </remarks>
  /// <example>
  /// <p>
  /// This is an example of specifying a context that reads its resources from
  /// an embedded Spring.NET XML object configuration file...
  /// </p>
  /// <code escaped="true">
  /// <configuration>
  ///     <configSections>
  ///        <sectionGroup name="spring">
  ///          <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
  ///        </sectionGroup>
  ///     </configSections>
  ///     <spring>
  ///        <context>
  ///          <resource uri="assembly://MyAssemblyName/MyResourceNamespace/MyObjects.xml"/>
  ///        </context>
  ///     </spring>
  /// </configuration>
  /// </code>
  /// <p>
  /// This is an example of specifying a context that reads its resources from
  /// a custom configuration section within the same application / web
  /// configuration file and uses case insensitive object lookups. 
  /// </p>
  /// <p>
  /// Please note that you <b>must</b> adhere to the naming
  /// of the various sections (i.e. '&lt;sectionGroup name="spring"&gt;' and
  /// '&lt;section name="context"&gt;'.
  /// </p>
  /// <code escaped="true">
  /// <configuration>
  ///     <configSections>
  ///        <sectionGroup name="spring">
  ///          <section name="context"
  ///            type="Spring.Context.Support.ContextHandler, Spring.Core"/>
  ///          <section name="objects"
  ///            type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
  ///        </sectionGroup>
  ///     </configSections>
  ///     <spring>
  ///        <context
  ///            caseSensitive="false"
  ///          type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
  ///          <resource uri="config://spring/objects"/>
  ///        </context>
  ///        <objects xmlns="http://www.springframework.net">
  ///          <!-- object definitions... -->
  ///        </objects>
  ///     </spring>
  /// </configuration>
  /// </code>
  /// <p>
  /// And this is an example of specifying a hierarchy of contexts. The
  /// hierarchy in this case is only a simple parent->child hierarchy, but
  /// hopefully it illustrates the nesting of context configurations. This
  /// nesting of contexts can be arbitrarily deep, and is one way... child
  /// contexts know about their parent contexts, but parent contexts do not
  /// know how many child contexts they have (if any), or have references
  /// to any such child contexts.
  /// </p>
  /// <code escaped="true">
  /// <configuration>
  ///   <configSections>
  ///     <sectionGroup name='spring'>
  ///       <section name='context'  type='Spring.Context.Support.ContextHandler, Spring.Core'/>
  ///       <section name='objects'  type='Spring.Context.Support.DefaultSectionHandler, Spring.Core' />
    ///             <sectionGroup name="child">
  ///           <section name='objects' type='Spring.Context.Support.DefaultSectionHandler, Spring.Core' />
    ///             </sectionGroup>
  ///     </sectionGroup>
  ///   </configSections>
  ///   
  ///     <spring>
  ///     <context name='Parent'>
  ///       <resource uri='config://spring/objects'/>
  ///         <context name='Child'>
  ///           <resource uri='config://spring/childObjects'/>
  ///         </context>
  ///     </context>
  ///     <!-- parent context's objects -->
  ///     <objects xmlns='http://www.springframework.net'>
  ///       <object id='Parent' type='Spring.Objects.TestObject,Spring.Core.Tests'>
  ///                 <property name='name' value='Parent'/>
  ///             </object>
  ///     </objects>
  ///     <!-- child context's objects -->
    ///         <child>
    ///         <objects xmlns='http://www.springframework.net'>
  ///           <object id='Child' type='Spring.Objects.TestObject,Spring.Core.Tests'>
  ///                     <property name='name' value='Child'/>
  ///                 </object>
    ///         </objects>
    ///         </child>
  ///     </spring>
  /// </configuration>
  /// </code>
  /// </example>
  /// <author>Mark Pollack</author>
  /// <author>Aleksandar Seovic</author>
  /// <author>Rick Evans</author>
  /// <seealso cref="ContextRegistry"/>
  public class ContextHandler : IConfigurationSectionHandler
  {
    private readonly ILog Log = LogManager.GetLogger(typeof(ContextHandler));
    
    /// <summary>
    /// The <see cref="System.Type"/> of <see cref="Spring.Context.IApplicationContext"/>
    /// created if no <c>type</c> attribute is specified on a <c>context</c> element.
    /// </summary>
    /// <seealso cref="GetContextType"/>
    protected virtual Type DefaultApplicationContextType
    {
      get { return typeof (XmlApplicationContext); }
    }

    /// <summary>
    /// Get the context's case-sensitivity to use if none is specified
    /// </summary>
    /// <remarks>
    /// <p>
    /// Derived handlers may override this property to change their default case-sensitivity.
    /// </p>
    /// <p>
    /// Defaults to 'true'.
    /// </p>
    /// </remarks>
    protected virtual bool DefaultCaseSensitivity
    {
      get { return true; }
    }
    
      /// <summary>
      /// Creates an <see cref="Spring.Context.IApplicationContext"/> instance
      /// using the context definitions supplied in a custom
      /// configuration section.
      /// </summary>
      /// <remarks>
      /// <p>
      /// This <see cref="Spring.Context.IApplicationContext"/> instance is
      /// also used to configure the <see cref="ContextRegistry"/>.
      /// </p>
      /// </remarks>
      /// <param name="parent">
      /// The configuration settings in a corresponding parent
      /// configuration section.
      /// </param>
      /// <param name="configContext">
      /// The configuration context when called from the ASP.NET
      /// configuration system. Otherwise, this parameter is reserved and
      /// is <see langword="null"/>.
      /// </param>
      /// <param name="section">
      /// The <see cref="System.Xml.XmlNode"/> for the section.
      /// </param>
      /// <returns>
      /// An <see cref="Spring.Context.IApplicationContext"/> instance
      /// populated with the object definitions supplied in the configuration
      /// section.
      /// </returns>
      public object Create(object parent, object configContext, XmlNode section)
      {
        XmlElement contextElement = section as XmlElement;

      #region Sanity Checks

        if (contextElement == null)
        {
          throw ConfigurationUtils.CreateConfigurationException(
            "Context configuration section must be an XmlElement.");
        }

        // sanity check on parent
        if ( (parent != null) && !(parent is IApplicationContext) )
        {
          throw ConfigurationUtils.CreateConfigurationException( 
            String.Format("Parent context must be of type IApplicationContext, but was '{0}'", parent.GetType().FullName));
        }

        #endregion
                    
      // determine name of context to be created
      string contextName = GetContextName(configContext, contextElement);
      if (!StringUtils.HasLength(contextName))
      {
        contextName = AbstractApplicationContext.DefaultRootContextName;
      }
        
      #region Instrumentation
      if (Log.IsDebugEnabled) Log.Debug(string.Format("creating context '{0}'", contextName ) );
      #endregion
        
        IApplicationContext context = null;
          try
          {
            IApplicationContext parentContext = parent as IApplicationContext;
            
              // determine context type
            Type contextType = GetContextType(contextElement, parentContext);

            // determine case-sensitivity
            bool caseSensitive = GetCaseSensitivity(contextElement);

            // get resource-list
            string[] resources = GetResources(contextElement);
            
            // finally create the context instance
        context = InstantiateContext(parentContext, configContext, contextName, contextType, caseSensitive, resources);

        // get and create child context definitions
                XmlNode[] childContexts = GetChildContexts(contextElement);
        CreateChildContexts(context, configContext, childContexts);

            if (Log.IsDebugEnabled) Log.Debug( string.Format("context '{0}' created for name '{1}'", context, contextName) );
          }
          catch (Exception ex)
          {
              if (!ConfigurationUtils.IsConfigurationException(ex))
              {
                    throw ConfigurationUtils.CreateConfigurationException(
                        String.Format("Error creating context '{0}': {1}", 
                        contextName, ReflectionUtils.GetExplicitBaseException(ex).Message), ex);
              }
              throw;
          }
          return context;
      }

    /// <summary>
    /// Create all child-contexts in the given <see cref="XmlNodeList"/> for the given context.
    /// </summary>
    /// <param name="parentContext">The parent context to use</param>
    /// <param name="configContext">The current configContext <see cref="IConfigurationSectionHandler.Create"/></param>
    /// <param name="childContexts">The list of child context elements</param>
    protected virtual void CreateChildContexts(IApplicationContext parentContext, object configContext, XmlNode[] childContexts)
    {  
      // create child contexts for 'the most recently created context'...
      foreach (XmlNode childContext in childContexts)
      {
        this.Create(parentContext, configContext, childContext);
      }
    }

    /// <summary>
    /// Instantiates a new context.
    /// </summary>
    protected virtual IApplicationContext InstantiateContext(IApplicationContext parentContext, object configContext, string contextName, Type contextType, bool caseSensitive, string[] resources)
    {
      IApplicationContext context;
      ContextInstantiator instantiator;
      
      if (parentContext == null)
      {
        instantiator = new RootContextInstantiator(contextType, contextName, caseSensitive, resources);
      } 
      else
      {
        instantiator = new DescendantContextInstantiator(parentContext, contextType, contextName, caseSensitive, resources);
      }
      
      if (IsLazy)
      {
        // TODO
      }
      context = instantiator.InstantiateContext();
      return context;
    }

    /// <summary>
    /// Gets the context's name specified in the name attribute of the context element.
    /// </summary>
    /// <param name="configContext">The current configContext <see cref="IConfigurationSectionHandler.Create"/></param>
    /// <param name="contextElement">The context element</param>
    protected virtual string GetContextName(object configContext, XmlElement contextElement)
    {
      string contextName;
      contextName = contextElement.GetAttribute(ContextSchema.NameAttribute);
      return contextName;
    }
    
    /// <summary>
    /// Extracts the context-type from the context element. 
    /// If none is specified, returns the parent's type.
    /// </summary>
    private Type GetContextType(XmlElement contextElement, IApplicationContext parentContext)
    {
      Type contextType;
      if (parentContext != null)
      {
        // set default context type to parent's type (allows for type inheritance)
        contextType = GetConfiguredContextType(contextElement, parentContext.GetType());
      }
      else
      {
        contextType = GetConfiguredContextType(contextElement, this.DefaultApplicationContextType);
      }
      return contextType;
    }

    /// <summary>
    /// Extracts the case-sensitivity attribute from the context element
    /// </summary>
    private  bool GetCaseSensitivity(XmlElement contextElement)
    {
      bool caseSensitive = DefaultCaseSensitivity;
      
      string caseSensitiveAttr = contextElement.GetAttribute(ContextSchema.CaseSensitiveAttribute);
      if (StringUtils.HasText(caseSensitiveAttr))
      {
        caseSensitive = Boolean.Parse(caseSensitiveAttr);
      }
      return caseSensitive;
    }

    /// <summary>
      /// Gets the context <see cref="System.Type"/> specified in the type
      /// attribute of the context element.
      /// </summary>
      /// <remarks>
      /// <p>
      /// If this attribute is not defined it defaults to the
      /// <see cref="Spring.Context.Support.XmlApplicationContext"/> type.
      /// </p>
      /// </remarks>
      /// <exception cref="TypeMismatchException">
      /// If the context type does not implement the
      /// <see cref="Spring.Context.IApplicationContext"/> interface.
      /// </exception>
      private Type GetConfiguredContextType(XmlElement contextElement, Type defaultContextType)
      {
            string typeName = contextElement.GetAttribute(ContextSchema.TypeAttribute);
      
            if (StringUtils.IsNullOrEmpty(typeName))
            {
                return defaultContextType;
            }
            else
            {
                Type type = TypeResolutionUtils.ResolveType(typeName);
                if (typeof(IApplicationContext).IsAssignableFrom(type))
                {
                    return type;
                }
                else
                {
                    throw new TypeMismatchException( type.Name + " does not implement IApplicationContext.");
                }
            }
      }

      /// <summary>
      /// Returns <see langword="true"/> if the context should be lazily
      /// initialized.
      /// </summary>
      private bool IsLazy
      {
          get { return false; }
      }

      /// <summary>
      /// Returns the array of resources containing object definitions for
      /// this context.
      /// </summary>
      private string[] GetResources( XmlElement contextElement )
      {
          ArrayList resourceNodes = new ArrayList(contextElement.ChildNodes.Count);
          foreach (XmlNode possibleResourceNode in contextElement.ChildNodes)
          {
              XmlElement possibleResourceElement = possibleResourceNode as XmlElement;
              if(possibleResourceElement != null &&
                 possibleResourceElement.LocalName == ContextSchema.ResourceElement)
              {
                  string resourceName = possibleResourceElement.GetAttribute(ContextSchema.URIAttribute);
                  if(StringUtils.HasText(resourceName))
                  {
                      resourceNodes.Add(resourceName);
                  }
              }
          }
          return (string[]) resourceNodes.ToArray(typeof(string));
      }

        /// <summary>
        /// Returns the array of child contexts for this context.
        /// </summary>
        private XmlNode[] GetChildContexts(XmlElement contextElement)
        {
            ArrayList contextNodes = new ArrayList(contextElement.ChildNodes.Count);
            foreach (XmlNode possibleContextNode in contextElement.ChildNodes)
            {
                XmlElement possibleContextElement = possibleContextNode as XmlElement;
                if (possibleContextElement != null &&
                   possibleContextElement.LocalName == ContextSchema.ContextElement)
                {
                    contextNodes.Add(possibleContextElement);
                }
            }
            return (XmlNode[])contextNodes.ToArray(typeof(XmlNode));
        }

      #region Inner Class : ContextInstantiator

      private abstract class ContextInstantiator
      {
          protected ContextInstantiator(
              Type contextType, string contextName, bool caseSensitive, string[] resources)
          {
              _contextType = contextType;
              _contextName = contextName;
                _caseSensitive = caseSensitive;
              _resources = resources;
          }

            public IApplicationContext InstantiateContext()
            {
                ConstructorInfo ctor = GetContextConstructor();
                if (ctor == null)
                {
                    string errorMessage = "No constructor with string[] argument found for context type [" + ContextType.Name + "]";
                    throw ConfigurationUtils.CreateConfigurationException(errorMessage);
                }
                IApplicationContext context = InvokeContextConstructor(ctor);
                ContextRegistry.RegisterContext(context);
                return context;
            }

          protected abstract ConstructorInfo GetContextConstructor();

          protected abstract IApplicationContext InvokeContextConstructor(
              ConstructorInfo ctor);

          protected Type ContextType
          {
              get { return _contextType; }
          }

          protected string ContextName
          {
              get { return _contextName; }
          }

          protected bool CaseSensitive
          {
              get { return _caseSensitive; }
          }

          protected string[] Resources
          {
              get { return _resources; }
          }

          private Type _contextType;
          private string _contextName;
            private bool _caseSensitive;
          private string[] _resources;
      }

      #endregion

      #region Inner Class : RootContextInstantiator

      private sealed class RootContextInstantiator : ContextInstantiator
      {
          public RootContextInstantiator(
              Type contextType, string contextName, bool caseSensitive, string[] resources)
              : base(contextType, contextName, caseSensitive, resources)
          {
          }

          protected override ConstructorInfo GetContextConstructor()
          {
              return ContextType.GetConstructor(new Type[] {typeof(string), typeof(bool), typeof(string[])});
          }

          protected override IApplicationContext InvokeContextConstructor(
              ConstructorInfo ctor)
          {
                return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, Resources}));
          }
      }

      #endregion

      #region Inner Class : DescendantContextInstantiator

      private sealed class DescendantContextInstantiator : ContextInstantiator
      {
          public DescendantContextInstantiator(
              IApplicationContext parentContext, Type contextType,
              string contextName, bool caseSensitive, string[] resources)
              : base(contextType, contextName, caseSensitive, resources)
          {
              this.parentContext = parentContext;
          }

          protected override ConstructorInfo GetContextConstructor()
          {
              return ContextType.GetConstructor(
                  new Type[] {typeof(string), typeof(bool), typeof(IApplicationContext), typeof(string[])});
          }

          protected override IApplicationContext InvokeContextConstructor(
              ConstructorInfo ctor)
          {
                return (IApplicationContext)(new SafeConstructor(ctor).Invoke(new object[] {ContextName, CaseSensitive, this.parentContext, Resources}));
          }

          private IApplicationContext parentContext;
      }

      #endregion

      #region Context Schema Constants

      /// <summary>
      /// Constants defining the structure and values associated with the
      /// schema for laying out Spring.NET contexts in XML.
      /// </summary>
      private sealed class ContextSchema
      {
          /// <summary>
          /// Defines a single
          /// <see cref="Spring.Context.IApplicationContext"/>.
          /// </summary>
          public const string ContextElement = "context";

          /// <summary>
          /// Specifies a context name.
          /// </summary>
          public const string NameAttribute = "name";

            /// <summary>
            /// Specifies if context should be case sensitive or not. Default is <c>true</c>.
            /// </summary>
            public const string CaseSensitiveAttribute = "caseSensitive";

          /// <summary>
          /// Specifies a <see cref="System.Type"/>.
          /// </summary>
          /// <remarks>
          /// <p>
          /// Does not have to be fully assembly qualified, but its generally regarded
          /// as better form if the <see cref="System.Type"/> names of one's objects
          /// are specified explicitly.
          /// </p>
          /// </remarks>
          public const string TypeAttribute = "type";

          /// <summary>
          /// Specifies whether context should be lazy initialized.
          /// </summary>
          public const string LazyAttribute = "lazy";

          /// <summary>
          /// Defines an <see cref="Spring.Core.IO.IResource"/>
          /// </summary>
          public const string ResourceElement = "resource";

          /// <summary>
          /// Specifies the URI for an
          /// <see cref="Spring.Core.IO.IResource"/>.
          /// </summary>
          public const string URIAttribute = "uri";
      }

      #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.