AbstractMessageSource.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 » AbstractMessageSource.cs
#region License

/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#endregion

using System;
using System.Globalization;
using Common.Logging;

namespace Spring.Context.Support{
    /// <summary>
    /// Abstract implementation of the <see cref="Spring.Context.IHierarchicalMessageSource"/> interface,
    /// implementing common handling of message variants, making it easy
    /// to implement a specific strategy for a concrete <see cref="Spring.Context.IMessageSource"/>.
    /// </summary>
    /// <remarks>
    /// <p>Subclasses must implement the abstract <code>ResolveObject</code>
    /// method.</p>
    /// <p><b>Note:</b> By default, message texts are only parsed through
    /// String.Format if arguments have been passed in for the message. In case
    /// of no arguments, message texts will be returned as-is. As a consequence,
    /// you should only use String.Format escaping for messages with actual
    /// arguments, and keep all other messages unescaped.
    /// </p>
    /// <p>Supports not only IMessageSourceResolvables as primary messages
    /// but also resolution of message arguments that are in turn
    /// IMessageSourceResolvables themselves.
    /// </p>
    /// <p>This class does not implement caching of messages per code, thus
    /// subclasses can dynamically change messages over time. Subclasses are
    /// encouraged to cache their messages in a modification-aware fashion,
    /// allowing for hot deployment of updated messages.
    /// </p>
    /// </remarks>
    /// <author>Rod Johnson</author>
    /// <author>Juergen Hoeller</author>
    /// <author>Griffin Caprio (.NET)</author>
    /// <author>Harald Radi (.NET)</author>
    /// <seealso cref="Spring.Context.IMessageSourceResolvable"/>
    /// <seealso cref="Spring.Context.IMessageSource"/>
    /// <seealso cref="Spring.Context.IHierarchicalMessageSource"/>
    public abstract class AbstractMessageSource : IHierarchicalMessageSource
    {
        #region Fields

        /// <summary>
        /// holds the logger instance shared with subclasses.
        /// </summary>
        protected readonly ILog log;

        private IMessageSource parentMessageSource;
        private bool useCodeAsDefaultMessage = false;

        #endregion

        #region Constructor

    /// <summary>
    /// Initializes this instance.
    /// </summary>
        protected AbstractMessageSource()
        {
            log = LogManager.GetLogger(GetType());
        }

        #endregion

        #region Properties


        /// <summary>Gets or Sets a value indicating whether to use the message code as 
        /// default message instead of throwing a NoSuchMessageException. 
        /// Useful for development and debugging. Default is "false".
        /// </summary>
        /// <remarks>
        /// <p>Note: In case of a IMessageSourceResolvable with multiple codes
        /// (like a FieldError) and a MessageSource that has a parent MessageSource,
        /// do <i>not</i> activate "UseCodeAsDefaultMessage" in the <i>parent</i>:
        /// Else, you'll get the first code returned as message by the parent,
        /// without attempts to check further codes.</p>
        /// <p>To be able to work with "UseCodeAsDefaultMessage" turned on in the parent,
        /// AbstractMessageSource contains special checks
        /// to delegate to the internal <code>GetMessageInternal</code> method if available.
        /// In general, it is recommended to just use "UseCodeAsDefaultMessage" during
        /// development and not rely on it in production in the first place, though.</p>
        /// <p>Alternatively, consider overriding the <code>GetDefaultMessage</code>
        /// method to return a custom fallback message for an unresolvable code.</p>
        /// </remarks>
        /// <value>
        ///   <c>true</c> if use the message code as default message instead of 
        /// throwing a NoSuchMessageException; otherwise, <c>false</c>.
        /// </value>
        public bool UseCodeAsDefaultMessage
        {
            get { return useCodeAsDefaultMessage; }
            set { useCodeAsDefaultMessage = value; }
        }

        #endregion

        #region IHierarchicalMessageSource Members

