ObjectWrapper.cs :  » Inversion-of-Control-Dependency-Injection » Spring.net » Spring » Objects » 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 » Objects » ObjectWrapper.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

using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Text;

using Common.Logging;
using Spring.Core;
using Spring.Expressions;
using Spring.Expressions.Parser.antlr;
using Spring.Util;
using StringUtilsSpring.Util.StringUtils;

namespace Spring.Objects{
    /// <summary>
    /// Default implementation of the <see cref="Spring.Objects.IObjectWrapper"/>
    /// interface that should be sufficient for all normal uses.
    /// </summary>
    /// <remarks>
    /// <p>
    /// <see cref="Spring.Objects.ObjectWrapper"/> will convert
    /// <see cref="System.Collections.IList"/> and array
    /// values to the corresponding target arrays, if necessary. Custom
    /// <see cref="System.ComponentModel.TypeConverter"/>s that deal with
    /// <see cref="System.Collections.IList"/>s or arrays can be written against a
    /// comma delimited <see cref="System.String"/> as <see cref="System.String"/>
    /// arrays are converted in such a format if the array itself is not assignable.
    /// </p>
    /// </remarks>
    /// <author>Rod Johnson</author>
    /// <author>Juergen Hoeller </author>
    /// <author>Jean-Pierre Pawlak</author>
    /// <author>Mark Pollack (.NET)</author>
    /// <author>Aleksandar Seovic(.NET)</author>
    [Serializable]
    public class ObjectWrapper : IObjectWrapper
    {
        private ILog Log = LogManager.GetLogger(typeof(ObjectWrapper));

        #region Fields

        /// <summary>The wrapped object.</summary>
        private object wrappedObject;

        /// <summary>
        /// The ILog instance for this class. We'll create a lot of these objects,
        /// so we don't want a new instance every time.
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(typeof(ObjectWrapper));

        #endregion

        #region Constructor (s) / Destructor

        /// <summary>
        /// Creates a new instance of the <see cref="Spring.Objects.ObjectWrapper"/> class.
        /// </summary>
        /// <remarks>
        /// <p>
        /// The wrapped target instance will need to be set afterwards.
        /// </p>
        /// </remarks>
        /// <seealso cref="Spring.Objects.ObjectWrapper.WrappedInstance"/>
        public ObjectWrapper()
        {}

        /// <summary>
        /// Creates a new instance of the <see cref="Spring.Objects.ObjectWrapper"/> class.
        /// </summary>
        /// <param name="instance">
        /// The object wrapped by this <see cref="Spring.Objects.ObjectWrapper"/>.
        /// </param>
        /// <exception cref="Spring.Objects.FatalObjectException">
        /// If the supplied <paramref name="instance"/> is <see lang="null"/>.
        /// </exception>
        public ObjectWrapper(object instance)
        {
            WrappedInstance = instance;
        }