        /// <summary>
        /// The parent message source used to try and resolve messages that
        /// this object can't resolve.
        /// </summary>
        /// <value></value>
        /// <remarks>
        ///   <p>
        /// If the value of this property is <see langword="null"/> then no
        /// further resolution is possible.
        /// </p>
        /// </remarks>
        public IMessageSource ParentMessageSource
        {
            get { return parentMessageSource; }
            set { parentMessageSource = value; }
        }

        /// <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 (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <remarks>
        /// If the lookup is not successful throw NoSuchMessageException
        /// </remarks>
        public string GetMessage(string name)
        {
            return GetMessage(name, CultureInfo.CurrentUICulture, null);
        }

        /// <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>
        /// <remarks>
        /// Note that the fallback behavior based on CultureInfo seem to
        /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
        /// <p>
        /// If the lookup is not successful, implementations are permitted to
        /// take one of two actions.
        /// </p>
        /// If the lookup is not successful throw NoSuchMessageException
        /// </remarks>
        public string GetMessage(string name, CultureInfo culture)
        {
            return GetMessage(name, culture, null);
        }

        /// <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 (see above for
        /// the return value in the case of an unsuccessful lookup).
        /// </returns>
        /// <remarks>
        /// If the lookup is not successful throw NoSuchMessageException
        /// </remarks>
        public string GetMessage(string name, params object[] arguments)
        {
            return GetMessage(name, CultureInfo.CurrentUICulture, 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>
        /// <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>
        /// <remarks>
        /// Note that the fallback behavior based on CultureInfo seem to
        /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
        /// <p>
        /// If the lookup is not successful throw NoSuchMessageException.
        /// </p>
        /// </remarks>        
        public string GetMessage(string name, CultureInfo culture, params object[] arguments)
        {
            string msg = GetMessageInternal(name, arguments, culture);
            if (msg != null) return msg;
            string fallback = GetDefaultMessage(name);
            if (fallback != null) return fallback;
            throw new NoSuchMessageException(name, culture);
        }

        /// <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 if name is not found.</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>
        /// <remarks>
        /// Note that the fallback behavior based on CultureInfo seem to
        /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
        /// <p>
        /// If the lookup is not successful throw NoSuchMessageException
        /// </p>
        /// </remarks>
        public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
        {
            string msg = GetMessageInternal(name, arguments, culture);
            if (msg != null) return msg;
            if (defaultMessage == null)
            {
                string fallback = GetDefaultMessage(name);
                if (fallback != null) return fallback;
            }
            return RenderDefaultMessage(defaultMessage, arguments, 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.
        /// </returns>
        /// <exception cref="Spring.Context.NoSuchMessageException">
        /// If the message could not be resolved.
        /// </exception>
        public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
        {
            string[] codes = resolvable.GetCodes();
            if (codes == null) codes = new string[0];
            for (int i = 0; i < codes.Length; i++)
            {
                string msg = GetMessageInternal(codes[i], resolvable.GetArguments(), culture);
                if (msg != null) return msg;
            }
            if (resolvable.DefaultMessage != null)
                return RenderDefaultMessage(resolvable.DefaultMessage, resolvable.GetArguments(), culture);
            if (codes.Length > 0)
            {
                string fallback = GetDefaultMessage(codes[0]);
                if (fallback != null) return fallback;
            }
            throw new NoSuchMessageException(codes.Length > 0 ? codes[codes.Length - 1] : null, 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)
        {
            object resource = GetResourceInternal(name, CultureInfo.CurrentUICulture);
            if (resource != null) return resource;
            if (ParentMessageSource != null)
                return ParentMessageSource.GetResourceObject(name, CultureInfo.CurrentUICulture);
            return null;
        }

        /// <summary>
        /// Gets a localized resource object identified by the supplied
        /// <paramref name="name"/>.
        /// </summary>
        /// <remarks>
        /// Note that the fallback behavior based on CultureInfo seem to 
        /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.  
        /// </remarks>      
        /// <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.  If
        /// the resource name resolves to null, then in .NET 1.1 the return
        /// value will be String.Empty whereas in .NET 2.0 it will return
        /// null.
        /// </returns>
        /// <seealso cref="Spring.Context.IMessageSource.GetResourceObject(string, CultureInfo)"/>
        public object GetResourceObject(string name, CultureInfo culture)
        {
            object resource = GetResourceInternal(name, culture);
            if (resource != null) return resource;
            if (ParentMessageSource != null) return ParentMessageSource.GetResourceObject(name, culture);
            return null;
        }

        /// <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)
        {
            ApplyResourcesInternal(value, objectName, culture);
            if (ParentMessageSource != null) ParentMessageSource.ApplyResources(value, objectName, culture);
        }

        #endregion

        #region Protected Methods

        /// <summary>Resolve the given code and arguments as message in the given culture,
        /// returning null if not found. Does <i>not</i> fall back to the code
        /// as default message. Invoked by GetMessage methods.
        /// </summary>
        /// <param name="code">The code to lookup up, such as 'calculator.noRateSet'.</param>
        /// <param name="args"> array of arguments that will be filled in for params
        /// within the message.</param>
        /// <param name="culture">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>
        /// The resolved message if the lookup was successful.
        /// </returns>
        protected string GetMessageInternal(string code, object[] args, CultureInfo culture)
        {
            if (code == null) return null;
            if (culture == null) culture = CultureInfo.CurrentUICulture;

            if ((args != null && args.Length > 0))
            {
                // Resolve arguments eagerly, for the case where the message
                // is defined in a parent MessageSource but resolvable arguments
                // are defined in the child MessageSource.
                args = ResolveArguments(args, culture);
            }

            string message = ResolveMessage(code, culture);

            if (message != null) return FormatMessage(message, args, culture);

            // Not found -> check parent, if any.
            return GetMessageFromParent(code, args, culture);
        }


        /// <summary>
        /// Try to retrieve the given message from the parent MessageSource, if any.
        /// </summary>
        /// <param name="code">The code to lookup up, such as 'calculator.noRateSet'.</param>
        /// <param name="args"> array of arguments that will be filled in for params
        /// within the message.</param>
        /// <param name="culture">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>
        /// The resolved message if the lookup was successful.
        /// </returns>
        protected string GetMessageFromParent(string code, object[] args, CultureInfo culture)
        {
            if (ParentMessageSource != null)
            {
                AbstractMessageSource parent = ParentMessageSource as AbstractMessageSource;
                if (parent != null)
                {
                    // Call internal method to avoid getting the default code back
                    // in case of "useCodeAsDefaultMessage" being activated.
                    return parent.GetMessageInternal(code, args, culture);
                }
                else
                {
                    // Check parent MessageSource, returning null if not found there.
                    return ParentMessageSource.GetMessage(code, null, culture, args);
                }
            }
            // Not found in parent either.
            return null;
        }


        /// <summary>
        /// Return a fallback default message for the given code, if any.
        /// </summary>
        /// <remarks>
        /// Default is to return the code itself if "UseCodeAsDefaultMessage"
        /// is activated, or return no fallback else. In case of no fallback,
        /// the caller will usually receive a NoSuchMessageException from GetMessage
        /// </remarks>
        /// <param name="code">The code to lookup up, such as 'calculator.noRateSet'.</param>
        /// <returns>The default message to use, or null if none.</returns>
        protected virtual string GetDefaultMessage(string code)
        {
            if (UseCodeAsDefaultMessage) return code;
            return null;
        }



        /// <summary>
        /// Renders the default message string.  The default message is passed in as specified by the
        /// caller and can be rendered into a fully formatted default message shown to the user.
        /// </summary>
        /// <remarks>Default implementation passed he String for String.Format resolving any 
        /// argument placeholders found in them.  Subclasses may override this method to plug
        /// in custom processing of default messages.
        /// </remarks>
        /// <param name="defaultMessage">The default message.</param>
        /// <param name="args">The array of agruments that will be filled in for parameter
        /// placeholders within the message, or null if none.</param>
        /// <param name="culture">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>The rendered default message (with resolved arguments)</returns>
        protected virtual string RenderDefaultMessage(string defaultMessage, object[] args, CultureInfo culture)
        {
            return FormatMessage(defaultMessage, args, culture);
        }

        /// <summary>
        /// Format the given default message String resolving any 
        /// agrument placeholders found in them.
        /// </summary>
        /// <param name="msg">The message to format.</param>
        /// <param name="args">The array of agruments that will be filled in for parameter
        /// placeholders within the message, or null if none.</param>
        /// <param name="culture">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>The formatted message (with resolved arguments)</returns>
        protected virtual string FormatMessage(string msg, object[] args, CultureInfo culture)
        {
            if (msg == null || ((args == null || args.Length == 0))) return msg;
            return String.Format(culture, msg, args);
        }


        /// <summary>
        /// Search through the given array of objects, find any
        /// MessageSourceResolvable objects and resolve them.
        /// </summary>
        /// <remarks>
        /// Allows for messages to have MessageSourceResolvables as arguments.
        /// </remarks>
        /// 
        /// <param name="args">The array of arguments for a message.</param>
        /// <param name="culture">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>An array of arguments with any IMessageSourceResolvables resolved</returns>
        protected virtual object[] ResolveArguments(object[] args, CultureInfo culture)
        {
            if (args == null) return new object[0];
            object[] resolvedArgs = new object[args.Length];

            for (int i = 0; i < args.Length; i++)
            {
                IMessageSourceResolvable resolvable = args[i] as IMessageSourceResolvable;
                if (resolvable != null) resolvedArgs[i] = GetMessage(resolvable, culture);
                else resolvedArgs[i] = args[i];
            }

            return resolvedArgs;
        }

    /// <summary>
    /// Gets the specified resource (e.g. Icon or Bitmap).
    /// </summary>
    /// <param name="name">The name of the resource to resolve.</param>
    /// <param name="cultureInfo">
    /// The <see cref="System.Globalization.CultureInfo"/> to resolve the
    /// code for.
    /// </param>
    /// <returns>The resource if found. <see langword="null"/> otherwise.</returns>
        protected object GetResourceInternal(string name, CultureInfo cultureInfo)
        {
            if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
            if (name == null) return null;
            return ResolveObject(name, cultureInfo);
        }

    /// <summary>
    /// Applies resources from the given name on the specified object.
    /// </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="cultureInfo">
    /// The <see cref="System.Globalization.CultureInfo"/> with which the
    /// resource is associated.
    /// </param>
    protected void ApplyResourcesInternal(object value, string objectName, CultureInfo cultureInfo)
        {
            if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
            ApplyResourcesToObject(value, objectName, cultureInfo);
        }

        #endregion

        #region Protected Abstract Methods

        /// <summary>
        /// Subclasses must implement this method to resolve a message.
        /// </summary>
        /// <param name="code">The code to lookup up, such as 'calculator.noRateSet'.</param>
        /// <param name="cultureInfo">The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.</param>
        /// <returns>The resolved message from the backing store of message data.</returns>
        protected abstract string ResolveMessage(string code, CultureInfo cultureInfo);

        /// <summary>
        /// Resolves an object (typically an icon or bitmap).
        /// </summary>
        /// <remarks>
        /// <p>
        /// Subclasses must implement this method to resolve an object.
        /// </p>
        /// </remarks>
        /// <param name="code">The code of the object to resolve.</param>
        /// <param name="cultureInfo">
        /// The <see cref="System.Globalization.CultureInfo"/> to resolve the
        /// code for.
        /// </param>
        /// <returns>
        /// The resolved object or <see langword="null"/> if not found.
        /// </returns>
        protected abstract object ResolveObject(string code, CultureInfo cultureInfo);

        /// <summary>
        /// Applies resources to object properties.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Subclasses must implement this method to apply resources
        /// to an arbitrary object.
        /// </p>
        /// </remarks>
        /// <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="cultureInfo">
        /// The <see cref="System.Globalization.CultureInfo"/> with which the
        /// resource is associated.
        /// </param>
        protected abstract void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo);


        #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.