        /// <summary>
        /// Creates a new instance of the <see cref="Spring.Objects.ObjectWrapper"/> class,
        /// instantiating a new instance of the specified <see cref="System.Type"/> and using
        /// it as the <see cref="Spring.Objects.ObjectWrapper.WrappedInstance"/>.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Please note that the <see cref="System.Type"/> passed as the
        /// <paramref name="type"/> argument must have a no-argument constructor.
        /// If it does not, an exception will be thrown when this class attempts
        /// to instantiate the supplied <paramref name="type"/> using it's
        /// (non-existent) constructor.
        /// </p>
        /// </remarks>
        /// <param name="type">
        /// The <see cref="System.Type"/> to instantiate and wrap.
        /// </param>
        /// <exception cref="Spring.Objects.FatalObjectException">
        /// If the <paramref name="type"/> is <see langword="null"/>, or if the
        /// invocation of the <paramref name="type"/>s default (no-arg) constructor
        /// fails (due to invalid arguments, insufficient permissions, etc).
        /// </exception>
        public ObjectWrapper(Type type) : this(true)
        {
            try
            {
                WrappedInstance = ObjectUtils.InstantiateType(type);
            } catch (FatalReflectionException e)
            {
                throw new FatalObjectException(e.Message, e);
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// The object wrapped by this <see cref="Spring.Objects.ObjectWrapper"/>.
        /// </summary>
        /// <exception cref="Spring.Objects.FatalObjectException">
        /// If the object cannot be changed; or an attempt is made to set the
        /// value of this property to <see langword="null"/>.
        /// </exception>
        public object WrappedInstance
        {
            get { return wrappedObject; }
            set
            {
                if (value == null)
                {
                    throw new FatalObjectException("Wraped instance cannot be null.");
                }
                this.wrappedObject = value;
            }
        }

        /// <summary>
        /// Convenience method to return the <see cref="System.Type"/> of the wrapped object.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Do <b>not</b> use this (convenience) method prior to setting the
        /// <see cref="Spring.Objects.ObjectWrapper.WrappedInstance"/> property.
        /// </p>
        /// </remarks>
        /// <returns>
        /// The <see cref="System.Type"/> of the wrapped object.
        /// </returns>
        /// <exception cref="System.NullReferenceException">
        /// If the <see cref="Spring.Objects.ObjectWrapper.WrappedInstance"/> property
        /// is <see lang="null"/>.
        /// </exception>
        public Type WrappedType
        {
            get { return WrappedInstance.GetType(); }
        }

        #endregion

        #region Methods

        /// <summary>Gets the value of a property.</summary>
        /// <param name="propertyName">
        /// The name of the property to get the value of.
        /// </param>
        /// <returns>The value of the property.</returns>
        /// <exception cref="Spring.Objects.FatalObjectException">
        /// If there is no such property, if the property isn't readable, or
        /// if getting the property value throws an exception.
        /// </exception>
        public virtual object GetPropertyValue(string propertyName)
        {
            try
            {
                IExpression propertyExpression = GetPropertyExpression(propertyName);
                return GetPropertyValue(propertyExpression);
            }
            catch (RecognitionException e)
            {
                throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e);
            }
            catch (TokenStreamRecognitionException e)
            {
                throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e);
            }
        }

        /// <summary>Gets the value of a property.</summary>
        /// <param name="propertyExpression">
        /// The property expression that should be used to retrieve the property value.
        /// </param>
        /// <returns>The value of the property.</returns>
        /// <exception cref="Spring.Objects.FatalObjectException">
        /// If there is no such property, if the property isn't readable, or
        /// if getting the property value throws an exception.
        /// </exception>
        public virtual object GetPropertyValue(IExpression propertyExpression)
        {
            return propertyExpression.GetValue(this.wrappedObject);
        }

        /// <summary>
        /// Sets a property value.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method is provided for convenience only. The
        /// <see cref="Spring.Objects.ObjectWrapper.SetPropertyValue(PropertyValue)"/>
        /// method is more powerful.
        /// </p>
        /// </remarks>
        /// <param name="propertyName">
        /// The name of the property to set value of.
        /// </param>
        /// <param name="val">The new value.</param>
        public virtual void SetPropertyValue(string propertyName, object val)
        {
            try
            {
                IExpression propertyExpression = GetPropertyExpression(propertyName);
                SetPropertyValue(propertyExpression, val);
            }
            catch (RecognitionException e)
            {
                throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e);
            }
            catch (TokenStreamRecognitionException e)
            {
                throw new InvalidPropertyException("Failed to parse property name '" + propertyName + "'.", e);
            }
        }

        /// <summary>
        /// Sets a property value.
        /// </summary>
        /// <param name="propertyExpression">
        /// The property expression that should be used to set the property value.
        /// </param>
        /// <param name="val">The new value.</param>
        public virtual void SetPropertyValue(IExpression propertyExpression, object val)
        {
            propertyExpression.SetValue(this.wrappedObject, val);
        }

        /// <summary>
        /// Sets a property value.
        /// </summary>
        /// <remarks>
        /// <p>
        /// <b>This is the preferred way to update an individual property.</b>
        /// </p>
        /// </remarks>
        /// <param name="pv">
        /// The object containing new property value.
        /// </param>
        public virtual void SetPropertyValue(PropertyValue pv)
        {
            SetPropertyValue(pv.Expression, pv.Value);
        }

        /// <summary>Set a number of property values in bulk.</summary>
        /// <remarks>
        /// <p>
        /// Does not allow unknown fields. Equivalent to
        /// <see cref="Spring.Objects.ObjectWrapper.SetPropertyValues(IPropertyValues, bool)"/>
        /// with <see langword="null"/> and <cref lang="false"/> for
        /// arguments.
        /// </p>
        /// </remarks>
        /// <param name="pvs">
        /// The <see cref="Spring.Objects.IPropertyValues"/> to set on the target
        /// object.
        /// </param>
        /// <exception cref="Spring.Core.NotWritablePropertyException">
        /// If an error is encountered while setting a property.
        /// </exception>
        /// <exception cref="Spring.Objects.PropertyAccessExceptionsException">
        /// On a <see cref="System.Type"/> mismatch while setting a property, insufficient permissions, etc.
        /// </exception>
        /// <seealso cref="Spring.Objects.IObjectWrapper.SetPropertyValues(IPropertyValues, bool)"/>
        public virtual void SetPropertyValues(IPropertyValues pvs)
        {
            SetPropertyValues(pvs, false);
        }

        /// <summary>
        /// Perform a bulk update with full control over behavior.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method may throw a reflection-based exception, if there is a critical
        /// failure such as no matching field... less serious exceptions will be accumulated
        /// and thrown as a single <see cref="Spring.Objects.PropertyAccessExceptionsException"/>.
        /// </p>
        /// </remarks>
        /// <param name="propertyValues">
        /// The <see cref="Spring.Objects.PropertyValue"/>s to set on the target object.
        /// </param>
        /// <param name="ignoreUnknown">
        /// Should we ignore unknown values (not found in the object!?).
        /// </param>
        /// <exception cref="NotWritablePropertyException">
        /// If an error is encountered while setting a property (only thrown if the
        /// <paramref name="ignoreUnknown"/> parameter is set to <see langword="false"/>).
        /// </exception>
        /// <exception cref="Spring.Objects.PropertyAccessExceptionsException">
        /// On a <see cref="System.Type"/> mismatch while setting a property, insufficient permissions, etc.
        /// </exception>
        /// <seealso cref="Spring.Objects.IObjectWrapper.SetPropertyValues(IPropertyValues, bool)"/>
        public virtual void SetPropertyValues(IPropertyValues propertyValues, bool ignoreUnknown)
        {
            ArrayList propertyAccessExceptions = new ArrayList();
            foreach (PropertyValue pv in propertyValues)
            {
                try
                {
                    SetPropertyValue(pv);
                }
                catch (NotWritablePropertyException ex)
                {
                    if (!ignoreUnknown)
                    {
                        Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex);
                        throw;
                    }
                }
                catch (InvalidPropertyException ex)
                {
                    if (!ignoreUnknown)
                    {
                        Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex);
                        throw;
                    }
                }
                catch (TypeMismatchException ex) // otherwise, just ignore it and continue...
                {
                    Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex);
                    propertyAccessExceptions.Add(ex);
                }
                catch (MethodInvocationException ex)
                {
                    Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex);
                    propertyAccessExceptions.Add(ex);
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("Failed setting property '{0}' on instance of type '{1}'", pv.Name, this.WrappedType.FullName), ex);
                    throw;
                }
            }

            // if we encountered individual exceptions, throw the composite exception...
            if (propertyAccessExceptions.Count > 0)
            {
                throw new PropertyAccessExceptionsException(this,
                                                            (PropertyAccessException[]) propertyAccessExceptions.ToArray(typeof(PropertyAccessException)));
            }
        }

        /// <summary>
        /// Returns PropertyInfo for the specified property
        /// </summary>
        /// <param name="propertyName">The name of the property to search for.</param>
        /// <returns>The <see cref="PropertyInfo"/> for the specified property.</returns>
        /// <exception cref="FatalObjectException">If <see cref="PropertyInfo"/> cannot be determined.</exception>
        public PropertyInfo GetPropertyInfo(string propertyName)
        {
            return (PropertyInfo) this.GetPropertyOrFieldInfo(propertyName);
        }

        /// <summary>
        /// Get the <see cref="System.Type"/> for a particular property.
        /// </summary>
        /// <param name="propertyName">
        /// The property the <see cref="System.Type"/> of which is to be retrieved.
        /// </param>
        /// <returns>
        /// The <see cref="System.Type"/> for a particular property..
        /// </returns>
        public Type GetPropertyType(string propertyName)
        {
            MemberInfo memberInfo = this.GetPropertyOrFieldInfo(propertyName);
            switch(memberInfo.MemberType)
            {
                case MemberTypes.Property:
                    return ((PropertyInfo) memberInfo).PropertyType;
                case MemberTypes.Field:
                    return ((FieldInfo) memberInfo).FieldType;
                default:
                    throw new FatalObjectException("'" + propertyName + "' is not a valid property expression.");
            }
        }

        /// <summary>
        /// Returns MemberInfo for the specified property or field
        /// </summary>
        /// <param name="propertyOrFieldName">The name of the property or field to search for.</param>
        /// <returns>The <see cref="PropertyInfo"/> or <see cref="FieldInfo"/> for the specified property or field.</returns>
        /// <exception cref="FatalObjectException">If <paramref name="propertyOrFieldName"/> does not resolve to a property or field.</exception>
        private MemberInfo GetPropertyOrFieldInfo(string propertyOrFieldName)
        {
            if(StringUtils.IsNullOrEmpty(propertyOrFieldName))
            {
                throw new FatalObjectException("Can't find property or field info for null or zero length property name.");
            }

            try
            {
                IExpression propertyExpression = GetPropertyExpression(propertyOrFieldName);
                if(propertyExpression is PropertyOrFieldNode)
                {
                    return ((PropertyOrFieldNode)propertyExpression).GetMemberInfo(this.wrappedObject);
                }
                else if(propertyExpression is IndexerNode)
                {
                    return ((IndexerNode)propertyExpression).GetPropertyInfo(this.wrappedObject, null);
                }
                else if(propertyExpression is Expression)
                {
                    return ((Expression)propertyExpression).GetPropertyInfo(this.wrappedObject, null);
                }
                else
                {
                    throw new FatalObjectException("'" + propertyOrFieldName + "' is not a valid property or field expression.");
                }
            }
            catch(RecognitionException e)
            {
                throw new FatalObjectException("Failed to parse property or field name '" + propertyOrFieldName + "'.", e);
            }
            catch(TokenStreamRecognitionException e)
            {
                throw new FatalObjectException("Failed to parse property or field name '" + propertyOrFieldName + "'.", e);
            }
        }


        /// <summary>
        /// Get the properties of the wrapped object.
        /// </summary>
        /// <returns>
        /// An array of <see cref="System.Reflection.PropertyInfo"/>s.
        /// </returns>
        public PropertyInfo[] GetPropertyInfos()
        {
            return WrappedType.GetProperties();
        }

        /// <summary>
        /// Return the collection of property descriptors.
        /// </summary>
        public PropertyDescriptorCollection PropertyDescriptors
        {
            get { return TypeDescriptor.GetProperties(WrappedInstance); }
        }

        /// <summary>
        /// This method is expensive! Only call for diagnostics and debugging reasons,
        /// not in production.
        /// </summary>
        /// <returns>
        /// A string describing the state of this object.
        /// </returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                sb.Append("ObjectWrapper: wrapping class [");
                sb.Append(WrappedType.FullName);
                sb.Append("]; ");
                foreach (PropertyDescriptor p in PropertyDescriptors)
                {
                    object val = GetPropertyValue(p.Name);
                    string valStr = (val != null) ? val.ToString() : "null";
                    sb.Append(p.Name).Append("={").Append(valStr).Append("}");
                }
            }
            catch (Exception ex)
            {
                sb.Append("Exception encountered: ").Append(ex.ToString());
            }
            return sb.ToString();
        }

        #endregion

        #region Helper methods

        /// <summary>
        /// Attempts to parse property expression first and falls back to full expression
        /// if that fails. Performance optimization.
        /// </summary>
        /// <param name="propertyName">Property expression to parse.</param>
        /// <returns>Parsed proeprty expression.</returns>
        internal static IExpression GetPropertyExpression(string propertyName)
        {
            IExpression propertyExpression = null;
            if (propertyName.IndexOfAny(new char[] { '.', '[', '(', ' ', '{' }) < 0)
            {
                try
                {
                    propertyExpression = Expression.ParseProperty(propertyName);
                }
                catch (Exception)
                {
                    propertyExpression = Expression.ParsePrimary(propertyName);
                }
            }
            else
            {
                propertyExpression = Expression.ParsePrimary(propertyName);
            }

            return propertyExpression;
        }

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