- /// Subclasses can override the
- ///
- /// method to change this behavior, so this is a useful/ base class for
- /// implementations.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// Rick Evans (.NET)
- /// Bruno Baia (.NET)
- /// $Id: AbstractMethodInvocation.cs,v 1.8 2007/07/05 20:29:21 bbaia Exp $
- [Serializable]
- public abstract class AbstractMethodInvocation : IMethodInvocation
- {
- ///
- /// The arguments (if any = may be ) to the method
- /// that is to be invoked.
- ///
- protected object[] arguments;
-
- ///
- /// The target object that the method is to be invoked on.
- ///
- protected object target;
-
- ///
- /// The AOP proxy for the target object.
- ///
- protected object proxy;
-
- ///
- /// The method invocation that is to be invoked.
- ///
- protected MethodInfo method;
-
- ///
- /// The list of and
- ///
- /// that need dynamic checks.
- ///
- protected IList interceptors;
-
- ///
- /// The declaring type of the method that is to be invoked.
- ///
- protected Type targetType;
-
- ///
- /// The index from 0 of the current interceptor we're invoking.
- ///
- protected int currentInterceptorIndex;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an abstract class, and as such exposes no publicly visible
- /// constructors.
- ///
- ///
- ///
- /// The list can also contain any
- /// s
- /// that need evaluation at runtime.
- /// s included in an
- ///
- /// must already have been found to have matched as far as was possible
- /// statically. Passing an array might be about 10% faster, but
- /// would complicate the code, and it would work only for static
- /// pointcuts.
- ///
- ///
- ///
- /// The AOP proxy.
- /// The target object.
- /// the target method.
- /// The target method's arguments.
- ///
- /// The of the target object.
- ///
- /// The list of interceptors that are to be applied. May be
- /// .
- ///
- ///
- /// If the is .
- ///
- protected AbstractMethodInvocation(object proxy, object target,
- MethodInfo method, object[] arguments, Type targetType, IList interceptors)
- {
- #region Sanity Check
-
- AssertUtils.ArgumentNotNull(target, "target");
- AssertUtils.ArgumentNotNull(method, "method");
-
- #endregion
-
- this.proxy = proxy;
- this.target = target;
- this.method = method;
- this.targetType = targetType;
- this.arguments = arguments;
- this.interceptors = interceptors;
- }
-
- ///
- /// Gets the method invocation that is to be invoked.
- ///
- ///
- ///
- /// May or may not correspond with a method invoked on an underlying
- /// implementation of that interface.
- ///
- ///
- ///
- public virtual MethodInfo Method
- {
- get { return method; }
- }
-
- ///
- /// Gets the static part of this joinpoint.
- ///
- ///
- /// The proxied member's information.
- ///
- ///
- public virtual MemberInfo StaticPart
- {
- get { return Method; }
- }
-
- ///
- /// Gets the proxy that this interception was made through.
- ///
- ///
- /// The proxy that this interception was made through.
- ///
- public virtual object Proxy
- {
- get { return this.proxy; }
- }
- ///
- /// Gets the target object for the invocation.
- ///
- ///
- /// The target object for this method invocation.
- ///
- public virtual object Target
- {
- get { return this.target; }
- }
- ///
- /// Gets the type of the target object.
- ///
- ///
- /// The type of the target object.
- ///
- public virtual Type TargetType
- {
- get { return this.targetType; }
- }
-
- ///
- /// Gets and sets the arguments (if any - may be )
- /// to the method that is to be invoked.
- ///
- ///
- /// The arguments (if any - may be ) to the
- /// method that is to be invoked.
- ///
- ///
- public virtual object[] Arguments
- {
- get { return this.arguments; }
- set { this.arguments = value; }
- }
-
- ///
- /// The list of method interceptors.
- ///
- ///
- ///
- /// May be .
- ///
- ///
- public virtual IList Interceptors
- {
- get { return this.interceptors; }
- set { this.interceptors = value; }
- }
-
- ///
- /// Gets the target object.
- ///
- public virtual object This
- {
- get { return this.target; }
- }
-
- ///
- /// Proceeds to the next interceptor in the chain.
- ///
- ///
- /// The return value of the method invocation.
- ///
- ///
- /// If any of the interceptors at the joinpoint throws an exception.
- ///
- ///
- public virtual object Proceed()
- {
- if (this.interceptors == null ||
- this.currentInterceptorIndex == this.interceptors.Count)
- {
- return InvokeJoinpoint();
- }
- object interceptor = this.interceptors[this.currentInterceptorIndex];
- InterceptorAndDynamicMethodMatcher dynamicMatcher
- = interceptor as InterceptorAndDynamicMethodMatcher;
- IMethodInvocation nextInvocation = PrepareMethodInvocationForProceed(this);
- if (dynamicMatcher != null)
- {
- // evaluate dynamic method matcher here: static part will already have
- // been evaluated and found to match...
- if (dynamicMatcher.MethodMatcher.Matches(
- nextInvocation.Method, nextInvocation.TargetType, nextInvocation.Arguments))
- {
- return dynamicMatcher.Interceptor.Invoke(nextInvocation);
- }
- else
- {
- // dynamic match failed; skip this interceptor and invoke the next in the chain...
- return nextInvocation.Proceed();
- }
- }
- else
- {
- // it's an interceptor so we just invoke it: the pointcut will have
- // been evaluated statically before this object was constructed...
- return ((IMethodInterceptor)interceptor).Invoke(nextInvocation);
- }
- }
-
- ///
- /// Retrieves a new instance
- /// for the next Proceed method call.
- ///
- ///
- /// The current instance.
- ///
- ///
- /// The new instance to use.
- ///
- ///
- protected abstract IMethodInvocation PrepareMethodInvocationForProceed(
- IMethodInvocation invocation);
-
- ///
- /// Invokes the joinpoint.
- ///
- ///
- ///
- /// Subclasses can override this to use custom invocation.
- ///
- ///
- ///
- /// The return value of the invocation of the joinpoint.
- ///
- ///
- /// If invoking the joinpoint resulted in an exception.
- ///
- ///
- protected abstract object InvokeJoinpoint();
-
- ///
- /// A that represents the current
- /// invocation.
- ///
- ///
- ///
- ///
- /// Does not invoke on the
- /// target
- /// object, as that too may be proxied.
- ///
- ///
+ /// Subclasses can override the
+ ///
+ /// method to change this behavior, so this is a useful/ base class for
+ /// implementations.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ /// Rick Evans (.NET)
+ /// Bruno Baia (.NET)
+ [Serializable]
+ public abstract class AbstractMethodInvocation : IMethodInvocation
+ {
+ ///
+ /// The arguments (if any = may be ) to the method
+ /// that is to be invoked.
+ ///
+ protected object[] arguments;
+
+ ///
+ /// The target object that the method is to be invoked on.
+ ///
+ protected object target;
+
+ ///
+ /// The AOP proxy for the target object.
+ ///
+ protected object proxy;
+
+ ///
+ /// The method invocation that is to be invoked.
+ ///
+ protected MethodInfo method;
+
+ ///
+ /// The list of and
+ ///
+ /// that need dynamic checks.
+ ///
+ protected IList interceptors;
+
+ ///
+ /// The declaring type of the method that is to be invoked.
+ ///
+ protected Type targetType;
+
+ ///
+ /// The index from 0 of the current interceptor we're invoking.
+ ///
+ protected int currentInterceptorIndex;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an abstract class, and as such exposes no publicly visible
+ /// constructors.
+ ///
+ ///
+ ///
+ /// The list can also contain any
+ /// s
+ /// that need evaluation at runtime.
+ /// s included in an
+ ///
+ /// must already have been found to have matched as far as was possible
+ /// statically. Passing an array might be about 10% faster, but
+ /// would complicate the code, and it would work only for static
+ /// pointcuts.
+ ///
+ ///
+ ///
+ /// The AOP proxy.
+ /// The target object.
+ /// the target method.
+ /// The target method's arguments.
+ ///
+ /// The of the target object.
+ ///
+ /// The list of interceptors that are to be applied. May be
+ /// .
+ ///
+ ///
+ /// If the is .
+ ///
+ protected AbstractMethodInvocation(object proxy, object target,
+ MethodInfo method, object[] arguments, Type targetType, IList interceptors)
+ {
+ #region Sanity Check
+
+ AssertUtils.ArgumentNotNull(target, "target");
+ AssertUtils.ArgumentNotNull(method, "method");
+
+ #endregion
+
+ this.proxy = proxy;
+ this.target = target;
+ this.method = method;
+ this.targetType = targetType;
+ this.arguments = arguments;
+ this.interceptors = interceptors;
+ }
+
+ ///
+ /// Gets the method invocation that is to be invoked.
+ ///
+ ///
+ ///
+ /// May or may not correspond with a method invoked on an underlying
+ /// implementation of that interface.
+ ///
+ ///
+ ///
+ public virtual MethodInfo Method
+ {
+ get { return method; }
+ }
+
+ ///
+ /// Gets the static part of this joinpoint.
+ ///
+ ///
+ /// The proxied member's information.
+ ///
+ ///
+ public virtual MemberInfo StaticPart
+ {
+ get { return Method; }
+ }
+
+ ///
+ /// Gets the proxy that this interception was made through.
+ ///
+ ///
+ /// The proxy that this interception was made through.
+ ///
+ public virtual object Proxy
+ {
+ get { return this.proxy; }
+ }
+ ///
+ /// Gets the target object for the invocation.
+ ///
+ ///
+ /// The target object for this method invocation.
+ ///
+ public virtual object Target
+ {
+ get { return this.target; }
+ }
+ ///
+ /// Gets the type of the target object.
+ ///
+ ///
+ /// The type of the target object.
+ ///
+ public virtual Type TargetType
+ {
+ get { return this.targetType; }
+ }
+
+ ///
+ /// Gets and sets the arguments (if any - may be )
+ /// to the method that is to be invoked.
+ ///
+ ///
+ /// The arguments (if any - may be ) to the
+ /// method that is to be invoked.
+ ///
+ ///
+ public virtual object[] Arguments
+ {
+ get { return this.arguments; }
+ set { this.arguments = value; }
+ }
+
+ ///
+ /// The list of method interceptors.
+ ///
+ ///
+ ///
+ /// May be .
+ ///
+ ///
+ public virtual IList Interceptors
+ {
+ get { return this.interceptors; }
+ set { this.interceptors = value; }
+ }
+
+ ///
+ /// Gets the target object.
+ ///
+ public virtual object This
+ {
+ get { return this.target; }
+ }
+
+ ///
+ /// Proceeds to the next interceptor in the chain.
+ ///
+ ///
+ /// The return value of the method invocation.
+ ///
+ ///
+ /// If any of the interceptors at the joinpoint throws an exception.
+ ///
+ ///
+ public virtual object Proceed()
+ {
+ if (this.interceptors == null ||
+ this.currentInterceptorIndex == this.interceptors.Count)
+ {
+ return InvokeJoinpoint();
+ }
+ object interceptor = this.interceptors[this.currentInterceptorIndex];
+ InterceptorAndDynamicMethodMatcher dynamicMatcher
+ = interceptor as InterceptorAndDynamicMethodMatcher;
+ IMethodInvocation nextInvocation = PrepareMethodInvocationForProceed(this);
+ if (dynamicMatcher != null)
+ {
+ // evaluate dynamic method matcher here: static part will already have
+ // been evaluated and found to match...
+ if (dynamicMatcher.MethodMatcher.Matches(
+ nextInvocation.Method, nextInvocation.TargetType, nextInvocation.Arguments))
+ {
+ return dynamicMatcher.Interceptor.Invoke(nextInvocation);
+ }
+ else
+ {
+ // dynamic match failed; skip this interceptor and invoke the next in the chain...
+ return nextInvocation.Proceed();
+ }
+ }
+ else
+ {
+ // it's an interceptor so we just invoke it: the pointcut will have
+ // been evaluated statically before this object was constructed...
+ return ((IMethodInterceptor)interceptor).Invoke(nextInvocation);
+ }
+ }
+
+ ///
+ /// Retrieves a new instance
+ /// for the next Proceed method call.
+ ///
+ ///
+ /// The current instance.
+ ///
+ ///
+ /// The new instance to use.
+ ///
+ ///
+ protected abstract IMethodInvocation PrepareMethodInvocationForProceed(
+ IMethodInvocation invocation);
+
+ ///
+ /// Invokes the joinpoint.
+ ///
+ ///
+ ///
+ /// Subclasses can override this to use custom invocation.
+ ///
+ ///
+ ///
+ /// The return value of the invocation of the joinpoint.
+ ///
+ ///
+ /// If invoking the joinpoint resulted in an exception.
+ ///
+ ///
+ protected abstract object InvokeJoinpoint();
+
+ ///
+ /// A that represents the current
+ /// invocation.
+ ///
+ ///
+ ///
+ ///
+ /// Does not invoke on the
+ /// target
+ /// object, as that too may be proxied.
+ ///
+ ///
- /// The only requirement for it to work is that it needs to be defined
- /// in an application context along with any arbitrary "non-native" Spring.NET
- /// instances that need
- /// to be recognized by Spring.NET's AOP framework.
- ///
- ///
- /// Dmitriy Kopylenko
- /// Aleksandar Seovic (.NET)
- /// $Id: AdvisorAdapterRegistrationManager.cs,v 1.5 2007/08/22 08:49:08 markpollack Exp $
- public class AdvisorAdapterRegistrationManager : IObjectPostProcessor
- {
- ///
- /// Apply this
- /// to the given new object instance before any object initialization callbacks.
- ///
- ///
- ///
- /// Does nothing, simply returns the supplied as is.
- ///
- ///
- ///
- /// The new object instance.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The object instance to use, either the original or a wrapped one.
- ///
- ///
- /// In case of errors.
- ///
- public virtual object PostProcessBeforeInitialization(object instance, string name)
- {
- return instance;
- }
-
- ///
- /// Apply this to the
- /// given new object instance after any object initialization callbacks.
- ///
- ///
- ///
- /// Registers the supplied with the
- ///
- /// singleton if it is an
- /// instance.
- ///
+ /// The only requirement for it to work is that it needs to be defined
+ /// in an application context along with any arbitrary "non-native" Spring.NET
+ /// instances that need
+ /// to be recognized by Spring.NET's AOP framework.
+ ///
+ ///
+ /// Dmitriy Kopylenko
+ /// Aleksandar Seovic (.NET)
+ public class AdvisorAdapterRegistrationManager : IObjectPostProcessor
+ {
+ ///
+ /// Apply this
+ /// to the given new object instance before any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// Does nothing, simply returns the supplied as is.
+ ///
+ ///
+ ///
+ /// The new object instance.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The object instance to use, either the original or a wrapped one.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ public virtual object PostProcessBeforeInitialization(object instance, string name)
+ {
+ return instance;
+ }
+
+ ///
+ /// Apply this to the
+ /// given new object instance after any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// Registers the supplied with the
+ ///
+ /// singleton if it is an
+ /// instance.
+ ///
- /// A more efficient alternative solution in cases where there is no
- /// interception advice and therefore no need to create an
- /// object may be
- /// offered in future.
- ///
- ///
- /// Used internally by the AOP framework: application developers should not need
- /// to use this class directly.
- ///
+ /// A more efficient alternative solution in cases where there is no
+ /// interception advice and therefore no need to create an
+ /// object may be
+ /// offered in future.
+ ///
+ ///
+ /// Used internally by the AOP framework: application developers should not need
+ /// to use this class directly.
+ ///
- /// Implementors can create AOP Alliance
- /// s from custom advice
- /// types, enabling these advice types to be used in the Spring.NET AOP
- /// framework, which uses interception under the covers.
- ///
- ///
- /// There is no need for most Spring.NET users to implement this interface;
- /// do so only if you need to introduce more
- /// or
- /// types to Spring.NET.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: IAdvisorAdapter.cs,v 1.4 2006/04/09 07:18:35 markpollack Exp $
- public interface IAdvisorAdapter
- {
- ///
- /// Does this adapter understand the supplied ?
- ///
- ///
- ///
- /// Is it valid to invoke the
- ///
- /// method with the given advice as an argument?
- ///
- ///
- ///
- /// such as
- /// .
- ///
- /// if this adapter understands the
- /// supplied .
- ///
- bool SupportsAdvice(IAdvice advice);
-
- ///
- /// Return an AOP Alliance
- /// exposing the
- /// behaviour of the given advice to an interception-based AOP
- /// framework.
- ///
- ///
- ///
- /// Don't worry about any
- /// contained in the supplied ;
- /// the AOP framework will take care of checking the pointcut.
- ///
+ /// Implementors can create AOP Alliance
+ /// s from custom advice
+ /// types, enabling these advice types to be used in the Spring.NET AOP
+ /// framework, which uses interception under the covers.
+ ///
+ ///
+ /// There is no need for most Spring.NET users to implement this interface;
+ /// do so only if you need to introduce more
+ /// or
+ /// types to Spring.NET.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public interface IAdvisorAdapter
+ {
+ ///
+ /// Does this adapter understand the supplied ?
+ ///
+ ///
+ ///
+ /// Is it valid to invoke the
+ ///
+ /// method with the given advice as an argument?
+ ///
+ ///
+ ///
+ /// such as
+ /// .
+ ///
+ /// if this adapter understands the
+ /// supplied .
+ ///
+ bool SupportsAdvice(IAdvice advice);
+
+ ///
+ /// Return an AOP Alliance
+ /// exposing the
+ /// behaviour of the given advice to an interception-based AOP
+ /// framework.
+ ///
+ ///
+ ///
+ /// Don't worry about any
+ /// contained in the supplied ;
+ /// the AOP framework will take care of checking the pointcut.
+ ///
- /// Implementations must also automatically register adapters for
- /// types.
- ///
- ///
- /// This is an SPI interface, that should not need to be implemented by any
- /// Spring.NET user.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: IAdvisorAdapterRegistry.cs,v 1.3 2006/04/09 07:18:35 markpollack Exp $
- public interface IAdvisorAdapterRegistry
- {
- ///
- /// Returns an wrapping the supplied
- /// .
- ///
- ///
- /// The object that should be an advice, such as
- /// or
- /// .
- ///
- ///
- /// An wrapping the supplied
- /// . Never returns . If
- /// the parameter is an
- /// , it will simply be returned.
- ///
- ///
- /// If no registered
- /// can wrap
- /// the supplied .
- ///
- IAdvisor Wrap(object advice);
-
- ///
- /// Returns an to
- /// allow the use of the supplied in an
- /// interception-based framework.
- ///
- ///
- ///
- /// Don't worry about the pointcut associated with the
- /// ; if it's an
- /// , just return an
- /// interceptor.
- ///
- ///
- ///
- /// The advisor to find an interceptor for.
- ///
- ///
- /// An interceptor to expose this advisor's behaviour.
- ///
- ///
- /// If the advisor type is not understood by any registered
- /// .
- ///
- IInterceptor GetInterceptor(IAdvisor advisor);
-
- ///
- /// Register the given .
- ///
- ///
- ///
- /// Note that it is not necessary to register adapters for
- /// instances: these
- /// must be automatically recognized by an
- ///
- /// implementation.
- ///
+ /// Implementations must also automatically register adapters for
+ /// types.
+ ///
+ ///
+ /// This is an SPI interface, that should not need to be implemented by any
+ /// Spring.NET user.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public interface IAdvisorAdapterRegistry
+ {
+ ///
+ /// Returns an wrapping the supplied
+ /// .
+ ///
+ ///
+ /// The object that should be an advice, such as
+ /// or
+ /// .
+ ///
+ ///
+ /// An wrapping the supplied
+ /// . Never returns . If
+ /// the parameter is an
+ /// , it will simply be returned.
+ ///
+ ///
+ /// If no registered
+ /// can wrap
+ /// the supplied .
+ ///
+ IAdvisor Wrap(object advice);
+
+ ///
+ /// Returns an to
+ /// allow the use of the supplied in an
+ /// interception-based framework.
+ ///
+ ///
+ ///
+ /// Don't worry about the pointcut associated with the
+ /// ; if it's an
+ /// , just return an
+ /// interceptor.
+ ///
+ ///
+ ///
+ /// The advisor to find an interceptor for.
+ ///
+ ///
+ /// An interceptor to expose this advisor's behaviour.
+ ///
+ ///
+ /// If the advisor type is not understood by any registered
+ /// .
+ ///
+ IInterceptor GetInterceptor(IAdvisor advisor);
+
+ ///
+ /// Register the given .
+ ///
+ ///
+ ///
+ /// Note that it is not necessary to register adapters for
+ /// instances: these
+ /// must be automatically recognized by an
+ ///
+ /// implementation.
+ ///
- /// In the future Spring.NET may also offer a more efficient alternative
- /// solution in cases where there is no interception advice and therefore
- /// no need to create an
- /// object.
- ///
- ///
- /// Used internally by the Spring.NET AOP framework: application developers
- /// should not need to use this class directly.
- ///
+ /// In the future Spring.NET may also offer a more efficient alternative
+ /// solution in cases where there is no interception advice and therefore
+ /// no need to create an
+ /// object.
+ ///
+ ///
+ /// Used internally by the Spring.NET AOP framework: application developers
+ /// should not need to use this class directly.
+ ///
- /// Implementations of the interface
- /// must define methods of the form...
- ///
- /// AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass);
- ///
- /// The method name is fixed (i.e. your methods must be named
- /// AfterThrowing. The first three arguments (as a whole) are
- /// optional, and only useful if futher information about the joinpoint is
- /// required. The return type can be anything, but is almost always
- /// by convention.
- ///
- ///
- /// Please note that the object encapsulating the throws advice does not
- /// need to implement the interface.
- /// Throws advice methods are discovered via reflection... the
- /// interface serves merely to
- /// discover objects that are to be considered as throws advice.
- /// Other mechanisms for discovering throws advice such as attributes are
- /// also equally valid... all that this class cares about is that a throws
- /// advice object implement one or more methods with a valid throws advice
- /// signature (see above, and the examples below).
- ///
- ///
- /// This is a framework class that should not normally need to be used
- /// directly by Spring.NET users.
- ///
- ///
- ///
- ///
- /// Find below some examples of valid
- /// method signatures...
- ///
- ///
- /// public class GlobalExceptionHandlingAdvice : IThrowsAdvice
- /// {
- /// public void AfterThrowing(Exception ex) {
- /// // handles absolutely any and every Exception...
- /// }
- /// }
- ///
- ///
- /// public class RemotingExceptionHandlingAdvice : IThrowsAdvice
- /// {
- /// public void AfterThrowing(RemotingException ex) {
- /// // handles any and every RemotingException (and subclasses of RemotingException)...
- /// }
- /// }
- ///
- ///
- /// using System.Data;
- ///
- /// public class DataExceptionHandlingAdvice
- /// {
- /// public void AfterThrowing(ConstraintException ex) {
- /// // specialised handling of ConstraintExceptions
- /// }
- ///
- /// public void AfterThrowing(NoNullAllowedException ex) {
- /// // specialised handling of NoNullAllowedExceptions
- /// }
- ///
- /// public void AfterThrowing(DataException ex) {
- /// // handles all other DataExceptions...
- /// }
- /// }
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: ThrowsAdviceInterceptor.cs,v 1.8 2007/05/04 13:16:44 bbaia Exp $
- ///
- [Serializable]
- public sealed class ThrowsAdviceInterceptor : IMethodInterceptor
- {
- private static readonly ILog log = LogManager.GetLogger(typeof(ThrowsAdviceInterceptor));
-
- private const string SpecialThrowingMethodName = "AfterThrowing";
-
- private readonly object throwsAdvice;
-
- ///
- /// The mapping of exception Types to MethodInfo handlers.
- ///
- private readonly IDictionary exceptionHandlers;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- ///
- /// The throws advice to check for exception handler methods.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- /// If no (0) handler methods were discovered on the supplied ;
- /// or if more than one handler method suitable for a particular
- /// type was discovered on the supplied
- /// .
- ///
- public ThrowsAdviceInterceptor(object advice)
- {
- AssertUtils.ArgumentNotNull(advice, "advice");
- this.exceptionHandlers = new Hashtable();
- this.throwsAdvice = advice;
- MapAllExceptionHandlingMethods(advice);
- if (exceptionHandlers.Count == 0)
- {
- throw new ArgumentException(
- "At least one handler method must be found in class ["
- + advice.GetType().FullName + "].");
- }
- }
-
- private void MapAllExceptionHandlingMethods(object advice)
- {
- MethodInfo[] methods = advice.GetType().GetMethods();
- foreach (MethodInfo method in methods)
- {
- int numParams = method.GetParameters().Length;
- if (method.Name.Equals(SpecialThrowingMethodName)
- && (numParams == 1 || numParams == 4))
- {
- Type lastParametersType = method.GetParameters()[numParams - 1].ParameterType;
- if (typeof (Exception).IsAssignableFrom(lastParametersType))
- {
- #region Instrumentation
-
- if(log.IsDebugEnabled)
- {
- log.Debug("Found exception handler method: " + method);
- }
-
- #endregion
-
- if(this.exceptionHandlers.Contains(lastParametersType))
- {
- throw new ArgumentException(
- "Throws advice handler method for the [" +
- lastParametersType + "] type already exists; don't define " +
- "both single and multiple argument methods for the same " +
- "Exception type in the same class.");
- }
- this.exceptionHandlers[lastParametersType] = method;
- }
- }
- }
- }
-
- ///
- /// Convenience property that returns the number of exception handler
- /// methods managed by this interceptor.
- ///
- ///
- /// The number of exception handler methods managed by this interceptor.
- ///
- public int HandlerMethodCount
- {
- get { return exceptionHandlers.Count; }
- }
-
- ///
- /// Executes interceptor if (and only if) the supplied
- /// throws an exception that is mapped to
- /// an appropriate exception handler.
- ///
- ///
- /// The method invocation that is being intercepted.
- ///
- ///
- /// The result of the call to the
- /// method of
- /// the supplied (this assumes no
- /// exception was thrown by the call to the supplied .
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- ///
- public object Invoke(IMethodInvocation invocation)
- {
- try
- {
- return invocation.Proceed();
- }
- catch (TargetInvocationException ex)
- {
- // bah, this is a tad gross...
- Exception realException = ex.InnerException;
- LookupAndInvokeAnyHandler(realException, invocation);
- throw realException;
- }
- catch (Exception ex)
- {
- LookupAndInvokeAnyHandler(ex, invocation);
- throw ex;
- }
- }
-
- private void LookupAndInvokeAnyHandler(Exception ex, IMethodInvocation invocation)
- {
- MethodInfo handlerMethod = GetExceptionHandler(ex);
- if (handlerMethod != null)
- {
- InvokeHandlerMethod(invocation, ex, handlerMethod);
- }
- }
-
- ///
- /// Gets the exception handler (if any) that has been mapped to the
- /// supplied .
- ///
- ///
- ///
+ /// Implementations of the interface
+ /// must define methods of the form...
+ ///
+ /// AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass);
+ ///
+ /// The method name is fixed (i.e. your methods must be named
+ /// AfterThrowing. The first three arguments (as a whole) are
+ /// optional, and only useful if futher information about the joinpoint is
+ /// required. The return type can be anything, but is almost always
+ /// by convention.
+ ///
+ ///
+ /// Please note that the object encapsulating the throws advice does not
+ /// need to implement the interface.
+ /// Throws advice methods are discovered via reflection... the
+ /// interface serves merely to
+ /// discover objects that are to be considered as throws advice.
+ /// Other mechanisms for discovering throws advice such as attributes are
+ /// also equally valid... all that this class cares about is that a throws
+ /// advice object implement one or more methods with a valid throws advice
+ /// signature (see above, and the examples below).
+ ///
+ ///
+ /// This is a framework class that should not normally need to be used
+ /// directly by Spring.NET users.
+ ///
+ ///
+ ///
+ ///
+ /// Find below some examples of valid
+ /// method signatures...
+ ///
+ ///
+ /// public class GlobalExceptionHandlingAdvice : IThrowsAdvice
+ /// {
+ /// public void AfterThrowing(Exception ex) {
+ /// // handles absolutely any and every Exception...
+ /// }
+ /// }
+ ///
+ ///
+ /// public class RemotingExceptionHandlingAdvice : IThrowsAdvice
+ /// {
+ /// public void AfterThrowing(RemotingException ex) {
+ /// // handles any and every RemotingException (and subclasses of RemotingException)...
+ /// }
+ /// }
+ ///
+ ///
+ /// using System.Data;
+ ///
+ /// public class DataExceptionHandlingAdvice
+ /// {
+ /// public void AfterThrowing(ConstraintException ex) {
+ /// // specialised handling of ConstraintExceptions
+ /// }
+ ///
+ /// public void AfterThrowing(NoNullAllowedException ex) {
+ /// // specialised handling of NoNullAllowedExceptions
+ /// }
+ ///
+ /// public void AfterThrowing(DataException ex) {
+ /// // handles all other DataExceptions...
+ /// }
+ /// }
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ [Serializable]
+ public sealed class ThrowsAdviceInterceptor : IMethodInterceptor
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof(ThrowsAdviceInterceptor));
+
+ private const string SpecialThrowingMethodName = "AfterThrowing";
+
+ private readonly object throwsAdvice;
+
+ ///
+ /// The mapping of exception Types to MethodInfo handlers.
+ ///
+ private readonly IDictionary exceptionHandlers;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ ///
+ /// The throws advice to check for exception handler methods.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ /// If no (0) handler methods were discovered on the supplied ;
+ /// or if more than one handler method suitable for a particular
+ /// type was discovered on the supplied
+ /// .
+ ///
+ public ThrowsAdviceInterceptor(object advice)
+ {
+ AssertUtils.ArgumentNotNull(advice, "advice");
+ this.exceptionHandlers = new Hashtable();
+ this.throwsAdvice = advice;
+ MapAllExceptionHandlingMethods(advice);
+ if (exceptionHandlers.Count == 0)
+ {
+ throw new ArgumentException(
+ "At least one handler method must be found in class ["
+ + advice.GetType().FullName + "].");
+ }
+ }
+
+ private void MapAllExceptionHandlingMethods(object advice)
+ {
+ MethodInfo[] methods = advice.GetType().GetMethods();
+ foreach (MethodInfo method in methods)
+ {
+ int numParams = method.GetParameters().Length;
+ if (method.Name.Equals(SpecialThrowingMethodName)
+ && (numParams == 1 || numParams == 4))
+ {
+ Type lastParametersType = method.GetParameters()[numParams - 1].ParameterType;
+ if (typeof (Exception).IsAssignableFrom(lastParametersType))
+ {
+ #region Instrumentation
+
+ if(log.IsDebugEnabled)
+ {
+ log.Debug("Found exception handler method: " + method);
+ }
+
+ #endregion
+
+ if(this.exceptionHandlers.Contains(lastParametersType))
+ {
+ throw new ArgumentException(
+ "Throws advice handler method for the [" +
+ lastParametersType + "] type already exists; don't define " +
+ "both single and multiple argument methods for the same " +
+ "Exception type in the same class.");
+ }
+ this.exceptionHandlers[lastParametersType] = method;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Convenience property that returns the number of exception handler
+ /// methods managed by this interceptor.
+ ///
+ ///
+ /// The number of exception handler methods managed by this interceptor.
+ ///
+ public int HandlerMethodCount
+ {
+ get { return exceptionHandlers.Count; }
+ }
+
+ ///
+ /// Executes interceptor if (and only if) the supplied
+ /// throws an exception that is mapped to
+ /// an appropriate exception handler.
+ ///
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied (this assumes no
+ /// exception was thrown by the call to the supplied .
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ ///
+ public object Invoke(IMethodInvocation invocation)
+ {
+ try
+ {
+ return invocation.Proceed();
+ }
+ catch (TargetInvocationException ex)
+ {
+ // bah, this is a tad gross...
+ Exception realException = ex.InnerException;
+ LookupAndInvokeAnyHandler(realException, invocation);
+ throw realException;
+ }
+ catch (Exception ex)
+ {
+ LookupAndInvokeAnyHandler(ex, invocation);
+ throw ex;
+ }
+ }
+
+ private void LookupAndInvokeAnyHandler(Exception ex, IMethodInvocation invocation)
+ {
+ MethodInfo handlerMethod = GetExceptionHandler(ex);
+ if (handlerMethod != null)
+ {
+ InvokeHandlerMethod(invocation, ex, handlerMethod);
+ }
+ }
+
+ ///
+ /// Gets the exception handler (if any) that has been mapped to the
+ /// supplied .
+ ///
+ ///
+ ///
- /// Instances of this class are not themselves AOP proxies, but
- /// subclasses of this class are normally factories from which AOP proxy
- /// instances are obtained directly.
- ///
- ///
- /// This class frees subclasses of the housekeeping of
- /// and
- /// instances, but doesn't actually
- /// implement proxy creation methods, the functionality for which
- /// is provided by subclasses.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: AdvisedSupport.cs,v 1.36 2008/01/14 20:49:47 oakinger Exp $
- ///
- [Serializable]
- public class AdvisedSupport : ProxyConfig, IAdvised
- {
- #region Fields
-
- /// The list of advice.
- ///
- ///
- /// If an is added, it
- /// will be wrapped in an advice before being added to this list.
- ///
- ///
- private IList _advisors = new ArrayList();
-
- ///
- /// Array updated on changes to the advisors list, which is easier to
- /// manipulate internally
- ///
- private IAdvisor[] _advisorsArray = new IAdvisor[] {};
-
- ///
- /// List of introductions.
- ///
- private IList _introductions = new ArrayList();
-
- ///
- /// Array updated on changes to the advisors list, which is easier to
- /// manipulate internally
- ///
- private IIntroductionAdvisor[] _introductionsArray
- = new IIntroductionAdvisor[] {};
-
- ///
- /// Interface map specifying which object should interface methods be
- /// delegated to.
- ///
- ///
- ///
- /// If entry value is methods should be delegated
- /// to the target object.
- ///
- ///
- private IDictionary interfaceMap = new ListDictionary();
-
- ///
- /// The for this instance.
- ///
- protected internal ITargetSource m_targetSource = EmptyTargetSource.Empty;
-
- ///
- /// Set to when the first AOP proxy has been
- /// created, meaning that we must track advice changes via the
- /// OnAdviceChange() callback.
- ///
- private bool isActive;
-
- private Type proxyType;
- private ConstructorInfo proxyConstructor;
-
- ///
- /// The list of event listeners.
- ///
- private IList listeners = new ArrayList();
-
- ///
- /// The advisor chain factory.
- ///
- private IAdvisorChainFactory advisorChainFactory;
-
- #endregion
-
- #region Constructor(s)
-
- ///
- /// Creates a new instance of the
- /// class using the
- /// default advisor chain factory.
- ///
- public AdvisedSupport()
- {
- AdvisorChainFactory = new HashtableCachingAdvisorChainFactory();
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// The interfaces that are to be proxied.
- ///
- /// If this
- ///
- public AdvisedSupport(Type[] interfaces) : this()
- {
- if (interfaces != null)
- {
- foreach (Type intf in interfaces)
- {
- AddInterfaceInternal(intf);
- }
- }
- }
-
- #endregion
-
- #region IAdvised implementation
-
- ///
- /// Gets and sets the
- ///
- /// implementation that will be used to get the interceptor
- /// chains for the advised
- /// .
- ///
- ///
- /// The
- /// implementation that will be used to get the interceptor
- /// chains for the advised
- /// .
- ///
- public virtual IAdvisorChainFactory AdvisorChainFactory
- {
- get
- {
- lock(this.SyncRoot)
- {
- return this.advisorChainFactory;
- }
- }
- set
- {
- lock(this.SyncRoot)
- {
- if (this.advisorChainFactory != null)
- {
- RemoveListener(this.advisorChainFactory);
- }
- this.advisorChainFactory = value;
- AddListener(this.advisorChainFactory);
- }
- }
- }
-
- ///
- /// Returns the current used
- /// by this object.
- ///
- ///
- /// The used by this
- /// object.
- ///
- ///
- public ITargetSource TargetSource
- {
- get { return this.m_targetSource; }
- set
- {
- bool initialized = !(this.m_targetSource is EmptyTargetSource);
- this.m_targetSource = value;
-
- if (this.m_targetSource != null && !initialized && interfaceMap.Count == 0)
- {
- Type[] interfaces = ReflectionUtils.GetInterfaces(this.m_targetSource.TargetType);
- foreach (Type intf in interfaces)
- {
- AddInterfaceInternal(intf);
- }
- }
- }
- }
-
- ///
- /// Returns a boolean specifying if this
- /// instance can be serialized.
- ///
- ///
- /// true if this instance can be serialized, false otherwise.
- ///
- public bool IsSerializable
- {
- get
- {
- bool canBeSerialized = TargetSource.TargetType.IsSerializable;
- if (canBeSerialized)
- {
- for (int i = 0; canBeSerialized && i < _advisorsArray.Length; i++)
- {
- IAdvisor advisor = _advisorsArray[i];
- canBeSerialized = advisor.GetType().IsSerializable
- && advisor.Advice.GetType().IsSerializable;
- }
- for (int i = 0; canBeSerialized && i < _introductionsArray.Length; i++)
- {
- IIntroductionAdvisor advisor = _introductionsArray[i];
- canBeSerialized = advisor.GetType().IsSerializable
- && advisor.Advice.GetType().IsSerializable;
- }
- }
-
- return canBeSerialized;
- }
- }
-
- ///
- /// Returns the collection of interface s
- /// to be (or that are being) proxied by this proxy.
- ///
- ///
- /// The collection of interface s
- /// to be (or that are being) proxied by this proxy.
- ///
- ///
- public virtual Type[] Interfaces
- {
- get
- {
- lock(this.SyncRoot)
- {
- Type[] proxiedInterfaces = new Type[this.interfaceMap.Keys.Count];
- this.interfaceMap.Keys.CopyTo(proxiedInterfaces, 0);
- return proxiedInterfaces;
- }
- }
- set
- {
- lock(this.SyncRoot)
- {
- this.interfaceMap.Clear();
- for (int i = 0; i < value.Length; i++)
- {
- AddInterfaceInternal(value[i]);
- }
- InterfacesChanged();
- }
- }
- }
-
- ///
- /// Returns the mapping of the proxied interface
- /// s to their delegates.
- ///
- ///
- /// The mapping of the proxied interface
- /// s to their delegates.
- ///
- ///
- public virtual IDictionary InterfaceMap
- {
- get
- {
- lock(this.SyncRoot)
- {
- return new Hashtable(this.interfaceMap);
- }
- }
- }
-
- ///
- /// Is the supplied (interface)
- /// proxied?
- ///
- ///
- /// The interface to test.
- ///
- ///
- /// if the supplied
- /// (interface) is proxied;
- /// if not or the supplied
- /// is .
- ///
- ///
- public virtual bool IsInterfaceProxied(Type intf)
- {
- if (intf != null)
- {
- lock(this.SyncRoot)
- {
- foreach (Type proxyInterface in this.interfaceMap.Keys)
- {
- if (intf.IsAssignableFrom(proxyInterface))
- {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- ///
- /// Returns the collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- /// The collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- public virtual IAdvisor[] Advisors
- {
- get
- {
- lock(this.SyncRoot)
- {
- return (IAdvisor[]) this._advisorsArray.Clone();
- }
- }
- }
-
- ///
- /// Returns the collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- ///
- /// Will never return , but may return an
- /// empty array (in the case where no
- /// instances have been
- /// applied to this proxy).
- ///
- ///
- ///
- /// The collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- public virtual IIntroductionAdvisor[] Introductions
- {
- get
- {
- lock(this.SyncRoot)
- {
- return (IIntroductionAdvisor[]) this._introductionsArray.Clone();
- }
- }
- }
-
- ///
- /// Adds the supplied to the end (or tail)
- /// of the advice (interceptor) chain.
- ///
- ///
- /// The to be added.
- ///
- ///
- ///
- public void AddAdvice(IAdvice advice)
- {
- //int position = this._advisors != null ? this._advisors.Count : 0;
- AddAdvice(-1, advice);
- }
-
- ///
- /// Adds the supplied to the supplied
- /// in the advice (interceptor) chain.
- ///
- ///
- /// The zero (0) indexed position (from the head) at which the
- /// supplied is to be inserted into the
- /// advice (interceptor) chain.
- ///
- ///
- /// The to be added.
- ///
- ///
- /// If the supplied is ;
- /// or is not an
- /// reference; or if the supplied is a
- /// .
- ///
- ///
- ///
- public void AddAdvice(int position, IAdvice advice)
- {
- if (advice is IInterceptor && !(advice is IMethodInterceptor))
- {
- throw new AopConfigException(
- GetType().FullName + " can only handle AOP Alliance IMethodInterceptor advice.");
- }
- if (advice is IIntroductionInterceptor)
- {
- throw
- new AopConfigException(
- "IIntroductionInterceptors may only be added as part of IIntroductionAdvisor.");
- }
-
- AddAdvisor(position, new DefaultPointcutAdvisor(advice));
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the interceptor
- /// (advice) chain for this proxy.
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this advisor, or -1 if the
- /// supplied is not an advisor for this
- /// proxy.
- ///
- public virtual int IndexOf(IAdvisor advisor)
- {
- lock(this.SyncRoot)
- {
- return IndexOfInternal(advisor);
- }
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the introductions
- /// for this proxy.
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this advisor, or -1 if the
- /// supplied is not an introduction advisor
- /// for this proxy.
- ///
- public virtual int IndexOf(IIntroductionAdvisor advisor)
- {
- lock(this.SyncRoot)
- {
- return IndexOfInternal(advisor);
- }
- }
-
- ///
- /// Removes the supplied the list of advisors
- /// for this proxy.
- ///
- /// The advisor to remove.
- ///
- /// if advisor was found in the list of
- /// for this
- /// proxy and was successfully removed; if not
- /// or if the supplied is .
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be removed.
- ///
- public bool RemoveAdvisor(IAdvisor advisor)
- {
- DieIfFrozen("Cannot remove advisor: config is frozen");
- bool wasRemoved = false;
- if (advisor != null)
- {
- lock(this.SyncRoot)
- {
- int index = IndexOf(advisor);
- if (index == -1)
- {
- wasRemoved = false;
- }
- else
- {
- RemoveAdvisorInternal(index);
- wasRemoved = true;
- }
- }
- }
- return wasRemoved;
- }
-
- ///
- /// Removes the at the supplied
- /// in the
- /// list
- /// from the list of
- /// for this proxy.
- ///
- ///
- /// The index of the to remove.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// at the supplied
- /// cannot be removed; or if the supplied is out of
- /// range.
- ///
- public virtual void RemoveAdvisor(int index)
- {
- DieIfFrozen("Cannot remove advisor: config is frozen");
- lock(this.SyncRoot)
- {
- RemoveAdvisorInternal(index);
- }
- }
-
- ///
- /// Removes the supplied from the list
- /// of .
- ///
- ///
- /// The to remove.
- ///
- ///
- /// if the supplied was
- /// found in the list of
- /// and successfully removed.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be removed.
- ///
- public bool RemoveAdvice(IAdvice advice)
- {
- lock(this.SyncRoot)
- {
- int index = IndexOf(advice);
- if (index == -1)
- {
- return false;
- }
- else
- {
- RemoveAdvisorInternal(index);
- return true;
- }
- }
- }
-
- ///
- /// Removes the supplied from the list
- /// of .
- ///
- ///
- /// The to remove.
- ///
- ///
- /// if the supplied was
- /// found in the list of
- /// and successfully removed.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be removed.
- ///
- public bool RemoveIntroduction(IIntroductionAdvisor introduction)
- {
- DieIfFrozen("Cannot remove introduction: config is frozen");
- bool wasRemoved = false;
- if (introduction != null)
- {
- lock(this.SyncRoot)
- {
- int index = IndexOf(introduction);
- if (index == -1)
- {
- wasRemoved = false;
- }
- else
- {
- RemoveIntroduction(index);
- wasRemoved = true;
- }
- }
- }
- return wasRemoved;
- }
-
- ///
- /// Removes the at the supplied
- /// in the list of
- /// for this proxy.
- ///
- /// The index of the advisor to remove.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// at the supplied
- /// cannot be removed; or if the supplied
- /// is out of range.
- ///
- public virtual void RemoveIntroduction(int index)
- {
- DieIfFrozen("Cannot remove introduction: config is frozen");
- lock(this.SyncRoot)
- {
- if (index < 0 || index >= _introductions.Count)
- {
- throw new AopConfigException(
- "Introduction index " + index + " is out of bounds: Only have " + _introductions.Count +
- " introductions.");
- }
- IIntroductionAdvisor advisor = (IIntroductionAdvisor) _introductions[index];
- // remove all interfaces introduced by the advisor...
- foreach (Type intf in advisor.Interfaces)
- {
- RemoveInterface(intf);
- }
- this._introductions.RemoveAt(index);
- UpdateIntroductionsArray();
- }
- }
-
-//
-// ///
-// /// Removes the supplied from the list of
-// /// for this
-// /// proxy.
-// ///
-// ///
-// /// The to be removed.
-// ///
-// ///
-// /// If this proxy configuration is frozen and the
-// /// cannot be added.
-// ///
-// public bool RemoveInterceptor(IInterceptor interceptor)
-// {
-// AssertFrozen("Cannot remove interceptor: config is frozen");
-// int index = IndexOf(interceptor);
-// if (index == -1)
-// {
-// return false;
-// }
-// else
-// {
-// RemoveAdvisor(index);
-// return true;
-// }
-// }
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The index in the
- /// list at which the supplied
- /// is to be inserted. If -1, appends to the end of the list.
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- public virtual void AddAdvisor(int index, IAdvisor advisor)
- {
- DieIfFrozen("Cannot add advisor: config is frozen");
- lock(this.SyncRoot)
- {
- // advisor already in list (SPRNET-846)
- if (_advisors.Contains(advisor)) return;
-
- if(index == -1)
- {
- this._advisors.Add(advisor);
- }
- else
- {
- this._advisors.Insert(index, advisor);
- }
- UpdateAdvisorsArray();
- InterceptorsChanged();
- }
- }
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- public virtual void AddAdvisor(IAdvisor advisor)
- {
- AddAdvisor(this._advisors.Count, advisor);
- }
-
- ///
- /// Adds the advisors from the supplied
- /// to the list of .
- ///
- ///
- /// The to add advisors from.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- public void AddAdvisors(IAdvisors advisors)
- {
- foreach (IAdvisor advisor in advisors.Advisors)
- {
- if (advisor is IIntroductionAdvisor)
- {
- AddIntroduction((IIntroductionAdvisor) advisor);
- }
- else
- {
- AddAdvisor(advisor);
- }
- }
- }
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The index in the
- /// list at which the supplied
- /// is to be inserted.
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- public virtual void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor)
- {
- DieIfFrozen("Cannot add introduction: config is frozen");
- introductionAdvisor.ValidateInterfaces();
-
- lock(this.SyncRoot)
- {
- if (index < this._introductions.Count)
- {
- this._introductions.RemoveAt(index);
- }
- this._introductions.Insert(index, introductionAdvisor);
-
- int intfCount = this.interfaceMap.Count;
- // If the advisor passed validation we can make the change
- foreach (Type intf in introductionAdvisor.Interfaces)
- {
- this.interfaceMap[intf] = introductionAdvisor;
- }
- UpdateIntroductionsArray();
- if (this.interfaceMap.Count != intfCount)
- {
- InterfacesChanged();
- }
- }
- }
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- public virtual void AddIntroduction(IIntroductionAdvisor introductionAdvisor)
- {
- Type introductionType = introductionAdvisor.Advice.GetType();
- lock(this.SyncRoot)
- {
- int pos = this._introductions.Count;
- for (int i = 0; i < pos; i++)
- {
- IIntroductionAdvisor introduction
- = (IIntroductionAdvisor) this._introductions[i];
- if (introduction.Advice.GetType() == introductionType)
- {
- pos = i;
- }
- }
- AddIntroduction(pos, introductionAdvisor);
- }
- }
-
- ///
- /// Replaces the that
- /// exists at the supplied in the list of
- ///
- /// with the supplied .
- ///
- ///
- /// The index of the
- /// in the list of
- ///
- /// that is to be replaced.
- ///
- ///
- /// The new (replacement) .
- ///
- ///
- /// If the supplied is out of range.
- ///
- public virtual void ReplaceIntroduction(int index, IIntroductionAdvisor introduction)
- {
- lock(this.SyncRoot)
- {
- if(index < 0 || index >= _introductions.Count)
- {
- throw new AopConfigException(
- "Introduction index " + index + " is out of bounds:" +
- " there are currently " + _introductions.Count +
- " introductions." );
- }
-
- _introductions[index] = introduction;
- }
- }
-
- ///
- /// Replaces the with the
- /// .
- ///
- ///
- /// The original (old) advisor to be replaced.
- ///
- ///
- /// The new advisor to replace the with.
- ///
- ///
- /// if the was
- /// replaced; if the was not found in the
- /// advisors collection (or the is
- /// , this method returns
- /// and (effectively) does nothing.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be replaced.
- ///
- ///
- public bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor)
- {
- DieIfFrozen("Cannot replace advisor: config is frozen.");
- lock(this.SyncRoot)
- {
- int index = IndexOf(oldAdvisor);
- if (index == -1 || newAdvisor == null)
- {
- return false;
- }
- RemoveAdvisor(index);
- AddAdvisor(index, newAdvisor);
- }
- return true;
- }
-
- ///
- /// As will normally be passed straight through
- /// to the advised target, this method returns the
- /// equivalent for the AOP proxy itself.
- ///
- ///
- /// A description of the proxy configuration.
- ///
- public virtual string ToProxyConfigString()
- {
- lock(this.SyncRoot)
- {
- return ToStringInternal();
- }
- }
-
- #endregion
-
- #region ITargetTypeAware implementation
-
- ///
- /// Gets the target type behind the implementing object.
- /// Ttypically a proxy configuration or an actual proxy.
- ///
- /// The type of the target or null if not known.
- public Type TargetType
- {
- get { return TargetSource.TargetType; }
- }
-
- #endregion
-
- #region Properties
- ///
- /// Sets the target object that is to be advised.
- ///
- ///
- ///
- /// This is a convenience write-only property that allows client code
- /// to set the target object... the target object will be implicitly
- /// wrapped within a new
- /// instance.
- ///
- ///
- public virtual object Target
- {
- set { TargetSource = new SingletonTargetSource(value); }
- }
-
- ///
- /// Called by subclasses to get a value indicating whether any AOP proxies have been created yet.
- ///
- /// true if this AOp proxies have been created; otherwise, false.
- protected bool IsActive
- {
- get { return isActive; }
- }
-
- #endregion
-
- ///
- /// Specifies the of proxies that are to be
- /// created for this instance of proxy config.
- ///
- ///
- ///
- /// If this property value is it simply means that
- /// no proxies have been created yet. Only when the first proxy is
- /// created will this property value be set by the AOP framework.
- ///
- ///
- /// Users will be able to add interceptors dynamically without proxy
- /// regeneration, but if they add introductions the proxy
- /// will have to be regenerated.
- ///
- ///
- ///
- /// The of proxies that are to be
- /// created for this instance of proxy config; if
- /// no proxies have been created yet.
- ///
- internal Type ProxyType
- {
- get { return this.proxyType; }
- set { this.proxyType = value; }
- }
-
- ///
- /// Caches proxy constructor for performance reasons.
- ///
- internal ConstructorInfo ProxyConstructor
- {
- get { return this.proxyConstructor; }
- set { this.proxyConstructor = value; }
- }
-
- ///
- /// Registers the supplied as a listener for
- /// notifications.
- ///
- ///
- /// The to
- /// register.
- ///
- public virtual void AddListener(IAdvisedSupportListener listener)
- {
- lock(this.SyncRoot)
- {
- this.listeners.Add(listener);
- }
- }
-
- ///
- /// Removes the supplied .
- ///
- ///
- /// The to
- /// be removed.
- ///
- public virtual void RemoveListener(IAdvisedSupportListener listener)
- {
- lock(this.SyncRoot)
- {
- this.listeners.Remove(listener);
- }
- }
-
- ///
- /// Adds a new interface to the list of interfaces that are proxied by this proxy.
- ///
- ///
- /// The interface to be proxied by this proxy.
- ///
- ///
- /// If this proxy configuration is frozen
- /// ();
- ///
- ///
- /// If the supplied is .
- ///
- public virtual void AddInterface(Type intf)
- {
- DieIfFrozen("Cannot add interface: configuration is frozen.");
- AssertUtils.ArgumentNotNull(intf, "intf", "Cannot proxy a null interface.");
-
- lock(this.SyncRoot)
- {
- AddInterfaceInternal(intf);
- InterfacesChanged();
- }
- }
-
- ///
- /// Adds a new interface to the list of interfaces that are proxied by this proxy.
- ///
- ///
- /// The interface to be proxied by this proxy.
- ///
- ///
- /// Access is not synchronized.
- ///
- protected virtual void AddInterfaceInternal(Type intf)
- {
- this.interfaceMap[intf] = null;
- }
-
- ///
- /// Removes the supplied (proxied) .
- ///
- ///
- ///
- /// Does nothing if the supplied (proxied)
- /// isn't proxied.
- ///
- ///
- /// The interface to remove.
- ///
- /// if the interface was removed.
- public virtual bool RemoveInterface(Type intf)
- {
- DieIfFrozen("Cannot remove interface: configuration is frozen.");
- lock(this.SyncRoot)
- {
- if (intf != null && this.interfaceMap.Contains(intf))
- {
- this.interfaceMap.Remove(intf);
- InterfacesChanged();
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the interceptor
- /// (advice) chain for this proxy.
- ///
- ///
- ///
- /// The return value of this method can be used to index into
- /// the
- /// list.
- ///
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this interceptor, or -1 if the
- /// supplied is not an advice for this
- /// proxy.
- ///
- public virtual int IndexOf(IAdvice advice)
- {
- lock(this.SyncRoot)
- {
- return IndexOfInternal(advice);
- }
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the interceptor
- /// (advice) chain for this proxy.
- ///
- ///
- ///
Acces is not synchronized
- ///
- /// The return value of this method can be used to index into
- /// the
- /// list.
- ///
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this interceptor, or -1 if the
- /// supplied is not an advice for this
- /// proxy.
- ///
- private int IndexOfInternal(IAdvice advice)
- {
- if (this._advisors != null)
- {
- for (int i = 0; i < this._advisors.Count; ++i)
- {
- IAdvisor advisor = (IAdvisor) this._advisors[i];
- if (advisor.Advice == advice)
- {
- return i;
- }
- }
- }
- return -1;
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the interceptor
- /// (advice) chain for this proxy.
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this advisor, or -1 if the
- /// supplied is not an advisor for this
- /// proxy.
- ///
- ///
- /// Access is not synchronized.
- ///
- private int IndexOfInternal(IAdvisor advisor)
- {
- return this._advisors != null ? this._advisors.IndexOf(advisor) : -1;
- }
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the introductions
- /// for this proxy.
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this advisor, or -1 if the
- /// supplied is not an introduction advisor
- /// for this proxy.
- ///
- ///
- /// Access is not synchronized
- ///
- private int IndexOfInternal(IIntroductionAdvisor advisor)
- {
- return this._introductions.IndexOf(advisor);
- }
-
- ///
- /// Removes the at the supplied
- /// in the
- /// list
- /// from the list of
- /// for this proxy.
- ///
- ///
- /// The index of the to remove.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// at the supplied
- /// cannot be removed; or if the supplied is out of
- /// range.
- ///
- ///
- /// Does not synchronize access.
- ///
- private void RemoveAdvisorInternal(int index)
- {
- if (index < 0 || index >= this._advisors.Count)
- {
- throw
- new AopConfigException(
- "Advisor index " + index + " is out of bounds: Only have " + this._advisors.Count + " advisors");
- }
- this._advisors.RemoveAt(index);
- this.UpdateAdvisorsArray();
- this.InterceptorsChanged();
- }
-
- ///
- /// Is the supplied included in any
- /// advisor?
- ///
- ///
- /// The to check for the
- /// inclusion of.
- ///
- ///
- /// if the supplied
- /// could be run in an invocation (this does not imply that said
- /// will be run).
- ///
- public bool AdviceIncluded(IAdvice advice)
- {
- return (IndexOf(advice) != -1);
- }
-
- ///
- /// Returns a count of all of the
- /// type-compatible with the supplied .
- ///
- ///
- /// The of the
- /// to check.
- ///
- ///
- /// A count of all of the
- /// type-compatible with the supplied .
- ///
- public int CountAdviceOfType(Type interceptorType)
- {
- int count = 0;
- lock(this.SyncRoot)
- {
- foreach (IAdvisor advisor in this._advisors)
- {
- if (interceptorType.IsAssignableFrom(advisor.Advice.GetType()))
- {
- ++count;
- }
- }
- }
- return count;
- }
-
- ///
- /// Throws an if
- /// this instances proxy configuration data is frozen.
- ///
- ///
- /// The message that will be passed through to the constructor of any
- /// thrown .
- ///
- ///
- /// If the configuration for this proxy is frozen.
- ///
- ///
- private void DieIfFrozen(string message)
- {
- if (IsFrozen)
- {
- throw new AopConfigException(message);
- }
- }
-
- ///
- /// Bring the advisors array up to date with the list.
- ///
- private void UpdateAdvisorsArray()
- {
- this._advisorsArray = new IAdvisor[this._advisors.Count];
- this._advisors.CopyTo(this._advisorsArray, 0);
- }
-
- ///
- /// Bring the introductions array up to date with the list.
- ///
- private void UpdateIntroductionsArray()
- {
- this._introductionsArray = new IIntroductionAdvisor[this._introductions.Count];
- this._introductions.CopyTo(this._introductionsArray, 0);
- }
-
- ///
- /// Callback method that is invoked when the list of proxied interfaces
- /// has changed.
- ///
- ///
- ///
- /// An example of such a change would be when a new introduction is
- /// added. Resetting
- /// to
- /// will cause a new proxy
- /// to be generated on the next call to get a proxy.
- ///
- ///
- private void InterfacesChanged()
- {
- ProxyType = null;
- if (this.isActive)
- {
- foreach (IAdvisedSupportListener listener in this.listeners)
- {
- listener.InterfacesChanged(this);
- }
- }
- }
-
- ///
- /// Callback method that is invoked when the interceptor list has changed.
- ///
- private void InterceptorsChanged()
- {
- if (this.isActive)
- {
- foreach (IAdvisedSupportListener listener in this.listeners)
- {
- listener.AdviceChanged(this);
- }
- }
- }
-
- ///
- /// Activates this instance.
- ///
- protected void Activate()
- {
- lock (this.SyncRoot)
- {
- this.isActive = true;
- foreach (IAdvisedSupportListener listener in this.listeners)
- {
- listener.Activated(this);
- }
- }
- }
-
- ///
- /// Creates an AOP proxy using this instance's configuration data.
- ///
- ///
- ///
- /// Subclasses must not create a proxy by any other means (at least
- /// without having a well thought out and cogent reason for doing so).
- /// This is because the implementation of this method performs some
- /// required housekeeping logic prior to creating an AOP proxy.
- ///
- ///
- ///
- protected internal virtual IAopProxy CreateAopProxy()
- {
- lock (this.SyncRoot)
- {
- if (!this.isActive)
- {
- Activate();
- }
- return AopProxyFactory.CreateAopProxy(this);
- }
- }
-
- ///
- /// Copies the configuration from the supplied other
- /// into this instance.
- ///
- ///
- ///
- /// Useful when this instance has been created using the no-argument
- /// constructor, and needs to get all of its confiuration data from
- /// another (most
- /// usually to have an independant copy of said configuration data).
- ///
+ /// Instances of this class are not themselves AOP proxies, but
+ /// subclasses of this class are normally factories from which AOP proxy
+ /// instances are obtained directly.
+ ///
+ ///
+ /// This class frees subclasses of the housekeeping of
+ /// and
+ /// instances, but doesn't actually
+ /// implement proxy creation methods, the functionality for which
+ /// is provided by subclasses.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ [Serializable]
+ public class AdvisedSupport : ProxyConfig, IAdvised
+ {
+ #region Fields
+
+ /// The list of advice.
+ ///
+ ///
+ /// If an is added, it
+ /// will be wrapped in an advice before being added to this list.
+ ///
+ ///
+ private IList _advisors = new ArrayList();
+
+ ///
+ /// Array updated on changes to the advisors list, which is easier to
+ /// manipulate internally
+ ///
+ private IAdvisor[] _advisorsArray = new IAdvisor[] {};
+
+ ///
+ /// List of introductions.
+ ///
+ private IList _introductions = new ArrayList();
+
+ ///
+ /// Array updated on changes to the advisors list, which is easier to
+ /// manipulate internally
+ ///
+ private IIntroductionAdvisor[] _introductionsArray
+ = new IIntroductionAdvisor[] {};
+
+ ///
+ /// Interface map specifying which object should interface methods be
+ /// delegated to.
+ ///
+ ///
+ ///
+ /// If entry value is methods should be delegated
+ /// to the target object.
+ ///
+ ///
+ private IDictionary interfaceMap = new ListDictionary();
+
+ ///
+ /// The for this instance.
+ ///
+ protected internal ITargetSource m_targetSource = EmptyTargetSource.Empty;
+
+ ///
+ /// Set to when the first AOP proxy has been
+ /// created, meaning that we must track advice changes via the
+ /// OnAdviceChange() callback.
+ ///
+ private bool isActive;
+
+ private Type proxyType;
+ private ConstructorInfo proxyConstructor;
+
+ ///
+ /// The list of event listeners.
+ ///
+ private IList listeners = new ArrayList();
+
+ ///
+ /// The advisor chain factory.
+ ///
+ private IAdvisorChainFactory advisorChainFactory;
+
+ #endregion
+
+ #region Constructor(s)
+
+ ///
+ /// Creates a new instance of the
+ /// class using the
+ /// default advisor chain factory.
+ ///
+ public AdvisedSupport()
+ {
+ AdvisorChainFactory = new HashtableCachingAdvisorChainFactory();
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// The interfaces that are to be proxied.
+ ///
+ /// If this
+ ///
+ public AdvisedSupport(Type[] interfaces) : this()
+ {
+ if (interfaces != null)
+ {
+ foreach (Type intf in interfaces)
+ {
+ AddInterfaceInternal(intf);
+ }
+ }
+ }
+
+ #endregion
+
+ #region IAdvised implementation
+
+ ///
+ /// Gets and sets the
+ ///
+ /// implementation that will be used to get the interceptor
+ /// chains for the advised
+ /// .
+ ///
+ ///
+ /// The
+ /// implementation that will be used to get the interceptor
+ /// chains for the advised
+ /// .
+ ///
+ public virtual IAdvisorChainFactory AdvisorChainFactory
+ {
+ get
+ {
+ lock(this.SyncRoot)
+ {
+ return this.advisorChainFactory;
+ }
+ }
+ set
+ {
+ lock(this.SyncRoot)
+ {
+ if (this.advisorChainFactory != null)
+ {
+ RemoveListener(this.advisorChainFactory);
+ }
+ this.advisorChainFactory = value;
+ AddListener(this.advisorChainFactory);
+ }
+ }
+ }
+
+ ///
+ /// Returns the current used
+ /// by this object.
+ ///
+ ///
+ /// The used by this
+ /// object.
+ ///
+ ///
+ public ITargetSource TargetSource
+ {
+ get { return this.m_targetSource; }
+ set
+ {
+ bool initialized = !(this.m_targetSource is EmptyTargetSource);
+ this.m_targetSource = value;
+
+ if (this.m_targetSource != null && !initialized && interfaceMap.Count == 0)
+ {
+ Type[] interfaces = ReflectionUtils.GetInterfaces(this.m_targetSource.TargetType);
+ foreach (Type intf in interfaces)
+ {
+ AddInterfaceInternal(intf);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Returns a boolean specifying if this
+ /// instance can be serialized.
+ ///
+ ///
+ /// true if this instance can be serialized, false otherwise.
+ ///
+ public bool IsSerializable
+ {
+ get
+ {
+ bool canBeSerialized = TargetSource.TargetType.IsSerializable;
+ if (canBeSerialized)
+ {
+ for (int i = 0; canBeSerialized && i < _advisorsArray.Length; i++)
+ {
+ IAdvisor advisor = _advisorsArray[i];
+ canBeSerialized = advisor.GetType().IsSerializable
+ && advisor.Advice.GetType().IsSerializable;
+ }
+ for (int i = 0; canBeSerialized && i < _introductionsArray.Length; i++)
+ {
+ IIntroductionAdvisor advisor = _introductionsArray[i];
+ canBeSerialized = advisor.GetType().IsSerializable
+ && advisor.Advice.GetType().IsSerializable;
+ }
+ }
+
+ return canBeSerialized;
+ }
+ }
+
+ ///
+ /// Returns the collection of interface s
+ /// to be (or that are being) proxied by this proxy.
+ ///
+ ///
+ /// The collection of interface s
+ /// to be (or that are being) proxied by this proxy.
+ ///
+ ///
+ public virtual Type[] Interfaces
+ {
+ get
+ {
+ lock(this.SyncRoot)
+ {
+ Type[] proxiedInterfaces = new Type[this.interfaceMap.Keys.Count];
+ this.interfaceMap.Keys.CopyTo(proxiedInterfaces, 0);
+ return proxiedInterfaces;
+ }
+ }
+ set
+ {
+ lock(this.SyncRoot)
+ {
+ this.interfaceMap.Clear();
+ for (int i = 0; i < value.Length; i++)
+ {
+ AddInterfaceInternal(value[i]);
+ }
+ InterfacesChanged();
+ }
+ }
+ }
+
+ ///
+ /// Returns the mapping of the proxied interface
+ /// s to their delegates.
+ ///
+ ///
+ /// The mapping of the proxied interface
+ /// s to their delegates.
+ ///
+ ///
+ public virtual IDictionary InterfaceMap
+ {
+ get
+ {
+ lock(this.SyncRoot)
+ {
+ return new Hashtable(this.interfaceMap);
+ }
+ }
+ }
+
+ ///
+ /// Is the supplied (interface)
+ /// proxied?
+ ///
+ ///
+ /// The interface to test.
+ ///
+ ///
+ /// if the supplied
+ /// (interface) is proxied;
+ /// if not or the supplied
+ /// is .
+ ///
+ ///
+ public virtual bool IsInterfaceProxied(Type intf)
+ {
+ if (intf != null)
+ {
+ lock(this.SyncRoot)
+ {
+ foreach (Type proxyInterface in this.interfaceMap.Keys)
+ {
+ if (intf.IsAssignableFrom(proxyInterface))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Returns the collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ /// The collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ public virtual IAdvisor[] Advisors
+ {
+ get
+ {
+ lock(this.SyncRoot)
+ {
+ return (IAdvisor[]) this._advisorsArray.Clone();
+ }
+ }
+ }
+
+ ///
+ /// Returns the collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ ///
+ /// Will never return , but may return an
+ /// empty array (in the case where no
+ /// instances have been
+ /// applied to this proxy).
+ ///
+ ///
+ ///
+ /// The collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ public virtual IIntroductionAdvisor[] Introductions
+ {
+ get
+ {
+ lock(this.SyncRoot)
+ {
+ return (IIntroductionAdvisor[]) this._introductionsArray.Clone();
+ }
+ }
+ }
+
+ ///
+ /// Adds the supplied to the end (or tail)
+ /// of the advice (interceptor) chain.
+ ///
+ ///
+ /// The to be added.
+ ///
+ ///
+ ///
+ public void AddAdvice(IAdvice advice)
+ {
+ //int position = this._advisors != null ? this._advisors.Count : 0;
+ AddAdvice(-1, advice);
+ }
+
+ ///
+ /// Adds the supplied to the supplied
+ /// in the advice (interceptor) chain.
+ ///
+ ///
+ /// The zero (0) indexed position (from the head) at which the
+ /// supplied is to be inserted into the
+ /// advice (interceptor) chain.
+ ///
+ ///
+ /// The to be added.
+ ///
+ ///
+ /// If the supplied is ;
+ /// or is not an
+ /// reference; or if the supplied is a
+ /// .
+ ///
+ ///
+ ///
+ public void AddAdvice(int position, IAdvice advice)
+ {
+ if (advice is IInterceptor && !(advice is IMethodInterceptor))
+ {
+ throw new AopConfigException(
+ GetType().FullName + " can only handle AOP Alliance IMethodInterceptor advice.");
+ }
+ if (advice is IIntroductionInterceptor)
+ {
+ throw
+ new AopConfigException(
+ "IIntroductionInterceptors may only be added as part of IIntroductionAdvisor.");
+ }
+
+ AddAdvisor(position, new DefaultPointcutAdvisor(advice));
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the interceptor
+ /// (advice) chain for this proxy.
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this advisor, or -1 if the
+ /// supplied is not an advisor for this
+ /// proxy.
+ ///
+ public virtual int IndexOf(IAdvisor advisor)
+ {
+ lock(this.SyncRoot)
+ {
+ return IndexOfInternal(advisor);
+ }
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the introductions
+ /// for this proxy.
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this advisor, or -1 if the
+ /// supplied is not an introduction advisor
+ /// for this proxy.
+ ///
+ public virtual int IndexOf(IIntroductionAdvisor advisor)
+ {
+ lock(this.SyncRoot)
+ {
+ return IndexOfInternal(advisor);
+ }
+ }
+
+ ///
+ /// Removes the supplied the list of advisors
+ /// for this proxy.
+ ///
+ /// The advisor to remove.
+ ///
+ /// if advisor was found in the list of
+ /// for this
+ /// proxy and was successfully removed; if not
+ /// or if the supplied is .
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be removed.
+ ///
+ public bool RemoveAdvisor(IAdvisor advisor)
+ {
+ DieIfFrozen("Cannot remove advisor: config is frozen");
+ bool wasRemoved = false;
+ if (advisor != null)
+ {
+ lock(this.SyncRoot)
+ {
+ int index = IndexOf(advisor);
+ if (index == -1)
+ {
+ wasRemoved = false;
+ }
+ else
+ {
+ RemoveAdvisorInternal(index);
+ wasRemoved = true;
+ }
+ }
+ }
+ return wasRemoved;
+ }
+
+ ///
+ /// Removes the at the supplied
+ /// in the
+ /// list
+ /// from the list of
+ /// for this proxy.
+ ///
+ ///
+ /// The index of the to remove.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// at the supplied
+ /// cannot be removed; or if the supplied is out of
+ /// range.
+ ///
+ public virtual void RemoveAdvisor(int index)
+ {
+ DieIfFrozen("Cannot remove advisor: config is frozen");
+ lock(this.SyncRoot)
+ {
+ RemoveAdvisorInternal(index);
+ }
+ }
+
+ ///
+ /// Removes the supplied from the list
+ /// of .
+ ///
+ ///
+ /// The to remove.
+ ///
+ ///
+ /// if the supplied was
+ /// found in the list of
+ /// and successfully removed.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be removed.
+ ///
+ public bool RemoveAdvice(IAdvice advice)
+ {
+ lock(this.SyncRoot)
+ {
+ int index = IndexOf(advice);
+ if (index == -1)
+ {
+ return false;
+ }
+ else
+ {
+ RemoveAdvisorInternal(index);
+ return true;
+ }
+ }
+ }
+
+ ///
+ /// Removes the supplied from the list
+ /// of .
+ ///
+ ///
+ /// The to remove.
+ ///
+ ///
+ /// if the supplied was
+ /// found in the list of
+ /// and successfully removed.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be removed.
+ ///
+ public bool RemoveIntroduction(IIntroductionAdvisor introduction)
+ {
+ DieIfFrozen("Cannot remove introduction: config is frozen");
+ bool wasRemoved = false;
+ if (introduction != null)
+ {
+ lock(this.SyncRoot)
+ {
+ int index = IndexOf(introduction);
+ if (index == -1)
+ {
+ wasRemoved = false;
+ }
+ else
+ {
+ RemoveIntroduction(index);
+ wasRemoved = true;
+ }
+ }
+ }
+ return wasRemoved;
+ }
+
+ ///
+ /// Removes the at the supplied
+ /// in the list of
+ /// for this proxy.
+ ///
+ /// The index of the advisor to remove.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// at the supplied
+ /// cannot be removed; or if the supplied
+ /// is out of range.
+ ///
+ public virtual void RemoveIntroduction(int index)
+ {
+ DieIfFrozen("Cannot remove introduction: config is frozen");
+ lock(this.SyncRoot)
+ {
+ if (index < 0 || index >= _introductions.Count)
+ {
+ throw new AopConfigException(
+ "Introduction index " + index + " is out of bounds: Only have " + _introductions.Count +
+ " introductions.");
+ }
+ IIntroductionAdvisor advisor = (IIntroductionAdvisor) _introductions[index];
+ // remove all interfaces introduced by the advisor...
+ foreach (Type intf in advisor.Interfaces)
+ {
+ RemoveInterface(intf);
+ }
+ this._introductions.RemoveAt(index);
+ UpdateIntroductionsArray();
+ }
+ }
+
+//
+// ///
+// /// Removes the supplied from the list of
+// /// for this
+// /// proxy.
+// ///
+// ///
+// /// The to be removed.
+// ///
+// ///
+// /// If this proxy configuration is frozen and the
+// /// cannot be added.
+// ///
+// public bool RemoveInterceptor(IInterceptor interceptor)
+// {
+// AssertFrozen("Cannot remove interceptor: config is frozen");
+// int index = IndexOf(interceptor);
+// if (index == -1)
+// {
+// return false;
+// }
+// else
+// {
+// RemoveAdvisor(index);
+// return true;
+// }
+// }
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The index in the
+ /// list at which the supplied
+ /// is to be inserted. If -1, appends to the end of the list.
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ public virtual void AddAdvisor(int index, IAdvisor advisor)
+ {
+ DieIfFrozen("Cannot add advisor: config is frozen");
+ lock(this.SyncRoot)
+ {
+ // advisor already in list (SPRNET-846)
+ if (_advisors.Contains(advisor)) return;
+
+ if(index == -1)
+ {
+ this._advisors.Add(advisor);
+ }
+ else
+ {
+ this._advisors.Insert(index, advisor);
+ }
+ UpdateAdvisorsArray();
+ InterceptorsChanged();
+ }
+ }
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ public virtual void AddAdvisor(IAdvisor advisor)
+ {
+ AddAdvisor(this._advisors.Count, advisor);
+ }
+
+ ///
+ /// Adds the advisors from the supplied
+ /// to the list of .
+ ///
+ ///
+ /// The to add advisors from.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ public void AddAdvisors(IAdvisors advisors)
+ {
+ foreach (IAdvisor advisor in advisors.Advisors)
+ {
+ if (advisor is IIntroductionAdvisor)
+ {
+ AddIntroduction((IIntroductionAdvisor) advisor);
+ }
+ else
+ {
+ AddAdvisor(advisor);
+ }
+ }
+ }
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The index in the
+ /// list at which the supplied
+ /// is to be inserted.
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ public virtual void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor)
+ {
+ DieIfFrozen("Cannot add introduction: config is frozen");
+ introductionAdvisor.ValidateInterfaces();
+
+ lock(this.SyncRoot)
+ {
+ if (index < this._introductions.Count)
+ {
+ this._introductions.RemoveAt(index);
+ }
+ this._introductions.Insert(index, introductionAdvisor);
+
+ int intfCount = this.interfaceMap.Count;
+ // If the advisor passed validation we can make the change
+ foreach (Type intf in introductionAdvisor.Interfaces)
+ {
+ this.interfaceMap[intf] = introductionAdvisor;
+ }
+ UpdateIntroductionsArray();
+ if (this.interfaceMap.Count != intfCount)
+ {
+ InterfacesChanged();
+ }
+ }
+ }
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ public virtual void AddIntroduction(IIntroductionAdvisor introductionAdvisor)
+ {
+ Type introductionType = introductionAdvisor.Advice.GetType();
+ lock(this.SyncRoot)
+ {
+ int pos = this._introductions.Count;
+ for (int i = 0; i < pos; i++)
+ {
+ IIntroductionAdvisor introduction
+ = (IIntroductionAdvisor) this._introductions[i];
+ if (introduction.Advice.GetType() == introductionType)
+ {
+ pos = i;
+ }
+ }
+ AddIntroduction(pos, introductionAdvisor);
+ }
+ }
+
+ ///
+ /// Replaces the that
+ /// exists at the supplied in the list of
+ ///
+ /// with the supplied .
+ ///
+ ///
+ /// The index of the
+ /// in the list of
+ ///
+ /// that is to be replaced.
+ ///
+ ///
+ /// The new (replacement) .
+ ///
+ ///
+ /// If the supplied is out of range.
+ ///
+ public virtual void ReplaceIntroduction(int index, IIntroductionAdvisor introduction)
+ {
+ lock(this.SyncRoot)
+ {
+ if(index < 0 || index >= _introductions.Count)
+ {
+ throw new AopConfigException(
+ "Introduction index " + index + " is out of bounds:" +
+ " there are currently " + _introductions.Count +
+ " introductions." );
+ }
+
+ _introductions[index] = introduction;
+ }
+ }
+
+ ///
+ /// Replaces the with the
+ /// .
+ ///
+ ///
+ /// The original (old) advisor to be replaced.
+ ///
+ ///
+ /// The new advisor to replace the with.
+ ///
+ ///
+ /// if the was
+ /// replaced; if the was not found in the
+ /// advisors collection (or the is
+ /// , this method returns
+ /// and (effectively) does nothing.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be replaced.
+ ///
+ ///
+ public bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor)
+ {
+ DieIfFrozen("Cannot replace advisor: config is frozen.");
+ lock(this.SyncRoot)
+ {
+ int index = IndexOf(oldAdvisor);
+ if (index == -1 || newAdvisor == null)
+ {
+ return false;
+ }
+ RemoveAdvisor(index);
+ AddAdvisor(index, newAdvisor);
+ }
+ return true;
+ }
+
+ ///
+ /// As will normally be passed straight through
+ /// to the advised target, this method returns the
+ /// equivalent for the AOP proxy itself.
+ ///
+ ///
+ /// A description of the proxy configuration.
+ ///
+ public virtual string ToProxyConfigString()
+ {
+ lock(this.SyncRoot)
+ {
+ return ToStringInternal();
+ }
+ }
+
+ #endregion
+
+ #region ITargetTypeAware implementation
+
+ ///
+ /// Gets the target type behind the implementing object.
+ /// Ttypically a proxy configuration or an actual proxy.
+ ///
+ /// The type of the target or null if not known.
+ public Type TargetType
+ {
+ get { return TargetSource.TargetType; }
+ }
+
+ #endregion
+
+ #region Properties
+ ///
+ /// Sets the target object that is to be advised.
+ ///
+ ///
+ ///
+ /// This is a convenience write-only property that allows client code
+ /// to set the target object... the target object will be implicitly
+ /// wrapped within a new
+ /// instance.
+ ///
+ ///
+ public virtual object Target
+ {
+ set { TargetSource = new SingletonTargetSource(value); }
+ }
+
+ ///
+ /// Called by subclasses to get a value indicating whether any AOP proxies have been created yet.
+ ///
+ /// true if this AOp proxies have been created; otherwise, false.
+ protected bool IsActive
+ {
+ get { return isActive; }
+ }
+
+ #endregion
+
+ ///
+ /// Specifies the of proxies that are to be
+ /// created for this instance of proxy config.
+ ///
+ ///
+ ///
+ /// If this property value is it simply means that
+ /// no proxies have been created yet. Only when the first proxy is
+ /// created will this property value be set by the AOP framework.
+ ///
+ ///
+ /// Users will be able to add interceptors dynamically without proxy
+ /// regeneration, but if they add introductions the proxy
+ /// will have to be regenerated.
+ ///
+ ///
+ ///
+ /// The of proxies that are to be
+ /// created for this instance of proxy config; if
+ /// no proxies have been created yet.
+ ///
+ internal Type ProxyType
+ {
+ get { return this.proxyType; }
+ set { this.proxyType = value; }
+ }
+
+ ///
+ /// Caches proxy constructor for performance reasons.
+ ///
+ internal ConstructorInfo ProxyConstructor
+ {
+ get { return this.proxyConstructor; }
+ set { this.proxyConstructor = value; }
+ }
+
+ ///
+ /// Registers the supplied as a listener for
+ /// notifications.
+ ///
+ ///
+ /// The to
+ /// register.
+ ///
+ public virtual void AddListener(IAdvisedSupportListener listener)
+ {
+ lock(this.SyncRoot)
+ {
+ this.listeners.Add(listener);
+ }
+ }
+
+ ///
+ /// Removes the supplied .
+ ///
+ ///
+ /// The to
+ /// be removed.
+ ///
+ public virtual void RemoveListener(IAdvisedSupportListener listener)
+ {
+ lock(this.SyncRoot)
+ {
+ this.listeners.Remove(listener);
+ }
+ }
+
+ ///
+ /// Adds a new interface to the list of interfaces that are proxied by this proxy.
+ ///
+ ///
+ /// The interface to be proxied by this proxy.
+ ///
+ ///
+ /// If this proxy configuration is frozen
+ /// ();
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public virtual void AddInterface(Type intf)
+ {
+ DieIfFrozen("Cannot add interface: configuration is frozen.");
+ AssertUtils.ArgumentNotNull(intf, "intf", "Cannot proxy a null interface.");
+
+ lock(this.SyncRoot)
+ {
+ AddInterfaceInternal(intf);
+ InterfacesChanged();
+ }
+ }
+
+ ///
+ /// Adds a new interface to the list of interfaces that are proxied by this proxy.
+ ///
+ ///
+ /// The interface to be proxied by this proxy.
+ ///
+ ///
+ /// Access is not synchronized.
+ ///
+ protected virtual void AddInterfaceInternal(Type intf)
+ {
+ this.interfaceMap[intf] = null;
+ }
+
+ ///
+ /// Removes the supplied (proxied) .
+ ///
+ ///
+ ///
+ /// Does nothing if the supplied (proxied)
+ /// isn't proxied.
+ ///
+ ///
+ /// The interface to remove.
+ ///
+ /// if the interface was removed.
+ public virtual bool RemoveInterface(Type intf)
+ {
+ DieIfFrozen("Cannot remove interface: configuration is frozen.");
+ lock(this.SyncRoot)
+ {
+ if (intf != null && this.interfaceMap.Contains(intf))
+ {
+ this.interfaceMap.Remove(intf);
+ InterfacesChanged();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the interceptor
+ /// (advice) chain for this proxy.
+ ///
+ ///
+ ///
+ /// The return value of this method can be used to index into
+ /// the
+ /// list.
+ ///
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this interceptor, or -1 if the
+ /// supplied is not an advice for this
+ /// proxy.
+ ///
+ public virtual int IndexOf(IAdvice advice)
+ {
+ lock(this.SyncRoot)
+ {
+ return IndexOfInternal(advice);
+ }
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the interceptor
+ /// (advice) chain for this proxy.
+ ///
+ ///
+ ///
Acces is not synchronized
+ ///
+ /// The return value of this method can be used to index into
+ /// the
+ /// list.
+ ///
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this interceptor, or -1 if the
+ /// supplied is not an advice for this
+ /// proxy.
+ ///
+ private int IndexOfInternal(IAdvice advice)
+ {
+ if (this._advisors != null)
+ {
+ for (int i = 0; i < this._advisors.Count; ++i)
+ {
+ IAdvisor advisor = (IAdvisor) this._advisors[i];
+ if (advisor.Advice == advice)
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the interceptor
+ /// (advice) chain for this proxy.
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this advisor, or -1 if the
+ /// supplied is not an advisor for this
+ /// proxy.
+ ///
+ ///
+ /// Access is not synchronized.
+ ///
+ private int IndexOfInternal(IAdvisor advisor)
+ {
+ return this._advisors != null ? this._advisors.IndexOf(advisor) : -1;
+ }
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the introductions
+ /// for this proxy.
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this advisor, or -1 if the
+ /// supplied is not an introduction advisor
+ /// for this proxy.
+ ///
+ ///
+ /// Access is not synchronized
+ ///
+ private int IndexOfInternal(IIntroductionAdvisor advisor)
+ {
+ return this._introductions.IndexOf(advisor);
+ }
+
+ ///
+ /// Removes the at the supplied
+ /// in the
+ /// list
+ /// from the list of
+ /// for this proxy.
+ ///
+ ///
+ /// The index of the to remove.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// at the supplied
+ /// cannot be removed; or if the supplied is out of
+ /// range.
+ ///
+ ///
+ /// Does not synchronize access.
+ ///
+ private void RemoveAdvisorInternal(int index)
+ {
+ if (index < 0 || index >= this._advisors.Count)
+ {
+ throw
+ new AopConfigException(
+ "Advisor index " + index + " is out of bounds: Only have " + this._advisors.Count + " advisors");
+ }
+ this._advisors.RemoveAt(index);
+ this.UpdateAdvisorsArray();
+ this.InterceptorsChanged();
+ }
+
+ ///
+ /// Is the supplied included in any
+ /// advisor?
+ ///
+ ///
+ /// The to check for the
+ /// inclusion of.
+ ///
+ ///
+ /// if the supplied
+ /// could be run in an invocation (this does not imply that said
+ /// will be run).
+ ///
+ public bool AdviceIncluded(IAdvice advice)
+ {
+ return (IndexOf(advice) != -1);
+ }
+
+ ///
+ /// Returns a count of all of the
+ /// type-compatible with the supplied .
+ ///
+ ///
+ /// The of the
+ /// to check.
+ ///
+ ///
+ /// A count of all of the
+ /// type-compatible with the supplied .
+ ///
+ public int CountAdviceOfType(Type interceptorType)
+ {
+ int count = 0;
+ lock(this.SyncRoot)
+ {
+ foreach (IAdvisor advisor in this._advisors)
+ {
+ if (interceptorType.IsAssignableFrom(advisor.Advice.GetType()))
+ {
+ ++count;
+ }
+ }
+ }
+ return count;
+ }
+
+ ///
+ /// Throws an if
+ /// this instances proxy configuration data is frozen.
+ ///
+ ///
+ /// The message that will be passed through to the constructor of any
+ /// thrown .
+ ///
+ ///
+ /// If the configuration for this proxy is frozen.
+ ///
+ ///
+ private void DieIfFrozen(string message)
+ {
+ if (IsFrozen)
+ {
+ throw new AopConfigException(message);
+ }
+ }
+
+ ///
+ /// Bring the advisors array up to date with the list.
+ ///
+ private void UpdateAdvisorsArray()
+ {
+ this._advisorsArray = new IAdvisor[this._advisors.Count];
+ this._advisors.CopyTo(this._advisorsArray, 0);
+ }
+
+ ///
+ /// Bring the introductions array up to date with the list.
+ ///
+ private void UpdateIntroductionsArray()
+ {
+ this._introductionsArray = new IIntroductionAdvisor[this._introductions.Count];
+ this._introductions.CopyTo(this._introductionsArray, 0);
+ }
+
+ ///
+ /// Callback method that is invoked when the list of proxied interfaces
+ /// has changed.
+ ///
+ ///
+ ///
+ /// An example of such a change would be when a new introduction is
+ /// added. Resetting
+ /// to
+ /// will cause a new proxy
+ /// to be generated on the next call to get a proxy.
+ ///
+ ///
+ private void InterfacesChanged()
+ {
+ ProxyType = null;
+ if (this.isActive)
+ {
+ foreach (IAdvisedSupportListener listener in this.listeners)
+ {
+ listener.InterfacesChanged(this);
+ }
+ }
+ }
+
+ ///
+ /// Callback method that is invoked when the interceptor list has changed.
+ ///
+ private void InterceptorsChanged()
+ {
+ if (this.isActive)
+ {
+ foreach (IAdvisedSupportListener listener in this.listeners)
+ {
+ listener.AdviceChanged(this);
+ }
+ }
+ }
+
+ ///
+ /// Activates this instance.
+ ///
+ protected void Activate()
+ {
+ lock (this.SyncRoot)
+ {
+ this.isActive = true;
+ foreach (IAdvisedSupportListener listener in this.listeners)
+ {
+ listener.Activated(this);
+ }
+ }
+ }
+
+ ///
+ /// Creates an AOP proxy using this instance's configuration data.
+ ///
+ ///
+ ///
+ /// Subclasses must not create a proxy by any other means (at least
+ /// without having a well thought out and cogent reason for doing so).
+ /// This is because the implementation of this method performs some
+ /// required housekeeping logic prior to creating an AOP proxy.
+ ///
+ ///
+ ///
+ protected internal virtual IAopProxy CreateAopProxy()
+ {
+ lock (this.SyncRoot)
+ {
+ if (!this.isActive)
+ {
+ Activate();
+ }
+ return AopProxyFactory.CreateAopProxy(this);
+ }
+ }
+
+ ///
+ /// Copies the configuration from the supplied other
+ /// into this instance.
+ ///
+ ///
+ ///
+ /// Useful when this instance has been created using the no-argument
+ /// constructor, and needs to get all of its confiuration data from
+ /// another (most
+ /// usually to have an independant copy of said configuration data).
+ ///
- /// The
- /// property is
- /// usable if the AOP framework is configured to expose the current proxy
- /// (not the default)... it returns the AOP proxy in use. Target objects or
- /// advice can use this to make advised calls. They can also use it to find
- /// advice configuration.
- ///
- ///
- /// The AOP framework does not expose proxies by default, as there is a
- /// performance cost in doing so.
- ///
- ///
- /// The functionality in this class might be used by a target object that
- /// needed access to resources on the invocation. However, this approach
- /// should not be used when there is a reasonable alternative, as it makes
- /// application code dependent on usage under AOP and the Spring.NET AOP
- /// framework.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: AopContext.cs,v 1.7 2006/09/15 21:25:16 markpollack Exp $
- public sealed class AopContext
- {
- private const string CURRENTPROXY_SLOTNAME = "AopContext.CurrentProxySlotName";
-
- ///
- /// The AOP proxy associated with this thread.
- ///
- ///
- ///
- /// Will be unless the
- /// property
- /// on the controlling proxy has been set to .
- ///
- ///
- /// The default value for the
- /// property
- /// is , for performance reasons.
- ///
- ///
- private static Stack ProxyStack
- {
- get
- {
- Stack proxyStack = LogicalThreadContext.GetData(CURRENTPROXY_SLOTNAME) as Stack;
- if (proxyStack == null)
- {
- proxyStack = new Stack();
- LogicalThreadContext.SetData(CURRENTPROXY_SLOTNAME, proxyStack);
- }
- return proxyStack;
- }
- }
-
- ///
- /// Gets the current AOP proxy.
- ///
- ///
- /// If the proxy stack is empty.
- ///
- public static object CurrentProxy
- {
- get
- {
- if (ProxyStack.Count == 0)
- {
- throw new AopConfigException(
- "Cannot find proxy: Set the 'ExposeProxy' property " +
- "to 'true' on IAdvised to make it available.");
- }
- return ProxyStack.Peek();
- }
- }
-
- ///
- /// Sets the current proxy by pushing it to the proxy stack.
- ///
- ///
- ///
- /// This method is for internal use only, and should never be called by
- /// client code.
- ///
- ///
- ///
- /// The proxy to put on top of the proxy stack.
- ///
- public static void PushProxy(object proxy)
- {
- ProxyStack.Push(proxy);
- }
-
- ///
- /// Removes the current proxy from the proxy stack, making the previous
- /// proxy (if any) the current proxy.
- ///
- ///
- ///
- /// This method is for internal use only, and should never be called by
- /// client code.
- ///
- ///
- ///
- /// If the proxy stack is empty.
- ///
- public static void PopProxy()
- {
- if (ProxyStack.Count == 0)
- {
- throw new AopConfigException(
- "Proxy stack empty. Always call 'PushProxy' before 'PopProxy'.");
- }
- ProxyStack.Pop();
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
+ /// The
+ /// property is
+ /// usable if the AOP framework is configured to expose the current proxy
+ /// (not the default)... it returns the AOP proxy in use. Target objects or
+ /// advice can use this to make advised calls. They can also use it to find
+ /// advice configuration.
+ ///
+ ///
+ /// The AOP framework does not expose proxies by default, as there is a
+ /// performance cost in doing so.
+ ///
+ ///
+ /// The functionality in this class might be used by a target object that
+ /// needed access to resources on the invocation. However, this approach
+ /// should not be used when there is a reasonable alternative, as it makes
+ /// application code dependent on usage under AOP and the Spring.NET AOP
+ /// framework.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public sealed class AopContext
+ {
+ private const string CURRENTPROXY_SLOTNAME = "AopContext.CurrentProxySlotName";
+
+ ///
+ /// The AOP proxy associated with this thread.
+ ///
+ ///
+ ///
+ /// Will be unless the
+ /// property
+ /// on the controlling proxy has been set to .
+ ///
+ ///
+ /// The default value for the
+ /// property
+ /// is , for performance reasons.
+ ///
+ ///
+ private static Stack ProxyStack
+ {
+ get
+ {
+ Stack proxyStack = LogicalThreadContext.GetData(CURRENTPROXY_SLOTNAME) as Stack;
+ if (proxyStack == null)
+ {
+ proxyStack = new Stack();
+ LogicalThreadContext.SetData(CURRENTPROXY_SLOTNAME, proxyStack);
+ }
+ return proxyStack;
+ }
+ }
+
+ ///
+ /// Gets the current AOP proxy.
+ ///
+ ///
+ /// If the proxy stack is empty.
+ ///
+ public static object CurrentProxy
+ {
+ get
+ {
+ if (ProxyStack.Count == 0)
+ {
+ throw new AopConfigException(
+ "Cannot find proxy: Set the 'ExposeProxy' property " +
+ "to 'true' on IAdvised to make it available.");
+ }
+ return ProxyStack.Peek();
+ }
+ }
+
+ ///
+ /// Sets the current proxy by pushing it to the proxy stack.
+ ///
+ ///
+ ///
+ /// This method is for internal use only, and should never be called by
+ /// client code.
+ ///
+ ///
+ ///
+ /// The proxy to put on top of the proxy stack.
+ ///
+ public static void PushProxy(object proxy)
+ {
+ ProxyStack.Push(proxy);
+ }
+
+ ///
+ /// Removes the current proxy from the proxy stack, making the previous
+ /// proxy (if any) the current proxy.
+ ///
+ ///
+ ///
+ /// This method is for internal use only, and should never be called by
+ /// client code.
+ ///
+ ///
+ ///
+ /// If the proxy stack is empty.
+ ///
+ public static void PopProxy()
+ {
+ if (ProxyStack.Count == 0)
+ {
+ throw new AopConfigException(
+ "Proxy stack empty. Always call 'PushProxy' before 'PopProxy'.");
+ }
+ ProxyStack.Pop();
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
- /// Not intended to be used directly by applications.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Aleksandar Seovic (.NET)
- /// $Id: AopUtils.cs,v 1.4 2007/10/10 18:07:38 markpollack Exp $
- public sealed class AopUtils
- {
-
- // This is a leaky abstraction as we have hardcoded known IAopProxyFactory implementations.
- private const string COMPOSITION_PROXY_TYPE_NAME = "CompositionAopProxy";
-
- private const string DECORATOR_PROXY_TYPE_NAME = "DecoratorAopProxy";
-
- ///
- /// Is the supplied an AOP proxy?
- ///
- ///
- /// Return whether the given object is either
- /// a composition-based proxy or a decorator-based proxy.
- ///
- /// The instance to be checked.
- ///
- /// if the supplied is
- /// an AOP proxy.
- ///
- public static bool IsAopProxy(object instance)
- {
- return IsCompositionAopProxy(instance) || IsDecoratorAopProxy(instance);
- }
-
- ///
- /// Is the supplied a composition-based AOP proxy?
- ///
- /// The instance to be checked.
- ///
- /// if the supplied is
- /// an composition-based AOP proxy.
- ///
- public static bool IsCompositionAopProxy(Object instance)
- {
- return ((instance != null) && instance.GetType().FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME));
- }
-
- ///
- /// Is the supplied a decorator-based AOP proxy?
- ///
- /// The instance to be checked.
- ///
- /// if the supplied is
- /// an decorator-based AOP proxy.
- ///
- public static bool IsDecoratorAopProxy(Object instance)
- {
- return ((instance != null) && instance.GetType().FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME));
- }
-
- ///
- /// Gets all of the interfaces that the of the
- /// supplied implements.
- ///
- ///
- ///
- /// This includes interfaces implemented by any superclasses.
- ///
- ///
- ///
- /// The object to analyse for interfaces.
- ///
- ///
- /// All of the interfaces that the of the
- /// supplied implements; or an empty
- /// array if the supplied is
- /// .
- ///
- public static Type[] GetAllInterfaces(object instance)
- {
- if (instance != null)
- {
- ISet interfaces = new HybridSet();
- Type type = instance.GetType();
- do
- {
- Type[] ifcs = type.GetInterfaces();
- foreach (Type ifc in ifcs)
- {
- interfaces.Add(ifc);
- }
- type = type.BaseType;
- } while (type != null);
- if (interfaces.Count > 0)
- {
- Type[] types = new Type[interfaces.Count];
- interfaces.CopyTo(types, 0);
- return types;
- }
- }
- return Type.EmptyTypes;
- }
-
- ///
- /// Can the supplied apply at all on the
- /// supplied ?
- ///
- ///
- ///
- /// This is an important test as it can be used to optimize out a
- /// pointcut for a class.
- ///
- ///
- /// Invoking this method with a that is
- /// an interface type will always yield a
- /// return value.
- ///
- ///
- /// The pointcut being tested.
- /// The class being tested.
- ///
- /// The interfaces being proxied. If , all
- /// methods on a class may be proxied.
- ///
- ///
- /// if the pointcut can apply on any method.
- ///
- public static bool CanApply(
- IPointcut pointcut, Type targetType, Type[] proxyInterfaces)
- {
- if (!pointcut.TypeFilter.Matches(targetType))
- {
- return false;
- }
-
- // It may apply to the class
- // Check whether it can apply on any method
- // Checks public methods, including inherited methods
- MethodInfo[] methods = targetType.GetMethods();
- for (int i = 0; i < methods.Length; ++i)
- {
- MethodInfo m = methods[i];
- // If we're looking only at interfaces and this method
- // isn't on any of them, skip it
- if (proxyInterfaces != null
- && !ReflectionUtils.MethodIsOnOneOfTheseInterfaces(m, proxyInterfaces))
- {
- continue;
- }
- if (pointcut.MethodMatcher.Matches(m, targetType))
- {
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Can the supplied apply at all on the
- /// supplied ?
- ///
- ///
- ///
- /// This is an important test as it can be used to optimize out an
- /// advisor for a class.
- ///
- ///
- /// The advisor to check.
- /// The class being tested.
- ///
- /// The interfaces being proxied. If , all
- /// methods on a class may be proxied.
- ///
- ///
- /// if the advisor can apply on any method.
- ///
- public static bool CanApply(
- IAdvisor advisor, Type targetType, Type[] proxyInterfaces)
- {
- if (advisor is IIntroductionAdvisor)
- {
- return ((IIntroductionAdvisor) advisor).TypeFilter.Matches(targetType);
- }
- else if (advisor is IPointcutAdvisor)
- {
- IPointcutAdvisor pca = (IPointcutAdvisor) advisor;
- return CanApply(pca.Pointcut, targetType, proxyInterfaces);
- }
- // no pointcut specified so assume it applies...
- return true;
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly
- /// visible constructors.
- ///
+ /// Not intended to be used directly by applications.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Aleksandar Seovic (.NET)
+ public sealed class AopUtils
+ {
+
+ // This is a leaky abstraction as we have hardcoded known IAopProxyFactory implementations.
+ private const string COMPOSITION_PROXY_TYPE_NAME = "CompositionAopProxy";
+
+ private const string DECORATOR_PROXY_TYPE_NAME = "DecoratorAopProxy";
+
+ ///
+ /// Is the supplied an AOP proxy?
+ ///
+ ///
+ /// Return whether the given object is either
+ /// a composition-based proxy or a decorator-based proxy.
+ ///
+ /// The instance to be checked.
+ ///
+ /// if the supplied is
+ /// an AOP proxy.
+ ///
+ public static bool IsAopProxy(object instance)
+ {
+ return IsCompositionAopProxy(instance) || IsDecoratorAopProxy(instance);
+ }
+
+ ///
+ /// Is the supplied a composition-based AOP proxy?
+ ///
+ /// The instance to be checked.
+ ///
+ /// if the supplied is
+ /// an composition-based AOP proxy.
+ ///
+ public static bool IsCompositionAopProxy(Object instance)
+ {
+ return ((instance != null) && instance.GetType().FullName.StartsWith(COMPOSITION_PROXY_TYPE_NAME));
+ }
+
+ ///
+ /// Is the supplied a decorator-based AOP proxy?
+ ///
+ /// The instance to be checked.
+ ///
+ /// if the supplied is
+ /// an decorator-based AOP proxy.
+ ///
+ public static bool IsDecoratorAopProxy(Object instance)
+ {
+ return ((instance != null) && instance.GetType().FullName.StartsWith(DECORATOR_PROXY_TYPE_NAME));
+ }
+
+ ///
+ /// Gets all of the interfaces that the of the
+ /// supplied implements.
+ ///
+ ///
+ ///
+ /// This includes interfaces implemented by any superclasses.
+ ///
+ ///
+ ///
+ /// The object to analyse for interfaces.
+ ///
+ ///
+ /// All of the interfaces that the of the
+ /// supplied implements; or an empty
+ /// array if the supplied is
+ /// .
+ ///
+ public static Type[] GetAllInterfaces(object instance)
+ {
+ if (instance != null)
+ {
+ ISet interfaces = new HybridSet();
+ Type type = instance.GetType();
+ do
+ {
+ Type[] ifcs = type.GetInterfaces();
+ foreach (Type ifc in ifcs)
+ {
+ interfaces.Add(ifc);
+ }
+ type = type.BaseType;
+ } while (type != null);
+ if (interfaces.Count > 0)
+ {
+ Type[] types = new Type[interfaces.Count];
+ interfaces.CopyTo(types, 0);
+ return types;
+ }
+ }
+ return Type.EmptyTypes;
+ }
+
+ ///
+ /// Can the supplied apply at all on the
+ /// supplied ?
+ ///
+ ///
+ ///
+ /// This is an important test as it can be used to optimize out a
+ /// pointcut for a class.
+ ///
+ ///
+ /// Invoking this method with a that is
+ /// an interface type will always yield a
+ /// return value.
+ ///
+ ///
+ /// The pointcut being tested.
+ /// The class being tested.
+ ///
+ /// The interfaces being proxied. If , all
+ /// methods on a class may be proxied.
+ ///
+ ///
+ /// if the pointcut can apply on any method.
+ ///
+ public static bool CanApply(
+ IPointcut pointcut, Type targetType, Type[] proxyInterfaces)
+ {
+ if (!pointcut.TypeFilter.Matches(targetType))
+ {
+ return false;
+ }
+
+ // It may apply to the class
+ // Check whether it can apply on any method
+ // Checks public methods, including inherited methods
+ MethodInfo[] methods = targetType.GetMethods();
+ for (int i = 0; i < methods.Length; ++i)
+ {
+ MethodInfo m = methods[i];
+ // If we're looking only at interfaces and this method
+ // isn't on any of them, skip it
+ if (proxyInterfaces != null
+ && !ReflectionUtils.MethodIsOnOneOfTheseInterfaces(m, proxyInterfaces))
+ {
+ continue;
+ }
+ if (pointcut.MethodMatcher.Matches(m, targetType))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Can the supplied apply at all on the
+ /// supplied ?
+ ///
+ ///
+ ///
+ /// This is an important test as it can be used to optimize out an
+ /// advisor for a class.
+ ///
+ ///
+ /// The advisor to check.
+ /// The class being tested.
+ ///
+ /// The interfaces being proxied. If , all
+ /// methods on a class may be proxied.
+ ///
+ ///
+ /// if the advisor can apply on any method.
+ ///
+ public static bool CanApply(
+ IAdvisor advisor, Type targetType, Type[] proxyInterfaces)
+ {
+ if (advisor is IIntroductionAdvisor)
+ {
+ return ((IIntroductionAdvisor) advisor).TypeFilter.Matches(targetType);
+ }
+ else if (advisor is IPointcutAdvisor)
+ {
+ IPointcutAdvisor pca = (IPointcutAdvisor) advisor;
+ return CanApply(pca.Pointcut, targetType, proxyInterfaces);
+ }
+ // no pointcut specified so assume it applies...
+ return true;
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly
+ /// visible constructors.
+ ///
Subclasses must implement the abstract findCandidateAdvisors() method
- /// to return a list of Advisors applying to any object. Subclasses can also
- /// override the inherited shouldSkip() method to exclude certain objects
- /// from autoproxying, but they must be careful to invoke the shouldSkip()
- /// method of this class, which tries to avoid circular reference problems
- /// and infinite loops.
- ///
Advisors or advices requiring ordering should implement the Ordered interface.
- /// This class sorts advisors by Ordered order value. Advisors that don't implement
- /// the Ordered interface will be considered to be unordered, and will appear
- /// at the end of the advisor chain in undefined order.
- ///
- ///
- /// Rod Johnson
- /// Adhari C Mahendra (.NET)
- /// $Id: AbstractAdvisorAutoProxyCreator.cs,v 1.5 2007/08/22 08:49:08 markpollack Exp $
- public abstract class AbstractAdvisorAutoProxyCreator : AbstractAutoProxyCreator
- {
- ///
- /// We override this method to ensure that all candidate advisors are materialized
- /// under a stack trace including this object. Otherwise, the dependencies won't
- /// be apparent to the circular-reference prevention strategy in AbstractObjectFactory.
- ///
- public override IObjectFactory ObjectFactory
- {
- //TODO investigate override...
- set
- {
- base.ObjectFactory = value;
- if (!(value is IConfigurableListableObjectFactory))
- {
- throw new InvalidOperationException(
- "Can not use AdvisorAutoProxyCreator without a ConfigurableListableObjectFactory");
- }
- }
- get { return base.ObjectFactory; }
- }
-
- ///
- /// Return whether the given object is to be proxied, what additional
- /// advices (e.g. AOP Alliance interceptors) and advisors to apply.
- ///
- /// the new object instance
- /// the name of the object
- /// targetSource returned by TargetSource property:
- /// may be ignored. Will be null unless a custom target source is in use.
- ///
- /// an array of additional interceptors for the particular object;
- /// or an empty array if no additional interceptors but just the common ones;
- /// or null if no proxy at all, not even with the common interceptors.
- ///
- ///
- ///
The previous name of this method was "GetInterceptorAndAdvisorForObject".
- /// It has been renamed in the course of general terminology clarification
- /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of
- /// Advice, so the generic Advice term is preferred now.
- ///
The third parameter, customTargetSource, is new in Spring 1.1;
- /// add it to existing implementations of this method.
Subclasses must implement the abstract findCandidateAdvisors() method
+ /// to return a list of Advisors applying to any object. Subclasses can also
+ /// override the inherited shouldSkip() method to exclude certain objects
+ /// from autoproxying, but they must be careful to invoke the shouldSkip()
+ /// method of this class, which tries to avoid circular reference problems
+ /// and infinite loops.
+ ///
Advisors or advices requiring ordering should implement the Ordered interface.
+ /// This class sorts advisors by Ordered order value. Advisors that don't implement
+ /// the Ordered interface will be considered to be unordered, and will appear
+ /// at the end of the advisor chain in undefined order.
+ ///
+ ///
+ /// Rod Johnson
+ /// Adhari C Mahendra (.NET)
+ public abstract class AbstractAdvisorAutoProxyCreator : AbstractAutoProxyCreator
+ {
+ ///
+ /// We override this method to ensure that all candidate advisors are materialized
+ /// under a stack trace including this object. Otherwise, the dependencies won't
+ /// be apparent to the circular-reference prevention strategy in AbstractObjectFactory.
+ ///
+ public override IObjectFactory ObjectFactory
+ {
+ //TODO investigate override...
+ set
+ {
+ base.ObjectFactory = value;
+ if (!(value is IConfigurableListableObjectFactory))
+ {
+ throw new InvalidOperationException(
+ "Can not use AdvisorAutoProxyCreator without a ConfigurableListableObjectFactory");
+ }
+ }
+ get { return base.ObjectFactory; }
+ }
+
+ ///
+ /// Return whether the given object is to be proxied, what additional
+ /// advices (e.g. AOP Alliance interceptors) and advisors to apply.
+ ///
+ /// the new object instance
+ /// the name of the object
+ /// targetSource returned by TargetSource property:
+ /// may be ignored. Will be null unless a custom target source is in use.
+ ///
+ /// an array of additional interceptors for the particular object;
+ /// or an empty array if no additional interceptors but just the common ones;
+ /// or null if no proxy at all, not even with the common interceptors.
+ ///
+ ///
+ ///
The previous name of this method was "GetInterceptorAndAdvisorForObject".
+ /// It has been renamed in the course of general terminology clarification
+ /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of
+ /// Advice, so the generic Advice term is preferred now.
+ ///
The third parameter, customTargetSource, is new in Spring 1.1;
+ /// add it to existing implementations of this method.
This class distinguishes between "common" interceptors: shared for all proxies it
- /// creates, and "specific" interceptors: unique per object instance. There need not
- /// be any common interceptors. If there are, they are set using the interceptorNames
- /// property. As with ProxyFactoryObject, interceptors names in the current factory
- /// are used rather than object references to allow correct handling of prototype
- /// advisors and interceptors: for example, to support stateful mixins.
- /// Any advice type is supported for "interceptorNames" entries.
- ///
Such autoproxying is particularly useful if there's a large number of objects that need
- /// to be wrapped with similar proxies, i.e. delegating to the same interceptors.
- /// Instead of x repetitive proxy definitions for x target objects, you can register
- /// one single such post processor with the object factory to achieve the same effect.
- ///
Subclasses can apply any strategy to decide if a object is to be proxied,
- /// e.g. by type, by name, by definition details, etc. They can also return
- /// additional interceptors that should just be applied to the specific object
- /// instance. The default concrete implementation is ObjectNameAutoProxyCreator,
- /// identifying the objects to be proxied via a list of object names.
- ///
Any number of TargetSourceCreator implementations can be used with any subclass,
- /// to create a custom target source - for example, to pool prototype objects.
- /// Autoproxying will occur even if there is no advice if a TargetSourceCreator specifies
- /// a custom TargetSource. If there are no TargetSourceCreators set, or if none matches,
- /// a SingletonTargetSource will be used by default to wrap the object to be autoproxied.
- ///
- /// Juergen Hoeller
- /// Rod Johnson
- /// Adhari C Mahendra (.NET)
- ///
- ///
- /// $Id: AbstractAutoProxyCreator.cs,v 1.15 2008/03/03 09:28:49 bbaia Exp $
- public abstract class AbstractAutoProxyCreator : ProxyConfig, IInstantiationAwareObjectPostProcessor, IObjectFactoryAware, IOrdered
- {
- #region Protected Fields
-
- ///
- /// The logger for this class hierarchy.
- ///
- protected readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
-
- ///
- /// Convenience constant for subclasses: Return value for "do not proxy".
- ///
- protected static readonly object[] DO_NOT_PROXY = null;
-
- ///
- /// Convenience constant for subclasses: Return value for
- /// "proxy without additional interceptors, just the common ones".
- ///
- protected static readonly object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new object[0];
-
- #endregion
-
- #region Private Fields
-
- ///
- /// Default value is same as non-ordered
- ///
- private int order = int.MaxValue;
-
- ///
- /// Default is global AdvisorAdapterRegistry
- ///
- private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance;
-
-
- ///
- ///
- ///
- private bool freezeProxy = false;
-
- ///
- /// Names of common interceptors.
- /// We must use object name rather than object references
- /// to handle prototype advisors/interceptors.
- /// Default is the empty array: no common interceptors.
- ///
- private string[] interceptorNames = new string[0];
-
- private bool applyCommonInterceptorsFirst = true;
- private IList customTargetSourceCreators = new ArrayList();
- private IObjectFactory owningObjectFactory;
-
- ///
- /// Set of object type + name strings, referring to all objects that this auto-proxy
- /// creator created a custom TargetSource for. Used to detect own pre-built proxies
- /// (from "PostProcessBeforeInstantiation") in the "PostProcessAfterInitialization" method.
- ///
- private ISet targetSourcedObjects = new SynchronizedSet(new HashedSet());
-
- private ISet advisedObjects = new SynchronizedSet(new HashedSet());
-
- private ISet nonAdvisedObjects = new SynchronizedSet(new HashedSet());
-
- #endregion
-
- #region Properties
-
- ///
- /// Sets the AdvisorAdapterRegistry to use.
- ///
- ///
- /// Default is the global AdvisorAdapterRegistry.
- ///
- public IAdvisorAdapterRegistry AdvisorAdapterRegistry
- {
- set { advisorAdapterRegistry = value; }
- }
-
- ///
- /// Sets custom TargetSourceCreators to be applied in this order.
- ///
- ///
- ///
- /// If the list is empty, or they all return null, a SingletonTargetSource
- /// will be created.
- ///
- ///
- /// TargetSourceCreators can only be invoked if this post processor is used
- /// in a IObjectFactory, and its ObjectFactoryAware callback is used.
- ///
- ///
- public IList CustomTargetSourceCreators
- {
- set { customTargetSourceCreators = value; }
- }
-
- ///
- /// Sets the common interceptors, a list of ,
- /// and introduction object names.
- ///
- ///
- ///
- /// If this property isn't set, there will be zero common interceptors.
- /// This is perfectly valid, if "specific" interceptors such as
- /// matching Advisors are all we want.
- ///
- ///
- ///
- /// The list of ,
- /// and introduction object names.
- ///
- ///
- ///
- public string[] InterceptorNames
- {
- set { interceptorNames = value; }
- }
-
- ///
- /// Sets whether the common interceptors should be applied before
- /// object-specific ones.
- ///
- ///
- /// Default is true; else, object-specific interceptors will get applied first.
- ///
- public bool ApplyCommonInterceptorsFirst
- {
- set { applyCommonInterceptorsFirst = value; }
- }
-
- ///
- /// Set whether or not the proxy should be frozen, preventing advice
- /// from being added to it once it is created.
- ///
- ///
- ///
Overridden from the super class to prevent the proxy configuration
- /// from being frozen before the proxy is created. The default is not frozen.
- ///
- ///
- public override bool IsFrozen
- {
- get { return freezeProxy; }
- set { this.freezeProxy = value; }
- }
-
- #endregion
-
- #region IObjectPostProcessor Members
-
- ///
- /// Create a proxy with the configured interceptors if the object is
- /// identified as one to proxy by the subclass.
- ///
- public virtual object PostProcessAfterInitialization(object obj, string objectName)
- {
- if (targetSourcedObjects.Contains(objectName))
- {
- return obj;
- }
-
- object cacheKey = GetCacheKey(obj.GetType(), objectName);
- if (nonAdvisedObjects.Contains(cacheKey))
- {
- return obj;
- }
- if (IsInfrastructureType(obj.GetType(), objectName) || ShouldSkip(obj.GetType(), objectName))
- {
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug(string.Format("Did not attempt to autoproxy infrastructure type [{0}]", obj.GetType().ToString()));
- }
-
- #endregion
-
- nonAdvisedObjects.Add(cacheKey);
- return obj;
- }
-
- //ITargetSource targetSource = GetCustomTargetSource(obj.GetType(), objectName);
- object[] specificInterceptors;
- if (RemotingServices.IsTransparentProxy(obj))
- {
- specificInterceptors = GetAdvicesAndAdvisorsForObject(ObjectFactory.GetType(objectName), objectName, null);
- }
- else
- {
- specificInterceptors = GetAdvicesAndAdvisorsForObject(obj.GetType(), objectName, null);
- }
-
-
- // proxy if we have advice or if a TargetSourceCreator wants to do some
- // fancy stuff such as pooling
- if (specificInterceptors != DO_NOT_PROXY)
- {
- advisedObjects.Add(cacheKey);
- return CreateProxy(obj.GetType(), objectName, specificInterceptors, new SingletonTargetSource(obj));
- }
- nonAdvisedObjects.Add(cacheKey);
- return obj;
- }
-
- ///
- /// No-op for before initialization.
- ///
- /// The obj.
- /// The name.
- ///
- public virtual object PostProcessBeforeInitialization(object obj, string name)
- {
- return obj;
- }
-
- #endregion
-
- #region IObjectFactoryAware Members
-
- ///
- /// Callback that supplies the owning factory to an object instance.
- ///
- ///
- /// Owning
- /// (may not be ). The object can immediately
- /// call methods on the factory.
- ///
- ///
- ///
- /// Invoked after population of normal object properties but before an init
- /// callback like 's
- ///
- /// method or a custom init-method.
- ///
- ///
- ///
- /// In case of initialization errors.
- ///
- public virtual IObjectFactory ObjectFactory
- {
- get { return owningObjectFactory; }
- set { owningObjectFactory = value; }
- }
-
- #endregion
-
- #region IOrdered Members
-
- ///
- /// Propery Order
- ///
- ///
- /// Ordering which will apply to this class's implementation
- /// of Ordered, used when applying multiple ObjectPostProcessors.
- /// Default value is int.MaxValue, meaning that it's non-ordered.
- ///
- public virtual int Order
- {
- get { return order; }
- set { order = value; }
- }
-
- #endregion
-
- #region Protected Methods
-
- ///
- /// Subclasses should override this method to return true if this
- /// object should not be considered for autoproxying by this post processor.
- /// Sometimes we need to be able to avoid this happening if it will lead to
- /// a circular reference. This implementation returns true.
- ///
- /// the type of the object
- /// the name of the object
- /// if remarkable to skip
- protected virtual bool ShouldSkip(Type objectType, string objectName)
- {
- return false;
- }
-
- ///
- /// Subclasses may choose to implement this: for example,
- /// to change the interfaces exposed
- ///
- ///
- /// ProxyFactory that will be used to create the proxy immediably after this method returns.
- ///
- protected virtual void CustomizeProxyFactory(ProxyFactory pf)
- {
- // This implementation does nothing
- }
-
- ///
- /// Determines whether the object is an infrastructure type,
- /// IAdvisor, IAdvice, IAdvisors or AbstractAutoProxyCreator
- ///
- /// The object type to compare
- /// The name of the object
- ///
- /// true if [is infrastructure type] [the specified obj]; otherwise, false.
- ///
- protected virtual bool IsInfrastructureType(Type type, String name)
- {
- return typeof (IAdvisor).IsAssignableFrom(type)
- || typeof (IAdvice).IsAssignableFrom(type)
- || typeof (IAdvisors).IsAssignableFrom(type)
- || typeof (AbstractAutoProxyCreator).IsAssignableFrom(type);
- }
-
-
- ///
- /// Create a target source for object instances. Uses any
- /// TargetSourceCreators if set. Returns null if no Custom TargetSource
- /// should be used.
- /// This implementation uses the customTargetSourceCreators property.
- /// Subclasses can override this method to use a different mechanism.
- ///
- /// the type of the object to create a TargetSource for
- /// the name of the object
- /// a TargetSource for this object
- protected virtual ITargetSource GetCustomTargetSource(Type objectType, string name)
- {
- // We can't create fancy target sources for directly registered singletons.
- if (customTargetSourceCreators != null &&
- owningObjectFactory != null && owningObjectFactory.ContainsObject(name))
- {
- for (int i = 0; i < customTargetSourceCreators.Count; i++)
- {
- ITargetSourceCreator tsc = (ITargetSourceCreator) customTargetSourceCreators[i];
- ITargetSource ts = tsc.GetTargetSource(objectType, name, owningObjectFactory);
- if (ts != null)
- {
- // found a match
- if (logger.IsInfoEnabled)
- {
- logger.Info(string.Format("TargetSourceCreator [{0} found custom TargetSource for object with objectName '{1}'", tsc, name));
- }
- return ts;
- }
- }
- }
-
- // no custom TargetSource found
- return null;
- }
-
- ///
- /// Return whether the given object is to be proxied, what additional
- /// advices (e.g. AOP Alliance interceptors) and advisors to apply.
- ///
- ///
- ///
The previous name of this method was "GetInterceptorAndAdvisorForObject".
- /// It has been renamed in the course of general terminology clarification
- /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of
- /// Advice, so the generic Advice term is preferred now.
- ///
The third parameter, customTargetSource, is new in Spring 1.1;
- /// add it to existing implementations of this method.
This class distinguishes between "common" interceptors: shared for all proxies it
+ /// creates, and "specific" interceptors: unique per object instance. There need not
+ /// be any common interceptors. If there are, they are set using the interceptorNames
+ /// property. As with ProxyFactoryObject, interceptors names in the current factory
+ /// are used rather than object references to allow correct handling of prototype
+ /// advisors and interceptors: for example, to support stateful mixins.
+ /// Any advice type is supported for "interceptorNames" entries.
+ ///
Such autoproxying is particularly useful if there's a large number of objects that need
+ /// to be wrapped with similar proxies, i.e. delegating to the same interceptors.
+ /// Instead of x repetitive proxy definitions for x target objects, you can register
+ /// one single such post processor with the object factory to achieve the same effect.
+ ///
Subclasses can apply any strategy to decide if a object is to be proxied,
+ /// e.g. by type, by name, by definition details, etc. They can also return
+ /// additional interceptors that should just be applied to the specific object
+ /// instance. The default concrete implementation is ObjectNameAutoProxyCreator,
+ /// identifying the objects to be proxied via a list of object names.
+ ///
Any number of TargetSourceCreator implementations can be used with any subclass,
+ /// to create a custom target source - for example, to pool prototype objects.
+ /// Autoproxying will occur even if there is no advice if a TargetSourceCreator specifies
+ /// a custom TargetSource. If there are no TargetSourceCreators set, or if none matches,
+ /// a SingletonTargetSource will be used by default to wrap the object to be autoproxied.
+ ///
+ /// Juergen Hoeller
+ /// Rod Johnson
+ /// Adhari C Mahendra (.NET)
+ ///
+ ///
+ public abstract class AbstractAutoProxyCreator : ProxyConfig, IInstantiationAwareObjectPostProcessor, IObjectFactoryAware, IOrdered
+ {
+ #region Protected Fields
+
+ ///
+ /// The logger for this class hierarchy.
+ ///
+ protected readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Convenience constant for subclasses: Return value for "do not proxy".
+ ///
+ protected static readonly object[] DO_NOT_PROXY = null;
+
+ ///
+ /// Convenience constant for subclasses: Return value for
+ /// "proxy without additional interceptors, just the common ones".
+ ///
+ protected static readonly object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new object[0];
+
+ #endregion
+
+ #region Private Fields
+
+ ///
+ /// Default value is same as non-ordered
+ ///
+ private int order = int.MaxValue;
+
+ ///
+ /// Default is global AdvisorAdapterRegistry
+ ///
+ private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance;
+
+
+ ///
+ ///
+ ///
+ private bool freezeProxy = false;
+
+ ///
+ /// Names of common interceptors.
+ /// We must use object name rather than object references
+ /// to handle prototype advisors/interceptors.
+ /// Default is the empty array: no common interceptors.
+ ///
+ private string[] interceptorNames = new string[0];
+
+ private bool applyCommonInterceptorsFirst = true;
+ private IList customTargetSourceCreators = new ArrayList();
+ private IObjectFactory owningObjectFactory;
+
+ ///
+ /// Set of object type + name strings, referring to all objects that this auto-proxy
+ /// creator created a custom TargetSource for. Used to detect own pre-built proxies
+ /// (from "PostProcessBeforeInstantiation") in the "PostProcessAfterInitialization" method.
+ ///
+ private ISet targetSourcedObjects = new SynchronizedSet(new HashedSet());
+
+ private ISet advisedObjects = new SynchronizedSet(new HashedSet());
+
+ private ISet nonAdvisedObjects = new SynchronizedSet(new HashedSet());
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Sets the AdvisorAdapterRegistry to use.
+ ///
+ ///
+ /// Default is the global AdvisorAdapterRegistry.
+ ///
+ public IAdvisorAdapterRegistry AdvisorAdapterRegistry
+ {
+ set { advisorAdapterRegistry = value; }
+ }
+
+ ///
+ /// Sets custom TargetSourceCreators to be applied in this order.
+ ///
+ ///
+ ///
+ /// If the list is empty, or they all return null, a SingletonTargetSource
+ /// will be created.
+ ///
+ ///
+ /// TargetSourceCreators can only be invoked if this post processor is used
+ /// in a IObjectFactory, and its ObjectFactoryAware callback is used.
+ ///
+ ///
+ public IList CustomTargetSourceCreators
+ {
+ set { customTargetSourceCreators = value; }
+ }
+
+ ///
+ /// Sets the common interceptors, a list of ,
+ /// and introduction object names.
+ ///
+ ///
+ ///
+ /// If this property isn't set, there will be zero common interceptors.
+ /// This is perfectly valid, if "specific" interceptors such as
+ /// matching Advisors are all we want.
+ ///
+ ///
+ ///
+ /// The list of ,
+ /// and introduction object names.
+ ///
+ ///
+ ///
+ public string[] InterceptorNames
+ {
+ set { interceptorNames = value; }
+ }
+
+ ///
+ /// Sets whether the common interceptors should be applied before
+ /// object-specific ones.
+ ///
+ ///
+ /// Default is true; else, object-specific interceptors will get applied first.
+ ///
+ public bool ApplyCommonInterceptorsFirst
+ {
+ set { applyCommonInterceptorsFirst = value; }
+ }
+
+ ///
+ /// Set whether or not the proxy should be frozen, preventing advice
+ /// from being added to it once it is created.
+ ///
+ ///
+ ///
Overridden from the super class to prevent the proxy configuration
+ /// from being frozen before the proxy is created. The default is not frozen.
+ ///
+ ///
+ public override bool IsFrozen
+ {
+ get { return freezeProxy; }
+ set { this.freezeProxy = value; }
+ }
+
+ #endregion
+
+ #region IObjectPostProcessor Members
+
+ ///
+ /// Create a proxy with the configured interceptors if the object is
+ /// identified as one to proxy by the subclass.
+ ///
+ public virtual object PostProcessAfterInitialization(object obj, string objectName)
+ {
+ if (targetSourcedObjects.Contains(objectName))
+ {
+ return obj;
+ }
+
+ object cacheKey = GetCacheKey(obj.GetType(), objectName);
+ if (nonAdvisedObjects.Contains(cacheKey))
+ {
+ return obj;
+ }
+ if (IsInfrastructureType(obj.GetType(), objectName) || ShouldSkip(obj.GetType(), objectName))
+ {
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug(string.Format("Did not attempt to autoproxy infrastructure type [{0}]", obj.GetType().ToString()));
+ }
+
+ #endregion
+
+ nonAdvisedObjects.Add(cacheKey);
+ return obj;
+ }
+
+ //ITargetSource targetSource = GetCustomTargetSource(obj.GetType(), objectName);
+ object[] specificInterceptors;
+ if (RemotingServices.IsTransparentProxy(obj))
+ {
+ specificInterceptors = GetAdvicesAndAdvisorsForObject(ObjectFactory.GetType(objectName), objectName, null);
+ }
+ else
+ {
+ specificInterceptors = GetAdvicesAndAdvisorsForObject(obj.GetType(), objectName, null);
+ }
+
+
+ // proxy if we have advice or if a TargetSourceCreator wants to do some
+ // fancy stuff such as pooling
+ if (specificInterceptors != DO_NOT_PROXY)
+ {
+ advisedObjects.Add(cacheKey);
+ return CreateProxy(obj.GetType(), objectName, specificInterceptors, new SingletonTargetSource(obj));
+ }
+ nonAdvisedObjects.Add(cacheKey);
+ return obj;
+ }
+
+ ///
+ /// No-op for before initialization.
+ ///
+ /// The obj.
+ /// The name.
+ ///
+ public virtual object PostProcessBeforeInitialization(object obj, string name)
+ {
+ return obj;
+ }
+
+ #endregion
+
+ #region IObjectFactoryAware Members
+
+ ///
+ /// Callback that supplies the owning factory to an object instance.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an init
+ /// callback like 's
+ ///
+ /// method or a custom init-method.
+ ///
+ ///
+ ///
+ /// In case of initialization errors.
+ ///
+ public virtual IObjectFactory ObjectFactory
+ {
+ get { return owningObjectFactory; }
+ set { owningObjectFactory = value; }
+ }
+
+ #endregion
+
+ #region IOrdered Members
+
+ ///
+ /// Propery Order
+ ///
+ ///
+ /// Ordering which will apply to this class's implementation
+ /// of Ordered, used when applying multiple ObjectPostProcessors.
+ /// Default value is int.MaxValue, meaning that it's non-ordered.
+ ///
+ public virtual int Order
+ {
+ get { return order; }
+ set { order = value; }
+ }
+
+ #endregion
+
+ #region Protected Methods
+
+ ///
+ /// Subclasses should override this method to return true if this
+ /// object should not be considered for autoproxying by this post processor.
+ /// Sometimes we need to be able to avoid this happening if it will lead to
+ /// a circular reference. This implementation returns true.
+ ///
+ /// the type of the object
+ /// the name of the object
+ /// if remarkable to skip
+ protected virtual bool ShouldSkip(Type objectType, string objectName)
+ {
+ return false;
+ }
+
+ ///
+ /// Subclasses may choose to implement this: for example,
+ /// to change the interfaces exposed
+ ///
+ ///
+ /// ProxyFactory that will be used to create the proxy immediably after this method returns.
+ ///
+ protected virtual void CustomizeProxyFactory(ProxyFactory pf)
+ {
+ // This implementation does nothing
+ }
+
+ ///
+ /// Determines whether the object is an infrastructure type,
+ /// IAdvisor, IAdvice, IAdvisors or AbstractAutoProxyCreator
+ ///
+ /// The object type to compare
+ /// The name of the object
+ ///
+ /// true if [is infrastructure type] [the specified obj]; otherwise, false.
+ ///
+ protected virtual bool IsInfrastructureType(Type type, String name)
+ {
+ return typeof (IAdvisor).IsAssignableFrom(type)
+ || typeof (IAdvice).IsAssignableFrom(type)
+ || typeof (IAdvisors).IsAssignableFrom(type)
+ || typeof (AbstractAutoProxyCreator).IsAssignableFrom(type);
+ }
+
+
+ ///
+ /// Create a target source for object instances. Uses any
+ /// TargetSourceCreators if set. Returns null if no Custom TargetSource
+ /// should be used.
+ /// This implementation uses the customTargetSourceCreators property.
+ /// Subclasses can override this method to use a different mechanism.
+ ///
+ /// the type of the object to create a TargetSource for
+ /// the name of the object
+ /// a TargetSource for this object
+ protected virtual ITargetSource GetCustomTargetSource(Type objectType, string name)
+ {
+ // We can't create fancy target sources for directly registered singletons.
+ if (customTargetSourceCreators != null &&
+ owningObjectFactory != null && owningObjectFactory.ContainsObject(name))
+ {
+ for (int i = 0; i < customTargetSourceCreators.Count; i++)
+ {
+ ITargetSourceCreator tsc = (ITargetSourceCreator) customTargetSourceCreators[i];
+ ITargetSource ts = tsc.GetTargetSource(objectType, name, owningObjectFactory);
+ if (ts != null)
+ {
+ // found a match
+ if (logger.IsInfoEnabled)
+ {
+ logger.Info(string.Format("TargetSourceCreator [{0} found custom TargetSource for object with objectName '{1}'", tsc, name));
+ }
+ return ts;
+ }
+ }
+ }
+
+ // no custom TargetSource found
+ return null;
+ }
+
+ ///
+ /// Return whether the given object is to be proxied, what additional
+ /// advices (e.g. AOP Alliance interceptors) and advisors to apply.
+ ///
+ ///
+ ///
The previous name of this method was "GetInterceptorAndAdvisorForObject".
+ /// It has been renamed in the course of general terminology clarification
+ /// in Spring 1.1. An AOP Alliance Interceptor is just a special form of
+ /// Advice, so the generic Advice term is preferred now.
+ ///
The third parameter, customTargetSource, is new in Spring 1.1;
+ /// add it to existing implementations of this method.
- /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
- /// as well as direct equality. Can be overridden in subclasses.
- ///
+ /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
+ /// as well as direct equality. Can be overridden in subclasses.
+ ///
- /// Creates a decorator-base proxy if one the following is true :
- /// - the "ProxyTargetType" property is set
- /// - no interfaces have been specified
- ///
- ///
- /// In general, specify "ProxyTargetType" to enforce a decorator-based proxy,
- /// or specify one or more interfaces to use a composition-based proxy.
- ///
+ /// Creates a decorator-base proxy if one the following is true :
+ /// - the "ProxyTargetType" property is set
+ /// - no interfaces have been specified
+ ///
+ ///
+ /// In general, specify "ProxyTargetType" to enforce a decorator-based proxy,
+ /// or specify one or more interfaces to use a composition-based proxy.
+ ///
- /// This configuration includes the
- /// s,
- /// s, and (any) proxied interfaces.
- ///
- ///
- /// Any AOP proxy obtained from Spring.NET can be cast to this interface to
- /// allow the manipulation of said proxy's AOP advice.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: IAdvised.cs,v 1.15 2007/10/10 18:07:38 markpollack Exp $
- ///
- [ProxyIgnore]
- public interface IAdvised
- {
- ///
- /// Should proxies obtained from this configuration expose
- /// the AOP proxy to the
- /// class?
- ///
- ///
- ///
- /// This is useful if an advised object needs to call another advised
- /// method on itself. (If it uses the this reference (Me
- /// in Visual Basic.NET), the invocation will not be advised).
- ///
- ///
- bool ExposeProxy { get; }
-
- ///
- /// Gets the
- ///
- /// implementation that will be used to get the interceptor
- /// chains for the advised
- /// .
- ///
- ///
- /// The
- /// implementation that will be used to get the interceptor
- /// chains for the advised
- /// .
- ///
- IAdvisorChainFactory AdvisorChainFactory { get; }
-
- ///
- /// Is the target to be proxied in addition
- /// to any interfaces declared on the proxied ?
- ///
- bool ProxyTargetType { get; }
-
- ///
- /// Is target type attributes, method attributes, method's return type attributes
- /// and method's parameter attributes to be proxied in addition
- /// to any interfaces declared on the proxied ?
- ///
- bool ProxyTargetAttributes { get; }
-
- ///
- /// Returns the collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- ///
- /// Will never return , but may return an
- /// empty array (in the case where no
- /// instances have been applied to
- /// this proxy).
- ///
- ///
- ///
- /// The collection of
- /// instances that have been applied to this proxy.
- ///
- IAdvisor[] Advisors { get; }
-
- ///
- /// Returns the collection of
- /// instances that have been applied to this proxy.
- ///
- ///
- ///
- /// Will never return , but may return an
- /// empty array (in the case where no
- /// instances have been
- /// applied to this proxy).
- ///
- ///
- ///
- /// The collection of
- /// instances that have been applied to this proxy.
- ///
- IIntroductionAdvisor[] Introductions { get; }
-
- ///
- /// Returns the collection of interface s
- /// to be (or that are being) proxied by this proxy.
- ///
- ///
- /// The collection of interface s
- /// to be (or that are being) proxied by this proxy.
- ///
- Type[] Interfaces { get; }
-
- ///
- /// Returns the mapping of the proxied interface
- /// s to their delegates.
- ///
- ///
- /// The mapping of the proxied interface
- /// s to their delegates.
- ///
- IDictionary InterfaceMap { get; }
-
- ///
- /// Is this configuration frozen?
- ///
- ///
- ///
- /// When a config is frozen, no advice changes can be made. This is
- /// useful for optimization, and useful when we don't want callers
- /// to be able to manipulate configuration after casting to
- /// .
- ///
- ///
- bool IsFrozen { get; }
-
- ///
- /// Returns the used by this
- /// object.
- ///
- ///
- /// The used by this
- /// object.
- ///
- ITargetSource TargetSource { get; }
-
- ///
- /// Returns a boolean specifying if this
- /// instance can be serialized.
- ///
- ///
- /// true if this instance can be serialized, false otherwise.
- ///
- bool IsSerializable { get; }
-
- ///
- /// Adds the supplied to the end (or tail)
- /// of the advice (interceptor) chain.
- ///
- ///
- ///
- /// Please be aware that Spring.NET's AOP implementation only supports
- /// method advice (as encapsulated by the
- /// interface).
- ///
- ///
- ///
- /// The to be added.
- ///
- ///
- ///
- void AddAdvice(IAdvice advice);
-
- ///
- /// Adds the supplied to the supplied
- /// in the advice (interceptor) chain.
- ///
- ///
- ///
- /// Please be aware that Spring.NET's AOP implementation only supports
- /// method advice (as encapsulated by the
- /// interface).
- ///
- ///
- ///
- /// The zero (0) indexed position (from the head) at which the
- /// supplied is to be inserted into the
- /// advice (interceptor) chain.
- ///
- ///
- /// The to be added.
- ///
- ///
- ///
- void AddAdvice(int position, IAdvice advice);
-
- ///
- /// Is the supplied (interface)
- /// proxied?
- ///
- ///
- /// The interface to test.
- ///
- ///
- /// if the supplied
- /// (interface) is proxied;
- /// if not or the supplied
- /// is .
- ///
- bool IsInterfaceProxied(Type intf);
-
- ///
- /// Adds the advisors from the supplied
- /// to the list of .
- ///
- ///
- /// The to add advisors from.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- void AddAdvisors(IAdvisors advisors);
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- void AddAdvisor(IAdvisor advisor);
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The index in the
- /// list at which the supplied
- /// is to be inserted.
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- void AddAdvisor(int index, IAdvisor advisor);
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- void AddIntroduction(IIntroductionAdvisor introductionAdvisor);
-
- ///
- /// Adds the supplied to the list
- /// of .
- ///
- ///
- /// The index in the
- /// list at which the supplied
- /// is to be inserted.
- ///
- ///
- /// The to add.
- ///
- ///
- /// If this proxy configuration is frozen and the
- /// cannot be added.
- ///
- void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor);
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the interceptor
- /// (advice) chain for this proxy.
- ///
- ///
- ///
- /// The return value of this method can be used to index into
- /// the
- /// list.
- ///
- ///
- ///
- /// The to search for.
- ///
- ///
- /// The zero (0) based index of this advisor, or -1 if the
- /// supplied is not an advisor for this
- /// proxy.
- ///
- int IndexOf(IAdvisor advisor);
-
- ///
- /// Return the index (0 based) of the supplied
- /// in the introductions
- /// for this proxy.
- ///
- ///
- ///
- /// The return value of this method can be used to index into
- /// the
- /// list.
- ///
+ /// This configuration includes the
+ /// s,
+ /// s, and (any) proxied interfaces.
+ ///
+ ///
+ /// Any AOP proxy obtained from Spring.NET can be cast to this interface to
+ /// allow the manipulation of said proxy's AOP advice.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ [ProxyIgnore]
+ public interface IAdvised
+ {
+ ///
+ /// Should proxies obtained from this configuration expose
+ /// the AOP proxy to the
+ /// class?
+ ///
+ ///
+ ///
+ /// This is useful if an advised object needs to call another advised
+ /// method on itself. (If it uses the this reference (Me
+ /// in Visual Basic.NET), the invocation will not be advised).
+ ///
+ ///
+ bool ExposeProxy { get; }
+
+ ///
+ /// Gets the
+ ///
+ /// implementation that will be used to get the interceptor
+ /// chains for the advised
+ /// .
+ ///
+ ///
+ /// The
+ /// implementation that will be used to get the interceptor
+ /// chains for the advised
+ /// .
+ ///
+ IAdvisorChainFactory AdvisorChainFactory { get; }
+
+ ///
+ /// Is the target to be proxied in addition
+ /// to any interfaces declared on the proxied ?
+ ///
+ bool ProxyTargetType { get; }
+
+ ///
+ /// Is target type attributes, method attributes, method's return type attributes
+ /// and method's parameter attributes to be proxied in addition
+ /// to any interfaces declared on the proxied ?
+ ///
+ bool ProxyTargetAttributes { get; }
+
+ ///
+ /// Returns the collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ ///
+ /// Will never return , but may return an
+ /// empty array (in the case where no
+ /// instances have been applied to
+ /// this proxy).
+ ///
+ ///
+ ///
+ /// The collection of
+ /// instances that have been applied to this proxy.
+ ///
+ IAdvisor[] Advisors { get; }
+
+ ///
+ /// Returns the collection of
+ /// instances that have been applied to this proxy.
+ ///
+ ///
+ ///
+ /// Will never return , but may return an
+ /// empty array (in the case where no
+ /// instances have been
+ /// applied to this proxy).
+ ///
+ ///
+ ///
+ /// The collection of
+ /// instances that have been applied to this proxy.
+ ///
+ IIntroductionAdvisor[] Introductions { get; }
+
+ ///
+ /// Returns the collection of interface s
+ /// to be (or that are being) proxied by this proxy.
+ ///
+ ///
+ /// The collection of interface s
+ /// to be (or that are being) proxied by this proxy.
+ ///
+ Type[] Interfaces { get; }
+
+ ///
+ /// Returns the mapping of the proxied interface
+ /// s to their delegates.
+ ///
+ ///
+ /// The mapping of the proxied interface
+ /// s to their delegates.
+ ///
+ IDictionary InterfaceMap { get; }
+
+ ///
+ /// Is this configuration frozen?
+ ///
+ ///
+ ///
+ /// When a config is frozen, no advice changes can be made. This is
+ /// useful for optimization, and useful when we don't want callers
+ /// to be able to manipulate configuration after casting to
+ /// .
+ ///
+ ///
+ bool IsFrozen { get; }
+
+ ///
+ /// Returns the used by this
+ /// object.
+ ///
+ ///
+ /// The used by this
+ /// object.
+ ///
+ ITargetSource TargetSource { get; }
+
+ ///
+ /// Returns a boolean specifying if this
+ /// instance can be serialized.
+ ///
+ ///
+ /// true if this instance can be serialized, false otherwise.
+ ///
+ bool IsSerializable { get; }
+
+ ///
+ /// Adds the supplied to the end (or tail)
+ /// of the advice (interceptor) chain.
+ ///
+ ///
+ ///
+ /// Please be aware that Spring.NET's AOP implementation only supports
+ /// method advice (as encapsulated by the
+ /// interface).
+ ///
+ ///
+ ///
+ /// The to be added.
+ ///
+ ///
+ ///
+ void AddAdvice(IAdvice advice);
+
+ ///
+ /// Adds the supplied to the supplied
+ /// in the advice (interceptor) chain.
+ ///
+ ///
+ ///
+ /// Please be aware that Spring.NET's AOP implementation only supports
+ /// method advice (as encapsulated by the
+ /// interface).
+ ///
+ ///
+ ///
+ /// The zero (0) indexed position (from the head) at which the
+ /// supplied is to be inserted into the
+ /// advice (interceptor) chain.
+ ///
+ ///
+ /// The to be added.
+ ///
+ ///
+ ///
+ void AddAdvice(int position, IAdvice advice);
+
+ ///
+ /// Is the supplied (interface)
+ /// proxied?
+ ///
+ ///
+ /// The interface to test.
+ ///
+ ///
+ /// if the supplied
+ /// (interface) is proxied;
+ /// if not or the supplied
+ /// is .
+ ///
+ bool IsInterfaceProxied(Type intf);
+
+ ///
+ /// Adds the advisors from the supplied
+ /// to the list of .
+ ///
+ ///
+ /// The to add advisors from.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ void AddAdvisors(IAdvisors advisors);
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ void AddAdvisor(IAdvisor advisor);
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The index in the
+ /// list at which the supplied
+ /// is to be inserted.
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ void AddAdvisor(int index, IAdvisor advisor);
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ void AddIntroduction(IIntroductionAdvisor introductionAdvisor);
+
+ ///
+ /// Adds the supplied to the list
+ /// of .
+ ///
+ ///
+ /// The index in the
+ /// list at which the supplied
+ /// is to be inserted.
+ ///
+ ///
+ /// The to add.
+ ///
+ ///
+ /// If this proxy configuration is frozen and the
+ /// cannot be added.
+ ///
+ void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor);
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the interceptor
+ /// (advice) chain for this proxy.
+ ///
+ ///
+ ///
+ /// The return value of this method can be used to index into
+ /// the
+ /// list.
+ ///
+ ///
+ ///
+ /// The to search for.
+ ///
+ ///
+ /// The zero (0) based index of this advisor, or -1 if the
+ /// supplied is not an advisor for this
+ /// proxy.
+ ///
+ int IndexOf(IAdvisor advisor);
+
+ ///
+ /// Return the index (0 based) of the supplied
+ /// in the introductions
+ /// for this proxy.
+ ///
+ ///
+ ///
+ /// The return value of this method can be used to index into
+ /// the
+ /// list.
+ ///
- /// Allows
- /// implementations to be notified of notable lifecycle events relating
- /// to the creation of a proxy, and changes to the configuration data of a
- /// proxy.
- ///
+ /// Allows
+ /// implementations to be notified of notable lifecycle events relating
+ /// to the creation of a proxy, and changes to the configuration data of a
+ /// proxy.
+ ///
- /// Note that it is no longer possible to configure subclasses to
- /// expose the .
- /// Interceptors should normally manage their own thread locals if they
- /// need to make resources available to advised objects. If it is
- /// absolutely necessary to expose the
- /// , use an
- /// interceptor to do so.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: ProxyConfig.cs,v 1.13 2007/09/07 01:51:49 markpollack Exp $
- [Serializable]
- public class ProxyConfig
- {
- #region Fields
- private bool proxyTargetType;
- private bool proxyTargetAttributes = true;
- private bool optimize;
- private bool frozen;
-
- private IAopProxyFactory aopProxyFactory =
- ObjectUtils.InstantiateType( typeof(ProxyConfig).Assembly, "Spring.Aop.Framework.DynamicProxy.CachedAopProxyFactory") as IAopProxyFactory;
- private bool exposeProxy;
- private object syncRoot = new object();
- #endregion
-
- #region Properites
-
- ///
- /// Use to synchronize access to this ProxyConfig instance
- ///
- public object SyncRoot
- {
- get { return syncRoot; }
- }
-
- ///
- /// Is the target to be proxied in addition
- /// to any interfaces declared on the proxied ?
- ///
- public virtual bool ProxyTargetType
- {
- get { return this.proxyTargetType; }
- set { this.proxyTargetType = value; }
- }
-
- ///
- /// Is target type attributes, method attributes, method's return type attributes
- /// and method's parameter attributes to be proxied in addition
- /// to any interfaces declared on the proxied ?
- ///
- public virtual bool ProxyTargetAttributes
- {
- get { return this.proxyTargetAttributes; }
- set { this.proxyTargetAttributes = value; }
- }
-
- ///
- /// Are any agressive optimizations to be performed?
- ///
- ///
- ///
- /// The exact meaning of agressive optimizations will differ
- /// between proxies, but there is usually some tradeoff.
- ///
- ///
- /// For example, optimization will usually mean that advice changes
- /// won't take effect after a proxy has been created. For this reason,
- /// optimization is disabled by default. An optimize value of
- /// may be ignored if other settings preclude
- /// optimization: for example, if the
- /// property
- /// is set to and such a value is not compatible
- /// with the optimization.
- ///
- ///
- /// The default is .
- ///
- ///
- public virtual bool Optimize
- {
- get { return this.optimize; }
- set { this.optimize = value; }
- }
-
- ///
- /// Should proxies obtained from this configuration expose
- /// the AOP proxy to the
- /// class?
- ///
- ///
- ///
- /// The default is , as enabling this property
- /// may impair performance.
- ///
- ///
- public bool ExposeProxy
- {
- get { return this.exposeProxy; }
- set { this.exposeProxy = value; }
- }
-
- ///
- /// Gets and set the factory to be used to create AOP proxies.
- ///
- ///
- ///
- /// This obviously allows one to customise the
- /// implementation,
- /// allowing different strategies to be dropped in without changing the
- /// core framework. For example, an
- /// implementation
- /// could return an
- /// using remoting proxies, Reflection.Emit or a code generation
- /// strategy.
- ///
- ///
- public virtual IAopProxyFactory AopProxyFactory
- {
- get { return this.aopProxyFactory; }
- set { this.aopProxyFactory = value; }
- }
-
- ///
- /// Is this configuration frozen?
- ///
- ///
- ///
+ /// Note that it is no longer possible to configure subclasses to
+ /// expose the .
+ /// Interceptors should normally manage their own thread locals if they
+ /// need to make resources available to advised objects. If it is
+ /// absolutely necessary to expose the
+ /// , use an
+ /// interceptor to do so.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
+ public class ProxyConfig
+ {
+ #region Fields
+ private bool proxyTargetType;
+ private bool proxyTargetAttributes = true;
+ private bool optimize;
+ private bool frozen;
+
+ private IAopProxyFactory aopProxyFactory =
+ ObjectUtils.InstantiateType( typeof(ProxyConfig).Assembly, "Spring.Aop.Framework.DynamicProxy.CachedAopProxyFactory") as IAopProxyFactory;
+ private bool exposeProxy;
+ private object syncRoot = new object();
+ #endregion
+
+ #region Properites
+
+ ///
+ /// Use to synchronize access to this ProxyConfig instance
+ ///
+ public object SyncRoot
+ {
+ get { return syncRoot; }
+ }
+
+ ///
+ /// Is the target to be proxied in addition
+ /// to any interfaces declared on the proxied ?
+ ///
+ public virtual bool ProxyTargetType
+ {
+ get { return this.proxyTargetType; }
+ set { this.proxyTargetType = value; }
+ }
+
+ ///
+ /// Is target type attributes, method attributes, method's return type attributes
+ /// and method's parameter attributes to be proxied in addition
+ /// to any interfaces declared on the proxied ?
+ ///
+ public virtual bool ProxyTargetAttributes
+ {
+ get { return this.proxyTargetAttributes; }
+ set { this.proxyTargetAttributes = value; }
+ }
+
+ ///
+ /// Are any agressive optimizations to be performed?
+ ///
+ ///
+ ///
+ /// The exact meaning of agressive optimizations will differ
+ /// between proxies, but there is usually some tradeoff.
+ ///
+ ///
+ /// For example, optimization will usually mean that advice changes
+ /// won't take effect after a proxy has been created. For this reason,
+ /// optimization is disabled by default. An optimize value of
+ /// may be ignored if other settings preclude
+ /// optimization: for example, if the
+ /// property
+ /// is set to and such a value is not compatible
+ /// with the optimization.
+ ///
+ ///
+ /// The default is .
+ ///
+ ///
+ public virtual bool Optimize
+ {
+ get { return this.optimize; }
+ set { this.optimize = value; }
+ }
+
+ ///
+ /// Should proxies obtained from this configuration expose
+ /// the AOP proxy to the
+ /// class?
+ ///
+ ///
+ ///
+ /// The default is , as enabling this property
+ /// may impair performance.
+ ///
+ ///
+ public bool ExposeProxy
+ {
+ get { return this.exposeProxy; }
+ set { this.exposeProxy = value; }
+ }
+
+ ///
+ /// Gets and set the factory to be used to create AOP proxies.
+ ///
+ ///
+ ///
+ /// This obviously allows one to customise the
+ /// implementation,
+ /// allowing different strategies to be dropped in without changing the
+ /// core framework. For example, an
+ /// implementation
+ /// could return an
+ /// using remoting proxies, Reflection.Emit or a code generation
+ /// strategy.
+ ///
+ ///
+ public virtual IAopProxyFactory AopProxyFactory
+ {
+ get { return this.aopProxyFactory; }
+ set { this.aopProxyFactory = value; }
+ }
+
+ ///
+ /// Is this configuration frozen?
+ ///
+ ///
+ ///
- /// This class provides a simple way of obtaining and configuring AOP
- /// proxies in code.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: ProxyFactory.cs,v 1.8 2007/03/16 04:01:19 aseovic Exp $
- [Serializable]
- public class ProxyFactory : AdvisedSupport
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public ProxyFactory()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class that proxys all of the interfaces exposed by the supplied
- /// .
- ///
- /// The object to proxy.
- ///
- /// If the is .
- ///
- public ProxyFactory(object target) : base(GetInterfaces(target))
- {
- Target = target;
- }
-
- ///
- /// Creates a new instance of the
- /// class that has no target object, only interfaces.
- ///
- ///
- ///
- /// Interceptors must be added if this factory is to do anything useful.
- ///
- ///
- /// The interfaces to implement.
- public ProxyFactory(Type[] interfaces) : base(interfaces) {}
-
- ///
- /// Creates a new proxy according to the settings in this factory.
- ///
- ///
- ///
- /// Can be called repeatedly; the effect of repeated invocations will
- /// (of course) vary if interfaces have been added or removed.
- ///
- ///
- /// An AOP proxy for target object.
- public virtual object GetProxy()
- {
- IAopProxy proxy = CreateAopProxy();
- return proxy.GetProxy();
- }
-
- #region Convenience Methods (Static) For Proxy Creation
-
- ///
- /// Creates a new proxy for the supplied
- /// and .
- ///
- ///
- ///
- /// This is a convenience method for creating a proxy for a single
- /// interceptor.
- ///
+ /// This class provides a simple way of obtaining and configuring AOP
+ /// proxies in code.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
+ public class ProxyFactory : AdvisedSupport
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public ProxyFactory()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class that proxys all of the interfaces exposed by the supplied
+ /// .
+ ///
+ /// The object to proxy.
+ ///
+ /// If the is .
+ ///
+ public ProxyFactory(object target) : base(GetInterfaces(target))
+ {
+ Target = target;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class that has no target object, only interfaces.
+ ///
+ ///
+ ///
+ /// Interceptors must be added if this factory is to do anything useful.
+ ///
+ ///
+ /// The interfaces to implement.
+ public ProxyFactory(Type[] interfaces) : base(interfaces) {}
+
+ ///
+ /// Creates a new proxy according to the settings in this factory.
+ ///
+ ///
+ ///
+ /// Can be called repeatedly; the effect of repeated invocations will
+ /// (of course) vary if interfaces have been added or removed.
+ ///
+ ///
+ /// An AOP proxy for target object.
+ public virtual object GetProxy()
+ {
+ IAopProxy proxy = CreateAopProxy();
+ return proxy.GetProxy();
+ }
+
+ #region Convenience Methods (Static) For Proxy Creation
+
+ ///
+ /// Creates a new proxy for the supplied
+ /// and .
+ ///
+ ///
+ ///
+ /// This is a convenience method for creating a proxy for a single
+ /// interceptor.
+ ///
- /// s and
- /// s are identified by a list of object
- /// names in the current container.
- ///
- /// Global interceptors and advisors can be added at the factory level
- /// (that is, outside the context of a
- /// definition). The
- /// specified interceptors and advisors are expanded in an interceptor list
- /// (see
- /// )
- /// where an 'xxx*' wildcard-style entry is included in the list,
- /// matching the given prefix with the object names. For example,
- /// 'global*' would match both 'globalObject1' and
- /// 'globalObjectBar', and '*' would match all defined
- /// interceptors. The matching interceptors get applied according to their
- /// returned order value, if they implement the
- /// interface. An interceptor name list
- /// may not conclude with a global 'xxx*' pattern, as global
- /// interceptors cannot invoke targets.
- ///
- ///
- /// It is possible to cast a proxy obtained from this factory to an
- /// reference, or to obtain the
- /// reference and
- /// programmatically manipulate it. This won't work for existing prototype
- /// references, which are independent... however, it will work for prototypes
- /// subsequently obtained from the factory. Changes to interception will
- /// work immediately on singletons (including existing references).
- /// However, to change interfaces or the target it is necessary to obtain a
- /// new instance from the surrounding container. This means that singleton
- /// instances obtained from the factory do not have the same object
- /// identity... however, they do have the same interceptors and target, and
- /// changing any reference will change all objects.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Federico Spinazzi (.NET)
- /// Choy Rim (.NET)
- /// Mark Pollack (.NET)
- /// Aleksandar Seovic (.NET)
- /// $Id: ProxyFactoryObject.cs,v 1.26 2007/08/03 14:38:30 markpollack Exp $
- ///
- ///
- ///
- ///
- ///
- [Serializable]
- public class ProxyFactoryObject
- : AdvisedSupport, IFactoryObject, IObjectFactoryAware, IAdvisedSupportListener
- {
- #region Fields
-
- ///
- /// The shared instance for this class.
- ///
- private static readonly ILog logger = LogManager.GetLogger(typeof (ProxyFactoryObject));
-
- ///
- /// Is the object managed by this factory a singleton or a prototype?
- ///
- private bool singleton = true;
-
- ///
- /// This suffix in a value in an interceptor list indicates to expand globals.
- ///
- public const string GlobalInterceptorSuffix = "*";
-
- ///
- /// The cached instance if this proxy factory object is a singleton.
- ///
- private object singletonInstance;
-
- ///
- /// The owning object factory (which cannot be changed after this object is initialized).
- ///
- private IObjectFactory objectFactory;
-
- ///
- /// The mapping from an or interceptor
- /// to an object name (or ), depending on where it was
- /// sourced from.
- ///
- ///
- ///
- /// If it's sourced from object name, it will need to be
- /// refreshed each time a new prototype instance is created.
- ///
- ///
- private IDictionary sourceDictionary = new Hashtable();
-
- ///
- /// Names of interceptors and pointcut objects in the factory.
- ///
- ///
- ///
- /// Default is for globals expansion only.
- ///
- ///
- private string[] interceptorNames = null;
-
- ///
- /// Names of introductions and pointcut objects in the factory.
- ///
- ///
- ///
- /// Default is for globals expansion only.
- ///
- ///
- private string[] introductionNames = null;
-
- ///
- /// The name of the target object(in the enclosing
- /// ).
- ///
- private string targetName = null;
-
- #endregion
-
- #region Properties
-
- ///
- /// Sets the names of the interfaces that are to be implemented by the proxy.
- ///
- ///
- /// The names of the interfaces that are to be implemented by the proxy.
- ///
- ///
- /// If the supplied value (or any of its elements) is ;
- /// or if any of the element values is not the (assembly qualified) name of
- /// an interface type.
- ///
- public virtual string[] ProxyInterfaces
- {
- set
- {
- try
- {
- Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value);
- }
- catch (Exception ex)
- {
- throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex);
- }
- }
- }
-
- ///
- /// Sets the name of the target object being proxied.
- ///
- ///
- ///
- /// Only works when the
- ///
- /// property is set; it is a logic error on the part of the programmer
- /// if this value is set and the accompanying
- /// is not also set.
- ///
- ///
- ///
- /// The name of the target object being proxied.
- ///
- public virtual string TargetName
- {
- set { this.targetName = value; }
- }
-
- ///
- /// Sets the list of and
- /// object names.
- ///
- ///
- ///
- /// This property must always be set (configured) when using a
- /// in an
- /// context.
- ///
- ///
- ///
- /// The list of and
- /// object names.
- ///
- ///
- ///
- ///
- ///
- public virtual string[] InterceptorNames
- {
- set { this.interceptorNames = value; }
- }
-
- ///
- /// Sets the list of introduction object names.
- ///
- ///
- ///
- /// Only works when the
- ///
- /// property is set; it is a logic error on the part of the programmer
- /// if this value is set and the accompanying
- /// is not supplied.
- ///
- ///
- ///
- /// The list of introduction object names. .
- ///
- public virtual string[] IntroductionNames
- {
- set { this.introductionNames = value; }
- }
-
- #endregion
-
- #region IFactoryObjectAware implementation
-
- ///
- /// Callback that supplies the owning factory to an object instance.
- ///
- ///
- /// Owning
- /// (may not be ). The object can immediately
- /// call methods on the factory.
- ///
- ///
- /// In case of initialization errors.
- ///
- ///
- ///
- public virtual IObjectFactory ObjectFactory
- {
- set
- {
- this.objectFactory = value;
-
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug("Setting IObjectFactory. Will configure target, interceptors and introductions...");
- }
-
- #endregion
-
- ConfigureAdvisorChain();
- ConfigureIntroductions();
-
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug("ProxyFactoryObject config: " + this);
- }
-
- #endregion
-
- if (IsSingleton)
- {
- if (this.targetName != null)
- {
- TargetSource = NamedObjectToTargetSource(this.objectFactory.GetObject(this.targetName));
- }
-
- // eagerly initialize the shared singleton instance...
- this.singletonInstance = CreateAopProxy().GetProxy();
-
- // must listen to superclass advice and interface change
- // events to recache singleton instance if necessary...
- AddListener(this);
- }
- }
- }
-
- #endregion
-
- #region IFactoryObject implementation
-
- ///
- /// Creates an instance of the AOP proxy to be returned by this factory
- ///
- ///
- ///
- /// Invoked when clients obtain objects from this factory object. The
- /// (proxy) instance will be cached for a singleton, and created on each
- /// call to
- /// for a prototype.
- ///
+ /// s and
+ /// s are identified by a list of object
+ /// names in the current container.
+ ///
+ /// Global interceptors and advisors can be added at the factory level
+ /// (that is, outside the context of a
+ /// definition). The
+ /// specified interceptors and advisors are expanded in an interceptor list
+ /// (see
+ /// )
+ /// where an 'xxx*' wildcard-style entry is included in the list,
+ /// matching the given prefix with the object names. For example,
+ /// 'global*' would match both 'globalObject1' and
+ /// 'globalObjectBar', and '*' would match all defined
+ /// interceptors. The matching interceptors get applied according to their
+ /// returned order value, if they implement the
+ /// interface. An interceptor name list
+ /// may not conclude with a global 'xxx*' pattern, as global
+ /// interceptors cannot invoke targets.
+ ///
+ ///
+ /// It is possible to cast a proxy obtained from this factory to an
+ /// reference, or to obtain the
+ /// reference and
+ /// programmatically manipulate it. This won't work for existing prototype
+ /// references, which are independent... however, it will work for prototypes
+ /// subsequently obtained from the factory. Changes to interception will
+ /// work immediately on singletons (including existing references).
+ /// However, to change interfaces or the target it is necessary to obtain a
+ /// new instance from the surrounding container. This means that singleton
+ /// instances obtained from the factory do not have the same object
+ /// identity... however, they do have the same interceptors and target, and
+ /// changing any reference will change all objects.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Federico Spinazzi (.NET)
+ /// Choy Rim (.NET)
+ /// Mark Pollack (.NET)
+ /// Aleksandar Seovic (.NET)
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Serializable]
+ public class ProxyFactoryObject
+ : AdvisedSupport, IFactoryObject, IObjectFactoryAware, IAdvisedSupportListener
+ {
+ #region Fields
+
+ ///
+ /// The shared instance for this class.
+ ///
+ private static readonly ILog logger = LogManager.GetLogger(typeof (ProxyFactoryObject));
+
+ ///
+ /// Is the object managed by this factory a singleton or a prototype?
+ ///
+ private bool singleton = true;
+
+ ///
+ /// This suffix in a value in an interceptor list indicates to expand globals.
+ ///
+ public const string GlobalInterceptorSuffix = "*";
+
+ ///
+ /// The cached instance if this proxy factory object is a singleton.
+ ///
+ private object singletonInstance;
+
+ ///
+ /// The owning object factory (which cannot be changed after this object is initialized).
+ ///
+ private IObjectFactory objectFactory;
+
+ ///
+ /// The mapping from an or interceptor
+ /// to an object name (or ), depending on where it was
+ /// sourced from.
+ ///
+ ///
+ ///
+ /// If it's sourced from object name, it will need to be
+ /// refreshed each time a new prototype instance is created.
+ ///
+ ///
+ private IDictionary sourceDictionary = new Hashtable();
+
+ ///
+ /// Names of interceptors and pointcut objects in the factory.
+ ///
+ ///
+ ///
+ /// Default is for globals expansion only.
+ ///
+ ///
+ private string[] interceptorNames = null;
+
+ ///
+ /// Names of introductions and pointcut objects in the factory.
+ ///
+ ///
+ ///
+ /// Default is for globals expansion only.
+ ///
+ ///
+ private string[] introductionNames = null;
+
+ ///
+ /// The name of the target object(in the enclosing
+ /// ).
+ ///
+ private string targetName = null;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Sets the names of the interfaces that are to be implemented by the proxy.
+ ///
+ ///
+ /// The names of the interfaces that are to be implemented by the proxy.
+ ///
+ ///
+ /// If the supplied value (or any of its elements) is ;
+ /// or if any of the element values is not the (assembly qualified) name of
+ /// an interface type.
+ ///
+ public virtual string[] ProxyInterfaces
+ {
+ set
+ {
+ try
+ {
+ Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value);
+ }
+ catch (Exception ex)
+ {
+ throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex);
+ }
+ }
+ }
+
+ ///
+ /// Sets the name of the target object being proxied.
+ ///
+ ///
+ ///
+ /// Only works when the
+ ///
+ /// property is set; it is a logic error on the part of the programmer
+ /// if this value is set and the accompanying
+ /// is not also set.
+ ///
+ ///
+ ///
+ /// The name of the target object being proxied.
+ ///
+ public virtual string TargetName
+ {
+ set { this.targetName = value; }
+ }
+
+ ///
+ /// Sets the list of and
+ /// object names.
+ ///
+ ///
+ ///
+ /// This property must always be set (configured) when using a
+ /// in an
+ /// context.
+ ///
+ ///
+ ///
+ /// The list of and
+ /// object names.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual string[] InterceptorNames
+ {
+ set { this.interceptorNames = value; }
+ }
+
+ ///
+ /// Sets the list of introduction object names.
+ ///
+ ///
+ ///
+ /// Only works when the
+ ///
+ /// property is set; it is a logic error on the part of the programmer
+ /// if this value is set and the accompanying
+ /// is not supplied.
+ ///
+ ///
+ ///
+ /// The list of introduction object names. .
+ ///
+ public virtual string[] IntroductionNames
+ {
+ set { this.introductionNames = value; }
+ }
+
+ #endregion
+
+ #region IFactoryObjectAware implementation
+
+ ///
+ /// Callback that supplies the owning factory to an object instance.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ ///
+ /// In case of initialization errors.
+ ///
+ ///
+ ///
+ public virtual IObjectFactory ObjectFactory
+ {
+ set
+ {
+ this.objectFactory = value;
+
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Setting IObjectFactory. Will configure target, interceptors and introductions...");
+ }
+
+ #endregion
+
+ ConfigureAdvisorChain();
+ ConfigureIntroductions();
+
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("ProxyFactoryObject config: " + this);
+ }
+
+ #endregion
+
+ if (IsSingleton)
+ {
+ if (this.targetName != null)
+ {
+ TargetSource = NamedObjectToTargetSource(this.objectFactory.GetObject(this.targetName));
+ }
+
+ // eagerly initialize the shared singleton instance...
+ this.singletonInstance = CreateAopProxy().GetProxy();
+
+ // must listen to superclass advice and interface change
+ // events to recache singleton instance if necessary...
+ AddListener(this);
+ }
+ }
+ }
+
+ #endregion
+
+ #region IFactoryObject implementation
+
+ ///
+ /// Creates an instance of the AOP proxy to be returned by this factory
+ ///
+ ///
+ ///
+ /// Invoked when clients obtain objects from this factory object. The
+ /// (proxy) instance will be cached for a singleton, and created on each
+ /// call to
+ /// for a prototype.
+ ///
- /// Spring.NET AOP is centered on around advice delivered via method
- /// interception, compliant with the AOP Alliance interception API.
- /// The interface allows support for
- /// different types of advice, such as before and after
- /// advice, which need not be implemented using interception.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- ///
- ///
- ///
- ///
- /// $Id: IAdvisor.cs,v 1.7 2006/04/09 07:18:36 markpollack Exp $
- public interface IAdvisor
- {
- ///
- /// Is this advice associated with a particular instance?
- ///
- ///
- ///
- /// An advisor that was creating a mixin would be a per instance
- /// operation and would thus return . If the
- /// advisor is not per instance, it is shared with all instances of the
- /// advised class obtained from the same Spring.NET IoC container.
- ///
- ///
- /// Use singleton and prototype object definitions or
- /// appropriate programmatic proxy creation to ensure that
- /// s have the correct lifecycle model.
- ///
- ///
- /// This method is not currently used by the framework.
- ///
- ///
- ///
- /// if this advice is associated with a
- /// particular instance.
- ///
- bool IsPerInstance { get; }
-
- ///
- /// Return the advice part of this aspect.
- ///
- ///
- ///
- /// An advice may be an interceptor, a throws advice, before advice,
- /// introduction etc.
- ///
+ /// Spring.NET AOP is centered on around advice delivered via method
+ /// interception, compliant with the AOP Alliance interception API.
+ /// The interface allows support for
+ /// different types of advice, such as before and after
+ /// advice, which need not be implemented using interception.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ ///
+ ///
+ ///
+ public interface IAdvisor
+ {
+ ///
+ /// Is this advice associated with a particular instance?
+ ///
+ ///
+ ///
+ /// An advisor that was creating a mixin would be a per instance
+ /// operation and would thus return . If the
+ /// advisor is not per instance, it is shared with all instances of the
+ /// advised class obtained from the same Spring.NET IoC container.
+ ///
+ ///
+ /// Use singleton and prototype object definitions or
+ /// appropriate programmatic proxy creation to ensure that
+ /// s have the correct lifecycle model.
+ ///
+ ///
+ /// This method is not currently used by the framework.
+ ///
+ ///
+ ///
+ /// if this advice is associated with a
+ /// particular instance.
+ ///
+ bool IsPerInstance { get; }
+
+ ///
+ /// Return the advice part of this aspect.
+ ///
+ ///
+ ///
+ /// An advice may be an interceptor, a throws advice, before advice,
+ /// introduction etc.
+ ///
- /// After returning advice is invoked only on a normal method
- /// return, but not if an exception is thrown. Such advice can see
- /// the return value of the advised method invocation, but cannot change it.
- ///
- ///
- /// Possible uses for this type of advice would include performing access
- /// control checks on the return value of an advised method invocation, the
- /// ubiquitous logging of method invocation return values (useful during
- /// development), etc.
- ///
- /// Note that the supplied cannot
- /// be changed by this type of advice... use the around advice type
- /// () if you
- /// need to change the return value of an advised method invocation.
- /// The data encapsulated by the supplied
- /// can of course be modified though.
- ///
+ /// After returning advice is invoked only on a normal method
+ /// return, but not if an exception is thrown. Such advice can see
+ /// the return value of the advised method invocation, but cannot change it.
+ ///
+ ///
+ /// Possible uses for this type of advice would include performing access
+ /// control checks on the return value of an advised method invocation, the
+ /// ubiquitous logging of method invocation return values (useful during
+ /// development), etc.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ ///
+ ///
+ public interface IAfterReturningAdvice : IAdvice
+ {
+ ///
+ /// Executes after
+ /// returns successfully.
+ ///
+ ///
+ ///
+ /// Note that the supplied cannot
+ /// be changed by this type of advice... use the around advice type
+ /// () if you
+ /// need to change the return value of an advised method invocation.
+ /// The data encapsulated by the supplied
+ /// can of course be modified though.
+ ///
- /// Before advice is advice that executes before a joinpoint, but
- /// which does not have the ability to prevent execution flow proceeding to
- /// the joinpoint (unless it throws an ).
- ///
- ///
- /// Spring.NET only supports method before advice. Although this
- /// is unlikely to change, this API is designed to allow field
- /// before advice in future if desired.
- ///
+ /// Before advice is advice that executes before a joinpoint, but
+ /// which does not have the ability to prevent execution flow proceeding to
+ /// the joinpoint (unless it throws an ).
+ ///
+ ///
+ /// Spring.NET only supports method before advice. Although this
+ /// is unlikely to change, this API is designed to allow field
+ /// before advice in future if desired.
+ ///
+ /// This interface cannot be implemented directly; subinterfaces must
+ /// provide the advice type implementing the introduction.
+ ///
+ ///
+ /// Introduction is the implementation of additional interfaces (not
+ /// implemented by a target) via AOP advice.
+ ///
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public interface IIntroductionAdvisor : IAdvisor
+ {
+ ///
+ /// Returns the filter determining which target classes this
+ /// introduction should apply to.
+ ///
+ ///
+ ///
+ /// This is the part of a pointcut.
+ /// Be advised that method matching doesn't make sense in the context
+ /// of introductions.
+ ///
+ ///
+ ///
+ /// The filter determining which target classes this introduction
+ /// should apply to.
+ ///
+ ITypeFilter TypeFilter { get; }
+
+ ///
+ /// Gets the interfaces introduced by this
+ /// .
+ ///
+ ///
+ /// The interfaces introduced by this
+ /// .
+ ///
+ Type[] Interfaces { get; }
+
+ ///
+ /// Can the advised interfaces be implemented by the introduction
+ /// advice?
+ ///
+ ///
+ ///
- /// This is a fundamental AOP concept called introduction.
- ///
- ///
- /// Introductions are often mixins, enabling the building of composite
- /// objects that can achieve many of the goals of multiple inheritance.
- ///
+ /// This is a fundamental AOP concept called introduction.
+ ///
+ ///
+ /// Introductions are often mixins, enabling the building of composite
+ /// objects that can achieve many of the goals of multiple inheritance.
+ ///
- /// Such advice cannot prevent the method call proceeding, short of
- /// throwing an .
- ///
- ///
- /// The main advantage of before advice is that there is no
- /// possibility of inadvertently failing to proceed down the interceptor
- /// chain, since there is no need (and indeed means) to invoke the next
- /// interceptor in the call chain.
- ///
- ///
- /// Possible uses for this type of advice would include performing class
- /// invariant checks prior to the actual method invocation, the ubiquitous
- /// logging of method invocations (useful during development), etc.
- ///
+ /// Such advice cannot prevent the method call proceeding, short of
+ /// throwing an .
+ ///
+ ///
+ /// The main advantage of before advice is that there is no
+ /// possibility of inadvertently failing to proceed down the interceptor
+ /// chain, since there is no need (and indeed means) to invoke the next
+ /// interceptor in the call chain.
+ ///
+ ///
+ /// Possible uses for this type of advice would include performing class
+ /// invariant checks prior to the actual method invocation, the ubiquitous
+ /// logging of method invocations (useful during development), etc.
+ ///
- /// An may be evaluated
- /// statically or at runtime (dynamically). Static
- /// matching involves only the method signature and (possibly) any
- /// s that have been applied to a method.
- /// Dynamic matching additionally takes into account the actual argument
- /// values passed to a method invocation.
- ///
- ///
- /// If the value of the
- /// property of an implementation instance returns ,
- /// evaluation can be performed statically, and the result will be the same
- /// for all invocations of this method, whatever their arguments. This
- /// means that if the value of the
- /// is
- /// , the three argument
- ///
- /// method will never be invoked for the lifetime of the
- /// .
- ///
- ///
- /// If an implementation returns in its two argument
- ///
- /// method, and the value of it's
- /// property is
- /// , the three argument
- ///
- /// method will be invoked immediately before each and every potential
- /// execution of the related advice, to decide whether the advice
- /// should run. All previous advice, such as earlier interceptors in an
- /// interceptor chain, will have run, so any state changes they have
- /// produced in parameters or thread local storage, will be available at
- /// the time of evaluation.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: IMethodMatcher.cs,v 1.9 2006/04/09 07:18:36 markpollack Exp $
- ///
- public interface IMethodMatcher
- {
- ///
- /// Is this dynamic?
- ///
- ///
- ///
- /// If , the three argument
- ///
- /// method will be invoked if the two argument
- ///
- /// method returns .
- ///
- ///
- /// Note that this property can be checked when an AOP proxy is created,
- /// and implementations need not check the value of this property again
- /// before each method invocation.
- ///
- ///
- ///
- /// if this
- /// is dynamic.
- ///
- bool IsRuntime { get; }
-
- ///
- /// Does the supplied satisfy this matcher?
- ///
- ///
- ///
- /// This is a static check. If this method invocation returns
- /// ,or if the
- /// property is
- /// , then no runtime check will be made.
- ///
- ///
- /// The candidate method.
- ///
- /// The target (may be ,
- /// in which case the candidate must be taken
- /// to be the 's declaring class).
- ///
- ///
- /// if this this method matches statically.
- ///
- bool Matches(MethodInfo method, Type targetType);
-
- ///
- /// Is there a runtime (dynamic) match for the supplied
- /// ?
- ///
- ///
- ///
- /// In order for this method to have even been invoked, the supplied
- /// must have matched
- /// statically. This method is invoked only if the two argument
- ///
- /// method returns for the supplied
- /// and , and
- /// if the property
- /// is .
- ///
- ///
- /// Invoked immediately before any potential running of the
- /// advice, and after any advice earlier in the advice chain has
- /// run.
- ///
+ /// An may be evaluated
+ /// statically or at runtime (dynamically). Static
+ /// matching involves only the method signature and (possibly) any
+ /// s that have been applied to a method.
+ /// Dynamic matching additionally takes into account the actual argument
+ /// values passed to a method invocation.
+ ///
+ ///
+ /// If the value of the
+ /// property of an implementation instance returns ,
+ /// evaluation can be performed statically, and the result will be the same
+ /// for all invocations of this method, whatever their arguments. This
+ /// means that if the value of the
+ /// is
+ /// , the three argument
+ ///
+ /// method will never be invoked for the lifetime of the
+ /// .
+ ///
+ ///
+ /// If an implementation returns in its two argument
+ ///
+ /// method, and the value of it's
+ /// property is
+ /// , the three argument
+ ///
+ /// method will be invoked immediately before each and every potential
+ /// execution of the related advice, to decide whether the advice
+ /// should run. All previous advice, such as earlier interceptors in an
+ /// interceptor chain, will have run, so any state changes they have
+ /// produced in parameters or thread local storage, will be available at
+ /// the time of evaluation.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ public interface IMethodMatcher
+ {
+ ///
+ /// Is this dynamic?
+ ///
+ ///
+ ///
+ /// If , the three argument
+ ///
+ /// method will be invoked if the two argument
+ ///
+ /// method returns .
+ ///
+ ///
+ /// Note that this property can be checked when an AOP proxy is created,
+ /// and implementations need not check the value of this property again
+ /// before each method invocation.
+ ///
+ ///
+ ///
+ /// if this
+ /// is dynamic.
+ ///
+ bool IsRuntime { get; }
+
+ ///
+ /// Does the supplied satisfy this matcher?
+ ///
+ ///
+ ///
+ /// This is a static check. If this method invocation returns
+ /// ,or if the
+ /// property is
+ /// , then no runtime check will be made.
+ ///
+ ///
+ /// The candidate method.
+ ///
+ /// The target (may be ,
+ /// in which case the candidate must be taken
+ /// to be the 's declaring class).
+ ///
+ ///
+ /// if this this method matches statically.
+ ///
+ bool Matches(MethodInfo method, Type targetType);
+
+ ///
+ /// Is there a runtime (dynamic) match for the supplied
+ /// ?
+ ///
+ ///
+ ///
+ /// In order for this method to have even been invoked, the supplied
+ /// must have matched
+ /// statically. This method is invoked only if the two argument
+ ///
+ /// method returns for the supplied
+ /// and , and
+ /// if the property
+ /// is .
+ ///
+ ///
+ /// Invoked immediately before any potential running of the
+ /// advice, and after any advice earlier in the advice chain has
+ /// run.
+ ///
- /// A pointcut is composed of s and
- /// s. Both these basic terms and an
- /// itself can be combined to build up
- /// sophisticated combinations.
- ///
+ /// A pointcut is composed of s and
+ /// s. Both these basic terms and an
+ /// itself can be combined to build up
+ /// sophisticated combinations.
+ ///
- /// This target will be invoked via reflection if no around advice chooses
- /// to end the interceptor chain itself.
- ///
- ///
- /// If an is "static", it
- /// will always return the same target, allowing optimizations in the AOP
- /// framework. Dynamic target sources can support pooling, hot swapping etc.
- ///
- ///
- /// Application developers don't usually need to work with target sources
- /// directly: this is an AOP framework interface.
- ///
+ /// This target will be invoked via reflection if no around advice chooses
+ /// to end the interceptor chain itself.
+ ///
+ ///
+ /// If an is "static", it
+ /// will always return the same target, allowing optimizations in the AOP
+ /// framework. Dynamic target sources can support pooling, hot swapping etc.
+ ///
+ ///
+ /// Application developers don't usually need to work with target sources
+ /// directly: this is an AOP framework interface.
+ ///
- /// There are no methods on this interface, as methods are discovered and
- /// invoked via reflection. Please do see read the API documentation for the
- /// class;
- /// said documention describes in detail the signature of the methods that
- /// implementations of the interface
- /// must adhere to in the specific case of Spring.NET's implementation of
- /// throws advice.
- ///
- ///
- /// There are any number of possible uses for this type of advice. Some
- /// examples would include the ubiquitous logging of any such exceptions,
- /// monitoring the number and type of exceptions and sending emails to
- /// a support desk once certain criteria have been met, wrapping generic
- /// exceptions such as in
- /// exceptions that are more meaningful to your business logic, etc.
- ///
+ /// There are no methods on this interface, as methods are discovered and
+ /// invoked via reflection. Please do see read the API documentation for the
+ /// class;
+ /// said documention describes in detail the signature of the methods that
+ /// implementations of the interface
+ /// must adhere to in the specific case of Spring.NET's implementation of
+ /// throws advice.
+ ///
+ ///
+ /// There are any number of possible uses for this type of advice. Some
+ /// examples would include the ubiquitous logging of any such exceptions,
+ /// monitoring the number and type of exceptions and sending emails to
+ /// a support desk once certain criteria have been met, wrapping generic
+ /// exceptions such as in
+ /// exceptions that are more meaningful to your business logic, etc.
+ ///
+ /// Can be used as part of a pointcut, or for the entire targeting of an
+ /// introduction.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ ///
+ ///
+ public interface ITypeFilter
+ {
+ ///
+ /// Should the pointcut apply to the supplied
+ /// ?
+ ///
+ ///
+ /// The candidate .
+ ///
+ ///
+ /// if the advice should apply to the supplied
+ ///
+ ///
+ bool Matches(Type type);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs
index 3b7a1905..bbaf9b2a 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AbstractGenericPointcutAdvisor.cs
@@ -1,64 +1,63 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 AopAlliance.Aop;
-
-namespace Spring.Aop.Support
-{
- ///
- /// Abstract PointcutAdvisor that allows for any Advice to be configured.
- ///
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: AbstractGenericPointcutAdvisor.cs,v 1.2 2007/08/10 17:39:44 bbaia Exp $
- [Serializable]
- public abstract class AbstractGenericPointcutAdvisor : AbstractPointcutAdvisor
- {
- private IAdvice advice;
-
-
- ///
- /// Return the advice part of this advisor.
- ///
- ///
- /// The advice that should apply if the pointcut matches.
- ///
- ///
- public override IAdvice Advice
- {
- get { return this.advice; }
- set { this.advice = value; }
- }
-
-
- ///
- /// Returns a that represents the current
- /// .
- ///
- ///
- /// A representation of this advisor.
- ///
- public override string ToString()
- {
- return GetType().Name + ": advice=[" + Advice + "]";
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 AopAlliance.Aop;
+
+namespace Spring.Aop.Support
+{
+ ///
+ /// Abstract PointcutAdvisor that allows for any Advice to be configured.
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ [Serializable]
+ public abstract class AbstractGenericPointcutAdvisor : AbstractPointcutAdvisor
+ {
+ private IAdvice advice;
+
+
+ ///
+ /// Return the advice part of this advisor.
+ ///
+ ///
+ /// The advice that should apply if the pointcut matches.
+ ///
+ ///
+ public override IAdvice Advice
+ {
+ get { return this.advice; }
+ set { this.advice = value; }
+ }
+
+
+ ///
+ /// Returns a that represents the current
+ /// .
+ ///
+ ///
+ /// A representation of this advisor.
+ ///
+ public override string ToString()
+ {
+ return GetType().Name + ": advice=[" + Advice + "]";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs
index f4805a8b..a295ccc0 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AbstractObjectFactoryPointcutAdvisor.cs
@@ -1,137 +1,136 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 AopAlliance.Aop;
-using Spring.Objects.Factory;
-using Spring.Util;
-
-namespace Spring.Aop.Support
-{
- ///
- /// Abstract ObjectFactory-based IPointcutAdvisor that allows for any Advice to be
- /// configured as reference to an Advice object in an ObjectFactory.
- ///
- ///
- /// specifying the name of an advice object instead of the advice object itself
- /// (if running within an ObjectFactory/ApplicationContext increses loose coupling
- /// at initialization time, in order not to initialize the advice object until the
- /// pointcut actually matches.
- ///
- /// Juergen Hoeller
- /// Mark Pollack
- /// $Id: AbstractObjectFactoryPointcutAdvisor.cs,v 1.2 2007/08/10 17:39:44 bbaia Exp $
- public abstract class AbstractObjectFactoryPointcutAdvisor : AbstractPointcutAdvisor, IObjectFactoryAware
- {
- private string adviceObjectName;
-
- private IObjectFactory objectFactory;
-
- private IAdvice advice;
-
- private object adviceMonitor = new object();
-
-
- ///
- /// Gets or sets the name of the advice object that this advisor should refer to.
- ///
- /// An instance of the specified object will be obtained on first access of
- /// this advisor's advice. This advisor will only ever obtain at most one
- /// single instance of the advice object, caching the instance for the lifetime of
- /// the advisor.
- /// The name of the advice object.
- public string AdviceObjectName
- {
- get { return adviceObjectName; }
- set { adviceObjectName = value; }
- }
-
- #region IObjectFactoryAware Members
-
- ///
- /// Callback that supplies the owning factory to an object instance.
- ///
- ///
- /// Owning
- /// (may not be ). The object can immediately
- /// call methods on the factory.
- ///
- ///
- ///
- /// Invoked after population of normal object properties but before an init
- /// callback like 's
- ///
- /// method or a custom init-method.
- ///
- ///
- ///
- /// In case of initialization errors.
- ///
- public IObjectFactory ObjectFactory
- {
- set { objectFactory = value; }
- }
-
- #endregion
-
- ///
- /// Return the advice part of this aspect.
- ///
- ///
- ///
- /// An advice may be an interceptor, a throws advice, before advice,
- /// introduction etc.
- ///
- ///
- ///
- /// The advice that should apply if the pointcut matches.
- ///
- public override IAdvice Advice
- {
- get
- {
- lock (adviceMonitor)
- {
- if (advice == null && adviceObjectName != null)
- {
- AssertUtils.State(objectFactory != null,
- "ObjectFactory must be set to resolve 'adviceObjectName'");
- advice = objectFactory.GetObject(adviceObjectName, typeof (IAdvice)) as IAdvice;
- }
- }
- return advice;
- }
- set
- {
- advice = value;
- }
- }
-
- ///
- /// Describe this Advisor, showing name of advice object.
- ///
- ///
- /// Type name and advice object name.
- ///
- public override string ToString()
- {
- return GetType().Name + ": advice object '" + AdviceObjectName + "'";
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 AopAlliance.Aop;
+using Spring.Objects.Factory;
+using Spring.Util;
+
+namespace Spring.Aop.Support
+{
+ ///
+ /// Abstract ObjectFactory-based IPointcutAdvisor that allows for any Advice to be
+ /// configured as reference to an Advice object in an ObjectFactory.
+ ///
+ ///
+ /// specifying the name of an advice object instead of the advice object itself
+ /// (if running within an ObjectFactory/ApplicationContext increses loose coupling
+ /// at initialization time, in order not to initialize the advice object until the
+ /// pointcut actually matches.
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack
+ public abstract class AbstractObjectFactoryPointcutAdvisor : AbstractPointcutAdvisor, IObjectFactoryAware
+ {
+ private string adviceObjectName;
+
+ private IObjectFactory objectFactory;
+
+ private IAdvice advice;
+
+ private object adviceMonitor = new object();
+
+
+ ///
+ /// Gets or sets the name of the advice object that this advisor should refer to.
+ ///
+ /// An instance of the specified object will be obtained on first access of
+ /// this advisor's advice. This advisor will only ever obtain at most one
+ /// single instance of the advice object, caching the instance for the lifetime of
+ /// the advisor.
+ /// The name of the advice object.
+ public string AdviceObjectName
+ {
+ get { return adviceObjectName; }
+ set { adviceObjectName = value; }
+ }
+
+ #region IObjectFactoryAware Members
+
+ ///
+ /// Callback that supplies the owning factory to an object instance.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an init
+ /// callback like 's
+ ///
+ /// method or a custom init-method.
+ ///
+ ///
+ ///
+ /// In case of initialization errors.
+ ///
+ public IObjectFactory ObjectFactory
+ {
+ set { objectFactory = value; }
+ }
+
+ #endregion
+
+ ///
+ /// Return the advice part of this aspect.
+ ///
+ ///
+ ///
+ /// An advice may be an interceptor, a throws advice, before advice,
+ /// introduction etc.
+ ///
+ ///
+ ///
+ /// The advice that should apply if the pointcut matches.
+ ///
+ public override IAdvice Advice
+ {
+ get
+ {
+ lock (adviceMonitor)
+ {
+ if (advice == null && adviceObjectName != null)
+ {
+ AssertUtils.State(objectFactory != null,
+ "ObjectFactory must be set to resolve 'adviceObjectName'");
+ advice = objectFactory.GetObject(adviceObjectName, typeof (IAdvice)) as IAdvice;
+ }
+ }
+ return advice;
+ }
+ set
+ {
+ advice = value;
+ }
+ }
+
+ ///
+ /// Describe this Advisor, showing name of advice object.
+ ///
+ ///
+ /// Type name and advice object name.
+ ///
+ public override string ToString()
+ {
+ return GetType().Name + ": advice object '" + AdviceObjectName + "'";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs
index 2c90ff85..1997c7ae 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AbstractPointcutAdvisor.cs
@@ -1,166 +1,165 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 AopAlliance.Aop;
-using Spring.Core;
-
-namespace Spring.Aop.Support
-{
- ///
- /// Abstract base class for implementations.
- ///
- ///
- /// Can be subclassed for returning a specific pointcut/advice or a freely configurable pointcut/advice.
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: AbstractPointcutAdvisor.cs,v 1.2 2008/01/14 20:49:47 oakinger Exp $
- [Serializable]
- public abstract class AbstractPointcutAdvisor : IPointcutAdvisor, IOrdered
- {
- #region Fields
-
- private int _order = Int32.MaxValue;
-
- #endregion
-
- #region IOrdered Members
-
- ///
- /// Returns this s order in the
- /// interception chain.
- ///
- ///
- /// This s order in the
- /// interception chain.
- ///
- public virtual int Order
- {
- get { return this._order; }
- set { this._order = value; }
- }
-
- #endregion
-
- #region IAdvisor Members
-
- ///
- /// Return the advice part of this aspect.
- ///
- ///
- ///
- /// An advice may be an interceptor, a throws advice, before advice,
- /// introduction etc.
- ///
- ///
- ///
- /// The advice that should apply if the pointcut matches.
- ///
- public abstract IAdvice Advice { get; set; }
-
- ///
- /// Is this advice associated with a particular instance?
- ///
- ///
- ///
- /// Not supported for dynamic advisors.
- ///
- ///
- ///
- /// if this advice is associated with a
- /// particular instance.
- ///
- /// Always.
- ///
- public virtual bool IsPerInstance
- {
- get
- {
- throw new NotSupportedException(
- "The 'IsPerInstance' property of the IAdvisor interface " +
- "is not yet supported in Spring.NET.");
- }
- }
-
- #endregion
-
- #region IPointcutAdvisor Members
-
- ///
- /// The that drives this advisor.
- ///
- public abstract IPointcut Pointcut { get; set; }
-
- #endregion
-
- #region Methods
- ///
- /// Determines whether the specified
- /// is equal to the current .
- ///
- /// The advisor to compare with.
- ///
- /// if this instance is equal to the
- /// specified .
- ///
- public override bool Equals(object o)
- {
- if (!(o is AbstractPointcutAdvisor))
- {
- return false;
- }
- IPointcutAdvisor otherAdvisor = (IPointcutAdvisor)o;
- if (otherAdvisor.Advice == null && otherAdvisor.Pointcut == null)
- {
- return (this.Advice == null && this.Pointcut == null);
- }
- else if (otherAdvisor.Advice == null)
- {
- return (Advice == null && otherAdvisor.Pointcut.Equals(this.Pointcut));
- }
- else if (otherAdvisor.Pointcut == null)
- {
- return (this.Pointcut == null && otherAdvisor.Advice.Equals(this.Advice));
- }
- else
- {
- return otherAdvisor.Advice.Equals(this.Advice) && otherAdvisor.Pointcut.Equals(this.Pointcut);
- }
- }
-
- ///
- /// Serves as a hash function for a particular type, suitable for use
- /// in hashing algorithms and data structures like a hash table.
- ///
- ///
- /// A hash code for the current .
- ///
- public override int GetHashCode()
- {
- return 0 // (SPRNET-847) base.GetHashCode()
- + 13 * (Pointcut == null ? 0 : Pointcut.GetHashCode())
- + 27 * (Advice == null ? 0 : Advice.GetHashCode());
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 AopAlliance.Aop;
+using Spring.Core;
+
+namespace Spring.Aop.Support
+{
+ ///
+ /// Abstract base class for implementations.
+ ///
+ ///
+ /// Can be subclassed for returning a specific pointcut/advice or a freely configurable pointcut/advice.
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ [Serializable]
+ public abstract class AbstractPointcutAdvisor : IPointcutAdvisor, IOrdered
+ {
+ #region Fields
+
+ private int _order = Int32.MaxValue;
+
+ #endregion
+
+ #region IOrdered Members
+
+ ///
+ /// Returns this s order in the
+ /// interception chain.
+ ///
+ ///
+ /// This s order in the
+ /// interception chain.
+ ///
+ public virtual int Order
+ {
+ get { return this._order; }
+ set { this._order = value; }
+ }
+
+ #endregion
+
+ #region IAdvisor Members
+
+ ///
+ /// Return the advice part of this aspect.
+ ///
+ ///
+ ///
+ /// An advice may be an interceptor, a throws advice, before advice,
+ /// introduction etc.
+ ///
+ ///
+ ///
+ /// The advice that should apply if the pointcut matches.
+ ///
+ public abstract IAdvice Advice { get; set; }
+
+ ///
+ /// Is this advice associated with a particular instance?
+ ///
+ ///
+ ///
- /// The regular expressions must be a match. For example, the
- /// .*Get.* pattern will match Com.Mycom.Foo.GetBar(), and
- /// Get.* will not.
- ///
- ///
- /// This base class is serializable. Subclasses should decorate all
- /// fields with the - the
- ///
- /// method in this class will be invoked again on the client side on deserialization.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Simon White (.NET)
- [Serializable]
- public abstract class AbstractRegularExpressionMethodPointcut
- : StaticMethodMatcherPointcut, ITypeFilter, ISerializable
- {
- [NonSerialized]
- private object[] _patterns = ObjectUtils.EmptyObjects;
-
- #region Constructors
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- protected AbstractRegularExpressionMethodPointcut()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- ///
- /// If an error was encountered during the deserialization process.
- ///
- protected AbstractRegularExpressionMethodPointcut(
- SerializationInfo info, StreamingContext context)
- {
- _patterns = (object[]) info.GetValue("Patterns", typeof(object[]));
- try
- {
- InitPatternRepresentation(_patterns);
- }
- catch (Exception ex)
- {
- throw new AspectException(
- "Failed to deserialize AOP regular expression pointcut: " + ex.Message);
- }
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The for this pointcut.
- ///
- ///
- /// The current .
- ///
- public override ITypeFilter TypeFilter
- {
- get { return this; }
- }
-
- ///
- /// Convenience property for setting a single pattern.
- ///
- ///
- /// Use this property or Patterns, not both.
- ///
- public virtual object Pattern
- {
- get { return (_patterns.Length > 0 ? _patterns[0] : null); }
- set
- {
- AssertUtils.ArgumentNotNull(value, "Pattern");
- this.Patterns = new object[] {value};
- }
- }
-
- ///
- /// The regular expressions defining methods to match.
- ///
- ///
- /// Matching will be the union of all these; if any match,
- /// the pointcut matches.
- ///
- public virtual object[] Patterns
- {
- get { return _patterns; }
- set
- {
- AssertUtils.ArgumentNotNull(value, "Patterns");
- this._patterns = value;
- InitPatternRepresentation(this.Patterns);
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Populates a with
- /// the data needed to serialize the target object.
- ///
- ///
- /// The to populate
- /// with data.
- ///
- ///
- /// The destination (see )
- /// for this serialization.
- ///
- [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- info.AddValue("Patterns", _patterns);
- }
-
- ///
- /// Subclasses must implement this to initialize regular expression pointcuts.
- ///
- ///
- ///
- /// Can be invoked multiple times.
- ///
- ///
- /// This method will be invoked from the property,
- /// and also on deserialization.
- ///
- ///
- ///
- /// The patterns to initialize.
- ///
- ///
- /// In the case of an invalid pattern.
- ///
- protected abstract void InitPatternRepresentation(object[] patterns);
-
- ///
- /// Does the pattern at the supplied
- /// match this ?
- ///
- /// The pattern to match
- /// The index of pattern.
- ///
- /// if there is a match.
- ///
- protected abstract bool Matches(string pattern, int patternIndex);
-
- ///
- /// Does the supplied satisfy this matcher?
- ///
- ///
- ///
- /// Try to match the regular expression against the fully qualified name
- /// of the method's declaring , plus the name of
- /// the supplied .
- ///
- ///
- /// Note that the declaring is that
- /// that originally declared
- /// the method, not necessarily the that is
- /// currently exposing it. For example,
- /// matches any subclass of 's
- /// method.
- ///
- ///
- /// The candidate method.
- ///
- /// The target (may be ,
- /// in which case the candidate must be taken
- /// to be the 's declaring class).
- ///
- ///
- /// if this this method matches statically.
- ///
- public override bool Matches(MethodInfo method, Type targetType)
- {
- string patt = method.DeclaringType.FullName + "." + method.Name;
- for (int i = 0; i < this.Patterns.Length; ++i)
- {
- bool matched = Matches(patt, i);
- if (matched)
- {
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Should the pointcut apply to the supplied
- /// ?
- ///
- ///
- ///
+ /// The regular expressions must be a match. For example, the
+ /// .*Get.* pattern will match Com.Mycom.Foo.GetBar(), and
+ /// Get.* will not.
+ ///
+ ///
+ /// This base class is serializable. Subclasses should decorate all
+ /// fields with the - the
+ ///
+ /// method in this class will be invoked again on the client side on deserialization.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ [Serializable]
+ public abstract class AbstractRegularExpressionMethodPointcut
+ : StaticMethodMatcherPointcut, ITypeFilter, ISerializable
+ {
+ [NonSerialized]
+ private object[] _patterns = ObjectUtils.EmptyObjects;
+
+ #region Constructors
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ protected AbstractRegularExpressionMethodPointcut()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ ///
+ /// If an error was encountered during the deserialization process.
+ ///
+ protected AbstractRegularExpressionMethodPointcut(
+ SerializationInfo info, StreamingContext context)
+ {
+ _patterns = (object[]) info.GetValue("Patterns", typeof(object[]));
+ try
+ {
+ InitPatternRepresentation(_patterns);
+ }
+ catch (Exception ex)
+ {
+ throw new AspectException(
+ "Failed to deserialize AOP regular expression pointcut: " + ex.Message);
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The for this pointcut.
+ ///
+ ///
+ /// The current .
+ ///
+ public override ITypeFilter TypeFilter
+ {
+ get { return this; }
+ }
+
+ ///
+ /// Convenience property for setting a single pattern.
+ ///
+ ///
+ /// Use this property or Patterns, not both.
+ ///
+ public virtual object Pattern
+ {
+ get { return (_patterns.Length > 0 ? _patterns[0] : null); }
+ set
+ {
+ AssertUtils.ArgumentNotNull(value, "Pattern");
+ this.Patterns = new object[] {value};
+ }
+ }
+
+ ///
+ /// The regular expressions defining methods to match.
+ ///
+ ///
+ /// Matching will be the union of all these; if any match,
+ /// the pointcut matches.
+ ///
+ public virtual object[] Patterns
+ {
+ get { return _patterns; }
+ set
+ {
+ AssertUtils.ArgumentNotNull(value, "Patterns");
+ this._patterns = value;
+ InitPatternRepresentation(this.Patterns);
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Populates a with
+ /// the data needed to serialize the target object.
+ ///
+ ///
+ /// The to populate
+ /// with data.
+ ///
+ ///
+ /// The destination (see )
+ /// for this serialization.
+ ///
+ [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ info.AddValue("Patterns", _patterns);
+ }
+
+ ///
+ /// Subclasses must implement this to initialize regular expression pointcuts.
+ ///
+ ///
+ ///
+ /// Can be invoked multiple times.
+ ///
+ ///
+ /// This method will be invoked from the property,
+ /// and also on deserialization.
+ ///
+ ///
+ ///
+ /// The patterns to initialize.
+ ///
+ ///
+ /// In the case of an invalid pattern.
+ ///
+ protected abstract void InitPatternRepresentation(object[] patterns);
+
+ ///
+ /// Does the pattern at the supplied
+ /// match this ?
+ ///
+ /// The pattern to match
+ /// The index of pattern.
+ ///
+ /// if there is a match.
+ ///
+ protected abstract bool Matches(string pattern, int patternIndex);
+
+ ///
+ /// Does the supplied satisfy this matcher?
+ ///
+ ///
+ ///
+ /// Try to match the regular expression against the fully qualified name
+ /// of the method's declaring , plus the name of
+ /// the supplied .
+ ///
+ ///
+ /// Note that the declaring is that
+ /// that originally declared
+ /// the method, not necessarily the that is
+ /// currently exposing it. For example,
+ /// matches any subclass of 's
+ /// method.
+ ///
+ ///
+ /// The candidate method.
+ ///
+ /// The target (may be ,
+ /// in which case the candidate must be taken
+ /// to be the 's declaring class).
+ ///
+ ///
+ /// if this this method matches statically.
+ ///
+ public override bool Matches(MethodInfo method, Type targetType)
+ {
+ string patt = method.DeclaringType.FullName + "." + method.Name;
+ for (int i = 0; i < this.Patterns.Length; ++i)
+ {
+ bool matched = Matches(patt, i);
+ if (matched)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Should the pointcut apply to the supplied
+ /// ?
+ ///
+ ///
+ ///
+ /// In this instance, simply returns .
+ ///
+ ///
+ ///
+ /// The candidate .
+ ///
+ ///
+ /// if the advice should apply to the supplied
+ ///
+ ///
+ public bool Matches(Type type)
+ {
+ return true;
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs
index 70decf3e..254bb009 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcut.cs
@@ -1,204 +1,203 @@
-#region License
-
-/*
-* Copyright 2002-2004 the original author or authors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Reflection;
-using Spring.Util;
-
-#endregion
-
-namespace Spring.Aop.Support
-{
- ///
- /// implementation that matches methods
- /// that have been decorated with a specified .
- ///
- /// Aleksandar Seovic
- /// Ronald Wildenberg
- /// $Id: AttributeMatchMethodPointcut.cs,v 1.8 2007/05/21 16:43:45 bbaia Exp $
- [Serializable]
- public class AttributeMatchMethodPointcut : StaticMethodMatcherPointcut
- {
- private Type _attribute;
- private bool _inherit = true;
- private bool _checkInterfaces = false;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public AttributeMatchMethodPointcut()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The to match.
- ///
- public AttributeMatchMethodPointcut(Type attribute)
- : this(attribute, true, false)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The to match.
- ///
- ///
- /// Flag that controls whether or not the inheritance tree of the
- /// method to be included in the search for the ?
- ///
- public AttributeMatchMethodPointcut(Type attribute, bool inherit)
- : this(attribute, inherit, false)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The to match.
- ///
- ///
- /// Flag that controls whether or not the inheritance tree of the
- /// method to be included in the search for the ?
- ///
- ///
- /// Flag that controls whether or not interfaces attributes of the
- /// method to be included in the search for the ?
- ///
- public AttributeMatchMethodPointcut(Type attribute, bool inherit, bool checkInterfaces)
- {
- Attribute = attribute;
- Inherit = inherit;
- CheckInterfaces = checkInterfaces;
- }
-
- ///
- /// The to match.
- ///
- ///
- /// If the supplied value is not a that
- /// derives from the class.
- ///
- public virtual Type Attribute
- {
- get { return _attribute; }
- set
- {
- if (value != null)
- {
- if (!typeof (Attribute).IsAssignableFrom(value))
- {
- throw new ArgumentException(
- string.Format(
- "The [{0}] Type must be derived from the [System.Attribute] class.",
- value));
- }
- }
- _attribute = value;
- }
- }
-
- ///
- /// Is the inheritance tree of the method to be included in the search for the
- /// ?
- ///
- ///
- ///
- /// The default is .
- ///
- ///
- public virtual bool Inherit
- {
- get { return _inherit; }
- set { _inherit = value; }
- }
-
- ///
- /// Is the interfaces attributes of the method to be included in the search for the
- /// ?
- ///
- ///
- ///
- /// The default is .
- ///
- ///
- public virtual bool CheckInterfaces
- {
- get { return _checkInterfaces; }
- set { _checkInterfaces = value; }
- }
-
- ///
- /// Does the supplied satisfy this matcher?
- ///
- /// The candidate method.
- ///
- /// The target (may be ,
- /// in which case the candidate must be taken
- /// to be the 's declaring class).
- ///
- ///
- /// if this this method matches statically.
- ///
- public override bool Matches(MethodInfo method, Type targetType)
- {
- if (method.IsDefined(Attribute, Inherit))
- {
- // Checks whether the attribute is defined on the method or a super definition of the method
- // but does not check attributes on implemented interfaces.
- return true;
- }
- else
- {
- if (CheckInterfaces)
- {
- Type[] parameterTypes = ReflectionUtils.GetParameterTypes(method);
-
- // Also check whether the attribute is defined on a method implemented from an interface.
- // First find all interfaces for the type that contains the method.
- // Next, check each interface for the presence of the attribute on the corresponding
- // method from the interface.
- foreach (Type interfaceType in method.DeclaringType.GetInterfaces())
- {
- MethodInfo intfMethod = interfaceType.GetMethod(method.Name, parameterTypes);
- if (intfMethod != null && intfMethod.IsDefined(Attribute, Inherit))
- {
- return true;
- }
- }
- }
- return false;
- }
- }
- }
+#region License
+
+/*
+* Copyright 2002-2004 the original author or authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Reflection;
+using Spring.Util;
+
+#endregion
+
+namespace Spring.Aop.Support
+{
+ ///
+ /// implementation that matches methods
+ /// that have been decorated with a specified .
+ ///
+ /// Aleksandar Seovic
+ /// Ronald Wildenberg
+ [Serializable]
+ public class AttributeMatchMethodPointcut : StaticMethodMatcherPointcut
+ {
+ private Type _attribute;
+ private bool _inherit = true;
+ private bool _checkInterfaces = false;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public AttributeMatchMethodPointcut()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The to match.
+ ///
+ public AttributeMatchMethodPointcut(Type attribute)
+ : this(attribute, true, false)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// Flag that controls whether or not the inheritance tree of the
+ /// method to be included in the search for the ?
+ ///
+ public AttributeMatchMethodPointcut(Type attribute, bool inherit)
+ : this(attribute, inherit, false)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// Flag that controls whether or not the inheritance tree of the
+ /// method to be included in the search for the ?
+ ///
+ ///
+ /// Flag that controls whether or not interfaces attributes of the
+ /// method to be included in the search for the ?
+ ///
+ public AttributeMatchMethodPointcut(Type attribute, bool inherit, bool checkInterfaces)
+ {
+ Attribute = attribute;
+ Inherit = inherit;
+ CheckInterfaces = checkInterfaces;
+ }
+
+ ///
+ /// The to match.
+ ///
+ ///
+ /// If the supplied value is not a that
+ /// derives from the class.
+ ///
+ public virtual Type Attribute
+ {
+ get { return _attribute; }
+ set
+ {
+ if (value != null)
+ {
+ if (!typeof (Attribute).IsAssignableFrom(value))
+ {
+ throw new ArgumentException(
+ string.Format(
+ "The [{0}] Type must be derived from the [System.Attribute] class.",
+ value));
+ }
+ }
+ _attribute = value;
+ }
+ }
+
+ ///
+ /// Is the inheritance tree of the method to be included in the search for the
+ /// ?
+ ///
+ ///
+ ///
+ /// The default is .
+ ///
+ ///
+ public virtual bool Inherit
+ {
+ get { return _inherit; }
+ set { _inherit = value; }
+ }
+
+ ///
+ /// Is the interfaces attributes of the method to be included in the search for the
+ /// ?
+ ///
+ ///
+ ///
- /// Evaluating such pointcuts is slower than evaluating normal pointcuts,
- /// but can nevertheless be useful in some cases. Of course, your mileage
- /// may vary as to what 'slower' actually means.
- ///
- ///
- /// Rod Johnson
- /// Simon White (.NET)
- /// $Id: ControlFlowPointcut.cs,v 1.6 2006/04/09 07:18:37 markpollack Exp $
- [Serializable]
- public class ControlFlowPointcut : IPointcut, ITypeFilter, IMethodMatcher
- {
- #region Fields
-
- private Type _type;
- private string _methodName;
- private int _evaluationCount;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The class under which all control flows are to be matched.
- ///
- public ControlFlowPointcut(Type type) : this(type, null)
- {
- }
-
- ///
- /// Construct a new pointcut that matches all calls below the
- /// given method in the given class.
- ///
- ///
- ///
- /// If the supplied is
- /// , all control flows below the given
- /// class will be successfully matched.
- ///
- ///
- ///
- /// The class under which all control flows are to be matched.
- ///
- ///
- /// The method name under which all control flows are to be matched.
- ///
- public ControlFlowPointcut(Type type, string methodName)
- {
- _type = type;
- _methodName = methodName;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The for this pointcut.
- ///
- ///
- /// The current .
- ///
- public ITypeFilter TypeFilter
- {
- get { return this; }
- }
-
- ///
- /// Gets the number of times this pointcut has been evaluated.
- ///
- ///
- ///
- /// Useful as a debugging aid.
- ///
- ///
- /// Note that this value is distinct from the number of times that this
- /// pointcut sucessfully matches a target method, in that a
- /// may be evaluated many times but
- /// never actually match even once.
- ///
- ///
- ///
- /// The number of times this pointcut has been evaluated.
- ///
- public int EvaluationCount
- {
- get { return _evaluationCount; }
- }
-
- ///
- /// The for this pointcut.
- ///
- ///
- /// The current .
- ///
- public IMethodMatcher MethodMatcher
- {
- get { return this; }
- }
-
- ///
- /// Is this a runtime pointcut?
- ///
- ///
- ///
- /// This implementation is a runtime pointcut, and so always returns
- /// .
- ///
- ///
- ///
- /// if this is a runtime pointcut.
- ///
- ///
- public bool IsRuntime
- {
- get { return true; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Should the pointcut apply to the supplied ?
- ///
- ///
- ///
- /// Subclasses are encouraged to override this method for greater
- /// filtering (and performance).
- ///
- ///
- /// The candidate target class.
- ///
- /// if the advice should apply to the supplied
- ///
- ///
- public virtual bool Matches(Type type)
- {
- return true;
- }
-
- ///
- /// Does the supplied satisfy this matcher?
- /// Perform static checking. If this returns false, or if the isRuntime() method
- /// returns false, no runtime check will be made.
- ///
- ///
- ///
- /// Subclasses are encouraged to override this method if it is possible
- /// to filter out some candidate classes.
- ///
- ///
- /// This, the default, implementation always matches (returns
- /// ). This means that the three argument
- ///
- /// method will always be invoked.
- ///
- ///
- /// The candidate method.
- ///
- /// The target class (may be , in which case the
- /// candidate class must be taken to be the 's
- /// declaring class).
- ///
- ///
- /// if this this method matches statically.
- ///
- ///
- public virtual bool Matches(MethodInfo method, Type targetType)
- {
- return true;
- }
-
- ///
- /// Is there a runtime (dynamic) match for the supplied
- /// ?
- ///
- ///
- ///
- /// Subclasses are encouraged to override this method if it is possible
- /// to filter out some candidate classes.
- ///
+ /// Evaluating such pointcuts is slower than evaluating normal pointcuts,
+ /// but can nevertheless be useful in some cases. Of course, your mileage
+ /// may vary as to what 'slower' actually means.
+ ///
+ ///
+ /// Rod Johnson
+ /// Simon White (.NET)
+ [Serializable]
+ public class ControlFlowPointcut : IPointcut, ITypeFilter, IMethodMatcher
+ {
+ #region Fields
+
+ private Type _type;
+ private string _methodName;
+ private int _evaluationCount;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The class under which all control flows are to be matched.
+ ///
+ public ControlFlowPointcut(Type type) : this(type, null)
+ {
+ }
+
+ ///
+ /// Construct a new pointcut that matches all calls below the
+ /// given method in the given class.
+ ///
+ ///
+ ///
+ /// If the supplied is
+ /// , all control flows below the given
+ /// class will be successfully matched.
+ ///
+ ///
+ ///
+ /// The class under which all control flows are to be matched.
+ ///
+ ///
+ /// The method name under which all control flows are to be matched.
+ ///
+ public ControlFlowPointcut(Type type, string methodName)
+ {
+ _type = type;
+ _methodName = methodName;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The for this pointcut.
+ ///
+ ///
+ /// The current .
+ ///
+ public ITypeFilter TypeFilter
+ {
+ get { return this; }
+ }
+
+ ///
+ /// Gets the number of times this pointcut has been evaluated.
+ ///
+ ///
+ ///
+ /// Useful as a debugging aid.
+ ///
+ ///
+ /// Note that this value is distinct from the number of times that this
+ /// pointcut sucessfully matches a target method, in that a
+ /// may be evaluated many times but
+ /// never actually match even once.
+ ///
+ ///
+ ///
+ /// The number of times this pointcut has been evaluated.
+ ///
+ public int EvaluationCount
+ {
+ get { return _evaluationCount; }
+ }
+
+ ///
+ /// The for this pointcut.
+ ///
+ ///
+ /// The current .
+ ///
+ public IMethodMatcher MethodMatcher
+ {
+ get { return this; }
+ }
+
+ ///
+ /// Is this a runtime pointcut?
+ ///
+ ///
+ ///
+ /// This implementation is a runtime pointcut, and so always returns
+ /// .
+ ///
+ ///
+ ///
+ /// if this is a runtime pointcut.
+ ///
+ ///
+ public bool IsRuntime
+ {
+ get { return true; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Should the pointcut apply to the supplied ?
+ ///
+ ///
+ ///
+ /// Subclasses are encouraged to override this method for greater
+ /// filtering (and performance).
+ ///
+ ///
+ /// The candidate target class.
+ ///
+ /// if the advice should apply to the supplied
+ ///
+ ///
+ public virtual bool Matches(Type type)
+ {
+ return true;
+ }
+
+ ///
+ /// Does the supplied satisfy this matcher?
+ /// Perform static checking. If this returns false, or if the isRuntime() method
+ /// returns false, no runtime check will be made.
+ ///
+ ///
+ ///
+ /// Subclasses are encouraged to override this method if it is possible
+ /// to filter out some candidate classes.
+ ///
+ ///
+ /// This, the default, implementation always matches (returns
+ /// ). This means that the three argument
+ ///
+ /// method will always be invoked.
+ ///
+ ///
+ /// The candidate method.
+ ///
+ /// The target class (may be , in which case the
+ /// candidate class must be taken to be the 's
+ /// declaring class).
+ ///
+ ///
+ /// if this this method matches statically.
+ ///
+ ///
+ public virtual bool Matches(MethodInfo method, Type targetType)
+ {
+ return true;
+ }
+
+ ///
+ /// Is there a runtime (dynamic) match for the supplied
+ /// ?
+ ///
+ ///
+ ///
+ /// Subclasses are encouraged to override this method if it is possible
+ /// to filter out some candidate classes.
+ ///
- /// This constructor adds all interfaces implemented by the supplied
- /// (except the
- /// interface) to the list of
- /// interfaces to introduce.
- ///
- ///
- /// The introduction to use.
- public DefaultIntroductionAdvisor(IAdvice introduction)
- : this(introduction, introduction.GetType().GetInterfaces())
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class using
- /// the supplied
- ///
- /// The introduction to use.
- ///
- /// The interface to introduce.
- ///
- public DefaultIntroductionAdvisor(IAdvice introduction, Type intf)
- : this(introduction, new Type[] {intf})
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class using
- /// the supplied
- ///
- /// The introduction to use.
- ///
- /// The interfaces to introduce.
- ///
- ///
- /// If the supplied is .
- ///
- public DefaultIntroductionAdvisor(IAdvice introduction, Type[] interfaces)
- {
- if (introduction == null)
- {
- throw new ArgumentNullException("introduction", "Introduction cannot be null");
- }
- _introduction = introduction;
- foreach (Type intf in interfaces)
- {
- if (intf != typeof (IAdvice))
- {
- AddInterface(intf);
- }
- }
- }
-
- ///
- /// Returns the filter determining which target classes this
- /// introduction should apply to.
- ///
- ///
- /// The filter determining which target classes this introduction
- /// should apply to.
- ///
- public virtual ITypeFilter TypeFilter
- {
- get { return this; }
- }
-
- ///
- /// Gets the interfaces introduced by this
- /// .
- ///
- ///
- /// The interfaces introduced by this
- /// .
- ///
- public virtual Type[] Interfaces
- {
- get
- {
- Type[] interfaces = new Type[_interfaces.Count];
- _interfaces.CopyTo(interfaces, 0);
- return interfaces;
- }
- }
-
- ///
- /// Is this advice associated with a particular instance?
- ///
- ///
- ///
- /// Default for an introduction is per-instance interception.
- ///
- ///
- ///
- /// if this advice is associated with a
- /// particular instance.
- ///
- public virtual bool IsPerInstance
- {
- get { return true; }
- }
-
- ///
- /// Return the advice part of this aspect.
- ///
- ///
- /// The advice that should apply if the pointcut matches.
- ///
- public virtual IAdvice Advice
- {
- get { return this._introduction; }
- }
-
- ///
- /// Adds the supplied to the list of
- /// introduced interfaces.
- ///
- /// The interface to add.
- ///
- /// If any of the are not interface .
- ///
- public virtual void AddInterface(Type intf)
- {
- if(intf != null)
- {
- BailIfNotAnInterfaceType(intf);
- _interfaces.Add(intf);
- }
- }
-
- ///
- /// Should the pointcut apply to the supplied
- /// ?
- ///
- ///
- ///
+ /// This constructor adds all interfaces implemented by the supplied
+ /// (except the
+ /// interface) to the list of
+ /// interfaces to introduce.
+ ///
+ ///
+ /// The introduction to use.
+ public DefaultIntroductionAdvisor(IAdvice introduction)
+ : this(introduction, introduction.GetType().GetInterfaces())
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class using
+ /// the supplied
+ ///
+ /// The introduction to use.
+ ///
+ /// The interface to introduce.
+ ///
+ public DefaultIntroductionAdvisor(IAdvice introduction, Type intf)
+ : this(introduction, new Type[] {intf})
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class using
+ /// the supplied
+ ///
+ /// The introduction to use.
+ ///
+ /// The interfaces to introduce.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public DefaultIntroductionAdvisor(IAdvice introduction, Type[] interfaces)
+ {
+ if (introduction == null)
+ {
+ throw new ArgumentNullException("introduction", "Introduction cannot be null");
+ }
+ _introduction = introduction;
+ foreach (Type intf in interfaces)
+ {
+ if (intf != typeof (IAdvice))
+ {
+ AddInterface(intf);
+ }
+ }
+ }
+
+ ///
+ /// Returns the filter determining which target classes this
+ /// introduction should apply to.
+ ///
+ ///
+ /// The filter determining which target classes this introduction
+ /// should apply to.
+ ///
+ public virtual ITypeFilter TypeFilter
+ {
+ get { return this; }
+ }
+
+ ///
+ /// Gets the interfaces introduced by this
+ /// .
+ ///
+ ///
+ /// The interfaces introduced by this
+ /// .
+ ///
+ public virtual Type[] Interfaces
+ {
+ get
+ {
+ Type[] interfaces = new Type[_interfaces.Count];
+ _interfaces.CopyTo(interfaces, 0);
+ return interfaces;
+ }
+ }
+
+ ///
+ /// Is this advice associated with a particular instance?
+ ///
+ ///
+ ///
+ /// Default for an introduction is per-instance interception.
+ ///
+ ///
+ ///
+ /// if this advice is associated with a
+ /// particular instance.
+ ///
+ public virtual bool IsPerInstance
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Return the advice part of this aspect.
+ ///
+ ///
+ /// The advice that should apply if the pointcut matches.
+ ///
+ public virtual IAdvice Advice
+ {
+ get { return this._introduction; }
+ }
+
+ ///
+ /// Adds the supplied to the list of
+ /// introduced interfaces.
+ ///
+ /// The interface to add.
+ ///
+ /// If any of the are not interface .
+ ///
+ public virtual void AddInterface(Type intf)
+ {
+ if(intf != null)
+ {
+ BailIfNotAnInterfaceType(intf);
+ _interfaces.Add(intf);
+ }
+ }
+
+ ///
+ /// Should the pointcut apply to the supplied
+ /// ?
+ ///
+ ///
+ ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected DynamicMethodMatcher()
- {
- }
-
- #endregion
-
- ///
- /// Is this dynamic?
- ///
- ///
- /// Always returns , to specify that this is a
- /// dynamic matcher.
- ///
- public virtual bool IsRuntime
- {
- get { return true; }
- }
-
- ///
- /// Does the supplied satisfy this matcher?
- ///
- ///
- ///
- /// Derived classes can override this method to add preconditions for
- /// dynamic matching.
- ///
- ///
- /// This implementation always returns .
- ///
- ///
- /// The candidate method.
- ///
- /// The target (may be ,
- /// in which case the candidate must be taken
- /// to be the 's declaring class).
- ///
- ///
- /// if this this method matches statically.
- ///
- public virtual bool Matches(MethodInfo method, Type targetType)
- {
- return true;
- }
-
- ///
- /// Is there a runtime (dynamic) match for the supplied
- /// ?
- ///
- ///
- ///
- /// Must be overriden by derived classes to provide criteria for dynamic matching.
- ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected DynamicMethodMatcher()
+ {
+ }
+
+ #endregion
+
+ ///
+ /// Is this dynamic?
+ ///
+ ///
+ /// Always returns , to specify that this is a
+ /// dynamic matcher.
+ ///
+ public virtual bool IsRuntime
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Does the supplied satisfy this matcher?
+ ///
+ ///
+ ///
+ /// Derived classes can override this method to add preconditions for
+ /// dynamic matching.
+ ///
+ ///
+ /// This implementation always returns .
+ ///
+ ///
+ /// The candidate method.
+ ///
+ /// The target (may be ,
+ /// in which case the candidate must be taken
+ /// to be the 's declaring class).
+ ///
+ ///
+ /// if this this method matches statically.
+ ///
+ public virtual bool Matches(MethodInfo method, Type targetType)
+ {
+ return true;
+ }
+
+ ///
+ /// Is there a runtime (dynamic) match for the supplied
+ /// ?
+ ///
+ ///
+ ///
+ /// Must be overriden by derived classes to provide criteria for dynamic matching.
+ ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- protected DynamicMethodMatcherPointcutAdvisor()
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class for the supplied .
- ///
- ///
- ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- ///
- /// The advice portion of this advisor.
- ///
- protected DynamicMethodMatcherPointcutAdvisor(IAdvice advice)
- {
- this._advice = advice;
- }
-
- ///
- /// Is this advice associated with a particular instance?
- ///
- ///
- ///
- /// Not supported for dynamic advisors.
- ///
- ///
- ///
- /// if this advice is associated with a
- /// particular instance.
- ///
- /// Always.
- ///
- public virtual bool IsPerInstance
- {
- get
- {
- throw new NotSupportedException(
- "The 'IsPerInstance' property of the IAdvisor interface " +
- "is not yet supported in Spring.NET.");
- }
- }
-
- ///
- /// The for this pointcut.
- ///
- ///
- ///
- /// This implementation always returns a filter that evaluates to
- /// for any .
- ///
- ///
- ///
- /// The current .
- ///
- public virtual ITypeFilter TypeFilter
- {
- get { return TrueTypeFilter.True; }
- }
-
- ///
- /// The for this pointcut.
- ///
- ///
- ///
- ///
- ///
- /// The current .
- ///
- public virtual IMethodMatcher MethodMatcher
- {
- get { return this; }
- }
-
- ///
- /// Returns this s order in the
- /// interception chain.
- ///
- ///
- /// This s order in the
- /// interception chain.
- ///
- public virtual int Order
- {
- get { return this._order; }
- set { this._order = value; }
- }
-
- ///
- /// Return the advice part of this aspect.
- ///
- ///
- /// The advice that should apply if the pointcut matches.
- ///
- ///
- public virtual IAdvice Advice
- {
- get { return this._advice; }
- set { this._advice = value; }
- }
-
- ///
- /// The that drives this advisor.
- ///
- ///
- ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ protected DynamicMethodMatcherPointcutAdvisor()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class for the supplied .
+ ///
+ ///
+ ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ ///
+ /// The advice portion of this advisor.
+ ///
+ protected DynamicMethodMatcherPointcutAdvisor(IAdvice advice)
+ {
+ this._advice = advice;
+ }
+
+ ///
+ /// Is this advice associated with a particular instance?
+ ///
+ ///
+ ///
+ /// Not supported for dynamic advisors.
+ ///
+ ///
+ ///
+ /// if this advice is associated with a
+ /// particular instance.
+ ///
+ /// Always.
+ ///
+ public virtual bool IsPerInstance
+ {
+ get
+ {
+ throw new NotSupportedException(
+ "The 'IsPerInstance' property of the IAdvisor interface " +
+ "is not yet supported in Spring.NET.");
+ }
+ }
+
+ ///
+ /// The for this pointcut.
+ ///
+ ///
+ ///
+ /// This implementation always returns a filter that evaluates to
+ /// for any .
+ ///
+ ///
+ ///
+ /// The current .
+ ///
+ public virtual ITypeFilter TypeFilter
+ {
+ get { return TrueTypeFilter.True; }
+ }
+
+ ///
+ /// The for this pointcut.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The current .
+ ///
+ public virtual IMethodMatcher MethodMatcher
+ {
+ get { return this; }
+ }
+
+ ///
+ /// Returns this s order in the
+ /// interception chain.
+ ///
+ ///
+ /// This s order in the
+ /// interception chain.
+ ///
+ public virtual int Order
+ {
+ get { return this._order; }
+ set { this._order = value; }
+ }
+
+ ///
+ /// Return the advice part of this aspect.
+ ///
+ ///
+ /// The advice that should apply if the pointcut matches.
+ ///
+ ///
+ public virtual IAdvice Advice
+ {
+ get { return this._advice; }
+ set { this._advice = value; }
+ }
+
+ ///
+ /// The that drives this advisor.
+ ///
+ ///
+ ///
- /// A method matcher may be evaluated statically (based on method and target
- /// class) or need further evaluation dynamically (based on arguments at
- /// the time of method invocation).
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: MethodMatchers.cs,v 1.7 2007/03/16 04:01:24 aseovic Exp $
- public sealed class MethodMatchers
- {
- ///
- /// Creates a new that is the
- /// union of the two supplied s.
- ///
- ///
- ///
- /// The newly created matcher will match all the methods that either of the two
- /// supplied matchers would match.
- ///
- ///
- /// The first method matcher.
- /// The second method matcher.
- ///
- /// A new that is the
- /// union of the two supplied s
- ///
- public static IMethodMatcher Union(
- IMethodMatcher firstMatcher, IMethodMatcher secondMatcher)
- {
- return new UnionMethodMatcher(firstMatcher, secondMatcher);
- }
-
- ///
- /// Creates a new that is the
- /// intersection of the two supplied s.
- ///
- ///
- ///
- /// The newly created matcher will match only those methods that both
- /// of the supplied matchers would match.
- ///
- ///
- /// The first method matcher.
- /// The second method matcher.
- ///
- /// A new that is the
- /// intersection of the two supplied s
- ///
- public static IMethodMatcher Intersection(
- IMethodMatcher firstMatcher, IMethodMatcher secondMatcher)
- {
- return new IntersectionMethodMatcher(firstMatcher, secondMatcher);
- }
-
- #region Inner Class : UnionMethodMatcher
-
- [Serializable]
- private sealed class UnionMethodMatcher : IMethodMatcher
- {
- private IMethodMatcher a;
- private IMethodMatcher b;
-
- public UnionMethodMatcher(IMethodMatcher a, IMethodMatcher b)
- {
- this.a = a;
- this.b = b;
- }
-
- public bool IsRuntime
- {
- get { return a.IsRuntime || b.IsRuntime; }
- }
-
- public bool Matches(MethodInfo m, Type targetType)
- {
- return a.Matches(m, targetType) || b.Matches(m, targetType);
- }
-
- public bool Matches(MethodInfo m, Type targetType, object[] args)
- {
- return a.Matches(m, targetType, args) || b.Matches(m, targetType, args);
- }
- }
-
- #endregion
-
- #region Inner Class : IntersectionMethodMatcher
-
- [Serializable]
- private sealed class IntersectionMethodMatcher : IMethodMatcher
- {
- private IMethodMatcher a;
- private IMethodMatcher b;
-
- public IntersectionMethodMatcher(IMethodMatcher a, IMethodMatcher b)
- {
- this.a = a;
- this.b = b;
- }
-
- public bool IsRuntime
- {
- get { return a.IsRuntime || b.IsRuntime; }
- }
-
- public bool Matches(MethodInfo m, Type targetType)
- {
- return a.Matches(m, targetType) && b.Matches(m, targetType);
- }
-
- public bool Matches(MethodInfo m, Type targetType, object[] args)
- {
- // Because a dynamic intersection may be composed of a static and dynamic part,
- // we must avoid calling the 3-arg matches method on a dynamic matcher, as
- // it will probably be an unsupported operation.
- bool aMatches = a.IsRuntime ? a.Matches(m, targetType, args) : a.Matches(m, targetType);
- bool bMatches = b.IsRuntime ? b.Matches(m, targetType, args) : b.Matches(m, targetType);
- return aMatches && bMatches;
- }
- }
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly
- /// visible constructors.
- ///
+ /// A method matcher may be evaluated statically (based on method and target
+ /// class) or need further evaluation dynamically (based on arguments at
+ /// the time of method invocation).
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public sealed class MethodMatchers
+ {
+ ///
+ /// Creates a new that is the
+ /// union of the two supplied s.
+ ///
+ ///
+ ///
+ /// The newly created matcher will match all the methods that either of the two
+ /// supplied matchers would match.
+ ///
+ ///
+ /// The first method matcher.
+ /// The second method matcher.
+ ///
+ /// A new that is the
+ /// union of the two supplied s
+ ///
+ public static IMethodMatcher Union(
+ IMethodMatcher firstMatcher, IMethodMatcher secondMatcher)
+ {
+ return new UnionMethodMatcher(firstMatcher, secondMatcher);
+ }
+
+ ///
+ /// Creates a new that is the
+ /// intersection of the two supplied s.
+ ///
+ ///
+ ///
+ /// The newly created matcher will match only those methods that both
+ /// of the supplied matchers would match.
+ ///
+ ///
+ /// The first method matcher.
+ /// The second method matcher.
+ ///
+ /// A new that is the
+ /// intersection of the two supplied s
+ ///
+ public static IMethodMatcher Intersection(
+ IMethodMatcher firstMatcher, IMethodMatcher secondMatcher)
+ {
+ return new IntersectionMethodMatcher(firstMatcher, secondMatcher);
+ }
+
+ #region Inner Class : UnionMethodMatcher
+
+ [Serializable]
+ private sealed class UnionMethodMatcher : IMethodMatcher
+ {
+ private IMethodMatcher a;
+ private IMethodMatcher b;
+
+ public UnionMethodMatcher(IMethodMatcher a, IMethodMatcher b)
+ {
+ this.a = a;
+ this.b = b;
+ }
+
+ public bool IsRuntime
+ {
+ get { return a.IsRuntime || b.IsRuntime; }
+ }
+
+ public bool Matches(MethodInfo m, Type targetType)
+ {
+ return a.Matches(m, targetType) || b.Matches(m, targetType);
+ }
+
+ public bool Matches(MethodInfo m, Type targetType, object[] args)
+ {
+ return a.Matches(m, targetType, args) || b.Matches(m, targetType, args);
+ }
+ }
+
+ #endregion
+
+ #region Inner Class : IntersectionMethodMatcher
+
+ [Serializable]
+ private sealed class IntersectionMethodMatcher : IMethodMatcher
+ {
+ private IMethodMatcher a;
+ private IMethodMatcher b;
+
+ public IntersectionMethodMatcher(IMethodMatcher a, IMethodMatcher b)
+ {
+ this.a = a;
+ this.b = b;
+ }
+
+ public bool IsRuntime
+ {
+ get { return a.IsRuntime || b.IsRuntime; }
+ }
+
+ public bool Matches(MethodInfo m, Type targetType)
+ {
+ return a.Matches(m, targetType) && b.Matches(m, targetType);
+ }
+
+ public bool Matches(MethodInfo m, Type targetType, object[] args)
+ {
+ // Because a dynamic intersection may be composed of a static and dynamic part,
+ // we must avoid calling the 3-arg matches method on a dynamic matcher, as
+ // it will probably be an unsupported operation.
+ bool aMatches = a.IsRuntime ? a.Matches(m, targetType, args) : a.Matches(m, targetType);
+ bool bMatches = b.IsRuntime ? b.Matches(m, targetType, args) : b.Matches(m, targetType);
+ return aMatches && bMatches;
+ }
+ }
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly
+ /// visible constructors.
+ ///
- /// Matching will be the union of all these; if any match, the pointcut matches.
- ///
- ///
- public virtual string[] MappedNames
- {
- set { this._mappedNames = value; }
- }
-
- ///
- /// Does the of the supplied
- /// matches any of the mapped names?
- ///
- ///
- /// The to check.
- ///
- ///
- /// The of the target class.
- ///
- ///
- /// if the name of the supplied
- /// matches one of the mapped names.
- ///
- public override bool Matches(MethodInfo method, Type targetType)
- {
- for (int i = 0; i < this._mappedNames.Length; i++)
- {
- string mappedName = this._mappedNames[i];
- if (mappedName.Equals(method.Name) || IsMatch(method.Name, mappedName))
- {
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Does the supplied match the supplied ?
- ///
- ///
- ///
- /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
- /// as well as direct equality. Can be overridden in subclasses.
- ///
+ /// Matching will be the union of all these; if any match, the pointcut matches.
+ ///
+ ///
+ public virtual string[] MappedNames
+ {
+ set { this._mappedNames = value; }
+ }
+
+ ///
+ /// Does the of the supplied
+ /// matches any of the mapped names?
+ ///
+ ///
+ /// The to check.
+ ///
+ ///
+ /// The of the target class.
+ ///
+ ///
+ /// if the name of the supplied
+ /// matches one of the mapped names.
+ ///
+ public override bool Matches(MethodInfo method, Type targetType)
+ {
+ for (int i = 0; i < this._mappedNames.Length; i++)
+ {
+ string mappedName = this._mappedNames[i];
+ if (mappedName.Equals(method.Name) || IsMatch(method.Name, mappedName))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Does the supplied match the supplied ?
+ ///
+ ///
+ ///
+ /// The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
+ /// as well as direct equality. Can be overridden in subclasses.
+ ///
- /// These methods are particularly useful for composing pointcuts
- /// using the union and intersection methods.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: Pointcuts.cs,v 1.6 2007/03/16 04:01:25 aseovic Exp $
- public sealed class Pointcuts
- {
- ///
- /// Creates a union of the two supplied pointcuts.
- ///
- /// The first pointcut.
- /// The second pointcut.
- ///
- /// The union of the two supplied pointcuts.
- ///
- ///
- public static IPointcut Union(IPointcut firstPointcut, IPointcut secondPointcut)
- {
- return new UnionPointcut(firstPointcut, secondPointcut);
- }
-
- ///
- /// Creates an that is the
- /// intersection of the two supplied pointcuts.
- ///
- /// The first pointcut.
- /// The second pointcut.
- ///
- /// An that is the
- /// intersection of the two supplied pointcuts.
- ///
- public static IPointcut Intersection(IPointcut firstPointcut, IPointcut secondPointcut)
- {
- return new ComposablePointcut(
- firstPointcut.TypeFilter, firstPointcut.MethodMatcher)
- .Intersection(secondPointcut);
- }
-
- ///
- /// Performs the least expensive check for a match.
- ///
- ///
- /// The to be evaluated.
- ///
- /// The candidate method.
- ///
- /// The target .
- ///
- /// The arguments to the method
- /// if there is a runtime match.
- ///
- public static bool Matches(
- IPointcut pointcut, MethodInfo method, Type targetType, object[] args)
- {
- if(pointcut != null)
- {
- if (pointcut == TruePointcut.True)
- {
- return true;
- }
- if (pointcut.TypeFilter.Matches(targetType))
- {
- IMethodMatcher mm = pointcut.MethodMatcher;
- if (mm.Matches(method, targetType))
- {
- return mm.IsRuntime ? mm.Matches(method, targetType, args) : true;
- }
- }
- }
- return false;
- }
-
- ///
- /// Are the supplied s equal?
- ///
- /// The first pointcut.
- /// The second pointcut.
- ///
- /// if the supplied s
- /// are equal.
- ///
- public static bool AreEqual(IPointcut firstPointcut, IPointcut secondPointcut)
- {
- return firstPointcut.TypeFilter == secondPointcut.TypeFilter
- && firstPointcut.MethodMatcher == secondPointcut.MethodMatcher;
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly
- /// visible constructors.
- ///
+ /// These methods are particularly useful for composing pointcuts
+ /// using the union and intersection methods.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public sealed class Pointcuts
+ {
+ ///
+ /// Creates a union of the two supplied pointcuts.
+ ///
+ /// The first pointcut.
+ /// The second pointcut.
+ ///
+ /// The union of the two supplied pointcuts.
+ ///
+ ///
+ public static IPointcut Union(IPointcut firstPointcut, IPointcut secondPointcut)
+ {
+ return new UnionPointcut(firstPointcut, secondPointcut);
+ }
+
+ ///
+ /// Creates an that is the
+ /// intersection of the two supplied pointcuts.
+ ///
+ /// The first pointcut.
+ /// The second pointcut.
+ ///
+ /// An that is the
+ /// intersection of the two supplied pointcuts.
+ ///
+ public static IPointcut Intersection(IPointcut firstPointcut, IPointcut secondPointcut)
+ {
+ return new ComposablePointcut(
+ firstPointcut.TypeFilter, firstPointcut.MethodMatcher)
+ .Intersection(secondPointcut);
+ }
+
+ ///
+ /// Performs the least expensive check for a match.
+ ///
+ ///
+ /// The to be evaluated.
+ ///
+ /// The candidate method.
+ ///
+ /// The target .
+ ///
+ /// The arguments to the method
+ /// if there is a runtime match.
+ ///
+ public static bool Matches(
+ IPointcut pointcut, MethodInfo method, Type targetType, object[] args)
+ {
+ if(pointcut != null)
+ {
+ if (pointcut == TruePointcut.True)
+ {
+ return true;
+ }
+ if (pointcut.TypeFilter.Matches(targetType))
+ {
+ IMethodMatcher mm = pointcut.MethodMatcher;
+ if (mm.Matches(method, targetType))
+ {
+ return mm.IsRuntime ? mm.Matches(method, targetType, args) : true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Are the supplied s equal?
+ ///
+ /// The first pointcut.
+ /// The second pointcut.
+ ///
+ /// if the supplied s
+ /// are equal.
+ ///
+ public static bool AreEqual(IPointcut firstPointcut, IPointcut secondPointcut)
+ {
+ return firstPointcut.TypeFilter == secondPointcut.TypeFilter
+ && firstPointcut.MethodMatcher == secondPointcut.MethodMatcher;
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly
+ /// visible constructors.
+ ///
- /// Configure this class using the and
- /// pass-through properties. These are analogous
- /// to the and
- /// s properties of the
- /// class.
- ///
- ///
- /// Can delegate to any type of regular expression pointcut. Currently only
- /// pointcuts based on the regular expression classes from the .NET Base
- /// Class Library are supported. The
- ///
- /// property must be a subclass of the
- /// class.
- ///
- ///
- /// This should not normally be set directly.
- ///
+ /// Configure this class using the and
+ /// pass-through properties. These are analogous
+ /// to the and
+ /// s properties of the
+ /// class.
+ ///
+ ///
+ /// Can delegate to any type of regular expression pointcut. Currently only
+ /// pointcuts based on the regular expression classes from the .NET Base
+ /// Class Library are supported. The
+ ///
+ /// property must be a subclass of the
+ /// class.
+ ///
+ ///
+ /// This should not normally be set directly.
+ ///
+ /// Returns if the supplied
+ /// can be assigned to the root .
+ ///
+ ///
+ ///
+ /// The candidate .
+ ///
+ ///
+ /// if the advice should apply to the supplied
+ ///
+ ///
+ public virtual bool Matches(Type type)
+ {
+ return _rootType.IsAssignableFrom(type);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs b/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs
index fb7d5900..efda9cd1 100644
--- a/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/SdkRegularExpressionMethodPointcut.cs
@@ -1,207 +1,207 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-using System.Text.RegularExpressions;
-using Common.Logging;
-using Spring.Util;
-
-#endregion
-
-namespace Spring.Aop.Support
-{
- ///
- /// Regular expression based pointcut object.
- ///
- ///
- ///
- /// Uses the regular expression classes from the .NET Base Class Library.
- ///
- ///
- /// The regular expressions must be a match. For example, the
- /// .*Get* pattern will match Com.Mycom.Foo.GetBar(), and
- /// Get.* will not.
- ///
- ///
- /// Rod Johnson
- /// Simon White (.NET)
- [Serializable]
- public class SdkRegularExpressionMethodPointcut : AbstractRegularExpressionMethodPointcut
- {
- private ILog _logger = LogManager.GetLogger(typeof(SdkRegularExpressionMethodPointcut));
- private Regex[] _compiledPatterns = new Regex[0];
- private RegexOptions _defaultOptions = RegexOptions.None;
-
- #region Constructors
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public SdkRegularExpressionMethodPointcut()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class,
- /// using the supplied pattern or .
- ///
- ///
- /// The intial pattern value(s) to be matched against.
- ///
- public SdkRegularExpressionMethodPointcut(params string[] patterns)
- {
- Patterns = patterns;
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- ///
- /// If an error was encountered during the deserialization process.
- ///
- protected SdkRegularExpressionMethodPointcut(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets or sets default options that should be used by
- /// regular expressions that don't have options explicitly set.
- ///
- ///
- /// Default options that should be used by regular expressions
- /// that don't have options explicitly set.
- ///
- public RegexOptions DefaultOptions
- {
- get { return _defaultOptions; }
- set
- {
- _defaultOptions = value;
- InitPatternRepresentation(Patterns);
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Initializes the regular expression pointcuts.
- ///
- ///
- ///
- /// Can be invoked multiple times.
- ///
- ///
- /// This method will be invoked from the
- /// property,
- /// and also on deserialization.
- ///
- ///
- ///
- /// The patterns to initialize.
- ///
- ///
- /// In the case of an invalid pattern.
- ///
- ///
- /// If the supplied is .
- ///
- protected override void InitPatternRepresentation(object[] patterns)
- {
- AssertUtils.ArgumentNotNull(patterns, "patterns");
-
- if (patterns.Length > 0)
- {
- _compiledPatterns = new Regex[patterns.Length];
- for (int i = 0; i < patterns.Length; i++)
- {
- if (patterns[i] == null)
- {
- throw new ArgumentNullException(
- "Null is not a valid value for an element of the Patterns property.");
- }
- else if (patterns[i] is Regex)
- {
- _compiledPatterns[i] = (Regex)patterns[i];
- }
- else if (patterns[i] is string)
- {
- _compiledPatterns[i] = new Regex((string)patterns[i], DefaultOptions);
- }
- else
- {
- throw new ArgumentException(
- "You can only specify a string value or an instance of a Regex class " +
- "as an element of the 'Patterns' property.");
- }
- }
- }
- }
-
- ///
- /// Does the pattern at the supplied
- /// match this ?
- ///
- /// The pattern to match
- /// The index of pattern.
- ///
- /// if there is a match.
- ///
- protected override bool Matches(string pattern, int patternIndex)
- {
- Match match = _compiledPatterns[patternIndex].Match(pattern);
- bool matched = match.Success;
-
- #region Instrumentation
-
- if (_logger.IsDebugEnabled)
- {
- _logger.Debug("Candidate is: '" + pattern + "'; pattern is '" +
- _compiledPatterns[patternIndex].ToString() + "'; matched=" + matched);
- }
-
- #endregion
-
- return matched;
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+using System.Text.RegularExpressions;
+using Common.Logging;
+using Spring.Util;
+
+#endregion
+
+namespace Spring.Aop.Support
+{
+ ///
+ /// Regular expression based pointcut object.
+ ///
+ ///
+ ///
+ /// Uses the regular expression classes from the .NET Base Class Library.
+ ///
+ ///
+ /// The regular expressions must be a match. For example, the
+ /// .*Get* pattern will match Com.Mycom.Foo.GetBar(), and
+ /// Get.* will not.
+ ///
+ ///
+ /// Rod Johnson
+ /// Simon White (.NET)
+ [Serializable]
+ public class SdkRegularExpressionMethodPointcut : AbstractRegularExpressionMethodPointcut
+ {
+ private ILog _logger = LogManager.GetLogger(typeof(SdkRegularExpressionMethodPointcut));
+ private Regex[] _compiledPatterns = new Regex[0];
+ private RegexOptions _defaultOptions = RegexOptions.None;
+
+ #region Constructors
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public SdkRegularExpressionMethodPointcut()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class,
+ /// using the supplied pattern or .
+ ///
+ ///
+ /// The intial pattern value(s) to be matched against.
+ ///
+ public SdkRegularExpressionMethodPointcut(params string[] patterns)
+ {
+ Patterns = patterns;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ ///
+ /// If an error was encountered during the deserialization process.
+ ///
+ protected SdkRegularExpressionMethodPointcut(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets default options that should be used by
+ /// regular expressions that don't have options explicitly set.
+ ///
+ ///
+ /// Default options that should be used by regular expressions
+ /// that don't have options explicitly set.
+ ///
+ public RegexOptions DefaultOptions
+ {
+ get { return _defaultOptions; }
+ set
+ {
+ _defaultOptions = value;
+ InitPatternRepresentation(Patterns);
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the regular expression pointcuts.
+ ///
+ ///
+ ///
+ /// Can be invoked multiple times.
+ ///
+ ///
+ /// This method will be invoked from the
+ /// property,
+ /// and also on deserialization.
+ ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- protected StaticMethodMatcherPointcutAdvisor()
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class for the supplied
- ///
- ///
- ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ protected StaticMethodMatcherPointcutAdvisor()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class for the supplied
+ ///
+ ///
+ ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
- /// Such pointcut unions are tricky, because one cannot simply OR
- /// the respective s: one has to
- /// ascertain that each 's
- /// is also satisfied.
- ///
+ /// Such pointcut unions are tricky, because one cannot simply OR
+ /// the respective s: one has to
+ /// ascertain that each 's
+ /// is also satisfied.
+ ///
- /// Maintains a pool of target instances, acquiring and releasing a target
- /// object from the pool for each method invocation.
- ///
- ///
- /// This class is independent of pooling technology.
- ///
- ///
- /// Subclasses must implement the
- /// and
- ///
- /// methods to work with their chosen pool. The
- ///
- /// method inherited from the
- /// base class
- /// can be used to create objects to put in the pool. Subclasses must also
- /// implement some of the monitoring methods from the
- /// interface. This class
- /// provides the
- ///
- /// method to return an
- /// making these statistics available on proxied objects.
- ///
- ///
- /// This class implements the interface in
- /// order to force subclasses to implement the
- /// method to cleanup and close
- /// down their pool.
- ///
- ///
- /// Rod Johnson
- /// Federico Spinazzi (.NET)
- /// $Id: AbstractPoolingTargetSource.cs,v 1.7 2007/03/16 04:01:26 aseovic Exp $
- [Serializable]
- public abstract class AbstractPoolingTargetSource
- : AbstractPrototypeTargetSource, PoolingConfig, IDisposable, IAdvice
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractPoolingTargetSource()
- {
- }
-
- #endregion
-
- ///
- /// Returns the target object (acquired from the pool).
- ///
- /// The target object (acquired from the pool).
- ///
- /// If unable to obtain the target object.
- ///
- public abstract override object GetTarget();
-
- ///
- /// Gets the mixin.
- ///
- ///
- /// An exposing statistics
- /// about the pool maintained by this object.
- ///
- public DefaultIntroductionAdvisor GetPoolingConfigMixin()
- {
- return new DefaultIntroductionAdvisor(this, typeof (PoolingConfig));
- }
-
- ///
- /// The maximum number of object instances in this pool.
- ///
- public int MaxSize
- {
- get { return _maxSize; }
- set { _maxSize = value; }
- }
-
- ///
- /// The number of active object instances in this pool.
- ///
- public abstract int Active { get; }
-
- ///
- /// The number of free object instances in this pool.
- ///
- public abstract int Free { get; }
-
- ///
- /// The target factory that will be used to perform the lookup
- /// of the object referred to by the
- ///
- /// property.
- ///
- ///
- /// The owning
- /// (will never be ).
- ///
- ///
- /// In case of initialization errors.
- ///
- ///
- public override IObjectFactory ObjectFactory
- {
- set
- {
- base.ObjectFactory = value;
- try
- {
- CreatePool(value);
- }
- catch (ObjectsException)
- {
- throw;
- }
- catch (Exception ex)
- {
- throw new ObjectInitializationException("Could not create instance pool.", ex);
- }
- }
- }
-
- ///
- /// Create the pool.
- ///
- ///
- /// The owning , in
- /// case one needs collaborators from it (normally one's own properties
- /// are sufficient).
- ///
- ///
- /// In the case of errors encountered during the creation of the pool.
- ///
- protected abstract void CreatePool(IObjectFactory factory);
-
- ///
- /// Releases the target object (returns it to the pool).
- ///
- ///
- /// The target object to release (return to the pool).
- ///
- ///
- /// In the case that the could not be released.
- ///
- public abstract override void ReleaseTarget(object target);
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or
- /// resetting unmanaged resources.
- ///
- ///
- ///
+ /// Maintains a pool of target instances, acquiring and releasing a target
+ /// object from the pool for each method invocation.
+ ///
+ ///
+ /// This class is independent of pooling technology.
+ ///
+ ///
+ /// Subclasses must implement the
+ /// and
+ ///
+ /// methods to work with their chosen pool. The
+ ///
+ /// method inherited from the
+ /// base class
+ /// can be used to create objects to put in the pool. Subclasses must also
+ /// implement some of the monitoring methods from the
+ /// interface. This class
+ /// provides the
+ ///
+ /// method to return an
+ /// making these statistics available on proxied objects.
+ ///
+ ///
+ /// This class implements the interface in
+ /// order to force subclasses to implement the
+ /// method to cleanup and close
+ /// down their pool.
+ ///
+ ///
+ /// Rod Johnson
+ /// Federico Spinazzi (.NET)
+ [Serializable]
+ public abstract class AbstractPoolingTargetSource
+ : AbstractPrototypeTargetSource, PoolingConfig, IDisposable, IAdvice
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractPoolingTargetSource()
+ {
+ }
+
+ #endregion
+
+ ///
+ /// Returns the target object (acquired from the pool).
+ ///
+ /// The target object (acquired from the pool).
+ ///
+ /// If unable to obtain the target object.
+ ///
+ public abstract override object GetTarget();
+
+ ///
+ /// Gets the mixin.
+ ///
+ ///
+ /// An exposing statistics
+ /// about the pool maintained by this object.
+ ///
+ public DefaultIntroductionAdvisor GetPoolingConfigMixin()
+ {
+ return new DefaultIntroductionAdvisor(this, typeof (PoolingConfig));
+ }
+
+ ///
+ /// The maximum number of object instances in this pool.
+ ///
+ public int MaxSize
+ {
+ get { return _maxSize; }
+ set { _maxSize = value; }
+ }
+
+ ///
+ /// The number of active object instances in this pool.
+ ///
+ public abstract int Active { get; }
+
+ ///
+ /// The number of free object instances in this pool.
+ ///
+ public abstract int Free { get; }
+
+ ///
+ /// The target factory that will be used to perform the lookup
+ /// of the object referred to by the
+ ///
+ /// property.
+ ///
+ ///
+ /// The owning
+ /// (will never be ).
+ ///
+ ///
+ /// In case of initialization errors.
+ ///
+ ///
+ public override IObjectFactory ObjectFactory
+ {
+ set
+ {
+ base.ObjectFactory = value;
+ try
+ {
+ CreatePool(value);
+ }
+ catch (ObjectsException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectInitializationException("Could not create instance pool.", ex);
+ }
+ }
+ }
+
+ ///
+ /// Create the pool.
+ ///
+ ///
+ /// The owning , in
+ /// case one needs collaborators from it (normally one's own properties
+ /// are sufficient).
+ ///
+ ///
+ /// In the case of errors encountered during the creation of the pool.
+ ///
+ protected abstract void CreatePool(IObjectFactory factory);
+
+ ///
+ /// Releases the target object (returns it to the pool).
+ ///
+ ///
+ /// The target object to release (return to the pool).
+ ///
+ ///
+ /// In the case that the could not be released.
+ ///
+ public abstract override void ReleaseTarget(object target);
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or
+ /// resetting unmanaged resources.
+ ///
+ ///
+ ///
- /// All such s must run in an
- /// , as they need to
- /// call the
- /// method to create a new prototype instance.
- ///
- ///
- /// Rod Johnson
- /// Federico Spinazzi (.NET)
- /// $Id: AbstractPrototypeTargetSource.cs,v 1.11 2007/07/28 07:32:52 markpollack Exp $
- public abstract class AbstractPrototypeTargetSource
- : ITargetSource, IObjectFactoryAware, IInitializingObject
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractPrototypeTargetSource()
- {
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The name of the target object to be created on each invocation.
- ///
- ///
- ///
- /// This object should be a prototype, or the same instance will always
- /// be obtained from the owning .
- ///
- ///
- public virtual string TargetObjectName
- {
- get { return _targetObjectName; }
- set {
- _targetObjectName = value;
- }
- }
-
- ///
- /// The of the target object.
- ///
- public virtual Type TargetType
- {
- get { return _targetType; }
- }
-
- ///
- /// Is the target source static?
- ///
- ///
- /// if the target source is static.
- ///
- public virtual bool IsStatic
- {
- get { return false; }
- }
-
- ///
- /// The target factory that will be used to perform the lookup
- /// of the object referred to by the
- /// property.
- ///
- ///
- ///
- /// Needed so that prototype instances can be created as necessary.
- ///
- ///
- ///
- /// The owning
- /// (will never be ).
- ///
- ///
- /// In case of initialization errors.
- ///
- ///
- public virtual IObjectFactory ObjectFactory
- {
- get { return _owningObjectFactory; }
- set
- {
- _owningObjectFactory = value;
- if (!value.IsPrototype(TargetObjectName))
- {
- throw new ObjectDefinitionStoreException(
- "Cannot use PrototypeTargetSource against a " +
- "Singleton object; instances would not be independent.");
- }
-
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug(string.Format(
- "Getting object with name '{0}' to determine class.",
- TargetObjectName));
- }
-
- #endregion
-
- _targetType = _owningObjectFactory.GetType(TargetObjectName);
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Subclasses should use this method to create a new prototype instance.
- ///
- protected virtual object NewPrototypeInstance()
- {
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug(string.Format(
- "Creating new target from object '{0}'.",
- TargetObjectName));
- }
-
- #endregion
-
- return ObjectFactory.GetObject(TargetObjectName);
- }
-
- ///
- /// Returns the target object.
- ///
- /// The target object.
- ///
- /// If unable to obtain the target object.
- ///
- public abstract object GetTarget();
-
- ///
- /// Releases the target object.
- ///
- /// The target object to release.
- public virtual void ReleaseTarget(object target)
- {
- }
-
- ///
- /// Invoked by an
- /// after it has set all object properties supplied
- /// (and satisfied the
- ///
- /// and
- /// interfaces).
- ///
- ///
- ///
- /// Ensures that the property has been
- /// set to a valid value (i.e. is not or a string
- /// that consists solely of whitespace).
- ///
+ /// All such s must run in an
+ /// , as they need to
+ /// call the
+ /// method to create a new prototype instance.
+ ///
+ ///
+ /// Rod Johnson
+ /// Federico Spinazzi (.NET)
+ public abstract class AbstractPrototypeTargetSource
+ : ITargetSource, IObjectFactoryAware, IInitializingObject
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractPrototypeTargetSource()
+ {
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The name of the target object to be created on each invocation.
+ ///
+ ///
+ ///
+ /// This object should be a prototype, or the same instance will always
+ /// be obtained from the owning .
+ ///
+ ///
+ public virtual string TargetObjectName
+ {
+ get { return _targetObjectName; }
+ set {
+ _targetObjectName = value;
+ }
+ }
+
+ ///
+ /// The of the target object.
+ ///
+ public virtual Type TargetType
+ {
+ get { return _targetType; }
+ }
+
+ ///
+ /// Is the target source static?
+ ///
+ ///
+ /// if the target source is static.
+ ///
+ public virtual bool IsStatic
+ {
+ get { return false; }
+ }
+
+ ///
+ /// The target factory that will be used to perform the lookup
+ /// of the object referred to by the
+ /// property.
+ ///
+ ///
+ ///
+ /// Needed so that prototype instances can be created as necessary.
+ ///
+ ///
+ ///
+ /// The owning
+ /// (will never be ).
+ ///
+ ///
+ /// In case of initialization errors.
+ ///
+ ///
+ public virtual IObjectFactory ObjectFactory
+ {
+ get { return _owningObjectFactory; }
+ set
+ {
+ _owningObjectFactory = value;
+ if (!value.IsPrototype(TargetObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ "Cannot use PrototypeTargetSource against a " +
+ "Singleton object; instances would not be independent.");
+ }
+
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug(string.Format(
+ "Getting object with name '{0}' to determine class.",
+ TargetObjectName));
+ }
+
+ #endregion
+
+ _targetType = _owningObjectFactory.GetType(TargetObjectName);
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Subclasses should use this method to create a new prototype instance.
+ ///
+ protected virtual object NewPrototypeInstance()
+ {
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug(string.Format(
+ "Creating new target from object '{0}'.",
+ TargetObjectName));
+ }
+
+ #endregion
+
+ return ObjectFactory.GetObject(TargetObjectName);
+ }
+
+ ///
+ /// Returns the target object.
+ ///
+ /// The target object.
+ ///
+ /// If unable to obtain the target object.
+ ///
+ public abstract object GetTarget();
+
+ ///
+ /// Releases the target object.
+ ///
+ /// The target object to release.
+ public virtual void ReleaseTarget(object target)
+ {
+ }
+
+ ///
+ /// Invoked by an
+ /// after it has set all object properties supplied
+ /// (and satisfied the
+ ///
+ /// and
+ /// interfaces).
+ ///
+ ///
+ ///
+ /// Ensures that the property has been
+ /// set to a valid value (i.e. is not or a string
+ /// that consists solely of whitespace).
+ ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: EmptyTargetSource.cs,v 1.4 2007/10/08 22:04:51 markpollack Exp $
- [Serializable]
- public sealed class EmptyTargetSource : ITargetSource, ISerializable
- {
- ///
- /// The to be used
- /// when there is no target object, and behavior is supplied by the
- /// advisors.
- ///
- public static readonly ITargetSource Empty = new EmptyTargetSource();
-
- private object _dummyTarget = new object();
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly visible constructors.
- ///
- ///
- private EmptyTargetSource()
- {
- }
-
- ///
- /// The of the target object.
- ///
- public Type TargetType
- {
- get { return typeof(object); }
- }
-
- ///
- /// Is the target source static?
- ///
- ///
- ///
- /// The
- /// instance is static, and this always returns .
- ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
+ public sealed class EmptyTargetSource : ITargetSource, ISerializable
+ {
+ ///
+ /// The to be used
+ /// when there is no target object, and behavior is supplied by the
+ /// advisors.
+ ///
+ public static readonly ITargetSource Empty = new EmptyTargetSource();
+
+ private object _dummyTarget = new object();
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible constructors.
+ ///
+ ///
+ private EmptyTargetSource()
+ {
+ }
+
+ ///
+ /// The of the target object.
+ ///
+ public Type TargetType
+ {
+ get { return typeof(object); }
+ }
+
+ ///
+ /// Is the target source static?
+ ///
+ ///
+ ///
+ /// The
+ /// instance is static, and this always returns .
+ ///
+ /// If configuring an object of this class in a Spring IoC container,
+ /// use constructor injection to supply the intial target.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.Net)
+ [Serializable]
+ public class HotSwappableTargetSource : ITargetSource
+ {
+ private object _target;
+
+ ///
+ /// Creates a new instance of the
+ /// with the initial target.
+ ///
+ ///
+ /// The initial target. May be .
+ ///
+ public HotSwappableTargetSource(object initialTarget)
+ {
+ _target = initialTarget;
+ }
+
+ ///
+ /// The of the target object.
+ ///
+ ///
+ ///
+ /// Can return .
+ ///
+ ///
+ public virtual Type TargetType
+ {
+ get { return _target.GetType(); }
+ }
+
+ ///
+ /// Is the target source static?
+ ///
+ ///
+ /// if the target source is static.
+ ///
+ public virtual bool IsStatic
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Returns the target object.
+ ///
+ /// The target object.
+ ///
+ /// If unable to obtain the target object.
+ ///
+ public object GetTarget()
+ {
+ // synchronization around something that takes so little time is fine...
+ lock (this)
+ {
+ return _target;
+ }
+ }
+
+ ///
+ /// Releases the target object.
+ ///
+ ///
+ ///
+ /// No-op implementation.
+ ///
+ ///
+ /// The target object to release.
+ public virtual void ReleaseTarget(Object target)
+ {
+ }
+
+ ///
+ /// Swap the target, returning the old target.
+ ///
+ /// The new target.
+ /// The old target.
+ ///
+ /// If the new target is .
+ ///
+ public virtual object Swap(object newTarget)
+ {
+ AssertUtils.ArgumentNotNull(newTarget, "newTarget", "Cannot swap to null.");
+ lock (this)
+ {
+ // TODO: type checks
+ object old = _target;
+ _target = newTarget;
+ return old;
+ }
+ }
+
+ ///
+ /// Determines whether the specified
+ /// is equal to the current .
+ ///
+ ///
+ ///
+ /// Two invoker interceptors are equal if they have the same target or
+ /// if the targets are equal.
+ ///
- /// Subclasses can, of course, override this method if they want to
- /// return a different implementation.
- ///
- ///
- ///
- /// An empty .
- ///
- protected virtual IObjectPool CreateObjectPool()
- {
- return new SimplePool(this, MaxSize);
- }
-
- ///
- /// Releases the target object (returns it to the pool).
- ///
- /// The target object to release (return to the pool).
- ///
- /// In the case that the could not be released.
- ///
- public override void ReleaseTarget(object target)
- {
- this.objectPool.ReturnObject(target);
- }
-
- ///
- /// The number of active object instances in this pool.
- ///
- public override int Active
- {
- get { return this.objectPool.NumActive; }
- }
-
- ///
- /// The number of free object instances in this pool.
- ///
- public override int Free
- {
- get { return this.objectPool.NumIdle; }
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or
- /// resetting unmanaged resources.
- ///
- ///
- ///
+ /// Subclasses can, of course, override this method if they want to
+ /// return a different implementation.
+ ///
+ ///
+ ///
+ /// An empty .
+ ///
+ protected virtual IObjectPool CreateObjectPool()
+ {
+ return new SimplePool(this, MaxSize);
+ }
+
+ ///
+ /// Releases the target object (returns it to the pool).
+ ///
+ /// The target object to release (return to the pool).
+ ///
+ /// In the case that the could not be released.
+ ///
+ public override void ReleaseTarget(object target)
+ {
+ this.objectPool.ReturnObject(target);
+ }
+
+ ///
+ /// The number of active object instances in this pool.
+ ///
+ public override int Active
+ {
+ get { return this.objectPool.NumActive; }
+ }
+
+ ///
+ /// The number of free object instances in this pool.
+ ///
+ public override int Free
+ {
+ get { return this.objectPool.NumIdle; }
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or
+ /// resetting unmanaged resources.
+ ///
+ ///
+ ///
- /// This is the default implementation of the
- /// interface used by the AOP
- /// framework. There should be no need to create objects of this class in
- /// application code.
- ///
- ///
- /// Rod Johnson
- /// Aleksandar Seovic (.NET)
- /// $Id: SingletonTargetSource.cs,v 1.8 2008/03/21 14:11:57 markpollack Exp $
- [Serializable]
- public sealed class SingletonTargetSource : ITargetSource
- {
- private object target;
-
- ///
- /// Creates a new instance of the
- ///
- /// for the specified target object.
- ///
- /// The target object to expose.
- ///
- /// If the supplied is
- /// .
- ///
- public SingletonTargetSource(object target)
- {
- AssertUtils.ArgumentNotNull(target, "target");
- this.target = target;
- }
-
- #region ITarget Source impl
-
- ///
- /// The of the target object.
- ///
- public Type TargetType
- {
- get { return target.GetType(); }
- }
-
- ///
- /// Is the target source static?
- ///
- ///
- /// because this target source is always static.
- ///
- public bool IsStatic
- {
- get { return true; }
- }
-
- ///
- /// Returns the target object.
- ///
- /// The target object.
- ///
- /// If unable to obtain the target object.
- ///
- public object GetTarget()
- {
- return target;
- }
-
- ///
- /// Releases the target object.
- ///
- ///
- ///
+ /// This is the default implementation of the
+ /// interface used by the AOP
+ /// framework. There should be no need to create objects of this class in
+ /// application code.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
+ public sealed class SingletonTargetSource : ITargetSource
+ {
+ private object target;
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// for the specified target object.
+ ///
+ /// The target object to expose.
+ ///
+ /// If the supplied is
+ /// .
+ ///
+ public SingletonTargetSource(object target)
+ {
+ AssertUtils.ArgumentNotNull(target, "target");
+ this.target = target;
+ }
+
+ #region ITarget Source impl
+
+ ///
+ /// The of the target object.
+ ///
+ public Type TargetType
+ {
+ get { return target.GetType(); }
+ }
+
+ ///
+ /// Is the target source static?
+ ///
+ ///
+ /// because this target source is always static.
+ ///
+ public bool IsStatic
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Returns the target object.
+ ///
+ /// The target object.
+ ///
+ /// If unable to obtain the target object.
+ ///
+ public object GetTarget()
+ {
+ return target;
+ }
+
+ ///
+ /// Releases the target object.
+ ///
+ ///
+ ///
- /// Application code is written as to a normal pool; callers can't assume
- /// they will be dealing with the same instance in invocations in different
- /// threads. However, state can be relied on during the operations of a
- /// single thread: for example, if one caller makes repeated calls on the
- /// AOP proxy.
- ///
- ///
- /// This class act both as an introduction and as an interceptor, so it
- /// should be added twice, once as an introduction and once as an
- /// interceptor.
- ///
- ///
- /// Rod Johnson
- /// Federico Spinazzi (.NET)
- /// $Id: ThreadLocalTargetSource.cs,v 1.8 2006/04/09 07:18:37 markpollack Exp $
- public sealed class ThreadLocalTargetSource : AbstractPrototypeTargetSource,
- IThreadLocalTargetSourceStats, IDisposable, IMethodInterceptor
- {
- #region Fields
-
- ///
- /// ThreadLocal holding the target associated with the current thread.
- ///
- ///
- ///
- /// Unlike most thread local storage which is static, this variable is
- /// meant to be per thread per instance of this class.
- ///
- ///
- private LocalDataStoreSlot _targetInThread = Thread.AllocateDataSlot();
-
- ///
- /// The set of managed targets, enabling us to keep track of the
- /// targets we've created.
- ///
- private ISet _targetSet = new ListSet();
-
- private int _invocations;
- private int _hits;
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets the number of invocations of the and
- /// methods.
- ///
- ///
- /// The number of invocations of the and
- /// methods.
- ///
- public int Invocations
- {
- get { return _invocations; }
- }
-
- ///
- /// Gets the number of hits that were satisfied by a thread bound object.
- ///
- ///
- /// The number of hits that were satisfied by a thread bound object.
- ///
- public int Hits
- {
- get { return _hits; }
- }
-
- ///
- /// Gets the number of thread bound objects created.
- ///
- /// The number of thread bound objects created.
- public int Objects
- {
- get { return _targetSet.Count; }
- }
-
- private object ThreadBoundTarget
- {
- get { return Thread.GetData(_targetInThread); }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Returns the target object.
- ///
- ///
- ///
- /// Tries to locate the target from thread local storage. If no target
- /// is found, a target will be obtained and bound to the thread.
- ///
+ /// Application code is written as to a normal pool; callers can't assume
+ /// they will be dealing with the same instance in invocations in different
+ /// threads. However, state can be relied on during the operations of a
+ /// single thread: for example, if one caller makes repeated calls on the
+ /// AOP proxy.
+ ///
+ ///
+ /// This class act both as an introduction and as an interceptor, so it
+ /// should be added twice, once as an introduction and once as an
+ /// interceptor.
+ ///
+ ///
+ /// Rod Johnson
+ /// Federico Spinazzi (.NET)
+ public sealed class ThreadLocalTargetSource : AbstractPrototypeTargetSource,
+ IThreadLocalTargetSourceStats, IDisposable, IMethodInterceptor
+ {
+ #region Fields
+
+ ///
+ /// ThreadLocal holding the target associated with the current thread.
+ ///
+ ///
+ ///
+ /// Unlike most thread local storage which is static, this variable is
+ /// meant to be per thread per instance of this class.
+ ///
+ ///
+ private LocalDataStoreSlot _targetInThread = Thread.AllocateDataSlot();
+
+ ///
+ /// The set of managed targets, enabling us to keep track of the
+ /// targets we've created.
+ ///
+ private ISet _targetSet = new ListSet();
+
+ private int _invocations;
+ private int _hits;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets the number of invocations of the and
+ /// methods.
+ ///
+ ///
+ /// The number of invocations of the and
+ /// methods.
+ ///
+ public int Invocations
+ {
+ get { return _invocations; }
+ }
+
+ ///
+ /// Gets the number of hits that were satisfied by a thread bound object.
+ ///
+ ///
+ /// The number of hits that were satisfied by a thread bound object.
+ ///
+ public int Hits
+ {
+ get { return _hits; }
+ }
+
+ ///
+ /// Gets the number of thread bound objects created.
+ ///
+ /// The number of thread bound objects created.
+ public int Objects
+ {
+ get { return _targetSet.Count; }
+ }
+
+ private object ThreadBoundTarget
+ {
+ get { return Thread.GetData(_targetInThread); }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Returns the target object.
+ ///
+ ///
+ ///
+ /// Tries to locate the target from thread local storage. If no target
+ /// is found, a target will be obtained and bound to the thread.
+ ///
+ /// Only one canonical instance is
+ /// provided out of the box. The
+ /// matches all classes.
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ [Serializable]
+ public sealed class TrueTypeFilter : ITypeFilter, ISerializable
+ {
+ ///
+ /// Canonical instance that
+ /// matches all classes.
+ ///
+ public static readonly ITypeFilter True = new TrueTypeFilter();
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible
+ /// constructors.
+ ///
+ ///
+ private TrueTypeFilter()
+ {
+ }
+
+ ///
+ /// Should the pointcut apply to the supplied
+ /// ?
+ ///
+ ///
+ /// The candidate .
+ ///
+ ///
+ /// if the advice should apply to the supplied
+ ///
+ ///
+ ///
+ public bool Matches(Type type)
+ {
+ return true;
+ }
+
+ ///
+ /// A that represents the current
+ /// .
+ ///
+ ///
+ /// A that represents the current
+ /// .
+ ///
+ public override string ToString()
+ {
+ return "TrueTypeFilter.True";
+ }
+
+ ///
+ /// Populates a with
+ /// the data needed to serialize the target object.
+ ///
+ ///
+ /// The to populate
+ /// with data.
+ ///
+ ///
+ /// The destination (see )
+ /// for this serialization.
+ ///
+ [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ info.SetType(typeof (TrueTypeFilterObjectReference));
+ }
+
+ [Serializable]
+ private sealed class TrueTypeFilterObjectReference : IObjectReference
+ {
+ public object GetRealObject(StreamingContext context)
+ {
+ return TrueTypeFilter.True;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs b/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs
index 90fa9526..1f15c7d1 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Aop/AspectException.cs
@@ -1,80 +1,79 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace AopAlliance.Aop
-{
- ///
- /// Superclass for all AOP infrastructure exceptions.
- ///
- /// Aleksandar Seovic
- /// $Id: AspectException.cs,v 1.3 2006/04/09 07:18:33 markpollack Exp $
- [Serializable]
- public class AspectException : Exception
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public AspectException()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public AspectException(string message) : base(message)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception that is being wrapped.
- ///
- public AspectException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected AspectException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
- }
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace AopAlliance.Aop
+{
+ ///
+ /// Superclass for all AOP infrastructure exceptions.
+ ///
+ /// Aleksandar Seovic
+ [Serializable]
+ public class AspectException : Exception
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public AspectException()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public AspectException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception that is being wrapped.
+ ///
+ public AspectException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected AspectException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs b/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs
index 5b4436d4..dd94810d 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Aop/IAdvice.cs
@@ -1,31 +1,31 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-
-#endregion
-
-namespace AopAlliance.Aop
-{
- ///
- /// Tag interface for advice.
- ///
- ///
- ///
- /// Implementations can be any type of advice, such as interceptors.
- ///
- ///
- public interface IAdvice
- {
- }
-}
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+
+#endregion
+
+namespace AopAlliance.Aop
+{
+ ///
+ /// Tag interface for advice.
+ ///
+ ///
+ ///
+ /// Implementations can be any type of advice, such as interceptors.
+ ///
+ ///
+ public interface IAdvice
+ {
+ }
+}
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs
index 46d2b2df..8f39324e 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInterceptor.cs
@@ -1,54 +1,54 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Intercepts the construction of a new object.
- ///
- ///
- ///
- /// Such interceptions are nested "on top" of the target.
- ///
- ///
- public interface IConstructorInterceptor : IInterceptor
- {
- ///
- /// Implement this method to perform extra treatments before and after
- /// the consruction of a new object.
- ///
- ///
- ///
- /// Polite implementations would certainly like to invoke
- /// .
- ///
- ///
- ///
- /// The constructor invocation that is being intercepted.
- ///
- ///
- /// The newly created object, which is also the result of the call to
- /// , and might be
- /// replaced by the interceptor.
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- object Construct(IConstructorInvocation invocation);
- }
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// Intercepts the construction of a new object.
+ ///
+ ///
+ ///
+ /// Such interceptions are nested "on top" of the target.
+ ///
+ ///
+ public interface IConstructorInterceptor : IInterceptor
+ {
+ ///
+ /// Implement this method to perform extra treatments before and after
+ /// the consruction of a new object.
+ ///
+ ///
+ ///
+ /// Polite implementations would certainly like to invoke
+ /// .
+ ///
+ ///
+ ///
+ /// The constructor invocation that is being intercepted.
+ ///
+ ///
+ /// The newly created object, which is also the result of the call to
+ /// , and might be
+ /// replaced by the interceptor.
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ object Construct(IConstructorInvocation invocation);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs
index 1da95926..ee766145 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IConstructorInvocation.cs
@@ -1,51 +1,51 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System.Reflection;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// A description of an invocation to a constuctor, given to an interceptor
- /// upon constructor-call.
- ///
- ///
- ///
- /// A constructor invocation is a joinpoint and can be intercepted by a
- /// constructor interceptor.
- ///
- ///
- ///
- public interface IConstructorInvocation : IInvocation
- {
- ///
- /// Gets the constructor invocation that is to be invoked.
- ///
- ///
- ///
- /// This property is a friendly implementation of the
- /// property.
- /// It should be used in preference to the
- /// property
- /// because it provides immediate access to the underlying constructor
- /// without the need to resort to a cast.
- ///
- ///
- ///
- /// The constructor invocation that is to be invoked.
- ///
- ConstructorInfo Constructor { get; }
- }
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System.Reflection;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// A description of an invocation to a constuctor, given to an interceptor
+ /// upon constructor-call.
+ ///
+ ///
+ ///
+ /// A constructor invocation is a joinpoint and can be intercepted by a
+ /// constructor interceptor.
+ ///
+ ///
+ ///
+ public interface IConstructorInvocation : IInvocation
+ {
+ ///
+ /// Gets the constructor invocation that is to be invoked.
+ ///
+ ///
+ ///
+ /// This property is a friendly implementation of the
+ /// property.
+ /// It should be used in preference to the
+ /// property
+ /// because it provides immediate access to the underlying constructor
+ /// without the need to resort to a cast.
+ ///
+ ///
+ ///
+ /// The constructor invocation that is to be invoked.
+ ///
+ ConstructorInfo Constructor { get; }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs
index 121c2ef4..0689389b 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInterceptor.cs
@@ -1,39 +1,39 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using AopAlliance.Aop;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Represents a generic interceptor.
- ///
- ///
- ///
- /// A generic interceptor can intercept runtime events that occur within a
- /// base program. Those events are materialized by (reified in) joinpoints.
- /// Runtime joinpoints can be invocations, field access, exceptions, etc.
- ///
- ///
- /// This interface is not used directly. Use the various derived interfaces
- /// to intercept specific events.
- ///
+ /// A generic interceptor can intercept runtime events that occur within a
+ /// base program. Those events are materialized by (reified in) joinpoints.
+ /// Runtime joinpoints can be invocations, field access, exceptions, etc.
+ ///
+ ///
+ /// This interface is not used directly. Use the various derived interfaces
+ /// to intercept specific events.
+ ///
+ ///
+ ///
+ public interface IInterceptor : IAdvice
+ {
+ }
+}
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs
index af4d0e8f..8782ae19 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IInvocation.cs
@@ -1,45 +1,45 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Represents an invocation in the program.
- ///
- ///
- ///
- /// An invocation is a joinpoint and can be intercepted by an interceptor.
- /// Typical examples would be a constructor invocation and a method call.
- ///
- ///
- public interface IInvocation : IJoinpoint
- {
- ///
- /// Gets the arguments to an invocation.
- ///
- ///
- ///
- /// It is of course possible to change element values within this array
- /// to change the arguments to an intercepted invocation.
- ///
- ///
- ///
- /// The arguments to an invocation.
- ///
- object[] Arguments { get; }
- }
-}
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// Represents an invocation in the program.
+ ///
+ ///
+ ///
+ /// An invocation is a joinpoint and can be intercepted by an interceptor.
+ /// Typical examples would be a constructor invocation and a method call.
+ ///
+ ///
+ public interface IInvocation : IJoinpoint
+ {
+ ///
+ /// Gets the arguments to an invocation.
+ ///
+ ///
+ ///
+ /// It is of course possible to change element values within this array
+ /// to change the arguments to an intercepted invocation.
+ ///
+ ///
+ ///
+ /// The arguments to an invocation.
+ ///
+ object[] Arguments { get; }
+ }
+}
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs
index 971fa7e9..98a97f73 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IJoinpoint.cs
@@ -1,88 +1,88 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System.Reflection;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Represents a generic runtime joinpoint (in the AOP terminology).
- ///
- ///
- ///
- /// A runtime joinpoint is an event that occurs on a static
- /// joinpoint (i.e. a location in a program). For instance, an
- /// invocation is the runtime joinpoint on a method (static joinpoint).
- /// The static part of a given joinpoint can be generically retrieved
- /// using the
- /// property.
- ///
- ///
- /// In the context of an interception framework, a runtime joinpoint
- /// is then the reification of an access to an accessible object (a
- /// method, a constructor, a field), i.e. the static part of the
- /// joinpoint. It is passed to the interceptors that are installed on
- /// the static joinpoint.
- ///
- ///
- ///
- public interface IJoinpoint
- {
- ///
- /// Gets the static part of this joinpoint.
- ///
- ///
- ///
- /// The static part is an accessible object on which a chain of
- /// interceptors are installed.
- ///
- ///
- ///
- /// The static part of this joinpoint.
- ///
- MemberInfo StaticPart { get; }
-
- ///
- /// Gets the object that holds the current joinpoint's static part.
- ///
- ///
- ///
- /// For instance, the target object for a method invocation.
- ///
- ///
- ///
- /// The object that holds the current joinpoint's static part.
- ///
- object This { get; }
-
- ///
- /// Proceeds to the next interceptor in the chain.
- ///
- ///
- ///
- /// The implementation and semantics of this method depend on the
- /// actual joinpoint type. Consult the derived interfaces of this
- /// interface for specifics.
- ///
- ///
- ///
- /// Consult the derived interfaces of this interface for specifics.
- ///
- ///
- /// If any of the interceptors at the joinpoint throws an exception.
- ///
- object Proceed();
- }
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System.Reflection;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// Represents a generic runtime joinpoint (in the AOP terminology).
+ ///
+ ///
+ ///
+ /// A runtime joinpoint is an event that occurs on a static
+ /// joinpoint (i.e. a location in a program). For instance, an
+ /// invocation is the runtime joinpoint on a method (static joinpoint).
+ /// The static part of a given joinpoint can be generically retrieved
+ /// using the
+ /// property.
+ ///
+ ///
+ /// In the context of an interception framework, a runtime joinpoint
+ /// is then the reification of an access to an accessible object (a
+ /// method, a constructor, a field), i.e. the static part of the
+ /// joinpoint. It is passed to the interceptors that are installed on
+ /// the static joinpoint.
+ ///
+ ///
+ ///
+ public interface IJoinpoint
+ {
+ ///
+ /// Gets the static part of this joinpoint.
+ ///
+ ///
+ ///
+ /// The static part is an accessible object on which a chain of
+ /// interceptors are installed.
+ ///
+ ///
+ ///
+ /// The static part of this joinpoint.
+ ///
+ MemberInfo StaticPart { get; }
+
+ ///
+ /// Gets the object that holds the current joinpoint's static part.
+ ///
+ ///
+ ///
+ /// For instance, the target object for a method invocation.
+ ///
+ ///
+ ///
+ /// The object that holds the current joinpoint's static part.
+ ///
+ object This { get; }
+
+ ///
+ /// Proceeds to the next interceptor in the chain.
+ ///
+ ///
+ ///
+ /// The implementation and semantics of this method depend on the
+ /// actual joinpoint type. Consult the derived interfaces of this
+ /// interface for specifics.
+ ///
+ ///
+ ///
+ /// Consult the derived interfaces of this interface for specifics.
+ ///
+ ///
+ /// If any of the interceptors at the joinpoint throws an exception.
+ ///
+ object Proceed();
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs
index 79bc1c16..0b0355ef 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInterceptor.cs
@@ -1,55 +1,55 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Intercepts calls on an interface on its way to the target.
- ///
- ///
- ///
- /// Such interceptions are nested "on top" of the target.
- ///
- ///
- public interface IMethodInterceptor : IInterceptor
- {
- ///
- /// Implement this method to perform extra treatments before and after
- /// the call to the supplied .
- ///
- ///
- ///
- /// Polite implementations would certainly like to invoke
- /// .
- ///
- ///
- ///
- /// The method invocation that is being intercepted.
- ///
- ///
- /// The result of the call to the
- /// method of
- /// the supplied ; this return value may
- /// well have been intercepted by the interceptor.
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- object Invoke(IMethodInvocation invocation);
- }
-}
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// Intercepts calls on an interface on its way to the target.
+ ///
+ ///
+ ///
+ /// Such interceptions are nested "on top" of the target.
+ ///
+ ///
+ public interface IMethodInterceptor : IInterceptor
+ {
+ ///
+ /// Implement this method to perform extra treatments before and after
+ /// the call to the supplied .
+ ///
+ ///
+ ///
+ /// Polite implementations would certainly like to invoke
+ /// .
+ ///
+ ///
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied ; this return value may
+ /// well have been intercepted by the interceptor.
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ object Invoke(IMethodInvocation invocation);
+ }
+}
diff --git a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs
index e4c27839..689ce09e 100644
--- a/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs
+++ b/src/Spring/Spring.Aop/AopAlliance/Intercept/IMethodInvocation.cs
@@ -1,77 +1,77 @@
-#region License
-
-/*
- * All the source code provided by AOP Alliance is Public Domain.
- *
- * http://aopalliance.sourceforge.net/
- *
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Reflection;
-
-#endregion
-
-namespace AopAlliance.Intercept
-{
- ///
- /// Description of an invocation to a method, given to an interceptor
- /// upon method-call.
- ///
- ///
- ///
- /// A method invocation is a joinpoint and can be intercepted by a method
- /// interceptor.
- ///
- ///
- ///
- public interface IMethodInvocation : IInvocation
- {
- ///
- /// Gets the method invocation that is to be invoked.
- ///
- ///
- ///
- /// This property is a friendly implementation of the
- /// property.
- /// It should be used in preference to the
- /// property
- /// because it provides immediate access to the underlying method
- /// without the need to resort to a cast.
- ///
- ///
- ///
- /// The method invocation that is to be invoked.
- ///
- MethodInfo Method { get; }
-
- ///
- /// Gets the proxy object for the invocation.
- ///
- ///
- /// The proxy object for this method invocation.
- ///
- object Proxy { get; }
-
- ///
- /// Gets the target object for the invocation.
- ///
- ///
- /// The target object for this method invocation.
- ///
- object Target { get; }
-
- ///
- /// Gets the type of the target object.
- ///
- ///
- /// The type of the target object.
- ///
- Type TargetType { get; }
-
- }
+#region License
+
+/*
+ * All the source code provided by AOP Alliance is Public Domain.
+ *
+ * http://aopalliance.sourceforge.net/
+ *
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Reflection;
+
+#endregion
+
+namespace AopAlliance.Intercept
+{
+ ///
+ /// Description of an invocation to a method, given to an interceptor
+ /// upon method-call.
+ ///
+ ///
+ ///
+ /// A method invocation is a joinpoint and can be intercepted by a method
+ /// interceptor.
+ ///
+ ///
+ ///
+ public interface IMethodInvocation : IInvocation
+ {
+ ///
+ /// Gets the method invocation that is to be invoked.
+ ///
+ ///
+ ///
+ /// This property is a friendly implementation of the
+ /// property.
+ /// It should be used in preference to the
+ /// property
+ /// because it provides immediate access to the underlying method
+ /// without the need to resort to a cast.
+ ///
+ ///
+ ///
+ /// The method invocation that is to be invoked.
+ ///
+ MethodInfo Method { get; }
+
+ ///
+ /// Gets the proxy object for the invocation.
+ ///
+ ///
+ /// The proxy object for this method invocation.
+ ///
+ object Proxy { get; }
+
+ ///
+ /// Gets the target object for the invocation.
+ ///
+ ///
+ /// The target object for this method invocation.
+ ///
+ object Target { get; }
+
+ ///
+ /// Gets the type of the target object.
+ ///
+ ///
+ /// The type of the target object.
+ ///
+ Type TargetType { get; }
+
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs
index 9304354e..50382bc5 100644
--- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs
@@ -1,184 +1,183 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 Common.Logging;
-using Spring.Expressions;
-
-namespace Spring.Aspects
-{
- ///
- /// An abstract base class providing all necessary functionality for typical IExceptionHandler implementations.
- ///
- /// Mark Pollack
- /// $Id: AbstractExceptionHandler.cs,v 1.2 2007/10/10 18:07:46 markpollack Exp $
- public abstract class AbstractExceptionHandler : IExceptionHandler
- {
- #region Fields
-
- ///
- /// The logging instance
- ///
- protected readonly ILog log;
-
- private IList sourceExceptionNames = new ArrayList();
- private IList sourceExceptionTypes = new ArrayList();
- private string actionExpressionText;
- private bool continueProcessing = false;
- private string constraintExpressionText;
-
- #endregion
-
- #region Constructor(s)
-
- ///
- /// Initializes a new instance of the class.
- ///
- public AbstractExceptionHandler()
- {
- log = LogManager.GetLogger(GetType());
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The exception names.
- public AbstractExceptionHandler(string[] exceptionNames)
- {
- log = LogManager.GetLogger(GetType());
- foreach (string exceptionName in exceptionNames)
- {
- SourceExceptionNames.Add(exceptionName);
- }
- }
-
- #endregion
-
- #region Implementation of IExceptionHandler
-
- #region Properties
-
- ///
- /// Gets the source exception names.
- ///
- /// The source exception names.
- public IList SourceExceptionNames
- {
- get { return sourceExceptionNames; }
- set { sourceExceptionNames = value; }
- }
-
- ///
- /// Gets the source exception types.
- ///
- /// The source exception types.
- public IList SourceExceptionTypes
- {
- get { return sourceExceptionTypes; }
- set { sourceExceptionTypes = value; }
- }
-
- ///
- /// Gets the action translation expression text
- ///
- /// The action translation expression.
- public string ActionExpressionText
- {
- get { return actionExpressionText; }
- set { actionExpressionText = value; }
- }
-
-
- ///
- /// Gets or sets the constraint expression text.
- ///
- /// The constraint expression text.
- public string ConstraintExpressionText
- {
- get { return constraintExpressionText; }
- set { constraintExpressionText = value; }
- }
-
- ///
- /// Gets a value indicating whether to continue processing.
- ///
- /// true if continue processing; otherwise, false.
- public bool ContinueProcessing
- {
- get { return continueProcessing; }
- set { continueProcessing = value; }
- }
-
- #endregion
-
-
-
- ///
- /// Determines whether this instance can handle the exception the specified exception.
- ///
- /// The exception.
- /// The call context dictionary.
- ///
- /// true if this instance can handle the specified exception; otherwise, false.
- ///
- public bool CanHandleException(Exception ex, IDictionary callContextDictionary)
- {
- if (SourceExceptionNames != null)
- {
- foreach (string exceptionName in SourceExceptionNames)
- {
- if (ex.GetType().Name.IndexOf(exceptionName) >= 0)
- {
- return true;
- }
- }
- }
- if (ConstraintExpressionText != null)
- {
- bool canProcess;
- try
- {
- IExpression expression = Expression.Parse(ConstraintExpressionText);
- canProcess = (bool) expression.GetValue(null, callContextDictionary);
- } catch (InvalidCastException e)
- {
- log.Warn("Was not able to unbox constraint expression to boolean [" + ConstraintExpressionText + "]", e);
- return false;
- } catch (Exception e)
- {
- log.Warn("Was not able to evaluate constraint expression [" + ConstraintExpressionText + "]",e);
- return false;
- }
- return canProcess;
- }
-
- return false;
- }
-
- ///
- /// Handles the exception.
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- public abstract object HandleException(IDictionary callContextDictionary);
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 Common.Logging;
+using Spring.Expressions;
+
+namespace Spring.Aspects
+{
+ ///
+ /// An abstract base class providing all necessary functionality for typical IExceptionHandler implementations.
+ ///
+ /// Mark Pollack
+ public abstract class AbstractExceptionHandler : IExceptionHandler
+ {
+ #region Fields
+
+ ///
+ /// The logging instance
+ ///
+ protected readonly ILog log;
+
+ private IList sourceExceptionNames = new ArrayList();
+ private IList sourceExceptionTypes = new ArrayList();
+ private string actionExpressionText;
+ private bool continueProcessing = false;
+ private string constraintExpressionText;
+
+ #endregion
+
+ #region Constructor(s)
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AbstractExceptionHandler()
+ {
+ log = LogManager.GetLogger(GetType());
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception names.
+ public AbstractExceptionHandler(string[] exceptionNames)
+ {
+ log = LogManager.GetLogger(GetType());
+ foreach (string exceptionName in exceptionNames)
+ {
+ SourceExceptionNames.Add(exceptionName);
+ }
+ }
+
+ #endregion
+
+ #region Implementation of IExceptionHandler
+
+ #region Properties
+
+ ///
+ /// Gets the source exception names.
+ ///
+ /// The source exception names.
+ public IList SourceExceptionNames
+ {
+ get { return sourceExceptionNames; }
+ set { sourceExceptionNames = value; }
+ }
+
+ ///
+ /// Gets the source exception types.
+ ///
+ /// The source exception types.
+ public IList SourceExceptionTypes
+ {
+ get { return sourceExceptionTypes; }
+ set { sourceExceptionTypes = value; }
+ }
+
+ ///
+ /// Gets the action translation expression text
+ ///
+ /// The action translation expression.
+ public string ActionExpressionText
+ {
+ get { return actionExpressionText; }
+ set { actionExpressionText = value; }
+ }
+
+
+ ///
+ /// Gets or sets the constraint expression text.
+ ///
+ /// The constraint expression text.
+ public string ConstraintExpressionText
+ {
+ get { return constraintExpressionText; }
+ set { constraintExpressionText = value; }
+ }
+
+ ///
+ /// Gets a value indicating whether to continue processing.
+ ///
+ /// true if continue processing; otherwise, false.
+ public bool ContinueProcessing
+ {
+ get { return continueProcessing; }
+ set { continueProcessing = value; }
+ }
+
+ #endregion
+
+
+
+ ///
+ /// Determines whether this instance can handle the exception the specified exception.
+ ///
+ /// The exception.
+ /// The call context dictionary.
+ ///
+ /// true if this instance can handle the specified exception; otherwise, false.
+ ///
+ public bool CanHandleException(Exception ex, IDictionary callContextDictionary)
+ {
+ if (SourceExceptionNames != null)
+ {
+ foreach (string exceptionName in SourceExceptionNames)
+ {
+ if (ex.GetType().Name.IndexOf(exceptionName) >= 0)
+ {
+ return true;
+ }
+ }
+ }
+ if (ConstraintExpressionText != null)
+ {
+ bool canProcess;
+ try
+ {
+ IExpression expression = Expression.Parse(ConstraintExpressionText);
+ canProcess = (bool) expression.GetValue(null, callContextDictionary);
+ } catch (InvalidCastException e)
+ {
+ log.Warn("Was not able to unbox constraint expression to boolean [" + ConstraintExpressionText + "]", e);
+ return false;
+ } catch (Exception e)
+ {
+ log.Warn("Was not able to evaluate constraint expression [" + ConstraintExpressionText + "]",e);
+ return false;
+ }
+ return canProcess;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Handles the exception.
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ public abstract object HandleException(IDictionary callContextDictionary);
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
index b84f1962..55f5d21c 100644
--- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandlerAdvice.cs
@@ -1,157 +1,156 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Text.RegularExpressions;
-using AopAlliance.Intercept;
-using Spring.Objects.Factory;
-using Spring.Util;
-
-namespace Spring.Aspects
-{
- ///
- /// This is
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: AbstractExceptionHandlerAdvice.cs,v 1.1 2007/10/08 22:05:16 markpollack Exp $
- public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject
- {
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and subclass specific actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception name' and subclass specific actions.
- public abstract string OnExceptionNameRegex
- {
- get; set;
- }
-
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions.
- public abstract string OnExceptionRegex
- {
- get; set;
- }
-
- ///
- /// Implement this method to perform extra treatments before and after
- /// the call to the supplied .
- ///
- ///
- ///
- /// Polite implementations would certainly like to invoke
- /// .
- ///
- ///
- ///
- /// The method invocation that is being intercepted.
- ///
- ///
- /// The result of the call to the
- /// method of
- /// the supplied ; this return value may
- /// well have been intercepted by the interceptor.
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- public abstract object Invoke(IMethodInvocation invocation);
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
- ///
- ///
- /// In the event of misconfiguration (such as the failure to set a
- /// required property) or if initialization fails.
- ///
- public abstract void AfterPropertiesSet();
-
- ///
- /// Parses the advice expression.
- ///
- /// The advice expression.
- /// An instance of ParsedAdviceExpression
- protected virtual ParsedAdviceExpression ParseAdviceExpression(string adviceExpression)
- {
- ParsedAdviceExpression parsedAdviceExpression = new ParsedAdviceExpression(adviceExpression);
-
- Match match = GetMatch(adviceExpression, OnExceptionNameRegex);
- if (match.Success)
- {
- parsedAdviceExpression.Success = true;
- //using exception names for exception filter
- parsedAdviceExpression.ExceptionNames = StringUtils.CommaDelimitedListToStringArray(match.Groups[2].Value.Trim());
- parsedAdviceExpression.ActionText = match.Groups[3].Value.Trim();
- parsedAdviceExpression.ActionExpressionText = match.Groups[4].Value.Trim();
- }
- else
- {
- match = GetMatch(adviceExpression, OnExceptionRegex);
- if (match.Success)
- {
- parsedAdviceExpression.Success = true;
- //using constratin expression for exception filter
- string constraintExpression = match.Groups[2].Value.Trim().Remove(0, 1);
- parsedAdviceExpression.ConstraintExpression = constraintExpression.Substring(0, constraintExpression.Length - 1);
- parsedAdviceExpression.ActionText = match.Groups[3].Value.Trim();
- parsedAdviceExpression.ActionExpressionText = match.Groups[4].Value.Trim();
- }
- }
- return parsedAdviceExpression;
- }
-
-
- ///
- /// Gets the match using exception constraint expression.
- ///
- /// The advice expression string.
- /// The regex string.
- /// The Match object resulting from the regular expression match.
- protected virtual Match GetMatch(string adviceExpressionString, string regexString)
- {
- RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
- Regex reg = new Regex(regexString, options);
- return reg.Match(adviceExpressionString);
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Text.RegularExpressions;
+using AopAlliance.Intercept;
+using Spring.Objects.Factory;
+using Spring.Util;
+
+namespace Spring.Aspects
+{
+ ///
+ /// This is
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public abstract class AbstractExceptionHandlerAdvice : IMethodInterceptor, IInitializingObject
+ {
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and subclass specific actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception name' and subclass specific actions.
+ public abstract string OnExceptionNameRegex
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception (constraint)' and subclass specific actions.
+ public abstract string OnExceptionRegex
+ {
+ get; set;
+ }
+
+ ///
+ /// Implement this method to perform extra treatments before and after
+ /// the call to the supplied .
+ ///
+ ///
+ ///
+ /// Polite implementations would certainly like to invoke
+ /// .
+ ///
+ ///
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied ; this return value may
+ /// well have been intercepted by the interceptor.
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ public abstract object Invoke(IMethodInvocation invocation);
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
- /// This advice can be used to cache the parameter of the method.
- ///
- ///
- /// Information that determines where, how and for how long the return value
- /// will be cached are retrieved from the s
- /// that are defined on the pointcut.
- ///
- ///
- /// Parameter values are cached *after* the target method is invoked in order to
- /// capture any parameter state changes it might make (for example, it is common
- /// to set an object identifier within the save method for the persistent entity).
- ///
- /// Note that the supplied cannot
- /// be changed by this type of advice... use the around advice type
- /// () if you
- /// need to change the return value of an advised method invocation.
- /// The data encapsulated by the supplied
- /// can of course be modified though.
- ///
+ /// This advice can be used to cache the parameter of the method.
+ ///
+ ///
+ /// Information that determines where, how and for how long the return value
+ /// will be cached are retrieved from the s
+ /// that are defined on the pointcut.
+ ///
+ ///
+ /// Parameter values are cached *after* the target method is invoked in order to
+ /// capture any parameter state changes it might make (for example, it is common
+ /// to set an object identifier within the save method for the persistent entity).
+ ///
+ /// Note that the supplied cannot
+ /// be changed by this type of advice... use the around advice type
+ /// () if you
+ /// need to change the return value of an advised method invocation.
+ /// The data encapsulated by the supplied
+ /// can of course be modified though.
+ ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
- /// This advice can be used to cache the return value of the method.
- ///
- ///
- /// Parameters that determine where, how and for how long the return value
- /// will be cached are retrieved from the and/or
- /// that are defined on the pointcut.
- ///
- /// This method tries to retrieve an object from the cache, using the supplied
- /// to generate a cache key. If an object is found
- /// in the cache, the cached value is returned and the method call does not
- /// proceed any further down the invocation chain.
- ///
- ///
- /// If object does not exist in the cache, the advised method is called (using
- /// )
- /// and any return value is cached for the next method invocation.
- ///
+ /// This advice can be used to cache the return value of the method.
+ ///
+ ///
+ /// Parameters that determine where, how and for how long the return value
+ /// will be cached are retrieved from the and/or
+ /// that are defined on the pointcut.
+ ///
+ /// This method tries to retrieve an object from the cache, using the supplied
+ /// to generate a cache key. If an object is found
+ /// in the cache, the cached value is returned and the method call does not
+ /// proceed any further down the invocation chain.
+ ///
+ ///
+ /// If object does not exist in the cache, the advised method is called (using
+ /// )
+ /// and any return value is cached for the next method invocation.
+ ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
- /// This advice can be used to evict items from the cache.
- ///
- ///
- /// Information that determines which items should be evicted and from which cache
- /// are retrieved from the s that are defined
- /// on the pointcut.
- ///
- ///
- /// Items are evicted *after* target method is invoked. Return value of the method,
- /// as well as method arguments, can be used to determine a list of keys for the items
- /// that should be evicted (return value will be passed as a context for
- /// expression evaluation, and method
- /// arguments will be passed as variables, keyed by argument name).
- ///
- /// Note that the supplied cannot
- /// be changed by this type of advice... use the around advice type
- /// () if you
- /// need to change the return value of an advised method invocation.
- /// The data encapsulated by the supplied
- /// can of course be modified though.
- ///
+ /// This advice can be used to evict items from the cache.
+ ///
+ ///
+ /// Information that determines which items should be evicted and from which cache
+ /// are retrieved from the s that are defined
+ /// on the pointcut.
+ ///
+ ///
+ /// Items are evicted *after* target method is invoked. Return value of the method,
+ /// as well as method arguments, can be used to determine a list of keys for the items
+ /// that should be evicted (return value will be passed as a context for
+ /// expression evaluation, and method
+ /// arguments will be passed as variables, keyed by argument name).
+ ///
+ /// Note that the supplied cannot
+ /// be changed by this type of advice... use the around advice type
+ /// () if you
+ /// need to change the return value of an advised method invocation.
+ /// The data encapsulated by the supplied
+ /// can of course be modified though.
+ ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
+ ///
+ ///
+ /// In the case of application context initialization errors.
+ ///
+ ///
+ /// If thrown by any application context methods.
+ ///
+ ///
+ public IApplicationContext ApplicationContext
+ {
+ get { return ((IApplicationContextAware) Advice).ApplicationContext; }
+ set { ((IApplicationContextAware) Advice).ApplicationContext = value; }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
index 17bc8b35..dade0c85 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs
@@ -1,391 +1,390 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Reflection;
-using AopAlliance.Intercept;
-using Common.Logging;
-
-namespace Spring.Aspects.Exceptions
-{
- ///
- /// Exception advice to perform exception translation, conversion of exceptions to default return values, and
- /// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as
- /// allowing for custom translation logic by leveraging the Spring expression language.
- ///
- ///
- ///
- /// The exception handler collection can be filled with either instances of objects that implement the interface
- /// or a string that follows a simple syntax for most common exception management
- /// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can
- /// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or
- /// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the
- /// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be
- /// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that
- /// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown.
- /// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context.
- ///
- /// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only
- /// the exception text for the new translated exception. If you ommit the exception text a default value will be
- /// used.
- /// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging
- /// an exception will continue the evaluation process, in all other cases exceution stops at that point and the
- /// appropriate exceptions handler is executed.
- ///
- ///
- ///
- /// on FooException1 log 'My Message, Method Name ' + #method.Name
- /// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e)
- /// on FooException2,Foo3Exception wrap BarException 'My Bar Message'
- /// on FooException4 replace BarException 'My Bar Message'
- /// on FooException5 return 32
- /// on FooException6 swallow
- ///
- ///
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: ExceptionHandlerAdvice.cs,v 1.9 2007/10/11 01:29:42 markpollack Exp $
- public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice
- {
- #region Fields
-
- private static readonly ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice));
-
- private IList exceptionHandlers = new ArrayList();
-
- private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
-
- private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions.
- public override string OnExceptionNameRegex
- {
- get { return onExceptionNameRegex; }
- set { onExceptionNameRegex = value; }
- }
-
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
- public override string OnExceptionRegex
- {
- get { return onExceptionRegex; }
- set { onExceptionRegex = value; }
- }
-
- ///
- /// Gets or sets the exception handler.
- ///
- /// The exception handler.
- public IList ExceptionHandlers
- {
- get { return exceptionHandlers; }
- set { exceptionHandlers = value; }
- }
-
- #endregion
-
- #region IMethodInterceptor implementation
-
- ///
- /// Implement this method to perform extra treatments before and after
- /// the call to the supplied .
- ///
- ///
- ///
- /// Polite implementations would certainly like to invoke
- /// .
- ///
- ///
- ///
- /// The method invocation that is being intercepted.
- ///
- ///
- /// The result of the call to the
- /// method of
- /// the supplied ; this return value may
- /// well have been intercepted by the interceptor.
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- public override object Invoke(IMethodInvocation invocation)
- {
- try
- {
- return invocation.Proceed();
- }
- catch (TargetInvocationException ex)
- {
- Exception realException = ex.InnerException;
- InvokeHandlers(realException, invocation);
- throw realException;
- }
- catch (Exception ex)
- {
- object returnVal = InvokeHandlers(ex, invocation);
-
- if (returnVal == null)
- {
- return null;
- }
-
- // if only logged
- if (returnVal.Equals("logged"))
- {
- throw;
- }
-
- //only here if we only are swallowing, returning alternative value, no matching handler was found.
-
- // no matching handler.
- if (returnVal.Equals("nomatch"))
- {
- throw;
- }
- else
- {
- //TODO make spring specific value.
- if (!returnVal.Equals("swallow"))
- {
- return returnVal;
- }
- else
- {
- return null;
- }
- }
- }
- }
-
- #endregion
-
- #region IInitializingObject implementation
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
- ///
- ///
- /// In the event of misconfiguration (such as the failure to set a
- /// required property) or if initialization fails.
- ///
- public override void AfterPropertiesSet()
- {
- if (exceptionHandlers.Count == 0)
- {
- throw new ArgumentException("At least one handler is required");
- }
- IList newExceptionHandlers = new ArrayList();
- foreach (object o in exceptionHandlers)
- {
- string handlerString = o as string;
- if (handlerString != null)
- {
- IExceptionHandler handler = Parse(handlerString);
- if (handler == null)
- {
- throw new ArgumentException("Was not able to parse exception handler string [" + handlerString +
- "]");
- }
- newExceptionHandlers.Add(handler);
- }
-
- }
- //TODO sync.
- exceptionHandlers = newExceptionHandlers;
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Invokes handlers registered for the passed exception and
- ///
- /// The exception to be handled
- /// The that raised this exception.
- /// The output of
- protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation)
- {
- IDictionary callContextDictionary = new Hashtable();
- callContextDictionary.Add("method", invocation.Method);
- callContextDictionary.Add("args", invocation.Arguments);
- callContextDictionary.Add("target", invocation.Target);
- callContextDictionary.Add("e", ex);
- object retValue = "nomatch";
- foreach (IExceptionHandler handler in exceptionHandlers)
- {
- if (handler != null)
- {
- if (handler.CanHandleException(ex, callContextDictionary))
- {
- retValue = handler.HandleException(callContextDictionary);
- if (!handler.ContinueProcessing)
- {
- return retValue;
- }
- }
- }
- }
- return retValue;
- }
-
- ///
- /// Parses the specified handler string, creating an instance of IExceptionHander.
- ///
- /// The handler string.
- /// an instance of an exception handler or null if was not able to correctly parse
- /// handler string.
- protected virtual IExceptionHandler Parse(string handlerString)
- {
- ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString);
-
- if (!parsedAdviceExpression.Success)
- {
- log.Warn("Could not parse exception hander statement " + handlerString);
- return null;
- }
-
- return CreateExceptionHandler(parsedAdviceExpression);
- }
-
- private static IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression)
- {
- if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0)
- {
- //TODO support user selection of level, log.Debug , log.Info etc.
- LogExceptionHandler handler = new LogExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = "#log.Trace(" + parsedAdviceExpression.ActionExpressionText + ")";
- return handler;
- }
- else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0)
- {
- TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
- return handler;
- }
- else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0)
- {
- TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression);
- return handler;
- }
- else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0)
- {
- TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression);
- return handler;
- }
- else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0)
- {
- SwallowExceptionHandler handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- return handler;
- }
- else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0)
- {
- ReturnValueExceptionHandler handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
- return handler;
- }
- else
- {
- log.Warn("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression);
- }
- return null;
- }
-
- private static string ParseWrappedExceptionExpression(string action, string handlerString)
- {
- int endOfActionIndex = handlerString.IndexOf(action) + action.Length;
- string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim();
- int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" ");
-
- string rawExpressionTextPart;
- string exception;
- //Has two pieces.
- if (endOfExceptionTypeIndex > 0)
- {
- exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim();
- rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim();
- }
- else
- {
- exception = exceptionAndMessage;
- if (action.Equals("wrap"))
- {
- rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name";
- } else
- {
- rawExpressionTextPart = "'Replaced ' + #e.GetType().Name";
- }
- }
-
- if (action.Equals("wrap"))
- {
- return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart);
- } else
- {
- return string.Format("new {0}({1})", exception, rawExpressionTextPart);
- }
- }
-
-
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Reflection;
+using AopAlliance.Intercept;
+using Common.Logging;
+
+namespace Spring.Aspects.Exceptions
+{
+ ///
+ /// Exception advice to perform exception translation, conversion of exceptions to default return values, and
+ /// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as
+ /// allowing for custom translation logic by leveraging the Spring expression language.
+ ///
+ ///
+ ///
+ /// The exception handler collection can be filled with either instances of objects that implement the interface
+ /// or a string that follows a simple syntax for most common exception management
+ /// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can
+ /// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or
+ /// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the
+ /// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be
+ /// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that
+ /// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown.
+ /// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context.
+ ///
+ /// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only
+ /// the exception text for the new translated exception. If you ommit the exception text a default value will be
+ /// used.
+ /// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging
+ /// an exception will continue the evaluation process, in all other cases exceution stops at that point and the
+ /// appropriate exceptions handler is executed.
+ ///
+ ///
+ ///
+ /// on FooException1 log 'My Message, Method Name ' + #method.Name
+ /// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e)
+ /// on FooException2,Foo3Exception wrap BarException 'My Bar Message'
+ /// on FooException4 replace BarException 'My Bar Message'
+ /// on FooException5 return 32
+ /// on FooException6 swallow
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice
+ {
+ #region Fields
+
+ private static readonly ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice));
+
+ private IList exceptionHandlers = new ArrayList();
+
+ private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
+
+ private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions.
+ public override string OnExceptionNameRegex
+ {
+ get { return onExceptionNameRegex; }
+ set { onExceptionNameRegex = value; }
+ }
+
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
+ public override string OnExceptionRegex
+ {
+ get { return onExceptionRegex; }
+ set { onExceptionRegex = value; }
+ }
+
+ ///
+ /// Gets or sets the exception handler.
+ ///
+ /// The exception handler.
+ public IList ExceptionHandlers
+ {
+ get { return exceptionHandlers; }
+ set { exceptionHandlers = value; }
+ }
+
+ #endregion
+
+ #region IMethodInterceptor implementation
+
+ ///
+ /// Implement this method to perform extra treatments before and after
+ /// the call to the supplied .
+ ///
+ ///
+ ///
+ /// Polite implementations would certainly like to invoke
+ /// .
+ ///
+ ///
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied ; this return value may
+ /// well have been intercepted by the interceptor.
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ public override object Invoke(IMethodInvocation invocation)
+ {
+ try
+ {
+ return invocation.Proceed();
+ }
+ catch (TargetInvocationException ex)
+ {
+ Exception realException = ex.InnerException;
+ InvokeHandlers(realException, invocation);
+ throw realException;
+ }
+ catch (Exception ex)
+ {
+ object returnVal = InvokeHandlers(ex, invocation);
+
+ if (returnVal == null)
+ {
+ return null;
+ }
+
+ // if only logged
+ if (returnVal.Equals("logged"))
+ {
+ throw;
+ }
+
+ //only here if we only are swallowing, returning alternative value, no matching handler was found.
+
+ // no matching handler.
+ if (returnVal.Equals("nomatch"))
+ {
+ throw;
+ }
+ else
+ {
+ //TODO make spring specific value.
+ if (!returnVal.Equals("swallow"))
+ {
+ return returnVal;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region IInitializingObject implementation
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
+ ///
+ ///
+ /// In the event of misconfiguration (such as the failure to set a
+ /// required property) or if initialization fails.
+ ///
+ public override void AfterPropertiesSet()
+ {
+ if (exceptionHandlers.Count == 0)
+ {
+ throw new ArgumentException("At least one handler is required");
+ }
+ IList newExceptionHandlers = new ArrayList();
+ foreach (object o in exceptionHandlers)
+ {
+ string handlerString = o as string;
+ if (handlerString != null)
+ {
+ IExceptionHandler handler = Parse(handlerString);
+ if (handler == null)
+ {
+ throw new ArgumentException("Was not able to parse exception handler string [" + handlerString +
+ "]");
+ }
+ newExceptionHandlers.Add(handler);
+ }
+
+ }
+ //TODO sync.
+ exceptionHandlers = newExceptionHandlers;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Invokes handlers registered for the passed exception and
+ ///
+ /// The exception to be handled
+ /// The that raised this exception.
+ /// The output of
+ protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation)
+ {
+ IDictionary callContextDictionary = new Hashtable();
+ callContextDictionary.Add("method", invocation.Method);
+ callContextDictionary.Add("args", invocation.Arguments);
+ callContextDictionary.Add("target", invocation.Target);
+ callContextDictionary.Add("e", ex);
+ object retValue = "nomatch";
+ foreach (IExceptionHandler handler in exceptionHandlers)
+ {
+ if (handler != null)
+ {
+ if (handler.CanHandleException(ex, callContextDictionary))
+ {
+ retValue = handler.HandleException(callContextDictionary);
+ if (!handler.ContinueProcessing)
+ {
+ return retValue;
+ }
+ }
+ }
+ }
+ return retValue;
+ }
+
+ ///
+ /// Parses the specified handler string, creating an instance of IExceptionHander.
+ ///
+ /// The handler string.
+ /// an instance of an exception handler or null if was not able to correctly parse
+ /// handler string.
+ protected virtual IExceptionHandler Parse(string handlerString)
+ {
+ ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString);
+
+ if (!parsedAdviceExpression.Success)
+ {
+ log.Warn("Could not parse exception hander statement " + handlerString);
+ return null;
+ }
+
+ return CreateExceptionHandler(parsedAdviceExpression);
+ }
+
+ private static IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression)
+ {
+ if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0)
+ {
+ //TODO support user selection of level, log.Debug , log.Info etc.
+ LogExceptionHandler handler = new LogExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ handler.ActionExpressionText = "#log.Trace(" + parsedAdviceExpression.ActionExpressionText + ")";
+ return handler;
+ }
+ else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0)
+ {
+ TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
+ return handler;
+ }
+ else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0)
+ {
+ TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression);
+ return handler;
+ }
+ else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0)
+ {
+ TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression);
+ return handler;
+ }
+ else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0)
+ {
+ SwallowExceptionHandler handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ return handler;
+ }
+ else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0)
+ {
+ ReturnValueExceptionHandler handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames);
+ handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
+ handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
+ return handler;
+ }
+ else
+ {
+ log.Warn("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression);
+ }
+ return null;
+ }
+
+ private static string ParseWrappedExceptionExpression(string action, string handlerString)
+ {
+ int endOfActionIndex = handlerString.IndexOf(action) + action.Length;
+ string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim();
+ int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" ");
+
+ string rawExpressionTextPart;
+ string exception;
+ //Has two pieces.
+ if (endOfExceptionTypeIndex > 0)
+ {
+ exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim();
+ rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim();
+ }
+ else
+ {
+ exception = exceptionAndMessage;
+ if (action.Equals("wrap"))
+ {
+ rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name";
+ } else
+ {
+ rawExpressionTextPart = "'Replaced ' + #e.GetType().Name";
+ }
+ }
+
+ if (action.Equals("wrap"))
+ {
+ return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart);
+ } else
+ {
+ return string.Format("new {0}({1})", exception, rawExpressionTextPart);
+ }
+ }
+
+
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs
index 56305bc1..36334288 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs
@@ -1,91 +1,90 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 Common.Logging;
-using Spring.Expressions;
-
-namespace Spring.Aspects.Exceptions
-{
- ///
- /// Log the exceptions. Default log nameis "LogExceptionHandler" and log level is Debug
- ///
- /// Mark Pollack
- /// $Id: LogExceptionHandler.cs,v 1.6 2008/02/26 00:03:24 markpollack Exp $
- public class LogExceptionHandler : AbstractExceptionHandler
- {
- private string logName = "LogExceptionHandler";
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- public LogExceptionHandler()
- {
- ContinueProcessing = true;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The exception names.
- public LogExceptionHandler(string[] exceptionNames) : base(exceptionNames)
- {
- ContinueProcessing = true;
- }
-
-
-
- ///
- /// Gets or sets the name of the log.
- ///
- /// The name of the log.
- public string LogName
- {
- get { return logName; }
- set { logName = value; }
- }
-
-
- ///
- /// Handles the exception.
- ///
- /// the calling context dictionary
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- ///
- public override object HandleException(IDictionary callContextDictionary)
- {
- ILog log = LogManager.GetLogger(logName);
- callContextDictionary.Add("log", log);
- try
- {
- IExpression expression = Expression.Parse(ActionExpressionText);
- expression.GetValue(null, callContextDictionary);
- }
- catch (Exception e)
- {
- log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
- }
- return "logged";
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 Common.Logging;
+using Spring.Expressions;
+
+namespace Spring.Aspects.Exceptions
+{
+ ///
+ /// Log the exceptions. Default log nameis "LogExceptionHandler" and log level is Debug
+ ///
+ /// Mark Pollack
+ public class LogExceptionHandler : AbstractExceptionHandler
+ {
+ private string logName = "LogExceptionHandler";
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LogExceptionHandler()
+ {
+ ContinueProcessing = true;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception names.
+ public LogExceptionHandler(string[] exceptionNames) : base(exceptionNames)
+ {
+ ContinueProcessing = true;
+ }
+
+
+
+ ///
+ /// Gets or sets the name of the log.
+ ///
+ /// The name of the log.
+ public string LogName
+ {
+ get { return logName; }
+ set { logName = value; }
+ }
+
+
+ ///
+ /// Handles the exception.
+ ///
+ /// the calling context dictionary
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ ///
+ public override object HandleException(IDictionary callContextDictionary)
+ {
+ ILog log = LogManager.GetLogger(logName);
+ callContextDictionary.Add("log", log);
+ try
+ {
+ IExpression expression = Expression.Parse(ActionExpressionText);
+ expression.GetValue(null, callContextDictionary);
+ }
+ catch (Exception e)
+ {
+ log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
+ }
+ return "logged";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs
index 46c239df..262dc295 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ReturnValueExceptionHandler.cs
@@ -1,72 +1,71 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 Common.Logging;
-using Spring.Expressions;
-
-namespace Spring.Aspects.Exceptions
-{
- ///
- /// Evaluates the expression for the return value of the method.
- ///
- /// Mark Pollack
- /// $Id: ReturnValueExceptionHandler.cs,v 1.3 2007/10/10 18:07:46 markpollack Exp $
- public class ReturnValueExceptionHandler : AbstractExceptionHandler
- {
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ReturnValueExceptionHandler()
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The exception names.
- public ReturnValueExceptionHandler(string[] exceptionNames) : base(exceptionNames)
- {
- }
-
-
-
- ///
- /// Returns the result of evaluating the translation expression.
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- public override object HandleException(IDictionary callContextDictionary)
- {
- object returnVal = null;
- try
- {
- IExpression expression = Expression.Parse(ActionExpressionText);
- returnVal = expression.GetValue(null, callContextDictionary);
- }
- catch (Exception e)
- {
- log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
- }
- return returnVal;
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 Common.Logging;
+using Spring.Expressions;
+
+namespace Spring.Aspects.Exceptions
+{
+ ///
+ /// Evaluates the expression for the return value of the method.
+ ///
+ /// Mark Pollack
+ public class ReturnValueExceptionHandler : AbstractExceptionHandler
+ {
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ReturnValueExceptionHandler()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception names.
+ public ReturnValueExceptionHandler(string[] exceptionNames) : base(exceptionNames)
+ {
+ }
+
+
+
+ ///
+ /// Returns the result of evaluating the translation expression.
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ public override object HandleException(IDictionary callContextDictionary)
+ {
+ object returnVal = null;
+ try
+ {
+ IExpression expression = Expression.Parse(ActionExpressionText);
+ returnVal = expression.GetValue(null, callContextDictionary);
+ }
+ catch (Exception e)
+ {
+ log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
+ }
+ return returnVal;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs
index f7f22db2..0b02bf91 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/SwallowExceptionHandler.cs
@@ -1,58 +1,57 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Collections;
-
-namespace Spring.Aspects.Exceptions
-{
- ///
- /// Returns a token to indicate that this exception should be swallowed.
- ///
- /// Mark Pollack
- /// $Id: SwallowExceptionHandler.cs,v 1.2 2007/10/02 21:56:53 markpollack Exp $
- public class SwallowExceptionHandler : AbstractExceptionHandler
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public SwallowExceptionHandler()
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The exception names.
- public SwallowExceptionHandler(string[] exceptionNames) : base(exceptionNames)
- {
- }
-
-
-
- ///
- /// Handles the exception.
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- public override object HandleException(IDictionary callContextDictionary)
- {
- return "swallow";
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Collections;
+
+namespace Spring.Aspects.Exceptions
+{
+ ///
+ /// Returns a token to indicate that this exception should be swallowed.
+ ///
+ /// Mark Pollack
+ public class SwallowExceptionHandler : AbstractExceptionHandler
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SwallowExceptionHandler()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception names.
+ public SwallowExceptionHandler(string[] exceptionNames) : base(exceptionNames)
+ {
+ }
+
+
+
+ ///
+ /// Handles the exception.
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ public override object HandleException(IDictionary callContextDictionary)
+ {
+ return "swallow";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs
index 65700a5a..2709fd90 100644
--- a/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/Exceptions/TranslationExceptionHandler.cs
@@ -1,80 +1,79 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 Common.Logging;
-using Spring.Expressions;
-
-namespace Spring.Aspects.Exceptions
-{
- ///
- /// Translates from one exception to another based. My wrap or replace exception depending on the expression.
- ///
- /// Mark Pollack
- /// $Id: TranslationExceptionHandler.cs,v 1.3 2007/10/10 18:07:46 markpollack Exp $
- public class TranslationExceptionHandler : AbstractExceptionHandler
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public TranslationExceptionHandler()
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The exception names.
- public TranslationExceptionHandler(string[] exceptionNames) : base(exceptionNames)
- {
- }
-
-
-
- ///
- /// Handles the exception.
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- public override object HandleException(IDictionary callContextDictionary)
- {
- object o = null;
- try {
- IExpression expression = Expression.Parse(ActionExpressionText);
- o = expression.GetValue(null, callContextDictionary);
- }
- catch (Exception e)
- {
- log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
- }
- Exception translatedException = o as Exception;
- if (translatedException != null)
- {
- ThrowTranslatedException(translatedException);
- }
- return null;
- }
-
- private void ThrowTranslatedException(Exception exception)
- {
- throw exception;
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 Common.Logging;
+using Spring.Expressions;
+
+namespace Spring.Aspects.Exceptions
+{
+ ///
+ /// Translates from one exception to another based. My wrap or replace exception depending on the expression.
+ ///
+ /// Mark Pollack
+ public class TranslationExceptionHandler : AbstractExceptionHandler
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TranslationExceptionHandler()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception names.
+ public TranslationExceptionHandler(string[] exceptionNames) : base(exceptionNames)
+ {
+ }
+
+
+
+ ///
+ /// Handles the exception.
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ public override object HandleException(IDictionary callContextDictionary)
+ {
+ object o = null;
+ try {
+ IExpression expression = Expression.Parse(ActionExpressionText);
+ o = expression.GetValue(null, callContextDictionary);
+ }
+ catch (Exception e)
+ {
+ log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
+ }
+ Exception translatedException = o as Exception;
+ if (translatedException != null)
+ {
+ ThrowTranslatedException(translatedException);
+ }
+ return null;
+ }
+
+ private void ThrowTranslatedException(Exception exception)
+ {
+ throw exception;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs
index 3ac61223..73f65cbd 100644
--- a/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs
+++ b/src/Spring/Spring.Aop/Aspects/IExceptionHandler.cs
@@ -1,97 +1,96 @@
-#region License
-
-/*
- * Copyright 2002-2007 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;
-
-namespace Spring.Aspects
-{
- ///
- /// Handles a thrown exception providing calling context.
- ///
- /// Mark Pollack
- /// $Id: IExceptionHandler.cs,v 1.1 2007/10/08 22:05:16 markpollack Exp $
- public interface IExceptionHandler
- {
- ///
- /// Determines whether this instance can handle the exception the specified exception.
- ///
- /// The exception.
- /// The call context dictionary.
- ///
- /// true if this instance can handle the specified exception; otherwise, false.
- ///
- bool CanHandleException(Exception ex, IDictionary callContextDictionary);
-
- ///
- /// Handles the exception.
- ///
- /// The call context dictionary.
- ///
- /// The return value from handling the exception, if not rethrown or a new exception is thrown.
- ///
- object HandleException(IDictionary callContextDictionary);
-
- ///
- /// Gets the source exception names.
- ///
- /// The source exception names.
- IList SourceExceptionNames
- {
- get; set;
- }
-
- ///
- /// Gets the source exception types.
- ///
- /// The source exception types.
- IList SourceExceptionTypes
- {
- get; set;
- }
-
- ///
- /// Gets the translation expression text
- ///
- /// The translation expression text
- string ActionExpressionText
- {
- get; set;
- }
-
- ///
- /// Gets or sets the constraint expression text.
- ///
- /// The constraint expression text.
- string ConstraintExpressionText
- {
- get; set;
- }
-
- ///
- /// Gets a value indicating whether to continue processing.
- ///
- /// true if continue processing; otherwise, false.
- bool ContinueProcessing
- {
- get; set;
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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;
+
+namespace Spring.Aspects
+{
+ ///
+ /// Handles a thrown exception providing calling context.
+ ///
+ /// Mark Pollack
+ public interface IExceptionHandler
+ {
+ ///
+ /// Determines whether this instance can handle the exception the specified exception.
+ ///
+ /// The exception.
+ /// The call context dictionary.
+ ///
+ /// true if this instance can handle the specified exception; otherwise, false.
+ ///
+ bool CanHandleException(Exception ex, IDictionary callContextDictionary);
+
+ ///
+ /// Handles the exception.
+ ///
+ /// The call context dictionary.
+ ///
+ /// The return value from handling the exception, if not rethrown or a new exception is thrown.
+ ///
+ object HandleException(IDictionary callContextDictionary);
+
+ ///
+ /// Gets the source exception names.
+ ///
+ /// The source exception names.
+ IList SourceExceptionNames
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets the source exception types.
+ ///
+ /// The source exception types.
+ IList SourceExceptionTypes
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets the translation expression text
+ ///
+ /// The translation expression text
+ string ActionExpressionText
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets or sets the constraint expression text.
+ ///
+ /// The constraint expression text.
+ string ConstraintExpressionText
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets a value indicating whether to continue processing.
+ ///
+ /// true if continue processing; otherwise, false.
+ bool ContinueProcessing
+ {
+ get; set;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
index a0b0b581..24016876 100644
--- a/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Logging/AbstractLoggingAdvice.cs
@@ -1,240 +1,239 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Reflection;
-using AopAlliance.Intercept;
-using Common.Logging;
-using Spring.Aop.Framework;
-
-namespace Spring.Aspects.Logging
-{
- ///
- /// Abstract base class for logging advice
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: AbstractLoggingAdvice.cs,v 1.2 2007/12/06 17:17:19 markpollack Exp $
- public abstract class AbstractLoggingAdvice : IMethodInterceptor
- {
- #region Fields
-
- ///
- /// The default ILog instance used to write logging messages.
- ///
- protected ILog defaultLogger = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType);
-
- ///
- /// Indicates whether or not proxy type names should be hidden when using dynamic loggers.
- ///
- private bool hideProxyTypeNames = false;
-
- #endregion
-
- #region Properties
-
- ///
- /// Sets a value indicating whether to use a dynamic logger or static logger
- ///
- /// Default is to use a static logger.
- ///
- /// Used to determine which ILog instance should be used to write log messages for
- /// a particular method invocation: a dynamic one for the Type getting called,
- /// or a static one for the Type of the trace interceptor.
- ///
- ///
- /// Specify either this property or LoggerName, not both.
- ///
- ///
- /// true if use dynamic logger; otherwise, false.
- public bool UseDynamicLogger
- {
- set
- {
- defaultLogger = (value ? null : LogManager.GetLogger(GetType()));
- }
- }
-
- ///
- /// Sets the name of the logger to use.
- ///
- ///
- /// The name will be passed to the underlying logging implementation through Common.Logging,
- /// getting interpreted as the log category according to the loggers configuration.
- ///
- /// This can be specified to not log into the category of a Type (whether this
- /// interceptor's class or the class getting called) but rather to a specific named category.
- ///
- ///
- /// Specify either this property or UseDynamicLogger, but not both.
- ///
- ///
- /// The name of the logger.
- public string LoggerName
- {
- set
- {
- defaultLogger = LogManager.GetLogger(value);
- }
- }
-
-
- ///
- /// Sets a value indicating whether hide proxy type names (whenever possible)
- /// when using dynamic loggers, i.e. property UseDynamicLogger is set to true.
- ///
- /// true if [hide proxy type names]; otherwise, false.
- public bool HideProxyTypeNames
- {
- set { hideProxyTypeNames = value; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Adds logging to the method invocation.
- ///
- ///
- /// The method IsInterceptorEnabled is called
- /// as an optimization to determine if logging should be applied. If logging should be
- /// applied, the method invocation is passed to the InvokeUnderLog method for handling.
- /// If not, the method proceeds as normal.
- ///
- ///
- /// The method invocation that is being intercepted.
- ///
- ///
- /// The result of the call to the
- /// method of
- /// the supplied ; this return value may
- /// well have been intercepted by the interceptor.
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- public object Invoke(IMethodInvocation invocation)
- {
- object o = invocation.This;
- ILog log = GetLoggerForInvocation(invocation);
- if (IsInterceptorEnabled(invocation, log))
- {
- return InvokeUnderLog(invocation, log);
- }
- else
- {
- return invocation.Proceed();
- }
-
- }
-
- ///
- /// Determines whether the interceptor is enabled for the specified invocation, that
- /// is, whether the method InvokeUnderLog is called.
- ///
- /// The default behavior is to check whether the given ILog instance
- /// is enabled by calling IsLogEnabled, whose default behavior is to check if
- /// the TRACE level of logging is enabled. Subclasses
- /// The invocation.
- /// The log to write messages to
- ///
- /// true if [is interceptor enabled] [the specified invocation]; otherwise, false.
- ///
- protected virtual bool IsInterceptorEnabled(IMethodInvocation invocation, ILog log)
- {
- return IsLogEnabled(log);
- }
-
- ///
- /// Determines whether the given log is enabled.
- ///
- ///
- /// Default is true when the trace level is enabled. Subclasses may override this
- /// to change the level at which logging occurs, or return true to ignore level
- /// checks.
- /// The log instance to check.
- ///
- /// true if log is for a given log level; otherwise, false.
- ///
- protected virtual bool IsLogEnabled(ILog log)
- {
- return log.IsTraceEnabled;
- }
-
- ///
- /// Subclasses must override this method to perform any tracing around the supplied
- /// IMethodInvocation.
- ///
- ///
- /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes
- /// by calling IMethodInvocation.Proceed().
- ///
- /// By default, the passed-in ILog instance will have log level
- /// "trace" enabled. Subclasses do not have to check for this again, unless
- /// they overwrite the IsInterceptorEnabled method to modify
- /// the default behavior.
- ///
- ///
- /// The method invocation to log
- /// The log to write messages to
- /// The result of the call to IMethodInvocation.Proceed()
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- protected abstract object InvokeUnderLog(IMethodInvocation invocation, ILog log);
-
-
- ///
- /// Gets the appropriate log instance to use for the given IMethodInvocation.
- ///
- ///
- /// If the UseDynamicLogger property is set to true, the ILog instance will be
- /// for the target class of the IMethodInvocation, otherwise the log will be the
- /// default static logger.
- ///
- /// The method invocation being logged.
- /// The ILog instance to use.
- protected virtual ILog GetLoggerForInvocation(IMethodInvocation invocation)
- {
- if (defaultLogger != null)
- {
- return defaultLogger;
- }
- else
- {
- object target = invocation.This;
- Type logCategoryType = target.GetType();
- if (hideProxyTypeNames)
- {
- logCategoryType = AopUtils.GetTargetType(target);
- }
- return LogManager.GetLogger(logCategoryType);
- }
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Reflection;
+using AopAlliance.Intercept;
+using Common.Logging;
+using Spring.Aop.Framework;
+
+namespace Spring.Aspects.Logging
+{
+ ///
+ /// Abstract base class for logging advice
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public abstract class AbstractLoggingAdvice : IMethodInterceptor
+ {
+ #region Fields
+
+ ///
+ /// The default ILog instance used to write logging messages.
+ ///
+ protected ILog defaultLogger = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Indicates whether or not proxy type names should be hidden when using dynamic loggers.
+ ///
+ private bool hideProxyTypeNames = false;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Sets a value indicating whether to use a dynamic logger or static logger
+ ///
+ /// Default is to use a static logger.
+ ///
+ /// Used to determine which ILog instance should be used to write log messages for
+ /// a particular method invocation: a dynamic one for the Type getting called,
+ /// or a static one for the Type of the trace interceptor.
+ ///
+ ///
+ /// Specify either this property or LoggerName, not both.
+ ///
+ ///
+ /// true if use dynamic logger; otherwise, false.
+ public bool UseDynamicLogger
+ {
+ set
+ {
+ defaultLogger = (value ? null : LogManager.GetLogger(GetType()));
+ }
+ }
+
+ ///
+ /// Sets the name of the logger to use.
+ ///
+ ///
+ /// The name will be passed to the underlying logging implementation through Common.Logging,
+ /// getting interpreted as the log category according to the loggers configuration.
+ ///
+ /// This can be specified to not log into the category of a Type (whether this
+ /// interceptor's class or the class getting called) but rather to a specific named category.
+ ///
+ ///
+ /// Specify either this property or UseDynamicLogger, but not both.
+ ///
+ ///
+ /// The name of the logger.
+ public string LoggerName
+ {
+ set
+ {
+ defaultLogger = LogManager.GetLogger(value);
+ }
+ }
+
+
+ ///
+ /// Sets a value indicating whether hide proxy type names (whenever possible)
+ /// when using dynamic loggers, i.e. property UseDynamicLogger is set to true.
+ ///
+ /// true if [hide proxy type names]; otherwise, false.
+ public bool HideProxyTypeNames
+ {
+ set { hideProxyTypeNames = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Adds logging to the method invocation.
+ ///
+ ///
+ /// The method IsInterceptorEnabled is called
+ /// as an optimization to determine if logging should be applied. If logging should be
+ /// applied, the method invocation is passed to the InvokeUnderLog method for handling.
+ /// If not, the method proceeds as normal.
+ ///
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied ; this return value may
+ /// well have been intercepted by the interceptor.
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ public object Invoke(IMethodInvocation invocation)
+ {
+ object o = invocation.This;
+ ILog log = GetLoggerForInvocation(invocation);
+ if (IsInterceptorEnabled(invocation, log))
+ {
+ return InvokeUnderLog(invocation, log);
+ }
+ else
+ {
+ return invocation.Proceed();
+ }
+
+ }
+
+ ///
+ /// Determines whether the interceptor is enabled for the specified invocation, that
+ /// is, whether the method InvokeUnderLog is called.
+ ///
+ /// The default behavior is to check whether the given ILog instance
+ /// is enabled by calling IsLogEnabled, whose default behavior is to check if
+ /// the TRACE level of logging is enabled. Subclasses
+ /// The invocation.
+ /// The log to write messages to
+ ///
+ /// true if [is interceptor enabled] [the specified invocation]; otherwise, false.
+ ///
+ protected virtual bool IsInterceptorEnabled(IMethodInvocation invocation, ILog log)
+ {
+ return IsLogEnabled(log);
+ }
+
+ ///
+ /// Determines whether the given log is enabled.
+ ///
+ ///
+ /// Default is true when the trace level is enabled. Subclasses may override this
+ /// to change the level at which logging occurs, or return true to ignore level
+ /// checks.
+ /// The log instance to check.
+ ///
+ /// true if log is for a given log level; otherwise, false.
+ ///
+ protected virtual bool IsLogEnabled(ILog log)
+ {
+ return log.IsTraceEnabled;
+ }
+
+ ///
+ /// Subclasses must override this method to perform any tracing around the supplied
+ /// IMethodInvocation.
+ ///
+ ///
+ /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes
+ /// by calling IMethodInvocation.Proceed().
+ ///
+ /// By default, the passed-in ILog instance will have log level
+ /// "trace" enabled. Subclasses do not have to check for this again, unless
+ /// they overwrite the IsInterceptorEnabled method to modify
+ /// the default behavior.
+ ///
+ ///
+ /// The method invocation to log
+ /// The log to write messages to
+ /// The result of the call to IMethodInvocation.Proceed()
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ protected abstract object InvokeUnderLog(IMethodInvocation invocation, ILog log);
+
+
+ ///
+ /// Gets the appropriate log instance to use for the given IMethodInvocation.
+ ///
+ ///
+ /// If the UseDynamicLogger property is set to true, the ILog instance will be
+ /// for the target class of the IMethodInvocation, otherwise the log will be the
+ /// default static logger.
+ ///
+ /// The method invocation being logged.
+ /// The ILog instance to use.
+ protected virtual ILog GetLoggerForInvocation(IMethodInvocation invocation)
+ {
+ if (defaultLogger != null)
+ {
+ return defaultLogger;
+ }
+ else
+ {
+ object target = invocation.This;
+ Type logCategoryType = target.GetType();
+ if (hideProxyTypeNames)
+ {
+ logCategoryType = AopUtils.GetTargetType(target);
+ }
+ return LogManager.GetLogger(logCategoryType);
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
index c7374ec8..2135e1ce 100644
--- a/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/Logging/SimpleLoggingAdvice.cs
@@ -1,459 +1,458 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Reflection;
-using System.Text;
-using AopAlliance.Intercept;
-using Common.Logging;
-
-namespace Spring.Aspects.Logging
-{
- ///
- /// Configurable advice for logging.
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: SimpleLoggingAdvice.cs,v 1.7 2008/04/04 15:30:13 markpollack Exp $
- public class SimpleLoggingAdvice : AbstractLoggingAdvice
- {
- #region Fields
-
- ///
- /// Flag to indicate if unique identifier should be in the log message.
- ///
- private bool logUniqueIdentifier;
-
- ///
- /// Flag to indicate if the execution time should be in the log message.
- ///
- private bool logExecutionTime;
-
- ///
- /// Flag to indicate if the method arguments should be in the log message.
- ///
- private bool logMethodArguments;
-
- ///
- /// Flag to indicate if the return value should be in the log message.
- ///
- private bool logReturnValue;
-
- ///
- /// The separator string to use for delmiting log message fields.
- ///
- private string separator = ", ";
-
- ///
- /// The log level to use for logging the entry, exit, exception messages.
- ///
- private LogLevel logLevel = LogLevel.Trace;
-
-
- #endregion
-
- #region Constructor(s)
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SimpleLoggingAdvice()
- {
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// if set to true to use dynamic logger, if
- /// false use static logger.
- public SimpleLoggingAdvice(bool useDynamicLogger)
- {
- UseDynamicLogger = useDynamicLogger;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets or sets a value indicating whether to log a unique identifier with the log message.
- ///
- /// true if [log unique identifier]; otherwise, false.
- public bool LogUniqueIdentifier
- {
- get { return logUniqueIdentifier; }
- set { logUniqueIdentifier = value; }
- }
-
- ///
- /// Gets or sets a value indicating whether to log execution time.
- ///
- /// true if log execution time; otherwise, false.
- public bool LogExecutionTime
- {
- get { return logExecutionTime; }
- set { logExecutionTime = value; }
- }
-
- ///
- /// Gets or sets a value indicating whether log method arguments.
- ///
- /// true if log method arguments]; otherwise, false.
- public bool LogMethodArguments
- {
- get { return logMethodArguments; }
- set { logMethodArguments = value; }
- }
-
- ///
- /// Gets or sets a value indicating whether log return value.
- ///
- /// true if log return value; otherwise, false.
- public bool LogReturnValue
- {
- get { return logReturnValue; }
- set { logReturnValue = value; }
- }
-
- ///
- /// Gets or sets the seperator string to use for delmiting log message fields.
- ///
- /// The seperator.
- public string Separator
- {
- get { return separator; }
- set { separator = value; }
- }
-
- ///
- /// Gets or sets the entry log level.
- ///
- /// The entry log level.
- public LogLevel LogLevel
- {
- get { return logLevel; }
- set { logLevel = value; }
- }
-
- #endregion
-
- #region Protected Methods
-
- ///
- /// Subclasses must override this method to perform any tracing around the supplied
- /// IMethodInvocation.
- ///
- /// The method invocation to log
- /// The log to write messages to
- ///
- /// The result of the call to IMethodInvocation.Proceed()
- ///
- ///
- /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes
- /// by calling IMethodInvocation.Proceed().
- ///
- /// By default, the passed-in ILog instance will have log level
- /// "trace" enabled. Subclasses do not have to check for this again, unless
- /// they overwrite the IsInterceptorEnabled method to modify
- /// the default behavior.
- ///
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- protected override object InvokeUnderLog(IMethodInvocation invocation, ILog log)
- {
- object returnValue = null;
- bool exitThroughException = false;
-
- DateTime startTime = DateTime.Now;
- string uniqueIdentifier = null;
-
- if (LogUniqueIdentifier)
- {
- uniqueIdentifier = CreateUniqueIdentifier();
- }
- try
- {
- WriteToLog(LogLevel, log, GetEntryMessage(invocation, uniqueIdentifier), null);
- returnValue = invocation.Proceed();
- return returnValue;
- } catch (Exception e)
- {
- TimeSpan executionTimeSpan = DateTime.Now - startTime;
- WriteToLog(LogLevel, log, GetExceptionMessage(invocation, e, executionTimeSpan, uniqueIdentifier), e);
- exitThroughException = true;
- throw;
- }
- finally
- {
- if (!exitThroughException)
- {
- TimeSpan executionTimeSpan = DateTime.Now - startTime;
- WriteToLog(LogLevel, log, GetExitMessage(invocation, returnValue, executionTimeSpan, uniqueIdentifier), null);
- }
- }
- }
-
- ///
- /// Determines whether the given log is enabled.
- ///
- /// The log instance to check.
- ///
- /// true if log is for a given log level; otherwise, false.
- ///
- ///
- /// Default is true when the trace level is enabled. Subclasses may override this
- /// to change the level at which logging occurs, or return true to ignore level
- /// checks.
- protected override bool IsLogEnabled(ILog log)
- {
- switch (LogLevel)
- {
- case LogLevel.All:
- case LogLevel.Trace:
- if (log.IsTraceEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Debug:
- if (log.IsDebugEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Error:
- if (log.IsErrorEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Fatal:
- if (log.IsFatalEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Info:
- if (log.IsInfoEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Warn:
- if (log.IsWarnEnabled)
- {
- return true;
- }
- break;
- case LogLevel.Off:
- default:
- break;
- }
- return false;
- }
-
- ///
- /// Creates a unique identifier.
- ///
- ///
- /// Default implementation uses Guid.NewGuid(). Subclasses may override to provide an alternative
- /// ID generation implementation.
- ///
- /// A unique identifier
- protected virtual string CreateUniqueIdentifier()
- {
- return Guid.NewGuid().ToString();
- }
-
- ///
- /// Gets the entry message to log
- ///
- /// The invocation.
- /// The id string.
- /// The entry log message
- protected virtual string GetEntryMessage(IMethodInvocation invocation, string idString)
- {
- StringBuilder sb = new StringBuilder(128);
- sb.Append("Entering ");
- AppendCommonInformation(sb, invocation, idString);
- if (logMethodArguments)
- {
- sb.Append(GetMethodArgumentAsString(invocation));
- }
-
- return RemoveLastSeparator(sb.ToString(), Separator);
- }
-
- ///
- /// Gets the exception message.
- ///
- /// The method invocation.
- /// The thown exception.
- /// The execution time span.
- /// The id string.
- /// The exception log message.
- protected virtual string GetExceptionMessage(IMethodInvocation invocation, Exception e, TimeSpan executionTimeSpan, string idString)
- {
- StringBuilder sb = new StringBuilder(128);
- sb.Append("Exception thrown in ");
- sb.Append(invocation.Method.Name).Append(Separator);
- AppendCommonInformation(sb, invocation, idString);
- if (LogExecutionTime)
- {
- sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms");
- }
-
- return RemoveLastSeparator(sb.ToString(), Separator);
- }
-
-
- ///
- /// Gets the exit log message.
- ///
- /// The method invocation.
- /// The return value.
- /// The execution time span.
- /// The id string.
- /// the exit log message
- protected virtual string GetExitMessage(IMethodInvocation invocation, object returnValue, TimeSpan executionTimeSpan, string idString)
- {
- StringBuilder sb = new StringBuilder(128);
- sb.Append("Exiting ");
- AppendCommonInformation(sb, invocation, idString);
- if (LogReturnValue && invocation.Method.ReturnType != typeof(void))
- {
- sb.Append("return=").Append(returnValue).Append(Separator);
- }
- if (LogExecutionTime)
- {
- sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms");
- }
- return RemoveLastSeparator(sb.ToString(), Separator);
- }
-
-
- ///
- /// Appends common information across entry,exit, exception logging
- ///
- /// Add method name and unique identifier if required.
- /// The string buffer building logging message.
- /// The method invocation.
- /// The unique identifier string.
- protected virtual void AppendCommonInformation(StringBuilder sb, IMethodInvocation invocation, string idString)
- {
- sb.Append(invocation.Method.Name);
- if (LogUniqueIdentifier)
- {
- sb.Append(Separator).Append(idString);
- }
- sb.Append(Separator);
- }
-
- ///
- /// Gets the method argument as argumen name/value pairs.
- ///
- /// The method invocation.
- /// string for logging method argument name and values.
- protected virtual string GetMethodArgumentAsString(IMethodInvocation invocation)
- {
- StringBuilder sb = new StringBuilder(128);
- ParameterInfo[] parameterInfos = invocation.Method.GetParameters();
- object[] argValues = invocation.Arguments;
- for (int i=0; i< parameterInfos.Length; i++)
- {
- sb.Append(parameterInfos[i].Name).Append("=").Append(argValues[i]);
- if (i != parameterInfos.Length) sb.Append("; ");
- }
-
- return RemoveLastSeparator(sb.ToString(), "; ");
- }
-
- #endregion
-
- #region Private Methods
-
- private string RemoveLastSeparator(string str, string separator)
- {
- if (str.EndsWith(separator))
- {
- return str.Substring(0, str.Length - separator.Length);
- }
- else
- {
- return str;
- }
- }
-
- private void WriteToLog(LogLevel logLevel, ILog log, string text, Exception e)
- {
- switch (logLevel)
- {
- case LogLevel.All:
- case LogLevel.Trace:
- if (log.IsTraceEnabled)
- {
- if (e == null) log.Trace(text); else log.Trace(text, e);
- }
- break;
- case LogLevel.Debug:
- if (log.IsDebugEnabled)
- {
- if (e == null) log.Debug(text); else log.Debug(text, e);
- }
- break;
- case LogLevel.Error:
- if (log.IsErrorEnabled)
- {
- if (e == null) log.Error(text); else log.Error(text, e);
- }
- break;
- case LogLevel.Fatal:
- if (log.IsFatalEnabled)
- {
- if (e == null) log.Fatal(text); else log.Fatal(text, e);
- }
- break;
- case LogLevel.Info:
- if (log.IsInfoEnabled)
- {
- if (e == null) log.Info(text); else log.Info(text, e);
- }
- break;
- case LogLevel.Warn:
- if (log.IsWarnEnabled)
- {
- if (e == null) log.Warn(text); else log.Warn(text, e);
- }
- break;
- case LogLevel.Off:
- default:
- break;
- }
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Reflection;
+using System.Text;
+using AopAlliance.Intercept;
+using Common.Logging;
+
+namespace Spring.Aspects.Logging
+{
+ ///
+ /// Configurable advice for logging.
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public class SimpleLoggingAdvice : AbstractLoggingAdvice
+ {
+ #region Fields
+
+ ///
+ /// Flag to indicate if unique identifier should be in the log message.
+ ///
+ private bool logUniqueIdentifier;
+
+ ///
+ /// Flag to indicate if the execution time should be in the log message.
+ ///
+ private bool logExecutionTime;
+
+ ///
+ /// Flag to indicate if the method arguments should be in the log message.
+ ///
+ private bool logMethodArguments;
+
+ ///
+ /// Flag to indicate if the return value should be in the log message.
+ ///
+ private bool logReturnValue;
+
+ ///
+ /// The separator string to use for delmiting log message fields.
+ ///
+ private string separator = ", ";
+
+ ///
+ /// The log level to use for logging the entry, exit, exception messages.
+ ///
+ private LogLevel logLevel = LogLevel.Trace;
+
+
+ #endregion
+
+ #region Constructor(s)
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SimpleLoggingAdvice()
+ {
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true to use dynamic logger, if
+ /// false use static logger.
+ public SimpleLoggingAdvice(bool useDynamicLogger)
+ {
+ UseDynamicLogger = useDynamicLogger;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets a value indicating whether to log a unique identifier with the log message.
+ ///
+ /// true if [log unique identifier]; otherwise, false.
+ public bool LogUniqueIdentifier
+ {
+ get { return logUniqueIdentifier; }
+ set { logUniqueIdentifier = value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to log execution time.
+ ///
+ /// true if log execution time; otherwise, false.
+ public bool LogExecutionTime
+ {
+ get { return logExecutionTime; }
+ set { logExecutionTime = value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether log method arguments.
+ ///
+ /// true if log method arguments]; otherwise, false.
+ public bool LogMethodArguments
+ {
+ get { return logMethodArguments; }
+ set { logMethodArguments = value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether log return value.
+ ///
+ /// true if log return value; otherwise, false.
+ public bool LogReturnValue
+ {
+ get { return logReturnValue; }
+ set { logReturnValue = value; }
+ }
+
+ ///
+ /// Gets or sets the seperator string to use for delmiting log message fields.
+ ///
+ /// The seperator.
+ public string Separator
+ {
+ get { return separator; }
+ set { separator = value; }
+ }
+
+ ///
+ /// Gets or sets the entry log level.
+ ///
+ /// The entry log level.
+ public LogLevel LogLevel
+ {
+ get { return logLevel; }
+ set { logLevel = value; }
+ }
+
+ #endregion
+
+ #region Protected Methods
+
+ ///
+ /// Subclasses must override this method to perform any tracing around the supplied
+ /// IMethodInvocation.
+ ///
+ /// The method invocation to log
+ /// The log to write messages to
+ ///
+ /// The result of the call to IMethodInvocation.Proceed()
+ ///
+ ///
+ /// Subclasses are resonsible for ensuring that the IMethodInvocation actually executes
+ /// by calling IMethodInvocation.Proceed().
+ ///
+ /// By default, the passed-in ILog instance will have log level
+ /// "trace" enabled. Subclasses do not have to check for this again, unless
+ /// they overwrite the IsInterceptorEnabled method to modify
+ /// the default behavior.
+ ///
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ protected override object InvokeUnderLog(IMethodInvocation invocation, ILog log)
+ {
+ object returnValue = null;
+ bool exitThroughException = false;
+
+ DateTime startTime = DateTime.Now;
+ string uniqueIdentifier = null;
+
+ if (LogUniqueIdentifier)
+ {
+ uniqueIdentifier = CreateUniqueIdentifier();
+ }
+ try
+ {
+ WriteToLog(LogLevel, log, GetEntryMessage(invocation, uniqueIdentifier), null);
+ returnValue = invocation.Proceed();
+ return returnValue;
+ } catch (Exception e)
+ {
+ TimeSpan executionTimeSpan = DateTime.Now - startTime;
+ WriteToLog(LogLevel, log, GetExceptionMessage(invocation, e, executionTimeSpan, uniqueIdentifier), e);
+ exitThroughException = true;
+ throw;
+ }
+ finally
+ {
+ if (!exitThroughException)
+ {
+ TimeSpan executionTimeSpan = DateTime.Now - startTime;
+ WriteToLog(LogLevel, log, GetExitMessage(invocation, returnValue, executionTimeSpan, uniqueIdentifier), null);
+ }
+ }
+ }
+
+ ///
+ /// Determines whether the given log is enabled.
+ ///
+ /// The log instance to check.
+ ///
+ /// true if log is for a given log level; otherwise, false.
+ ///
+ ///
+ /// Default is true when the trace level is enabled. Subclasses may override this
+ /// to change the level at which logging occurs, or return true to ignore level
+ /// checks.
+ protected override bool IsLogEnabled(ILog log)
+ {
+ switch (LogLevel)
+ {
+ case LogLevel.All:
+ case LogLevel.Trace:
+ if (log.IsTraceEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Debug:
+ if (log.IsDebugEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Error:
+ if (log.IsErrorEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Fatal:
+ if (log.IsFatalEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Info:
+ if (log.IsInfoEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Warn:
+ if (log.IsWarnEnabled)
+ {
+ return true;
+ }
+ break;
+ case LogLevel.Off:
+ default:
+ break;
+ }
+ return false;
+ }
+
+ ///
+ /// Creates a unique identifier.
+ ///
+ ///
+ /// Default implementation uses Guid.NewGuid(). Subclasses may override to provide an alternative
+ /// ID generation implementation.
+ ///
+ /// A unique identifier
+ protected virtual string CreateUniqueIdentifier()
+ {
+ return Guid.NewGuid().ToString();
+ }
+
+ ///
+ /// Gets the entry message to log
+ ///
+ /// The invocation.
+ /// The id string.
+ /// The entry log message
+ protected virtual string GetEntryMessage(IMethodInvocation invocation, string idString)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.Append("Entering ");
+ AppendCommonInformation(sb, invocation, idString);
+ if (logMethodArguments)
+ {
+ sb.Append(GetMethodArgumentAsString(invocation));
+ }
+
+ return RemoveLastSeparator(sb.ToString(), Separator);
+ }
+
+ ///
+ /// Gets the exception message.
+ ///
+ /// The method invocation.
+ /// The thown exception.
+ /// The execution time span.
+ /// The id string.
+ /// The exception log message.
+ protected virtual string GetExceptionMessage(IMethodInvocation invocation, Exception e, TimeSpan executionTimeSpan, string idString)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.Append("Exception thrown in ");
+ sb.Append(invocation.Method.Name).Append(Separator);
+ AppendCommonInformation(sb, invocation, idString);
+ if (LogExecutionTime)
+ {
+ sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms");
+ }
+
+ return RemoveLastSeparator(sb.ToString(), Separator);
+ }
+
+
+ ///
+ /// Gets the exit log message.
+ ///
+ /// The method invocation.
+ /// The return value.
+ /// The execution time span.
+ /// The id string.
+ /// the exit log message
+ protected virtual string GetExitMessage(IMethodInvocation invocation, object returnValue, TimeSpan executionTimeSpan, string idString)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.Append("Exiting ");
+ AppendCommonInformation(sb, invocation, idString);
+ if (LogReturnValue && invocation.Method.ReturnType != typeof(void))
+ {
+ sb.Append("return=").Append(returnValue).Append(Separator);
+ }
+ if (LogExecutionTime)
+ {
+ sb.Append(executionTimeSpan.TotalMilliseconds).Append(" ms");
+ }
+ return RemoveLastSeparator(sb.ToString(), Separator);
+ }
+
+
+ ///
+ /// Appends common information across entry,exit, exception logging
+ ///
+ /// Add method name and unique identifier if required.
+ /// The string buffer building logging message.
+ /// The method invocation.
+ /// The unique identifier string.
+ protected virtual void AppendCommonInformation(StringBuilder sb, IMethodInvocation invocation, string idString)
+ {
+ sb.Append(invocation.Method.Name);
+ if (LogUniqueIdentifier)
+ {
+ sb.Append(Separator).Append(idString);
+ }
+ sb.Append(Separator);
+ }
+
+ ///
+ /// Gets the method argument as argumen name/value pairs.
+ ///
+ /// The method invocation.
+ /// string for logging method argument name and values.
+ protected virtual string GetMethodArgumentAsString(IMethodInvocation invocation)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ ParameterInfo[] parameterInfos = invocation.Method.GetParameters();
+ object[] argValues = invocation.Arguments;
+ for (int i=0; i< parameterInfos.Length; i++)
+ {
+ sb.Append(parameterInfos[i].Name).Append("=").Append(argValues[i]);
+ if (i != parameterInfos.Length) sb.Append("; ");
+ }
+
+ return RemoveLastSeparator(sb.ToString(), "; ");
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private string RemoveLastSeparator(string str, string separator)
+ {
+ if (str.EndsWith(separator))
+ {
+ return str.Substring(0, str.Length - separator.Length);
+ }
+ else
+ {
+ return str;
+ }
+ }
+
+ private void WriteToLog(LogLevel logLevel, ILog log, string text, Exception e)
+ {
+ switch (logLevel)
+ {
+ case LogLevel.All:
+ case LogLevel.Trace:
+ if (log.IsTraceEnabled)
+ {
+ if (e == null) log.Trace(text); else log.Trace(text, e);
+ }
+ break;
+ case LogLevel.Debug:
+ if (log.IsDebugEnabled)
+ {
+ if (e == null) log.Debug(text); else log.Debug(text, e);
+ }
+ break;
+ case LogLevel.Error:
+ if (log.IsErrorEnabled)
+ {
+ if (e == null) log.Error(text); else log.Error(text, e);
+ }
+ break;
+ case LogLevel.Fatal:
+ if (log.IsFatalEnabled)
+ {
+ if (e == null) log.Fatal(text); else log.Fatal(text, e);
+ }
+ break;
+ case LogLevel.Info:
+ if (log.IsInfoEnabled)
+ {
+ if (e == null) log.Info(text); else log.Info(text, e);
+ }
+ break;
+ case LogLevel.Warn:
+ if (log.IsWarnEnabled)
+ {
+ if (e == null) log.Warn(text); else log.Warn(text, e);
+ }
+ break;
+ case LogLevel.Off:
+ default:
+ break;
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs b/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs
index 0c127b7b..45253ff7 100644
--- a/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs
+++ b/src/Spring/Spring.Aop/Aspects/ParsedAdviceExpression.cs
@@ -1,115 +1,114 @@
-#region License
-
-/*
- * Copyright 2002-2007 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
-
-namespace Spring.Aspects
-{
- ///
- /// This class contains the results of parsing an advice expresion of the form
- /// on exception name [ExceptionName1,ExceptionName2,...] [action] [action expression]
- /// or
- /// on exception [constraint expression] [action] [action expression]
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: ParsedAdviceExpression.cs,v 1.1 2007/10/08 22:05:16 markpollack Exp $
- public class ParsedAdviceExpression
- {
- private string adviceExpression;
-
- private string[] exceptionNames = new string[0];
- private string constraintExpression = null;
- private string actionExpressionText = null;
- private string actionText = null;
- private bool success;
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The advice expression.
- public ParsedAdviceExpression(string adviceExpression)
- {
- this.adviceExpression = adviceExpression;
- }
-
-
- ///
- /// Gets or sets the advice expression.
- ///
- /// The advice expression.
- public string AdviceExpression
- {
- get { return adviceExpression; }
- set { adviceExpression = value; }
- }
-
- ///
- /// Gets or sets the exception names.
- ///
- /// The exception names.
- public string[] ExceptionNames
- {
- get { return exceptionNames; }
- set { exceptionNames = value; }
- }
-
- ///
- /// Gets or sets the constraint expression.
- ///
- /// The constraint expression.
- public string ConstraintExpression
- {
- get { return constraintExpression; }
- set { constraintExpression = value; }
- }
-
- ///
- /// Gets or sets the action expression text.
- ///
- /// The action expression text.
- public string ActionExpressionText
- {
- get { return actionExpressionText; }
- set { actionExpressionText = value; }
- }
-
- ///
- /// Gets or sets the action text.
- ///
- /// The action text.
- public string ActionText
- {
- get { return actionText; }
- set { actionText = value; }
- }
-
- ///
- /// Gets or sets a value indicating whether this is success.
- ///
- /// true if success; otherwise, false.
- public bool Success
- {
- get { return success; }
- set { success = value; }
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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
+
+namespace Spring.Aspects
+{
+ ///
+ /// This class contains the results of parsing an advice expresion of the form
+ /// on exception name [ExceptionName1,ExceptionName2,...] [action] [action expression]
+ /// or
+ /// on exception [constraint expression] [action] [action expression]
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public class ParsedAdviceExpression
+ {
+ private string adviceExpression;
+
+ private string[] exceptionNames = new string[0];
+ private string constraintExpression = null;
+ private string actionExpressionText = null;
+ private string actionText = null;
+ private bool success;
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The advice expression.
+ public ParsedAdviceExpression(string adviceExpression)
+ {
+ this.adviceExpression = adviceExpression;
+ }
+
+
+ ///
+ /// Gets or sets the advice expression.
+ ///
+ /// The advice expression.
+ public string AdviceExpression
+ {
+ get { return adviceExpression; }
+ set { adviceExpression = value; }
+ }
+
+ ///
+ /// Gets or sets the exception names.
+ ///
+ /// The exception names.
+ public string[] ExceptionNames
+ {
+ get { return exceptionNames; }
+ set { exceptionNames = value; }
+ }
+
+ ///
+ /// Gets or sets the constraint expression.
+ ///
+ /// The constraint expression.
+ public string ConstraintExpression
+ {
+ get { return constraintExpression; }
+ set { constraintExpression = value; }
+ }
+
+ ///
+ /// Gets or sets the action expression text.
+ ///
+ /// The action expression text.
+ public string ActionExpressionText
+ {
+ get { return actionExpressionText; }
+ set { actionExpressionText = value; }
+ }
+
+ ///
+ /// Gets or sets the action text.
+ ///
+ /// The action text.
+ public string ActionText
+ {
+ get { return actionText; }
+ set { actionText = value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether this is success.
+ ///
+ /// true if success; otherwise, false.
+ public bool Success
+ {
+ get { return success; }
+ set { success = value; }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
index 514e43af..b2ab7fd8 100644
--- a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
@@ -1,316 +1,315 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Text.RegularExpressions;
-using System.Threading;
-using AopAlliance.Intercept;
-using Common.Logging;
-using Spring.Core.TypeConversion;
-using Spring.Expressions;
-
-namespace Spring.Aspects
-{
- ///
- /// AOP Advice to retry a method invocation on an exception. The retry semantics are defined by a DSL of the
- /// form on exception name [ExceptionName1,ExceptionName2,...] retry [number of times] [delay|rate] [delay time|rate expression].
- /// For example, on exception name ArithmeticException retry 3x delay 1s
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: RetryAdvice.cs,v 1.5 2008/03/17 20:25:34 markpollack Exp $
- public class RetryAdvice : AbstractExceptionHandlerAdvice
- {
- #region Fields
-
- private static readonly ILog log = LogManager.GetLogger(typeof (RetryAdvice));
-
- private TimeSpanConverter timeSpanConverter = new TimeSpanConverter();
-
- private RetryExceptionHandler retryExceptionHandler;
-
- private string retryExpression;
-
- private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(retry)\s*(.*?)$";
-
- private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(retry)\s*(.*?)$";
-
- //retry 3x delay 10s
- private string delayRegex = @"^(\d+)x\s+(delay)\s+(\d+\w+)?$";
-
- //retry 3x rate 10n+5
- private string rateRegex = @"^(\d+)x\s+(rate)\s+(\(.*?\))?$";
- #endregion
-
- #region Properties
-
- ///
- /// Gets or sets the retry expression.
- ///
- /// The retry expression.
- public string RetryExpression
- {
- get { return retryExpression; }
- set { retryExpression = value; }
- }
-
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions.
- public override string OnExceptionNameRegex
- {
- get { return onExceptionNameRegex; }
- set { onExceptionNameRegex = value; }
- }
-
- ///
- /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
- ///
- /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
- public override string OnExceptionRegex
- {
- get { return onExceptionRegex; }
- set { onExceptionRegex = value; }
- }
-
- #endregion
-
- #region IMethodInterceptor implementation
-
- ///
- /// Implement this method to perform extra treatments before and after
- /// the call to the supplied .
- ///
- /// The method invocation that is being intercepted.
- ///
- /// The result of the call to the
- /// method of
- /// the supplied ; this return value may
- /// well have been intercepted by the interceptor.
- ///
- ///
- ///
- /// Polite implementations would certainly like to invoke
- /// .
- ///
- ///
- ///
- /// If any of the interceptors in the chain or the target object itself
- /// throws an exception.
- ///
- public override object Invoke(IMethodInvocation invocation)
- {
- IDictionary callContextDictionary = new Hashtable();
- callContextDictionary.Add("method", invocation.Method);
- callContextDictionary.Add("args", invocation.Arguments);
- callContextDictionary.Add("target", invocation.Target);
- int numAttempts = 0;
-
- object returnVal = null;
- do
- {
- try
- {
- returnVal = invocation.Proceed();
- break;
- }
- catch (Exception ex)
- {
- callContextDictionary["e"] = ex;
- if (retryExceptionHandler.CanHandleException(ex, callContextDictionary))
- {
- numAttempts++;
- if (numAttempts == retryExceptionHandler.MaximumRetryCount)
- {
- throw;
- }
- else
- {
- if (log.IsTraceEnabled)
- {
- log.Trace("Retrying " + invocation.Method.Name);
- }
- callContextDictionary["n"] = numAttempts;
- Sleep(retryExceptionHandler, callContextDictionary);
- }
- }
- else
- {
- throw;
- }
- }
- } while (numAttempts <= retryExceptionHandler.MaximumRetryCount);
-
-
- log.Debug("Invoked successfully after " + numAttempts + " attempt(s)");
- return returnVal;
- }
-
- private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary)
- {
- if (handler.IsDelayBased)
- {
- Thread.Sleep(handler.DelayTimeSpan);
- }
- else
- {
- try
- {
- IExpression expression = Expression.Parse(handler.DelayRateExpression);
- object result = expression.GetValue(null, callContextDictionary);
- decimal d = decimal.Parse(result.ToString());
- decimal rounded = decimal.Round(d*1000,0);
- int sleepInSeconds = decimal.ToInt32(rounded);
- Thread.Sleep(sleepInSeconds);
- }
- catch (InvalidCastException e)
- {
- log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
- Thread.Sleep(1000);
- }
- catch (Exception e)
- {
- log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
- Thread.Sleep(1000);
- }
- }
- }
-
- #endregion
-
- #region IInitializingObject implementation
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
- ///
- ///
- /// In the event of misconfiguration (such as the failure to set a
- /// required property) or if initialization fails.
- ///
- public override void AfterPropertiesSet()
- {
- if (retryExpression == null)
- {
- throw new ArgumentException("Must specify retry expression.");
- }
- RetryExceptionHandler handler = Parse(retryExpression);
- if (handler == null)
- {
- throw new ArgumentException("Was not able to parse retry expression string [" + retryExpression + "]");
- }
- retryExceptionHandler = handler;
- }
-
- #endregion
-
- ///
- /// Parses the specified handler string.
- ///
- /// The handler string.
- ///
- protected virtual RetryExceptionHandler Parse(string retryExpressionString)
- {
-
- ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(retryExpressionString);
-
- if (!parsedAdviceExpression.Success)
- {
- log.Warn("Could not parse retry expression " + retryExpressionString);
- return null;
- }
-
- RetryExceptionHandler handler = new RetryExceptionHandler(parsedAdviceExpression.ExceptionNames);
- handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
- handler.ActionExpressionText = parsedAdviceExpression.AdviceExpression;
-
- Match match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, delayRegex);
-
- if (match.Success)
- {
- handler.MaximumRetryCount = int.Parse(match.Groups[1].Value.Trim());
- handler.IsDelayBased = true;
-
- try
- {
- string ts = match.Groups[3].Value.Trim();
- handler.DelayTimeSpan = (TimeSpan) timeSpanConverter.ConvertFrom(null, null, ts);
- } catch (Exception)
- {
- log.Warn("Could not parse timespan " + match.Groups[3].Value.Trim());
- return null;
- }
- return handler;
- }
- else
- {
- match = GetMatchForActionExpression(parsedAdviceExpression.ActionExpressionText, rateRegex);
- if (match.Success)
- {
- handler.MaximumRetryCount = int.Parse(match.Groups[1].Value.Trim());
- handler.IsDelayBased = false;
- handler.DelayRateExpression = match.Groups[3].Value.Trim();
- return handler;
- }
- else
- {
- return null;
- }
- }
-
- }
-
- ///
- /// Gets the match for action expression.
- ///
- /// The action expression string.
- /// The regex string.
- /// The Match object resulting from the regular expression match.
- protected virtual Match GetMatchForActionExpression(string actionExpressionString, string regexString)
- {
- RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
- Regex reg = new Regex(regexString, options);
- return reg.Match(actionExpressionString);
- }
-
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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.Text.RegularExpressions;
+using System.Threading;
+using AopAlliance.Intercept;
+using Common.Logging;
+using Spring.Core.TypeConversion;
+using Spring.Expressions;
+
+namespace Spring.Aspects
+{
+ ///
+ /// AOP Advice to retry a method invocation on an exception. The retry semantics are defined by a DSL of the
+ /// form on exception name [ExceptionName1,ExceptionName2,...] retry [number of times] [delay|rate] [delay time|rate expression].
+ /// For example, on exception name ArithmeticException retry 3x delay 1s
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public class RetryAdvice : AbstractExceptionHandlerAdvice
+ {
+ #region Fields
+
+ private static readonly ILog log = LogManager.GetLogger(typeof (RetryAdvice));
+
+ private TimeSpanConverter timeSpanConverter = new TimeSpanConverter();
+
+ private RetryExceptionHandler retryExceptionHandler;
+
+ private string retryExpression;
+
+ private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(retry)\s*(.*?)$";
+
+ private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(retry)\s*(.*?)$";
+
+ //retry 3x delay 10s
+ private string delayRegex = @"^(\d+)x\s+(delay)\s+(\d+\w+)?$";
+
+ //retry 3x rate 10n+5
+ private string rateRegex = @"^(\d+)x\s+(rate)\s+(\(.*?\))?$";
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the retry expression.
+ ///
+ /// The retry expression.
+ public string RetryExpression
+ {
+ get { return retryExpression; }
+ set { retryExpression = value; }
+ }
+
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions.
+ public override string OnExceptionNameRegex
+ {
+ get { return onExceptionNameRegex; }
+ set { onExceptionNameRegex = value; }
+ }
+
+ ///
+ /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
+ ///
+ /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions.
+ public override string OnExceptionRegex
+ {
+ get { return onExceptionRegex; }
+ set { onExceptionRegex = value; }
+ }
+
+ #endregion
+
+ #region IMethodInterceptor implementation
+
+ ///
+ /// Implement this method to perform extra treatments before and after
+ /// the call to the supplied .
+ ///
+ /// The method invocation that is being intercepted.
+ ///
+ /// The result of the call to the
+ /// method of
+ /// the supplied ; this return value may
+ /// well have been intercepted by the interceptor.
+ ///
+ ///
+ ///
+ /// Polite implementations would certainly like to invoke
+ /// .
+ ///
+ ///
+ ///
+ /// If any of the interceptors in the chain or the target object itself
+ /// throws an exception.
+ ///
+ public override object Invoke(IMethodInvocation invocation)
+ {
+ IDictionary callContextDictionary = new Hashtable();
+ callContextDictionary.Add("method", invocation.Method);
+ callContextDictionary.Add("args", invocation.Arguments);
+ callContextDictionary.Add("target", invocation.Target);
+ int numAttempts = 0;
+
+ object returnVal = null;
+ do
+ {
+ try
+ {
+ returnVal = invocation.Proceed();
+ break;
+ }
+ catch (Exception ex)
+ {
+ callContextDictionary["e"] = ex;
+ if (retryExceptionHandler.CanHandleException(ex, callContextDictionary))
+ {
+ numAttempts++;
+ if (numAttempts == retryExceptionHandler.MaximumRetryCount)
+ {
+ throw;
+ }
+ else
+ {
+ if (log.IsTraceEnabled)
+ {
+ log.Trace("Retrying " + invocation.Method.Name);
+ }
+ callContextDictionary["n"] = numAttempts;
+ Sleep(retryExceptionHandler, callContextDictionary);
+ }
+ }
+ else
+ {
+ throw;
+ }
+ }
+ } while (numAttempts <= retryExceptionHandler.MaximumRetryCount);
+
+
+ log.Debug("Invoked successfully after " + numAttempts + " attempt(s)");
+ return returnVal;
+ }
+
+ private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary)
+ {
+ if (handler.IsDelayBased)
+ {
+ Thread.Sleep(handler.DelayTimeSpan);
+ }
+ else
+ {
+ try
+ {
+ IExpression expression = Expression.Parse(handler.DelayRateExpression);
+ object result = expression.GetValue(null, callContextDictionary);
+ decimal d = decimal.Parse(result.ToString());
+ decimal rounded = decimal.Round(d*1000,0);
+ int sleepInSeconds = decimal.ToInt32(rounded);
+ Thread.Sleep(sleepInSeconds);
+ }
+ catch (InvalidCastException e)
+ {
+ log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
+ Thread.Sleep(1000);
+ }
+ catch (Exception e)
+ {
+ log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
+ Thread.Sleep(1000);
+ }
+ }
+ }
+
+ #endregion
+
+ #region IInitializingObject implementation
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
- /// This attribute allows application developers to specify that an argument
- /// of the method should be cached, but it will not do any caching by itself.
- ///
- ///
- /// In order to actually cache the result, an application developer
- /// must apply a Spring.Aspects.Cache.CacheParameterAdvice to
- /// all of the members that have this attribute defined.
- ///
- ///
- /// You can specify this attribute multiple times on the same method in order to
- /// cache several method parameters.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: CacheParameterAttribute.cs,v 1.2 2007/03/31 01:07:26 bbaia Exp $
- [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
- [Serializable]
- public sealed class CacheParameterAttribute : BaseCacheAttribute
- {
- ///
- /// Creates an attribute instance.
- ///
- public CacheParameterAttribute()
- {
- }
-
- ///
- /// Creates an attribute instance.
- ///
- ///
- /// The name of the cache to use.
- ///
- ///
- /// An expression string that should be evaluated in order to determine
- /// the cache key for the item.
- ///
- public CacheParameterAttribute(string cacheName, string key)
- : base(cacheName, key)
- {
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+
+namespace Spring.Caching
+{
+ ///
+ /// This attribute should be used to mark methods whose argument(s)
+ /// need to be cached.
+ ///
+ ///
+ ///
+ /// This attribute allows application developers to specify that an argument
+ /// of the method should be cached, but it will not do any caching by itself.
+ ///
+ ///
+ /// In order to actually cache the result, an application developer
+ /// must apply a Spring.Aspects.Cache.CacheParameterAdvice to
+ /// all of the members that have this attribute defined.
+ ///
+ ///
+ /// You can specify this attribute multiple times on the same method in order to
+ /// cache several method parameters.
+ ///
+ ///
+ /// Aleksandar Seovic
+ [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
+ [Serializable]
+ public sealed class CacheParameterAttribute : BaseCacheAttribute
+ {
+ ///
+ /// Creates an attribute instance.
+ ///
+ public CacheParameterAttribute()
+ {
+ }
+
+ ///
+ /// Creates an attribute instance.
+ ///
+ ///
+ /// The name of the cache to use.
+ ///
+ ///
+ /// An expression string that should be evaluated in order to determine
+ /// the cache key for the item.
+ ///
+ public CacheParameterAttribute(string cacheName, string key)
+ : base(cacheName, key)
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs b/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs
index bee2ef45..b575fd79 100644
--- a/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs
+++ b/src/Spring/Spring.Core/Caching/CacheResultAttribute.cs
@@ -1,69 +1,68 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-
-namespace Spring.Caching
-{
- ///
- /// This attribute should be used to mark methods whose result
- /// needs to be cached.
- ///
- ///
- ///
- /// This attribute allows application developers to mark that a result
- /// of the method invocation should be cached, but it will not do any
- /// caching by itself.
- ///
- ///
- /// In order to actually cache the result, an application developer
- /// must apply a Spring.Aspects.Cache.CacheResultAdvice to
- /// all of the members that have this attribute defined.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: CacheResultAttribute.cs,v 1.1 2007/02/09 07:12:23 aseovic Exp $
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
- [Serializable]
- public sealed class CacheResultAttribute : BaseCacheAttribute
- {
- ///
- /// Creates an attribute instance.
- ///
- public CacheResultAttribute()
- {
- }
-
- ///
- /// Creates an attribute instance.
- ///
- ///
- /// The name of the cache to use.
- ///
- ///
- /// An expression string that should be evaluated in order to determine
- /// the cache key for the item.
- ///
- public CacheResultAttribute(string cacheName, string key)
- : base(cacheName, key)
- {
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+
+namespace Spring.Caching
+{
+ ///
+ /// This attribute should be used to mark methods whose result
+ /// needs to be cached.
+ ///
+ ///
+ ///
+ /// This attribute allows application developers to mark that a result
+ /// of the method invocation should be cached, but it will not do any
+ /// caching by itself.
+ ///
+ ///
+ /// In order to actually cache the result, an application developer
+ /// must apply a Spring.Aspects.Cache.CacheResultAdvice to
+ /// all of the members that have this attribute defined.
+ ///
+ ///
+ /// Aleksandar Seovic
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+ [Serializable]
+ public sealed class CacheResultAttribute : BaseCacheAttribute
+ {
+ ///
+ /// Creates an attribute instance.
+ ///
+ public CacheResultAttribute()
+ {
+ }
+
+ ///
+ /// Creates an attribute instance.
+ ///
+ ///
+ /// The name of the cache to use.
+ ///
+ ///
+ /// An expression string that should be evaluated in order to determine
+ /// the cache key for the item.
+ ///
+ public CacheResultAttribute(string cacheName, string key)
+ : base(cacheName, key)
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs b/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs
index 91824086..7c46add3 100644
--- a/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs
+++ b/src/Spring/Spring.Core/Caching/CacheResultItemsAttribute.cs
@@ -1,70 +1,69 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-
-namespace Spring.Caching
-{
- ///
- /// This attribute should be used with methods that return an
- /// in order to cache each item separately.
- ///
- ///
- ///
- /// This attribute allows application developers to specify that each item
- /// from the collection returned by the method should be cached,
- /// but it will not do any caching by itself.
- ///
- ///
- /// In order to actually cache the result, an application developer
- /// must apply a Spring.Aspects.Cache.CacheResultAdvice to
- /// all of the members that have this attribute defined.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: CacheResultItemsAttribute.cs,v 1.2 2007/03/31 02:59:48 bbaia Exp $
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
- [Serializable]
- public sealed class CacheResultItemsAttribute : BaseCacheAttribute
- {
- ///
- /// Creates an attribute instance.
- ///
- public CacheResultItemsAttribute()
- {
- }
-
- ///
- /// Creates an attribute instance.
- ///
- ///
- /// The name of the cache to use.
- ///
- ///
- /// An expression string that should be evaluated in order to determine
- /// the cache key for the item.
- ///
- public CacheResultItemsAttribute(string cacheName, string key)
- : base(cacheName, key)
- {
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+
+namespace Spring.Caching
+{
+ ///
+ /// This attribute should be used with methods that return an
+ /// in order to cache each item separately.
+ ///
+ ///
+ ///
+ /// This attribute allows application developers to specify that each item
+ /// from the collection returned by the method should be cached,
+ /// but it will not do any caching by itself.
+ ///
+ ///
+ /// In order to actually cache the result, an application developer
+ /// must apply a Spring.Aspects.Cache.CacheResultAdvice to
+ /// all of the members that have this attribute defined.
+ ///
+ ///
+ /// Aleksandar Seovic
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
+ [Serializable]
+ public sealed class CacheResultItemsAttribute : BaseCacheAttribute
+ {
+ ///
+ /// Creates an attribute instance.
+ ///
+ public CacheResultItemsAttribute()
+ {
+ }
+
+ ///
+ /// Creates an attribute instance.
+ ///
+ ///
+ /// The name of the cache to use.
+ ///
+ ///
+ /// An expression string that should be evaluated in order to determine
+ /// the cache key for the item.
+ ///
+ public CacheResultItemsAttribute(string cacheName, string key)
+ : base(cacheName, key)
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Caching/ICache.cs b/src/Spring/Spring.Core/Caching/ICache.cs
index 86511f4b..ee18ce62 100644
--- a/src/Spring/Spring.Core/Caching/ICache.cs
+++ b/src/Spring/Spring.Core/Caching/ICache.cs
@@ -1,108 +1,107 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-
-namespace Spring.Caching
-{
- ///
- /// Defines a contract that all cache implementations have to fulfill.
- ///
- /// Aleksandar Seovic
- /// Erich Eichinger
- /// $Id: ICache.cs,v 1.5 2007/08/27 09:38:11 oakinger Exp $
- public interface ICache
- {
- ///
- /// Gets the number of items in the cache.
- ///
- int Count { get; }
-
- ///
- /// Gets a collection of all cache item keys.
- ///
- ICollection Keys { get; }
-
- ///
- /// Retrieves an item from the cache.
- ///
- ///
- /// Item key.
- ///
- ///
- /// Item for the specified , or null.
- ///
- object Get(object key);
-
- ///
- /// Removes an item from the cache.
- ///
- ///
- /// Item key.
- ///
- void Remove(object key);
-
- ///
- /// Removes collection of items from the cache.
- ///
- ///
- /// Collection of keys to remove.
- ///
- void RemoveAll(ICollection keys);
-
- ///
- /// Removes all items from the cache.
- ///
- void Clear();
-
- ///
- /// Inserts an item into the cache.
- ///
- ///
- /// Items inserted using this method have no expiration time
- /// and default cache priority.
- ///
- ///
- /// Item key.
- ///
- ///
- /// Item value.
- ///
- void Insert(object key, object value);
-
- ///
- /// Inserts an item into the cache.
- ///
- ///
- /// Items inserted using this method have default cache priority.
- ///
- ///
- /// Item key.
- ///
- ///
- /// Item value.
- ///
- ///
- /// Item's time-to-live.
- ///
- void Insert(object key, object value, TimeSpan timeToLive);
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+
+namespace Spring.Caching
+{
+ ///
+ /// Defines a contract that all cache implementations have to fulfill.
+ ///
+ /// Aleksandar Seovic
+ /// Erich Eichinger
+ public interface ICache
+ {
+ ///
+ /// Gets the number of items in the cache.
+ ///
+ int Count { get; }
+
+ ///
+ /// Gets a collection of all cache item keys.
+ ///
+ ICollection Keys { get; }
+
+ ///
+ /// Retrieves an item from the cache.
+ ///
+ ///
+ /// Item key.
+ ///
+ ///
+ /// Item for the specified , or null.
+ ///
+ object Get(object key);
+
+ ///
+ /// Removes an item from the cache.
+ ///
+ ///
+ /// Item key.
+ ///
+ void Remove(object key);
+
+ ///
+ /// Removes collection of items from the cache.
+ ///
+ ///
+ /// Collection of keys to remove.
+ ///
+ void RemoveAll(ICollection keys);
+
+ ///
+ /// Removes all items from the cache.
+ ///
+ void Clear();
+
+ ///
+ /// Inserts an item into the cache.
+ ///
+ ///
+ /// Items inserted using this method have no expiration time
+ /// and default cache priority.
+ ///
+ ///
+ /// Item key.
+ ///
+ ///
+ /// Item value.
+ ///
+ void Insert(object key, object value);
+
+ ///
+ /// Inserts an item into the cache.
+ ///
+ ///
+ /// Items inserted using this method have default cache priority.
+ ///
+ ///
+ /// Item key.
+ ///
+ ///
+ /// Item value.
+ ///
+ ///
+ /// Item's time-to-live.
+ ///
+ void Insert(object key, object value, TimeSpan timeToLive);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs b/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs
index b16283d2..4a1bb535 100644
--- a/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs
+++ b/src/Spring/Spring.Core/Caching/InvalidateCacheAttribute.cs
@@ -1,146 +1,145 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using Spring.Expressions;
-
-namespace Spring.Caching
-{
- ///
- /// This attribute should be used to mark method that should
- /// invalidate one or more cache items when invoked.
- ///
- ///
- ///
- /// This attribute allows application developers to specify that some
- /// cache items should be evicted from cache when the method is invoked,
- /// but it will not do any eviction by itself.
- ///
- ///
- /// In order to actually evict cache items, an application developer
- /// must apply a Spring.Aspects.Cache.InvalidateCacheAdvice to
- /// all of the members that have this attribute defined.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: InvalidateCacheAttribute.cs,v 1.2 2007/04/01 15:04:39 bbaia Exp $
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
- [Serializable]
- public sealed class InvalidateCacheAttribute : Attribute
- {
- private string cacheName;
- private string keys;
- private IExpression keysExpression;
- private string condition;
- private IExpression conditionExpression;
-
- ///
- /// Creates an attribute instance.
- ///
- public InvalidateCacheAttribute()
- {
- }
-
- ///
- /// Creates an attribute instance.
- ///
- ///
- /// The name of the cache to use.
- ///
- public InvalidateCacheAttribute(string cacheName)
- {
- this.cacheName = cacheName;
- }
-
- ///
- /// Gets or sets the name of the cache to use.
- ///
- ///
- /// The name of the cache to use.
- ///
- public string CacheName
- {
- get { return cacheName; }
- set { cacheName = value; }
- }
-
- ///
- /// Gets or sets a SpEL expression that should be evaluated in order
- /// to determine the keys for the items that should be evicted.
- ///
- ///
- /// An expression string that should be evaluated in order
- /// to determine the keys for the items that should be evicted.
- ///
- public string Keys
- {
- get { return keys; }
- set
- {
- keys = value;
- keysExpression = Expression.Parse(value);
- }
- }
-
- ///
- /// Gets an expression instance that should be evaluated in order
- /// to determine the keys for the items that should be evicted.
- ///
- ///
- /// An expression instance that should be evaluated in order
- /// to determine the keys for the items that should be evicted.
- ///
- public IExpression KeysExpression
- {
- get { return keysExpression; }
- }
-
- ///
- /// Gets or sets a SpEL expression that should be evaluated in order
- /// to determine whether items should be evicted.
- ///
- ///
- /// An expression string that should be evaluated in order to determine
- /// whether items should be evicted.
- ///
- public string Condition
- {
- get { return condition; }
- set
- {
- condition = value;
- conditionExpression = Expression.Parse(value);
- }
- }
-
- ///
- /// Gets an expression instance that should be evaluated in order
- /// to determine whether items should be evicted.
- ///
- ///
- /// An expression instance that should be evaluated in order to determine
- /// whether items should be evicted.
- ///
- public IExpression ConditionExpression
- {
- get { return conditionExpression; }
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using Spring.Expressions;
+
+namespace Spring.Caching
+{
+ ///
+ /// This attribute should be used to mark method that should
+ /// invalidate one or more cache items when invoked.
+ ///
+ ///
+ ///
+ /// This attribute allows application developers to specify that some
+ /// cache items should be evicted from cache when the method is invoked,
+ /// but it will not do any eviction by itself.
+ ///
+ ///
+ /// In order to actually evict cache items, an application developer
+ /// must apply a Spring.Aspects.Cache.InvalidateCacheAdvice to
+ /// all of the members that have this attribute defined.
+ ///
- /// The implementations in this class are appropriate when the base
- /// implementation does not allow elements. The methods
- /// ,
- /// , and
- /// are based on
- /// the ,
- /// , and
- /// methods
- /// respectively but throw exceptions instead of indicating failure via
- /// or returns.
- ///
- /// An implementation that extends this class must
- /// minimally define a method
- /// which does
- /// not permit the insertion of elements, along with methods
- /// , and
- /// . Typically,
- /// additional methods will be overridden as well. If these requirements
- /// cannot be met, consider instead subclassing
- /// }.
- ///
- ///
- /// Doug Lea
- /// Griffin Caprio (.NET)
- /// $Id: AbstractQueue.cs,v 1.8 2007/08/27 09:38:11 oakinger Exp $
- [Serializable]
- public abstract class AbstractQueue : IQueue
- {
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// This is an abstract class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- protected AbstractQueue()
- {}
-
- ///
- /// Inserts the specified element into this queue if it is possible
- /// to do so immediately without violating capacity restrictions.
- ///
- ///
- /// The element to add.
- ///
- ///
- /// if successful.
- ///
- ///
- /// If the element cannot be added at this time due to capacity restrictions.
- ///
- public virtual bool Add(object objectToAdd)
- {
- if(Offer(objectToAdd))
- {
- return true;
- }
- else
- {
- throw new InvalidOperationException("Queue full.");
- }
- }
-
- ///
- /// Retrieves and removes the head of this queue.
- ///
- ///
- ///
- /// This method differs from
- /// only in that
- /// it throws an exception if this queue is empty.
- ///
- ///
- ///
- /// The head of this queue
- ///
- ///
- /// If this queue is empty.
- ///
- public virtual object Remove()
- {
- object element = Poll();
- if(element != null)
- {
- return element;
- }
- else
- {
- throw new NoElementsException("Queue is empty.");
- }
- }
-
-
- ///
- /// Retrieves, but does not remove, the head of this queue.
- ///
- ///
- ///
- /// This method differs from
- /// only in that it throws an exception if this queue is empty.
- ///
- ///
- /// ALso note that this implementation returns the result of
- /// unless the queue
- /// is empty.
- ///
- ///
- /// The head of this queue.
- ///
- /// If this queue is empty.
- ///
- public virtual object Element()
- {
- object element = Peek();
- if(element != null)
- {
- return element;
- }
- else
- {
- throw new NoElementsException("Queue is empty.");
- }
- }
-
- ///
- /// Removes all of the elements from this queue.
- ///
- ///
- ///
- /// The queue will be empty after this call returns.
- ///
- ///
- /// This implementation repeatedly invokes
- /// until it
- /// returns .
- ///
- ///
- public virtual void Clear()
- {
- while(Poll() != null)
- {
- ;
- }
- }
-
- ///
- /// Adds all of the elements in the supplied
- /// to this queue.
- ///
- ///
- ///
- /// Attempts to
- ///
- /// of a queue to itself result in .
- /// Further, the behavior of this operation is undefined if the specified
- /// collection is modified while the operation is in progress.
- ///
- ///
- /// This implementation iterates over the specified collection,
- /// and adds each element returned by the iterator to this queue, in turn.
- /// An exception encountered while trying to add an element (including,
- /// in particular, a element) may result in only some
- /// of the elements having been successfully added when the associated
- /// exception is thrown.
- ///
- ///
- ///
- /// The collection containing the elements to be added to this queue.
- ///
- ///
- /// if this queue changed as a result of the call.
- ///
- ///
- /// If the supplied or any one of its elements are .
- ///
- ///
- /// If the collection is the current or
- /// the collection size is greater than the queue capacity.
- ///
- public virtual bool AddAll(ICollection collection)
- {
- if(collection == null)
- {
- throw new ArgumentNullException("Collection cannot be null.");
- }
- if(collection == this)
- {
- throw new ArgumentException();
- }
- if(collection.Count > Capacity)
- {
- throw new ArgumentException("Collcation size greater than queue capacity.");
- }
- bool modified = false;
- foreach(object element in collection)
- {
- if(element == null)
- {
- throw new ArgumentNullException("Cannot add null elements to this queue.");
- }
- else if(Add(element))
- {
- modified = true;
- }
- }
- return modified;
- }
-
- ///
- /// Inserts the specified element into this queue if it is possible to do
- /// so immediately without violating capacity restrictions.
- ///
- ///
- ///
- /// When using a capacity-restricted queue, this method is generally
- /// preferable to ,
- /// which can fail to insert an element only by throwing an exception.
- ///
+ /// The implementations in this class are appropriate when the base
+ /// implementation does not allow elements. The methods
+ /// ,
+ /// , and
+ /// are based on
+ /// the ,
+ /// , and
+ /// methods
+ /// respectively but throw exceptions instead of indicating failure via
+ /// or returns.
+ ///
+ /// An implementation that extends this class must
+ /// minimally define a method
+ /// which does
+ /// not permit the insertion of elements, along with methods
+ /// , and
+ /// . Typically,
+ /// additional methods will be overridden as well. If these requirements
+ /// cannot be met, consider instead subclassing
+ /// }.
+ ///
+ ///
+ /// Doug Lea
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public abstract class AbstractQueue : IQueue
+ {
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// This is an abstract class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ protected AbstractQueue()
+ {}
+
+ ///
+ /// Inserts the specified element into this queue if it is possible
+ /// to do so immediately without violating capacity restrictions.
+ ///
+ ///
+ /// The element to add.
+ ///
+ ///
+ /// if successful.
+ ///
+ ///
+ /// If the element cannot be added at this time due to capacity restrictions.
+ ///
+ public virtual bool Add(object objectToAdd)
+ {
+ if(Offer(objectToAdd))
+ {
+ return true;
+ }
+ else
+ {
+ throw new InvalidOperationException("Queue full.");
+ }
+ }
+
+ ///
+ /// Retrieves and removes the head of this queue.
+ ///
+ ///
+ ///
+ /// This method differs from
+ /// only in that
+ /// it throws an exception if this queue is empty.
+ ///
+ ///
+ ///
+ /// The head of this queue
+ ///
+ ///
+ /// If this queue is empty.
+ ///
+ public virtual object Remove()
+ {
+ object element = Poll();
+ if(element != null)
+ {
+ return element;
+ }
+ else
+ {
+ throw new NoElementsException("Queue is empty.");
+ }
+ }
+
+
+ ///
+ /// Retrieves, but does not remove, the head of this queue.
+ ///
+ ///
+ ///
+ /// This method differs from
+ /// only in that it throws an exception if this queue is empty.
+ ///
+ ///
+ /// ALso note that this implementation returns the result of
+ /// unless the queue
+ /// is empty.
+ ///
+ ///
+ /// The head of this queue.
+ ///
+ /// If this queue is empty.
+ ///
+ public virtual object Element()
+ {
+ object element = Peek();
+ if(element != null)
+ {
+ return element;
+ }
+ else
+ {
+ throw new NoElementsException("Queue is empty.");
+ }
+ }
+
+ ///
+ /// Removes all of the elements from this queue.
+ ///
+ ///
+ ///
+ /// The queue will be empty after this call returns.
+ ///
+ ///
+ /// This implementation repeatedly invokes
+ /// until it
+ /// returns .
+ ///
+ ///
+ public virtual void Clear()
+ {
+ while(Poll() != null)
+ {
+ ;
+ }
+ }
+
+ ///
+ /// Adds all of the elements in the supplied
+ /// to this queue.
+ ///
+ ///
+ ///
+ /// Attempts to
+ ///
+ /// of a queue to itself result in .
+ /// Further, the behavior of this operation is undefined if the specified
+ /// collection is modified while the operation is in progress.
+ ///
+ ///
+ /// This implementation iterates over the specified collection,
+ /// and adds each element returned by the iterator to this queue, in turn.
+ /// An exception encountered while trying to add an element (including,
+ /// in particular, a element) may result in only some
+ /// of the elements having been successfully added when the associated
+ /// exception is thrown.
+ ///
+ ///
+ ///
+ /// The collection containing the elements to be added to this queue.
+ ///
+ ///
+ /// if this queue changed as a result of the call.
+ ///
+ ///
+ /// If the supplied or any one of its elements are .
+ ///
+ ///
+ /// If the collection is the current or
+ /// the collection size is greater than the queue capacity.
+ ///
+ public virtual bool AddAll(ICollection collection)
+ {
+ if(collection == null)
+ {
+ throw new ArgumentNullException("Collection cannot be null.");
+ }
+ if(collection == this)
+ {
+ throw new ArgumentException();
+ }
+ if(collection.Count > Capacity)
+ {
+ throw new ArgumentException("Collcation size greater than queue capacity.");
+ }
+ bool modified = false;
+ foreach(object element in collection)
+ {
+ if(element == null)
+ {
+ throw new ArgumentNullException("Cannot add null elements to this queue.");
+ }
+ else if(Add(element))
+ {
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ ///
+ /// Inserts the specified element into this queue if it is possible to do
+ /// so immediately without violating capacity restrictions.
+ ///
+ ///
+ ///
+ /// When using a capacity-restricted queue, this method is generally
+ /// preferable to ,
+ /// which can fail to insert an element only by throwing an exception.
+ ///
- /// You can use any object that implements the
- /// interface to hold set
- /// data. You can define your own, or you can use one of the objects
- /// provided in the framework. The type of
- /// you
- /// choose will affect both the performance and the behavior of the
- /// using it.
- ///
- ///
- /// This object overrides the method,
- /// but not the method, because
- /// the class is mutable.
- /// Therefore, it is not safe to use as a key value in a dictionary.
- ///
- ///
- /// To make a typed based on your
- /// own , simply derive a new
- /// class with a constructor that takes no parameters. Some
- /// implmentations cannot be defined
- /// with a default constructor. If this is the case for your class, you
- /// will need to override clone as well.
- ///
- ///
- /// It is also standard practice that at least one of your constructors
- /// takes an or an
- /// as an argument.
- ///
- ///
- ///
- /// $Id: DictionarySet.cs,v 1.7 2007/03/16 04:01:27 aseovic Exp $
- [Serializable]
- public abstract class DictionarySet : Set
- {
- private IDictionary _internalDictionary;
-
- private static readonly object PlaceholderObject = new object();
- private static readonly object NullPlaceHolderKey = new object();
-
- ///
- /// Provides the storage for elements in the
- /// , stored as the key-set
- /// of the object.
- ///
- ///
- ///
- /// Set this object in the constructor if you create your own
- /// class.
- ///
- ///
- protected IDictionary InternalDictionary
- {
- get { return _internalDictionary; }
- set { _internalDictionary = value; }
- }
-
- ///
- /// The placeholder object used as the value for the
- /// instance.
- ///
- ///
- /// There is a single instance of this object globally, used for all
- /// s.
- ///
- protected static object Placeholder
- {
- get { return PlaceholderObject; }
- }
-
- ///
- /// Adds the specified element to this set if it is not already present.
- ///
- /// The object to add to the set.
- ///
- /// is the object was added,
- /// if the object was already present.
- ///
- public override bool Add(object element)
- {
- element = MaskNull(element);
- if (InternalDictionary[element] != null)
- {
- return false;
- }
- else
- {
- //The object we are adding is just a placeholder. The thing we are
- //really concerned with is 'o', the key.
- InternalDictionary.Add(element, PlaceholderObject);
- return true;
- }
- }
-
- ///
- /// Adds all the elements in the specified collection to the set if
- /// they are not already present.
- ///
- /// A collection of objects to add to the set.
- ///
- /// is the set changed as a result of this
- /// operation.
- ///
- public override bool AddAll(ICollection collection)
- {
- bool changed = false;
- foreach (object o in collection)
- {
- changed |= this.Add(o);
- }
- return changed;
- }
-
- ///
- /// Removes all objects from this set.
- ///
- public override void Clear()
- {
- InternalDictionary.Clear();
- }
-
- ///
- /// Returns if this set contains the specified
- /// element.
- ///
- /// The element to look for.
- ///
- /// if this set contains the specified element.
- ///
- public override bool Contains(object element)
- {
- element = MaskNull(element);
- return InternalDictionary[element] != null;
- }
-
- ///
- /// Returns if the set contains all the
- /// elements in the specified collection.
- ///
- /// A collection of objects.
- ///
- /// if the set contains all the elements in the
- /// specified collection; also if the
- /// supplied is .
- ///
- public override bool ContainsAll(ICollection collection)
- {
- if(collection == null)
- {
- return false;
- }
- foreach (object o in collection)
- {
- if (!this.Contains(MaskNull(o)))
- {
- return false;
- }
- }
- return true;
- }
-
- ///
- /// Returns if this set contains no elements.
- ///
- public override bool IsEmpty
- {
- get { return InternalDictionary.Count == 0; }
- }
-
- ///
- /// Removes the specified element from the set.
- ///
- /// The element to be removed.
- ///
- /// if the set contained the specified element.
- ///
- public override bool Remove(object element)
- {
- element = MaskNull(element);
- bool contained = this.Contains(element);
- if (contained)
- {
- InternalDictionary.Remove(element);
- }
- return contained;
- }
-
- ///
- /// Remove all the specified elements from this set, if they exist in
- /// this set.
- ///
- /// A collection of elements to remove.
- ///
- /// if the set was modified as a result of this
- /// operation.
- ///
- public override bool RemoveAll(ICollection collection)
- {
- bool changed = false;
- foreach (object o in collection)
- {
- changed |= this.Remove(o);
- }
- return changed;
- }
-
- ///
- /// Retains only the elements in this set that are contained in the
- /// specified collection.
- ///
- ///
- /// The collection that defines the set of elements to be retained.
- ///
- ///
- /// if this set changed as a result of this
- /// operation.
- ///
- public override bool RetainAll(ICollection collection)
- {
- //Put data from C into a set so we can use the Contains() method.
- Set cSet = new HybridSet(collection);
-
- //We are going to build a set of elements to remove.
- Set removeSet = new HybridSet();
-
- foreach (object o in this)
- {
- //If C does not contain O, then we need to remove O from our
- //set. We can't do this while iterating through our set, so
- //we put it into RemoveSet for later.
- if (!cSet.Contains(o))
- {
- removeSet.Add(o);
- }
- }
- return this.RemoveAll(removeSet);
- }
-
- ///
- /// Copies the elements in the to
- /// an array.
- ///
- ///
- ///
- /// The type of array needs to be compatible with the objects in the
- /// , obviously.
- ///
+ /// You can use any object that implements the
+ /// interface to hold set
+ /// data. You can define your own, or you can use one of the objects
+ /// provided in the framework. The type of
+ /// you
+ /// choose will affect both the performance and the behavior of the
+ /// using it.
+ ///
+ ///
+ /// This object overrides the method,
+ /// but not the method, because
+ /// the class is mutable.
+ /// Therefore, it is not safe to use as a key value in a dictionary.
+ ///
+ ///
+ /// To make a typed based on your
+ /// own , simply derive a new
+ /// class with a constructor that takes no parameters. Some
+ /// implmentations cannot be defined
+ /// with a default constructor. If this is the case for your class, you
+ /// will need to override clone as well.
+ ///
+ ///
+ /// It is also standard practice that at least one of your constructors
+ /// takes an or an
+ /// as an argument.
+ ///
+ ///
+ ///
+ [Serializable]
+ public abstract class DictionarySet : Set
+ {
+ private IDictionary _internalDictionary;
+
+ private static readonly object PlaceholderObject = new object();
+ private static readonly object NullPlaceHolderKey = new object();
+
+ ///
+ /// Provides the storage for elements in the
+ /// , stored as the key-set
+ /// of the object.
+ ///
+ ///
+ ///
+ /// Set this object in the constructor if you create your own
+ /// class.
+ ///
+ ///
+ protected IDictionary InternalDictionary
+ {
+ get { return _internalDictionary; }
+ set { _internalDictionary = value; }
+ }
+
+ ///
+ /// The placeholder object used as the value for the
+ /// instance.
+ ///
+ ///
+ /// There is a single instance of this object globally, used for all
+ /// s.
+ ///
+ protected static object Placeholder
+ {
+ get { return PlaceholderObject; }
+ }
+
+ ///
+ /// Adds the specified element to this set if it is not already present.
+ ///
+ /// The object to add to the set.
+ ///
+ /// is the object was added,
+ /// if the object was already present.
+ ///
+ public override bool Add(object element)
+ {
+ element = MaskNull(element);
+ if (InternalDictionary[element] != null)
+ {
+ return false;
+ }
+ else
+ {
+ //The object we are adding is just a placeholder. The thing we are
+ //really concerned with is 'o', the key.
+ InternalDictionary.Add(element, PlaceholderObject);
+ return true;
+ }
+ }
+
+ ///
+ /// Adds all the elements in the specified collection to the set if
+ /// they are not already present.
+ ///
+ /// A collection of objects to add to the set.
+ ///
+ /// is the set changed as a result of this
+ /// operation.
+ ///
+ public override bool AddAll(ICollection collection)
+ {
+ bool changed = false;
+ foreach (object o in collection)
+ {
+ changed |= this.Add(o);
+ }
+ return changed;
+ }
+
+ ///
+ /// Removes all objects from this set.
+ ///
+ public override void Clear()
+ {
+ InternalDictionary.Clear();
+ }
+
+ ///
+ /// Returns if this set contains the specified
+ /// element.
+ ///
+ /// The element to look for.
+ ///
+ /// if this set contains the specified element.
+ ///
+ public override bool Contains(object element)
+ {
+ element = MaskNull(element);
+ return InternalDictionary[element] != null;
+ }
+
+ ///
+ /// Returns if the set contains all the
+ /// elements in the specified collection.
+ ///
+ /// A collection of objects.
+ ///
+ /// if the set contains all the elements in the
+ /// specified collection; also if the
+ /// supplied is .
+ ///
+ public override bool ContainsAll(ICollection collection)
+ {
+ if(collection == null)
+ {
+ return false;
+ }
+ foreach (object o in collection)
+ {
+ if (!this.Contains(MaskNull(o)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Returns if this set contains no elements.
+ ///
+ public override bool IsEmpty
+ {
+ get { return InternalDictionary.Count == 0; }
+ }
+
+ ///
+ /// Removes the specified element from the set.
+ ///
+ /// The element to be removed.
+ ///
+ /// if the set contained the specified element.
+ ///
+ public override bool Remove(object element)
+ {
+ element = MaskNull(element);
+ bool contained = this.Contains(element);
+ if (contained)
+ {
+ InternalDictionary.Remove(element);
+ }
+ return contained;
+ }
+
+ ///
+ /// Remove all the specified elements from this set, if they exist in
+ /// this set.
+ ///
+ /// A collection of elements to remove.
+ ///
+ /// if the set was modified as a result of this
+ /// operation.
+ ///
+ public override bool RemoveAll(ICollection collection)
+ {
+ bool changed = false;
+ foreach (object o in collection)
+ {
+ changed |= this.Remove(o);
+ }
+ return changed;
+ }
+
+ ///
+ /// Retains only the elements in this set that are contained in the
+ /// specified collection.
+ ///
+ ///
+ /// The collection that defines the set of elements to be retained.
+ ///
+ ///
+ /// if this set changed as a result of this
+ /// operation.
+ ///
+ public override bool RetainAll(ICollection collection)
+ {
+ //Put data from C into a set so we can use the Contains() method.
+ Set cSet = new HybridSet(collection);
+
+ //We are going to build a set of elements to remove.
+ Set removeSet = new HybridSet();
+
+ foreach (object o in this)
+ {
+ //If C does not contain O, then we need to remove O from our
+ //set. We can't do this while iterating through our set, so
+ //we put it into RemoveSet for later.
+ if (!cSet.Contains(o))
+ {
+ removeSet.Add(o);
+ }
+ }
+ return this.RemoveAll(removeSet);
+ }
+
+ ///
+ /// Copies the elements in the to
+ /// an array.
+ ///
+ ///
+ ///
+ /// The type of array needs to be compatible with the objects in the
+ /// , obviously.
+ ///
- /// This will give the best lookup, add, and remove performance for very
- /// large data-sets, but iteration will occur in no particular order.
- ///
+ /// This will give the best lookup, add, and remove performance for very
+ /// large data-sets, but iteration will occur in no particular order.
+ ///
- /// Besides basic operations,
- /// queues provide additional insertion, extraction, and inspection
- /// operations.
- ///
- ///
- /// Each of these methods exists in two forms: one throws
- /// an exception if the operation fails, the other returns a special
- /// value (either or , depending on the
- /// operation). The latter form of the insert operation is designed
- /// specifically for use with capacity-restricted
- /// implementations; in most implementations, insert operations cannot
- /// fail.
- ///
- ///
- /// Queues typically, but do not necessarily, order elements in a
- /// FIFO (first-in-first-out) manner. Among the exceptions are
- /// priority queues, which order elements according to a supplied
- /// comparator, or the elements' natural ordering, and LIFO queues (or
- /// stacks) which order the elements LIFO (last-in-first-out).
- /// Whatever the ordering used, the head of the queue is that
- /// element which would be removed by a call to
- /// or
- /// . In a FIFO queue, all new
- /// elements are inserted at the tail of the queue. Other kinds of queues may
- /// use different placement rules. Every implementation
- /// must specify its ordering properties.
- ///
- ///
- /// The method inserts an
- /// element if possible, otherwise returning . This differs from the
- /// method, which can fail to
- /// add an element only by throwing an exception. The
- /// method is designed for
- /// use when failure is a normal, rather than exceptional occurrence, for example,
- /// in fixed-capacity (or "bounded" queues.
- ///
- ///
- /// The
- /// methods remove and
- /// return the head of the queue. Exactly which element is removed from the
- /// queue is a function of the queue's ordering policy, which differs from
- /// implementation to implementation. The
- /// and
- /// methods differ only in their
- /// behavior when the queue is empty: the
- /// method throws an exception,
- /// while the method returns
- /// .
- ///
- ///
- /// The and
- /// methods return, but do
- /// not remove, the head of the queue.
- ///
- ///
- /// The interface does not define the blocking queue
- /// methods, which are common in concurrent programming.
- ///
- ///
- /// implementations generally do not allow insertion
- /// of elements, although some implementations, such as
- /// a linked list, do not prohibit the insertion of .
- /// Even in the implementations that permit it, should
- /// not be inserted into a , as is also
- /// used as a special return value by the
- /// method to
- /// indicate that the queue contains no elements.
- ///
- ///
- /// implementations generally do not define
- /// element-based versions of methods
- /// and , but instead inherit the
- /// identity based versions from the class object, because element-based equality
- /// is not always well-defined for queues with the same elements but different
- /// ordering properties.
- ///
- ///
- /// Based on the back port of JCP JSR-166.
- ///
- ///
- /// Doug Lea
- /// Griffin Caprio (.NET)
- /// $Id: IQueue.cs,v 1.7 2006/09/30 18:39:24 gcaprio Exp $
- public interface IQueue : ICollection
- {
- ///
- /// Inserts the specified element into this queue if it is possible to do so
- /// immediately without violating capacity restrictions, returning
- /// upon success and throwing an
- /// if no space is
- /// currently available.
- ///
- ///
- /// The element to add.
- ///
- ///
- /// if successful.
- ///
- ///
- /// If the element cannot be added at this time due to capacity restrictions.
- ///
- ///
- /// If the class of the supplied prevents it
- /// from being added to this queue.
- ///
- ///
- /// If the specified element is and this queue does not
- /// permit elements.
- ///
- ///
- /// If some property of the supplied prevents
- /// it from being added to this queue.
- ///
- bool Add(object objectToAdd);
-
- ///
- /// Inserts the specified element into this queue if it is possible to do
- /// so immediately without violating capacity restrictions.
- ///
- ///
- ///
- /// When using a capacity-restricted queue, this method is generally
- /// preferable to ,
- /// which can fail to insert an element only by throwing an exception.
- ///
- ///
- ///
- /// The element to add.
- ///
- ///
- /// if the element was added to this queue.
- ///
- ///
- /// If the element cannot be added at this time due to capacity restrictions.
- ///
- ///
- /// If the supplied is
- /// .
- ///
- ///
- /// If some property of the supplied prevents
- /// it from being added to this queue.
- ///
- bool Offer(object objectToAdd);
-
- ///
- /// Retrieves and removes the head of this queue.
- ///
- ///
- ///
- /// This method differs from
- /// only in that it throws an exception if this queue is empty.
- ///
- ///
- ///
- /// The head of this queue
- ///
- /// if this queue is empty
- object Remove();
-
- ///
- /// Retrieves and removes the head of this queue,
- /// or returns if this queue is empty.
- ///
- ///
- /// The head of this queue, or if this queue is empty.
- ///
- object Poll();
-
- ///
- /// Retrieves, but does not remove, the head of this queue.
- ///
- ///
- ///
- /// This method differs from
- /// only in that it throws an exception if this queue is empty.
- ///
+ /// Besides basic operations,
+ /// queues provide additional insertion, extraction, and inspection
+ /// operations.
+ ///
+ ///
+ /// Each of these methods exists in two forms: one throws
+ /// an exception if the operation fails, the other returns a special
+ /// value (either or , depending on the
+ /// operation). The latter form of the insert operation is designed
+ /// specifically for use with capacity-restricted
+ /// implementations; in most implementations, insert operations cannot
+ /// fail.
+ ///
+ ///
+ /// Queues typically, but do not necessarily, order elements in a
+ /// FIFO (first-in-first-out) manner. Among the exceptions are
+ /// priority queues, which order elements according to a supplied
+ /// comparator, or the elements' natural ordering, and LIFO queues (or
+ /// stacks) which order the elements LIFO (last-in-first-out).
+ /// Whatever the ordering used, the head of the queue is that
+ /// element which would be removed by a call to
+ /// or
+ /// . In a FIFO queue, all new
+ /// elements are inserted at the tail of the queue. Other kinds of queues may
+ /// use different placement rules. Every implementation
+ /// must specify its ordering properties.
+ ///
+ ///
+ /// The method inserts an
+ /// element if possible, otherwise returning . This differs from the
+ /// method, which can fail to
+ /// add an element only by throwing an exception. The
+ /// method is designed for
+ /// use when failure is a normal, rather than exceptional occurrence, for example,
+ /// in fixed-capacity (or "bounded" queues.
+ ///
+ ///
+ /// The
+ /// methods remove and
+ /// return the head of the queue. Exactly which element is removed from the
+ /// queue is a function of the queue's ordering policy, which differs from
+ /// implementation to implementation. The
+ /// and
+ /// methods differ only in their
+ /// behavior when the queue is empty: the
+ /// method throws an exception,
+ /// while the method returns
+ /// .
+ ///
+ ///
+ /// The and
+ /// methods return, but do
+ /// not remove, the head of the queue.
+ ///
+ ///
+ /// The interface does not define the blocking queue
+ /// methods, which are common in concurrent programming.
+ ///
+ ///
+ /// implementations generally do not allow insertion
+ /// of elements, although some implementations, such as
+ /// a linked list, do not prohibit the insertion of .
+ /// Even in the implementations that permit it, should
+ /// not be inserted into a , as is also
+ /// used as a special return value by the
+ /// method to
+ /// indicate that the queue contains no elements.
+ ///
+ ///
+ /// implementations generally do not define
+ /// element-based versions of methods
+ /// and , but instead inherit the
+ /// identity based versions from the class object, because element-based equality
+ /// is not always well-defined for queues with the same elements but different
+ /// ordering properties.
+ ///
+ ///
+ /// Based on the back port of JCP JSR-166.
+ ///
+ ///
+ /// Doug Lea
+ /// Griffin Caprio (.NET)
+ public interface IQueue : ICollection
+ {
+ ///
+ /// Inserts the specified element into this queue if it is possible to do so
+ /// immediately without violating capacity restrictions, returning
+ /// upon success and throwing an
+ /// if no space is
+ /// currently available.
+ ///
+ ///
+ /// The element to add.
+ ///
+ ///
+ /// if successful.
+ ///
+ ///
+ /// If the element cannot be added at this time due to capacity restrictions.
+ ///
+ ///
+ /// If the class of the supplied prevents it
+ /// from being added to this queue.
+ ///
+ ///
+ /// If the specified element is and this queue does not
+ /// permit elements.
+ ///
+ ///
+ /// If some property of the supplied prevents
+ /// it from being added to this queue.
+ ///
+ bool Add(object objectToAdd);
+
+ ///
+ /// Inserts the specified element into this queue if it is possible to do
+ /// so immediately without violating capacity restrictions.
+ ///
+ ///
+ ///
+ /// When using a capacity-restricted queue, this method is generally
+ /// preferable to ,
+ /// which can fail to insert an element only by throwing an exception.
+ ///
+ ///
+ ///
+ /// The element to add.
+ ///
+ ///
+ /// if the element was added to this queue.
+ ///
+ ///
+ /// If the element cannot be added at this time due to capacity restrictions.
+ ///
+ ///
+ /// If the supplied is
+ /// .
+ ///
+ ///
+ /// If some property of the supplied prevents
+ /// it from being added to this queue.
+ ///
+ bool Offer(object objectToAdd);
+
+ ///
+ /// Retrieves and removes the head of this queue.
+ ///
+ ///
+ ///
+ /// This method differs from
+ /// only in that it throws an exception if this queue is empty.
+ ///
+ ///
+ ///
+ /// The head of this queue
+ ///
+ /// if this queue is empty
+ object Remove();
+
+ ///
+ /// Retrieves and removes the head of this queue,
+ /// or returns if this queue is empty.
+ ///
+ ///
+ /// The head of this queue, or if this queue is empty.
+ ///
+ object Poll();
+
+ ///
+ /// Retrieves, but does not remove, the head of this queue.
+ ///
+ ///
+ ///
+ /// This method differs from
+ /// only in that it throws an exception if this queue is empty.
+ ///
- /// This interface models the mathematical
- /// abstraction. The order of
- /// elements in a set is dependant on (a)the data-structure implementation, and
- /// (b)the implementation of the various
- /// methods, and thus is not
- /// guaranteed.
- ///
- ///
- /// overrides the
- /// method to test for "equivalency":
- /// whether the two sets contain the same elements. The "==" and "!="
- /// operators are not overridden by design, since it is often desirable to
- /// compare object references for equality.
- ///
- ///
- /// Also, the method is not
- /// implemented on any of the set implementations, since none of them are
- /// truly immutable. This is by design, and it is the way almost all
- /// collections in the .NET framework function. So as a general rule, don't
- /// store collection objects inside
- /// instances. You would typically want to use a keyed
- /// instead.
- ///
- ///
- /// None of the implementations in
- /// this library are guaranteed to be thread-safe in any way unless wrapped
- /// in a .
- ///
- ///
- /// The following table summarizes the binary operators that are supported
- /// by the class.
- ///
- ///
- ///
- /// Operation
- /// Description
- /// Method
- ///
- ///
- /// Union (OR)
- ///
- /// Element included in result if it exists in either A OR
- /// B.
- ///
- /// Union()
- ///
- ///
- /// Intersection (AND)
- ///
- /// Element included in result if it exists in both A AND
- /// B.
- ///
- /// InterSect()
- ///
- ///
- /// Exclusive Or (XOR)
- ///
- /// Element included in result if it exists in one, but not both,
- /// of A and B.
- ///
- /// ExclusiveOr()
- ///
- ///
- /// Minus (n/a)
- ///
- /// Take all the elements in A. Now, if any of them exist in
- /// B, remove them. Note that unlike the other operators,
- /// A - B is not the same as B - A.
- ///
- /// Minus()
- ///
- ///
- ///
- /// $Id: ISet.cs,v 1.5 2006/04/09 07:18:37 markpollack Exp $
- public interface ISet : ICollection, ICloneable
- {
- ///
- /// Performs a "union" of the two sets, where all the elements
- /// in both sets are present.
- ///
- ///
- ///
- /// That is, the element is included if it is in either
- /// or this set. Neither this set nor the input
- /// set are modified during the operation. The return value is a
- /// clone of this set with the extra elements added in.
- ///
- ///
- /// A collection of elements.
- ///
- /// A new containing the union of
- /// this with the specified
- /// collection. Neither of the input objects is modified by the union.
- ///
- ISet Union(ISet setOne);
-
- ///
- /// Performs an "intersection" of the two sets, where only the elements
- /// that are present in both sets remain.
- ///
- ///
- ///
- /// That is, the element is included if it exists in both sets. The
- /// Intersect() operation does not modify the input sets. It
- /// returns a clone of this set with the appropriate elements
- /// removed.
- ///
- ///
- /// A set of elements.
- ///
- /// The intersection of this set with .
- ///
- ISet Intersect(ISet setOne);
-
- ///
- /// Performs a "minus" of this set from the
- /// set.
- ///
- ///
- ///
- /// This returns a set of all the elements in set
- /// , removing the elements that are also in
- /// this set. The original sets are not modified during this operation.
- /// The result set is a clone of this
- /// containing the elements from
- /// the operation.
- ///
- ///
- /// A set of elements.
- ///
- /// A set containing the elements from this set with the elements in
- /// removed.
- ///
- ISet Minus(ISet setOne);
-
- ///
- /// Performs an "exclusive-or" of the two sets, keeping only those
- /// elements that are in one of the sets, but not in both.
- ///
- ///
- ///
- /// The original sets are not modified during this operation. The
- /// result set is a clone of this set containing the elements
- /// from the exclusive-or operation.
- ///
+ /// This interface models the mathematical
+ /// abstraction. The order of
+ /// elements in a set is dependant on (a)the data-structure implementation, and
+ /// (b)the implementation of the various
+ /// methods, and thus is not
+ /// guaranteed.
+ ///
+ ///
+ /// overrides the
+ /// method to test for "equivalency":
+ /// whether the two sets contain the same elements. The "==" and "!="
+ /// operators are not overridden by design, since it is often desirable to
+ /// compare object references for equality.
+ ///
+ ///
+ /// Also, the method is not
+ /// implemented on any of the set implementations, since none of them are
+ /// truly immutable. This is by design, and it is the way almost all
+ /// collections in the .NET framework function. So as a general rule, don't
+ /// store collection objects inside
+ /// instances. You would typically want to use a keyed
+ /// instead.
+ ///
+ ///
+ /// None of the implementations in
+ /// this library are guaranteed to be thread-safe in any way unless wrapped
+ /// in a .
+ ///
+ ///
+ /// The following table summarizes the binary operators that are supported
+ /// by the class.
+ ///
+ ///
+ ///
+ /// Operation
+ /// Description
+ /// Method
+ ///
+ ///
+ /// Union (OR)
+ ///
+ /// Element included in result if it exists in either A OR
+ /// B.
+ ///
+ /// Union()
+ ///
+ ///
+ /// Intersection (AND)
+ ///
+ /// Element included in result if it exists in both A AND
+ /// B.
+ ///
+ /// InterSect()
+ ///
+ ///
+ /// Exclusive Or (XOR)
+ ///
+ /// Element included in result if it exists in one, but not both,
+ /// of A and B.
+ ///
+ /// ExclusiveOr()
+ ///
+ ///
+ /// Minus (n/a)
+ ///
+ /// Take all the elements in A. Now, if any of them exist in
+ /// B, remove them. Note that unlike the other operators,
+ /// A - B is not the same as B - A.
+ ///
+ /// Minus()
+ ///
+ ///
+ ///
+ public interface ISet : ICollection, ICloneable
+ {
+ ///
+ /// Performs a "union" of the two sets, where all the elements
+ /// in both sets are present.
+ ///
+ ///
+ ///
+ /// That is, the element is included if it is in either
+ /// or this set. Neither this set nor the input
+ /// set are modified during the operation. The return value is a
+ /// clone of this set with the extra elements added in.
+ ///
+ ///
+ /// A collection of elements.
+ ///
+ /// A new containing the union of
+ /// this with the specified
+ /// collection. Neither of the input objects is modified by the union.
+ ///
+ ISet Union(ISet setOne);
+
+ ///
+ /// Performs an "intersection" of the two sets, where only the elements
+ /// that are present in both sets remain.
+ ///
+ ///
+ ///
+ /// That is, the element is included if it exists in both sets. The
+ /// Intersect() operation does not modify the input sets. It
+ /// returns a clone of this set with the appropriate elements
+ /// removed.
+ ///
+ ///
+ /// A set of elements.
+ ///
+ /// The intersection of this set with .
+ ///
+ ISet Intersect(ISet setOne);
+
+ ///
+ /// Performs a "minus" of this set from the
+ /// set.
+ ///
+ ///
+ ///
+ /// This returns a set of all the elements in set
+ /// , removing the elements that are also in
+ /// this set. The original sets are not modified during this operation.
+ /// The result set is a clone of this
+ /// containing the elements from
+ /// the operation.
+ ///
+ ///
+ /// A set of elements.
+ ///
+ /// A set containing the elements from this set with the elements in
+ /// removed.
+ ///
+ ISet Minus(ISet setOne);
+
+ ///
+ /// Performs an "exclusive-or" of the two sets, keeping only those
+ /// elements that are in one of the sets, but not in both.
+ ///
+ ///
+ ///
+ /// The original sets are not modified during this operation. The
+ /// result set is a clone of this set containing the elements
+ /// from the exclusive-or operation.
+ ///
- /// Although this class is advertised as immutable, it really isn't.
- /// Anyone with access to the wrapped
- /// can still change the data. So
- /// is not implemented for this , as
- /// is the case for all
- /// implementations in this library. This design decision was based on the
- /// efficiency of not having to clone the wrapped
- /// every time you wrap a mutable
- /// .
- ///
- ///
- /// $Id: ImmutableSet.cs,v 1.6 2007/03/16 04:01:28 aseovic Exp $
- [Serializable]
- public sealed class ImmutableSet : Set
- {
- private const string ErrorMessage = "Object is immutable.";
- private ISet _mBasisSet;
-
- internal ISet BasisSet
- {
- get { return _mBasisSet; }
- }
-
- ///
- /// Constructs an immutable (read-only)
- /// wrapper.
- ///
- ///
- /// The that is to be wrapped.
- ///
- public ImmutableSet(ISet basisSet)
- {
- _mBasisSet = basisSet;
- }
-
- ///
- /// Adds the specified element to this set if it is not already present.
- ///
- /// The object to add to the set.
- ///
- /// is the object was added,
- /// if the object was already present.
- ///
- ///
- public override sealed bool Add(object element)
- {
- throw CreateNotSupportedException();
- }
-
- ///
- /// Adds all the elements in the specified collection to the set if
- /// they are not already present.
- ///
- /// A collection of objects to add to the set.
- ///
- /// is the set changed as a result of this
- /// operation.
- ///
- ///
- public override sealed bool AddAll(ICollection collection)
- {
- throw CreateNotSupportedException();
- }
-
- ///
- /// Removes all objects from this set.
- ///
- ///
- public override sealed void Clear()
- {
- throw CreateNotSupportedException();
- }
-
- ///
- /// Returns if this set contains the specified
- /// element.
- ///
- /// The element to look for.
- ///
- /// if this set contains the specified element.
- ///
- public override sealed bool Contains(object element)
- {
- return _mBasisSet.Contains(element);
- }
-
- ///
- /// Returns if the set contains all the
- /// elements in the specified collection.
- ///
- /// A collection of objects.
- ///
- /// if the set contains all the elements in the
- /// specified collection.
- ///
- public override sealed bool ContainsAll(ICollection collection)
- {
- return _mBasisSet.ContainsAll(collection);
- }
-
- ///
- /// Returns if this set contains no elements.
- ///
- public override sealed bool IsEmpty
- {
- get { return _mBasisSet.IsEmpty; }
- }
-
- ///
- /// Removes the specified element from the set.
- ///
- /// The element to be removed.
- ///
- /// if the set contained the specified element.
- ///
- ///
- public override sealed bool Remove(object element)
- {
- throw CreateNotSupportedException();
- }
-
- ///
- /// Remove all the specified elements from this set, if they exist in
- /// this set.
- ///
- /// A collection of elements to remove.
- ///
- /// if the set was modified as a result of this
- /// operation.
- ///
- ///
- public override sealed bool RemoveAll(ICollection collection)
- {
- throw CreateNotSupportedException();
- }
-
- ///
- /// Retains only the elements in this set that are contained in the
- /// specified collection.
- ///
- ///
- /// The collection that defines the set of elements to be retained.
- ///
- ///
- /// if this set changed as a result of this
- /// operation.
- ///
- ///
- public override sealed bool RetainAll(ICollection collection)
- {
- throw CreateNotSupportedException();
- }
-
- private static NotSupportedException CreateNotSupportedException()
- {
- return new NotSupportedException(ImmutableSet.ErrorMessage);
- }
-
- ///
- /// Copies the elements in the to
- /// an array.
- ///
- ///
- ///
- /// The type of array needs to be compatible with the objects in the
- /// , obviously.
- ///
- ///
- ///
- /// An array that will be the target of the copy operation.
- ///
- ///
- /// The zero-based index where copying will start.
- ///
- public override sealed void CopyTo(Array array, int index)
- {
- _mBasisSet.CopyTo(array, index);
- }
-
- ///
- /// The number of elements currently contained in this collection.
- ///
- public override sealed int Count
- {
- get { return _mBasisSet.Count; }
- }
-
- ///
- /// Returns if the
- /// is synchronized across
- /// threads.
- ///
- ///
- ///
- /// Note that enumeration is inherently not thread-safe. Use the
- /// to lock the object during enumeration.
- ///
+ /// Although this class is advertised as immutable, it really isn't.
+ /// Anyone with access to the wrapped
+ /// can still change the data. So
+ /// is not implemented for this , as
+ /// is the case for all
+ /// implementations in this library. This design decision was based on the
+ /// efficiency of not having to clone the wrapped
+ /// every time you wrap a mutable
+ /// .
+ ///
+ ///
+ [Serializable]
+ public sealed class ImmutableSet : Set
+ {
+ private const string ErrorMessage = "Object is immutable.";
+ private ISet _mBasisSet;
+
+ internal ISet BasisSet
+ {
+ get { return _mBasisSet; }
+ }
+
+ ///
+ /// Constructs an immutable (read-only)
+ /// wrapper.
+ ///
+ ///
+ /// The that is to be wrapped.
+ ///
+ public ImmutableSet(ISet basisSet)
+ {
+ _mBasisSet = basisSet;
+ }
+
+ ///
+ /// Adds the specified element to this set if it is not already present.
+ ///
+ /// The object to add to the set.
+ ///
+ /// is the object was added,
+ /// if the object was already present.
+ ///
+ ///
+ public override sealed bool Add(object element)
+ {
+ throw CreateNotSupportedException();
+ }
+
+ ///
+ /// Adds all the elements in the specified collection to the set if
+ /// they are not already present.
+ ///
+ /// A collection of objects to add to the set.
+ ///
+ /// is the set changed as a result of this
+ /// operation.
+ ///
+ ///
+ public override sealed bool AddAll(ICollection collection)
+ {
+ throw CreateNotSupportedException();
+ }
+
+ ///
+ /// Removes all objects from this set.
+ ///
+ ///
+ public override sealed void Clear()
+ {
+ throw CreateNotSupportedException();
+ }
+
+ ///
+ /// Returns if this set contains the specified
+ /// element.
+ ///
+ /// The element to look for.
+ ///
+ /// if this set contains the specified element.
+ ///
+ public override sealed bool Contains(object element)
+ {
+ return _mBasisSet.Contains(element);
+ }
+
+ ///
+ /// Returns if the set contains all the
+ /// elements in the specified collection.
+ ///
+ /// A collection of objects.
+ ///
+ /// if the set contains all the elements in the
+ /// specified collection.
+ ///
+ public override sealed bool ContainsAll(ICollection collection)
+ {
+ return _mBasisSet.ContainsAll(collection);
+ }
+
+ ///
+ /// Returns if this set contains no elements.
+ ///
+ public override sealed bool IsEmpty
+ {
+ get { return _mBasisSet.IsEmpty; }
+ }
+
+ ///
+ /// Removes the specified element from the set.
+ ///
+ /// The element to be removed.
+ ///
+ /// if the set contained the specified element.
+ ///
+ ///
+ public override sealed bool Remove(object element)
+ {
+ throw CreateNotSupportedException();
+ }
+
+ ///
+ /// Remove all the specified elements from this set, if they exist in
+ /// this set.
+ ///
+ /// A collection of elements to remove.
+ ///
+ /// if the set was modified as a result of this
+ /// operation.
+ ///
+ ///
+ public override sealed bool RemoveAll(ICollection collection)
+ {
+ throw CreateNotSupportedException();
+ }
+
+ ///
+ /// Retains only the elements in this set that are contained in the
+ /// specified collection.
+ ///
+ ///
+ /// The collection that defines the set of elements to be retained.
+ ///
+ ///
+ /// if this set changed as a result of this
+ /// operation.
+ ///
+ ///
+ public override sealed bool RetainAll(ICollection collection)
+ {
+ throw CreateNotSupportedException();
+ }
+
+ private static NotSupportedException CreateNotSupportedException()
+ {
+ return new NotSupportedException(ImmutableSet.ErrorMessage);
+ }
+
+ ///
+ /// Copies the elements in the to
+ /// an array.
+ ///
+ ///
+ ///
+ /// The type of array needs to be compatible with the objects in the
+ /// , obviously.
+ ///
+ ///
+ ///
+ /// An array that will be the target of the copy operation.
+ ///
+ ///
+ /// The zero-based index where copying will start.
+ ///
+ public override sealed void CopyTo(Array array, int index)
+ {
+ _mBasisSet.CopyTo(array, index);
+ }
+
+ ///
+ /// The number of elements currently contained in this collection.
+ ///
+ public override sealed int Count
+ {
+ get { return _mBasisSet.Count; }
+ }
+
+ ///
+ /// Returns if the
+ /// is synchronized across
+ /// threads.
+ ///
+ ///
+ ///
+ /// Note that enumeration is inherently not thread-safe. Use the
+ /// to lock the object during enumeration.
+ ///
- /// This is the indexer for the
- /// class.
- ///
- ///
- ///
- public object this[int index]
- {
- get { return GetNode(index).Value; }
- set { GetNode(index).Value = value; }
- }
-
- ///
- /// Removes the object at the specified index.
- ///
- /// The lookup index.
- ///
- /// If the specified is greater than the
- /// number of objects within the list.
- ///
- public void RemoveAt(int index)
- {
- CheckUpdateState();
- RemoveNode(GetNode(index));
- }
-
- ///
- /// Inserts an object at the specified index.
- ///
- /// The lookup index.
- /// The object to be inserted.
- ///
- /// If the specified is greater than the
- /// number of objects within the list.
- ///
- public void Insert(int index, object value)
- {
- CheckUpdateState();
-
- Node node = null;
- if (index == _nodeIndex)
- {
- node = new Node(value, _rootNode.PreviousNode, _rootNode);
- }
- else
- {
- Node insert = GetNode(index);
- node = new Node(value, insert.PreviousNode, insert);
- }
- node.PreviousNode.NextNode = node;
- node.NextNode.PreviousNode = node;
- _nodeIndex++;
- _modId++;
- }
-
- ///
- /// Removes the first instance of the specified object found.
- ///
- /// The object to remove
- public void Remove(object value)
- {
- CheckUpdateState();
- NodeHolder nh = GetNode(value);
- RemoveNode(nh.Node);
- }
-
- ///
- /// Returns if this list contains the specified
- /// element.
- ///
- /// The element to look for.
- ///
- /// if this list contains the specified element.
- ///
- public bool Contains(object value)
- {
- return GetNode(value) != null;
- }
-
- ///
- /// Removes all objects from the list.
- ///
- public void Clear()
- {
- _rootNode = new Node(null, null, null);
- _nodeIndex = 0;
- _modId++;
- }
-
- ///
- /// Returns the index of the first instance of the specified
- /// found.
- ///
- /// The object to search for
- ///
- /// The index of the first instance found, or -1 if the element was not
- /// found.
- ///
- public int IndexOf(object value)
- {
- NodeHolder nh = GetNode(value);
- if (nh == null)
- {
- return -1;
- }
- return nh.Index;
- }
-
- ///
- /// Adds the specified object to the end of the list.
- ///
- /// The object to add
- /// The index that the object was added at.
- public int Add(object value)
- {
- Insert(_nodeIndex, value);
- return _nodeIndex - 1;
- }
-
- ///
- /// Adds all of the elements of the supplied
- /// list to the end of this list.
- ///
- /// The list of objects to add.
- public void AddAll(IList elements)
- {
- foreach (object obj in elements)
- {
- Add(obj);
- }
- }
-
- ///
- /// Is the list a fixed size?
- ///
- ///
- /// if the list is a fixed size list.
- ///
- public bool IsFixedSize
- {
- get { return false; }
- }
-
- #endregion
-
- #region Private Methods
-
- ///
- /// Checks whether the list can be modified.
- ///
- ///
- /// If the list cannot be modified.
- ///
- private void CheckUpdateState()
- {
- if (IsReadOnly || IsFixedSize)
- {
- throw new NotSupportedException("LinkedList cannot be modified.");
- }
- }
-
- ///
- /// Validates the specified index.
- ///
- /// The lookup index.
- ///
- /// If the index is invalid.
- ///
- private void ValidateIndex(int index)
- {
- if (index < 0 || index >= _nodeIndex)
- {
- throw new ArgumentOutOfRangeException("index");
- }
- }
-
- ///
- /// Returns the node at the specified index.
- ///
- /// The lookup index.
- /// The node at the specified index.
- ///
- /// If the specified is greater than the
- /// number of objects within the list.
- ///
- private Node GetNode(int index)
- {
- ValidateIndex(index);
- Node node = _rootNode;
- for (int i = 0; i <= index; i++)
- {
- node = node.NextNode;
- }
- return node;
- }
-
- ///
- /// Returns the node (and index) of the first node that contains
- /// the specified value.
- ///
- /// The value to search for.
- ///
- /// The node, or if not found.
- ///
- private NodeHolder GetNode(object value)
- {
- int i = 0;
- if (value == null)
- {
-
- for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode)
- {
- if (n.Value == null)
- {
- return new NodeHolder(n, i);
- }
- i++;
- }
- }
- else
- {
-
- for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode)
- {
- if (value.Equals(n.Value))
- {
- return new NodeHolder(n, i);
- }
- i++;
- }
- }
- return null;
- }
-
- ///
- /// Removes the specified node.
- ///
- /// The node to be removed.
- private void RemoveNode(Node node)
- {
- Node previousNode = node.PreviousNode;
- previousNode.NextNode = node.NextNode;
- node.NextNode.PreviousNode = previousNode;
- node.PreviousNode = null;
- node.NextNode = null;
- _nodeIndex--;
- _modId++;
- }
-
- #endregion
-
- #region ICollection Members
-
- ///
- /// Returns if the list is synchronized across
- /// threads.
- ///
- ///
- ///
- /// This implementation always returns .
- ///
- ///
- /// Note that enumeration is inherently not thread-safe. Use the
- /// to lock the object during enumeration.
- ///
- ///
- public bool IsSynchronized
- {
- get { return false; }
- }
-
- ///
- /// The number of objects within the list.
- ///
- public int Count
- {
- get { return _nodeIndex; }
- }
-
- ///
- /// Copies the elements in this list to an array.
- ///
- ///
- ///
- /// The type of array needs to be compatible with the objects in this
- /// list, obviously.
- ///
- ///
- ///
- /// An array that will be the target of the copy operation.
- ///
- ///
- /// The zero-based index where copying will start.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- /// If the supplied is less than zero
- /// or is greater than the length of .
- ///
- ///
- /// If the supplied is of insufficient size.
- ///
- public void CopyTo(Array array, int index)
- {
- if (array == null)
- {
- throw new ArgumentNullException("array");
- }
- if ((index < 0) || (index > array.Length))
- {
- throw new ArgumentOutOfRangeException("index", String.Format("Index {0} is out of range.", index));
- }
- if ((array.Length - index) < this._nodeIndex)
- {
- throw new ArgumentException("Array is of insufficient size.");
- }
-
- Node node = this._rootNode;
- for (int i = 0, pos = index; i < this._nodeIndex; i++, pos++)
- {
- node = node.NextNode;
- array.SetValue(node.Value, pos);
- }
- }
-
- ///
- /// An object that can be used to synchronize this
- /// to make it thread-safe.
- ///
- ///
- /// An object that can be used to synchronize this
- /// to make it thread-safe.
- ///
- public object SyncRoot
- {
- get { return this; }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- ///
- /// Gets an enumerator for the elements in the
- /// .
- ///
- ///
- ///
+ /// This is the indexer for the
+ /// class.
+ ///
+ ///
+ ///
+ public object this[int index]
+ {
+ get { return GetNode(index).Value; }
+ set { GetNode(index).Value = value; }
+ }
+
+ ///
+ /// Removes the object at the specified index.
+ ///
+ /// The lookup index.
+ ///
+ /// If the specified is greater than the
+ /// number of objects within the list.
+ ///
+ public void RemoveAt(int index)
+ {
+ CheckUpdateState();
+ RemoveNode(GetNode(index));
+ }
+
+ ///
+ /// Inserts an object at the specified index.
+ ///
+ /// The lookup index.
+ /// The object to be inserted.
+ ///
+ /// If the specified is greater than the
+ /// number of objects within the list.
+ ///
+ public void Insert(int index, object value)
+ {
+ CheckUpdateState();
+
+ Node node = null;
+ if (index == _nodeIndex)
+ {
+ node = new Node(value, _rootNode.PreviousNode, _rootNode);
+ }
+ else
+ {
+ Node insert = GetNode(index);
+ node = new Node(value, insert.PreviousNode, insert);
+ }
+ node.PreviousNode.NextNode = node;
+ node.NextNode.PreviousNode = node;
+ _nodeIndex++;
+ _modId++;
+ }
+
+ ///
+ /// Removes the first instance of the specified object found.
+ ///
+ /// The object to remove
+ public void Remove(object value)
+ {
+ CheckUpdateState();
+ NodeHolder nh = GetNode(value);
+ RemoveNode(nh.Node);
+ }
+
+ ///
+ /// Returns if this list contains the specified
+ /// element.
+ ///
+ /// The element to look for.
+ ///
+ /// if this list contains the specified element.
+ ///
+ public bool Contains(object value)
+ {
+ return GetNode(value) != null;
+ }
+
+ ///
+ /// Removes all objects from the list.
+ ///
+ public void Clear()
+ {
+ _rootNode = new Node(null, null, null);
+ _nodeIndex = 0;
+ _modId++;
+ }
+
+ ///
+ /// Returns the index of the first instance of the specified
+ /// found.
+ ///
+ /// The object to search for
+ ///
+ /// The index of the first instance found, or -1 if the element was not
+ /// found.
+ ///
+ public int IndexOf(object value)
+ {
+ NodeHolder nh = GetNode(value);
+ if (nh == null)
+ {
+ return -1;
+ }
+ return nh.Index;
+ }
+
+ ///
+ /// Adds the specified object to the end of the list.
+ ///
+ /// The object to add
+ /// The index that the object was added at.
+ public int Add(object value)
+ {
+ Insert(_nodeIndex, value);
+ return _nodeIndex - 1;
+ }
+
+ ///
+ /// Adds all of the elements of the supplied
+ /// list to the end of this list.
+ ///
+ /// The list of objects to add.
+ public void AddAll(IList elements)
+ {
+ foreach (object obj in elements)
+ {
+ Add(obj);
+ }
+ }
+
+ ///
+ /// Is the list a fixed size?
+ ///
+ ///
+ /// if the list is a fixed size list.
+ ///
+ public bool IsFixedSize
+ {
+ get { return false; }
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Checks whether the list can be modified.
+ ///
+ ///
+ /// If the list cannot be modified.
+ ///
+ private void CheckUpdateState()
+ {
+ if (IsReadOnly || IsFixedSize)
+ {
+ throw new NotSupportedException("LinkedList cannot be modified.");
+ }
+ }
+
+ ///
+ /// Validates the specified index.
+ ///
+ /// The lookup index.
+ ///
+ /// If the index is invalid.
+ ///
+ private void ValidateIndex(int index)
+ {
+ if (index < 0 || index >= _nodeIndex)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ }
+
+ ///
+ /// Returns the node at the specified index.
+ ///
+ /// The lookup index.
+ /// The node at the specified index.
+ ///
+ /// If the specified is greater than the
+ /// number of objects within the list.
+ ///
+ private Node GetNode(int index)
+ {
+ ValidateIndex(index);
+ Node node = _rootNode;
+ for (int i = 0; i <= index; i++)
+ {
+ node = node.NextNode;
+ }
+ return node;
+ }
+
+ ///
+ /// Returns the node (and index) of the first node that contains
+ /// the specified value.
+ ///
+ /// The value to search for.
+ ///
+ /// The node, or if not found.
+ ///
+ private NodeHolder GetNode(object value)
+ {
+ int i = 0;
+ if (value == null)
+ {
+
+ for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode)
+ {
+ if (n.Value == null)
+ {
+ return new NodeHolder(n, i);
+ }
+ i++;
+ }
+ }
+ else
+ {
+
+ for (Node n = _rootNode.NextNode; n != _rootNode; n = n.NextNode)
+ {
+ if (value.Equals(n.Value))
+ {
+ return new NodeHolder(n, i);
+ }
+ i++;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Removes the specified node.
+ ///
+ /// The node to be removed.
+ private void RemoveNode(Node node)
+ {
+ Node previousNode = node.PreviousNode;
+ previousNode.NextNode = node.NextNode;
+ node.NextNode.PreviousNode = previousNode;
+ node.PreviousNode = null;
+ node.NextNode = null;
+ _nodeIndex--;
+ _modId++;
+ }
+
+ #endregion
+
+ #region ICollection Members
+
+ ///
+ /// Returns if the list is synchronized across
+ /// threads.
+ ///
+ ///
+ ///
+ /// This implementation always returns .
+ ///
+ ///
+ /// Note that enumeration is inherently not thread-safe. Use the
+ /// to lock the object during enumeration.
+ ///
+ ///
+ public bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ ///
+ /// The number of objects within the list.
+ ///
+ public int Count
+ {
+ get { return _nodeIndex; }
+ }
+
+ ///
+ /// Copies the elements in this list to an array.
+ ///
+ ///
+ ///
+ /// The type of array needs to be compatible with the objects in this
+ /// list, obviously.
+ ///
+ ///
+ ///
+ /// An array that will be the target of the copy operation.
+ ///
+ ///
+ /// The zero-based index where copying will start.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ /// If the supplied is less than zero
+ /// or is greater than the length of .
+ ///
+ ///
+ /// If the supplied is of insufficient size.
+ ///
+ public void CopyTo(Array array, int index)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+ if ((index < 0) || (index > array.Length))
+ {
+ throw new ArgumentOutOfRangeException("index", String.Format("Index {0} is out of range.", index));
+ }
+ if ((array.Length - index) < this._nodeIndex)
+ {
+ throw new ArgumentException("Array is of insufficient size.");
+ }
+
+ Node node = this._rootNode;
+ for (int i = 0, pos = index; i < this._nodeIndex; i++, pos++)
+ {
+ node = node.NextNode;
+ array.SetValue(node.Value, pos);
+ }
+ }
+
+ ///
+ /// An object that can be used to synchronize this
+ /// to make it thread-safe.
+ ///
+ ///
+ /// An object that can be used to synchronize this
+ /// to make it thread-safe.
+ ///
+ public object SyncRoot
+ {
+ get { return this; }
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ ///
+ /// Gets an enumerator for the elements in the
+ /// .
+ ///
+ ///
+ ///
- /// Performance is much better for very small lists than either
- /// or .
- /// However, performance degrades rapidly as the data-set gets bigger. Use a
- /// instead if you are not sure your data-set
- /// will always remain very small. Iteration produces elements in the order they were added.
- /// However, element order is not guaranteed to be maintained by the various
- /// mathematical operators.
- ///
+ /// Performance is much better for very small lists than either
+ /// or .
+ /// However, performance degrades rapidly as the data-set gets bigger. Use a
+ /// instead if you are not sure your data-set
+ /// will always remain very small. Iteration produces elements in the order they were added.
+ /// However, element order is not guaranteed to be maintained by the various
+ /// mathematical operators.
+ ///
- /// When using a capacity-restricted queue, this method is generally
- /// preferable to ,
- /// which can fail to insert an element only by throwing an exception.
- ///
+ /// When using a capacity-restricted queue, this method is generally
+ /// preferable to ,
+ /// which can fail to insert an element only by throwing an exception.
+ ///
- /// That is, the element is included if it is in either
- /// or . The return
- /// value is a clone of one of the sets (
- /// if it is not ) with elements of the other set
- /// added in. Neither of the input sets is modified by the operation.
- ///
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing the union of the input sets;
- /// if both sets are .
- ///
- public static ISet Union(ISet setOne, ISet anotherSet)
- {
- if (setOne == null && anotherSet == null)
- {
- return null;
- }
- else if (setOne == null)
- {
- return (ISet) anotherSet.Clone();
- }
- else if (anotherSet == null)
- {
- return (ISet) setOne.Clone();
- }
- else
- {
- return setOne.Union(anotherSet);
- }
- }
-
- ///
- /// Performs a "union" of two sets, where all the elements in both are
- /// present.
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing the union of the input sets;
- /// if both sets are .
- ///
- ///
- public static Set operator |(Set setOne, Set anotherSet)
- {
- return (Set) Union(setOne, anotherSet);
- }
-
- ///
- /// Performs an "intersection" of the two sets, where only the elements
- /// that are present in both sets remain.
- ///
- /// A set of elements.
- ///
- /// The intersection of this set with .
- ///
- ///
- public virtual ISet Intersect(ISet setOne)
- {
- ISet resultSet = (ISet) this.Clone();
- if (setOne != null)
- {
- resultSet.RetainAll(setOne);
- }
- else
- {
- resultSet.Clear();
- }
- return resultSet;
- }
-
- ///
- /// Performs an "intersection" of the two sets, where only the elements
- /// that are present in both sets remain.
- ///
- ///
- ///
- /// That is, the element is included only if it exists in both
- /// and . Neither input
- /// object is modified by the operation. The result object is a
- /// clone of one of the input objects (
- /// if it is not ) containing the elements from
- /// the intersect operation.
- ///
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// The intersection of the two input sets; if
- /// both sets are .
- ///
- public static ISet Intersect(ISet setOne, ISet anotherSet)
- {
- if (setOne == null && anotherSet == null)
- {
- return null;
- }
- else if (setOne == null)
- {
- return anotherSet.Intersect(setOne);
- }
- else
- {
- return setOne.Intersect(anotherSet);
- }
- }
-
- ///
- /// Performs an "intersection" of the two sets, where only the elements
- /// that are present in both sets remain.
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// The intersection of the two input sets; if
- /// both sets are .
- ///
- ///
- public static Set operator &(Set setOne, Set anotherSet)
- {
- return (Set) Intersect(setOne, anotherSet);
- }
-
- ///
- /// Performs a "minus" of this set from the
- /// set.
- ///
- /// A set of elements.
- ///
- /// A set containing the elements from this set with the elements in
- /// removed.
- ///
- ///
- public virtual ISet Minus(ISet setOne)
- {
- ISet resultSet = (ISet) this.Clone();
- if (setOne != null)
- {
- resultSet.RemoveAll(setOne);
- }
- return resultSet;
- }
-
- ///
- /// Performs a "minus" of set from set
- /// .
- ///
- ///
- ///
- /// This returns a set of all the elements in set
- /// , removing the elements that are also in
- /// set . The original sets are not modified
- /// during this operation. The result set is a clone of set
- /// containing the elements from the operation.
- ///
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing
- /// - elements.
- /// if is
- /// .
- ///
- public static ISet Minus(ISet setOne, ISet anotherSet)
- {
- if (setOne == null)
- {
- return null;
- }
- else
- {
- return setOne.Minus(anotherSet);
- }
- }
-
- ///
- /// Performs a "minus" of set from set
- /// .
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing
- /// - elements.
- /// if is
- /// .
- ///
- ///
- public static Set operator -(Set setOne, Set anotherSet)
- {
- return (Set) Minus(setOne, anotherSet);
- }
-
-
- ///
- /// Performs an "exclusive-or" of the two sets, keeping only those
- /// elements that are in one of the sets, but not in both.
- ///
- /// A set of elements.
- ///
- /// A set containing the result of
- /// ^ this.
- ///
- ///
- public virtual ISet ExclusiveOr(ISet setOne)
- {
- ISet resultSet = (ISet) this.Clone();
- foreach (object element in setOne)
- {
- if (resultSet.Contains(element))
- {
- resultSet.Remove(element);
- }
- else
- {
- resultSet.Add(element);
- }
- }
- return resultSet;
- }
-
- ///
- /// Performs an "exclusive-or" of the two sets, keeping only those
- /// elements that are in one of the sets, but not in both.
- ///
- ///
- ///
- /// The original sets are not modified during this operation. The
- /// result set is a clone of one of the sets (
- /// if it is not )
- /// containing the elements from the exclusive-or operation.
- ///
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing the result of
- /// ^ .
- /// if both sets are .
- ///
- public static ISet ExclusiveOr(ISet setOne, ISet anotherSet)
- {
- if (setOne == null && anotherSet == null)
- {
- return null;
- }
- else if (setOne == null)
- {
- return (Set) anotherSet.Clone();
- }
- else if (anotherSet == null)
- {
- return (Set) setOne.Clone();
- }
- else
- {
- return setOne.ExclusiveOr(anotherSet);
- }
- }
-
- ///
- /// Performs an "exclusive-or" of the two sets, keeping only those
- /// elements that are in one of the sets, but not in both.
- ///
- /// A set of elements.
- /// A set of elements.
- ///
- /// A set containing the result of
- /// ^ .
- /// if both sets are .
- ///
- ///
- public static Set operator ^(Set setOne, Set anotherSet)
- {
- return (Set) ExclusiveOr(setOne, anotherSet);
- }
-
- ///
- /// Adds the specified element to this set if it is not already present.
- ///
- /// The object to add to the set.
- ///
- /// is the object was added,
- /// if the object was already present.
- ///
- public abstract bool Add(object element);
-
- ///
- /// Adds all the elements in the specified collection to the set if
- /// they are not already present.
- ///
- /// A collection of objects to add to the set.
- ///
- /// is the set changed as a result of this
- /// operation.
- ///
- public abstract bool AddAll(ICollection collection);
-
- ///
- /// Removes all objects from this set.
- ///
- public abstract void Clear();
-
- ///
- /// Returns if this set contains the specified
- /// element.
- ///
- /// The element to look for.
- ///
- /// if this set contains the specified element.
- ///
- public abstract bool Contains(object element);
-
- ///
- /// Returns if the set contains all the
- /// elements in the specified collection.
- ///
- /// A collection of objects.
- ///
- /// if the set contains all the elements in the
- /// specified collection.
- ///
- public abstract bool ContainsAll(ICollection collection);
-
- ///
- /// Returns if this set contains no elements.
- ///
- public abstract bool IsEmpty { get; }
-
- ///
- /// Removes the specified element from the set.
- ///
- /// The element to be removed.
- ///
- /// if the set contained the specified element.
- ///
- public abstract bool Remove(object element);
-
- ///
- /// Remove all the specified elements from this set, if they exist in
- /// this set.
- ///
- /// A collection of elements to remove.
- ///
- /// if the set was modified as a result of this
- /// operation.
- ///
- public abstract bool RemoveAll(ICollection collection);
-
- ///
- /// Retains only the elements in this set that are contained in the
- /// specified collection.
- ///
- ///
- /// The collection that defines the set of elements to be retained.
- ///
- ///
- /// if this set changed as a result of this
- /// operation.
- ///
- public abstract bool RetainAll(ICollection collection);
-
- ///
- /// Returns a clone of the
- /// instance.
- ///
- ///
- ///
- /// This will work for derived
- /// classes if the derived class implements a constructor that takes no
- /// arguments.
- ///
- ///
- /// A clone of this object.
- public virtual object Clone()
- {
- Set newSet = (Set) Activator.CreateInstance(this.GetType());
- newSet.AddAll(this);
- return newSet;
- }
-
- ///
- /// Copies the elements in the to
- /// an array.
- ///
- ///
- ///
- /// The type of array needs to be compatible with the objects in the
- /// , obviously.
- ///
- ///
- ///
- /// An array that will be the target of the copy operation.
- ///
- ///
- /// The zero-based index where copying will start.
- ///
- public abstract void CopyTo(Array array, int index);
-
- ///
- /// The number of elements currently contained in this collection.
- ///
- public abstract int Count { get; }
-
- ///
- /// Returns if the
- /// is synchronized across
- /// threads.
- ///
- ///
- ///
- /// Note that enumeration is inherently not thread-safe. Use the
- /// to lock the object during enumeration.
- ///
- ///
- public abstract bool IsSynchronized { get; }
-
- ///
- /// An object that can be used to synchronize this collection to make
- /// it thread-safe.
- ///
- ///
- ///
- /// When implementing this, if your object uses a base object, like an
- /// , or anything that has
- /// a SyncRoot, return that object instead of "this".
- ///
- ///
- ///
- /// An object that can be used to synchronize this collection to make
- /// it thread-safe.
- ///
- public abstract object SyncRoot { get; }
-
- ///
- /// Gets an enumerator for the elements in the
- /// .
- ///
- ///
- /// An over the elements
- /// in the .
- ///
- public abstract IEnumerator GetEnumerator();
-
- ///
- /// This method will test the
- /// against another for
- /// "equality".
- ///
- ///
- ///
- /// In this case, "equality" means that the two sets contain the same
- /// elements. The "==" and "!=" operators are not overridden by design.
- /// If you wish to check for "equivalent"
- /// instances, use
- /// Equals(). If you wish to check to see if two references are
- /// actually the same object, use "==" and "!=".
- ///
+ /// That is, the element is included if it is in either
+ /// or . The return
+ /// value is a clone of one of the sets (
+ /// if it is not ) with elements of the other set
+ /// added in. Neither of the input sets is modified by the operation.
+ ///
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing the union of the input sets;
+ /// if both sets are .
+ ///
+ public static ISet Union(ISet setOne, ISet anotherSet)
+ {
+ if (setOne == null && anotherSet == null)
+ {
+ return null;
+ }
+ else if (setOne == null)
+ {
+ return (ISet) anotherSet.Clone();
+ }
+ else if (anotherSet == null)
+ {
+ return (ISet) setOne.Clone();
+ }
+ else
+ {
+ return setOne.Union(anotherSet);
+ }
+ }
+
+ ///
+ /// Performs a "union" of two sets, where all the elements in both are
+ /// present.
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing the union of the input sets;
+ /// if both sets are .
+ ///
+ ///
+ public static Set operator |(Set setOne, Set anotherSet)
+ {
+ return (Set) Union(setOne, anotherSet);
+ }
+
+ ///
+ /// Performs an "intersection" of the two sets, where only the elements
+ /// that are present in both sets remain.
+ ///
+ /// A set of elements.
+ ///
+ /// The intersection of this set with .
+ ///
+ ///
+ public virtual ISet Intersect(ISet setOne)
+ {
+ ISet resultSet = (ISet) this.Clone();
+ if (setOne != null)
+ {
+ resultSet.RetainAll(setOne);
+ }
+ else
+ {
+ resultSet.Clear();
+ }
+ return resultSet;
+ }
+
+ ///
+ /// Performs an "intersection" of the two sets, where only the elements
+ /// that are present in both sets remain.
+ ///
+ ///
+ ///
+ /// That is, the element is included only if it exists in both
+ /// and . Neither input
+ /// object is modified by the operation. The result object is a
+ /// clone of one of the input objects (
+ /// if it is not ) containing the elements from
+ /// the intersect operation.
+ ///
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// The intersection of the two input sets; if
+ /// both sets are .
+ ///
+ public static ISet Intersect(ISet setOne, ISet anotherSet)
+ {
+ if (setOne == null && anotherSet == null)
+ {
+ return null;
+ }
+ else if (setOne == null)
+ {
+ return anotherSet.Intersect(setOne);
+ }
+ else
+ {
+ return setOne.Intersect(anotherSet);
+ }
+ }
+
+ ///
+ /// Performs an "intersection" of the two sets, where only the elements
+ /// that are present in both sets remain.
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// The intersection of the two input sets; if
+ /// both sets are .
+ ///
+ ///
+ public static Set operator &(Set setOne, Set anotherSet)
+ {
+ return (Set) Intersect(setOne, anotherSet);
+ }
+
+ ///
+ /// Performs a "minus" of this set from the
+ /// set.
+ ///
+ /// A set of elements.
+ ///
+ /// A set containing the elements from this set with the elements in
+ /// removed.
+ ///
+ ///
+ public virtual ISet Minus(ISet setOne)
+ {
+ ISet resultSet = (ISet) this.Clone();
+ if (setOne != null)
+ {
+ resultSet.RemoveAll(setOne);
+ }
+ return resultSet;
+ }
+
+ ///
+ /// Performs a "minus" of set from set
+ /// .
+ ///
+ ///
+ ///
+ /// This returns a set of all the elements in set
+ /// , removing the elements that are also in
+ /// set . The original sets are not modified
+ /// during this operation. The result set is a clone of set
+ /// containing the elements from the operation.
+ ///
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing
+ /// - elements.
+ /// if is
+ /// .
+ ///
+ public static ISet Minus(ISet setOne, ISet anotherSet)
+ {
+ if (setOne == null)
+ {
+ return null;
+ }
+ else
+ {
+ return setOne.Minus(anotherSet);
+ }
+ }
+
+ ///
+ /// Performs a "minus" of set from set
+ /// .
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing
+ /// - elements.
+ /// if is
+ /// .
+ ///
+ ///
+ public static Set operator -(Set setOne, Set anotherSet)
+ {
+ return (Set) Minus(setOne, anotherSet);
+ }
+
+
+ ///
+ /// Performs an "exclusive-or" of the two sets, keeping only those
+ /// elements that are in one of the sets, but not in both.
+ ///
+ /// A set of elements.
+ ///
+ /// A set containing the result of
+ /// ^ this.
+ ///
+ ///
+ public virtual ISet ExclusiveOr(ISet setOne)
+ {
+ ISet resultSet = (ISet) this.Clone();
+ foreach (object element in setOne)
+ {
+ if (resultSet.Contains(element))
+ {
+ resultSet.Remove(element);
+ }
+ else
+ {
+ resultSet.Add(element);
+ }
+ }
+ return resultSet;
+ }
+
+ ///
+ /// Performs an "exclusive-or" of the two sets, keeping only those
+ /// elements that are in one of the sets, but not in both.
+ ///
+ ///
+ ///
+ /// The original sets are not modified during this operation. The
+ /// result set is a clone of one of the sets (
+ /// if it is not )
+ /// containing the elements from the exclusive-or operation.
+ ///
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing the result of
+ /// ^ .
+ /// if both sets are .
+ ///
+ public static ISet ExclusiveOr(ISet setOne, ISet anotherSet)
+ {
+ if (setOne == null && anotherSet == null)
+ {
+ return null;
+ }
+ else if (setOne == null)
+ {
+ return (Set) anotherSet.Clone();
+ }
+ else if (anotherSet == null)
+ {
+ return (Set) setOne.Clone();
+ }
+ else
+ {
+ return setOne.ExclusiveOr(anotherSet);
+ }
+ }
+
+ ///
+ /// Performs an "exclusive-or" of the two sets, keeping only those
+ /// elements that are in one of the sets, but not in both.
+ ///
+ /// A set of elements.
+ /// A set of elements.
+ ///
+ /// A set containing the result of
+ /// ^ .
+ /// if both sets are .
+ ///
+ ///
+ public static Set operator ^(Set setOne, Set anotherSet)
+ {
+ return (Set) ExclusiveOr(setOne, anotherSet);
+ }
+
+ ///
+ /// Adds the specified element to this set if it is not already present.
+ ///
+ /// The object to add to the set.
+ ///
+ /// is the object was added,
+ /// if the object was already present.
+ ///
+ public abstract bool Add(object element);
+
+ ///
+ /// Adds all the elements in the specified collection to the set if
+ /// they are not already present.
+ ///
+ /// A collection of objects to add to the set.
+ ///
+ /// is the set changed as a result of this
+ /// operation.
+ ///
+ public abstract bool AddAll(ICollection collection);
+
+ ///
+ /// Removes all objects from this set.
+ ///
+ public abstract void Clear();
+
+ ///
+ /// Returns if this set contains the specified
+ /// element.
+ ///
+ /// The element to look for.
+ ///
+ /// if this set contains the specified element.
+ ///
+ public abstract bool Contains(object element);
+
+ ///
+ /// Returns if the set contains all the
+ /// elements in the specified collection.
+ ///
+ /// A collection of objects.
+ ///
+ /// if the set contains all the elements in the
+ /// specified collection.
+ ///
+ public abstract bool ContainsAll(ICollection collection);
+
+ ///
+ /// Returns if this set contains no elements.
+ ///
+ public abstract bool IsEmpty { get; }
+
+ ///
+ /// Removes the specified element from the set.
+ ///
+ /// The element to be removed.
+ ///
+ /// if the set contained the specified element.
+ ///
+ public abstract bool Remove(object element);
+
+ ///
+ /// Remove all the specified elements from this set, if they exist in
+ /// this set.
+ ///
+ /// A collection of elements to remove.
+ ///
+ /// if the set was modified as a result of this
+ /// operation.
+ ///
+ public abstract bool RemoveAll(ICollection collection);
+
+ ///
+ /// Retains only the elements in this set that are contained in the
+ /// specified collection.
+ ///
+ ///
+ /// The collection that defines the set of elements to be retained.
+ ///
+ ///
+ /// if this set changed as a result of this
+ /// operation.
+ ///
+ public abstract bool RetainAll(ICollection collection);
+
+ ///
+ /// Returns a clone of the
+ /// instance.
+ ///
+ ///
+ ///
+ /// This will work for derived
+ /// classes if the derived class implements a constructor that takes no
+ /// arguments.
+ ///
+ ///
+ /// A clone of this object.
+ public virtual object Clone()
+ {
+ Set newSet = (Set) Activator.CreateInstance(this.GetType());
+ newSet.AddAll(this);
+ return newSet;
+ }
+
+ ///
+ /// Copies the elements in the to
+ /// an array.
+ ///
+ ///
+ ///
+ /// The type of array needs to be compatible with the objects in the
+ /// , obviously.
+ ///
+ ///
+ ///
+ /// An array that will be the target of the copy operation.
+ ///
+ ///
+ /// The zero-based index where copying will start.
+ ///
+ public abstract void CopyTo(Array array, int index);
+
+ ///
+ /// The number of elements currently contained in this collection.
+ ///
+ public abstract int Count { get; }
+
+ ///
+ /// Returns if the
+ /// is synchronized across
+ /// threads.
+ ///
+ ///
+ ///
+ /// Note that enumeration is inherently not thread-safe. Use the
+ /// to lock the object during enumeration.
+ ///
+ ///
+ public abstract bool IsSynchronized { get; }
+
+ ///
+ /// An object that can be used to synchronize this collection to make
+ /// it thread-safe.
+ ///
+ ///
+ ///
+ /// When implementing this, if your object uses a base object, like an
+ /// , or anything that has
+ /// a SyncRoot, return that object instead of "this".
+ ///
+ ///
+ ///
+ /// An object that can be used to synchronize this collection to make
+ /// it thread-safe.
+ ///
+ public abstract object SyncRoot { get; }
+
+ ///
+ /// Gets an enumerator for the elements in the
+ /// .
+ ///
+ ///
+ /// An over the elements
+ /// in the .
+ ///
+ public abstract IEnumerator GetEnumerator();
+
+ ///
+ /// This method will test the
+ /// against another for
+ /// "equality".
+ ///
+ ///
+ ///
+ /// In this case, "equality" means that the two sets contain the same
+ /// elements. The "==" and "!=" operators are not overridden by design.
+ /// If you wish to check for "equivalent"
+ /// instances, use
+ /// Equals(). If you wish to check to see if two references are
+ /// actually the same object, use "==" and "!=".
+ ///
- /// This gives good performance for operations on very large data-sets,
- /// though not as good - asymptotically - as a
- /// . However, iteration occurs
- /// in order.
- ///
- ///
- /// Elements that you put into this type of collection must implement
- /// , and they must actually be comparable.
- /// You can't mix and
- /// values, for example.
- ///
- ///
- /// This implementation does
- /// not support elements that are .
- ///
+ /// This gives good performance for operations on very large data-sets,
+ /// though not as good - asymptotically - as a
+ /// . However, iteration occurs
+ /// in order.
+ ///
+ ///
+ /// Elements that you put into this type of collection must implement
+ /// , and they must actually be comparable.
+ /// You can't mix and
+ /// values, for example.
+ ///
+ ///
+ /// This implementation does
+ /// not support elements that are .
+ ///
+ ///
+ ///
+ [Serializable]
+ public class SortedSet : DictionarySet
+ {
+ ///
+ /// Creates a new set instance based on a sorted tree.
+ ///
+ public SortedSet()
+ {
+ InternalDictionary = new SortedList();
+ }
+
+ ///
+ /// Creates a new set instance based on a sorted tree and initializes
+ /// it based on a collection of elements.
+ ///
+ ///
+ /// A collection of elements that defines the initial set contents.
+ ///
+ public SortedSet(ICollection initialValues) : this()
+ {
+ this.AddAll(initialValues);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs b/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs
index f6061e71..11a62b09 100644
--- a/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs
+++ b/src/Spring/Spring.Core/Collections/SynchronizedDictionaryEnumerator.cs
@@ -1,76 +1,75 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System.Collections;
-
-namespace Spring.Collections
-{
- ///
- /// Synchronized that should be returned by synchronized
- /// dictionary implementations in order to ensure that the enumeration is thread safe.
- ///
- /// Aleksandar Seovic
- /// $Id: SynchronizedDictionaryEnumerator.cs,v 1.1 2006/05/03 01:13:41 aseovic Exp $
- internal class SynchronizedDictionaryEnumerator : SynchronizedEnumerator, IDictionaryEnumerator
- {
- public SynchronizedDictionaryEnumerator(object syncRoot, IDictionaryEnumerator enumerator)
- : base(syncRoot, enumerator)
- {
- }
-
- protected IDictionaryEnumerator Enumerator
- {
- get { return (IDictionaryEnumerator) enumerator; }
- }
-
- public object Key
- {
- get
- {
- lock (syncRoot)
- {
- return Enumerator.Key;
- }
- }
- }
-
- public object Value
- {
- get
- {
- lock (syncRoot)
- {
- return Enumerator.Value;
- }
- }
- }
-
- public DictionaryEntry Entry
- {
- get
- {
- lock (syncRoot)
- {
- return Enumerator.Entry;
- }
- }
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System.Collections;
+
+namespace Spring.Collections
+{
+ ///
+ /// Synchronized that should be returned by synchronized
+ /// dictionary implementations in order to ensure that the enumeration is thread safe.
+ ///
+ /// Aleksandar Seovic
+ internal class SynchronizedDictionaryEnumerator : SynchronizedEnumerator, IDictionaryEnumerator
+ {
+ public SynchronizedDictionaryEnumerator(object syncRoot, IDictionaryEnumerator enumerator)
+ : base(syncRoot, enumerator)
+ {
+ }
+
+ protected IDictionaryEnumerator Enumerator
+ {
+ get { return (IDictionaryEnumerator) enumerator; }
+ }
+
+ public object Key
+ {
+ get
+ {
+ lock (syncRoot)
+ {
+ return Enumerator.Key;
+ }
+ }
+ }
+
+ public object Value
+ {
+ get
+ {
+ lock (syncRoot)
+ {
+ return Enumerator.Value;
+ }
+ }
+ }
+
+ public DictionaryEntry Entry
+ {
+ get
+ {
+ lock (syncRoot)
+ {
+ return Enumerator.Entry;
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs b/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs
index 5060853b..e62be05f 100644
--- a/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs
+++ b/src/Spring/Spring.Core/Collections/SynchronizedEnumerator.cs
@@ -1,69 +1,68 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System.Collections;
-
-namespace Spring.Collections
-{
- ///
- /// Synchronized that should be returned by synchronized
- /// collections in order to ensure that the enumeration is thread safe.
- ///
- /// Aleksandar Seovic
- /// $Id: SynchronizedEnumerator.cs,v 1.1 2006/05/03 01:13:41 aseovic Exp $
- internal class SynchronizedEnumerator : IEnumerator
- {
- protected object syncRoot;
- protected IEnumerator enumerator;
-
- public SynchronizedEnumerator(object syncRoot, IEnumerator enumerator)
- {
- this.syncRoot = syncRoot;
- this.enumerator = enumerator;
- }
-
- public bool MoveNext()
- {
- lock (syncRoot)
- {
- return enumerator.MoveNext();
- }
- }
-
- public void Reset()
- {
- lock (syncRoot)
- {
- enumerator.Reset();
- }
- }
-
- public object Current
- {
- get
- {
- lock (syncRoot)
- {
- return enumerator.Current;
- }
- }
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System.Collections;
+
+namespace Spring.Collections
+{
+ ///
+ /// Synchronized that should be returned by synchronized
+ /// collections in order to ensure that the enumeration is thread safe.
+ ///
+ /// Aleksandar Seovic
+ internal class SynchronizedEnumerator : IEnumerator
+ {
+ protected object syncRoot;
+ protected IEnumerator enumerator;
+
+ public SynchronizedEnumerator(object syncRoot, IEnumerator enumerator)
+ {
+ this.syncRoot = syncRoot;
+ this.enumerator = enumerator;
+ }
+
+ public bool MoveNext()
+ {
+ lock (syncRoot)
+ {
+ return enumerator.MoveNext();
+ }
+ }
+
+ public void Reset()
+ {
+ lock (syncRoot)
+ {
+ enumerator.Reset();
+ }
+ }
+
+ public object Current
+ {
+ get
+ {
+ lock (syncRoot)
+ {
+ return enumerator.Current;
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs
index 4b754c36..c8ba2cc8 100644
--- a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs
+++ b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs
@@ -1,367 +1,366 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-using Spring.Util;
-
-namespace Spring.Collections
-{
- ///
- /// Synchronized that, unlike hashtable created
- /// using method, synchronizes
- /// reads from the underlying hashtable in addition to writes.
- ///
- ///
- ///
- /// In addition to synchronizing reads, this implementation also fixes
- /// IEnumerator/ICollection issue described at
- /// http://msdn.microsoft.com/netframework/programming/breakingchanges/runtime/clr.aspx
- /// (search for SynchronizedHashtable for issue description), by implementing
- /// interface explicitly, and returns thread safe enumerator
- /// implementations as well.
- ///
- ///
- /// This class should be used whenever a truly synchronized
- /// is needed.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: SynchronizedHashtable.cs,v 1.2 2007/08/27 13:57:17 oakinger Exp $
- [Serializable]
- public class SynchronizedHashtable : IDictionary, ICollection, IEnumerable, ICloneable
- {
- private readonly Hashtable _table;
-
- #region Constructors
-
- ///
- /// Initializes a new instance of
- ///
- public SynchronizedHashtable()
- {
- this._table = new Hashtable();
- }
-
- ///
- /// Initializes a new instance of , copying inital entries from .
- ///
- public SynchronizedHashtable(IDictionary dictionary)
- {
- AssertUtils.ArgumentNotNull(dictionary, "dictionary");
- this._table = new Hashtable(dictionary);
- }
-
- #endregion
-
- #region Properties
-
- ///
- ///Gets a value indicating whether the object is read-only.
- ///
- ///
- ///true if the object is read-only; otherwise, false.
- ///
- public bool IsReadOnly
- {
- get
- {
- lock (SyncRoot)
- {
- return _table.IsReadOnly;
- }
- }
- }
-
- ///
- ///Gets a value indicating whether the object has a fixed size.
- ///
- ///
- ///true if the object has a fixed size; otherwise, false.
- ///
- public bool IsFixedSize
- {
- get
- {
- lock (SyncRoot)
- {
- return _table.IsFixedSize;
- }
- }
- }
-
- ///
- ///Gets a value indicating whether access to the is synchronized (thread safe).
- ///
- ///
- ///true if access to the is synchronized (thread safe); otherwise, false.
- ///
- public bool IsSynchronized
- {
- get { return true; }
- }
-
- ///
- ///Gets an object containing the keys of the object.
- ///
- ///
- ///An object containing the keys of the object.
- ///
- public ICollection Keys
- {
- get
- {
- lock (SyncRoot)
- {
- return _table.Keys;
- }
- }
- }
-
- ///
- ///Gets an object containing the values in the object.
- ///
- ///
- ///An object containing the values in the object.
- ///
- public ICollection Values
- {
- get
- {
- lock (SyncRoot)
- {
- return _table.Values;
- }
- }
- }
-
- ///
- ///Gets an object that can be used to synchronize access to the .
- ///
- ///
- ///An object that can be used to synchronize access to the .
- ///
- public object SyncRoot
- {
- get { return _table.SyncRoot; }
- }
-
- ///
- ///Gets the number of elements contained in the .
- ///
- ///
- ///The number of elements contained in the .
- ///
- public int Count
- {
- get
- {
- lock (SyncRoot)
- {
- return _table.Count;
- }
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- ///Adds an element with the provided key and value to the object.
- ///
- ///The to use as the value of the element to add.
- ///The to use as the key of the element to add.
- ///An element with the same key already exists in the object.
- ///key is null.
- ///The is read-only.-or- The has a fixed size. 2
- public void Add(object key, object value)
- {
- lock (SyncRoot)
- {
- _table.Add(key, value);
- }
- }
-
- ///
- ///Removes all elements from the object.
- ///
- ///The object is read-only. 2
- public void Clear()
- {
- lock (SyncRoot)
- {
- _table.Clear();
- }
- }
-
- ///
- ///Creates a new object that is a copy of the current instance.
- ///
- ///
- ///A new object that is a copy of this instance.
- ///
- public object Clone()
- {
- lock (SyncRoot)
- {
- return new SynchronizedHashtable(this);
- }
- }
-
- ///
- ///Determines whether the object contains an element with the specified key.
- ///
- ///
- ///true if the contains an element with the key; otherwise, false.
- ///
- ///The key to locate in the object.
- ///key is null. 2
- public bool Contains(object key)
- {
- lock (SyncRoot)
- {
- return _table.Contains(key);
- }
- }
-
- ///
- /// Returns, whether this contains an entry with the specified .
- ///
- ///The key to look for
- ///, if this contains an entry with this
- public bool ContainsKey(object key)
- {
- lock (SyncRoot)
- {
- return _table.ContainsKey(key);
- }
- }
-
- ///
- /// Returns, whether this contains an entry with the specified .
- ///
- ///The valúe to look for
- ///, if this contains an entry with this
- public bool ContainsValue(object value)
- {
- lock (SyncRoot)
- {
- return _table.ContainsValue(value);
- }
- }
-
- ///
- ///Copies the elements of the to an , starting at a particular index.
- ///
- ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing.
- ///The zero-based index in array at which copying begins.
- ///array is null.
- ///The type of the source cannot be cast automatically to the type of the destination array.
- ///index is less than zero.
- ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. 2
- public void CopyTo(Array array, int index)
- {
- lock (SyncRoot)
- {
- _table.CopyTo(array, index);
- }
- }
-
- ///
- ///Returns an object for the object.
- ///
- ///
- ///An object for the object.
- ///
- public IDictionaryEnumerator GetEnumerator()
- {
- lock (SyncRoot)
- {
- return new SynchronizedDictionaryEnumerator(SyncRoot, _table.GetEnumerator());
- }
- }
-
- ///
- ///Removes the element with the specified key from the object.
- ///
- ///The key of the element to remove.
- ///The object is read-only.-or- The has a fixed size.
- ///key is null. 2
- public void Remove(object key)
- {
- lock (SyncRoot)
- {
- _table.Remove(key);
- }
- }
-
- #endregion
-
- #region IEnumerable implementation
-
- ///
- ///Returns an enumerator that iterates through a collection.
- ///
- ///
- ///An object that can be used to iterate through the collection.
- ///
- IEnumerator IEnumerable.GetEnumerator()
- {
- lock (SyncRoot)
- {
- return new SynchronizedEnumerator(SyncRoot, ((IEnumerable) _table).GetEnumerator());
- }
- }
-
- #endregion
-
- #region Indexer
-
- ///
- ///Gets or sets the element with the specified key.
- ///
- ///
- ///The element with the specified key.
- ///
- ///The key of the element to get or set.
- ///The property is set and the object is read-only.-or- The property is set, key does not exist in the collection, and the has a fixed size.
- ///key is null. 2
- public object this[object key]
- {
- get
- {
- lock (SyncRoot)
- {
- return _table[key];
- }
- }
- set
- {
- lock (SyncRoot)
- {
- _table[key] = value;
- }
- }
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using Spring.Util;
+
+namespace Spring.Collections
+{
+ ///
+ /// Synchronized that, unlike hashtable created
+ /// using method, synchronizes
+ /// reads from the underlying hashtable in addition to writes.
+ ///
+ ///
+ ///
+ /// In addition to synchronizing reads, this implementation also fixes
+ /// IEnumerator/ICollection issue described at
+ /// http://msdn.microsoft.com/en-us/netframework/aa570326.aspx
+ /// (search for SynchronizedHashtable for issue description), by implementing
+ /// interface explicitly, and returns thread safe enumerator
+ /// implementations as well.
+ ///
+ ///
+ /// This class should be used whenever a truly synchronized
+ /// is needed.
+ ///
- /// The implementation is extremely conservative, serializing critical
- /// sections to prevent possible deadlocks, and locking on everything. The
- /// one exception is for enumeration, which is inherently not thread-safe.
- /// For this, you have to lock the SyncRoot object for the
- /// duration of the enumeration.
- ///
- ///
- ///
- /// $Id: SynchronizedSet.cs,v 1.6 2007/03/16 04:01:29 aseovic Exp $
- [Serializable]
- public sealed class SynchronizedSet : Set
- {
- private ISet _mBasisSet;
- private object _mSyncRoot;
-
- ///
- /// Constructs a thread-safe
- /// wrapper.
- ///
- ///
- /// The object that this object
- /// will wrap.
- ///
- ///
- /// If the supplied ecposes a
- /// SyncRoot value.
- ///
- public SynchronizedSet(ISet basisSet)
- {
- _mBasisSet = basisSet;
- _mSyncRoot = basisSet.SyncRoot;
- if (_mSyncRoot == null)
- {
- throw new NullReferenceException(
- "The Set you specified returned a null SyncRoot.");
- }
- }
-
- ///
- /// Adds the specified element to this set if it is not already present.
- ///
- /// The object to add to the set.
- ///
- /// is the object was added,
- /// if the object was already present.
- ///
- public override sealed bool Add(object element)
- {
- lock (_mSyncRoot)
- {
- return _mBasisSet.Add(element);
- }
- }
-
- ///
- /// Adds all the elements in the specified collection to the set if
- /// they are not already present.
- ///
- /// A collection of objects to add to the set.
- ///
- /// is the set changed as a result of this
- /// operation.
- ///
- public override sealed bool AddAll(ICollection collection)
- {
- if(collection == null)
- {
- return false;
- }
- Set temp;
- lock (collection.SyncRoot)
- {
- temp = new HybridSet(collection);
- }
- lock (_mSyncRoot)
- {
- return _mBasisSet.AddAll(temp);
- }
- }
-
- ///
- /// Removes all objects from this set.
- ///
- public override sealed void Clear()
- {
- lock (_mSyncRoot)
- {
- _mBasisSet.Clear();
- }
- }
-
- ///
- /// Returns if this set contains the specified
- /// element.
- ///
- /// The element to look for.
- ///
- /// if this set contains the specified element.
- ///
- public override sealed bool Contains(object element)
- {
- lock (_mSyncRoot)
- {
- return _mBasisSet.Contains(element);
- }
- }
-
- ///
- /// Returns if the set contains all the
- /// elements in the specified collection.
- ///
- /// A collection of objects.
- ///
- /// if the set contains all the elements in the
- /// specified collection; also if the
- /// supplied is .
- ///
- public override sealed bool ContainsAll(ICollection collection)
- {
- if(collection == null)
- {
- return false;
- }
- Set temp;
- lock (collection.SyncRoot)
- {
- temp = new HybridSet(collection);
- }
- lock (_mSyncRoot)
- {
- return _mBasisSet.ContainsAll(temp);
- }
- }
-
- ///
- /// Returns if this set contains no elements.
- ///
- public override sealed bool IsEmpty
- {
- get
- {
- lock (_mSyncRoot)
- {
- return _mBasisSet.IsEmpty;
- }
- }
- }
-
- ///
- /// Removes the specified element from the set.
- ///
- /// The element to be removed.
- ///
- /// if the set contained the specified element.
- ///
- public override sealed bool Remove(object element)
- {
- lock (_mSyncRoot)
- {
- return _mBasisSet.Remove(element);
- }
- }
-
- ///
- /// Remove all the specified elements from this set, if they exist in
- /// this set.
- ///
- /// A collection of elements to remove.
- ///
- /// if the set was modified as a result of this
- /// operation.
- ///
- public override sealed bool RemoveAll(ICollection collection)
- {
- Set temp;
- lock (collection.SyncRoot)
- {
- temp = new HybridSet(collection);
- }
- lock (_mSyncRoot)
- {
- return _mBasisSet.RemoveAll(temp);
- }
- }
-
- ///
- /// Retains only the elements in this set that are contained in the
- /// specified collection.
- ///
- ///
- /// The collection that defines the set of elements to be retained.
- ///
- ///
- /// if this set changed as a result of this
- /// operation.
- ///
- public override sealed bool RetainAll(ICollection c)
- {
- Set temp;
- lock (c.SyncRoot)
- {
- temp = new HybridSet(c);
- }
- lock (_mSyncRoot)
- {
- return _mBasisSet.RetainAll(temp);
- }
- }
-
- ///
- /// Copies the elements in the to
- /// an array.
- ///
- ///
- ///
- /// The type of array needs to be compatible with the objects in the
- /// , obviously.
- ///
+ /// The implementation is extremely conservative, serializing critical
+ /// sections to prevent possible deadlocks, and locking on everything. The
+ /// one exception is for enumeration, which is inherently not thread-safe.
+ /// For this, you have to lock the SyncRoot object for the
+ /// duration of the enumeration.
+ ///
+ ///
+ ///
+ [Serializable]
+ public sealed class SynchronizedSet : Set
+ {
+ private ISet _mBasisSet;
+ private object _mSyncRoot;
+
+ ///
+ /// Constructs a thread-safe
+ /// wrapper.
+ ///
+ ///
+ /// The object that this object
+ /// will wrap.
+ ///
+ ///
+ /// If the supplied ecposes a
+ /// SyncRoot value.
+ ///
+ public SynchronizedSet(ISet basisSet)
+ {
+ _mBasisSet = basisSet;
+ _mSyncRoot = basisSet.SyncRoot;
+ if (_mSyncRoot == null)
+ {
+ throw new NullReferenceException(
+ "The Set you specified returned a null SyncRoot.");
+ }
+ }
+
+ ///
+ /// Adds the specified element to this set if it is not already present.
+ ///
+ /// The object to add to the set.
+ ///
+ /// is the object was added,
+ /// if the object was already present.
+ ///
+ public override sealed bool Add(object element)
+ {
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.Add(element);
+ }
+ }
+
+ ///
+ /// Adds all the elements in the specified collection to the set if
+ /// they are not already present.
+ ///
+ /// A collection of objects to add to the set.
+ ///
+ /// is the set changed as a result of this
+ /// operation.
+ ///
+ public override sealed bool AddAll(ICollection collection)
+ {
+ if(collection == null)
+ {
+ return false;
+ }
+ Set temp;
+ lock (collection.SyncRoot)
+ {
+ temp = new HybridSet(collection);
+ }
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.AddAll(temp);
+ }
+ }
+
+ ///
+ /// Removes all objects from this set.
+ ///
+ public override sealed void Clear()
+ {
+ lock (_mSyncRoot)
+ {
+ _mBasisSet.Clear();
+ }
+ }
+
+ ///
+ /// Returns if this set contains the specified
+ /// element.
+ ///
+ /// The element to look for.
+ ///
+ /// if this set contains the specified element.
+ ///
+ public override sealed bool Contains(object element)
+ {
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.Contains(element);
+ }
+ }
+
+ ///
+ /// Returns if the set contains all the
+ /// elements in the specified collection.
+ ///
+ /// A collection of objects.
+ ///
+ /// if the set contains all the elements in the
+ /// specified collection; also if the
+ /// supplied is .
+ ///
+ public override sealed bool ContainsAll(ICollection collection)
+ {
+ if(collection == null)
+ {
+ return false;
+ }
+ Set temp;
+ lock (collection.SyncRoot)
+ {
+ temp = new HybridSet(collection);
+ }
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.ContainsAll(temp);
+ }
+ }
+
+ ///
+ /// Returns if this set contains no elements.
+ ///
+ public override sealed bool IsEmpty
+ {
+ get
+ {
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.IsEmpty;
+ }
+ }
+ }
+
+ ///
+ /// Removes the specified element from the set.
+ ///
+ /// The element to be removed.
+ ///
+ /// if the set contained the specified element.
+ ///
+ public override sealed bool Remove(object element)
+ {
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.Remove(element);
+ }
+ }
+
+ ///
+ /// Remove all the specified elements from this set, if they exist in
+ /// this set.
+ ///
+ /// A collection of elements to remove.
+ ///
+ /// if the set was modified as a result of this
+ /// operation.
+ ///
+ public override sealed bool RemoveAll(ICollection collection)
+ {
+ Set temp;
+ lock (collection.SyncRoot)
+ {
+ temp = new HybridSet(collection);
+ }
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.RemoveAll(temp);
+ }
+ }
+
+ ///
+ /// Retains only the elements in this set that are contained in the
+ /// specified collection.
+ ///
+ ///
+ /// The collection that defines the set of elements to be retained.
+ ///
+ ///
+ /// if this set changed as a result of this
+ /// operation.
+ ///
+ public override sealed bool RetainAll(ICollection c)
+ {
+ Set temp;
+ lock (c.SyncRoot)
+ {
+ temp = new HybridSet(c);
+ }
+ lock (_mSyncRoot)
+ {
+ return _mBasisSet.RetainAll(temp);
+ }
+ }
+
+ ///
+ /// Copies the elements in the to
+ /// an array.
+ ///
+ ///
+ ///
+ /// The type of array needs to be compatible with the objects in the
+ /// , obviously.
+ ///
- /// implementations
- /// provide:
- ///
- ///
- ///
- /// Object factory functionality inherited from the
- ///
- /// and
- /// interfaces.
- ///
- ///
- ///
- ///
- /// The ability to resolve messages, supporting internationalization.
- /// Inherited from the
- /// interface.
- ///
- ///
- ///
- ///
- /// The ability to load file resources in a generic fashion.
- /// Inherited from the
- /// interface.
- ///
- ///
- ///
- ///
- /// Acts an an event registry for supporting loosely coupled eventing
- /// between objecs. Inherited from the
- /// interface.
- ///
- ///
- ///
- ///
- /// The ability to raise events related to the context lifecycle. Inherited
- /// from the
- /// interface.
- ///
- ///
- ///
- ///
- /// Inheritance from a parent context. Definitions in a descendant context
- /// will always take priority.
- ///
- ///
- ///
- ///
- ///
- /// In addition to standard object factory lifecycle capabilities,
- /// implementations need
- /// to detect
- /// ,
- /// , and
- /// objects and supply
- /// their attendant dependencies accordingly.
- ///
- ///
- /// This interface is the central client interface in Spring.NET's IoC
- /// container implementation. As such it does inherit a quite sizeable
- /// number of interfaces; implementations are strongly encouraged to use
- /// composition to satisfy each of the inherited interfaces (where
- /// appropriate of course).
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- ///
- ///
- ///
- ///
- /// $Id: IApplicationContext.cs,v 1.15 2007/08/08 17:46:37 bbaia Exp $
- public interface IApplicationContext
- : IListableObjectFactory, IHierarchicalObjectFactory, IMessageSource,
- IApplicationEventPublisher, IResourceLoader, IEventRegistry, IDisposable
- {
- ///
- /// Raised in response to an application context event.
- ///
- event ApplicationEventHandler ContextEvent;
-
- ///
- /// Returns the date and time this context was loaded.
- ///
- ///
- ///
- /// This is to be set immediately after an
- /// has been
- /// instantiated and its configuration has been loaded. Implementations
- /// are permitted to update this value if the context is reset or
- /// refreshed in some way.
- ///
- ///
- ///
- /// The representing when this context
- /// was loaded.
- ///
- ///
- DateTime StartupDate { get; }
-
- ///
- /// Gets the parent context, or if there is no
- /// parent context.
- ///
- ///
- ///
- /// If the parent context is , then this context
- /// is the root of any context hierarchy.
- ///
+ /// implementations
+ /// provide:
+ ///
+ ///
+ ///
+ /// Object factory functionality inherited from the
+ ///
+ /// and
+ /// interfaces.
+ ///
+ ///
+ ///
+ ///
+ /// The ability to resolve messages, supporting internationalization.
+ /// Inherited from the
+ /// interface.
+ ///
+ ///
+ ///
+ ///
+ /// The ability to load file resources in a generic fashion.
+ /// Inherited from the
+ /// interface.
+ ///
+ ///
+ ///
+ ///
+ /// Acts an an event registry for supporting loosely coupled eventing
+ /// between objecs. Inherited from the
+ /// interface.
+ ///
+ ///
+ ///
+ ///
+ /// The ability to raise events related to the context lifecycle. Inherited
+ /// from the
+ /// interface.
+ ///
+ ///
+ ///
+ ///
+ /// Inheritance from a parent context. Definitions in a descendant context
+ /// will always take priority.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// In addition to standard object factory lifecycle capabilities,
+ /// implementations need
+ /// to detect
+ /// ,
+ /// , and
+ /// objects and supply
+ /// their attendant dependencies accordingly.
+ ///
+ ///
+ /// This interface is the central client interface in Spring.NET's IoC
+ /// container implementation. As such it does inherit a quite sizeable
+ /// number of interfaces; implementations are strongly encouraged to use
+ /// composition to satisfy each of the inherited interfaces (where
+ /// appropriate of course).
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ ///
+ ///
+ public interface IApplicationContext
+ : IListableObjectFactory, IHierarchicalObjectFactory, IMessageSource,
+ IApplicationEventPublisher, IResourceLoader, IEventRegistry, IDisposable
+ {
+ ///
+ /// Raised in response to an application context event.
+ ///
+ event ApplicationEventHandler ContextEvent;
+
+ ///
+ /// Returns the date and time this context was loaded.
+ ///
+ ///
+ ///
+ /// This is to be set immediately after an
+ /// has been
+ /// instantiated and its configuration has been loaded. Implementations
+ /// are permitted to update this value if the context is reset or
+ /// refreshed in some way.
+ ///
+ ///
+ ///
+ /// The representing when this context
+ /// was loaded.
+ ///
+ ///
+ DateTime StartupDate { get; }
+
+ ///
+ /// Gets the parent context, or if there is no
+ /// parent context.
+ ///
+ ///
+ ///
+ /// If the parent context is , then this context
+ /// is the root of any context hierarchy.
+ ///
- /// Implementing this interface makes sense when an object requires access
- /// to a set of collaborating objects. Note that configuration via object
- /// references is preferable to implementing this interface just for object
- /// lookup purposes.
- ///
- ///
- /// This interface can also be implemented if an object needs access to
- /// file resources, i.e. wants to call
- /// , or access to
- /// the . However, it is
- /// preferable to implement the more specific
- ///
- /// interface to receive a reference to the
- /// object in that scenario.
- ///
- ///
- /// Note that dependencies can also
- /// be exposed as object properties of the
- /// type, populated via strings with
- /// automatic type conversion performed by an object factory. This obviates
- /// the need for implementing any callback interface just for the purpose
- /// of accessing a specific file resource.
- ///
- ///
- ///
- /// is a convenience implementation of this interface for your
- /// application objects.
- ///
- ///
- /// For a list of all object lifecycle methods, see the overview for the
- /// interface.
- ///
- ///
- /// Rod Johnson
- /// Mark Pollack (.NET)
- /// $Id: IApplicationContextAware.cs,v 1.8 2007/08/08 17:46:37 bbaia Exp $
- ///
- ///
- ///
- /// $Id: IApplicationContextAware.cs,v 1.8 2007/08/08 17:46:37 bbaia Exp $
- public interface IApplicationContextAware
- {
- ///
- /// Set the that this
- /// object runs in.
- ///
- ///
- ///
- /// Normally this call will be used to initialize the object.
- ///
- ///
- /// Invoked after population of normal object properties but before an
- /// init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked after the setting of any
- /// 's
- ///
- /// property.
- ///
+ /// Implementing this interface makes sense when an object requires access
+ /// to a set of collaborating objects. Note that configuration via object
+ /// references is preferable to implementing this interface just for object
+ /// lookup purposes.
+ ///
+ ///
+ /// This interface can also be implemented if an object needs access to
+ /// file resources, i.e. wants to call
+ /// , or access to
+ /// the . However, it is
+ /// preferable to implement the more specific
+ ///
+ /// interface to receive a reference to the
+ /// object in that scenario.
+ ///
+ ///
+ /// Note that dependencies can also
+ /// be exposed as object properties of the
+ /// type, populated via strings with
+ /// automatic type conversion performed by an object factory. This obviates
+ /// the need for implementing any callback interface just for the purpose
+ /// of accessing a specific file resource.
+ ///
+ ///
+ ///
+ /// is a convenience implementation of this interface for your
+ /// application objects.
+ ///
+ ///
+ /// For a list of all object lifecycle methods, see the overview for the
+ /// interface.
+ ///
+ ///
+ /// Rod Johnson
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ ///
+ public interface IApplicationContextAware
+ {
+ ///
+ /// Set the that this
+ /// object runs in.
+ ///
+ ///
+ ///
+ /// Normally this call will be used to initialize the object.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an
+ /// init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked after the setting of any
+ /// 's
+ ///
+ /// property.
+ ///
- /// This interface is to be implemented by most (if not all)
- /// implementations.
- ///
- ///
- /// Configuration and lifecycle methods are encapsulated here to avoid
- /// making them obvious to
- /// client code.
- ///
- ///
- /// Calling will close this
- /// application context, releasing all resources and locks that the
- /// implementation might hold. This includes disposing all cached
- /// singleton objects.
- ///
- ///
- /// does not invoke the
- /// attendant on any parent
- /// context.
- ///
- ///
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: IConfigurableApplicationContext.cs,v 1.10 2006/04/09 07:18:38 markpollack Exp $
- ///
- ///
- public interface IConfigurableApplicationContext : IApplicationContext
- {
- ///
- /// Return the internal object factory of this application context.
- ///
- ///
- ///
- /// Can be used to access specific functionality of the factory.
- ///
- ///
- /// This is just guaranteed to return an instance that is not
- /// after the context has been refreshed
- /// at least once.
- ///
- ///
- /// Do not use this to post-process the object factory; singletons
- /// will already have been instantiated. Use an
- ///
- /// to intercept the object factory setup process before objects even
- /// get touched.
- ///
- ///
- ///
- IConfigurableListableObjectFactory ObjectFactory { get; }
-
- ///
- /// Add an
- ///
- /// that will get applied to the internal object factory of this
- /// application context on refresh, before any of the object
- /// definitions are evaluated.
- ///
- ///
- ///
- /// To be invoked during context configuration.
- ///
+ /// This interface is to be implemented by most (if not all)
+ /// implementations.
+ ///
+ ///
+ /// Configuration and lifecycle methods are encapsulated here to avoid
+ /// making them obvious to
+ /// client code.
+ ///
+ ///
+ /// Calling will close this
+ /// application context, releasing all resources and locks that the
+ /// implementation might hold. This includes disposing all cached
+ /// singleton objects.
+ ///
+ ///
+ /// does not invoke the
+ /// attendant on any parent
+ /// context.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ public interface IConfigurableApplicationContext : IApplicationContext
+ {
+ ///
+ /// Return the internal object factory of this application context.
+ ///
+ ///
+ ///
+ /// Can be used to access specific functionality of the factory.
+ ///
+ ///
+ /// This is just guaranteed to return an instance that is not
+ /// after the context has been refreshed
+ /// at least once.
+ ///
+ ///
+ /// Do not use this to post-process the object factory; singletons
+ /// will already have been instantiated. Use an
+ ///
+ /// to intercept the object factory setup process before objects even
+ /// get touched.
+ ///
+ ///
+ ///
+ IConfigurableListableObjectFactory ObjectFactory { get; }
+
+ ///
+ /// Add an
+ ///
+ /// that will get applied to the internal object factory of this
+ /// application context on refresh, before any of the object
+ /// definitions are evaluated.
+ ///
+ ///
+ ///
+ /// To be invoked during context configuration.
+ ///
- /// This enables the parameterization and internationalization of messages.
- ///
- ///
- /// Spring.NET provides one out-of-the-box implementation for production
- /// use:
- ///
- ///
.
- ///
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// Aleksandar Seovic (.NET)
- /// $Id: IMessageSource.cs,v 1.13 2007/07/02 21:24:39 markpollack Exp $
- ///
- public interface IMessageSource {
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- ///
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- ///
- ///
- /// Throw an exception.
- ///
- ///
- ///
- /// Return the supplied as is.
- ///
- ///
- ///
- ///
- /// The name of the message to resolve.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- string GetMessage(string name);
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- ///
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- ///
- ///
- /// Throw an exception.
- ///
- ///
- ///
- /// Return the supplied as is.
- ///
- ///
- ///
- ///
- /// The name of the message to resolve.
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- string GetMessage(string name, params object[] arguments);
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- ///
- ///
- /// Throw an exception.
- ///
- ///
- ///
- /// Return the supplied as is.
- ///
- ///
- ///
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- string GetMessage(string name, CultureInfo culture);
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- ///
- ///
- /// Throw an exception.
- ///
- ///
- ///
- /// Return the supplied as is.
- ///
- ///
- ///
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- string GetMessage(string name, CultureInfo culture, params object[] arguments);
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- ///
- ///
- /// Throw an exception.
- ///
- ///
- ///
- /// Return the supplied as is.
- ///
- ///
- ///
- ///
- /// The name of the message to resolve.
- /// The default message if name is not found.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments);
-
- ///
- /// Resolve the message using all of the attributes contained within
- /// the supplied
- /// argument.
- ///
- ///
- /// The value object storing those attributes that are required to
- /// properly resolve a message.
- ///
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If the message could not be resolved.
- ///
- string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture);
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- ///
- /// This method must use the
- ///
- /// value to obtain a resource.
- ///
- ///
- /// Examples of resources that may be resolved by this method include
- /// (but are not limited to) objects such as icons and bitmaps.
- ///
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- object GetResourceObject(string name);
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- ///
- /// Examples of resources that may be resolved by this method include
- /// (but are not limited to) objects such as icons and bitmaps.
- ///
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- object GetResourceObject(string name, CultureInfo culture);
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- ///
- /// Resource key names are of the form objectName.propertyName.
- ///
+ /// This enables the parameterization and internationalization of messages.
+ ///
+ ///
+ /// Spring.NET provides one out-of-the-box implementation for production
+ /// use:
+ ///
+ ///
.
+ ///
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ /// Aleksandar Seovic (.NET)
+ ///
+ public interface IMessageSource {
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ ///
+ ///
+ /// Throw an exception.
+ ///
+ ///
+ ///
+ /// Return the supplied as is.
+ ///
+ ///
+ ///
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ string GetMessage(string name);
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ ///
+ ///
+ /// Throw an exception.
+ ///
+ ///
+ ///
+ /// Return the supplied as is.
+ ///
+ ///
+ ///
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ string GetMessage(string name, params object[] arguments);
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ ///
+ ///
+ /// Throw an exception.
+ ///
+ ///
+ ///
+ /// Return the supplied as is.
+ ///
+ ///
+ ///
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ string GetMessage(string name, CultureInfo culture);
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ ///
+ ///
+ /// Throw an exception.
+ ///
+ ///
+ ///
+ /// Return the supplied as is.
+ ///
+ ///
+ ///
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ string GetMessage(string name, CultureInfo culture, params object[] arguments);
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ ///
+ ///
+ /// Throw an exception.
+ ///
+ ///
+ ///
+ /// Return the supplied as is.
+ ///
+ ///
+ ///
+ ///
+ /// The name of the message to resolve.
+ /// The default message if name is not found.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments);
+
+ ///
+ /// Resolve the message using all of the attributes contained within
+ /// the supplied
+ /// argument.
+ ///
+ ///
+ /// The value object storing those attributes that are required to
+ /// properly resolve a message.
+ ///
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture);
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// This method must use the
+ ///
+ /// value to obtain a resource.
+ ///
+ ///
+ /// Examples of resources that may be resolved by this method include
+ /// (but are not limited to) objects such as icons and bitmaps.
+ ///
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ object GetResourceObject(string name);
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// Examples of resources that may be resolved by this method include
+ /// (but are not limited to) objects such as icons and bitmaps.
+ ///
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ object GetResourceObject(string name, CultureInfo culture);
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ ///
+ /// Resource key names are of the form objectName.propertyName.
+ ///
- /// In the current implementation, the
- /// will typically be the
- /// associated that
- /// spawned the implementing object.
- ///
- ///
- /// The can usually also be
- /// passed on as an object reference to arbitrary object properties or
- /// constructor arguments, because a
- /// is typically defined as an
- /// object with the well known name "messageSource" in the
- /// associated application context.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: IMessageSourceAware.cs,v 1.4 2006/04/09 07:18:38 markpollack Exp $
- ///
- public interface IMessageSourceAware
- {
- ///
- /// Sets the associated
- /// with this object.
- ///
- ///
- ///
- /// Invoked after population of normal object properties but
- /// before an initializing callback such as the
- ///
- /// method of the
- /// interface
- /// or a custom init-method.
- ///
- ///
- /// It is also invoked before the
- ///
- /// property of any
- ///
- /// implementation.
- ///
+ /// In the current implementation, the
+ /// will typically be the
+ /// associated that
+ /// spawned the implementing object.
+ ///
+ ///
+ /// The can usually also be
+ /// passed on as an object reference to arbitrary object properties or
+ /// constructor arguments, because a
+ /// is typically defined as an
+ /// object with the well known name "messageSource" in the
+ /// associated application context.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ public interface IMessageSourceAware
+ {
+ ///
+ /// Sets the associated
+ /// with this object.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal object properties but
+ /// before an initializing callback such as the
+ ///
+ /// method of the
+ /// interface
+ /// or a custom init-method.
+ ///
+ ///
+ /// It is also invoked before the
+ ///
+ /// property of any
+ ///
+ /// implementation.
+ ///
- /// Spring.NET's own validation error classes implement this interface.
- ///
- ///
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: IMessageSourceResolvable.cs,v 1.6 2006/04/09 07:18:38 markpollack Exp $
- ///
- ///
- public interface IMessageSourceResolvable
- {
- ///
- /// Return the codes to be used to resolve this message, in the order
- /// that they are to be tried.
- ///
- ///
- ///
- /// The last code will therefore be the default one.
- ///
+ /// Spring.NET's own validation error classes implement this interface.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ public interface IMessageSourceResolvable
+ {
+ ///
+ /// Return the codes to be used to resolve this message, in the order
+ /// that they are to be tried.
+ ///
+ ///
+ ///
+ /// The last code will therefore be the default one.
+ ///
- /// Note that dependencies can also
- /// be exposed as object properties of type
- /// , populated via strings with
- /// automatic type conversion by the object factory. This obviates the
- /// need for implementing any callback interface just for the purpose of
- /// accessing a specific resource.
- ///
- ///
- /// You typically need an
- /// when your application object has to access a variety of file resources
- /// whose names are calculated. A good strategy is to make the object use
- /// a default resource loader but still implement the
- /// interface to allow
- /// for overriding when running in an
- /// .
- ///
- ///
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: IResourceLoaderAware.cs,v 1.8 2007/08/08 17:46:37 bbaia Exp $
- ///
- ///
- ///
- public interface IResourceLoaderAware
- {
- ///
- /// Gets and sets the
- /// that this object runs in.
- ///
- ///
- ///
- /// Invoked after population of normal objects properties but
- /// before an init callback such as
- /// 's
- ///
- /// or a custom init-method. Invoked before setting
- /// 's
- ///
- /// property.
- ///
+ /// Note that dependencies can also
+ /// be exposed as object properties of type
+ /// , populated via strings with
+ /// automatic type conversion by the object factory. This obviates the
+ /// need for implementing any callback interface just for the purpose of
+ /// accessing a specific resource.
+ ///
+ ///
+ /// You typically need an
+ /// when your application object has to access a variety of file resources
+ /// whose names are calculated. A good strategy is to make the object use
+ /// a default resource loader but still implement the
+ /// interface to allow
+ /// for overriding when running in an
+ /// .
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ ///
+ public interface IResourceLoaderAware
+ {
+ ///
+ /// Gets and sets the
+ /// that this object runs in.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal objects properties but
+ /// before an init callback such as
+ /// 's
+ ///
+ /// or a custom init-method. Invoked before setting
+ /// 's
+ ///
+ /// property.
+ ///
- /// Does not mandate the type of storage used for configuration, but does
- /// implement common functionality. Uses the Template Method design
- /// pattern, requiring concrete subclasses to implement
- /// methods.
- ///
- ///
- /// In contrast to a plain vanilla
- /// , an
- /// is supposed
- /// to detect special objects defined in its object factory: therefore,
- /// this class automatically registers
- /// s,
- /// s
- /// and s that are
- /// defined as objects in the context.
- ///
- ///
- /// An may be also supplied as
- /// an object in the context, with the special, well-known-name of
- /// "messageSource". Else, message resolution is delegated to the
- /// parent context.
- ///
- ///
- /// Rod Johnson
- /// Juergan Hoeller
- /// Griffin Caprio (.NET)
- /// $Id: AbstractApplicationContext.cs,v 1.74 2007/08/27 09:38:28 oakinger Exp $
- ///
- ///
- public abstract class AbstractApplicationContext
- : ConfigurableResourceLoader, IConfigurableApplicationContext
- {
- #region Constants
-
- ///
- /// Name of the .Net config section that contains Spring.Net context definition.
- ///
- public const string ContextSectionName = "spring/context";
-
- ///
- /// Default name of the root context.
- ///
- public const string DefaultRootContextName = "spring.root";
-
- #endregion
-
- #region Fields
-
- private const long TicksAtEpoch = 621355968000000000;
-
- ///
- /// The special, well-known-name of the default
- /// in the context.
- ///
- ///
- ///
- /// If no can be found
- /// in the context using this lookup key, then message resolution
- /// will be delegated to the parent context (if any).
- ///
- ///
- public static readonly string MessageSourceObjectName = "messageSource";
-
- ///
- /// The special, well-known-name of the default
- /// in the context.
- ///
- ///
- ///
- /// If no can be found
- /// in the context using this lookup key, then a default
- /// will be used.
- ///
- ///
- public static readonly string EventRegistryObjectName = "eventRegistry";
-
- ///
- /// The instance for this class.
- ///
- private static readonly ILog log = LogManager.GetLogger(typeof(AbstractApplicationContext));
-
- ///
- /// The instance we delegate
- /// our implementation of said interface to.
- ///
- private IMessageSource _messageSource;
-
- ///
- /// The instance we
- /// delegate our implementation of said interface to.
- ///
- private IEventRegistry _eventRegistry;
-
- private IApplicationContext _parentApplicationContext;
- private readonly IList _objectFactoryPostProcessors;
- private IList _defaultObjectPostProcessors;
- private string _name;
- private DateTime _startupDate;
- private readonly bool _caseSensitive;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// with no parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- protected AbstractApplicationContext() : this(null, true, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// with no parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- /// Flag specifying whether to make this context case sensitive or not.
- protected AbstractApplicationContext(bool caseSensitive) : this(null, caseSensitive, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// with the supplied parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- /// The application context name.
- /// Flag specifying whether to make this context case sensitive or not.
- /// The parent application context.
- protected AbstractApplicationContext(string name, bool caseSensitive,
- IApplicationContext parentApplicationContext)
- {
- _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name;
- _caseSensitive = caseSensitive;
- _parentApplicationContext = parentApplicationContext;
- _objectFactoryPostProcessors = new ArrayList();
- _defaultObjectPostProcessors = new ArrayList();
- AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker());
- AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this));
- }
-
- ///
- /// Adds the given to the list of standard
- /// processors being added to the underlying
- ///
- ///
- /// Each time is called on this context, the context ensures, that
- /// all default s are registered with the underlying .
- ///
- /// The instance.
- protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor)
- {
- _defaultObjectPostProcessors.Add(defaultObjectPostProcessor);
- }
-
- ///
- /// Closes this context and disposes of any resources (such as
- /// singleton objects in the wrapped
- /// ).
- ///
- public virtual void Dispose()
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Closing application context [{0}].",
- Name));
- }
-
- #endregion
-
- new DefensiveEventRaiser().Raise(
- ContextEvent, this,
- new ContextEventArgs(ContextEventArgs.ContextEvent.Closed));
- ObjectFactory.Dispose();
- }
-
- #endregion
-
- #region Abstract Methods
-
- ///
- /// Subclasses must implement this method to perform the actual
- /// configuration loading.
- ///
- ///
- ///
- /// This method is invoked by
- /// ,
- /// before any other initialization occurs.
- ///
- ///
- ///
- /// In the case of errors encountered while refreshing the object factory.
- ///
- protected abstract void RefreshObjectFactory();
-
- #endregion
-
- ///
- /// An object that can be used to synchronize access to the
- ///
- public object SyncRoot
- {
- get { return this; }
- }
-
- ///
- /// The timestamp when this context was first loaded.
- ///
- ///
- /// The timestamp (milliseconds) when this context was first loaded.
- ///
- public long StartupDateMilliseconds
- {
- get { return (StartupDate.Ticks - TicksAtEpoch)/10000; }
- }
-
-
- ///
- /// Gets a flag indicating whether context should be case sensitive.
- ///
- /// true if object lookups are case sensitive; otherwise, false.
- protected bool CaseSensitive
- {
- get { return _caseSensitive; }
- }
-
- ///
- /// The for this context.
- ///
- ///
- /// If the context has not been initialized yet.
- ///
- public IMessageSource MessageSource
- {
- get
- {
- if (_messageSource == null)
- {
- throw new InvalidOperationException(
- "MessageSource not initialized - call 'Refresh()' " +
- "before accessing messages via the context: " + this);
- }
- return _messageSource;
- }
- }
-
- ///
- /// The for this context.
- ///
- ///
- /// If the context has not been initialized yet.
- ///
- public IEventRegistry EventRegistry
- {
- get
- {
- if (_eventRegistry == null)
- {
- throw new InvalidOperationException(
- "EventRegistry not initialized - call 'Refresh()' " +
- "before accessing the event registry via the context: " + this);
- }
- return _eventRegistry;
- }
- }
-
- ///
- /// Returns the internal object factory of the parent context if it implements
- /// ; else,
- /// returns the parent context itself.
- ///
- ///
- /// The parent context's object factory, or the parent itself.
- ///
- protected IObjectFactory GetInternalParentObjectFactory()
- {
- IConfigurableApplicationContext configContext
- = _parentApplicationContext as IConfigurableApplicationContext;
- if (configContext != null)
- {
- return ((IConfigurableApplicationContext)
- _parentApplicationContext).ObjectFactory;
- }
- else
- {
- return _parentApplicationContext;
- }
- }
-
- ///
- /// Raises an application context event.
- ///
- ///
- /// Any arguments to the event. May be .
- ///
- protected virtual void OnContextEvent(ApplicationEventArgs e)
- {
- OnContextEvent(this, e);
- }
-
- ///
- /// Raises an application context event.
- ///
- ///
- /// The source of the event.
- ///
- ///
- /// Any arguments to the event. May be .
- ///
- protected virtual void OnContextEvent(object source, ApplicationEventArgs e)
- {
- new DefensiveEventRaiser().Raise(ContextEvent, source, e);
- }
-
- ///
- /// Modify the application context's internal object factory after its standard
- /// initialization.
- ///
- ///
- ///
- /// All object definitions will have been loaded, but no objects
- /// will have been instantiated yet. This allows for the registration
- /// of special
- /// s
- /// in certain
- /// implementations.
- ///
- ///
- ///
- /// The object factory used by the application context.
- ///
- ///
- /// In the case of errors.
- /// .
- protected virtual void PostProcessObjectFactory(
- IConfigurableListableObjectFactory objectFactory)
- {
- }
-
- ///
- /// Template method which can be overridden to add context-specific
- /// refresh work.
- ///
- ///
- ///
- /// Called on initialization of special objects, before instantiation
- /// of singletons.
- ///
- ///
- protected virtual void OnRefresh()
- {
- }
-
- ///
- /// Instantiate and invoke all registered
- ///
- /// objects, respecting any explicit ordering.
- ///
- ///
- ///
- /// Must be called before singleton instantiation.
- ///
- ///
- /// In the case of errors.
- private void InvokeObjectFactoryPostProcessors()
- {
- // do NOT include IFactoryObjects; they (typically) need to be instantiated
- // to determine the Type of object that they create, and if they are instantiated
- // then we won't be able to do any factory post processin' on 'em...
- string[] factoryProcessorNames
- = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false);
- ArrayList orderedFactoryProcessors = new ArrayList();
- IList nonOrderedFactoryProcessorNames = new ArrayList();
- for (int i = 0; i < factoryProcessorNames.Length; ++i)
- {
- string processorName = factoryProcessorNames[i];
- object processor = GetObject(processorName);
- if (typeof(IOrdered).IsAssignableFrom(GetType(processorName)))
- {
- orderedFactoryProcessors.Add(processor);
- }
- else
- {
- nonOrderedFactoryProcessorNames.Add(processor);
- }
- }
- // first, invoke those IObjectFactoryPostProcessors that implement IOrdered...
- orderedFactoryProcessors.Sort(new OrderComparator());
- ProcessObjectFactoryPostProcessors(orderedFactoryProcessors);
- // and then the unordered ones...
- ProcessObjectFactoryPostProcessors(nonOrderedFactoryProcessorNames);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "processed {0} IFactoryObjectPostProcessors defined in application context [{1}].",
- factoryProcessorNames.Length,
- Name));
- }
-
- #endregion
- }
-
- private void ProcessObjectFactoryPostProcessors(IList orderedFactoryProcessors)
- {
- foreach (IObjectFactoryPostProcessor processor in orderedFactoryProcessors)
- {
- processor.PostProcessObjectFactory(ObjectFactory);
- }
- }
-
- private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
- {
- RegisterObjectPostProcessorChecker(objectFactory);
- IDictionary dict = GetObjectsOfType(typeof(IObjectPostProcessor), true, false);
- ArrayList objectProcessors = new ArrayList(dict.Values);
- objectProcessors.Sort(new OrderComparator());
- foreach (IObjectPostProcessor objectPostProcessor in objectProcessors)
- {
- ObjectFactory.AddObjectPostProcessor(objectPostProcessor);
- }
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "processed {0} IObjectPostProcessors defined in application context [{1}].",
- objectProcessors.Count,
- Name));
- }
- }
-
- ///
- /// Register an IObjectPostProcessorChecker that logs an info
- /// message when an object is created during IObjectPostProcessor
- /// instantiation, i.e. when an object is not eligible for being
- /// processed by all IObjectPostProcessors.
- ///
- private void RegisterObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory)
- {
- int objectPostProcessorCount
- = ObjectFactory.ObjectPostProcessorCount + 1
- + GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length;
-// ObjectFactory.AddObjectPostProcessor(
-// new ObjectPostProcessorChecker(objectFactory, objectPostProcessorCount));
- ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount);
- }
-
- ///
- /// Initializes the default event registry for this context.
- ///
- private void InitEventRegistry()
- {
- if (ContainsObject(EventRegistryObjectName))
- {
- object candidateRegistry = GetObject(EventRegistryObjectName);
- if (candidateRegistry is IEventRegistry)
- {
- _eventRegistry = (IEventRegistry) candidateRegistry;
-
- #region Instrumentation
-
- log.Debug(StringUtils.Surround(
- "Using IEventRegistry [", EventRegistry, "]"));
-
- #endregion
- }
- else
- {
- _eventRegistry = new EventRegistry();
-
- #region Instrumentation
-
- if (log.IsWarnEnabled)
- {
- log.Warn(string.Format(
- "Found object in context named '{0}' : this name " +
- "is typically reserved for IEventRegistry objects. " +
- "Falling back to default '{1}'.",
- EventRegistryObjectName, EventRegistry));
- }
-
- #endregion
- }
- }
- else
- {
- _eventRegistry = new EventRegistry();
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No IEventRegistry found with name '{0}' : using default '{1}'.",
- EventRegistryObjectName, EventRegistry));
- }
-
- #endregion
- }
- ICollection interestedParties
- = GetObjectsOfType(typeof(IEventRegistryAware), true, false).Values;
- foreach (IEventRegistryAware party in interestedParties)
- {
- party.EventRegistry = EventRegistry;
- }
- EventRegistry.PublishEvents(this);
- }
-
- ///
- /// Returns the internal message source of the parent context if said
- /// parent context is an , else
- /// simply the parent context itself.
- ///
- ///
- /// The internal message source of the parent context if said
- /// parent context is an , else
- /// simply the parent context itself.
- ///
- protected virtual IMessageSource GetInternalParentMessageSource()
- {
- AbstractApplicationContext parent
- = ParentContext as AbstractApplicationContext;
- return parent == null ? ParentContext : parent._messageSource;
- }
-
- ///
- /// Initializes the default message source for this context.
- ///
- ///
- ///
- /// Uses any parent context's message source if one is not available
- /// in this context.
- ///
- ///
- private void InitMessageSource()
- {
- if (ContainsObject(MessageSourceObjectName))
- {
- object candidateSource = GetObject(MessageSourceObjectName);
- if (candidateSource is IMessageSource)
- {
- _messageSource
- = (IMessageSource) GetObject(MessageSourceObjectName);
-
- // make IMessageSource aware of any parent IMessageSource...
- if (ParentContext != null)
- {
- IHierarchicalMessageSource hierSource
- = MessageSource as IHierarchicalMessageSource;
- if (hierSource != null)
- {
- IMessageSource parentMessageSource
- = GetInternalParentMessageSource();
- hierSource.ParentMessageSource = parentMessageSource;
- }
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(StringUtils.Surround(
- "Using MessageSource [", MessageSource, "]"));
- }
-
- #endregion
- }
- else
- {
- _messageSource = new DelegatingMessageSource(
- GetInternalParentMessageSource());
-
- #region Instrumentation
-
- if (log.IsWarnEnabled)
- {
- log.Warn(string.Format(
- "Found object in context named '{0}' : this name " +
- "is typically reserved for IMessageSource objects. " +
- "Falling back to default '{1}'.",
- MessageSourceObjectName, MessageSource));
- }
-
- #endregion
- }
- }
- else if (ParentContext != null)
- {
- _messageSource = new DelegatingMessageSource(
- GetInternalParentMessageSource());
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No message source found in the current context: using parent context's message source '{0}'.",
- MessageSource));
- }
-
- #endregion
- }
- else
- {
- _messageSource = new StaticMessageSource();
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "No IMessageSource found with name '{0}' : using default '{1}'.",
- MessageSourceObjectName, MessageSource));
- }
-
- #endregion
- }
- }
-
- private void RefreshApplicationEventListeners()
- {
- ICollection listeners
- = GetObjectsOfType(
- typeof(IApplicationEventListener), true, false).Values;
- foreach (IApplicationEventListener applicationListener in listeners)
- {
- EventRegistry.Subscribe(applicationListener);
- }
- }
-
- ///
- /// Returns the list of the
- /// s
- /// that will be applied to the objects created with this factory.
- ///
- ///
- ///
- /// The elements of this list are instances of implementations of the
- ///
- /// interface.
- ///
- ///
- ///
- /// The list of the
- /// s
- /// that will be applied to the objects created with this factory.
- ///
- private IList ObjectFactoryPostProcessors
- {
- get { return _objectFactoryPostProcessors; }
- }
-
- #region IConfigurableApplicationContext Members
-
- ///
- /// Return the internal object factory of this application context.
- ///
- public abstract IConfigurableListableObjectFactory ObjectFactory { get; }
-
- ///
- /// Add a new
- /// that will get applied to the internal object factory of this application context
- /// on refresh, before any of the object definitions are evaluated.
- ///
- ///
- /// The factory processor to register.
- ///
- public void AddObjectFactoryPostProcessor(
- IObjectFactoryPostProcessor objectFactoryPostProcessor)
- {
- _objectFactoryPostProcessors.Add(objectFactoryPostProcessor);
- }
-
- ///
- /// Load or refresh the persistent representation of the configuration,
- /// which might an XML file, properties file, or relational database schema.
- ///
- ///
- /// If the configuration cannot be loaded.
- ///
- ///
- /// If the object factory could not be initialized.
- ///
- public virtual void Refresh()
- {
- lock (SyncRoot)
- {
-
- /*
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- StackTrace stackTrace = new StackTrace(1, true);
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Refreshing application context [{0}]. Called from:{1}",
- Name, stackTrace));
- }
-
- #endregion
- */
-
- _startupDate = DateTime.Now;
-
- RefreshObjectFactory();
- IConfigurableListableObjectFactory objectFactory = ObjectFactory;
-
- EnsureKnownObjectPostProcessors(objectFactory);
- objectFactory.IgnoreDependencyType(typeof(IResourceLoader));
- objectFactory.IgnoreDependencyType(typeof(IApplicationContext));
-
- PostProcessObjectFactory(objectFactory);
- foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors)
- {
- factoryProcessor.PostProcessObjectFactory(objectFactory);
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "{0} objects defined in application context [{1}].",
- ObjectDefinitionCount == 0 ? "No" : ObjectDefinitionCount.ToString(),
- Name));
- }
-
- #endregion
-
- InvokeObjectFactoryPostProcessors();
- RegisterObjectPostProcessors(objectFactory);
- InitEventRegistry();
- InitMessageSource();
- OnRefresh();
- RefreshApplicationEventListeners();
-
- objectFactory.PreInstantiateSingletons();
-
- new DefensiveEventRaiser().Raise(
- ContextEvent, this,
- new ContextEventArgs(ContextEventArgs.ContextEvent.Refreshed));
- }
- }
-
- ///
- /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory
- ///
- ///
- protected void EnsureKnownObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
- {
- // index 0 contains the ObjectPostProcessorChecker that is handled separately!
- for (int i = 1; i < _defaultObjectPostProcessors.Count; i++)
- {
- objectFactory.AddObjectPostProcessor((IObjectPostProcessor) this._defaultObjectPostProcessors[i]);
- }
- }
-
- ///
- /// Gets the parent context, or if there is no
- /// parent context.
- ///
- ///
- /// The parent context, or if there is no
- /// parent.
- ///
- ///
- public virtual IApplicationContext ParentContext
- {
- get { return _parentApplicationContext; }
- set { _parentApplicationContext = value; }
- }
-
- #endregion
-
- #region IApplicationContext Members
-
- ///
- /// Raised in response to an implementation-dependant application
- /// context event.
- ///
- public event ApplicationEventHandler ContextEvent;
-
- ///
- /// The date and time this context was first loaded.
- ///
- ///
- /// The representing when this context
- /// was first loaded.
- ///
- public DateTime StartupDate
- {
- get { return _startupDate; }
- }
-
- ///
- /// A name for this context.
- ///
- ///
- /// A name for this context.
- ///
- public string Name
- {
- get { return _name; }
- set { _name = value; }
- }
-
-
-
- #endregion
-
- #region IListableObjectFactory Members
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectNamesForType(Type type)
- {
- return ObjectFactory.GetObjectNamesForType(type);
- }
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s).
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectNamesForType(
- Type type, bool includePrototypes, bool includeFactoryObjects)
- {
- return ObjectFactory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects);
- }
-
- ///
- /// Return the names of all objects defined in this factory.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectDefinitionNames()
- {
- return ObjectFactory.GetObjectDefinitionNames();
- }
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public virtual IObjectDefinition GetObjectDefinition(string name)
- {
- return ObjectFactory.GetObjectDefinition(name);
- }
-
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- /// Whether to search parent object factories.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
- {
- return ObjectFactory.GetObjectDefinition(name, includeAncestors);
- }
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- /// The (class or interface) to match.
- ///
- ///
- /// A of the matching objects,
- /// containing the object names as keys and the corresponding object instances
- /// as values.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- public IDictionary GetObjectsOfType(Type type)
- {
- return GetObjectsOfType(type, true, true);
- }
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- /// The (class or interface) to match.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s).
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// A of the matching objects,
- /// containing the object names as keys and the corresponding object instances
- /// as values.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- public IDictionary GetObjectsOfType(
- Type type, bool includePrototypes, bool includeFactoryObjects)
- {
- return ObjectFactory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
- }
-
- ///
- /// Return the number of objects defined in the factory.
- ///
- ///
- /// The number of objects defined in the factory.
- ///
- ///
- public int ObjectDefinitionCount
- {
- get { return ObjectFactory.ObjectDefinitionCount; }
- }
-
- ///
- /// Check if this object factory contains an object definition with the given name.
- ///
- /// The name of the object to look for.
- ///
- /// True if this object factory contains an object definition with the given name.
- ///
- ///
- public bool ContainsObjectDefinition(string name)
- {
- return ObjectFactory.ContainsObjectDefinition(name);
- }
-
- #endregion
-
- #region IObjectFactory Members
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- public object this[string name]
- {
- get { return ObjectFactory.GetObject(name); }
- }
-
- ///
- /// Does this object factory contain an object with the given name?
- ///
- /// The name of the object to query.
- ///
- /// if an object with the given name is defined.
- ///
- ///
- public bool ContainsObject(string name)
- {
- return ObjectFactory.ContainsObject(name);
- }
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- /// The object name to check for aliases.
- /// The aliases, or an empty array if none.
- ///
- /// If there's no such object definition.
- ///
- ///
- public string[] GetAliases(string name)
- {
- return ObjectFactory.GetAliases(name);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- public object GetObject(string name, Type requiredType)
- {
- return ObjectFactory.GetObject(name, requiredType);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- public object GetObject(string name)
- {
- return ObjectFactory.GetObject(name);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. If there is no factory method and the
- /// arguments are not null, then match the argument values by type and
- /// call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the supplied is .
- ///
- public object GetObject(string name, object[] arguments)
- {
- return ObjectFactory.GetObject(name, arguments);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public object GetObject(string name, Type requiredType, object[] arguments)
- {
- return ObjectFactory.GetObject(name, requiredType, arguments);
- }
-
- ///
- /// Is this object a singleton?
- ///
- /// The name of the object to query.
- /// True if the named object is a singleton.
- ///
- /// If there's no such object definition.
- ///
- ///
- public bool IsSingleton(string name)
- {
- return ObjectFactory.IsSingleton(name);
- }
-
- ///
- /// Determines whether the specified object name is prototype. That is, will GetObject
- /// always return independent instances?
- ///
- /// The name of the object to query
- ///
- /// true if the specified object name will always deliver independent instances; otherwise, false.
- ///
- /// This method returning false does not clearly indicate a singleton object.
- /// It indicated non-independent instances, which may correspond to a scoped object as
- /// well. use the IsSingleton property to explicitly check for a shared
- /// singleton instance.
- /// Translates aliases back to the corresponding canonical object name. Will ask the
- /// parent factory if the object can not be found in this factory instance.
- ///
- ///
- /// if there is no object with the given name.
- public bool IsPrototype(string name)
- {
- return ObjectFactory.IsPrototype(name);
- }
-
-
- ///
- /// Determines whether the object with the given name matches the specified type.
- ///
- /// More specifically, check whether a GetObject call for the given name
- /// would return an object that is assignable to the specified target type.
- /// Translates aliases back to the corresponding canonical bean name.
- /// Will ask the parent factory if the bean cannot be found in this factory instance.
- ///
- /// The name of the object to query.
- /// Type of the target to match against.
- ///
- /// true if the object type matches; otherwise, false
- /// if it doesn't match or cannot be determined yet.
- ///
- /// Ff there is no object with the given name
- ///
- public bool IsTypeMatch(string name, Type targetType)
- {
- return ObjectFactory.IsTypeMatch(name, targetType);
- }
-
- ///
- /// Determine the of the object with the
- /// given name.
- ///
- /// The name of the object to query.
- ///
- /// The of the object, or
- /// if not determinable.
- ///
- ///
- public Type GetType(string name)
- {
- return ObjectFactory.GetType(name);
- }
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the named object definition.
- ///
- ///
- /// The object instance that is to be so configured.
- ///
- ///
- /// The name of the object definition expressing the dependencies that are to
- /// be injected into the supplied instance.
- ///
- ///
- public object ConfigureObject(object target, string name)
- {
- return ObjectFactory.ConfigureObject(target, name);
- }
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the supplied .
- ///
- ///
- /// The object instance that is to be so configured.
- ///
- ///
- /// The name of the object definition expressing the dependencies that are to
- /// be injected into the supplied instance.
- ///
- ///
- /// An object definition that should be used to configure object.
- ///
- ///
- public object ConfigureObject(object target, string name, IObjectDefinition definition)
- {
- return ObjectFactory.ConfigureObject(target, name, definition);
- }
-
- #endregion
-
- #region IHierarchicalObjectFactory Members
-
- ///
- /// Return the parent object factory, or if there is none.
- ///
- ///
- /// The parent object factory, or if there is none.
- ///
- ///
- public IObjectFactory ParentObjectFactory
- {
- get { return _parentApplicationContext; }
- }
-
- #endregion
-
- #region IMessageSource Members
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(
- string name, CultureInfo culture, params object[] arguments)
- {
- return MessageSource.GetMessage(name, culture, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The default message.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
- {
- return MessageSource.GetMessage(name, defaultMessage, culture, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The resolved message if the lookup was successful.
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- public string GetMessage(string name)
- {
- return MessageSource.GetMessage(name);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- ///
- /// The resolved message if the lookup was successful.
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, params object[] arguments)
- {
- return MessageSource.GetMessage(name, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If no message could be resolved.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public string GetMessage(string name, CultureInfo culture)
- {
- return MessageSource.GetMessage(name, culture);
- }
-
- ///
- /// Resolve the message using all of the attributes contained within
- /// the supplied
- /// argument.
- ///
- ///
- /// The value object storing those attributes that are required to
- /// properly resolve a message.
- ///
- ///
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If the message could not be resolved.
- ///
- ///
- public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
- {
- return MessageSource.GetMessage(resolvable, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- object IMessageSource.GetResourceObject(string name, CultureInfo culture)
- {
- return GetResourceObject(name, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- object IMessageSource.GetResourceObject(string name)
- {
- return GetResourceObject(name);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- public object GetResourceObject(string name, CultureInfo culture)
- {
- return MessageSource.GetResourceObject(name, culture);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- public object GetResourceObject(string name)
- {
- return MessageSource.GetResourceObject(name);
- }
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- public void ApplyResources(object value, string objectName, CultureInfo culture)
- {
- MessageSource.ApplyResources(value, objectName, culture);
- }
-
- #endregion
-
- #region IEventRegistry Members
-
- ///
- /// Publishes all events of the source object.
- ///
- ///
- /// The source object containing events to publish.
- ///
- ///
- public void PublishEvents(object sourceObject)
- {
- _eventRegistry.PublishEvents(sourceObject);
- }
-
- ///
- /// Subscribes to all events published, if the subscriber
- /// implements compatible handler methods.
- ///
- /// The subscriber to use.
- ///
- public void Subscribe(object subscriber)
- {
- _eventRegistry.Subscribe(subscriber);
- }
-
- ///
- /// Subscribes to published events of a all objects of a given
- /// , if the subscriber implements
- /// compatible handler methods.
- ///
- /// The subscriber to use.
- ///
- /// The target to subscribe to.
- ///
- ///
- public void Subscribe(object subscriber, Type targetSourceType)
- {
- _eventRegistry.Subscribe(subscriber, targetSourceType);
- }
-
- #endregion
-
- ///
- /// Publishes an application context event.
- ///
- ///
- ///
+ /// Does not mandate the type of storage used for configuration, but does
+ /// implement common functionality. Uses the Template Method design
+ /// pattern, requiring concrete subclasses to implement
+ /// methods.
+ ///
+ ///
+ /// In contrast to a plain vanilla
+ /// , an
+ /// is supposed
+ /// to detect special objects defined in its object factory: therefore,
+ /// this class automatically registers
+ /// s,
+ /// s
+ /// and s that are
+ /// defined as objects in the context.
+ ///
+ ///
+ /// An may be also supplied as
+ /// an object in the context, with the special, well-known-name of
+ /// "messageSource". Else, message resolution is delegated to the
+ /// parent context.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergan Hoeller
+ /// Griffin Caprio (.NET)
+ ///
+ ///
+ public abstract class AbstractApplicationContext
+ : ConfigurableResourceLoader, IConfigurableApplicationContext
+ {
+ #region Constants
+
+ ///
+ /// Name of the .Net config section that contains Spring.Net context definition.
+ ///
+ public const string ContextSectionName = "spring/context";
+
+ ///
+ /// Default name of the root context.
+ ///
+ public const string DefaultRootContextName = "spring.root";
+
+ #endregion
+
+ #region Fields
+
+ private const long TicksAtEpoch = 621355968000000000;
+
+ ///
+ /// The special, well-known-name of the default
+ /// in the context.
+ ///
+ ///
+ ///
+ /// If no can be found
+ /// in the context using this lookup key, then message resolution
+ /// will be delegated to the parent context (if any).
+ ///
+ ///
+ public static readonly string MessageSourceObjectName = "messageSource";
+
+ ///
+ /// The special, well-known-name of the default
+ /// in the context.
+ ///
+ ///
+ ///
+ /// If no can be found
+ /// in the context using this lookup key, then a default
+ /// will be used.
+ ///
+ ///
+ public static readonly string EventRegistryObjectName = "eventRegistry";
+
+ ///
+ /// The instance for this class.
+ ///
+ private static readonly ILog log = LogManager.GetLogger(typeof(AbstractApplicationContext));
+
+ ///
+ /// The instance we delegate
+ /// our implementation of said interface to.
+ ///
+ private IMessageSource _messageSource;
+
+ ///
+ /// The instance we
+ /// delegate our implementation of said interface to.
+ ///
+ private IEventRegistry _eventRegistry;
+
+ private IApplicationContext _parentApplicationContext;
+ private readonly IList _objectFactoryPostProcessors;
+ private IList _defaultObjectPostProcessors;
+ private string _name;
+ private DateTime _startupDate;
+ private readonly bool _caseSensitive;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// with no parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ protected AbstractApplicationContext() : this(null, true, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// with no parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this context case sensitive or not.
+ protected AbstractApplicationContext(bool caseSensitive) : this(null, caseSensitive, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// with the supplied parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ /// The application context name.
+ /// Flag specifying whether to make this context case sensitive or not.
+ /// The parent application context.
+ protected AbstractApplicationContext(string name, bool caseSensitive,
+ IApplicationContext parentApplicationContext)
+ {
+ _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name;
+ _caseSensitive = caseSensitive;
+ _parentApplicationContext = parentApplicationContext;
+ _objectFactoryPostProcessors = new ArrayList();
+ _defaultObjectPostProcessors = new ArrayList();
+ AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker());
+ AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this));
+ }
+
+ ///
+ /// Adds the given to the list of standard
+ /// processors being added to the underlying
+ ///
+ ///
+ /// Each time is called on this context, the context ensures, that
+ /// all default s are registered with the underlying .
+ ///
+ /// The instance.
+ protected void AddDefaultObjectPostProcessor(IObjectPostProcessor defaultObjectPostProcessor)
+ {
+ _defaultObjectPostProcessors.Add(defaultObjectPostProcessor);
+ }
+
+ ///
+ /// Closes this context and disposes of any resources (such as
+ /// singleton objects in the wrapped
+ /// ).
+ ///
+ public virtual void Dispose()
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Closing application context [{0}].",
+ Name));
+ }
+
+ #endregion
+
+ new DefensiveEventRaiser().Raise(
+ ContextEvent, this,
+ new ContextEventArgs(ContextEventArgs.ContextEvent.Closed));
+ ObjectFactory.Dispose();
+ }
+
+ #endregion
+
+ #region Abstract Methods
+
+ ///
+ /// Subclasses must implement this method to perform the actual
+ /// configuration loading.
+ ///
+ ///
+ ///
+ /// This method is invoked by
+ /// ,
+ /// before any other initialization occurs.
+ ///
+ ///
+ ///
+ /// In the case of errors encountered while refreshing the object factory.
+ ///
+ protected abstract void RefreshObjectFactory();
+
+ #endregion
+
+ ///
+ /// An object that can be used to synchronize access to the
+ ///
+ public object SyncRoot
+ {
+ get { return this; }
+ }
+
+ ///
+ /// The timestamp when this context was first loaded.
+ ///
+ ///
+ /// The timestamp (milliseconds) when this context was first loaded.
+ ///
+ public long StartupDateMilliseconds
+ {
+ get { return (StartupDate.Ticks - TicksAtEpoch)/10000; }
+ }
+
+
+ ///
+ /// Gets a flag indicating whether context should be case sensitive.
+ ///
+ /// true if object lookups are case sensitive; otherwise, false.
+ protected bool CaseSensitive
+ {
+ get { return _caseSensitive; }
+ }
+
+ ///
+ /// The for this context.
+ ///
+ ///
+ /// If the context has not been initialized yet.
+ ///
+ public IMessageSource MessageSource
+ {
+ get
+ {
+ if (_messageSource == null)
+ {
+ throw new InvalidOperationException(
+ "MessageSource not initialized - call 'Refresh()' " +
+ "before accessing messages via the context: " + this);
+ }
+ return _messageSource;
+ }
+ }
+
+ ///
+ /// The for this context.
+ ///
+ ///
+ /// If the context has not been initialized yet.
+ ///
+ public IEventRegistry EventRegistry
+ {
+ get
+ {
+ if (_eventRegistry == null)
+ {
+ throw new InvalidOperationException(
+ "EventRegistry not initialized - call 'Refresh()' " +
+ "before accessing the event registry via the context: " + this);
+ }
+ return _eventRegistry;
+ }
+ }
+
+ ///
+ /// Returns the internal object factory of the parent context if it implements
+ /// ; else,
+ /// returns the parent context itself.
+ ///
+ ///
+ /// The parent context's object factory, or the parent itself.
+ ///
+ protected IObjectFactory GetInternalParentObjectFactory()
+ {
+ IConfigurableApplicationContext configContext
+ = _parentApplicationContext as IConfigurableApplicationContext;
+ if (configContext != null)
+ {
+ return ((IConfigurableApplicationContext)
+ _parentApplicationContext).ObjectFactory;
+ }
+ else
+ {
+ return _parentApplicationContext;
+ }
+ }
+
+ ///
+ /// Raises an application context event.
+ ///
+ ///
+ /// Any arguments to the event. May be .
+ ///
+ protected virtual void OnContextEvent(ApplicationEventArgs e)
+ {
+ OnContextEvent(this, e);
+ }
+
+ ///
+ /// Raises an application context event.
+ ///
+ ///
+ /// The source of the event.
+ ///
+ ///
+ /// Any arguments to the event. May be .
+ ///
+ protected virtual void OnContextEvent(object source, ApplicationEventArgs e)
+ {
+ new DefensiveEventRaiser().Raise(ContextEvent, source, e);
+ }
+
+ ///
+ /// Modify the application context's internal object factory after its standard
+ /// initialization.
+ ///
+ ///
+ ///
+ /// All object definitions will have been loaded, but no objects
+ /// will have been instantiated yet. This allows for the registration
+ /// of special
+ /// s
+ /// in certain
+ /// implementations.
+ ///
+ ///
+ ///
+ /// The object factory used by the application context.
+ ///
+ ///
+ /// In the case of errors.
+ /// .
+ protected virtual void PostProcessObjectFactory(
+ IConfigurableListableObjectFactory objectFactory)
+ {
+ }
+
+ ///
+ /// Template method which can be overridden to add context-specific
+ /// refresh work.
+ ///
+ ///
+ ///
+ /// Called on initialization of special objects, before instantiation
+ /// of singletons.
+ ///
+ ///
+ protected virtual void OnRefresh()
+ {
+ }
+
+ ///
+ /// Instantiate and invoke all registered
+ ///
+ /// objects, respecting any explicit ordering.
+ ///
+ ///
+ ///
+ /// Must be called before singleton instantiation.
+ ///
+ ///
+ /// In the case of errors.
+ private void InvokeObjectFactoryPostProcessors()
+ {
+ // do NOT include IFactoryObjects; they (typically) need to be instantiated
+ // to determine the Type of object that they create, and if they are instantiated
+ // then we won't be able to do any factory post processin' on 'em...
+ string[] factoryProcessorNames
+ = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false);
+ ArrayList orderedFactoryProcessors = new ArrayList();
+ IList nonOrderedFactoryProcessorNames = new ArrayList();
+ for (int i = 0; i < factoryProcessorNames.Length; ++i)
+ {
+ string processorName = factoryProcessorNames[i];
+ object processor = GetObject(processorName);
+ if (typeof(IOrdered).IsAssignableFrom(GetType(processorName)))
+ {
+ orderedFactoryProcessors.Add(processor);
+ }
+ else
+ {
+ nonOrderedFactoryProcessorNames.Add(processor);
+ }
+ }
+ // first, invoke those IObjectFactoryPostProcessors that implement IOrdered...
+ orderedFactoryProcessors.Sort(new OrderComparator());
+ ProcessObjectFactoryPostProcessors(orderedFactoryProcessors);
+ // and then the unordered ones...
+ ProcessObjectFactoryPostProcessors(nonOrderedFactoryProcessorNames);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "processed {0} IFactoryObjectPostProcessors defined in application context [{1}].",
+ factoryProcessorNames.Length,
+ Name));
+ }
+
+ #endregion
+ }
+
+ private void ProcessObjectFactoryPostProcessors(IList orderedFactoryProcessors)
+ {
+ foreach (IObjectFactoryPostProcessor processor in orderedFactoryProcessors)
+ {
+ processor.PostProcessObjectFactory(ObjectFactory);
+ }
+ }
+
+ private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
+ {
+ RegisterObjectPostProcessorChecker(objectFactory);
+ IDictionary dict = GetObjectsOfType(typeof(IObjectPostProcessor), true, false);
+ ArrayList objectProcessors = new ArrayList(dict.Values);
+ objectProcessors.Sort(new OrderComparator());
+ foreach (IObjectPostProcessor objectPostProcessor in objectProcessors)
+ {
+ ObjectFactory.AddObjectPostProcessor(objectPostProcessor);
+ }
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "processed {0} IObjectPostProcessors defined in application context [{1}].",
+ objectProcessors.Count,
+ Name));
+ }
+ }
+
+ ///
+ /// Register an IObjectPostProcessorChecker that logs an info
+ /// message when an object is created during IObjectPostProcessor
+ /// instantiation, i.e. when an object is not eligible for being
+ /// processed by all IObjectPostProcessors.
+ ///
+ private void RegisterObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory)
+ {
+ int objectPostProcessorCount
+ = ObjectFactory.ObjectPostProcessorCount + 1
+ + GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length;
+// ObjectFactory.AddObjectPostProcessor(
+// new ObjectPostProcessorChecker(objectFactory, objectPostProcessorCount));
+ ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount);
+ }
+
+ ///
+ /// Initializes the default event registry for this context.
+ ///
+ private void InitEventRegistry()
+ {
+ if (ContainsObject(EventRegistryObjectName))
+ {
+ object candidateRegistry = GetObject(EventRegistryObjectName);
+ if (candidateRegistry is IEventRegistry)
+ {
+ _eventRegistry = (IEventRegistry) candidateRegistry;
+
+ #region Instrumentation
+
+ log.Debug(StringUtils.Surround(
+ "Using IEventRegistry [", EventRegistry, "]"));
+
+ #endregion
+ }
+ else
+ {
+ _eventRegistry = new EventRegistry();
+
+ #region Instrumentation
+
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(string.Format(
+ "Found object in context named '{0}' : this name " +
+ "is typically reserved for IEventRegistry objects. " +
+ "Falling back to default '{1}'.",
+ EventRegistryObjectName, EventRegistry));
+ }
+
+ #endregion
+ }
+ }
+ else
+ {
+ _eventRegistry = new EventRegistry();
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No IEventRegistry found with name '{0}' : using default '{1}'.",
+ EventRegistryObjectName, EventRegistry));
+ }
+
+ #endregion
+ }
+ ICollection interestedParties
+ = GetObjectsOfType(typeof(IEventRegistryAware), true, false).Values;
+ foreach (IEventRegistryAware party in interestedParties)
+ {
+ party.EventRegistry = EventRegistry;
+ }
+ EventRegistry.PublishEvents(this);
+ }
+
+ ///
+ /// Returns the internal message source of the parent context if said
+ /// parent context is an , else
+ /// simply the parent context itself.
+ ///
+ ///
+ /// The internal message source of the parent context if said
+ /// parent context is an , else
+ /// simply the parent context itself.
+ ///
+ protected virtual IMessageSource GetInternalParentMessageSource()
+ {
+ AbstractApplicationContext parent
+ = ParentContext as AbstractApplicationContext;
+ return parent == null ? ParentContext : parent._messageSource;
+ }
+
+ ///
+ /// Initializes the default message source for this context.
+ ///
+ ///
+ ///
+ /// Uses any parent context's message source if one is not available
+ /// in this context.
+ ///
+ ///
+ private void InitMessageSource()
+ {
+ if (ContainsObject(MessageSourceObjectName))
+ {
+ object candidateSource = GetObject(MessageSourceObjectName);
+ if (candidateSource is IMessageSource)
+ {
+ _messageSource
+ = (IMessageSource) GetObject(MessageSourceObjectName);
+
+ // make IMessageSource aware of any parent IMessageSource...
+ if (ParentContext != null)
+ {
+ IHierarchicalMessageSource hierSource
+ = MessageSource as IHierarchicalMessageSource;
+ if (hierSource != null)
+ {
+ IMessageSource parentMessageSource
+ = GetInternalParentMessageSource();
+ hierSource.ParentMessageSource = parentMessageSource;
+ }
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(StringUtils.Surround(
+ "Using MessageSource [", MessageSource, "]"));
+ }
+
+ #endregion
+ }
+ else
+ {
+ _messageSource = new DelegatingMessageSource(
+ GetInternalParentMessageSource());
+
+ #region Instrumentation
+
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(string.Format(
+ "Found object in context named '{0}' : this name " +
+ "is typically reserved for IMessageSource objects. " +
+ "Falling back to default '{1}'.",
+ MessageSourceObjectName, MessageSource));
+ }
+
+ #endregion
+ }
+ }
+ else if (ParentContext != null)
+ {
+ _messageSource = new DelegatingMessageSource(
+ GetInternalParentMessageSource());
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No message source found in the current context: using parent context's message source '{0}'.",
+ MessageSource));
+ }
+
+ #endregion
+ }
+ else
+ {
+ _messageSource = new StaticMessageSource();
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "No IMessageSource found with name '{0}' : using default '{1}'.",
+ MessageSourceObjectName, MessageSource));
+ }
+
+ #endregion
+ }
+ }
+
+ private void RefreshApplicationEventListeners()
+ {
+ ICollection listeners
+ = GetObjectsOfType(
+ typeof(IApplicationEventListener), true, false).Values;
+ foreach (IApplicationEventListener applicationListener in listeners)
+ {
+ EventRegistry.Subscribe(applicationListener);
+ }
+ }
+
+ ///
+ /// Returns the list of the
+ /// s
+ /// that will be applied to the objects created with this factory.
+ ///
+ ///
+ ///
+ /// The elements of this list are instances of implementations of the
+ ///
+ /// interface.
+ ///
+ ///
+ ///
+ /// The list of the
+ /// s
+ /// that will be applied to the objects created with this factory.
+ ///
+ private IList ObjectFactoryPostProcessors
+ {
+ get { return _objectFactoryPostProcessors; }
+ }
+
+ #region IConfigurableApplicationContext Members
+
+ ///
+ /// Return the internal object factory of this application context.
+ ///
+ public abstract IConfigurableListableObjectFactory ObjectFactory { get; }
+
+ ///
+ /// Add a new
+ /// that will get applied to the internal object factory of this application context
+ /// on refresh, before any of the object definitions are evaluated.
+ ///
+ ///
+ /// The factory processor to register.
+ ///
+ public void AddObjectFactoryPostProcessor(
+ IObjectFactoryPostProcessor objectFactoryPostProcessor)
+ {
+ _objectFactoryPostProcessors.Add(objectFactoryPostProcessor);
+ }
+
+ ///
+ /// Load or refresh the persistent representation of the configuration,
+ /// which might an XML file, properties file, or relational database schema.
+ ///
+ ///
+ /// If the configuration cannot be loaded.
+ ///
+ ///
+ /// If the object factory could not be initialized.
+ ///
+ public virtual void Refresh()
+ {
+ lock (SyncRoot)
+ {
+
+ /*
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ StackTrace stackTrace = new StackTrace(1, true);
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Refreshing application context [{0}]. Called from:{1}",
+ Name, stackTrace));
+ }
+
+ #endregion
+ */
+
+ _startupDate = DateTime.Now;
+
+ RefreshObjectFactory();
+ IConfigurableListableObjectFactory objectFactory = ObjectFactory;
+
+ EnsureKnownObjectPostProcessors(objectFactory);
+ objectFactory.IgnoreDependencyType(typeof(IResourceLoader));
+ objectFactory.IgnoreDependencyType(typeof(IApplicationContext));
+
+ PostProcessObjectFactory(objectFactory);
+ foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors)
+ {
+ factoryProcessor.PostProcessObjectFactory(objectFactory);
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} objects defined in application context [{1}].",
+ ObjectDefinitionCount == 0 ? "No" : ObjectDefinitionCount.ToString(),
+ Name));
+ }
+
+ #endregion
+
+ InvokeObjectFactoryPostProcessors();
+ RegisterObjectPostProcessors(objectFactory);
+ InitEventRegistry();
+ InitMessageSource();
+ OnRefresh();
+ RefreshApplicationEventListeners();
+
+ objectFactory.PreInstantiateSingletons();
+
+ new DefensiveEventRaiser().Raise(
+ ContextEvent, this,
+ new ContextEventArgs(ContextEventArgs.ContextEvent.Refreshed));
+ }
+ }
+
+ ///
+ /// Ensures, that predefined ObjectPostProcessors are registered with this ObjectFactory
+ ///
+ ///
+ protected void EnsureKnownObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
+ {
+ // index 0 contains the ObjectPostProcessorChecker that is handled separately!
+ for (int i = 1; i < _defaultObjectPostProcessors.Count; i++)
+ {
+ objectFactory.AddObjectPostProcessor((IObjectPostProcessor) this._defaultObjectPostProcessors[i]);
+ }
+ }
+
+ ///
+ /// Gets the parent context, or if there is no
+ /// parent context.
+ ///
+ ///
+ /// The parent context, or if there is no
+ /// parent.
+ ///
+ ///
+ public virtual IApplicationContext ParentContext
+ {
+ get { return _parentApplicationContext; }
+ set { _parentApplicationContext = value; }
+ }
+
+ #endregion
+
+ #region IApplicationContext Members
+
+ ///
+ /// Raised in response to an implementation-dependant application
+ /// context event.
+ ///
+ public event ApplicationEventHandler ContextEvent;
+
+ ///
+ /// The date and time this context was first loaded.
+ ///
+ ///
+ /// The representing when this context
+ /// was first loaded.
+ ///
+ public DateTime StartupDate
+ {
+ get { return _startupDate; }
+ }
+
+ ///
+ /// A name for this context.
+ ///
+ ///
+ /// A name for this context.
+ ///
+ public string Name
+ {
+ get { return _name; }
+ set { _name = value; }
+ }
+
+
+
+ #endregion
+
+ #region IListableObjectFactory Members
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectNamesForType(Type type)
+ {
+ return ObjectFactory.GetObjectNamesForType(type);
+ }
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s).
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectNamesForType(
+ Type type, bool includePrototypes, bool includeFactoryObjects)
+ {
+ return ObjectFactory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects);
+ }
+
+ ///
+ /// Return the names of all objects defined in this factory.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectDefinitionNames()
+ {
+ return ObjectFactory.GetObjectDefinitionNames();
+ }
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public virtual IObjectDefinition GetObjectDefinition(string name)
+ {
+ return ObjectFactory.GetObjectDefinition(name);
+ }
+
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ /// Whether to search parent object factories.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
+ {
+ return ObjectFactory.GetObjectDefinition(name, includeAncestors);
+ }
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ /// The (class or interface) to match.
+ ///
+ ///
+ /// A of the matching objects,
+ /// containing the object names as keys and the corresponding object instances
+ /// as values.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ public IDictionary GetObjectsOfType(Type type)
+ {
+ return GetObjectsOfType(type, true, true);
+ }
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ /// The (class or interface) to match.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s).
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// A of the matching objects,
+ /// containing the object names as keys and the corresponding object instances
+ /// as values.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ public IDictionary GetObjectsOfType(
+ Type type, bool includePrototypes, bool includeFactoryObjects)
+ {
+ return ObjectFactory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
+ }
+
+ ///
+ /// Return the number of objects defined in the factory.
+ ///
+ ///
+ /// The number of objects defined in the factory.
+ ///
+ ///
+ public int ObjectDefinitionCount
+ {
+ get { return ObjectFactory.ObjectDefinitionCount; }
+ }
+
+ ///
+ /// Check if this object factory contains an object definition with the given name.
+ ///
+ /// The name of the object to look for.
+ ///
+ /// True if this object factory contains an object definition with the given name.
+ ///
+ ///
+ public bool ContainsObjectDefinition(string name)
+ {
+ return ObjectFactory.ContainsObjectDefinition(name);
+ }
+
+ #endregion
+
+ #region IObjectFactory Members
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ public object this[string name]
+ {
+ get { return ObjectFactory.GetObject(name); }
+ }
+
+ ///
+ /// Does this object factory contain an object with the given name?
+ ///
+ /// The name of the object to query.
+ ///
+ /// if an object with the given name is defined.
+ ///
+ ///
+ public bool ContainsObject(string name)
+ {
+ return ObjectFactory.ContainsObject(name);
+ }
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ /// The object name to check for aliases.
+ /// The aliases, or an empty array if none.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ public string[] GetAliases(string name)
+ {
+ return ObjectFactory.GetAliases(name);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ public object GetObject(string name, Type requiredType)
+ {
+ return ObjectFactory.GetObject(name, requiredType);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ public object GetObject(string name)
+ {
+ return ObjectFactory.GetObject(name);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. If there is no factory method and the
+ /// arguments are not null, then match the argument values by type and
+ /// call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public object GetObject(string name, object[] arguments)
+ {
+ return ObjectFactory.GetObject(name, arguments);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public object GetObject(string name, Type requiredType, object[] arguments)
+ {
+ return ObjectFactory.GetObject(name, requiredType, arguments);
+ }
+
+ ///
+ /// Is this object a singleton?
+ ///
+ /// The name of the object to query.
+ /// True if the named object is a singleton.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ public bool IsSingleton(string name)
+ {
+ return ObjectFactory.IsSingleton(name);
+ }
+
+ ///
+ /// Determines whether the specified object name is prototype. That is, will GetObject
+ /// always return independent instances?
+ ///
+ /// The name of the object to query
+ ///
+ /// true if the specified object name will always deliver independent instances; otherwise, false.
+ ///
+ /// This method returning false does not clearly indicate a singleton object.
+ /// It indicated non-independent instances, which may correspond to a scoped object as
+ /// well. use the IsSingleton property to explicitly check for a shared
+ /// singleton instance.
+ /// Translates aliases back to the corresponding canonical object name. Will ask the
+ /// parent factory if the object can not be found in this factory instance.
+ ///
+ ///
+ /// if there is no object with the given name.
+ public bool IsPrototype(string name)
+ {
+ return ObjectFactory.IsPrototype(name);
+ }
+
+
+ ///
+ /// Determines whether the object with the given name matches the specified type.
+ ///
+ /// More specifically, check whether a GetObject call for the given name
+ /// would return an object that is assignable to the specified target type.
+ /// Translates aliases back to the corresponding canonical bean name.
+ /// Will ask the parent factory if the bean cannot be found in this factory instance.
+ ///
+ /// The name of the object to query.
+ /// Type of the target to match against.
+ ///
+ /// true if the object type matches; otherwise, false
+ /// if it doesn't match or cannot be determined yet.
+ ///
+ /// Ff there is no object with the given name
+ ///
+ public bool IsTypeMatch(string name, Type targetType)
+ {
+ return ObjectFactory.IsTypeMatch(name, targetType);
+ }
+
+ ///
+ /// Determine the of the object with the
+ /// given name.
+ ///
+ /// The name of the object to query.
+ ///
+ /// The of the object, or
+ /// if not determinable.
+ ///
+ ///
+ public Type GetType(string name)
+ {
+ return ObjectFactory.GetType(name);
+ }
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the named object definition.
+ ///
+ ///
+ /// The object instance that is to be so configured.
+ ///
+ ///
+ /// The name of the object definition expressing the dependencies that are to
+ /// be injected into the supplied instance.
+ ///
+ ///
+ public object ConfigureObject(object target, string name)
+ {
+ return ObjectFactory.ConfigureObject(target, name);
+ }
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the supplied .
+ ///
+ ///
+ /// The object instance that is to be so configured.
+ ///
+ ///
+ /// The name of the object definition expressing the dependencies that are to
+ /// be injected into the supplied instance.
+ ///
+ ///
+ /// An object definition that should be used to configure object.
+ ///
+ ///
+ public object ConfigureObject(object target, string name, IObjectDefinition definition)
+ {
+ return ObjectFactory.ConfigureObject(target, name, definition);
+ }
+
+ #endregion
+
+ #region IHierarchicalObjectFactory Members
+
+ ///
+ /// Return the parent object factory, or if there is none.
+ ///
+ ///
+ /// The parent object factory, or if there is none.
+ ///
+ ///
+ public IObjectFactory ParentObjectFactory
+ {
+ get { return _parentApplicationContext; }
+ }
+
+ #endregion
+
+ #region IMessageSource Members
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(
+ string name, CultureInfo culture, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The default message.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, defaultMessage, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ public string GetMessage(string name)
+ {
+ return MessageSource.GetMessage(name);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, params object[] arguments)
+ {
+ return MessageSource.GetMessage(name, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If no message could be resolved.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public string GetMessage(string name, CultureInfo culture)
+ {
+ return MessageSource.GetMessage(name, culture);
+ }
+
+ ///
+ /// Resolve the message using all of the attributes contained within
+ /// the supplied
+ /// argument.
+ ///
+ ///
+ /// The value object storing those attributes that are required to
+ /// properly resolve a message.
+ ///
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
+ {
+ return MessageSource.GetMessage(resolvable, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ object IMessageSource.GetResourceObject(string name, CultureInfo culture)
+ {
+ return GetResourceObject(name, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ object IMessageSource.GetResourceObject(string name)
+ {
+ return GetResourceObject(name);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name, CultureInfo culture)
+ {
+ return MessageSource.GetResourceObject(name, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name)
+ {
+ return MessageSource.GetResourceObject(name);
+ }
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ /// An object that contains the property values to be applied.
+ ///
+ ///
+ /// The base name of the object to use for key lookup.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ public void ApplyResources(object value, string objectName, CultureInfo culture)
+ {
+ MessageSource.ApplyResources(value, objectName, culture);
+ }
+
+ #endregion
+
+ #region IEventRegistry Members
+
+ ///
+ /// Publishes all events of the source object.
+ ///
+ ///
+ /// The source object containing events to publish.
+ ///
+ ///
+ public void PublishEvents(object sourceObject)
+ {
+ _eventRegistry.PublishEvents(sourceObject);
+ }
+
+ ///
+ /// Subscribes to all events published, if the subscriber
+ /// implements compatible handler methods.
+ ///
+ /// The subscriber to use.
+ ///
+ public void Subscribe(object subscriber)
+ {
+ _eventRegistry.Subscribe(subscriber);
+ }
+
+ ///
+ /// Subscribes to published events of a all objects of a given
+ /// , if the subscriber implements
+ /// compatible handler methods.
+ ///
+ /// The subscriber to use.
+ ///
+ /// The target to subscribe to.
+ ///
+ ///
+ public void Subscribe(object subscriber, Type targetSourceType)
+ {
+ _eventRegistry.Subscribe(subscriber, targetSourceType);
+ }
+
+ #endregion
+
+ ///
+ /// Publishes an application context event.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The source of the event. May be .
+ ///
+ ///
+ /// The event that is to be raised.
+ ///
+ ///
+ public void PublishEvent(object sender, ApplicationEventArgs e)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Publishing event in context [{0}] : {1}",
+ Name, e));
+ }
+
+ #endregion
+
+ OnContextEvent(sender, e);
+
+ if (ParentContext != null)
+ {
+ ParentContext.PublishEvent(sender, e);
+ }
+ }
+
+ #region IPostProcessor implementation
+
+ private sealed class ObjectPostProcessorChecker : IObjectPostProcessor
+ {
+ private int _objectPostProcessorTargetCount;
+ private IConfigurableListableObjectFactory _objectFactory;
+
+
+ public ObjectPostProcessorChecker()
+ {
+ }
+
+// public ObjectPostProcessorChecker(
+// IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount)
+// {
+// _objectFactory = objectFactory;
+// _objectPostProcessorTargetCount = objectPostProcessorTargetCount;
+// }
+
+ public void Reset(IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount)
+ {
+ _objectFactory = objectFactory;
+ _objectPostProcessorTargetCount = objectPostProcessorTargetCount;
+ }
+
+ public object PostProcessBeforeInitialization(object obj, string name)
+ {
+ return obj;
+ }
+
+ public object PostProcessAfterInitialization(object obj, string objectName)
+ {
+ if (_objectFactory.ObjectPostProcessorCount < _objectPostProcessorTargetCount)
+ {
+ #region Instrumentation
+
+ if (log.IsInfoEnabled)
+ {
+ log.Info(string.Format(
+ "Object '{0}' is not eligible for being processed by all " +
+ "IObjectPostProcessors (for example: not eligible for auto-proxying).", objectName));
+ }
+
+ #endregion
+ }
+ return obj;
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs b/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs
index 0c426817..ec211c66 100644
--- a/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs
+++ b/src/Spring/Spring.Core/Context/Support/AbstractMessageSource.cs
@@ -1,617 +1,616 @@
-#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
-{
- ///
- /// Abstract implementation of the interface,
- /// implementing common handling of message variants, making it easy
- /// to implement a specific strategy for a concrete .
- ///
- ///
- ///
Subclasses must implement the abstract ResolveObject
- /// method.
- ///
Note: 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.
- ///
- ///
Supports not only IMessageSourceResolvables as primary messages
- /// but also resolution of message arguments that are in turn
- /// IMessageSourceResolvables themselves.
- ///
- ///
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.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Griffin Caprio (.NET)
- /// Harald Radi (.NET)
- /// $Id: AbstractMessageSource.cs,v 1.23 2007/08/28 14:16:15 oakinger Exp $
- ///
- ///
- ///
- public abstract class AbstractMessageSource : IHierarchicalMessageSource
- {
- #region Fields
-
- ///
- /// holds the logger instance shared with subclasses.
- ///
- protected readonly ILog log;
-
- private IMessageSource parentMessageSource;
- private bool useCodeAsDefaultMessage = false;
-
- #endregion
-
- #region Constructor
-
- ///
- /// Initializes this instance.
- ///
- protected AbstractMessageSource()
- {
- log = LogManager.GetLogger(GetType());
- }
-
- #endregion
-
- #region Properties
-
-
- /// 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".
- ///
- ///
- ///
Note: In case of a IMessageSourceResolvable with multiple codes
- /// (like a FieldError) and a MessageSource that has a parent MessageSource,
- /// do not activate "UseCodeAsDefaultMessage" in the parent:
- /// Else, you'll get the first code returned as message by the parent,
- /// without attempts to check further codes.
- ///
To be able to work with "UseCodeAsDefaultMessage" turned on in the parent,
- /// AbstractMessageSource contains special checks
- /// to delegate to the internal GetMessageInternal 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.
- ///
Alternatively, consider overriding the GetDefaultMessage
- /// method to return a custom fallback message for an unresolvable code.
- ///
- ///
- /// true if use the message code as default message instead of
- /// throwing a NoSuchMessageException; otherwise, false.
- ///
- public bool UseCodeAsDefaultMessage
- {
- get { return useCodeAsDefaultMessage; }
- set { useCodeAsDefaultMessage = value; }
- }
-
- #endregion
-
- #region IHierarchicalMessageSource Members
-
- ///
- /// The parent message source used to try and resolve messages that
- /// this object can't resolve.
- ///
- ///
- ///
- ///
- /// If the value of this property is then no
- /// further resolution is possible.
- ///
- ///
- public IMessageSource ParentMessageSource
- {
- get { return parentMessageSource; }
- set { parentMessageSource = value; }
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If the lookup is not successful throw NoSuchMessageException
- ///
- public string GetMessage(string name)
- {
- return GetMessage(name, CultureInfo.CurrentUICulture, null);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful, implementations are permitted to
- /// take one of two actions.
- ///
- /// If the lookup is not successful throw NoSuchMessageException
- ///
- public string GetMessage(string name, CultureInfo culture)
- {
- return GetMessage(name, culture, null);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// If the lookup is not successful throw NoSuchMessageException
- ///
- public string GetMessage(string name, params object[] arguments)
- {
- return GetMessage(name, CultureInfo.CurrentUICulture, arguments);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The that represents
- /// the culture for which the resource is localized.
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful throw NoSuchMessageException.
- ///
- ///
- 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);
- }
-
- ///
- /// Resolve the message identified by the supplied
- /// .
- ///
- /// The name of the message to resolve.
- /// The default message if name is not found.
- /// The that represents
- /// the culture for which the resource is localized.
- /// The array of arguments that will be filled in for parameters within
- /// the message, or if there are no parameters
- /// within the message. Parameters within a message should be
- /// referenced using the same syntax as the format string for the
- /// method.
- ///
- /// The resolved message if the lookup was successful (see above for
- /// the return value in the case of an unsuccessful lookup).
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- /// If the lookup is not successful throw NoSuchMessageException
- ///
- ///
- 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);
- }
-
- ///
- /// Resolve the message using all of the attributes contained within
- /// the supplied
- /// argument.
- ///
- /// The value object storing those attributes that are required to
- /// properly resolve a message.
- /// The that represents
- /// the culture for which the resource is localized.
- ///
- /// The resolved message if the lookup was successful.
- ///
- ///
- /// If the message could not be resolved.
- ///
- 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);
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The resolved object, or if not found.
- ///
- ///
- public object GetResourceObject(string name)
- {
- object resource = GetResourceInternal(name, CultureInfo.CurrentUICulture);
- if (resource != null) return resource;
- if (ParentMessageSource != null)
- return ParentMessageSource.GetResourceObject(name, CultureInfo.CurrentUICulture);
- return null;
- }
-
- ///
- /// Gets a localized resource object identified by the supplied
- /// .
- ///
- ///
- /// Note that the fallback behavior based on CultureInfo seem to
- /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
- ///
- ///
- /// The name of the resource object to resolve.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- /// The resolved object, or 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.
- ///
- ///
- 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;
- }
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- ///
- public void ApplyResources(
- object value, string objectName, CultureInfo culture)
- {
- ApplyResourcesInternal(value, objectName, culture);
- if (ParentMessageSource != null) ParentMessageSource.ApplyResources(value, objectName, culture);
- }
-
- #endregion
-
- #region Protected Methods
-
- /// Resolve the given code and arguments as message in the given culture,
- /// returning null if not found. Does not fall back to the code
- /// as default message. Invoked by GetMessage methods.
- ///
- /// The code to lookup up, such as 'calculator.noRateSet'.
- /// array of arguments that will be filled in for params
- /// within the message.
- /// The with which the
- /// resource is associated.
- ///
- /// The resolved message if the lookup was successful.
- ///
- 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);
- }
-
-
- ///
- /// Try to retrieve the given message from the parent MessageSource, if any.
- ///
- /// The code to lookup up, such as 'calculator.noRateSet'.
- /// array of arguments that will be filled in for params
- /// within the message.
- /// The with which the
- /// resource is associated.
- ///
- /// The resolved message if the lookup was successful.
- ///
- 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;
- }
-
-
- ///
- /// Return a fallback default message for the given code, if any.
- ///
- ///
- /// 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
- ///
- /// The code to lookup up, such as 'calculator.noRateSet'.
- /// The default message to use, or null if none.
- protected virtual string GetDefaultMessage(string code)
- {
- if (UseCodeAsDefaultMessage) return code;
- return null;
- }
-
-
-
- ///
- /// 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.
- ///
- /// 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.
- ///
- /// The default message.
- /// The array of agruments that will be filled in for parameter
- /// placeholders within the message, or null if none.
- /// The with which the
- /// resource is associated.
- /// The rendered default message (with resolved arguments)
- protected virtual string RenderDefaultMessage(string defaultMessage, object[] args, CultureInfo culture)
- {
- return FormatMessage(defaultMessage, args, culture);
- }
-
- ///
- /// Format the given default message String resolving any
- /// agrument placeholders found in them.
- ///
- /// The message to format.
- /// The array of agruments that will be filled in for parameter
- /// placeholders within the message, or null if none.
- /// The with which the
- /// resource is associated.
- /// The formatted message (with resolved arguments)
- 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);
- }
-
-
- ///
- /// Search through the given array of objects, find any
- /// MessageSourceResolvable objects and resolve them.
- ///
- ///
- /// Allows for messages to have MessageSourceResolvables as arguments.
- ///
- ///
- /// The array of arguments for a message.
- /// The with which the
- /// resource is associated.
- /// An array of arguments with any IMessageSourceResolvables resolved
- 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;
- }
-
- ///
- /// Gets the specified resource (e.g. Icon or Bitmap).
- ///
- /// The name of the resource to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- /// The resource if found. otherwise.
- protected object GetResourceInternal(string name, CultureInfo cultureInfo)
- {
- if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
- if (name == null) return null;
- return ResolveObject(name, cultureInfo);
- }
-
- ///
- /// Applies resources from the given name on the specified object.
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- protected void ApplyResourcesInternal(object value, string objectName, CultureInfo cultureInfo)
- {
- if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
- ApplyResourcesToObject(value, objectName, cultureInfo);
- }
-
- #endregion
-
- #region Protected Abstract Methods
-
- ///
- /// Subclasses must implement this method to resolve a message.
- ///
- /// The code to lookup up, such as 'calculator.noRateSet'.
- /// The with which the
- /// resource is associated.
- /// The resolved message from the backing store of message data.
- protected abstract string ResolveMessage(string code, CultureInfo cultureInfo);
-
- ///
- /// Resolves an object (typically an icon or bitmap).
- ///
- ///
- ///
- /// Subclasses must implement this method to resolve an object.
- ///
- ///
- /// The code of the object to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- ///
- /// The resolved object or if not found.
- ///
- protected abstract object ResolveObject(string code, CultureInfo cultureInfo);
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- ///
- /// Subclasses must implement this method to apply resources
- /// to an arbitrary object.
- ///
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- protected abstract void ApplyResourcesToObject(object value, string objectName, CultureInfo cultureInfo);
-
-
- #endregion
-
- }
+#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
+{
+ ///
+ /// Abstract implementation of the interface,
+ /// implementing common handling of message variants, making it easy
+ /// to implement a specific strategy for a concrete .
+ ///
+ ///
+ ///
Subclasses must implement the abstract ResolveObject
+ /// method.
+ ///
Note: 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.
+ ///
+ ///
Supports not only IMessageSourceResolvables as primary messages
+ /// but also resolution of message arguments that are in turn
+ /// IMessageSourceResolvables themselves.
+ ///
+ ///
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.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Griffin Caprio (.NET)
+ /// Harald Radi (.NET)
+ ///
+ ///
+ ///
+ public abstract class AbstractMessageSource : IHierarchicalMessageSource
+ {
+ #region Fields
+
+ ///
+ /// holds the logger instance shared with subclasses.
+ ///
+ protected readonly ILog log;
+
+ private IMessageSource parentMessageSource;
+ private bool useCodeAsDefaultMessage = false;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes this instance.
+ ///
+ protected AbstractMessageSource()
+ {
+ log = LogManager.GetLogger(GetType());
+ }
+
+ #endregion
+
+ #region Properties
+
+
+ /// 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".
+ ///
+ ///
+ ///
Note: In case of a IMessageSourceResolvable with multiple codes
+ /// (like a FieldError) and a MessageSource that has a parent MessageSource,
+ /// do not activate "UseCodeAsDefaultMessage" in the parent:
+ /// Else, you'll get the first code returned as message by the parent,
+ /// without attempts to check further codes.
+ ///
To be able to work with "UseCodeAsDefaultMessage" turned on in the parent,
+ /// AbstractMessageSource contains special checks
+ /// to delegate to the internal GetMessageInternal 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.
+ ///
Alternatively, consider overriding the GetDefaultMessage
+ /// method to return a custom fallback message for an unresolvable code.
+ ///
+ ///
+ /// true if use the message code as default message instead of
+ /// throwing a NoSuchMessageException; otherwise, false.
+ ///
+ public bool UseCodeAsDefaultMessage
+ {
+ get { return useCodeAsDefaultMessage; }
+ set { useCodeAsDefaultMessage = value; }
+ }
+
+ #endregion
+
+ #region IHierarchicalMessageSource Members
+
+ ///
+ /// The parent message source used to try and resolve messages that
+ /// this object can't resolve.
+ ///
+ ///
+ ///
+ ///
+ /// If the value of this property is then no
+ /// further resolution is possible.
+ ///
+ ///
+ public IMessageSource ParentMessageSource
+ {
+ get { return parentMessageSource; }
+ set { parentMessageSource = value; }
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the lookup is not successful throw NoSuchMessageException
+ ///
+ public string GetMessage(string name)
+ {
+ return GetMessage(name, CultureInfo.CurrentUICulture, null);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful, implementations are permitted to
+ /// take one of two actions.
+ ///
+ /// If the lookup is not successful throw NoSuchMessageException
+ ///
+ public string GetMessage(string name, CultureInfo culture)
+ {
+ return GetMessage(name, culture, null);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the lookup is not successful throw NoSuchMessageException
+ ///
+ public string GetMessage(string name, params object[] arguments)
+ {
+ return GetMessage(name, CultureInfo.CurrentUICulture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The that represents
+ /// the culture for which the resource is localized.
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful throw NoSuchMessageException.
+ ///
+ ///
+ 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);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The default message if name is not found.
+ /// The that represents
+ /// the culture for which the resource is localized.
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ /// If the lookup is not successful throw NoSuchMessageException
+ ///
+ ///
+ 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);
+ }
+
+ ///
+ /// Resolve the message using all of the attributes contained within
+ /// the supplied
+ /// argument.
+ ///
+ /// The value object storing those attributes that are required to
+ /// properly resolve a message.
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ 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);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name)
+ {
+ object resource = GetResourceInternal(name, CultureInfo.CurrentUICulture);
+ if (resource != null) return resource;
+ if (ParentMessageSource != null)
+ return ParentMessageSource.GetResourceObject(name, CultureInfo.CurrentUICulture);
+ return null;
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// Note that the fallback behavior based on CultureInfo seem to
+ /// have a bug that is fixed by installed .NET 1.1 Service Pack 1.
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or 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.
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ /// An object that contains the property values to be applied.
+ ///
+ ///
+ /// The base name of the object to use for key lookup.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ public void ApplyResources(
+ object value, string objectName, CultureInfo culture)
+ {
+ ApplyResourcesInternal(value, objectName, culture);
+ if (ParentMessageSource != null) ParentMessageSource.ApplyResources(value, objectName, culture);
+ }
+
+ #endregion
+
+ #region Protected Methods
+
+ /// Resolve the given code and arguments as message in the given culture,
+ /// returning null if not found. Does not fall back to the code
+ /// as default message. Invoked by GetMessage methods.
+ ///
+ /// The code to lookup up, such as 'calculator.noRateSet'.
+ /// array of arguments that will be filled in for params
+ /// within the message.
+ /// The with which the
+ /// resource is associated.
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ 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);
+ }
+
+
+ ///
+ /// Try to retrieve the given message from the parent MessageSource, if any.
+ ///
+ /// The code to lookup up, such as 'calculator.noRateSet'.
+ /// array of arguments that will be filled in for params
+ /// within the message.
+ /// The with which the
+ /// resource is associated.
+ ///
+ /// The resolved message if the lookup was successful.
+ ///
+ 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;
+ }
+
+
+ ///
+ /// Return a fallback default message for the given code, if any.
+ ///
+ ///
+ /// 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
+ ///
+ /// The code to lookup up, such as 'calculator.noRateSet'.
+ /// The default message to use, or null if none.
+ protected virtual string GetDefaultMessage(string code)
+ {
+ if (UseCodeAsDefaultMessage) return code;
+ return null;
+ }
+
+
+
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// The default message.
+ /// The array of agruments that will be filled in for parameter
+ /// placeholders within the message, or null if none.
+ /// The with which the
+ /// resource is associated.
+ /// The rendered default message (with resolved arguments)
+ protected virtual string RenderDefaultMessage(string defaultMessage, object[] args, CultureInfo culture)
+ {
+ return FormatMessage(defaultMessage, args, culture);
+ }
+
+ ///
+ /// Format the given default message String resolving any
+ /// agrument placeholders found in them.
+ ///
+ /// The message to format.
+ /// The array of agruments that will be filled in for parameter
+ /// placeholders within the message, or null if none.
+ /// The with which the
+ /// resource is associated.
+ /// The formatted message (with resolved arguments)
+ 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);
+ }
+
+
+ ///
+ /// Search through the given array of objects, find any
+ /// MessageSourceResolvable objects and resolve them.
+ ///
+ ///
+ /// Allows for messages to have MessageSourceResolvables as arguments.
+ ///
+ ///
+ /// The array of arguments for a message.
+ /// The with which the
+ /// resource is associated.
+ /// An array of arguments with any IMessageSourceResolvables resolved
+ 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;
+ }
+
+ ///
+ /// Gets the specified resource (e.g. Icon or Bitmap).
+ ///
+ /// The name of the resource to resolve.
+ ///
+ /// The to resolve the
+ /// code for.
+ ///
+ /// The resource if found. otherwise.
+ protected object GetResourceInternal(string name, CultureInfo cultureInfo)
+ {
+ if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
+ if (name == null) return null;
+ return ResolveObject(name, cultureInfo);
+ }
+
+ ///
+ /// Applies resources from the given name on the specified object.
+ ///
+ ///
+ /// An object that contains the property values to be applied.
+ ///
+ ///
+ /// The base name of the object to use for key lookup.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ protected void ApplyResourcesInternal(object value, string objectName, CultureInfo cultureInfo)
+ {
+ if (cultureInfo == null) cultureInfo = CultureInfo.CurrentUICulture;
+ ApplyResourcesToObject(value, objectName, cultureInfo);
+ }
+
+ #endregion
+
+ #region Protected Abstract Methods
+
+ ///
+ /// Subclasses must implement this method to resolve a message.
+ ///
+ /// The code to lookup up, such as 'calculator.noRateSet'.
+ /// The with which the
+ /// resource is associated.
+ /// The resolved message from the backing store of message data.
+ protected abstract string ResolveMessage(string code, CultureInfo cultureInfo);
+
+ ///
+ /// Resolves an object (typically an icon or bitmap).
+ ///
+ ///
+ ///
+ /// Subclasses must implement this method to resolve an object.
+ ///
+ ///
+ /// The code of the object to resolve.
+ ///
+ /// The to resolve the
+ /// code for.
+ ///
+ ///
+ /// The resolved object or if not found.
+ ///
+ protected abstract object ResolveObject(string code, CultureInfo cultureInfo);
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ ///
+ /// Subclasses must implement this method to apply resources
+ /// to an arbitrary object.
+ ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- protected AbstractXmlApplicationContext() : this(null, true, null)
- {}
-
- ///
- /// Creates a new instance of the
- /// class
- /// with the given parent context.
- ///
- ///
- ///
- /// This is an class, and as such exposes
- /// no public constructors.
- ///
- ///
- /// The application context name.
- /// Flag specifying whether to make this context case sensitive or not.
- /// The parent context.
- protected AbstractXmlApplicationContext(string name, bool caseSensitive,
- IApplicationContext parentContext) : base(name, caseSensitive, parentContext)
- {}
-
- ///
- /// An array of resource locations, referring to the XML object
- /// definition files that this context is to be built with.
- ///
- ///
- ///
- /// Examples of the format of the various strings that would be
- /// returned by accessing this property can be found in the overview
- /// documentation of with the
- /// class.
- ///
- ///
- ///
- /// An array of resource locations, or if none.
- ///
- protected abstract string[] ConfigurationLocations { get; }
-
- ///
- /// Instantiates and populates the underlying
- /// with the object
- /// definitions yielded up by the
- /// method.
- ///
- ///
- /// In the case of errors encountered while refreshing the object factory.
- ///
- ///
- /// In the case of errors encountered reading any of the resources
- /// yielded by the method.
- ///
- ///
- protected override void RefreshObjectFactory()
- {
- // Shut down previous object factory, if any.
- IConfigurableListableObjectFactory oldObjectFactory = null;
- oldObjectFactory = _objectFactory;
-
- if (oldObjectFactory != null)
- {
- _objectFactory = null;
- oldObjectFactory.Dispose();
- }
-
- try
- {
- DefaultListableObjectFactory objectFactory = CreateObjectFactory();
- LoadObjectDefinitions(objectFactory);
-
- _objectFactory = objectFactory;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(
- "Refreshed ObjectFactory for application context '{0}'.",
- Name));
- }
-
- #endregion
- }
- catch (IOException ex)
- {
- throw new ApplicationContextException(
- string.Format(
- "I/O error parsing XML resource for application context '{0}'.",
- Name), ex);
- }
- catch (UriFormatException ex)
- {
- throw new ApplicationContextException(
- string.Format(
- "Error parsing resource locations [{0}] for application context '{1}'.",
- StringUtils.ArrayToCommaDelimitedString(ConfigurationLocations),
- Name), ex);
- }
- }
-
-
- ///
- /// Initialize the object definition reader used for loading the object
- /// definitions of this context.
- ///
- ///
- ///
- /// The default implementation of this method is a no-op; i.e. it does
- /// nothing. Can be overridden in subclasses to provide custom
- /// initialization of the supplied
- /// ; for example, a derived
- /// class may want to turn off XML validation.
- ///
- ///
- ///
- /// The object definition reader used by this context.
- ///
- protected virtual void InitObjectDefinitionReader(
- XmlObjectDefinitionReader objectDefinitionReader)
- {}
-
- ///
- /// Load the object definitions with the given
- /// .
- ///
- ///
- ///
- /// The lifecycle of the object factory is handled by
- /// ;
- /// therefore this method is just supposed to load and / or register
- /// object definitions.
- ///
- ///
- ///
- /// The reader containing object definitions.
- ///
- /// In case of object registration errors.
- ///
- ///
- /// In the case of errors encountered reading any of the resources
- /// yielded by the method.
- ///
- protected virtual void LoadObjectDefinitions(
- XmlObjectDefinitionReader objectDefinitionReader)
- {
- string[] locations = ConfigurationLocations;
- if (locations != null)
- {
- objectDefinitionReader.LoadObjectDefinitions(ConfigurationLocations);
- }
- }
-
-
- ///
- /// Loads the object definitions into the given object factory, typically through
- /// delegating to one or more object definition readers.
- ///
- /// The object factory to lead object definitions into
- ///
- ///
- protected virtual void LoadObjectDefinitions(DefaultListableObjectFactory objectFactory)
- {
- //Create a new XmlObjectDefinitionReader for the given ObjectFactory
- XmlObjectDefinitionReader objectDefinitionReader = new XmlObjectDefinitionReader(objectFactory);
-
- // Configure the bean definition reader with this context's
- // resource loading environment.
- objectDefinitionReader.ResourceLoader = this;
-
- // Allow a subclass to provide custom initialization of the reader,
- // then proceed with actually loading the object definitions.
- InitObjectDefinitionReader(objectDefinitionReader);
- LoadObjectDefinitions(objectDefinitionReader);
- }
-
- ///
- /// Customizes the internal object factory used by this context.
- ///
- /// Called for each attempt.
- ///
- /// The default implementation is empty. Can be overriden in subclassses to customize
- /// DefaultListableBeanFatory's standard settings.
- ///
- /// The newly created object factory for this context
- protected virtual void CustomizeObjectFactory(DefaultListableObjectFactory objectFactory)
- {
-
- }
-
- ///
- /// Create an internal object factory for this context.
- ///
- ///
- ///
- /// Called for each attempt.
- /// This default implementation creates a
- ///
- /// with the internal object factory of this context's parent serving
- /// as the parent object factory. Can be overridden in subclasse,s
- /// for example to customize DefaultListableBeanFactory's settings.
- ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ protected AbstractXmlApplicationContext() : this(null, true, null)
+ {}
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// with the given parent context.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes
+ /// no public constructors.
+ ///
+ ///
+ /// The application context name.
+ /// Flag specifying whether to make this context case sensitive or not.
+ /// The parent context.
+ protected AbstractXmlApplicationContext(string name, bool caseSensitive,
+ IApplicationContext parentContext) : base(name, caseSensitive, parentContext)
+ {}
+
+ ///
+ /// An array of resource locations, referring to the XML object
+ /// definition files that this context is to be built with.
+ ///
+ ///
+ ///
+ /// Examples of the format of the various strings that would be
+ /// returned by accessing this property can be found in the overview
+ /// documentation of with the
+ /// class.
+ ///
+ ///
+ ///
+ /// An array of resource locations, or if none.
+ ///
+ protected abstract string[] ConfigurationLocations { get; }
+
+ ///
+ /// Instantiates and populates the underlying
+ /// with the object
+ /// definitions yielded up by the
+ /// method.
+ ///
+ ///
+ /// In the case of errors encountered while refreshing the object factory.
+ ///
+ ///
+ /// In the case of errors encountered reading any of the resources
+ /// yielded by the method.
+ ///
+ ///
+ protected override void RefreshObjectFactory()
+ {
+ // Shut down previous object factory, if any.
+ IConfigurableListableObjectFactory oldObjectFactory = null;
+ oldObjectFactory = _objectFactory;
+
+ if (oldObjectFactory != null)
+ {
+ _objectFactory = null;
+ oldObjectFactory.Dispose();
+ }
+
+ try
+ {
+ DefaultListableObjectFactory objectFactory = CreateObjectFactory();
+ LoadObjectDefinitions(objectFactory);
+
+ _objectFactory = objectFactory;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(
+ "Refreshed ObjectFactory for application context '{0}'.",
+ Name));
+ }
+
+ #endregion
+ }
+ catch (IOException ex)
+ {
+ throw new ApplicationContextException(
+ string.Format(
+ "I/O error parsing XML resource for application context '{0}'.",
+ Name), ex);
+ }
+ catch (UriFormatException ex)
+ {
+ throw new ApplicationContextException(
+ string.Format(
+ "Error parsing resource locations [{0}] for application context '{1}'.",
+ StringUtils.ArrayToCommaDelimitedString(ConfigurationLocations),
+ Name), ex);
+ }
+ }
+
+
+ ///
+ /// Initialize the object definition reader used for loading the object
+ /// definitions of this context.
+ ///
+ ///
+ ///
+ /// The default implementation of this method is a no-op; i.e. it does
+ /// nothing. Can be overridden in subclasses to provide custom
+ /// initialization of the supplied
+ /// ; for example, a derived
+ /// class may want to turn off XML validation.
+ ///
+ ///
+ ///
+ /// The object definition reader used by this context.
+ ///
+ protected virtual void InitObjectDefinitionReader(
+ XmlObjectDefinitionReader objectDefinitionReader)
+ {}
+
+ ///
+ /// Load the object definitions with the given
+ /// .
+ ///
+ ///
+ ///
+ /// The lifecycle of the object factory is handled by
+ /// ;
+ /// therefore this method is just supposed to load and / or register
+ /// object definitions.
+ ///
+ ///
+ ///
+ /// The reader containing object definitions.
+ ///
+ /// In case of object registration errors.
+ ///
+ ///
+ /// In the case of errors encountered reading any of the resources
+ /// yielded by the method.
+ ///
+ protected virtual void LoadObjectDefinitions(
+ XmlObjectDefinitionReader objectDefinitionReader)
+ {
+ string[] locations = ConfigurationLocations;
+ if (locations != null)
+ {
+ objectDefinitionReader.LoadObjectDefinitions(ConfigurationLocations);
+ }
+ }
+
+
+ ///
+ /// Loads the object definitions into the given object factory, typically through
+ /// delegating to one or more object definition readers.
+ ///
+ /// The object factory to lead object definitions into
+ ///
+ ///
+ protected virtual void LoadObjectDefinitions(DefaultListableObjectFactory objectFactory)
+ {
+ //Create a new XmlObjectDefinitionReader for the given ObjectFactory
+ XmlObjectDefinitionReader objectDefinitionReader = new XmlObjectDefinitionReader(objectFactory);
+
+ // Configure the bean definition reader with this context's
+ // resource loading environment.
+ objectDefinitionReader.ResourceLoader = this;
+
+ // Allow a subclass to provide custom initialization of the reader,
+ // then proceed with actually loading the object definitions.
+ InitObjectDefinitionReader(objectDefinitionReader);
+ LoadObjectDefinitions(objectDefinitionReader);
+ }
+
+ ///
+ /// Customizes the internal object factory used by this context.
+ ///
+ /// Called for each attempt.
+ ///
+ /// The default implementation is empty. Can be overriden in subclassses to customize
+ /// DefaultListableBeanFatory's standard settings.
+ ///
+ /// The newly created object factory for this context
+ protected virtual void CustomizeObjectFactory(DefaultListableObjectFactory objectFactory)
+ {
+
+ }
+
+ ///
+ /// Create an internal object factory for this context.
+ ///
+ ///
+ ///
+ /// Called for each attempt.
+ /// This default implementation creates a
+ ///
+ /// with the internal object factory of this context's parent serving
+ /// as the parent object factory. Can be overridden in subclasse,s
+ /// for example to customize DefaultListableBeanFactory's settings.
+ ///
- /// If an object's class implements more than one of the
- /// ,
- /// , and
- /// interfaces, then the
- /// order in which the interfaces are satisfied is as follows...
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Application contexts will automatically register this with their
- /// underlying object factory. Applications should thus never need to use
- /// this class directly.
- ///
+ /// If an object's class implements more than one of the
+ /// ,
+ /// , and
+ /// interfaces, then the
+ /// order in which the interfaces are satisfied is as follows...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Application contexts will automatically register this with their
+ /// underlying object factory. Applications should thus never need to use
+ /// this class directly.
+ ///
- /// It saves the application context reference and provides an
- /// initialization callback method. Furthermore, it offers numerous
- /// convenience methods for message lookup.
- ///
- ///
- /// There is no requirement to subclass this class: it just makes things
- /// a little easier if you need access to the context, e.g. for access to
- /// file resources or to the message source. Note that many application
- /// objects do not need to be aware of the application context at all,
- /// as they can receive collaborating objects via object references.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Griffin Caprio (.NET)
- /// $Id: ApplicationObjectSupport.cs,v 1.8 2007/07/17 14:51:14 oakinger Exp $
- public abstract class ApplicationObjectSupport : IApplicationContextAware
- {
- private IApplicationContext _applicationContext;
- private MessageSourceAccessor _messageSourceAccessor;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected ApplicationObjectSupport()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- ///
- /// The that this
- /// object runs in.
- ///
- protected ApplicationObjectSupport(
- IApplicationContext applicationContext)
- {
- _applicationContext = applicationContext;
- }
-
- ///
- /// The context class that any context passed to the
- ///
- /// must be an instance of.
- ///
- ///
- /// The
- /// .
- ///
- protected virtual Type RequiredType
- {
- get { return typeof (IApplicationContext); }
- }
-
- ///
- /// Intializes the wrapped
- /// .
- ///
- ///
- ///
- /// This is a template method that subclasses can override for custom
- /// initialization behavior.
- ///
- ///
- /// Gets called by the
- ///
- /// instance directly after setting the context instance.
- ///
+ /// It saves the application context reference and provides an
+ /// initialization callback method. Furthermore, it offers numerous
+ /// convenience methods for message lookup.
+ ///
+ ///
+ /// There is no requirement to subclass this class: it just makes things
+ /// a little easier if you need access to the context, e.g. for access to
+ /// file resources or to the message source. Note that many application
+ /// objects do not need to be aware of the application context at all,
+ /// as they can receive collaborating objects via object references.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Griffin Caprio (.NET)
+ public abstract class ApplicationObjectSupport : IApplicationContextAware
+ {
+ private IApplicationContext _applicationContext;
+ private MessageSourceAccessor _messageSourceAccessor;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected ApplicationObjectSupport()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ ///
+ /// The that this
+ /// object runs in.
+ ///
+ protected ApplicationObjectSupport(
+ IApplicationContext applicationContext)
+ {
+ _applicationContext = applicationContext;
+ }
+
+ ///
+ /// The context class that any context passed to the
+ ///
+ /// must be an instance of.
+ ///
+ ///
+ /// The
+ /// .
+ ///
+ protected virtual Type RequiredType
+ {
+ get { return typeof (IApplicationContext); }
+ }
+
+ ///
+ /// Intializes the wrapped
+ /// .
+ ///
+ ///
+ ///
+ /// This is a template method that subclasses can override for custom
+ /// initialization behavior.
+ ///
+ ///
+ /// Gets called by the
+ ///
+ /// instance directly after setting the context instance.
+ ///
- /// Note that if the type attribute is not present in the declaration
- /// of a particular context, then a default
- ///
- /// is assumed. This default
- ///
- /// is currently the
- /// ; please note the exact
- /// of this default is an
- /// implementation detail, that, while unlikely, may do so in the future.
- /// to
- ///
- ///
- ///
- ///
- /// This is an example of specifying a context that reads its resources from
- /// an embedded Spring.NET XML object configuration file...
- ///
- /// 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.
- ///
- ///
- /// Please note that you must adhere to the naming
- /// of the various sections (i.e. '<sectionGroup name="spring">' and
- /// '<section name="context">'.
- ///
- /// 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.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Mark Pollack
- /// Aleksandar Seovic
- /// Rick Evans
- /// $Id: ContextHandler.cs,v 1.36 2008/03/13 20:07:33 bbaia Exp $
- ///
- public class ContextHandler : IConfigurationSectionHandler
- {
- private readonly ILog Log = LogManager.GetLogger(typeof(ContextHandler));
-
- ///
- /// The of
- /// created if no type attribute is specified on a context element.
- ///
- ///
- protected virtual Type DefaultApplicationContextType
- {
- get { return typeof (XmlApplicationContext); }
- }
-
- ///
- /// Get the context's case-sensitivity to use if none is specified
- ///
- ///
- ///
- /// Derived handlers may override this property to change their default case-sensitivity.
- ///
- ///
- /// Defaults to 'true'.
- ///
- ///
- protected virtual bool DefaultCaseSensitivity
- {
- get { return true; }
- }
-
- ///
- /// Creates an instance
- /// using the context definitions supplied in a custom
- /// configuration section.
- ///
- ///
- ///
- /// This instance is
- /// also used to configure the .
- ///
- ///
- ///
- /// The configuration settings in a corresponding parent
- /// configuration section.
- ///
- ///
- /// The configuration context when called from the ASP.NET
- /// configuration system. Otherwise, this parameter is reserved and
- /// is .
- ///
- ///
- /// The for the section.
- ///
- ///
- /// An instance
- /// populated with the object definitions supplied in the configuration
- /// section.
- ///
- 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;
- }
-
- ///
- /// Create all child-contexts in the given for the given context.
- ///
- /// The parent context to use
- /// The current configContext
- /// The list of child context elements
- 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);
- }
- }
-
- ///
- /// Instantiates a new context.
- ///
- 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;
- }
-
- ///
- /// Gets the context's name specified in the name attribute of the context element.
- ///
- /// The current configContext
- /// The context element
- protected virtual string GetContextName(object configContext, XmlElement contextElement)
- {
- string contextName;
- contextName = contextElement.GetAttribute(ContextSchema.NameAttribute);
- return contextName;
- }
-
- ///
- /// Extracts the context-type from the context element.
- /// If none is specified, returns the parent's type.
- ///
- 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;
- }
-
- ///
- /// Extracts the case-sensitivity attribute from the context element
- ///
- private bool GetCaseSensitivity(XmlElement contextElement)
- {
- bool caseSensitive = DefaultCaseSensitivity;
-
- string caseSensitiveAttr = contextElement.GetAttribute(ContextSchema.CaseSensitiveAttribute);
- if (StringUtils.HasText(caseSensitiveAttr))
- {
- caseSensitive = Boolean.Parse(caseSensitiveAttr);
- }
- return caseSensitive;
- }
-
- ///
- /// Gets the context specified in the type
- /// attribute of the context element.
- ///
- ///
- ///
- /// If this attribute is not defined it defaults to the
- /// type.
- ///
- ///
- ///
- /// If the context type does not implement the
- /// interface.
- ///
- 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.");
- }
- }
- }
-
- ///
- /// Returns if the context should be lazily
- /// initialized.
- ///
- private bool IsLazy
- {
- get { return false; }
- }
-
- ///
- /// Returns the array of resources containing object definitions for
- /// this context.
- ///
- 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));
- }
-
- ///
- /// Returns the array of child contexts for this context.
- ///
- 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) ObjectUtils.InstantiateType(
- ctor, 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) ObjectUtils.InstantiateType(
- ctor, new object[] {ContextName, CaseSensitive, this.parentContext, Resources});
- }
-
- private IApplicationContext parentContext;
- }
-
- #endregion
-
- #region Context Schema Constants
-
- ///
- /// Constants defining the structure and values associated with the
- /// schema for laying out Spring.NET contexts in XML.
- ///
- private sealed class ContextSchema
- {
- ///
- /// Defines a single
- /// .
- ///
- public const string ContextElement = "context";
-
- ///
- /// Specifies a context name.
- ///
- public const string NameAttribute = "name";
-
- ///
- /// Specifies if context should be case sensitive or not. Default is true.
- ///
- public const string CaseSensitiveAttribute = "caseSensitive";
-
- ///
- /// Specifies a .
- ///
- ///
- ///
- /// Does not have to be fully assembly qualified, but its generally regarded
- /// as better form if the names of one's objects
- /// are specified explicitly.
- ///
+ /// Note that if the type attribute is not present in the declaration
+ /// of a particular context, then a default
+ ///
+ /// is assumed. This default
+ ///
+ /// is currently the
+ /// ; please note the exact
+ /// of this default is an
+ /// implementation detail, that, while unlikely, may do so in the future.
+ /// to
+ ///
+ ///
+ ///
+ ///
+ /// This is an example of specifying a context that reads its resources from
+ /// an embedded Spring.NET XML object configuration file...
+ ///
+ /// 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.
+ ///
+ ///
+ /// Please note that you must adhere to the naming
+ /// of the various sections (i.e. '<sectionGroup name="spring">' and
+ /// '<section name="context">'.
+ ///
+ /// 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.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ /// Aleksandar Seovic
+ /// Rick Evans
+ ///
+ public class ContextHandler : IConfigurationSectionHandler
+ {
+ private readonly ILog Log = LogManager.GetLogger(typeof(ContextHandler));
+
+ ///
+ /// The of
+ /// created if no type attribute is specified on a context element.
+ ///
+ ///
+ protected virtual Type DefaultApplicationContextType
+ {
+ get { return typeof (XmlApplicationContext); }
+ }
+
+ ///
+ /// Get the context's case-sensitivity to use if none is specified
+ ///
+ ///
+ ///
+ /// Derived handlers may override this property to change their default case-sensitivity.
+ ///
+ ///
+ /// Defaults to 'true'.
+ ///
+ ///
+ protected virtual bool DefaultCaseSensitivity
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Creates an instance
+ /// using the context definitions supplied in a custom
+ /// configuration section.
+ ///
+ ///
+ ///
+ /// This instance is
+ /// also used to configure the .
+ ///
+ ///
+ ///
+ /// The configuration settings in a corresponding parent
+ /// configuration section.
+ ///
+ ///
+ /// The configuration context when called from the ASP.NET
+ /// configuration system. Otherwise, this parameter is reserved and
+ /// is .
+ ///
+ ///
+ /// The for the section.
+ ///
+ ///
+ /// An instance
+ /// populated with the object definitions supplied in the configuration
+ /// section.
+ ///
+ 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;
+ }
+
+ ///
+ /// Create all child-contexts in the given for the given context.
+ ///
+ /// The parent context to use
+ /// The current configContext
+ /// The list of child context elements
+ 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);
+ }
+ }
+
+ ///
+ /// Instantiates a new context.
+ ///
+ 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;
+ }
+
+ ///
+ /// Gets the context's name specified in the name attribute of the context element.
+ ///
+ /// The current configContext
+ /// The context element
+ protected virtual string GetContextName(object configContext, XmlElement contextElement)
+ {
+ string contextName;
+ contextName = contextElement.GetAttribute(ContextSchema.NameAttribute);
+ return contextName;
+ }
+
+ ///
+ /// Extracts the context-type from the context element.
+ /// If none is specified, returns the parent's type.
+ ///
+ 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;
+ }
+
+ ///
+ /// Extracts the case-sensitivity attribute from the context element
+ ///
+ private bool GetCaseSensitivity(XmlElement contextElement)
+ {
+ bool caseSensitive = DefaultCaseSensitivity;
+
+ string caseSensitiveAttr = contextElement.GetAttribute(ContextSchema.CaseSensitiveAttribute);
+ if (StringUtils.HasText(caseSensitiveAttr))
+ {
+ caseSensitive = Boolean.Parse(caseSensitiveAttr);
+ }
+ return caseSensitive;
+ }
+
+ ///
+ /// Gets the context specified in the type
+ /// attribute of the context element.
+ ///
+ ///
+ ///
+ /// If this attribute is not defined it defaults to the
+ /// type.
+ ///
+ ///
+ ///
+ /// If the context type does not implement the
+ /// interface.
+ ///
+ 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.");
+ }
+ }
+ }
+
+ ///
+ /// Returns if the context should be lazily
+ /// initialized.
+ ///
+ private bool IsLazy
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Returns the array of resources containing object definitions for
+ /// this context.
+ ///
+ 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));
+ }
+
+ ///
+ /// Returns the array of child contexts for this context.
+ ///
+ 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) ObjectUtils.InstantiateType(
+ ctor, 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) ObjectUtils.InstantiateType(
+ ctor, new object[] {ContextName, CaseSensitive, this.parentContext, Resources});
+ }
+
+ private IApplicationContext parentContext;
+ }
+
+ #endregion
+
+ #region Context Schema Constants
+
+ ///
+ /// Constants defining the structure and values associated with the
+ /// schema for laying out Spring.NET contexts in XML.
+ ///
+ private sealed class ContextSchema
+ {
+ ///
+ /// Defines a single
+ /// .
+ ///
+ public const string ContextElement = "context";
+
+ ///
+ /// Specifies a context name.
+ ///
+ public const string NameAttribute = "name";
+
+ ///
+ /// Specifies if context should be case sensitive or not. Default is true.
+ ///
+ public const string CaseSensitiveAttribute = "caseSensitive";
+
+ ///
+ /// Specifies a .
+ ///
+ ///
+ ///
+ /// Does not have to be fully assembly qualified, but its generally regarded
+ /// as better form if the names of one's objects
+ /// are specified explicitly.
+ ///
- /// A singleton implementation to access one or more application contexts. Application
- /// context instances are cached.
- ///
- ///
Note that the use of this class or similar is unnecessary except (sometimes) for
- /// a small amount of glue code. Excessive usage will lead to code that is more tightly
- /// coupled, and harder to modify or test. Consider refactoring your code to use standard
- /// Dependency Injection techniques or implement the interface IApplicationContextAware to
- /// obtain a reference to an application context.
- ///
- /// Mark Pollack
- /// Aleksandar Seovic
- ///
- /// $Id: ContextRegistry.cs,v 1.28 2008/03/21 10:49:37 oakinger Exp $
- public sealed class ContextRegistry
- {
- ///
- /// The shared instance for this class (and derived classes).
- ///
- private static readonly ILog log = LogManager.GetLogger(typeof(ContextRegistry));
-
- private static readonly object syncRoot = new Object();
- private static readonly ContextRegistry instance = new ContextRegistry();
- private static string rootContextName = null;
-
- private IDictionary contextMap = CollectionsUtil.CreateCaseInsensitiveHashtable();
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the ContextRegistry class.
- ///
- ///
- ///
- /// Explicit static constructor to tell C# compiler
- /// not to mark type as beforefieldinit.
- ///
- ///
- static ContextRegistry()
- {}
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// This event is fired, if ContextRegistry.Clear() is called.
- /// Clients may register to get informed
- ///
- ///
- /// This event is fired while still holding a lock on the Registry.
- /// 'sender' parameter is sent as typeof(ContextRegistry), EventArgs are not used
- ///
- public static event EventHandler Cleared;
-
- ///
- /// Gets an object that should be used to synchronize access to ContextRegistry
- /// from the calling code.
- ///
- public static object SyncRoot
- {
- get { return syncRoot; }
- }
-
- ///
- /// Registers an instance of an
- /// .
- ///
- ///
- ///
- /// This is usually called via a
- /// inside a .NET
- /// application configuration file.
- ///
- ///
- /// The application context to be registered.
- ///
- /// If a context has previously been registered using the same name
- ///
- public static void RegisterContext(IApplicationContext context)
- {
- lock (syncRoot)
- {
- if (instance.contextMap.Contains(context.Name))
- {
- IApplicationContext ctx = (IApplicationContext)instance.contextMap[context.Name];
- throw new ApplicationContextException(
- string.Format("Existing context '{0}' already registered under name '{1}'.",
- ctx, context.Name));
- }
- instance.contextMap[context.Name] = context;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(String.Format(
- "Registering context '{0}' under name '{1}'.", context, context.Name));
- }
-
- #endregion
-
- if (rootContextName == null)
- {
- rootContextName = context.Name;
- }
- }
- }
-
- ///
- /// Returns the root application context.
- ///
- ///
- ///
- /// The first call to GetContext will create the context
- /// as specified in the .NET application configuration file
- /// under the location spring/context.
- ///
- /// The first call to GetContext will create the context
- /// as specified in the .NET application configuration file
- /// under the location spring/context.
- ///
+ /// A singleton implementation to access one or more application contexts. Application
+ /// context instances are cached.
+ ///
+ ///
Note that the use of this class or similar is unnecessary except (sometimes) for
+ /// a small amount of glue code. Excessive usage will lead to code that is more tightly
+ /// coupled, and harder to modify or test. Consider refactoring your code to use standard
+ /// Dependency Injection techniques or implement the interface IApplicationContextAware to
+ /// obtain a reference to an application context.
+ ///
+ /// Mark Pollack
+ /// Aleksandar Seovic
+ ///
+ public sealed class ContextRegistry
+ {
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ private static readonly ILog log = LogManager.GetLogger(typeof(ContextRegistry));
+
+ private static readonly object syncRoot = new Object();
+ private static readonly ContextRegistry instance = new ContextRegistry();
+ private static string rootContextName = null;
+
+ private IDictionary contextMap = CollectionsUtil.CreateCaseInsensitiveHashtable();
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the ContextRegistry class.
+ ///
+ ///
+ ///
+ /// Explicit static constructor to tell C# compiler
+ /// not to mark type as beforefieldinit.
+ ///
+ ///
+ static ContextRegistry()
+ {}
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// This event is fired, if ContextRegistry.Clear() is called.
+ /// Clients may register to get informed
+ ///
+ ///
+ /// This event is fired while still holding a lock on the Registry.
+ /// 'sender' parameter is sent as typeof(ContextRegistry), EventArgs are not used
+ ///
+ public static event EventHandler Cleared;
+
+ ///
+ /// Gets an object that should be used to synchronize access to ContextRegistry
+ /// from the calling code.
+ ///
+ public static object SyncRoot
+ {
+ get { return syncRoot; }
+ }
+
+ ///
+ /// Registers an instance of an
+ /// .
+ ///
+ ///
+ ///
+ /// This is usually called via a
+ /// inside a .NET
+ /// application configuration file.
+ ///
+ ///
+ /// The application context to be registered.
+ ///
+ /// If a context has previously been registered using the same name
+ ///
+ public static void RegisterContext(IApplicationContext context)
+ {
+ lock (syncRoot)
+ {
+ if (instance.contextMap.Contains(context.Name))
+ {
+ IApplicationContext ctx = (IApplicationContext)instance.contextMap[context.Name];
+ throw new ApplicationContextException(
+ string.Format("Existing context '{0}' already registered under name '{1}'.",
+ ctx, context.Name));
+ }
+ instance.contextMap[context.Name] = context;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(String.Format(
+ "Registering context '{0}' under name '{1}'.", context, context.Name));
+ }
+
+ #endregion
+
+ if (rootContextName == null)
+ {
+ rootContextName = context.Name;
+ }
+ }
+ }
+
+ ///
+ /// Returns the root application context.
+ ///
+ ///
+ ///
+ /// The first call to GetContext will create the context
+ /// as specified in the .NET application configuration file
+ /// under the location spring/context.
+ ///
+ /// The first call to GetContext will create the context
+ /// as specified in the .NET application configuration file
+ /// under the location spring/context.
+ ///
- /// Provides easy ways to store all the necessary values needed to resolve
- /// messages from an .
- ///
- ///
- /// Juergen Hoeller
- /// Griffin Caprio (.NET)
- /// $Id: DefaultMessageSourceResolvable.cs,v 1.4 2007/07/02 21:24:39 markpollack Exp $
- ///
- [Serializable]
- public class DefaultMessageSourceResolvable : IMessageSourceResolvable
- {
- private string[] codes;
- private object[] arguments;
- private string defaultMessage;
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class
- /// using a single code.
- ///
- /// The message code to be resolved.
- public DefaultMessageSourceResolvable(string code)
- : this(new string[] {code}, StringUtils.EmptyStrings, string.Empty)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The codes to be used to resolve this message
- public DefaultMessageSourceResolvable(string[] codes)
- : this(codes, StringUtils.EmptyStrings, string.Empty)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// using multiple codes.
- ///
- /// The message codes to be resolved.
- ///
- /// The arguments used to resolve the supplied .
- ///
- public DefaultMessageSourceResolvable(string[] codes, object[] arguments)
- : this(codes, arguments, string.Empty)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// using multiple codes and a default message.
- ///
- /// The message codes to be resolved.
- ///
- /// The arguments used to resolve the supplied .
- ///
- ///
- /// The default message used if no code could be resolved.
- ///
- public DefaultMessageSourceResolvable(
- string[] codes, object[] arguments, string defaultMessage)
- {
- this.codes = codes;
- this.arguments = arguments;
- this.defaultMessage = defaultMessage;
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// from another resolvable.
- ///
- ///
- ///
- /// This is the copy constructor for the
- /// class.
- ///
+ /// Provides easy ways to store all the necessary values needed to resolve
+ /// messages from an .
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Griffin Caprio (.NET)
+ ///
+ [Serializable]
+ public class DefaultMessageSourceResolvable : IMessageSourceResolvable
+ {
+ private string[] codes;
+ private object[] arguments;
+ private string defaultMessage;
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// using a single code.
+ ///
+ /// The message code to be resolved.
+ public DefaultMessageSourceResolvable(string code)
+ : this(new string[] {code}, StringUtils.EmptyStrings, string.Empty)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The codes to be used to resolve this message
+ public DefaultMessageSourceResolvable(string[] codes)
+ : this(codes, StringUtils.EmptyStrings, string.Empty)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// using multiple codes.
+ ///
+ /// The message codes to be resolved.
+ ///
+ /// The arguments used to resolve the supplied .
+ ///
+ public DefaultMessageSourceResolvable(string[] codes, object[] arguments)
+ : this(codes, arguments, string.Empty)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// using multiple codes and a default message.
+ ///
+ /// The message codes to be resolved.
+ ///
+ /// The arguments used to resolve the supplied .
+ ///
+ ///
+ /// The default message used if no code could be resolved.
+ ///
+ public DefaultMessageSourceResolvable(
+ string[] codes, object[] arguments, string defaultMessage)
+ {
+ this.codes = codes;
+ this.arguments = arguments;
+ this.defaultMessage = defaultMessage;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// from another resolvable.
+ ///
+ ///
+ ///
+ /// This is the copy constructor for the
+ /// class.
+ ///
- /// If no parent is available,
- /// no messages will be resolved (and a
- /// will be thrown).
- ///
- ///
- /// Used as placeholder by the
- /// class,
- /// if the context definition doesn't define its own
- /// . Not intended for direct use
- /// in applications.
- ///
+ /// If no parent is available,
+ /// no messages will be resolved (and a
+ /// will be thrown).
+ ///
+ ///
+ /// Used as placeholder by the
+ /// class,
+ /// if the context definition doesn't define its own
+ /// . Not intended for direct use
+ /// in applications.
+ ///
+ ///
+ /// Juergan Hoeller
+ /// Rick Evans (.NET)
+ ///
+ public class DelegatingMessageSource : IHierarchicalMessageSource
+ {
+ #region Fields
+
+ private IMessageSource _parentMessageSource;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public DelegatingMessageSource()
+ {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The parent message source used to try and resolve messages that
+ /// this object can't resolve.
+ ///
+ public DelegatingMessageSource(IMessageSource parentMessageSource)
+ {
+ ParentMessageSource = parentMessageSource;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The parent message source used to try and resolve messages that
+ /// this object can't resolve.
+ ///
+ ///
+ public IMessageSource ParentMessageSource
+ {
+ get
+ {
+ if (_parentMessageSource == null)
+ {
+ _parentMessageSource = new SpecialCaseNullMessageSource();
+ }
+ return _parentMessageSource;
+ }
+ set { _parentMessageSource = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(string name)
+ {
+ return ParentMessageSource.GetMessage(name);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(string name, params object[] arguments)
+ {
+ return ParentMessageSource.GetMessage(name, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(string name, CultureInfo culture)
+ {
+ return ParentMessageSource.GetMessage(name, culture);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(string name, CultureInfo culture, params object[] arguments)
+ {
+ return ParentMessageSource.GetMessage(name, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message identified by the supplied
+ /// .
+ ///
+ /// The name of the message to resolve.
+ /// The default message.
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The array of arguments that will be filled in for parameters within
+ /// the message, or if there are no parameters
+ /// within the message. Parameters within a message should be
+ /// referenced using the same syntax as the format string for the
+ /// method.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
+ {
+ return ParentMessageSource.GetMessage(name, defaultMessage, culture, arguments);
+ }
+
+ ///
+ /// Resolve the message using all of the attributes contained within
+ /// the supplied
+ /// argument.
+ ///
+ ///
+ /// The value object storing those attributes that are required to
+ /// properly resolve a message.
+ ///
+ ///
+ /// The that represents
+ /// the culture for which the resource is localized.
+ ///
+ ///
+ /// The resolved message if the lookup was successful (see above for
+ /// the return value in the case of an unsuccessful lookup).
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ /// If the message could not be resolved.
+ ///
+ ///
+ public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
+ {
+ return ParentMessageSource.GetMessage(resolvable, culture);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name)
+ {
+ return ParentMessageSource.GetResourceObject(name);
+ }
+
+ ///
+ /// Gets a localized resource object identified by the supplied
+ /// .
+ ///
+ ///
+ /// The name of the resource object to resolve.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ /// The resolved object, or if not found.
+ ///
+ ///
+ public object GetResourceObject(string name, CultureInfo culture)
+ {
+ return ParentMessageSource.GetResourceObject(name, culture);
+ }
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ /// An object that contains the property values to be applied.
+ ///
+ ///
+ /// The base name of the object to use for key lookup.
+ ///
+ ///
+ /// The with which the
+ /// resource is associated.
+ ///
+ ///
+ public void ApplyResources(object value, string objectName, CultureInfo culture)
+ {
+ ParentMessageSource.ApplyResources(value, objectName, culture);
+ }
+
+ #endregion
+
+ #region Inner Class : SpecialCaseNullMessageSource
+
+ private sealed class SpecialCaseNullMessageSource : IMessageSource
+ {
+ public string GetMessage(string name)
+ {
+ return GetMessage(name, (object[]) null);
+ }
+
+ public string GetMessage(string name, params object[] arguments)
+ {
+ return GetMessage(name, CultureInfo.CurrentUICulture, null);
+ }
+
+ public string GetMessage(string name, CultureInfo culture)
+ {
+ return GetMessage(name, culture, null);
+ }
+
+ public string GetMessage(string name, CultureInfo culture, params object[] arguments)
+ {
+ throw new NoSuchMessageException(name, culture);
+ }
+
+ public string GetMessage(string name, string defaultMessage, CultureInfo culture, params object[] arguments)
+ {
+ throw new NoSuchMessageException(name, culture);
+ }
+
+
+ public string GetMessage(IMessageSourceResolvable resolvable, CultureInfo culture)
+ {
+ if (StringUtils.HasText(resolvable.DefaultMessage))
+ {
+ return resolvable.DefaultMessage;
+ }
+ string[] codes = resolvable.GetCodes();
+ string code = (codes != null && codes.Length > 0 ? codes[0] : string.Empty);
+ throw new NoSuchMessageException(code, culture);
+ }
+
+ public object GetResourceObject(string name)
+ {
+ return GetResourceObject(name, CultureInfo.CurrentUICulture);
+ }
+
+ public object GetResourceObject(string name, CultureInfo culture)
+ {
+ throw new ApplicationContextException(
+ string.Format(
+ "Cannot lookup the named resource '{0}' for locale '{1}' " +
+ ": no IMessageSource in context.",
+ name, culture));
+ }
+
+ public void ApplyResources(object value, string objectName, CultureInfo culture)
+ {
+ throw new ApplicationContextException(
+ string.Format(
+ "Cannot apply [{0}] resource to object '{1}' for locale '{2}' " +
+ ": no IMessageSource in context.",
+ value, objectName, culture));
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs
index 935382fa..eeb91b87 100644
--- a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs
+++ b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs
@@ -1,259 +1,258 @@
-#region License
-
-/*
- * Copyright 2002-2007 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 Spring.Core.IO;
-using Spring.Objects.Factory.Config;
-using Spring.Objects.Factory.Support;
-using Spring.Util;
-
-namespace Spring.Context.Support
-{
- ///
- /// Generic ApplicationContext implementation that holds a single internal
- /// instance and does not
- /// assume a specific object definition format.
- ///
- ///
- /// Implements the interface in order
- /// to allow for aplying any object definition readers to it.
- /// Typical usage is to register a variety of object definitions via the
- /// interface and then call
- /// to initialize those
- /// objects with application context semantics (handling
- /// , auto-detecting
- /// ObjectFactoryPostProcessors, etc).
- ///
- /// In contrast to other IApplicationContext implementations that create a new internal
- /// IObjectFactory instance for each refresh, the internal IObjectFactory of this context
- /// is available right from the start, to be able to register object definitions on it.
- /// may only be called once
- /// Usage examples
- ///
- /// GenericApplicationContext ctx = new GenericApplicationContext();
- ///
- ///
- ///
- /// Mark Pollack
- /// $Id: GenericApplicationContext.cs,v 1.5 2008/02/17 13:34:44 markpollack Exp $
- public class GenericApplicationContext : AbstractApplicationContext, IObjectDefinitionRegistry
- {
- private DefaultListableObjectFactory objectFactory;
-
- private bool refreshed = false;
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- public GenericApplicationContext()
- {
- objectFactory = new DefaultListableObjectFactory();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// if set to true names in the context are case sensitive.
- public GenericApplicationContext(bool caseSensitive)
- {
- objectFactory = new DefaultListableObjectFactory(caseSensitive);
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The object factory instance to use for this context.
- public GenericApplicationContext(DefaultListableObjectFactory objectFactory)
- {
- AssertUtils.ArgumentNotNull(objectFactory, "objectFactory", "ObjectFactory must not be null");
- this.objectFactory = objectFactory;
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The parent application context.
- public GenericApplicationContext(IApplicationContext parent)
- {
- objectFactory = new DefaultListableObjectFactory();
- ParentContext = parent;
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The name of the application context.
- /// if set to true names in the context are case sensitive.
- /// The parent application context.
- public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent) : this(caseSensitive)
- {
- Name = name;
- ParentContext = parent;
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The object factory to use for this context
- /// The parent applicaiton context.
- public GenericApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) : this(objectFactory)
- {
- ParentContext = parent;
- }
-
-
-
- ///
- /// Gets the parent context, or if there is no
- /// parent context. Set the parent of this application context also setting
- /// the parent of the interanl ObjectFactory accordingly.
- ///
- /// The parent context
- ///
- /// The parent context, or if there is no
- /// parent.
- ///
- ///
- public override IApplicationContext ParentContext
- {
- get
- {
- return base.ParentContext;
- }
- set {
- base.ParentContext = value;
- objectFactory.ParentObjectFactory = GetInternalParentObjectFactory();
- }
- }
-
-
- ///
- /// Do nothing operation. We hold a single internal ObjectFactory and rely on callers
- /// to register objects throug our public methods (or the ObjectFactory's).
- ///
- ///
- /// In the case of errors encountered while refreshing the object factory.
- ///
- protected override void RefreshObjectFactory()
- {
- if (refreshed)
- {
- throw new InvalidOperationException(
- "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
- }
-
- refreshed = true;
- }
-
- ///
- /// Return the internal object factory of this application context.
- ///
- ///
- public override IConfigurableListableObjectFactory ObjectFactory
- {
- get { return objectFactory; }
- }
-
- ///
- /// Gets the underlying object factory of this context, available for
- /// registering object definitions.
- ///
- /// You need to call Refresh to initialize the
- /// objects factory and its contained objects with application context
- /// semantics (autodecting IObjectFactoryPostProcessors, etc).
- /// The internal object factory (as DefaultListableObjectFactory).
- public DefaultListableObjectFactory DefaultListableObjectFactory
- {
- get { return objectFactory; }
- }
-
-
-
- #region IObjectDefinitionRegistry Members
-
- ///
- /// Returns the
- ///
- /// for the given object name.
- ///
- /// The name of the object to find a definition for.
- ///
- /// The for
- /// the given name (never null).
- ///
- ///
- /// If the object definition cannot be resolved.
- ///
- ///
- /// In case of errors.
- ///
- public override IObjectDefinition GetObjectDefinition(string name)
- {
- return objectFactory.GetObjectDefinition(name);
- }
-
- ///
- /// Register a new object definition with this registry.
- /// Must support
- ///
- /// and .
- ///
- /// The name of the object instance to register.
- /// The definition of the object instance to register.
- ///
- ///
- /// Must support
- /// and
- /// .
- ///
- ///
- ///
- /// If the object definition is invalid.
- ///
- public void RegisterObjectDefinition(string name, IObjectDefinition definition)
- {
- objectFactory.RegisterObjectDefinition(name, definition);
- }
-
- ///
- /// 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).
- ///
- /// The name of the object.
- /// The alias that will behave the same as the object name.
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// If the alias is already in use.
- ///
- public void RegisterAlias(string name, string theAlias)
- {
- objectFactory.RegisterAlias(name, theAlias);
- }
-
- #endregion
- }
+#region License
+
+/*
+ * Copyright 2002-2007 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 Spring.Core.IO;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Util;
+
+namespace Spring.Context.Support
+{
+ ///
+ /// Generic ApplicationContext implementation that holds a single internal
+ /// instance and does not
+ /// assume a specific object definition format.
+ ///
+ ///
+ /// Implements the interface in order
+ /// to allow for aplying any object definition readers to it.
+ /// Typical usage is to register a variety of object definitions via the
+ /// interface and then call
+ /// to initialize those
+ /// objects with application context semantics (handling
+ /// , auto-detecting
+ /// ObjectFactoryPostProcessors, etc).
+ ///
+ /// In contrast to other IApplicationContext implementations that create a new internal
+ /// IObjectFactory instance for each refresh, the internal IObjectFactory of this context
+ /// is available right from the start, to be able to register object definitions on it.
+ /// may only be called once
+ /// Usage examples
+ ///
+ /// GenericApplicationContext ctx = new GenericApplicationContext();
+ ///
+ ///
+ ///
+ /// Mark Pollack
+ public class GenericApplicationContext : AbstractApplicationContext, IObjectDefinitionRegistry
+ {
+ private DefaultListableObjectFactory objectFactory;
+
+ private bool refreshed = false;
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public GenericApplicationContext()
+ {
+ objectFactory = new DefaultListableObjectFactory();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true names in the context are case sensitive.
+ public GenericApplicationContext(bool caseSensitive)
+ {
+ objectFactory = new DefaultListableObjectFactory(caseSensitive);
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object factory instance to use for this context.
+ public GenericApplicationContext(DefaultListableObjectFactory objectFactory)
+ {
+ AssertUtils.ArgumentNotNull(objectFactory, "objectFactory", "ObjectFactory must not be null");
+ this.objectFactory = objectFactory;
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The parent application context.
+ public GenericApplicationContext(IApplicationContext parent)
+ {
+ objectFactory = new DefaultListableObjectFactory();
+ ParentContext = parent;
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the application context.
+ /// if set to true names in the context are case sensitive.
+ /// The parent application context.
+ public GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent) : this(caseSensitive)
+ {
+ Name = name;
+ ParentContext = parent;
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object factory to use for this context
+ /// The parent applicaiton context.
+ public GenericApplicationContext(DefaultListableObjectFactory objectFactory, IApplicationContext parent) : this(objectFactory)
+ {
+ ParentContext = parent;
+ }
+
+
+
+ ///
+ /// Gets the parent context, or if there is no
+ /// parent context. Set the parent of this application context also setting
+ /// the parent of the interanl ObjectFactory accordingly.
+ ///
+ /// The parent context
+ ///
+ /// The parent context, or if there is no
+ /// parent.
+ ///
+ ///
+ public override IApplicationContext ParentContext
+ {
+ get
+ {
+ return base.ParentContext;
+ }
+ set {
+ base.ParentContext = value;
+ objectFactory.ParentObjectFactory = GetInternalParentObjectFactory();
+ }
+ }
+
+
+ ///
+ /// Do nothing operation. We hold a single internal ObjectFactory and rely on callers
+ /// to register objects throug our public methods (or the ObjectFactory's).
+ ///
+ ///
+ /// In the case of errors encountered while refreshing the object factory.
+ ///
+ protected override void RefreshObjectFactory()
+ {
+ if (refreshed)
+ {
+ throw new InvalidOperationException(
+ "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
+ }
+
+ refreshed = true;
+ }
+
+ ///
+ /// Return the internal object factory of this application context.
+ ///
+ ///
+ public override IConfigurableListableObjectFactory ObjectFactory
+ {
+ get { return objectFactory; }
+ }
+
+ ///
+ /// Gets the underlying object factory of this context, available for
+ /// registering object definitions.
+ ///
+ /// You need to call Refresh to initialize the
+ /// objects factory and its contained objects with application context
+ /// semantics (autodecting IObjectFactoryPostProcessors, etc).
+ /// The internal object factory (as DefaultListableObjectFactory).
+ public DefaultListableObjectFactory DefaultListableObjectFactory
+ {
+ get { return objectFactory; }
+ }
+
+
+
+ #region IObjectDefinitionRegistry Members
+
+ ///
+ /// Returns the
+ ///
+ /// for the given object name.
+ ///
+ /// The name of the object to find a definition for.
+ ///
+ /// The for
+ /// the given name (never null).
+ ///
+ ///
+ /// If the object definition cannot be resolved.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ public override IObjectDefinition GetObjectDefinition(string name)
+ {
+ return objectFactory.GetObjectDefinition(name);
+ }
+
+ ///
+ /// Register a new object definition with this registry.
+ /// Must support
+ ///
+ /// and .
+ ///
+ /// The name of the object instance to register.
+ /// The definition of the object instance to register.
+ ///
+ ///
- /// Spring.NET allows the registration of custom configuration parsers that
- /// can be used to create simplified configuration schemas that better
- /// describe object definitions.
- ///
- ///
- /// For example, Spring.NET uses this facility internally in order to
- /// define simplified schemas for various AOP, Data and Services definitions.
- ///
- ///
- ///
- ///
- /// The following example shows how to configure both this section handler
- /// and how to define custom configuration parsers within a Spring.NET
- /// config section.
- ///
+ /// Spring.NET allows the registration of custom configuration parsers that
+ /// can be used to create simplified configuration schemas that better
+ /// describe object definitions.
+ ///
+ ///
+ /// For example, Spring.NET uses this facility internally in order to
+ /// define simplified schemas for various AOP, Data and Services definitions.
+ ///
+ ///
+ ///
+ ///
+ /// The following example shows how to configure both this section handler
+ /// and how to define custom configuration parsers within a Spring.NET
+ /// config section.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// ...
+ ///
+ /// ...
+ ///
+ ///
+ ///
+ ///
+ /// Aleksandar Seovic
+ ///
+ public class NamespaceParsersSectionHandler : IConfigurationSectionHandler
+ {
+ private const string ParserElementName = "parser";
+ private const string TypeAttributeName = "type";
+ private const string NamespaceAttributeName = "namespace";
+ private const string SchemaLocationAttributeName = "schemaLocation";
+
+ ///
+ /// Registers parsers specified in the (recommended, Spring.NET standard)
+ /// parsers config section with the .
+ ///
+ ///
+ /// The configuration settings in a corresponding parent
+ /// configuration section.
+ ///
+ ///
+ /// The configuration context when called from the ASP.NET
+ /// configuration system. Otherwise, this parameter is reserved and
+ /// is .
+ ///
+ ///
+ /// The for the section.
+ ///
+ ///
+ /// This method always returns , because parsers
+ /// are registered as a side-effect of this object's execution and there
+ /// is thus no need to return anything.
+ ///
+ public object Create(object parent, object configContext, XmlNode section)
+ {
+ if (section != null)
+ {
+ XmlNodeList parsers = ((XmlElement)section).GetElementsByTagName(ParserElementName);
+ foreach (XmlElement parserElement in parsers)
+ {
+ string parserTypeName = GetRequiredAttributeValue(parserElement, TypeAttributeName, section);
+ string xmlNamespace = parserElement.GetAttribute(NamespaceAttributeName);
+ string schemaLocation = parserElement.GetAttribute(SchemaLocationAttributeName);
+
+ Type parserType = TypeResolutionUtils.ResolveType(parserTypeName);
+ NamespaceParserRegistry.RegisterParser(parserType, xmlNamespace, schemaLocation);
+ }
+ }
+ return null;
+ }
+
+ private static string GetRequiredAttributeValue(
+ XmlElement aliasElement, string requiredAttributeName, XmlNode section)
+ {
+ XmlAttribute attribute = aliasElement.GetAttributeNode(requiredAttributeName);
+ if (attribute == null)
+ {
+ string errorMessage = string.Format(CultureInfo.InvariantCulture,
+ "The '{0}' attribute is required for the element.", requiredAttributeName);
+ throw ConfigurationUtils.CreateConfigurationException(errorMessage, section);
+ }
+ return attribute.Value;
+ }
+ }
+}
diff --git a/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs b/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs
index e9b691d7..9573aa1e 100644
--- a/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs
+++ b/src/Spring/Spring.Core/Context/Support/NullMessageSource.cs
@@ -1,117 +1,116 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System.Globalization;
-
-#endregion
-
-namespace Spring.Context.Support
-{
- ///
- /// An that doesn't do a whole lot.
- ///
- ///
- ///
- /// is an implementation of
- /// the NullObject pattern. It should be used in those situations where a
- /// needs to be passed (say to a
- /// method) but where the resolution of messages is not required.
- ///
- ///
- /// There should not (typically) be a need to instantiate instances of this class;
- /// does not maintan any state
- /// and the instance is
- /// thus safe to pass around.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: NullMessageSource.cs,v 1.5 2007/08/27 09:38:29 oakinger Exp $
- public sealed class NullMessageSource : AbstractMessageSource
- {
- ///
- /// The canonical instance of the
- /// class.
- ///
- public static readonly NullMessageSource Null = new NullMessageSource();
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// Consider using
- /// instead.
- ///
- ///
- public NullMessageSource()
- {}
-
- ///
- /// Simply returns the supplied message as-is.
- ///
- /// The code of the message to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- ///
- /// The supplied message as-is.
- ///
- protected override string ResolveMessage(string code, CultureInfo cultureInfo)
- {
- return code;
- }
-
- ///
- /// Always returns .
- ///
- /// The code of the object to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- ///
- /// (always).
- ///
- protected override object ResolveObject(string code, CultureInfo cultureInfo)
- {
- return null;
- }
-
- ///
- /// Does nothing.
- ///
- ///
- /// An object that contains the property values to be applied.
- ///
- ///
- /// The base name of the object to use for key lookup.
- ///
- ///
- /// The with which the
- /// resource is associated.
- ///
- protected override void ApplyResourcesToObject(
- object value, string objectName, CultureInfo cultureInfo)
- {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System.Globalization;
+
+#endregion
+
+namespace Spring.Context.Support
+{
+ ///
+ /// An that doesn't do a whole lot.
+ ///
+ ///
+ ///
+ /// is an implementation of
+ /// the NullObject pattern. It should be used in those situations where a
+ /// needs to be passed (say to a
+ /// method) but where the resolution of messages is not required.
+ ///
+ ///
+ /// There should not (typically) be a need to instantiate instances of this class;
+ /// does not maintan any state
+ /// and the instance is
+ /// thus safe to pass around.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public sealed class NullMessageSource : AbstractMessageSource
+ {
+ ///
+ /// The canonical instance of the
+ /// class.
+ ///
+ public static readonly NullMessageSource Null = new NullMessageSource();
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
- /// Spring allows registration of custom resource handlers that can be used to load
- /// object definitions from.
- ///
- ///
- /// For example, if you wanted to store your object definitions in a database instead
- /// of in the config file, you could write a custom implementation
- /// and register it with Spring using 'db' as a protocol name.
- ///
- ///
- /// Afterwards, you would simply specify resource URI within the context config element
- /// using your custom resource handler.
- ///
- ///
- ///
- ///
- /// The following example shows how to configure both this section handler,
- /// how to define custom resource within Spring config section, and how to load
- /// object definitions using custom resource handler:
- ///
+ /// Spring allows registration of custom resource handlers that can be used to load
+ /// object definitions from.
+ ///
+ ///
+ /// For example, if you wanted to store your object definitions in a database instead
+ /// of in the config file, you could write a custom implementation
+ /// and register it with Spring using 'db' as a protocol name.
+ ///
+ ///
+ /// Afterwards, you would simply specify resource URI within the context config element
+ /// using your custom resource handler.
+ ///
+ ///
+ ///
+ ///
+ /// The following example shows how to configure both this section handler,
+ /// how to define custom resource within Spring config section, and how to load
+ /// object definitions using custom resource handler:
+ ///
- /// The list may contain objects of type or
- /// . types
- /// are converted to instances using the notation
- /// resourcename, assembly partial name.
- ///
+ /// The list may contain objects of type or
+ /// . types
+ /// are converted to instances using the notation
+ /// resourcename, assembly partial name.
+ ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Griffin Caprio (.NET)
- ///
- /// $Id: StaticMessageSource.cs,v 1.16 2007/08/27 13:57:27 oakinger Exp $
- public class StaticMessageSource : AbstractMessageSource
- {
- private Hashtable _messages;
- private Hashtable _objects;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public StaticMessageSource()
- {
- _messages = new Hashtable();
- _objects = new Hashtable();
- }
-
- ///
- /// Returns a format string.
- ///
- /// The code of the message to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- ///
- /// A format string or if not found.
- ///
- ///
- protected override string ResolveMessage(string code, CultureInfo cultureInfo)
- {
- return (string) _messages[GetLookupKey(code, cultureInfo)];
- }
-
- ///
- /// Resolves an object (typically an icon or bitmap).
- ///
- /// The code of the object to resolve.
- ///
- /// The to resolve the
- /// code for.
- ///
- ///
- /// The resolved object or if not found.
- ///
- ///
- protected override object ResolveObject(string code, CultureInfo cultureInfo)
- {
- return _objects[GetLookupKey(code, cultureInfo)];
- }
-
-
- // *** NOTE Don't use cref for ComponentResourceManager as it doesn't
- // exist on 1.0
- //
-
- ///
- /// Applies resources to object properties.
- ///
- ///
- ///
- /// Uses a System.ComponentModel.ComponentResourceManager
- /// internally to apply resources to object properties. Resource key
- /// names are of the form objectName.propertyName.
- ///
- ///
- /// This feature is not currently supported on version 1.0 of the .NET platform.
- ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Griffin Caprio (.NET)
+ ///
+ public class StaticMessageSource : AbstractMessageSource
+ {
+ private Hashtable _messages;
+ private Hashtable _objects;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public StaticMessageSource()
+ {
+ _messages = new Hashtable();
+ _objects = new Hashtable();
+ }
+
+ ///
+ /// Returns a format string.
+ ///
+ /// The code of the message to resolve.
+ ///
+ /// The to resolve the
+ /// code for.
+ ///
+ ///
+ /// A format string or if not found.
+ ///
+ ///
+ protected override string ResolveMessage(string code, CultureInfo cultureInfo)
+ {
+ return (string) _messages[GetLookupKey(code, cultureInfo)];
+ }
+
+ ///
+ /// Resolves an object (typically an icon or bitmap).
+ ///
+ /// The code of the object to resolve.
+ ///
+ /// The to resolve the
+ /// code for.
+ ///
+ ///
+ /// The resolved object or if not found.
+ ///
+ ///
+ protected override object ResolveObject(string code, CultureInfo cultureInfo)
+ {
+ return _objects[GetLookupKey(code, cultureInfo)];
+ }
+
+
+ // *** NOTE Don't use cref for ComponentResourceManager as it doesn't
+ // exist on 1.0
+ //
+
+ ///
+ /// Applies resources to object properties.
+ ///
+ ///
+ ///
+ /// Uses a System.ComponentModel.ComponentResourceManager
+ /// internally to apply resources to object properties. Resource key
+ /// names are of the form objectName.propertyName.
+ ///
+ ///
+ /// This feature is not currently supported on version 1.0 of the .NET platform.
+ ///
- /// Type aliases can be used instead of fully qualified type names anywhere
- /// a type name is expected in a Spring.NET configuration file.
- ///
- ///
- /// This includes type names specified within an object definition, as well
- /// as values of the properties or constructor arguments that expect
- /// instances.
- ///
- ///
- ///
- ///
- /// The following example shows how to configure both this section handler and
- /// how to define type aliases within a Spring.NET config section:
- ///
+ /// Type aliases can be used instead of fully qualified type names anywhere
+ /// a type name is expected in a Spring.NET configuration file.
+ ///
+ ///
+ /// This includes type names specified within an object definition, as well
+ /// as values of the properties or constructor arguments that expect
+ /// instances.
+ ///
+ ///
+ ///
+ ///
+ /// The following example shows how to configure both this section handler and
+ /// how to define type aliases within a Spring.NET config section:
+ ///
- /// Type converters are used to convert objects from one type into another
- /// when injecting property values, evaluating expressions, performing data
- /// binding, etc.
- ///
- ///
- /// They are a very powerful mechanism as they allow Spring.NET to automatically
- /// convert string-based property values from the configuration file into the appropriate
- /// type based on the target property's type or to convert string values submitted
- /// via a web form into a type that is used by your data model when Spring.NET data
- /// binding is used. Because they offer such tremendous help, you should always provide
- /// a type converter implementation for your custom types that you want to be able to use
- /// for injected properties or for data binding.
- ///
- ///
- /// The standard .NET mechanism for specifying type converter for a particular type is
- /// to decorate the type with a , passing the type
- /// of the -derived class as a parameter.
- ///
- ///
- /// This mechanism will still work and is a preferred way of defining type converters if
- /// you control the source code for the type that you want to define a converter for. However,
- /// this configuration section allows you to specify converters for the types that you don't
- /// control and it also allows you to override some of the standard type converters, such as
- /// the ones that are defined for some of the types in the .NET Base Class Library.
- ///
- ///
- ///
- ///
- /// The following example shows how to configure both this section handler and
- /// how to define type converters within a Spring.NET config section:
- ///
+ /// Type converters are used to convert objects from one type into another
+ /// when injecting property values, evaluating expressions, performing data
+ /// binding, etc.
+ ///
+ ///
+ /// They are a very powerful mechanism as they allow Spring.NET to automatically
+ /// convert string-based property values from the configuration file into the appropriate
+ /// type based on the target property's type or to convert string values submitted
+ /// via a web form into a type that is used by your data model when Spring.NET data
+ /// binding is used. Because they offer such tremendous help, you should always provide
+ /// a type converter implementation for your custom types that you want to be able to use
+ /// for injected properties or for data binding.
+ ///
+ ///
+ /// The standard .NET mechanism for specifying type converter for a particular type is
+ /// to decorate the type with a , passing the type
+ /// of the -derived class as a parameter.
+ ///
+ ///
+ /// This mechanism will still work and is a preferred way of defining type converters if
+ /// you control the source code for the type that you want to define a converter for. However,
+ /// this configuration section allows you to specify converters for the types that you don't
+ /// control and it also allows you to override some of the standard type converters, such as
+ /// the ones that are defined for some of the types in the .NET Base Class Library.
+ ///
+ ///
+ ///
+ ///
+ /// The following example shows how to configure both this section handler and
+ /// how to define type converters within a Spring.NET config section:
+ ///
- /// Currently, the resources that are supported are the file,
- /// http, ftp, config and assembly resource
- /// types.
- ///
- ///
- /// You can provide custom implementations of the
- /// interface and and register them
- /// with any that inherits
- /// from the
- ///
- /// interface.
- ///
- ///
- /// In case of multiple config locations, later object definitions will
- /// override ones defined in previously loaded resources. This can be
- /// leveraged to deliberately override certain object definitions via an
- /// extra XML file.
- ///
- ///
- ///
- ///
- /// Find below some examples of instantiating an
- /// using a
- /// variety of different XML resources.
- ///
+ /// Currently, the resources that are supported are the file,
+ /// http, ftp, config and assembly resource
+ /// types.
+ ///
+ ///
+ /// You can provide custom implementations of the
+ /// interface and and register them
+ /// with any that inherits
+ /// from the
+ ///
+ /// interface.
+ ///
+ ///
+ /// In case of multiple config locations, later object definitions will
+ /// override ones defined in previously loaded resources. This can be
+ /// leveraged to deliberately override certain object definitions via an
+ /// extra XML file.
+ ///
+ ///
+ ///
+ ///
+ /// Find below some examples of instantiating an
+ /// using a
+ /// variety of different XML resources.
+ ///
- ///
- ///
- bool IControlFlow.Under(Type type, string methodName)
- {
- ComposedCriteria criteria = new ComposedCriteria();
- criteria.Add(new MethodsDeclaredTypeCriteria(type));
- criteria.Add(new RegularExpressionMethodNameCriteria(methodName));
- return IsMatch(criteria);
- }
-
- ///
- /// Does the current stack trace contain the supplied ?
- ///
- ///
- ///
- /// This leaves it up to the caller to decide what matches, but is obviously less of
- /// an abstraction because the caller must know the exact format of the underlying
- /// stack trace.
- ///
+ ///
+ ///
+ bool IControlFlow.Under(Type type, string methodName)
+ {
+ ComposedCriteria criteria = new ComposedCriteria();
+ criteria.Add(new MethodsDeclaredTypeCriteria(type));
+ criteria.Add(new RegularExpressionMethodNameCriteria(methodName));
+ return IsMatch(criteria);
+ }
+
+ ///
+ /// Does the current stack trace contain the supplied ?
+ ///
+ ///
+ ///
+ /// This leaves it up to the caller to decide what matches, but is obviously less of
+ /// an abstraction because the caller must know the exact format of the underlying
+ /// stack trace.
+ ///
+ /// The error code is a , rather than a number, so it can
+ /// be given user-readable values, such as "object.failureDescription".
+ ///
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.Net)
+ public interface IErrorCoded
+ {
+ ///
+ /// Return the error code associated with this failure.
+ ///
+ ///
+ ///
+ /// The GUI can render this anyway it pleases, allowing for I18n etc.
+ ///
- /// The method will
- /// check whether a or
- /// can be opened;
- /// will always return
- /// ;
- /// and
- /// throw an exception;
- /// and will
- /// return the value of the
- /// property.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// Aleksandar Seovic (.NET)
- /// $Id: AbstractResource.cs,v 1.25 2007/12/06 22:08:47 markpollack Exp $
- ///
- public abstract class AbstractResource : IResource
- {
- ///
- /// The default special character that denotes the base (home, or root)
- /// path.
- ///
- ///
- ///
- /// Will be resolved (by those
- /// implementations that support it) to the home (or root) path for
- /// the specific implementation.
- ///
- ///
- /// For example, in the case of a web application this will (probably)
- /// resolve to the virtual directory of said web application.
- ///
- ///
- protected const string DefaultBasePathPlaceHolder = "~";
-
- private string protocol;
- private string basePathPlaceHolder = DefaultBasePathPlaceHolder;
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractResource()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- ///
- /// A string representation of the resource.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s).
- ///
- protected AbstractResource(string resourceName)
- {
- AssertUtils.ArgumentHasText(resourceName, "resourceName");
- protocol = ConfigurableResourceLoader.GetProtocol(resourceName);
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The special character that denotes the base (home, or root)
- /// path.
- ///
- ///
- ///
- /// Will be resolved (by those
- /// implementations that support it) to the home (or root) path for
- /// the specific implementation.
- ///
- ///
- /// For example, in the case of a web application this will (probably)
- /// resolve to the virtual directory of said web application.
- ///
- ///
- ///
- public string BasePathPlaceHolder
- {
- get { return basePathPlaceHolder; }
- set { basePathPlaceHolder = value; }
- }
-
- ///
- /// Return an for this resource.
- ///
- ///
- /// An .
- ///
- ///
- /// If the stream could not be opened.
- ///
- ///
- public abstract Stream InputStream { get; }
-
- ///
- /// Returns a description for this resource.
- ///
- ///
- /// A description for this resource.
- ///
- ///
- public abstract string Description { get; }
-
- ///
- /// Returns the protocol associated with this resource (if any).
- ///
- ///
- ///
- /// The value of this property may be if no
- /// protocol is associated with the resource type (for example if the
- /// resource is a memory stream).
- ///
- ///
- ///
- /// The protocol associated with this resource (if any).
- ///
- public string Protocol
- {
- get { return protocol; }
- }
-
- ///
- /// Does this resource represent a handle with an open stream?
- ///
- ///
- ///
- ///
- ///
- /// if this resource represents a handle with an
- /// open stream.
- ///
- ///
- public virtual bool IsOpen
- {
- get { return false; }
- }
-
- ///
- /// Returns the handle for this resource.
- ///
- ///
- ///
- /// This, the default implementation, always throws a
- /// , assuming that the
- /// resource cannot be exposed as a .
- ///
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// This, the default implementation, always throws a
- /// .
- ///
- ///
- public virtual Uri Uri
- {
- get
- {
- throw new FileNotFoundException(
- Description + " cannot be resolved to a Uri.");
- }
- }
-
- ///
- /// Returns a handle for this resource.
- ///
- ///
- ///
- /// This, the default implementation, always throws a
- /// , assuming that the
- /// resource cannot be resolved to an absolute file path.
- ///
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// This implementation always throws a
- /// .
- ///
- ///
- ///
- public virtual FileInfo File
- {
- get
- {
- throw new FileNotFoundException(
- Description + " cannot be resolved to an absolute file path.");
- }
- }
-
- ///
- /// Does this resource actually exist in physical form?
- ///
- ///
- ///
- /// This implementation checks whether a
- /// can be opened, falling back to whether a
- /// can be opened.
- ///
- ///
- /// This will cover both directories and content resources.
- ///
- ///
- /// This implementation will also return if
- /// permission to the (file's) path is denied.
- ///
- ///
- ///
- /// if this resource actually exists in physical
- /// form (for example on a filesystem).
- ///
- ///
- ///
- public virtual bool Exists
- {
- get
- {
- try
- {
- return File.Exists;
- }
- catch (IOException)
- {
- try
- {
- Stream inputStream = InputStream;
- inputStream.Close();
- return true;
- } catch (Exception)
- {
- return false;
- }
- }
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Strips any protocol name from the supplied
- /// .
- ///
- ///
- ///
- /// If the supplied does not
- /// have any protocol associated with it, then the supplied
- /// will be returned as-is.
- ///
- ///
- ///
- ///
- /// GetResourceNameWithoutProtocol("http://www.mycompany.com/resource.txt");
- /// // returns www.mycompany.com/resource.txt
- ///
- ///
- ///
- /// The name of the resource.
- ///
- ///
- /// The name of the resource without the protocol name.
- ///
- protected static string GetResourceNameWithoutProtocol(string resourceName)
- {
- int pos = resourceName.IndexOf(
- ConfigurableResourceLoader.ProtocolSeparator);
- if (pos == -1)
- {
- return resourceName;
- }
- else
- {
- return resourceName.Substring(pos + ConfigurableResourceLoader.ProtocolSeparator.Length);
- }
- }
-
- ///
- /// Resolves the supplied to its value
- /// sans any leading protocol.
- ///
- ///
- /// The name of the resource.
- ///
- ///
- /// The name of the resource without the protocol name.
- ///
- ///
- protected virtual string ResolveResourceNameWithoutProtocol(string resourceName)
- {
- return ResolveBasePathPlaceHolder(
- GetResourceNameWithoutProtocol(resourceName), BasePathPlaceHolder);
- }
-
- ///
- /// Resolves the presence of the
- /// value
- /// in the supplied into a path.
- ///
- ///
- ///
- /// The default implementation simply returns the supplied
- /// as is.
- ///
- ///
- ///
- /// The name of the resource.
- ///
- ///
- /// The string that is a placeholder for a base path.
- ///
- ///
- /// The name of the resource with any
- /// value having been resolved into an actual path.
- ///
- protected virtual string ResolveBasePathPlaceHolder(
- string resourceName, string basePathPlaceHolder)
- {
- return resourceName;
- }
-
- ///
- /// This implementation returns the
- /// of this resource.
- ///
- ///
- public override string ToString()
- {
- return Description;
- }
-
- ///
- /// Determines whether the specified is
- /// equal to the current .
- ///
- ///
- ///
- /// This implementation compares values.
- ///
- ///
- ///
- public override bool Equals(object obj)
- {
- return obj is IResource
- && ((IResource)obj).Description.Equals(Description);
- }
-
- ///
- /// Serves as a hash function for a particular type, suitable for use
- /// in hashing algorithms and data structures like a hash table.
- ///
- ///
- ///
- /// This implementation returns the hashcode of the
- /// property.
- ///
- ///
- ///
- public override int GetHashCode()
- {
- return Description.GetHashCode();
- }
-
- #endregion
-
- #region Relative Resource Support
-
- ///
- /// Factory Method. Create a new instance of the current resource type using the given resourceName
- ///
- protected virtual IResource CreateResourceInstance( string resourceName )
- {
- return null;
- }
-
- ///
- /// The ResourceLoader to be used for resolving relative resources
- ///
- protected virtual IResourceLoader GetResourceLoader()
- {
- return new ConfigurableResourceLoader();
- }
-
- ///
- /// Does this support relative
- /// resource retrieval?
- ///
- ///
- ///
- /// This property is generally to be consulted prior to attempting
- /// to attempting to access a resource that is relative to this
- /// resource (via a call to
- /// ).
- ///
- ///
- ///
- /// if this
- /// supports relative resource
- /// retrieval.
- ///
- protected virtual bool SupportsRelativeResources
- {
- get { return false; }
- }
-
- ///
- /// Gets the root location of the resource.
- ///
- ///
- ///
- /// Where root resource can be taken to mean that part of the resource
- /// descriptor that doesn't change when a relative resource is looked
- /// up. Examples of such a root location would include a drive letter,
- /// a web server name, an assembly name, etc.
- ///
- ///
- ///
- /// The root location of the resource.
- ///
- ///
- /// This, the default implementation, always throws a
- /// .
- ///
- protected virtual string RootLocation
- {
- get { throw new NotSupportedException(); }
- }
-
- ///
- /// Gets the current path of the resource.
- ///
- ///
- ///
- /// An example value of this property would be the name of the
- /// directory containing a filesystem based resource.
- ///
- ///
- ///
- /// The current path of the resource.
- ///
- ///
- /// This, the default implementation, always throws a
- /// .
- ///
- protected virtual string ResourcePath
- {
- get { throw new NotSupportedException(); }
- }
-
- ///
- /// Gets those characters that are valid path separators for the
- /// resource type.
- ///
- ///
- ///
- /// An example value of this property would be the
- /// and
- /// values for a
- /// filesystem based resource.
- ///
- ///
- /// Any derived classes that override this method are expected to
- /// return a new array for each access of this property.
- ///
- ///
- ///
- /// Those characters that are valid path separators for the resource
- /// type.
- ///
- ///
- /// This, the default implementation, always throws a
- /// .
- ///
- protected virtual char[] PathSeparatorChars
- {
- get { throw new NotSupportedException(); }
- }
-
- ///
- /// Does the supplied relative ?
- ///
- ///
- /// The name of the resource to test.
- ///
- ///
- /// if resource name is relative;
- /// otherwise .
- ///
- protected virtual bool IsRelativeResource(string resourceName)
- {
- return false;
- }
-
- ///
- /// Creates a new resource that is relative to this resource based on the
- /// supplied .
- ///
- ///
- ///
- /// This method can accept either a fully qualified resource name or a
- /// relative resource name as it's parameter.
- ///
- ///
- /// A fully qualified resource is one that has a protocol prefix and
- /// all elements of the resource name. All other resources are treated
- /// as relative to this resource, and the following rules are used to
- /// locate a relative resource:
- ///
+ /// The method will
+ /// check whether a or
+ /// can be opened;
+ /// will always return
+ /// ;
+ /// and
+ /// throw an exception;
+ /// and will
+ /// return the value of the
+ /// property.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ /// Aleksandar Seovic (.NET)
+ ///
+ public abstract class AbstractResource : IResource
+ {
+ ///
+ /// The default special character that denotes the base (home, or root)
+ /// path.
+ ///
+ ///
+ ///
+ /// Will be resolved (by those
+ /// implementations that support it) to the home (or root) path for
+ /// the specific implementation.
+ ///
+ ///
+ /// For example, in the case of a web application this will (probably)
+ /// resolve to the virtual directory of said web application.
+ ///
+ ///
+ protected const string DefaultBasePathPlaceHolder = "~";
+
+ private string protocol;
+ private string basePathPlaceHolder = DefaultBasePathPlaceHolder;
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractResource()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ ///
+ /// A string representation of the resource.
+ ///
+ ///
+ /// If the supplied is
+ /// or contains only whitespace character(s).
+ ///
+ protected AbstractResource(string resourceName)
+ {
+ AssertUtils.ArgumentHasText(resourceName, "resourceName");
+ protocol = ConfigurableResourceLoader.GetProtocol(resourceName);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The special character that denotes the base (home, or root)
+ /// path.
+ ///
+ ///
+ ///
+ /// Will be resolved (by those
+ /// implementations that support it) to the home (or root) path for
+ /// the specific implementation.
+ ///
+ ///
+ /// For example, in the case of a web application this will (probably)
+ /// resolve to the virtual directory of said web application.
+ ///
+ ///
+ ///
+ public string BasePathPlaceHolder
+ {
+ get { return basePathPlaceHolder; }
+ set { basePathPlaceHolder = value; }
+ }
+
+ ///
+ /// Return an for this resource.
+ ///
+ ///
+ /// An .
+ ///
+ ///
+ /// If the stream could not be opened.
+ ///
+ ///
+ public abstract Stream InputStream { get; }
+
+ ///
+ /// Returns a description for this resource.
+ ///
+ ///
+ /// A description for this resource.
+ ///
+ ///
+ public abstract string Description { get; }
+
+ ///
+ /// Returns the protocol associated with this resource (if any).
+ ///
+ ///
+ ///
+ /// The value of this property may be if no
+ /// protocol is associated with the resource type (for example if the
+ /// resource is a memory stream).
+ ///
+ ///
+ ///
+ /// The protocol associated with this resource (if any).
+ ///
+ public string Protocol
+ {
+ get { return protocol; }
+ }
+
+ ///
+ /// Does this resource represent a handle with an open stream?
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// if this resource represents a handle with an
+ /// open stream.
+ ///
+ ///
+ public virtual bool IsOpen
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Returns the handle for this resource.
+ ///
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// , assuming that the
+ /// resource cannot be exposed as a .
+ ///
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// .
+ ///
+ ///
+ public virtual Uri Uri
+ {
+ get
+ {
+ throw new FileNotFoundException(
+ Description + " cannot be resolved to a Uri.");
+ }
+ }
+
+ ///
+ /// Returns a handle for this resource.
+ ///
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// , assuming that the
+ /// resource cannot be resolved to an absolute file path.
+ ///
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// This implementation always throws a
+ /// .
+ ///
+ ///
+ ///
+ public virtual FileInfo File
+ {
+ get
+ {
+ throw new FileNotFoundException(
+ Description + " cannot be resolved to an absolute file path.");
+ }
+ }
+
+ ///
+ /// Does this resource actually exist in physical form?
+ ///
+ ///
+ ///
+ /// This implementation checks whether a
+ /// can be opened, falling back to whether a
+ /// can be opened.
+ ///
+ ///
+ /// This will cover both directories and content resources.
+ ///
+ ///
+ /// This implementation will also return if
+ /// permission to the (file's) path is denied.
+ ///
+ ///
+ ///
+ /// if this resource actually exists in physical
+ /// form (for example on a filesystem).
+ ///
+ ///
+ ///
+ public virtual bool Exists
+ {
+ get
+ {
+ try
+ {
+ return File.Exists;
+ }
+ catch (IOException)
+ {
+ try
+ {
+ Stream inputStream = InputStream;
+ inputStream.Close();
+ return true;
+ } catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Strips any protocol name from the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// If the supplied does not
+ /// have any protocol associated with it, then the supplied
+ /// will be returned as-is.
+ ///
+ ///
+ ///
+ ///
+ /// GetResourceNameWithoutProtocol("http://www.mycompany.com/resource.txt");
+ /// // returns www.mycompany.com/resource.txt
+ ///
+ ///
+ ///
+ /// The name of the resource.
+ ///
+ ///
+ /// The name of the resource without the protocol name.
+ ///
+ protected static string GetResourceNameWithoutProtocol(string resourceName)
+ {
+ int pos = resourceName.IndexOf(
+ ConfigurableResourceLoader.ProtocolSeparator);
+ if (pos == -1)
+ {
+ return resourceName;
+ }
+ else
+ {
+ return resourceName.Substring(pos + ConfigurableResourceLoader.ProtocolSeparator.Length);
+ }
+ }
+
+ ///
+ /// Resolves the supplied to its value
+ /// sans any leading protocol.
+ ///
+ ///
+ /// The name of the resource.
+ ///
+ ///
+ /// The name of the resource without the protocol name.
+ ///
+ ///
+ protected virtual string ResolveResourceNameWithoutProtocol(string resourceName)
+ {
+ return ResolveBasePathPlaceHolder(
+ GetResourceNameWithoutProtocol(resourceName), BasePathPlaceHolder);
+ }
+
+ ///
+ /// Resolves the presence of the
+ /// value
+ /// in the supplied into a path.
+ ///
+ ///
+ ///
+ /// The default implementation simply returns the supplied
+ /// as is.
+ ///
+ ///
+ ///
+ /// The name of the resource.
+ ///
+ ///
+ /// The string that is a placeholder for a base path.
+ ///
+ ///
+ /// The name of the resource with any
+ /// value having been resolved into an actual path.
+ ///
+ protected virtual string ResolveBasePathPlaceHolder(
+ string resourceName, string basePathPlaceHolder)
+ {
+ return resourceName;
+ }
+
+ ///
+ /// This implementation returns the
+ /// of this resource.
+ ///
+ ///
+ public override string ToString()
+ {
+ return Description;
+ }
+
+ ///
+ /// Determines whether the specified is
+ /// equal to the current .
+ ///
+ ///
+ ///
+ /// This implementation compares values.
+ ///
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is IResource
+ && ((IResource)obj).Description.Equals(Description);
+ }
+
+ ///
+ /// Serves as a hash function for a particular type, suitable for use
+ /// in hashing algorithms and data structures like a hash table.
+ ///
+ ///
+ ///
+ /// This implementation returns the hashcode of the
+ /// property.
+ ///
+ ///
+ ///
+ public override int GetHashCode()
+ {
+ return Description.GetHashCode();
+ }
+
+ #endregion
+
+ #region Relative Resource Support
+
+ ///
+ /// Factory Method. Create a new instance of the current resource type using the given resourceName
+ ///
+ protected virtual IResource CreateResourceInstance( string resourceName )
+ {
+ return null;
+ }
+
+ ///
+ /// The ResourceLoader to be used for resolving relative resources
+ ///
+ protected virtual IResourceLoader GetResourceLoader()
+ {
+ return new ConfigurableResourceLoader();
+ }
+
+ ///
+ /// Does this support relative
+ /// resource retrieval?
+ ///
+ ///
+ ///
+ /// This property is generally to be consulted prior to attempting
+ /// to attempting to access a resource that is relative to this
+ /// resource (via a call to
+ /// ).
+ ///
+ ///
+ ///
+ /// if this
+ /// supports relative resource
+ /// retrieval.
+ ///
+ protected virtual bool SupportsRelativeResources
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Gets the root location of the resource.
+ ///
+ ///
+ ///
+ /// Where root resource can be taken to mean that part of the resource
+ /// descriptor that doesn't change when a relative resource is looked
+ /// up. Examples of such a root location would include a drive letter,
+ /// a web server name, an assembly name, etc.
+ ///
+ ///
+ ///
+ /// The root location of the resource.
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// .
+ ///
+ protected virtual string RootLocation
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ ///
+ /// Gets the current path of the resource.
+ ///
+ ///
+ ///
+ /// An example value of this property would be the name of the
+ /// directory containing a filesystem based resource.
+ ///
+ ///
+ ///
+ /// The current path of the resource.
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// .
+ ///
+ protected virtual string ResourcePath
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ ///
+ /// Gets those characters that are valid path separators for the
+ /// resource type.
+ ///
+ ///
+ ///
+ /// An example value of this property would be the
+ /// and
+ /// values for a
+ /// filesystem based resource.
+ ///
+ ///
+ /// Any derived classes that override this method are expected to
+ /// return a new array for each access of this property.
+ ///
+ ///
+ ///
+ /// Those characters that are valid path separators for the resource
+ /// type.
+ ///
+ ///
+ /// This, the default implementation, always throws a
+ /// .
+ ///
+ protected virtual char[] PathSeparatorChars
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ ///
+ /// Does the supplied relative ?
+ ///
+ ///
+ /// The name of the resource to test.
+ ///
+ ///
+ /// if resource name is relative;
+ /// otherwise .
+ ///
+ protected virtual bool IsRelativeResource(string resourceName)
+ {
+ return false;
+ }
+
+ ///
+ /// Creates a new resource that is relative to this resource based on the
+ /// supplied .
+ ///
+ ///
+ ///
+ /// This method can accept either a fully qualified resource name or a
+ /// relative resource name as it's parameter.
+ ///
+ ///
+ /// A fully qualified resource is one that has a protocol prefix and
+ /// all elements of the resource name. All other resources are treated
+ /// as relative to this resource, and the following rules are used to
+ /// locate a relative resource:
+ ///
+ ///
+ /// Aleksandar Seovic (.NET)
+ /// Federico Spinazzi (.NET)
+ public class AssemblyResource : AbstractResource
+ {
+ #region Fields
+
+ private Assembly _assembly;
+ private string[] _resources;
+ private string _resourceName;
+ private string _fullResourceName;
+ private string _resourceNamespace;
+ private string _resourceAssemblyName;
+ private static readonly ILog log = LogManager.GetLogger(typeof(AssemblyResource));
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The name of the assembly resource.
+ ///
+ ///
+ /// If the supplied did not conform
+ /// to the expected format.
+ ///
+ ///
+ /// If the assembly specified in the supplied
+ /// was loaded twice with two
+ /// different evidences.
+ ///
+ ///
+ /// If the assembly specified in the supplied
+ /// could not be found.
+ ///
+ ///
+ /// If the caller does not have the required permission to load
+ /// the assembly specified in the supplied
+ /// .
+ ///
+ ///
+ public AssemblyResource(string resourceName) : base(resourceName)
+ {
+ string[] info = GetResourceNameWithoutProtocol(resourceName).Split('/');
+ if (info.Length != 3)
+ {
+ throw new UriFormatException(
+ "Invalid resource name. Name has to be in " +
+ "'assembly://' format.");
+ }
+#if NET_2_0
+ this._assembly = Assembly.Load(info[0]);
+#else
+ this._assembly = Assembly.LoadWithPartialName(info[0]);
+#endif
+ if (this._assembly == null)
+ {
+ throw new FileNotFoundException("Unable to load assembly [" + info[0] + "]");
+ }
+ this._fullResourceName = resourceName;
+ this._resourceAssemblyName = info[0];
+ this._resourceNamespace = info[1];
+ this._resourceName = String.Format("{0}.{1}", info[1], info[2]);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Return an for this resource.
+ ///
+ ///
+ /// An .
+ ///
+ ///
+ /// If the stream could not be opened.
+ ///
+ ///
+ /// If the caller does not have the required permission to load
+ /// the underlying assembly's manifest.
+ ///
+ ///
+ ///
+ public override Stream InputStream
+ {
+ get
+ {
+ Stream stream = _assembly.GetManifestResourceStream(_resourceName);
+ if (stream == null)
+ {
+ log.Error("Could not load resource with name = [" + _resourceName +
+ "] from assembly + " + _assembly);
+ log.Error("URI specified = [" + this._fullResourceName + "] Spring.NET URI syntax is 'assembly://assemblyName/namespace/resourceName'.");
+ log.Error("Resource name often has the default namespace prefixed, e.g. 'assembly://MyAssembly/MyNamespace/MyNamespace.MyResource.txt'.");
+ }
+ return stream;
+ }
+ }
+
+ ///
+ /// Does the embedded resource specified in the value passed to the
+ /// constructor exist?
+ ///
+ ///
+ /// if this resource actually exists in physical
+ /// form (for example on a filesystem).
+ ///
+ ///
+ ///
+ ///
+ public override bool Exists
+ {
+ get
+ {
+ if (_resources == null)
+ {
+ _resources = _assembly.GetManifestResourceNames();
+ Array.Sort(_resources);
+ }
+ return (Array.BinarySearch(_resources, _resourceName) >= 0);
+ }
+ }
+
+ ///
+ /// Does this support relative
+ /// resource retrieval?
+ ///
+ ///
+ ///
+ /// This implementation does support relative resource retrieval, and
+ /// so will always return .
+ ///
- /// If created with the name of a configuration section, then all methods
- /// aside from the description return ,
- /// , or throw an exception. If created with an
- /// , then the
- /// property
- /// will return a corresponding to parse.
- ///
- ///
- /// Mark Pollack
- /// Rick Evans
- /// $Id: ConfigSectionResource.cs,v 1.27 2007/12/05 00:57:31 bbaia Exp $
- public class ConfigSectionResource : AbstractResource
- {
- private XmlElement configElement;
- private string sectionName;
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates new instance of the
- /// class.
- ///
- ///
- /// The actual XML configuration section.
- ///
- ///
- /// If the supplied is .
- ///
- public ConfigSectionResource(XmlElement configSection)
- {
- AssertUtils.ArgumentNotNull(configSection, "configSection");
- sectionName = configSection.Name;
- configElement = configSection;
- }
-
- ///
- /// Creates new instance of the
- /// class.
- ///
- ///
- /// The name of the configuration section.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s).
- ///
- public ConfigSectionResource(string resourceName) : base(resourceName)
- {
- AssertUtils.ArgumentHasText(resourceName, "resourceName");
- sectionName = GetResourceNameWithoutProtocol(resourceName);
- configElement = (XmlElement) ConfigurationUtils.GetSection(sectionName);
- }
-
- #endregion
-
- #region IResource Members
-
- ///
- /// Returns the handle for this resource.
- ///
- ///
- ///
- /// This implementation always returns .
- ///
- ///
- ///
- /// .
- ///
- ///
- public override Uri Uri
- {
- get { return null; }
- }
-
- ///
- /// Returns a handle for this resource.
- ///
- ///
- ///
- /// This implementation always returns .
- ///
- ///
- ///
- /// .
- ///
- ///
- public override FileInfo File
- {
- get { return null; }
- }
-
- ///
- /// Returns a description for this resource (the name of the
- /// configuration section in this case).
- ///
- ///
- /// A description for this resource.
- ///
- ///
- public override string Description
- {
- get
- {
- return StringUtils.Surround("config [", sectionName, "]");
- }
- }
-
- ///
- /// Does this resource actually exist in physical form?
- ///
- ///
- ///
- /// This implementation always returns .
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public override bool Exists
- {
- get { return false; }
- }
-
- #endregion
-
- #region IInputStreamSource Members
-
- ///
- /// Return an for this resource.
- ///
- ///
- /// An .
- ///
- ///
- /// If the stream could not be opened.
- ///
- ///
- public override Stream InputStream
- {
- get { return new MemoryStream(Encoding.UTF8.GetBytes(configElement.OuterXml)); }
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Exposes the actual for the
- /// configuration section.
- ///
- ///
- ///
- /// Introduced to accomodate line info tracking during parsing.
- ///
+ /// If created with the name of a configuration section, then all methods
+ /// aside from the description return ,
+ /// , or throw an exception. If created with an
+ /// , then the
+ /// property
+ /// will return a corresponding to parse.
+ ///
+ ///
+ /// Mark Pollack
+ /// Rick Evans
+ public class ConfigSectionResource : AbstractResource
+ {
+ private XmlElement configElement;
+ private string sectionName;
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates new instance of the
+ /// class.
+ ///
+ ///
+ /// The actual XML configuration section.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public ConfigSectionResource(XmlElement configSection)
+ {
+ AssertUtils.ArgumentNotNull(configSection, "configSection");
+ sectionName = configSection.Name;
+ configElement = configSection;
+ }
+
+ ///
+ /// Creates new instance of the
+ /// class.
+ ///
+ ///
+ /// The name of the configuration section.
+ ///
+ ///
+ /// If the supplied is
+ /// or contains only whitespace character(s).
+ ///
+ public ConfigSectionResource(string resourceName) : base(resourceName)
+ {
+ AssertUtils.ArgumentHasText(resourceName, "resourceName");
+ sectionName = GetResourceNameWithoutProtocol(resourceName);
+ configElement = (XmlElement) ConfigurationUtils.GetSection(sectionName);
+ }
+
+ #endregion
+
+ #region IResource Members
+
+ ///
+ /// Returns the handle for this resource.
+ ///
+ ///
+ ///
+ /// This implementation always returns .
+ ///
+ ///
+ ///
+ /// .
+ ///
+ ///
+ public override Uri Uri
+ {
+ get { return null; }
+ }
+
+ ///
+ /// Returns a handle for this resource.
+ ///
+ ///
+ ///
+ /// This implementation always returns .
+ ///
+ ///
+ ///
+ /// .
+ ///
+ ///
+ public override FileInfo File
+ {
+ get { return null; }
+ }
+
+ ///
+ /// Returns a description for this resource (the name of the
+ /// configuration section in this case).
+ ///
+ ///
+ /// A description for this resource.
+ ///
+ ///
+ public override string Description
+ {
+ get
+ {
+ return StringUtils.Surround("config [", sectionName, "]");
+ }
+ }
+
+ ///
+ /// Does this resource actually exist in physical form?
+ ///
+ ///
+ ///
+ /// This implementation always returns .
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool Exists
+ {
+ get { return false; }
+ }
+
+ #endregion
+
+ #region IInputStreamSource Members
+
+ ///
+ /// Return an for this resource.
+ ///
+ ///
+ /// An .
+ ///
+ ///
+ /// If the stream could not be opened.
+ ///
+ ///
+ public override Stream InputStream
+ {
+ get { return new MemoryStream(Encoding.UTF8.GetBytes(configElement.OuterXml)); }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Exposes the actual for the
+ /// configuration section.
+ ///
+ ///
+ ///
+ /// Introduced to accomodate line info tracking during parsing.
+ ///
- /// This implementation
- /// supports the configuration of resource access protocols and the
- /// corresponding .NET types that know how to handle those protocols.
- ///
- ///
- /// Basic protocol-to-resource type mappings are also defined by this class,
- /// while others can be added either internally, by application contexts
- /// extending this class, or externally, by the end user configuring the
- /// context.
- ///
- ///
- /// Only one resource type can be defined for each protocol, but multiple
- /// protocols can map to the same resource type (for example, the
- /// "http" and "ftp" protocols both map to the
- /// type. The protocols that are
- /// mapped by default can be found in the following list.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: ConfigurableResourceLoader.cs,v 1.25 2007/08/08 17:46:55 bbaia Exp $
- ///
- ///
- ///
- public class ConfigurableResourceLoader : IResourceLoader
- {
- ///
- /// The separator between the protocol name and the resource name.
- ///
- public const string ProtocolSeparator = "://";
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public ConfigurableResourceLoader()
- { }
-
- ///
- /// Creates a new instance of the
- /// class using the specified default protocol for unqualified resources.
- ///
- public ConfigurableResourceLoader(string defaultProtocol)
- {
- AssertUtils.ArgumentNotNull(defaultProtocol, "defaultProtocol");
- this.defaultProtocol = defaultProtocol;
- }
-
- ///
- /// The default protocol to use for unqualified resources.
- ///
- ///
- ///
+ /// This implementation
+ /// supports the configuration of resource access protocols and the
+ /// corresponding .NET types that know how to handle those protocols.
+ ///
+ ///
+ /// Basic protocol-to-resource type mappings are also defined by this class,
+ /// while others can be added either internally, by application contexts
+ /// extending this class, or externally, by the end user configuring the
+ /// context.
+ ///
+ ///
+ /// Only one resource type can be defined for each protocol, but multiple
+ /// protocols can map to the same resource type (for example, the
+ /// "http" and "ftp" protocols both map to the
+ /// type. The protocols that are
+ /// mapped by default can be found in the following list.
+ ///
+ ///
+ /// Aleksandar Seovic
+ ///
+ ///
+ ///
+ public class ConfigurableResourceLoader : IResourceLoader
+ {
+ ///
+ /// The separator between the protocol name and the resource name.
+ ///
+ public const string ProtocolSeparator = "://";
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public ConfigurableResourceLoader()
+ { }
+
+ ///
+ /// Creates a new instance of the
+ /// class using the specified default protocol for unqualified resources.
+ ///
+ public ConfigurableResourceLoader(string defaultProtocol)
+ {
+ AssertUtils.ArgumentNotNull(defaultProtocol, "defaultProtocol");
+ this.defaultProtocol = defaultProtocol;
+ }
+
+ ///
+ /// The default protocol to use for unqualified resources.
+ ///
+ ///
+ ///
- /// Supports resolution as both a and a
- /// .
- ///
- ///
- /// Also supports the use of the ~ character. If the ~ character
- /// is the first character in a resource path (sans protocol), the ~
- /// character will be replaced with the value of the
- /// System.AppDomain.CurrentDomain.BaseDirectory property (an example of
- /// this can be seen in the examples below).
- ///
- ///
- ///
- ///
- /// Consider the example of an application that is running (has been launched
- /// from) the C:\App\ directory. The following resource paths will map
- /// to the following resources on the filesystem...
- ///
- ///
- /// strings.txt C:\App\strings.txt
- /// ~/strings.txt C:\App\strings.txt
- /// file://~/strings.txt C:\App\strings.txt
- /// file://~/../strings.txt C:\strings.txt
- /// ../strings.txt C:\strings.txt
- /// ~/../strings.txt C:\strings.txt
- ///
- /// // note that only a leading ~ character is resolved to the executing directory...
- /// stri~ngs.txt C:\App\stri~ngs.txt
- ///
- ///
- /// Juergen Hoeller
- /// Leonardo Susatyo (.NET)
- /// Aleksandar Seovic (.NET)
- /// $Id: FileSystemResource.cs,v 1.23 2007/08/08 17:46:55 bbaia Exp $
- public class FileSystemResource : AbstractResource
- {
- private FileInfo fileHandle;
- private string rootLocation;
- private string resourcePath;
-
- #region Constructors
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- protected FileSystemResource()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The name of the file system resource.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s).
- ///
- public FileSystemResource(string resourceName)
- : this(resourceName, false)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The name of the file system resource.
- ///
- ///
- /// Supresses initialization of this instance. Used from derived classes.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s).
- ///
- protected FileSystemResource(string resourceName, bool suppressInitialize)
- : base(resourceName)
- {
- if (!suppressInitialize)
- {
- Initialize( resourceName );
- }
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Returns the underlying handle for
- /// this resource.
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- public override FileInfo File
- {
- get { return fileHandle; }
- }
-
- ///
- /// Does this support relative
- /// resource retrieval?
- ///
- ///
- ///
- /// This implementation does support relative resource retrieval, and
- /// so will always return .
- ///
+ /// Supports resolution as both a and a
+ /// .
+ ///
+ ///
+ /// Also supports the use of the ~ character. If the ~ character
+ /// is the first character in a resource path (sans protocol), the ~
+ /// character will be replaced with the value of the
+ /// System.AppDomain.CurrentDomain.BaseDirectory property (an example of
+ /// this can be seen in the examples below).
+ ///
+ ///
+ ///
+ ///
+ /// Consider the example of an application that is running (has been launched
+ /// from) the C:\App\ directory. The following resource paths will map
+ /// to the following resources on the filesystem...
+ ///
+ ///
+ /// strings.txt C:\App\strings.txt
+ /// ~/strings.txt C:\App\strings.txt
+ /// file://~/strings.txt C:\App\strings.txt
+ /// file://~/../strings.txt C:\strings.txt
+ /// ../strings.txt C:\strings.txt
+ /// ~/../strings.txt C:\strings.txt
+ ///
+ /// // note that only a leading ~ character is resolved to the executing directory...
+ /// stri~ngs.txt C:\App\stri~ngs.txt
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Leonardo Susatyo (.NET)
+ /// Aleksandar Seovic (.NET)
+ public class FileSystemResource : AbstractResource
+ {
+ private FileInfo fileHandle;
+ private string rootLocation;
+ private string resourcePath;
+
+ #region Constructors
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ protected FileSystemResource()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The name of the file system resource.
+ ///
+ ///
+ /// If the supplied is
+ /// or contains only whitespace character(s).
+ ///
+ public FileSystemResource(string resourceName)
+ : this(resourceName, false)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The name of the file system resource.
+ ///
+ ///
+ /// Supresses initialization of this instance. Used from derived classes.
+ ///
+ ///
+ /// If the supplied is
+ /// or contains only whitespace character(s).
+ ///
+ protected FileSystemResource(string resourceName, bool suppressInitialize)
+ : base(resourceName)
+ {
+ if (!suppressInitialize)
+ {
+ Initialize( resourceName );
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Returns the underlying handle for
+ /// this resource.
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ public override FileInfo File
+ {
+ get { return fileHandle; }
+ }
+
+ ///
+ /// Does this support relative
+ /// resource retrieval?
+ ///
+ ///
+ ///
+ /// This implementation does support relative resource retrieval, and
+ /// so will always return .
+ ///
- /// This interface encapsulates a resource descriptor that abstracts away
- /// from the underlying type of resource; possible resource types include
- /// files, memory streams, and databases (this list is not exhaustive).
- ///
- ///
- /// A can definitely be opened and accessed
- /// for every such resource; if the resource exists in a physical form (for
- /// example, the resource is not an in-memory stream or one that has been
- /// extracted from an assembly or ZIP file), a or
- /// can also be accessed. The actual
- /// behavior is implementation-specific.
- ///
- ///
- /// This interface, when used in tandem with the
- /// interface, forms the backbone of
- /// Spring.NET's resource handling. Third party extensions or libraries
- /// that want to integrate external resources with Spring.NET's IoC
- /// container are encouraged expose such resources via this abstraction.
- ///
- ///
- /// Interfaces cannot obviously mandate implementation, but derived classes
- /// are strongly encouraged to expose a constructor that takes a
- /// single as it's sole argument (see example).
- /// Exposing such a constructor will make your custom
- /// implementation integrate nicely
- /// with the class.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: IResource.cs,v 1.12 2007/08/08 17:46:55 bbaia Exp $
- ///
- ///
- [TypeConverter(typeof(ResourceConverter))]
- public interface IResource : IInputStreamSource
- {
- ///
- /// Does this resource represent a handle with an open stream?
- ///
- ///
- ///
- /// If , the
- /// cannot be read multiple times, and must be read and then closed to
- /// avoid resource leaks.
- ///
- ///
- /// Will be for all usual resource descriptors.
- ///
- ///
- ///
- /// if this resource represents a handle with an
- /// open stream.
- ///
- ///
- bool IsOpen { get; }
-
- ///
- /// Returns the handle for this resource.
- ///
- ///
- ///
- /// For safety, always check the value of the
- /// property prior to
- /// accessing this property; resources that cannot be exposed as
- /// a will typically return
- /// from a call to the
- /// property.
- ///
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// If the resource is not available or cannot be exposed as a
- /// .
- ///
- ///
- ///
- Uri Uri { get; }
-
- ///
- /// Returns a handle for this resource.
- ///
- ///
- ///
- /// For safety, always check the value of the
- /// property prior to
- /// accessing this property; resources that cannot be exposed as
- /// a will typically return
- /// from a call to the
- /// property.
- ///
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// If the resource is not available on a filesystem, or cannot be
- /// exposed as a handle.
- ///
- ///
- ///
- FileInfo File { get; }
-
- ///
- /// Returns a description for this resource.
- ///
- ///
- ///
- /// The description is typically used for diagnostics and other such
- /// logging when working with the resource.
- ///
- ///
- /// Implementations are also encouraged to return this value from their
- /// method.
- ///
- ///
- ///
- /// A description for this resource.
- ///
- string Description { get; }
-
- ///
- /// Does this resource actually exist in physical form?
- ///
- ///
- ///
- /// An example of a resource that physically exists would be a
- /// file on a local filesystem. An example of a resource that does not
- /// physically exist would be an in-memory stream.
- ///
+ /// This interface encapsulates a resource descriptor that abstracts away
+ /// from the underlying type of resource; possible resource types include
+ /// files, memory streams, and databases (this list is not exhaustive).
+ ///
+ ///
+ /// A can definitely be opened and accessed
+ /// for every such resource; if the resource exists in a physical form (for
+ /// example, the resource is not an in-memory stream or one that has been
+ /// extracted from an assembly or ZIP file), a or
+ /// can also be accessed. The actual
+ /// behavior is implementation-specific.
+ ///
+ ///
+ /// This interface, when used in tandem with the
+ /// interface, forms the backbone of
+ /// Spring.NET's resource handling. Third party extensions or libraries
+ /// that want to integrate external resources with Spring.NET's IoC
+ /// container are encouraged expose such resources via this abstraction.
+ ///
+ ///
+ /// Interfaces cannot obviously mandate implementation, but derived classes
+ /// are strongly encouraged to expose a constructor that takes a
+ /// single as it's sole argument (see example).
+ /// Exposing such a constructor will make your custom
+ /// implementation integrate nicely
+ /// with the class.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ ///
+ [TypeConverter(typeof(ResourceConverter))]
+ public interface IResource : IInputStreamSource
+ {
+ ///
+ /// Does this resource represent a handle with an open stream?
+ ///
+ ///
+ ///
+ /// If , the
+ /// cannot be read multiple times, and must be read and then closed to
+ /// avoid resource leaks.
+ ///
+ ///
+ /// Will be for all usual resource descriptors.
+ ///
+ ///
+ ///
+ /// if this resource represents a handle with an
+ /// open stream.
+ ///
+ ///
+ bool IsOpen { get; }
+
+ ///
+ /// Returns the handle for this resource.
+ ///
+ ///
+ ///
+ /// For safety, always check the value of the
+ /// property prior to
+ /// accessing this property; resources that cannot be exposed as
+ /// a will typically return
+ /// from a call to the
+ /// property.
+ ///
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// If the resource is not available or cannot be exposed as a
+ /// .
+ ///
+ ///
+ ///
+ Uri Uri { get; }
+
+ ///
+ /// Returns a handle for this resource.
+ ///
+ ///
+ ///
+ /// For safety, always check the value of the
+ /// property prior to
+ /// accessing this property; resources that cannot be exposed as
+ /// a will typically return
+ /// from a call to the
+ /// property.
+ ///
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// If the resource is not available on a filesystem, or cannot be
+ /// exposed as a handle.
+ ///
+ ///
+ ///
+ FileInfo File { get; }
+
+ ///
+ /// Returns a description for this resource.
+ ///
+ ///
+ ///
+ /// The description is typically used for diagnostics and other such
+ /// logging when working with the resource.
+ ///
+ ///
+ /// Implementations are also encouraged to return this value from their
+ /// method.
+ ///
+ ///
+ ///
+ /// A description for this resource.
+ ///
+ string Description { get; }
+
+ ///
+ /// Does this resource actually exist in physical form?
+ ///
+ ///
+ ///
+ /// An example of a resource that physically exists would be a
+ /// file on a local filesystem. An example of a resource that does not
+ /// physically exist would be an in-memory stream.
+ ///
- /// An implementation is
- /// generally required to support the functionality described by this
- /// interface.
- ///
- ///
- /// The class is a
- /// standalone implementation that is usable outside an
- /// ; the aforementioned
- /// class is also used by the
- /// class.
- ///
- /// The handle should always be a reusable resource descriptor; this
- /// allows one to make repeated calls to the underlying
- /// .
- ///
- ///
- ///
- ///
- /// Must support fully qualified URLs, e.g. "file:C:/test.dat".
- ///
- ///
- /// Should support relative file paths, e.g. "test.dat" (this will be
- /// implementation-specific, typically provided by an
- /// implementation).
- ///
+ /// An implementation is
+ /// generally required to support the functionality described by this
+ /// interface.
+ ///
+ ///
+ /// The class is a
+ /// standalone implementation that is usable outside an
+ /// ; the aforementioned
+ /// class is also used by the
+ /// class.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ ///
+ ///
+ ///
+ public interface IResourceLoader
+ {
+ ///
+ /// Return an handle for the
+ /// specified resource.
+ ///
+ ///
+ ///
+ /// The handle should always be a reusable resource descriptor; this
+ /// allows one to make repeated calls to the underlying
+ /// .
+ ///
+ ///
+ ///
+ ///
+ /// Must support fully qualified URLs, e.g. "file:C:/test.dat".
+ ///
+ ///
+ /// Should support relative file paths, e.g. "test.dat" (this will be
+ /// implementation-specific, typically provided by an
+ /// implementation).
+ ///
- /// Should only be used if no other
- /// implementation is applicable.
- ///
- ///
- /// In contrast to other
- /// implementations, this is an adapter for an already opened
- /// resource - the
- /// therefore always returns . Do not use this class
- /// if you need to keep the resource descriptor somewhere, or if you need
- /// to read a stream multiple times.
- ///
+ /// Should only be used if no other
+ /// implementation is applicable.
+ ///
+ ///
+ /// In contrast to other
+ /// implementations, this is an adapter for an already opened
+ /// resource - the
+ /// therefore always returns . Do not use this class
+ /// if you need to keep the resource descriptor somewhere, or if you need
+ /// to read a stream multiple times.
+ ///
- /// A resource path may contain placeholder variables of the form ${...}
- /// that will be expended to environment variables.
- ///
- ///
- /// Currently only supports conversion from a
- /// instance.
- ///
- ///
- ///
- ///
- /// On Win9x boxes, this resource path, ${userprofile}\objects.xml will
- /// be expanded at runtime with the value of the 'userprofile' environment
- /// variable substituted for the '${userprofile}' portion of the path.
- ///
- ///
- /// // assuming a user called Rick, running on a plain vanilla Windows XP setup...
- /// // this resource path...
- ///
- /// ${userprofile}\objects.xml
- ///
- /// // will become (after expansion)...
- ///
- /// C:\Documents and Settings\Rick\objects.xml
- ///
- ///
- /// Mark Pollack
- /// $Id: ResourceConverter.cs,v 1.14 2007/08/08 17:46:55 bbaia Exp $
- ///
- ///
- public class ResourceConverter : TypeConverter
- {
- private ILog _log = LogManager.GetLogger(typeof (ResourceConverter));
- private IResourceLoader _resourceLoader;
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public ResourceConverter()
- {
- _resourceLoader = new ConfigurableResourceLoader();
- }
-
- ///
- /// Creates a new instance of the
- /// class using the specified resourceLoader.
- ///
- /// the underlying IResourceLoader to be used to resolve resources
- public ResourceConverter( IResourceLoader resourceLoader )
- {
- AssertUtils.ArgumentNotNull( resourceLoader, "resourceLoader" );
- _resourceLoader = resourceLoader;
- }
- #endregion
-
- ///
- /// Returns whether this converter can convert an object of one
- /// to a
- ///
- ///
- /// A
- /// that provides a format context.
- ///
- ///
- /// A that represents the
- /// you want to convert from.
- ///
- ///
- /// if the conversion is possible.
- ///
- public override bool CanConvertFrom(
- ITypeDescriptorContext context,
- Type sourceType)
- {
- if (sourceType == typeof (string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- /// Convert from a string value to a
- /// instance.
- ///
- ///
- /// A
- /// that provides a format context.
- ///
- ///
- /// The to use
- /// as the current culture.
- ///
- ///
- /// The value that is to be converted.
- ///
- ///
- /// An if successful.
- ///
- ///
- /// If the resource name objectained form the supplied
- /// is malformed.
- ///
- ///
- /// In the case of any errors arising from the instantiation of the
- /// returned instance.
- ///
- public override object ConvertFrom(
- ITypeDescriptorContext context,
- CultureInfo culture, object value)
- {
- string resource = value as string;
- if (resource != null)
- {
- return GetResourceLoader().GetResource(ResolvePath(resource));
- }
- return base.ConvertFrom(context, culture, value);
- }
-
- ///
- /// Resolve the given path, replacing placeholder values with
- /// corresponding property values if necessary.
- ///
- ///
- ///
- /// This implementation resolves environment variables only.
- ///
+ /// A resource path may contain placeholder variables of the form ${...}
+ /// that will be expended to environment variables.
+ ///
+ ///
+ /// Currently only supports conversion from a
+ /// instance.
+ ///
+ ///
+ ///
+ ///
+ /// On Win9x boxes, this resource path, ${userprofile}\objects.xml will
+ /// be expanded at runtime with the value of the 'userprofile' environment
+ /// variable substituted for the '${userprofile}' portion of the path.
+ ///
+ ///
+ /// // assuming a user called Rick, running on a plain vanilla Windows XP setup...
+ /// // this resource path...
+ ///
+ /// ${userprofile}\objects.xml
+ ///
+ /// // will become (after expansion)...
+ ///
+ /// C:\Documents and Settings\Rick\objects.xml
+ ///
+ ///
+ /// Mark Pollack
+ ///
+ ///
+ public class ResourceConverter : TypeConverter
+ {
+ private ILog _log = LogManager.GetLogger(typeof (ResourceConverter));
+ private IResourceLoader _resourceLoader;
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public ResourceConverter()
+ {
+ _resourceLoader = new ConfigurableResourceLoader();
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class using the specified resourceLoader.
+ ///
+ /// the underlying IResourceLoader to be used to resolve resources
+ public ResourceConverter( IResourceLoader resourceLoader )
+ {
+ AssertUtils.ArgumentNotNull( resourceLoader, "resourceLoader" );
+ _resourceLoader = resourceLoader;
+ }
+ #endregion
+
+ ///
+ /// Returns whether this converter can convert an object of one
+ /// to a
+ ///
+ ///
+ /// A
+ /// that provides a format context.
+ ///
+ ///
+ /// A that represents the
+ /// you want to convert from.
+ ///
+ ///
+ /// if the conversion is possible.
+ ///
+ public override bool CanConvertFrom(
+ ITypeDescriptorContext context,
+ Type sourceType)
+ {
+ if (sourceType == typeof (string))
+ {
+ return true;
+ }
+ return base.CanConvertFrom(context, sourceType);
+ }
+
+ ///
+ /// Convert from a string value to a
+ /// instance.
+ ///
+ ///
+ /// A
+ /// that provides a format context.
+ ///
+ ///
+ /// The to use
+ /// as the current culture.
+ ///
+ ///
+ /// The value that is to be converted.
+ ///
+ ///
+ /// An if successful.
+ ///
+ ///
+ /// If the resource name objectained form the supplied
+ /// is malformed.
+ ///
+ ///
+ /// In the case of any errors arising from the instantiation of the
+ /// returned instance.
+ ///
+ public override object ConvertFrom(
+ ITypeDescriptorContext context,
+ CultureInfo culture, object value)
+ {
+ string resource = value as string;
+ if (resource != null)
+ {
+ return GetResourceLoader().GetResource(ResolvePath(resource));
+ }
+ return base.ConvertFrom(context, culture, value);
+ }
+
+ ///
+ /// Resolve the given path, replacing placeholder values with
+ /// corresponding property values if necessary.
+ ///
+ ///
+ ///
+ /// This implementation resolves environment variables only.
+ ///
+ ///
+ /// The original resource path.
+ /// The resolved resource path.
+ protected virtual string ResolvePath(string path)
+ {
+ // quite inefficient, but cost is only ever paid once at startup...
+ IList expressions = StringUtils.GetAntExpressions(path);
+ foreach (string expression in expressions)
+ {
+ string environmentValue
+ = Environment.GetEnvironmentVariable(expression);
+ if (environmentValue != null)
+ {
+ path = StringUtils.SetAntExpression(
+ path, expression, environmentValue);
+ }
+ else
+ {
+ #region Instrumentation
+
+ if (_log.IsWarnEnabled)
+ {
+ _log.Warn(string.Format(
+ CultureInfo.InvariantCulture,
+ "Could not resolve placeholder '{0}' in resource path " +
+ "'{1}' as an environment variable.", expression, path));
+ }
+
+ #endregion
+ }
+ }
+ return path;
+ }
+
+ ///
+ /// Return the used to
+ /// resolve the string.
+ ///
+ ///
+ /// The used to resolve
+ /// the string.
+ ///
+ protected internal virtual IResourceLoader GetResourceLoader()
+ {
+ return _resourceLoader;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs
index 053d6154..bb3ab665 100644
--- a/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs
+++ b/src/Spring/Spring.Core/Core/IO/ResourceHandlerRegistry.cs
@@ -1,264 +1,263 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-using System.Reflection;
-
-using Spring.Context.Support;
-using Spring.Core.TypeResolution;
-using Spring.Util;
-using Spring.Reflection.Dynamic;
-
-namespace Spring.Core.IO
-{
- ///
- /// Registry class that allows users to register and retrieve protocol handlers.
- ///
- ///
- ///
- /// Resource handler is an implementation of interface
- /// that should be used to process resources with the specified protocol.
- ///
- ///
- /// They are used throughout the framework to access resources from various
- /// sources. For example, application context loads object definitions from the resources
- /// that are processed using one of the registered resource handlers.
- ///
- /// Following resource handlers are registered by default:
- ///
- ///
- /// Protocol
- /// Handler Type
- /// Description
- ///
- ///
- /// config
- ///
- /// Resolves the resources by loading specified configuration section from the standard .NET config file.
- ///
- ///
- /// file
- ///
- /// Resolves filesystem resources.
- ///
- ///
- /// http
- ///
- /// Resolves remote web resources.
- ///
- ///
- /// https
- ///
- /// Resolves remote web resources via HTTPS.
- ///
- ///
- /// ftp
- ///
- /// Resolves ftp resources.
- ///
- ///
- /// assembly
- ///
- /// Resolves resources that are embedded into an assembly.
- ///
- ///
- /// web
- /// Spring.Core.IO.WebResource, Spring.Web*
- /// Resolves resources relative to the web application's virtual directory.
- ///
- ///
- /// * only available in web applications.
- ///
- /// Users can create and register their own protocol handlers by implementing interface
- /// and mapping custom protocol name to that implementation. See for details
- /// on how to register custom protocol handler.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: ResourceHandlerRegistry.cs,v 1.7 2007/08/08 17:46:55 bbaia Exp $
- public class ResourceHandlerRegistry
- {
- ///
- /// Name of the .Net config section that contains definitions
- /// for custom resource handlers.
- ///
- private const string ResourcesSectionName = "spring/resourceHandlers";
-
- private static IDictionary resourceHandlers = new Hashtable();
-
- ///
- /// Registers standard and user-configured resource handlers.
- ///
- static ResourceHandlerRegistry()
- {
- lock (resourceHandlers.SyncRoot)
- {
- resourceHandlers["config"] = GetResourceConstructor(typeof(ConfigSectionResource));
- resourceHandlers["file"] = GetResourceConstructor(typeof(FileSystemResource));
- resourceHandlers["http"] = GetResourceConstructor(typeof(UrlResource));
- resourceHandlers["https"] = GetResourceConstructor(typeof(UrlResource));
-#if NET_2_0
- resourceHandlers["ftp"] = GetResourceConstructor(typeof(UrlResource));
-#endif
- resourceHandlers["assembly"] = GetResourceConstructor(typeof(AssemblyResource));
-
- // register custom resource handlers
- ConfigurationUtils.GetSection(ResourcesSectionName);
- }
- }
-
- ///
- /// Returns resource handler for the specified protocol name.
- ///
- ///
- ///
- /// This method returns object that should be used
- /// to create an instance of the -derived type by passing
- /// resource location as a parameter.
- ///
- ///
- /// Name of the protocol to get the handler for.
- /// Resource handler constructor for the specified protocol name.
- /// If is null.
- public static IDynamicConstructor GetResourceHandler(string protocolName)
- {
- AssertUtils.ArgumentNotNull(protocolName, "protocolName");
- return (IDynamicConstructor) resourceHandlers[protocolName];
- }
-
- ///
- /// Returns true if a handler is registered for the specified protocol,
- /// false otherwise.
- ///
- /// Name of the protocol.
- ///
- /// true if a handler is registered for the specified protocol, false otherwise.
- ///
- /// If is null.
- public static bool IsHandlerRegistered(string protocolName)
- {
- return resourceHandlers.Contains(protocolName);
- }
-
- ///
- /// Registers resource handler and maps it to the specified protocol name.
- ///
- ///
- ///
- /// If the mapping already exists, the existing mapping will be
- /// silently overwritten with the new mapping.
- ///
- ///
- ///
- /// The protocol to add (or override).
- ///
- ///
- /// The type name of the concrete implementation of the
- /// interface that will handle
- /// the specified protocol.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s); or
- /// if the supplied is
- /// .
- ///
- ///
- /// If the supplied is not a
- /// that derives from the
- /// interface; or (having passed
- /// this first check), the supplied
- /// does not expose a constructor that takes a single
- /// parameter.
- ///
- public static void RegisterResourceHandler(string protocolName, string handlerTypeName)
- {
- AssertUtils.ArgumentHasText(protocolName, "protocolName");
- AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName");
-
- Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName);
- RegisterResourceHandler(protocolName, handlerType);
- }
-
- ///
- /// Registers resource handler and maps it to the specified protocol name.
- ///
- ///
- ///
- /// If the mapping already exists, the existing mapping will be
- /// silently overwritten with the new mapping.
- ///
- ///
- ///
- /// The protocol to add (or override).
- ///
- ///
- /// The concrete implementation of the
- /// interface that will handle
- /// the specified protocol.
- ///
- ///
- /// If the supplied is
- /// or contains only whitespace character(s); or
- /// if the supplied is
- /// .
- ///
- ///
- /// If the supplied is not a
- /// that derives from the
- /// interface; or (having passed
- /// this first check), the supplied
- /// does not expose a constructor that takes a single
- /// parameter.
- ///
- public static void RegisterResourceHandler(string protocolName, Type handlerType)
- {
- #region Sanity Checks
-
- AssertUtils.ArgumentHasText(protocolName, "protocolName");
- AssertUtils.ArgumentNotNull(handlerType, "handlerType");
- if (!typeof(IResource).IsAssignableFrom(handlerType))
- {
- throw new ArgumentException(
- string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName));
- }
-
- #endregion
-
- lock (resourceHandlers.SyncRoot)
- {
- IDynamicConstructor ctor = GetResourceConstructor(handlerType);
- resourceHandlers[protocolName] = ctor;
- }
- }
-
- private static IDynamicConstructor GetResourceConstructor(Type handlerType)
- {
- ConstructorInfo ctor = handlerType.GetConstructor(new Type[] {typeof(string)});
- if (ctor == null)
- {
- throw new ArgumentException(
- string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName));
- }
- return DynamicConstructor.Create(ctor);
- }
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+using Spring.Context.Support;
+using Spring.Core.TypeResolution;
+using Spring.Util;
+using Spring.Reflection.Dynamic;
+
+namespace Spring.Core.IO
+{
+ ///
+ /// Registry class that allows users to register and retrieve protocol handlers.
+ ///
+ ///
+ ///
+ /// Resource handler is an implementation of interface
+ /// that should be used to process resources with the specified protocol.
+ ///
+ ///
+ /// They are used throughout the framework to access resources from various
+ /// sources. For example, application context loads object definitions from the resources
+ /// that are processed using one of the registered resource handlers.
+ ///
+ /// Following resource handlers are registered by default:
+ ///
+ ///
+ /// Protocol
+ /// Handler Type
+ /// Description
+ ///
+ ///
+ /// config
+ ///
+ /// Resolves the resources by loading specified configuration section from the standard .NET config file.
+ ///
+ ///
+ /// file
+ ///
+ /// Resolves filesystem resources.
+ ///
+ ///
+ /// http
+ ///
+ /// Resolves remote web resources.
+ ///
+ ///
+ /// https
+ ///
+ /// Resolves remote web resources via HTTPS.
+ ///
+ ///
+ /// ftp
+ ///
+ /// Resolves ftp resources.
+ ///
+ ///
+ /// assembly
+ ///
+ /// Resolves resources that are embedded into an assembly.
+ ///
+ ///
+ /// web
+ /// Spring.Core.IO.WebResource, Spring.Web*
+ /// Resolves resources relative to the web application's virtual directory.
+ ///
+ ///
+ /// * only available in web applications.
+ ///
+ /// Users can create and register their own protocol handlers by implementing interface
+ /// and mapping custom protocol name to that implementation. See for details
+ /// on how to register custom protocol handler.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public class ResourceHandlerRegistry
+ {
+ ///
+ /// Name of the .Net config section that contains definitions
+ /// for custom resource handlers.
+ ///
+ private const string ResourcesSectionName = "spring/resourceHandlers";
+
+ private static IDictionary resourceHandlers = new Hashtable();
+
+ ///
+ /// Registers standard and user-configured resource handlers.
+ ///
+ static ResourceHandlerRegistry()
+ {
+ lock (resourceHandlers.SyncRoot)
+ {
+ resourceHandlers["config"] = GetResourceConstructor(typeof(ConfigSectionResource));
+ resourceHandlers["file"] = GetResourceConstructor(typeof(FileSystemResource));
+ resourceHandlers["http"] = GetResourceConstructor(typeof(UrlResource));
+ resourceHandlers["https"] = GetResourceConstructor(typeof(UrlResource));
+#if NET_2_0
+ resourceHandlers["ftp"] = GetResourceConstructor(typeof(UrlResource));
+#endif
+ resourceHandlers["assembly"] = GetResourceConstructor(typeof(AssemblyResource));
+
+ // register custom resource handlers
+ ConfigurationUtils.GetSection(ResourcesSectionName);
+ }
+ }
+
+ ///
+ /// Returns resource handler for the specified protocol name.
+ ///
+ ///
+ ///
+ /// This method returns object that should be used
+ /// to create an instance of the -derived type by passing
+ /// resource location as a parameter.
+ ///
+ ///
+ /// Name of the protocol to get the handler for.
+ /// Resource handler constructor for the specified protocol name.
+ /// If is null.
+ public static IDynamicConstructor GetResourceHandler(string protocolName)
+ {
+ AssertUtils.ArgumentNotNull(protocolName, "protocolName");
+ return (IDynamicConstructor) resourceHandlers[protocolName];
+ }
+
+ ///
+ /// Returns true if a handler is registered for the specified protocol,
+ /// false otherwise.
+ ///
+ /// Name of the protocol.
+ ///
+ /// true if a handler is registered for the specified protocol, false otherwise.
+ ///
+ /// If is null.
+ public static bool IsHandlerRegistered(string protocolName)
+ {
+ return resourceHandlers.Contains(protocolName);
+ }
+
+ ///
+ /// Registers resource handler and maps it to the specified protocol name.
+ ///
+ ///
+ ///
+ /// If the mapping already exists, the existing mapping will be
+ /// silently overwritten with the new mapping.
+ ///
+ ///
+ ///
+ /// The protocol to add (or override).
+ ///
+ ///
+ /// The type name of the concrete implementation of the
+ /// interface that will handle
+ /// the specified protocol.
+ ///
+ ///
+ /// If the supplied is
+ /// or contains only whitespace character(s); or
+ /// if the supplied is
+ /// .
+ ///
+ ///
+ /// If the supplied is not a
+ /// that derives from the
+ /// interface; or (having passed
+ /// this first check), the supplied
+ /// does not expose a constructor that takes a single
+ /// parameter.
+ ///
+ public static void RegisterResourceHandler(string protocolName, string handlerTypeName)
+ {
+ AssertUtils.ArgumentHasText(protocolName, "protocolName");
+ AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName");
+
+ Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName);
+ RegisterResourceHandler(protocolName, handlerType);
+ }
+
+ ///
+ /// Registers resource handler and maps it to the specified protocol name.
+ ///
+ ///
+ ///
+ /// If the mapping already exists, the existing mapping will be
+ /// silently overwritten with the new mapping.
+ ///
- /// Obviously supports resolution as a , and also
- /// as a in the case of the "file:"
- /// protocol.
- ///
- ///
- ///
- ///
- /// Some examples of the strings that can be used to initialize a new
- /// instance of the class
- /// include...
- ///
- ///
- /// file:///Config/objects.xml
- ///
- ///
- /// http://www.mycompany.com/services.txt
- ///
- ///
- ///
- ///
- /// Juergen Hoeller
- /// Leonardo Susatyo (.NET)
- /// Aleksandar Seovic (.NET)
- /// $Id: UrlResource.cs,v 1.15 2007/08/08 17:46:55 bbaia Exp $
- ///
- ///
- ///
- public class UrlResource : AbstractResource
- {
- private Uri _uri;
- private WebRequest _webRequest;
- private string _rootLocation;
- private string _resourcePath;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// Some examples of the values that the
- /// can typically be expected to hold include...
- ///
- ///
- /// file:///Config/objects.xml
- ///
- ///
- /// http://www.mycompany.com/services.txt
- ///
- ///
- ///
- ///
- ///
- /// A string representation of the resource.
- ///
- public UrlResource(string resourceName) : base(resourceName)
- {
- this._uri = new Uri(resourceName);
- _rootLocation = _uri.Host;
- if (!_uri.IsDefaultPort)
- {
- _rootLocation += ":" + _uri.Port;
- }
- _resourcePath = _uri.AbsolutePath;
- int n = _resourcePath.LastIndexOf('/');
- if (n > 0)
- {
- _resourcePath = _resourcePath.Substring(1, n - 1);
- }
- else
- {
- _resourcePath = null;
- }
- _webRequest = WebRequest.Create(_uri);
- }
-
- ///
- /// Returns the instance
- /// used for the resource resolution.
- ///
- ///
- /// A instance.
- ///
- ///
- ///
- public WebRequest WebRequest
- {
- get { return _webRequest; }
- }
-
- ///
- /// Return an for this resource.
- ///
- ///
- /// An .
- ///
- ///
- /// If the stream could not be opened.
- ///
- ///
- public override Stream InputStream
- {
- get { return _webRequest.GetResponse().GetResponseStream(); }
- }
-
- ///
- /// Returns the handle for this resource.
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// If the resource is not available or cannot be exposed as a
- /// .
- ///
- ///
- public override Uri Uri
- {
- get { return _uri; }
- }
-
- ///
- /// Returns a handle for this resource.
- ///
- ///
- /// The handle for this resource.
- ///
- ///
- /// If the resource is not available on a filesystem.
- ///
- ///
- public override FileInfo File
- {
- get
- {
- if (_uri.IsFile)
- {
- return new FileInfo(_uri.AbsolutePath);
- }
- throw new FileNotFoundException(Description +
- " cannot be resolved to absolute file path - " +
- "resource does not use 'file:' protocol." );
- }
- }
-
- ///
- /// Does this support relative
- /// resource retrieval?
- ///
- ///
- ///
- /// This implementation does support relative resource retrieval, and
- /// so will always return .
- ///
+ /// Obviously supports resolution as a , and also
+ /// as a in the case of the "file:"
+ /// protocol.
+ ///
+ ///
+ ///
+ ///
+ /// Some examples of the strings that can be used to initialize a new
+ /// instance of the class
+ /// include...
+ ///
+ ///
+ /// file:///Config/objects.xml
+ ///
+ ///
+ /// http://www.mycompany.com/services.txt
+ ///
+ ///
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Leonardo Susatyo (.NET)
+ /// Aleksandar Seovic (.NET)
+ ///
+ ///
+ ///
+ public class UrlResource : AbstractResource
+ {
+ private Uri _uri;
+ private WebRequest _webRequest;
+ private string _rootLocation;
+ private string _resourcePath;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// Some examples of the values that the
+ /// can typically be expected to hold include...
+ ///
+ ///
+ /// file:///Config/objects.xml
+ ///
+ ///
+ /// http://www.mycompany.com/services.txt
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// A string representation of the resource.
+ ///
+ public UrlResource(string resourceName) : base(resourceName)
+ {
+ this._uri = new Uri(resourceName);
+ _rootLocation = _uri.Host;
+ if (!_uri.IsDefaultPort)
+ {
+ _rootLocation += ":" + _uri.Port;
+ }
+ _resourcePath = _uri.AbsolutePath;
+ int n = _resourcePath.LastIndexOf('/');
+ if (n > 0)
+ {
+ _resourcePath = _resourcePath.Substring(1, n - 1);
+ }
+ else
+ {
+ _resourcePath = null;
+ }
+ _webRequest = WebRequest.Create(_uri);
+ }
+
+ ///
+ /// Returns the instance
+ /// used for the resource resolution.
+ ///
+ ///
+ /// A instance.
+ ///
+ ///
+ ///
+ public WebRequest WebRequest
+ {
+ get { return _webRequest; }
+ }
+
+ ///
+ /// Return an for this resource.
+ ///
+ ///
+ /// An .
+ ///
+ ///
+ /// If the stream could not be opened.
+ ///
+ ///
+ public override Stream InputStream
+ {
+ get { return _webRequest.GetResponse().GetResponseStream(); }
+ }
+
+ ///
+ /// Returns the handle for this resource.
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// If the resource is not available or cannot be exposed as a
+ /// .
+ ///
+ ///
+ public override Uri Uri
+ {
+ get { return _uri; }
+ }
+
+ ///
+ /// Returns a handle for this resource.
+ ///
+ ///
+ /// The handle for this resource.
+ ///
+ ///
+ /// If the resource is not available on a filesystem.
+ ///
+ ///
+ public override FileInfo File
+ {
+ get
+ {
+ if (_uri.IsFile)
+ {
+ return new FileInfo(_uri.AbsolutePath);
+ }
+ throw new FileNotFoundException(Description +
+ " cannot be resolved to absolute file path - " +
+ "resource does not use 'file:' protocol." );
+ }
+ }
+
+ ///
+ /// Does this support relative
+ /// resource retrieval?
+ ///
+ ///
+ ///
+ /// This implementation does support relative resource retrieval, and
+ /// so will always return .
+ ///
- /// The actual order can be interpreted as prioritization, the first object (with the
- /// lowest order value) having the highest priority.
- ///
- ///
- /// Juergen Hoeller
- /// Aleksandar Seovic (.Net)
- /// $Id: IOrdered.cs,v 1.6 2007/05/26 00:42:36 markpollack Exp $
- public interface IOrdered
- {
-
- ///
- /// Return the order value of this object, where a higher value means greater in
- /// terms of sorting.
- ///
- ///
- ///
- /// Normally starting with 0 or 1, with indicating
- /// greatest. Same order values will result in arbitrary positions for the affected
- /// objects.
- ///
- ///
- /// Higher value can be interpreted as lower priority, consequently the first object
- /// has highest priority.
- ///
+ /// The actual order can be interpreted as prioritization, the first object (with the
+ /// lowest order value) having the highest priority.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Aleksandar Seovic (.Net)
+ public interface IOrdered
+ {
+
+ ///
+ /// Return the order value of this object, where a higher value means greater in
+ /// terms of sorting.
+ ///
+ ///
+ ///
+ /// Normally starting with 0 or 1, with indicating
+ /// greatest. Same order values will result in arbitrary positions for the affected
+ /// objects.
+ ///
+ ///
+ /// Higher value can be interpreted as lower priority, consequently the first object
+ /// has highest priority.
+ ///
+ /// This class supports checking the generic arguments count of both
+ /// generic methods and constructors.
+ ///
+ ///
+ /// Bruno Baia
+ public class MethodGenericArgumentsCountCriteria : ICriteria
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This constructor sets the
+ ///
+ /// property to zero (0).
+ ///
+ /// This class supports checking the parameter count of both methods and
+ /// constructors.
+ ///
+ ///
+ /// Default parameters, etc need to taken into account.
+ ///
+ ///
+ /// Rick Evans
+ public class MethodParametersCountCriteria : ICriteria
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This constructor sets the
+ ///
+ /// property to zero (0).
+ ///
- /// If no array is passed to the overloaded constructor,
- /// any method that has no parameters will satisfy an instance of this
- /// class. The same effect could be achieved by passing the
- /// array to the overloaded constructor.
- ///
- ///
- /// Rick Evans
- /// $Id: MethodParametersCriteria.cs,v 1.2 2007/09/20 14:20:46 bbaia Exp $
- public class MethodParametersCriteria : ICriteria
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public MethodParametersCriteria() : this(Type.EmptyTypes)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// If the supplied array is null, then this
- /// constructor uses the array.
- ///
- ///
- ///
- /// The array that this criteria will use to
- /// check parameter s.
- ///
- public MethodParametersCriteria(Type[] parameters)
- {
- _parameters = parameters;
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Does the supplied satisfy the criteria encapsulated by
- /// this instance?
- ///
- ///
- ///
- /// This implementation respects the inheritance chain of any parameter
- /// s... i.e. methods that have a base type (or
- /// interface) that is assignable to the in the
- /// same corresponding index of the parameter types will satisfy this
- /// criteria instance.
- ///
+ /// If no array is passed to the overloaded constructor,
+ /// any method that has no parameters will satisfy an instance of this
+ /// class. The same effect could be achieved by passing the
+ /// array to the overloaded constructor.
+ ///
+ ///
+ /// Rick Evans
+ public class MethodParametersCriteria : ICriteria
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public MethodParametersCriteria() : this(Type.EmptyTypes)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// If the supplied array is null, then this
+ /// constructor uses the array.
+ ///
+ ///
+ ///
+ /// The array that this criteria will use to
+ /// check parameter s.
+ ///
+ public MethodParametersCriteria(Type[] parameters)
+ {
+ _parameters = parameters;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Does the supplied satisfy the criteria encapsulated by
+ /// this instance?
+ ///
+ ///
+ ///
+ /// This implementation respects the inheritance chain of any parameter
+ /// s... i.e. methods that have a base type (or
+ /// interface) that is assignable to the in the
+ /// same corresponding index of the parameter types will satisfy this
+ /// criteria instance.
+ ///
- /// Non- objects are treated as greatest order values,
- /// thus ending up at the end of a list, in arbitrary order (just like same order values of
- /// objects).
- ///
- ///
- /// Juergen Hoeller
- /// Aleksandar Seovic (.Net)
- /// $Id: OrderComparator.cs,v 1.5 2006/04/09 07:18:38 markpollack Exp $
- public class OrderComparator : IComparer
- {
- ///
- /// Compares two objects and returns a value indicating whether one is less than,
- /// equal to or greater than the other.
- ///
- ///
- ///
- /// Uses direct evaluation instead of
- /// to avoid unnecessary boxing.
- ///
+ /// Non- objects are treated as greatest order values,
+ /// thus ending up at the end of a list, in arbitrary order (just like same order values of
+ /// objects).
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Aleksandar Seovic (.Net)
+ public class OrderComparator : IComparer
+ {
+ ///
+ /// Compares two objects and returns a value indicating whether one is less than,
+ /// equal to or greater than the other.
+ ///
+ ///
+ ///
+ /// Uses direct evaluation instead of
+ /// to avoid unnecessary boxing.
+ ///
- /// Provides some additional properties over and above the name of the
- /// property that has changed (which is inherited from the
- /// base class).
- /// This allows calling code to determine whether or not a property has
- /// actually changed (i.e. a PropertyChanged event may have been
- /// raised, but the value itself may be equivalent).
- ///
+ /// Provides some additional properties over and above the name of the
+ /// property that has changed (which is inherited from the
+ /// base class).
+ /// This allows calling code to determine whether or not a property has
+ /// actually changed (i.e. a PropertyChanged event may have been
+ /// raised, but the value itself may be equivalent).
+ ///
- /// Can use a given for
- /// (locale-specific) parsing and rendering.
- ///
- ///
- /// This is not meant to be used as a system
- /// but rather as a
- /// locale-specific number converter within custom controller code, to
- /// parse user-entered number strings into number properties of objects,
- /// and render them in a UI form.
- ///
- ///
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: CustomNumberConverter.cs,v 1.1 2007/07/31 18:16:08 bbaia Exp $
- public class CustomNumberConverter : TypeConverter
- {
- private Type _type;
- private NumberFormatInfo _nfi;
- private bool _allowEmpty;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The primitive numeric to convert to.
- ///
- ///
- /// The to use for
- /// (locale-specific) parsing and rendering
- ///
- ///
- /// Is an empty string allowed to be converted? If
- /// , an empty string value will be converted to
- /// numeric 0.
- ///
- /// Id the supplied is not a primitive
- /// .
- ///
- ///
- public CustomNumberConverter(
- Type type, NumberFormatInfo format, bool allowEmpty)
- {
- if (!type.IsPrimitive)
- {
- throw new ArgumentException(
- "Property type must be a primitive type.");
- }
- this._type = type;
- this._nfi = format;
- this._allowEmpty = allowEmpty;
- }
-
- ///
- /// Returns whether this converter can convert an object of one
- /// to a
- ///
- ///
- ///
- /// Currently only supports conversion from a
- /// instance.
- ///
+ /// Can use a given for
+ /// (locale-specific) parsing and rendering.
+ ///
+ ///
+ /// This is not meant to be used as a system
+ /// but rather as a
+ /// locale-specific number converter within custom controller code, to
+ /// parse user-entered number strings into number properties of objects,
+ /// and render them in a UI form.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ public class CustomNumberConverter : TypeConverter
+ {
+ private Type _type;
+ private NumberFormatInfo _nfi;
+ private bool _allowEmpty;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The primitive numeric to convert to.
+ ///
+ ///
+ /// The to use for
+ /// (locale-specific) parsing and rendering
+ ///
+ ///
+ /// Is an empty string allowed to be converted? If
+ /// , an empty string value will be converted to
+ /// numeric 0.
+ ///
+ /// Id the supplied is not a primitive
+ /// .
+ ///
+ ///
+ public CustomNumberConverter(
+ Type type, NumberFormatInfo format, bool allowEmpty)
+ {
+ if (!type.IsPrimitive)
+ {
+ throw new ArgumentException(
+ "Property type must be a primitive type.");
+ }
+ this._type = type;
+ this._nfi = format;
+ this._allowEmpty = allowEmpty;
+ }
+
+ ///
+ /// Returns whether this converter can convert an object of one
+ /// to a
+ ///
+ ///
+ ///
+ /// Currently only supports conversion from a
+ /// instance.
+ ///
- /// Handles conversion from an XML formatted string to a
- /// object
- /// (see below for an example of the expected XML format).
- ///
- ///
- /// This converter must be registered before it will be available. Standard
- /// converters in this namespace are automatically registered by the
- /// class.
- ///
- ///
- ///
- ///
- /// Find below some examples of the XML formatted strings that this
- /// converter will sucessfully convert. Note that the name of the top level
- /// (document) element is quite arbitrary... it is only the content that
- /// matters (and which must be in the format
- /// <add key="..." value="..."/>. For your continued sanity
- /// though, you may wish to standardize on the top level name of
- /// 'dictionary' (although you are of course free to not do so).
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// The following example uses a different top level (document) element
- /// name, but is equivalent to the first example.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: NameValueConverter.cs,v 1.1 2007/07/31 18:16:08 bbaia Exp $
- public class NameValueConverter : TypeConverter
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public NameValueConverter()
- {
- }
-
- #endregion
-
- ///
- /// Returns whether this converter can convert an object of one
- /// to a
- ///
- ///
- ///
- ///
- /// Currently only supports conversion from an
- /// XML formatted instance.
- ///
+ /// Handles conversion from an XML formatted string to a
+ /// object
+ /// (see below for an example of the expected XML format).
+ ///
+ ///
+ /// This converter must be registered before it will be available. Standard
+ /// converters in this namespace are automatically registered by the
+ /// class.
+ ///
+ ///
+ ///
+ ///
+ /// Find below some examples of the XML formatted strings that this
+ /// converter will sucessfully convert. Note that the name of the top level
+ /// (document) element is quite arbitrary... it is only the content that
+ /// matters (and which must be in the format
+ /// <add key="..." value="..."/>. For your continued sanity
+ /// though, you may wish to standardize on the top level name of
+ /// 'dictionary' (although you are of course free to not do so).
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The following example uses a different top level (document) element
+ /// name, but is equivalent to the first example.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ public class NameValueConverter : TypeConverter
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public NameValueConverter()
+ {
+ }
+
+ #endregion
+
+ ///
+ /// Returns whether this converter can convert an object of one
+ /// to a
+ ///
+ ///
+ ///
+ ///
+ /// Currently only supports conversion from an
+ /// XML formatted instance.
+ ///
- /// Currently only supports conversion to and from a
- /// .
- ///
- ///
- /// Rick Evans (.NET)
- /// $Id: RuntimeTypeConverter.cs,v 1.1 2007/07/31 18:16:08 bbaia Exp $
- public class RuntimeTypeConverter : TypeConverter
- {
- #region Constructor (s) / Destructor
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public RuntimeTypeConverter () {}
- #endregion
-
- #region Methods
- ///
- /// Returns whether this converter can convert an object of one
- /// to the
- /// of this converter.
- ///
- ///
- ///
- /// Currently only supports conversion from a
- /// instance.
- ///
+ /// Currently only supports conversion to and from a
+ /// .
+ ///
+ ///
+ /// Rick Evans (.NET)
+ public class RuntimeTypeConverter : TypeConverter
+ {
+ #region Constructor (s) / Destructor
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public RuntimeTypeConverter () {}
+ #endregion
+
+ #region Methods
+ ///
+ /// Returns whether this converter can convert an object of one
+ /// to the
+ /// of this converter.
+ ///
+ ///
+ ///
+ /// Currently only supports conversion from a
+ /// instance.
+ ///
- /// Defaults to using the , (comma) as the list separator. Note that the value
- /// of the current is
- /// not used.
- ///
- ///
- /// If you want to provide your own list separator, you can set the value of the
- ///
- /// property to the value that you want. Please note that this value will be used
- /// for all future conversions in preference to the default list separator.
- ///
- ///
- /// Please note that the individual elements of a string will be passed
- /// through as is (i.e. no conversion or trimming of surrounding
- /// whitespace will be performed).
- ///
- ///
- /// This should be
- /// automatically registered with any
- /// implementations.
- ///
- ///
- ///
- ///
- /// public class StringArrayConverterExample
- /// {
- /// public static void Main()
- /// {
- /// StringArrayConverter converter = new StringArrayConverter();
- ///
- /// string csvWords = "This,Is,It";
- /// string[] frankBoothWords = converter.ConvertFrom(csvWords);
- ///
- /// // the 'frankBoothWords' array will have 3 elements, namely
- /// // "This", "Is", "It".
- ///
- /// // please note that extraneous whitespace is NOT trimmed off
- /// // in the current implementation...
- /// string csv = " Cogito ,ergo ,sum ";
- /// string[] descartesWords = converter.ConvertFrom(csv);
- ///
- /// // the 'descartesWords' array will have 3 elements, namely
- /// // " Cogito ", "ergo ", "sum ".
- /// // notice how the whitespace has NOT been trimmed.
- /// }
- /// }
- ///
- ///
- ///
- /// $Id: StringArrayConverter.cs,v 1.1 2007/07/31 18:16:08 bbaia Exp $
- public class StringArrayConverter : TypeConverter
- {
- private const string DefaultListSeparator = ",";
-
- private string listSeparator = DefaultListSeparator;
-
- ///
- /// The value that will be used as the list separator when performing
- /// conversions.
- ///
- ///
- /// A 'single' string character that will be used as the list separator
- /// when performing conversions.
- ///
- ///
- /// If the supplied value is not and is an empty
- /// string, or has more than one character.
- ///
- public string ListSeparator
- {
- get { return this.listSeparator; }
- set
- {
- if (value != null)
- {
- if (value.Length != 1)
- {
- throw new ArgumentException(
- "The 'ListSeparator' must be exactly one character in length.");
- }
- listSeparator = value;
- }
- else
- {
- listSeparator = DefaultListSeparator;
- }
- }
- }
-
- ///
- /// Can we convert from a the sourcetype to a array?
- ///
- ///
- ///
- /// Currently only supports conversion from a instance.
- ///
+ /// Defaults to using the , (comma) as the list separator. Note that the value
+ /// of the current is
+ /// not used.
+ ///
+ ///
+ /// If you want to provide your own list separator, you can set the value of the
+ ///
+ /// property to the value that you want. Please note that this value will be used
+ /// for all future conversions in preference to the default list separator.
+ ///
+ ///
+ /// Please note that the individual elements of a string will be passed
+ /// through as is (i.e. no conversion or trimming of surrounding
+ /// whitespace will be performed).
+ ///
+ ///
+ /// This should be
+ /// automatically registered with any
+ /// implementations.
+ ///
+ ///
+ ///
+ ///
+ /// public class StringArrayConverterExample
+ /// {
+ /// public static void Main()
+ /// {
+ /// StringArrayConverter converter = new StringArrayConverter();
+ ///
+ /// string csvWords = "This,Is,It";
+ /// string[] frankBoothWords = converter.ConvertFrom(csvWords);
+ ///
+ /// // the 'frankBoothWords' array will have 3 elements, namely
+ /// // "This", "Is", "It".
+ ///
+ /// // please note that extraneous whitespace is NOT trimmed off
+ /// // in the current implementation...
+ /// string csv = " Cogito ,ergo ,sum ";
+ /// string[] descartesWords = converter.ConvertFrom(csv);
+ ///
+ /// // the 'descartesWords' array will have 3 elements, namely
+ /// // " Cogito ", "ergo ", "sum ".
+ /// // notice how the whitespace has NOT been trimmed.
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ public class StringArrayConverter : TypeConverter
+ {
+ private const string DefaultListSeparator = ",";
+
+ private string listSeparator = DefaultListSeparator;
+
+ ///
+ /// The value that will be used as the list separator when performing
+ /// conversions.
+ ///
+ ///
+ /// A 'single' string character that will be used as the list separator
+ /// when performing conversions.
+ ///
+ ///
+ /// If the supplied value is not and is an empty
+ /// string, or has more than one character.
+ ///
+ public string ListSeparator
+ {
+ get { return this.listSeparator; }
+ set
+ {
+ if (value != null)
+ {
+ if (value.Length != 1)
+ {
+ throw new ArgumentException(
+ "The 'ListSeparator' must be exactly one character in length.");
+ }
+ listSeparator = value;
+ }
+ else
+ {
+ listSeparator = DefaultListSeparator;
+ }
+ }
+ }
+
+ ///
+ /// Can we convert from a the sourcetype to a array?
+ ///
+ ///
+ ///
+ /// Currently only supports conversion from a instance.
+ ///
- /// Type parameters can be applied to classes, interfaces,
- /// structures, methods, delegates, etc...
- ///
- ///
- public class GenericArgumentsHolder
- {
- #region Constants
-
- ///
- /// The generic arguments prefix.
- ///
- public const char GenericArgumentsPrefix = '<';
-
- ///
- /// The generic arguments suffix.
- ///
- public const char GenericArgumentsSuffix = '>';
-
- ///
- /// The character that separates a list of generic arguments.
- ///
- public const char GenericArgumentsSeparator = ',';
-
- #endregion
-
- #region Fields
-
- private string unresolvedGenericTypeName;
- private string unresolvedGenericMethodName;
- private string[] unresolvedGenericArguments;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the GenericArgumentsHolder class.
- ///
- ///
- /// The string value to parse looking for a generic definition
- /// and retrieving its generic arguments.
- ///
- public GenericArgumentsHolder(string value)
- {
- ParseGenericArguments(value);
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The (unresolved) generic type name portion
- /// of the original value when parsing a generic type.
- ///
- public string GenericTypeName
- {
- get { return unresolvedGenericTypeName; }
- }
-
- ///
- /// The (unresolved) generic method name portion
- /// of the original value when parsing a generic method.
- ///
- public string GenericMethodName
- {
- get { return unresolvedGenericMethodName; }
- }
-
- ///
- /// Is the string value contains generic arguments ?
- ///
- ///
- ///
- /// A generic argument can be a type parameter or a type argument.
- ///
- ///
- public bool ContainsGenericArguments
- {
- get
- {
- return (unresolvedGenericArguments != null &&
- unresolvedGenericArguments.Length > 0);
- }
- }
-
- ///
- /// Is generic arguments only contains type parameters ?
- ///
- public bool IsGenericDefinition
- {
- get
- {
- if (unresolvedGenericArguments == null)
- return false;
-
- foreach (string arg in unresolvedGenericArguments)
- {
- if (arg.Length > 0)
- return false;
- }
- return true;
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Returns an array of unresolved generic arguments types.
- ///
- ///
- ///
- /// A empty string represents a type parameter that
- /// did not have been substituted by a specific type.
- ///
+ /// Type parameters can be applied to classes, interfaces,
+ /// structures, methods, delegates, etc...
+ ///
+ ///
+ public class GenericArgumentsHolder
+ {
+ #region Constants
+
+ ///
+ /// The generic arguments prefix.
+ ///
+ public const char GenericArgumentsPrefix = '<';
+
+ ///
+ /// The generic arguments suffix.
+ ///
+ public const char GenericArgumentsSuffix = '>';
+
+ ///
+ /// The character that separates a list of generic arguments.
+ ///
+ public const char GenericArgumentsSeparator = ',';
+
+ #endregion
+
+ #region Fields
+
+ private string unresolvedGenericTypeName;
+ private string unresolvedGenericMethodName;
+ private string[] unresolvedGenericArguments;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the GenericArgumentsHolder class.
+ ///
+ ///
+ /// The string value to parse looking for a generic definition
+ /// and retrieving its generic arguments.
+ ///
+ public GenericArgumentsHolder(string value)
+ {
+ ParseGenericArguments(value);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The (unresolved) generic type name portion
+ /// of the original value when parsing a generic type.
+ ///
+ public string GenericTypeName
+ {
+ get { return unresolvedGenericTypeName; }
+ }
+
+ ///
+ /// The (unresolved) generic method name portion
+ /// of the original value when parsing a generic method.
+ ///
+ public string GenericMethodName
+ {
+ get { return unresolvedGenericMethodName; }
+ }
+
+ ///
+ /// Is the string value contains generic arguments ?
+ ///
+ ///
+ ///
+ /// A generic argument can be a type parameter or a type argument.
+ ///
+ ///
+ public bool ContainsGenericArguments
+ {
+ get
+ {
+ return (unresolvedGenericArguments != null &&
+ unresolvedGenericArguments.Length > 0);
+ }
+ }
+
+ ///
+ /// Is generic arguments only contains type parameters ?
+ ///
+ public bool IsGenericDefinition
+ {
+ get
+ {
+ if (unresolvedGenericArguments == null)
+ return false;
+
+ foreach (string arg in unresolvedGenericArguments)
+ {
+ if (arg.Length > 0)
+ return false;
+ }
+ return true;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Returns an array of unresolved generic arguments types.
+ ///
+ ///
+ ///
+ /// A empty string represents a type parameter that
+ /// did not have been substituted by a specific type.
+ ///
- /// The rationale behind the creation of this interface is to centralise
- /// the resolution of type names to instances
- /// beyond that offered by the plain vanilla
- /// method call.
- ///
+ /// The rationale behind the creation of this interface is to centralise
+ /// the resolution of type names to instances
+ /// beyond that offered by the plain vanilla
+ /// method call.
+ ///
- /// Simplifies configuration by allowing aliases to be used instead of
- /// fully qualified type names.
- ///
- ///
- /// Comes 'pre-loaded' with a number of convenience alias' for the more
- /// common types; an example would be the 'int' (or 'Integer'
- /// for Visual Basic.NET developers) alias for the
- /// type.
- ///
- ///
- /// Aleksandar Seovic
- ///
- /// $Id: TypeRegistry.cs,v 1.1 2007/07/31 18:16:08 bbaia Exp $
- public sealed class TypeRegistry
- {
- #region Constants
-
- ///
- /// Name of the .Net config section that contains Spring.Net type aliases.
- ///
- private const string TypeAliasesSectionName = "spring/typeAliases";
-
- ///
- /// The alias around the 'int' type.
- ///
- public const string Int32Alias = "int";
-
- ///
- /// The alias around the 'Integer' type (Visual Basic.NET style).
- ///
- public const string Int32AliasVB = "Integer";
-
- ///
- /// The alias around the 'int[]' array type.
- ///
- public const string Int32ArrayAlias = "int[]";
-
- ///
- /// The alias around the 'Integer()' array type (Visual Basic.NET style).
- ///
- public const string Int32ArrayAliasVB = "Integer()";
-
- ///
- /// The alias around the 'decimal' type.
- ///
- public const string DecimalAlias = "decimal";
-
- ///
- /// The alias around the 'Decimal' type (Visual Basic.NET style).
- ///
- public const string DecimalAliasVB = "Decimal";
-
- ///
- /// The alias around the 'decimal[]' array type.
- ///
- public const string DecimalArrayAlias = "decimal[]";
-
- ///
- /// The alias around the 'Decimal()' array type (Visual Basic.NET style).
- ///
- public const string DecimalArrayAliasVB = "Decimal()";
-
- ///
- /// The alias around the 'char' type.
- ///
- public const string CharAlias = "char";
-
- ///
- /// The alias around the 'Char' type (Visual Basic.NET style).
- ///
- public const string CharAliasVB = "Char";
-
- ///
- /// The alias around the 'char[]' array type.
- ///
- public const string CharArrayAlias = "char[]";
-
- ///
- /// The alias around the 'Char()' array type (Visual Basic.NET style).
- ///
- public const string CharArrayAliasVB = "Char()";
-
- ///
- /// The alias around the 'long' type.
- ///
- public const string Int64Alias = "long";
-
- ///
- /// The alias around the 'Long' type (Visual Basic.NET style).
- ///
- public const string Int64AliasVB = "Long";
-
- ///
- /// The alias around the 'long[]' array type.
- ///
- public const string Int64ArrayAlias = "long[]";
-
- ///
- /// The alias around the 'Long()' array type (Visual Basic.NET style).
- ///
- public const string Int64ArrayAliasVB = "Long()";
-
- ///
- /// The alias around the 'short' type.
- ///
- public const string Int16Alias = "short";
-
- ///
- /// The alias around the 'Short' type (Visual Basic.NET style).
- ///
- public const string Int16AliasVB = "Short";
-
- ///
- /// The alias around the 'short[]' array type.
- ///
- public const string Int16ArrayAlias = "short[]";
-
- ///
- /// The alias around the 'Short()' array type (Visual Basic.NET style).
- ///
- public const string Int16ArrayAliasVB = "Short()";
-
- ///
- /// The alias around the 'unsigned int' type.
- ///
- public const string UInt32Alias = "uint";
-
- ///
- /// The alias around the 'unsigned long' type.
- ///
- public const string UInt64Alias = "ulong";
-
- ///
- /// The alias around the 'ulong[]' array type.
- ///
- public const string UInt64ArrayAlias = "ulong[]";
-
- ///
- /// The alias around the 'uint[]' array type.
- ///
- public const string UInt32ArrayAlias = "uint[]";
-
- ///
- /// The alias around the 'unsigned short' type.
- ///
- public const string UInt16Alias = "ushort";
-
- ///
- /// The alias around the 'ushort[]' array type.
- ///
- public const string UInt16ArrayAlias = "ushort[]";
-
- ///
- /// The alias around the 'double' type.
- ///
- public const string DoubleAlias = "double";
-
- ///
- /// The alias around the 'Double' type (Visual Basic.NET style).
- ///
- public const string DoubleAliasVB = "Double";
-
- ///
- /// The alias around the 'double[]' array type.
- ///
- public const string DoubleArrayAlias = "double[]";
-
- ///
- /// The alias around the 'Double()' array type (Visual Basic.NET style).
- ///
- public const string DoubleArrayAliasVB = "Double()";
-
- ///
- /// The alias around the 'float' type.
- ///
- public const string FloatAlias = "float";
-
- ///
- /// The alias around the 'Single' type (Visual Basic.NET style).
- ///
- public const string SingleAlias = "Single";
-
- ///
- /// The alias around the 'float[]' array type.
- ///
- public const string FloatArrayAlias = "float[]";
-
- ///
- /// The alias around the 'Single()' array type (Visual Basic.NET style).
- ///
- public const string SingleArrayAliasVB = "Single()";
-
- ///
- /// The alias around the 'DateTime' type.
- ///
- public const string DateTimeAlias = "DateTime";
-
- ///
- /// The alias around the 'DateTime' type (C# style).
- ///
- public const string DateAlias = "date";
-
- ///
- /// The alias around the 'DateTime' type (Visual Basic.NET style).
- ///
- public const string DateAliasVB = "Date";
-
- ///
- /// The alias around the 'DateTime[]' array type.
- ///
- public const string DateTimeArrayAlias = "DateTime[]";
-
- ///
- /// The alias around the 'DateTime[]' array type.
- ///
- public const string DateTimeArrayAliasCSharp = "date[]";
-
- ///
- /// The alias around the 'DateTime()' array type (Visual Basic.NET style).
- ///
- public const string DateTimeArrayAliasVB = "DateTime()";
-
- ///
- /// The alias around the 'bool' type.
- ///
- public const string BoolAlias = "bool";
-
- ///
- /// The alias around the 'Boolean' type (Visual Basic.NET style).
- ///
- public const string BoolAliasVB = "Boolean";
-
- ///
- /// The alias around the 'bool[]' array type.
- ///
- public const string BoolArrayAlias = "bool[]";
-
- ///
- /// The alias around the 'Boolean()' array type (Visual Basic.NET style).
- ///
- public const string BoolArrayAliasVB = "Boolean()";
-
- ///
- /// The alias around the 'string' type.
- ///
- public const string StringAlias = "string";
-
- ///
- /// The alias around the 'string' type (Visual Basic.NET style).
- ///
- public const string StringAliasVB = "String";
-
- ///
- /// The alias around the 'string[]' array type.
- ///
- public const string StringArrayAlias = "string[]";
-
- ///
- /// The alias around the 'string[]' array type (Visual Basic.NET style).
- ///
- public const string StringArrayAliasVB = "String()";
-
- ///
- /// The alias around the 'object' type.
- ///
- public const string ObjectAlias = "object";
-
- ///
- /// The alias around the 'object' type (Visual Basic.NET style).
- ///
- public const string ObjectAliasVB = "Object";
-
- ///
- /// The alias around the 'object[]' array type.
- ///
- public const string ObjectArrayAlias = "object[]";
-
- ///
- /// The alias around the 'object[]' array type (Visual Basic.NET style).
- ///
- public const string ObjectArrayAliasVB = "Object()";
-
-#if NET_2_0
- ///
- /// The alias around the 'int?' type.
- ///
- public const string NullableInt32Alias = "int?";
-
- ///
- /// The alias around the 'int?[]' array type.
- ///
- public const string NullableInt32ArrayAlias = "int?[]";
-
- ///
- /// The alias around the 'decimal?' type.
- ///
- public const string NullableDecimalAlias = "decimal?";
-
- ///
- /// The alias around the 'decimal?[]' array type.
- ///
- public const string NullableDecimalArrayAlias = "decimal?[]";
-
- ///
- /// The alias around the 'char?' type.
- ///
- public const string NullableCharAlias = "char?";
-
- ///
- /// The alias around the 'char?[]' array type.
- ///
- public const string NullableCharArrayAlias = "char?[]";
-
- ///
- /// The alias around the 'long?' type.
- ///
- public const string NullableInt64Alias = "long?";
-
- ///
- /// The alias around the 'long?[]' array type.
- ///
- public const string NullableInt64ArrayAlias = "long?[]";
-
- ///
- /// The alias around the 'short?' type.
- ///
- public const string NullableInt16Alias = "short?";
-
- ///
- /// The alias around the 'short?[]' array type.
- ///
- public const string NullableInt16ArrayAlias = "short?[]";
-
- ///
- /// The alias around the 'unsigned int?' type.
- ///
- public const string NullableUInt32Alias = "uint?";
-
- ///
- /// The alias around the 'unsigned long?' type.
- ///
- public const string NullableUInt64Alias = "ulong?";
-
- ///
- /// The alias around the 'ulong?[]' array type.
- ///
- public const string NullableUInt64ArrayAlias = "ulong?[]";
-
- ///
- /// The alias around the 'uint?[]' array type.
- ///
- public const string NullableUInt32ArrayAlias = "uint?[]";
-
- ///
- /// The alias around the 'unsigned short?' type.
- ///
- public const string NullableUInt16Alias = "ushort?";
-
- ///
- /// The alias around the 'ushort?[]' array type.
- ///
- public const string NullableUInt16ArrayAlias = "ushort?[]";
-
- ///
- /// The alias around the 'double?' type.
- ///
- public const string NullableDoubleAlias = "double?";
-
- ///
- /// The alias around the 'double?[]' array type.
- ///
- public const string NullableDoubleArrayAlias = "double?[]";
-
- ///
- /// The alias around the 'float?' type.
- ///
- public const string NullableFloatAlias = "float?";
-
- ///
- /// The alias around the 'float?[]' array type.
- ///
- public const string NullableFloatArrayAlias = "float?[]";
-
- ///
- /// The alias around the 'bool?' type.
- ///
- public const string NullableBoolAlias = "bool?";
-
- ///
- /// The alias around the 'bool?[]' array type.
- ///
- public const string NullableBoolArrayAlias = "bool?[]";
-#endif
-
- #endregion
-
- #region Fields
-
- private static IDictionary types = new Hashtable();
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Registers standard and user-configured type aliases.
- ///
- static TypeRegistry()
- {
- lock (types.SyncRoot)
- {
- types["Int32"] = typeof(Int32);
- types[Int32Alias] = typeof(Int32);
- types[Int32AliasVB] = typeof(Int32);
- types[Int32ArrayAlias] = typeof(Int32[]);
- types[Int32ArrayAliasVB] = typeof(Int32[]);
-
- types["UInt32"] = typeof(UInt32);
- types[UInt32Alias] = typeof(UInt32);
- types[UInt32ArrayAlias] = typeof(UInt32[]);
-
- types["Int16"] = typeof(Int16);
- types[Int16Alias] = typeof(Int16);
- types[Int16AliasVB] = typeof(Int16);
- types[Int16ArrayAlias] = typeof(Int16[]);
- types[Int16ArrayAliasVB] = typeof(Int16[]);
-
- types["UInt16"] = typeof(UInt16);
- types[UInt16Alias] = typeof(UInt16);
- types[UInt16ArrayAlias] = typeof(UInt16[]);
-
- types["Int64"] = typeof(Int64);
- types[Int64Alias] = typeof(Int64);
- types[Int64AliasVB] = typeof(Int64);
- types[Int64ArrayAlias] = typeof(Int64[]);
- types[Int64ArrayAliasVB] = typeof(Int64[]);
-
- types["UInt64"] = typeof(UInt64);
- types[UInt64Alias] = typeof(UInt64);
- types[UInt64ArrayAlias] = typeof(UInt64[]);
-
- types[DoubleAlias] = typeof(double);
- types[DoubleAliasVB] = typeof(double);
- types[DoubleArrayAlias] = typeof(double[]);
- types[DoubleArrayAliasVB] = typeof(double[]);
-
- types[FloatAlias] = typeof(float);
- types[SingleAlias] = typeof(float);
- types[FloatArrayAlias] = typeof(float[]);
- types[SingleArrayAliasVB] = typeof(float[]);
-
- types[DateTimeAlias] = typeof(DateTime);
- types[DateAlias] = typeof(DateTime);
- types[DateAliasVB] = typeof(DateTime);
- types[DateTimeArrayAlias] = typeof(DateTime[]);
- types[DateTimeArrayAliasCSharp] = typeof(DateTime[]);
- types[DateTimeArrayAliasVB] = typeof(DateTime[]);
-
- types[BoolAlias] = typeof(bool);
- types[BoolAliasVB] = typeof(bool);
- types[BoolArrayAlias] = typeof(bool[]);
- types[BoolArrayAliasVB] = typeof(bool[]);
-
- types[DecimalAlias] = typeof(decimal);
- types[DecimalAliasVB] = typeof(decimal);
- types[DecimalArrayAlias] = typeof(decimal[]);
- types[DecimalArrayAliasVB] = typeof(decimal[]);
-
- types[CharAlias] = typeof(char);
- types[CharAliasVB] = typeof(char);
- types[CharArrayAlias] = typeof(char[]);
- types[CharArrayAliasVB] = typeof(char[]);
-
- types[StringAlias] = typeof(string);
- types[StringAliasVB] = typeof(string);
- types[StringArrayAlias] = typeof(string[]);
- types[StringArrayAliasVB] = typeof(string[]);
-
- types[ObjectAlias] = typeof(object);
- types[ObjectAliasVB] = typeof(object);
- types[ObjectArrayAlias] = typeof(object[]);
- types[ObjectArrayAliasVB] = typeof(object[]);
-
-#if NET_2_0
- types[NullableInt32Alias] = typeof(int?);
- types[NullableInt32ArrayAlias] = typeof(int?[]);
-
- types[NullableDecimalAlias] = typeof(decimal?);
- types[NullableDecimalArrayAlias] = typeof(decimal?[]);
-
- types[NullableCharAlias] = typeof(char?);
- types[NullableCharArrayAlias] = typeof(char?[]);
-
- types[NullableInt64Alias] = typeof(long?);
- types[NullableInt64ArrayAlias] = typeof(long?[]);
-
- types[NullableInt16Alias] = typeof(short?);
- types[NullableInt16ArrayAlias] = typeof(short?[]);
-
- types[NullableUInt32Alias] = typeof(uint?);
- types[NullableUInt32ArrayAlias] = typeof(uint?[]);
-
- types[NullableUInt64Alias] = typeof(ulong?);
- types[NullableUInt64ArrayAlias] = typeof(ulong?[]);
-
- types[NullableUInt16Alias] = typeof(ushort?);
- types[NullableUInt16ArrayAlias] = typeof(ushort?[]);
-
- types[NullableDoubleAlias] = typeof(double?);
- types[NullableDoubleArrayAlias] = typeof(double?[]);
-
- types[NullableFloatAlias] = typeof(float?);
- types[NullableFloatArrayAlias] = typeof(float?[]);
-
- types[NullableBoolAlias] = typeof(bool?);
- types[NullableBoolArrayAlias] = typeof(bool?[]);
-#endif
-
- // register user-configured type aliases
- ConfigurationUtils.GetSection(TypeAliasesSectionName);
- }
- }
-
- #endregion
-
- ///
- /// Registers an alias for the specified .
- ///
- ///
- ///
- /// This overload does eager resolution of the
- /// referred to by the parameter. It will throw a
- /// if the referred
- /// to by the parameter cannot be resolved.
- ///
+ /// Simplifies configuration by allowing aliases to be used instead of
+ /// fully qualified type names.
+ ///
+ ///
+ /// Comes 'pre-loaded' with a number of convenience alias' for the more
+ /// common types; an example would be the 'int' (or 'Integer'
+ /// for Visual Basic.NET developers) alias for the
+ /// type.
+ ///
+ ///
+ /// Aleksandar Seovic
+ ///
+ public sealed class TypeRegistry
+ {
+ #region Constants
+
+ ///
+ /// Name of the .Net config section that contains Spring.Net type aliases.
+ ///
+ private const string TypeAliasesSectionName = "spring/typeAliases";
+
+ ///
+ /// The alias around the 'int' type.
+ ///
+ public const string Int32Alias = "int";
+
+ ///
+ /// The alias around the 'Integer' type (Visual Basic.NET style).
+ ///
+ public const string Int32AliasVB = "Integer";
+
+ ///
+ /// The alias around the 'int[]' array type.
+ ///
+ public const string Int32ArrayAlias = "int[]";
+
+ ///
+ /// The alias around the 'Integer()' array type (Visual Basic.NET style).
+ ///
+ public const string Int32ArrayAliasVB = "Integer()";
+
+ ///
+ /// The alias around the 'decimal' type.
+ ///
+ public const string DecimalAlias = "decimal";
+
+ ///
+ /// The alias around the 'Decimal' type (Visual Basic.NET style).
+ ///
+ public const string DecimalAliasVB = "Decimal";
+
+ ///
+ /// The alias around the 'decimal[]' array type.
+ ///
+ public const string DecimalArrayAlias = "decimal[]";
+
+ ///
+ /// The alias around the 'Decimal()' array type (Visual Basic.NET style).
+ ///
+ public const string DecimalArrayAliasVB = "Decimal()";
+
+ ///
+ /// The alias around the 'char' type.
+ ///
+ public const string CharAlias = "char";
+
+ ///
+ /// The alias around the 'Char' type (Visual Basic.NET style).
+ ///
+ public const string CharAliasVB = "Char";
+
+ ///
+ /// The alias around the 'char[]' array type.
+ ///
+ public const string CharArrayAlias = "char[]";
+
+ ///
+ /// The alias around the 'Char()' array type (Visual Basic.NET style).
+ ///
+ public const string CharArrayAliasVB = "Char()";
+
+ ///
+ /// The alias around the 'long' type.
+ ///
+ public const string Int64Alias = "long";
+
+ ///
+ /// The alias around the 'Long' type (Visual Basic.NET style).
+ ///
+ public const string Int64AliasVB = "Long";
+
+ ///
+ /// The alias around the 'long[]' array type.
+ ///
+ public const string Int64ArrayAlias = "long[]";
+
+ ///
+ /// The alias around the 'Long()' array type (Visual Basic.NET style).
+ ///
+ public const string Int64ArrayAliasVB = "Long()";
+
+ ///
+ /// The alias around the 'short' type.
+ ///
+ public const string Int16Alias = "short";
+
+ ///
+ /// The alias around the 'Short' type (Visual Basic.NET style).
+ ///
+ public const string Int16AliasVB = "Short";
+
+ ///
+ /// The alias around the 'short[]' array type.
+ ///
+ public const string Int16ArrayAlias = "short[]";
+
+ ///
+ /// The alias around the 'Short()' array type (Visual Basic.NET style).
+ ///
+ public const string Int16ArrayAliasVB = "Short()";
+
+ ///
+ /// The alias around the 'unsigned int' type.
+ ///
+ public const string UInt32Alias = "uint";
+
+ ///
+ /// The alias around the 'unsigned long' type.
+ ///
+ public const string UInt64Alias = "ulong";
+
+ ///
+ /// The alias around the 'ulong[]' array type.
+ ///
+ public const string UInt64ArrayAlias = "ulong[]";
+
+ ///
+ /// The alias around the 'uint[]' array type.
+ ///
+ public const string UInt32ArrayAlias = "uint[]";
+
+ ///
+ /// The alias around the 'unsigned short' type.
+ ///
+ public const string UInt16Alias = "ushort";
+
+ ///
+ /// The alias around the 'ushort[]' array type.
+ ///
+ public const string UInt16ArrayAlias = "ushort[]";
+
+ ///
+ /// The alias around the 'double' type.
+ ///
+ public const string DoubleAlias = "double";
+
+ ///
+ /// The alias around the 'Double' type (Visual Basic.NET style).
+ ///
+ public const string DoubleAliasVB = "Double";
+
+ ///
+ /// The alias around the 'double[]' array type.
+ ///
+ public const string DoubleArrayAlias = "double[]";
+
+ ///
+ /// The alias around the 'Double()' array type (Visual Basic.NET style).
+ ///
+ public const string DoubleArrayAliasVB = "Double()";
+
+ ///
+ /// The alias around the 'float' type.
+ ///
+ public const string FloatAlias = "float";
+
+ ///
+ /// The alias around the 'Single' type (Visual Basic.NET style).
+ ///
+ public const string SingleAlias = "Single";
+
+ ///
+ /// The alias around the 'float[]' array type.
+ ///
+ public const string FloatArrayAlias = "float[]";
+
+ ///
+ /// The alias around the 'Single()' array type (Visual Basic.NET style).
+ ///
+ public const string SingleArrayAliasVB = "Single()";
+
+ ///
+ /// The alias around the 'DateTime' type.
+ ///
+ public const string DateTimeAlias = "DateTime";
+
+ ///
+ /// The alias around the 'DateTime' type (C# style).
+ ///
+ public const string DateAlias = "date";
+
+ ///
+ /// The alias around the 'DateTime' type (Visual Basic.NET style).
+ ///
+ public const string DateAliasVB = "Date";
+
+ ///
+ /// The alias around the 'DateTime[]' array type.
+ ///
+ public const string DateTimeArrayAlias = "DateTime[]";
+
+ ///
+ /// The alias around the 'DateTime[]' array type.
+ ///
+ public const string DateTimeArrayAliasCSharp = "date[]";
+
+ ///
+ /// The alias around the 'DateTime()' array type (Visual Basic.NET style).
+ ///
+ public const string DateTimeArrayAliasVB = "DateTime()";
+
+ ///
+ /// The alias around the 'bool' type.
+ ///
+ public const string BoolAlias = "bool";
+
+ ///
+ /// The alias around the 'Boolean' type (Visual Basic.NET style).
+ ///
+ public const string BoolAliasVB = "Boolean";
+
+ ///
+ /// The alias around the 'bool[]' array type.
+ ///
+ public const string BoolArrayAlias = "bool[]";
+
+ ///
+ /// The alias around the 'Boolean()' array type (Visual Basic.NET style).
+ ///
+ public const string BoolArrayAliasVB = "Boolean()";
+
+ ///
+ /// The alias around the 'string' type.
+ ///
+ public const string StringAlias = "string";
+
+ ///
+ /// The alias around the 'string' type (Visual Basic.NET style).
+ ///
+ public const string StringAliasVB = "String";
+
+ ///
+ /// The alias around the 'string[]' array type.
+ ///
+ public const string StringArrayAlias = "string[]";
+
+ ///
+ /// The alias around the 'string[]' array type (Visual Basic.NET style).
+ ///
+ public const string StringArrayAliasVB = "String()";
+
+ ///
+ /// The alias around the 'object' type.
+ ///
+ public const string ObjectAlias = "object";
+
+ ///
+ /// The alias around the 'object' type (Visual Basic.NET style).
+ ///
+ public const string ObjectAliasVB = "Object";
+
+ ///
+ /// The alias around the 'object[]' array type.
+ ///
+ public const string ObjectArrayAlias = "object[]";
+
+ ///
+ /// The alias around the 'object[]' array type (Visual Basic.NET style).
+ ///
+ public const string ObjectArrayAliasVB = "Object()";
+
+#if NET_2_0
+ ///
+ /// The alias around the 'int?' type.
+ ///
+ public const string NullableInt32Alias = "int?";
+
+ ///
+ /// The alias around the 'int?[]' array type.
+ ///
+ public const string NullableInt32ArrayAlias = "int?[]";
+
+ ///
+ /// The alias around the 'decimal?' type.
+ ///
+ public const string NullableDecimalAlias = "decimal?";
+
+ ///
+ /// The alias around the 'decimal?[]' array type.
+ ///
+ public const string NullableDecimalArrayAlias = "decimal?[]";
+
+ ///
+ /// The alias around the 'char?' type.
+ ///
+ public const string NullableCharAlias = "char?";
+
+ ///
+ /// The alias around the 'char?[]' array type.
+ ///
+ public const string NullableCharArrayAlias = "char?[]";
+
+ ///
+ /// The alias around the 'long?' type.
+ ///
+ public const string NullableInt64Alias = "long?";
+
+ ///
+ /// The alias around the 'long?[]' array type.
+ ///
+ public const string NullableInt64ArrayAlias = "long?[]";
+
+ ///
+ /// The alias around the 'short?' type.
+ ///
+ public const string NullableInt16Alias = "short?";
+
+ ///
+ /// The alias around the 'short?[]' array type.
+ ///
+ public const string NullableInt16ArrayAlias = "short?[]";
+
+ ///
+ /// The alias around the 'unsigned int?' type.
+ ///
+ public const string NullableUInt32Alias = "uint?";
+
+ ///
+ /// The alias around the 'unsigned long?' type.
+ ///
+ public const string NullableUInt64Alias = "ulong?";
+
+ ///
+ /// The alias around the 'ulong?[]' array type.
+ ///
+ public const string NullableUInt64ArrayAlias = "ulong?[]";
+
+ ///
+ /// The alias around the 'uint?[]' array type.
+ ///
+ public const string NullableUInt32ArrayAlias = "uint?[]";
+
+ ///
+ /// The alias around the 'unsigned short?' type.
+ ///
+ public const string NullableUInt16Alias = "ushort?";
+
+ ///
+ /// The alias around the 'ushort?[]' array type.
+ ///
+ public const string NullableUInt16ArrayAlias = "ushort?[]";
+
+ ///
+ /// The alias around the 'double?' type.
+ ///
+ public const string NullableDoubleAlias = "double?";
+
+ ///
+ /// The alias around the 'double?[]' array type.
+ ///
+ public const string NullableDoubleArrayAlias = "double?[]";
+
+ ///
+ /// The alias around the 'float?' type.
+ ///
+ public const string NullableFloatAlias = "float?";
+
+ ///
+ /// The alias around the 'float?[]' array type.
+ ///
+ public const string NullableFloatArrayAlias = "float?[]";
+
+ ///
+ /// The alias around the 'bool?' type.
+ ///
+ public const string NullableBoolAlias = "bool?";
+
+ ///
+ /// The alias around the 'bool?[]' array type.
+ ///
+ public const string NullableBoolArrayAlias = "bool?[]";
+#endif
+
+ #endregion
+
+ #region Fields
+
+ private static IDictionary types = new Hashtable();
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Registers standard and user-configured type aliases.
+ ///
+ static TypeRegistry()
+ {
+ lock (types.SyncRoot)
+ {
+ types["Int32"] = typeof(Int32);
+ types[Int32Alias] = typeof(Int32);
+ types[Int32AliasVB] = typeof(Int32);
+ types[Int32ArrayAlias] = typeof(Int32[]);
+ types[Int32ArrayAliasVB] = typeof(Int32[]);
+
+ types["UInt32"] = typeof(UInt32);
+ types[UInt32Alias] = typeof(UInt32);
+ types[UInt32ArrayAlias] = typeof(UInt32[]);
+
+ types["Int16"] = typeof(Int16);
+ types[Int16Alias] = typeof(Int16);
+ types[Int16AliasVB] = typeof(Int16);
+ types[Int16ArrayAlias] = typeof(Int16[]);
+ types[Int16ArrayAliasVB] = typeof(Int16[]);
+
+ types["UInt16"] = typeof(UInt16);
+ types[UInt16Alias] = typeof(UInt16);
+ types[UInt16ArrayAlias] = typeof(UInt16[]);
+
+ types["Int64"] = typeof(Int64);
+ types[Int64Alias] = typeof(Int64);
+ types[Int64AliasVB] = typeof(Int64);
+ types[Int64ArrayAlias] = typeof(Int64[]);
+ types[Int64ArrayAliasVB] = typeof(Int64[]);
+
+ types["UInt64"] = typeof(UInt64);
+ types[UInt64Alias] = typeof(UInt64);
+ types[UInt64ArrayAlias] = typeof(UInt64[]);
+
+ types[DoubleAlias] = typeof(double);
+ types[DoubleAliasVB] = typeof(double);
+ types[DoubleArrayAlias] = typeof(double[]);
+ types[DoubleArrayAliasVB] = typeof(double[]);
+
+ types[FloatAlias] = typeof(float);
+ types[SingleAlias] = typeof(float);
+ types[FloatArrayAlias] = typeof(float[]);
+ types[SingleArrayAliasVB] = typeof(float[]);
+
+ types[DateTimeAlias] = typeof(DateTime);
+ types[DateAlias] = typeof(DateTime);
+ types[DateAliasVB] = typeof(DateTime);
+ types[DateTimeArrayAlias] = typeof(DateTime[]);
+ types[DateTimeArrayAliasCSharp] = typeof(DateTime[]);
+ types[DateTimeArrayAliasVB] = typeof(DateTime[]);
+
+ types[BoolAlias] = typeof(bool);
+ types[BoolAliasVB] = typeof(bool);
+ types[BoolArrayAlias] = typeof(bool[]);
+ types[BoolArrayAliasVB] = typeof(bool[]);
+
+ types[DecimalAlias] = typeof(decimal);
+ types[DecimalAliasVB] = typeof(decimal);
+ types[DecimalArrayAlias] = typeof(decimal[]);
+ types[DecimalArrayAliasVB] = typeof(decimal[]);
+
+ types[CharAlias] = typeof(char);
+ types[CharAliasVB] = typeof(char);
+ types[CharArrayAlias] = typeof(char[]);
+ types[CharArrayAliasVB] = typeof(char[]);
+
+ types[StringAlias] = typeof(string);
+ types[StringAliasVB] = typeof(string);
+ types[StringArrayAlias] = typeof(string[]);
+ types[StringArrayAliasVB] = typeof(string[]);
+
+ types[ObjectAlias] = typeof(object);
+ types[ObjectAliasVB] = typeof(object);
+ types[ObjectArrayAlias] = typeof(object[]);
+ types[ObjectArrayAliasVB] = typeof(object[]);
+
+#if NET_2_0
+ types[NullableInt32Alias] = typeof(int?);
+ types[NullableInt32ArrayAlias] = typeof(int?[]);
+
+ types[NullableDecimalAlias] = typeof(decimal?);
+ types[NullableDecimalArrayAlias] = typeof(decimal?[]);
+
+ types[NullableCharAlias] = typeof(char?);
+ types[NullableCharArrayAlias] = typeof(char?[]);
+
+ types[NullableInt64Alias] = typeof(long?);
+ types[NullableInt64ArrayAlias] = typeof(long?[]);
+
+ types[NullableInt16Alias] = typeof(short?);
+ types[NullableInt16ArrayAlias] = typeof(short?[]);
+
+ types[NullableUInt32Alias] = typeof(uint?);
+ types[NullableUInt32ArrayAlias] = typeof(uint?[]);
+
+ types[NullableUInt64Alias] = typeof(ulong?);
+ types[NullableUInt64ArrayAlias] = typeof(ulong?[]);
+
+ types[NullableUInt16Alias] = typeof(ushort?);
+ types[NullableUInt16ArrayAlias] = typeof(ushort?[]);
+
+ types[NullableDoubleAlias] = typeof(double?);
+ types[NullableDoubleArrayAlias] = typeof(double?[]);
+
+ types[NullableFloatAlias] = typeof(float?);
+ types[NullableFloatArrayAlias] = typeof(float?[]);
+
+ types[NullableBoolAlias] = typeof(bool?);
+ types[NullableBoolArrayAlias] = typeof(bool?[]);
+#endif
+
+ // register user-configured type aliases
+ ConfigurationUtils.GetSection(TypeAliasesSectionName);
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Registers an alias for the specified .
+ ///
+ ///
+ ///
+ /// This overload does eager resolution of the
+ /// referred to by the parameter. It will throw a
+ /// if the referred
+ /// to by the parameter cannot be resolved.
+ ///
- /// is
- /// deprecated in .NET 2.0, but is still used here (even when this class is
- /// compiled for .NET 2.0);
- /// will
- /// still resolve (non-.NET Framework) local assemblies when given only the
- /// display name of an assembly (the behaviour for .NET Framework assemblies
- /// and strongly named assemblies is documented in the docs for the
- /// method).
- ///
+ /// is
+ /// deprecated in .NET 2.0, but is still used here (even when this class is
+ /// compiled for .NET 2.0);
+ /// will
+ /// still resolve (non-.NET Framework) local assemblies when given only the
+ /// display name of an assembly (the behaviour for .NET Framework assemblies
+ /// and strongly named assemblies is documented in the docs for the
+ /// method).
+ ///
- /// Preparing this object once and reusing it many times for expression
- /// evaluation can result in significant performance improvements, as
- /// expression parsing and reflection lookups are only performed once.
- ///
+ /// Preparing this object once and reusing it many times for expression
+ /// evaluation can result in significant performance improvements, as
+ /// expression parsing and reflection lookups are only performed once.
+ ///
- /// This class allows users to get or set properties, execute methods, and evaluate
- /// logical and arithmetic expressions.
- ///
- ///
- /// Methods in this class parse expression on every invocation.
- /// If you plan to reuse the same expression many times, you should prepare
- /// the expression once using the static method,
- /// and then call to evaluate it.
- ///
- ///
- /// This can result in significant performance improvements as it avoids expression
- /// parsing and node resolution every time it is called.
- ///
+ /// This class allows users to get or set properties, execute methods, and evaluate
+ /// logical and arithmetic expressions.
+ ///
+ ///
+ /// Methods in this class parse expression on every invocation.
+ /// If you plan to reuse the same expression many times, you should prepare
+ /// the expression once using the static method,
+ /// and then call to evaluate it.
+ ///
+ ///
+ /// This can result in significant performance improvements as it avoids expression
+ /// parsing and node resolution every time it is called.
+ ///
- /// This class contains the bulk of the localizer logic, including implementation
- /// of the ApplyResources methods that are defined in
- /// interface.
- ///
- ///
- /// All specific localizers need to do is inherit this class and implement
- /// GetResources method that will return a list of
- /// objects that should be applied to a specified target.
- ///
- ///
- /// Custom implementations can use whatever type of resource storage they want,
- /// such as standard .NET resource sets, custom XML files, database, etc.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: AbstractLocalizer.cs,v 1.5 2007/07/24 17:26:25 oakinger Exp $
- public abstract class AbstractLocalizer : ILocalizer
- {
- private IResourceCache resourceCache = new NullResourceCache();
-
- ///
- /// Gets or sets the resource cache instance.
- ///
- /// The resource cache instance.
- public IResourceCache ResourceCache
- {
- get { return resourceCache; }
- set { resourceCache = value; }
- }
-
- ///
- /// Applies resources of the specified culture to the specified target object.
- ///
- /// Target object to apply resources to.
- /// instance to retrieve resources from.
- /// Resource culture to use for resource lookup.
- public void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture)
- {
- AssertUtils.ArgumentNotNull(target, "target");
- AssertUtils.ArgumentNotNull(culture, "culture");
-
- IList resources = GetResources(target, messageSource, culture);
- foreach (Resource resource in resources)
- {
- resource.Target.SetValue(target, null, resource.Value);
- }
- }
-
- ///
- /// Applies resources to the specified target object, using current thread's uiCulture to resolve resources.
- ///
- /// Target object to apply resources to.
- /// instance to retrieve resources from.
- public void ApplyResources(object target, IMessageSource messageSource)
- {
- AssertUtils.ArgumentNotNull(target, "target");
- ApplyResources(target, messageSource, Thread.CurrentThread.CurrentUICulture);
- }
-
- ///
- /// Returns a list of instances that should be applied to the target.
- ///
- /// Target to get a list of resources for.
- /// instance to retrieve resources from.
- /// Resource locale.
- /// A list of resources to apply.
- private IList GetResources(object target, IMessageSource messageSource, CultureInfo culture)
- {
- IList resources = resourceCache.GetResources(target, culture);
-
- if (resources == null)
- {
- resources = LoadResources(target, messageSource, culture);
- resourceCache.PutResources(target, culture, resources);
- }
-
- return resources;
- }
-
- ///
- /// Loads resources from the storage and creates a list of instances that should be applied to the target.
- ///
- /// Target to get a list of resources for.
- /// instance to retrieve resources from.
- /// Resource locale.
- /// A list of resources to apply.
- protected abstract IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture);
-
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System.Collections;
+using System.Globalization;
+using System.Threading;
+
+using Spring.Context;
+using Spring.Util;
+
+namespace Spring.Globalization
+{
+ ///
+ /// Abstract base class that all localizers should extend
+ ///
+ ///
+ ///
+ /// This class contains the bulk of the localizer logic, including implementation
+ /// of the ApplyResources methods that are defined in
+ /// interface.
+ ///
+ ///
+ /// All specific localizers need to do is inherit this class and implement
+ /// GetResources method that will return a list of
+ /// objects that should be applied to a specified target.
+ ///
+ ///
+ /// Custom implementations can use whatever type of resource storage they want,
+ /// such as standard .NET resource sets, custom XML files, database, etc.
+ ///
- /// The 'context' is determined by the appropriate implementation class.
- /// An example of such a context might be a thread local bound
- /// , or a
- /// sourced from an HTTP
- /// session.
- ///
- ///
- ///
- /// The that should be used
- /// by the caller.
- ///
- CultureInfo ResolveCulture();
-
- ///
- /// Sets the .
- ///
- ///
- ///
- /// This is an optional operation and does not need to be implemented
- /// such that it actually does anything useful (i.e. it can be a no-op).
- ///
+ /// The 'context' is determined by the appropriate implementation class.
+ /// An example of such a context might be a thread local bound
+ /// , or a
+ /// sourced from an HTTP
+ /// session.
+ ///
+ ///
+ ///
+ /// The that should be used
+ /// by the caller.
+ ///
+ CultureInfo ResolveCulture();
+
+ ///
+ /// Sets the .
+ ///
+ ///
+ ///
+ /// This is an optional operation and does not need to be implemented
+ /// such that it actually does anything useful (i.e. it can be a no-op).
+ ///
+ ///
+ ///
+ /// The new or
+ /// to clear the current .
+ ///
+ void SetCulture(CultureInfo culture);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Globalization/IFormatter.cs b/src/Spring/Spring.Core/Globalization/IFormatter.cs
index a51a0eec..320dd33d 100644
--- a/src/Spring/Spring.Core/Globalization/IFormatter.cs
+++ b/src/Spring/Spring.Core/Globalization/IFormatter.cs
@@ -1,51 +1,50 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-namespace Spring.Globalization
-{
- ///
- /// Interface that should be implemented by all formatters.
- ///
- ///
- ///
- /// Formatters assume that source value is a string, and make no assumptions
- /// about the target value's type, which means that Parse method can return
- /// object of any type.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: IFormatter.cs,v 1.2 2006/04/09 07:18:47 markpollack Exp $
- public interface IFormatter
- {
- ///
- /// Formats the specified value.
- ///
- /// The value to format.
- /// Formatted .
- string Format(object value);
-
- ///
- /// Parses the specified value.
- ///
- /// The value to parse.
- /// Parsed .
- object Parse(string value);
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+namespace Spring.Globalization
+{
+ ///
+ /// Interface that should be implemented by all formatters.
+ ///
+ ///
+ ///
+ /// Formatters assume that source value is a string, and make no assumptions
+ /// about the target value's type, which means that Parse method can return
+ /// object of any type.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public interface IFormatter
+ {
+ ///
+ /// Formats the specified value.
+ ///
+ /// The value to format.
+ /// Formatted .
+ string Format(object value);
+
+ ///
+ /// Parses the specified value.
+ ///
+ /// The value to parse.
+ /// Parsed .
+ object Parse(string value);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Globalization/ILocalizer.cs b/src/Spring/Spring.Core/Globalization/ILocalizer.cs
index 7e41875a..f2e028ff 100644
--- a/src/Spring/Spring.Core/Globalization/ILocalizer.cs
+++ b/src/Spring/Spring.Core/Globalization/ILocalizer.cs
@@ -1,61 +1,60 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System.Globalization;
-
-using Spring.Context;
-
-namespace Spring.Globalization
-{
- ///
- /// Defines an interface that localizers have to implement.
- ///
- ///
- ///
- /// Localizers are used to automatically apply resources to object's members
- /// using reflection.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: ILocalizer.cs,v 1.2 2006/04/09 07:18:47 markpollack Exp $
- public interface ILocalizer
- {
- ///
- /// Gets or sets the resource cache instance.
- ///
- /// The resource cache instance.
- IResourceCache ResourceCache { get; set; }
-
- ///
- /// Applies resources of the specified culture to the specified target object.
- ///
- /// Target object to apply resources to.
- /// instance to retrieve resources from.
- /// Resource culture to use for resource lookup.
- void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture);
-
- ///
- /// Applies resources to the specified target object, using current thread's culture to resolve resources.
- ///
- /// Target object to apply resources to.
- /// instance to retrieve resources from.
- void ApplyResources(object target, IMessageSource messageSource);
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System.Globalization;
+
+using Spring.Context;
+
+namespace Spring.Globalization
+{
+ ///
+ /// Defines an interface that localizers have to implement.
+ ///
+ ///
+ ///
+ /// Localizers are used to automatically apply resources to object's members
+ /// using reflection.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public interface ILocalizer
+ {
+ ///
+ /// Gets or sets the resource cache instance.
+ ///
+ /// The resource cache instance.
+ IResourceCache ResourceCache { get; set; }
+
+ ///
+ /// Applies resources of the specified culture to the specified target object.
+ ///
+ /// Target object to apply resources to.
+ /// instance to retrieve resources from.
+ /// Resource culture to use for resource lookup.
+ void ApplyResources(object target, IMessageSource messageSource, CultureInfo culture);
+
+ ///
+ /// Applies resources to the specified target object, using current thread's culture to resolve resources.
+ ///
+ /// Target object to apply resources to.
+ /// instance to retrieve resources from.
+ void ApplyResources(object target, IMessageSource messageSource);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Globalization/IResourceCache.cs b/src/Spring/Spring.Core/Globalization/IResourceCache.cs
index 5a171804..c489d8c4 100644
--- a/src/Spring/Spring.Core/Globalization/IResourceCache.cs
+++ b/src/Spring/Spring.Core/Globalization/IResourceCache.cs
@@ -1,50 +1,49 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System.Collections;
-using System.Globalization;
-
-namespace Spring.Globalization
-{
- ///
- /// Defines an interface that resource cache adapters have to implement.
- ///
- /// Aleksandar Seovic
- /// $Id: IResourceCache.cs,v 1.2 2006/04/09 07:18:47 markpollack Exp $
- public interface IResourceCache
- {
- ///
- /// Gets the list of resources from cache.
- ///
- /// Target to get a list of resources for.
- /// Resource culture.
- /// A list of cached resources for the specified target object and culture.
- IList GetResources(object target, CultureInfo culture);
-
- ///
- /// Puts the list of resources in the cache.
- ///
- /// Target to cache a list of resources for.
- /// Resource culture.
- /// A list of resources to cache.
- /// A list of cached resources for the specified target object and culture.
- void PutResources(object target, CultureInfo culture, IList resources);
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System.Collections;
+using System.Globalization;
+
+namespace Spring.Globalization
+{
+ ///
+ /// Defines an interface that resource cache adapters have to implement.
+ ///
+ /// Aleksandar Seovic
+ public interface IResourceCache
+ {
+ ///
+ /// Gets the list of resources from cache.
+ ///
+ /// Target to get a list of resources for.
+ /// Resource culture.
+ /// A list of cached resources for the specified target object and culture.
+ IList GetResources(object target, CultureInfo culture);
+
+ ///
+ /// Puts the list of resources in the cache.
+ ///
+ /// Target to cache a list of resources for.
+ /// Resource culture.
+ /// A list of resources to cache.
+ /// A list of cached resources for the specified target object and culture.
+ void PutResources(object target, CultureInfo culture, IList resources);
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs b/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs
index f1e13f4c..eaf5057a 100644
--- a/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs
+++ b/src/Spring/Spring.Core/Globalization/Localizers/ResourceSetLocalizer.cs
@@ -1,112 +1,111 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Collections;
-using System.Globalization;
-using System.Resources;
-using Common.Logging;
-using Spring.Context;
-using Spring.Context.Support;
-using Spring.Expressions;
-
-namespace Spring.Globalization.Localizers
-{
- ///
- /// Loads a list of resources that should be applied from the .NET .
- ///
- ///
- ///
- /// This implementation will iterate over all resource managers
- /// within the message source and return a list of all the resources whose name starts with '$this'.
- ///
- ///
- /// All other resources will be ignored, but you can retrieve them by calling one of
- /// GetMessage methods on the message source directly.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: ResourceSetLocalizer.cs,v 1.11 2007/07/24 17:26:25 oakinger Exp $
- public class ResourceSetLocalizer : AbstractLocalizer
- {
- private static readonly ILog log = LogManager.GetLogger(typeof(ResourceSetLocalizer));
-
- private static readonly IList ignoreList =
- new string[] {"$this.DefaultModifiers", "$this.TrayAutoArrange", "$this.TrayLargeIcon"};
-
- ///
- /// Loads resources from the storage and creates a list of instances that should be applied to the target.
- ///
- ///
- /// This feature is not currently supported on version 1.0 of the .NET platform.
- ///
- /// Target to get a list of resources for.
- /// instance to retrieve resources from.
- /// Resource locale.
- /// A list of resources to apply.
- protected override IList LoadResources(object target, IMessageSource messageSource, CultureInfo culture)
- {
-#if ! NET_1_0
- IList resources;
- resources = new ArrayList();
-
- if (messageSource is ResourceSetMessageSource)
- {
- for (int i = 0; i < ((ResourceSetMessageSource) messageSource).ResourceManagers.Count; i++)
- {
- ResourceManager rm = ((ResourceSetMessageSource) messageSource).ResourceManagers[i] as ResourceManager;
- ResourceSet invariantResources = null;
- try
- {
- invariantResources = rm.GetResourceSet(CultureInfo.InvariantCulture, true, true);
- }
- catch (MissingManifestResourceException mmrex)
- {
- // ignore but log missing ResourceSet
- log.Debug("No ResourceSet available for invariant culture", mmrex);
- }
-
- if (invariantResources != null)
- {
- foreach (DictionaryEntry resource in invariantResources)
- {
- string resourceName = (string)resource.Key;
- if (resourceName.StartsWith("$this") && !ignoreList.Contains(resourceName))
- {
- // redirect resource resolution if necessary
- object resourceValue = rm.GetObject(resourceName, culture);
- if (resourceValue is String && ((String)resourceValue).StartsWith("$messageSource"))
- {
- resourceValue = messageSource.GetResourceObject(((String)resourceValue).Substring(15), culture);
- }
- resources.Add(new Resource(Expression.ParsePrimary(resourceName.Substring(6)), resourceValue));
- }
- }
- }
- }
- }
- return resources;
-#else
- throw new NotSupportedException("Operation not supported in .NET 1.0 Release.");
-#endif
- }
-
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Resources;
+using Common.Logging;
+using Spring.Context;
+using Spring.Context.Support;
+using Spring.Expressions;
+
+namespace Spring.Globalization.Localizers
+{
+ ///
+ /// Loads a list of resources that should be applied from the .NET .
+ ///
+ ///
+ ///
+ /// This implementation will iterate over all resource managers
+ /// within the message source and return a list of all the resources whose name starts with '$this'.
+ ///
+ ///
+ /// All other resources will be ignored, but you can retrieve them by calling one of
+ /// GetMessage methods on the message source directly.
+ ///
- /// It tries to get the
- /// from the value of the
- ///
- /// property and falls back to the of the
- /// current thread if the
- ///
- /// is .
- ///
- /// The 'context' in this implementation is the
- /// value of the
- ///
- /// property (if said property value is not ), or the
- /// of the current thread if it is
- /// .
- ///
+ /// It tries to get the
+ /// from the value of the
+ ///
+ /// property and falls back to the of the
+ /// current thread if the
+ ///
+ /// is .
+ ///
+ /// The 'context' in this implementation is the
+ /// value of the
+ ///
+ /// property (if said property value is not ), or the
+ /// of the current thread if it is
+ /// .
+ ///
- /// This interface only applies to objects that have been instantiated
- /// within the context of an
- /// . This interface does
- /// not typically need to be implemented by application code, but is rather
- /// used by classes internal to Spring.NET.
- ///
- ///
- /// Mark Pollack
- /// Rick Evans
- /// $Id: IEventRegistryAware.cs,v 1.2 2006/04/09 07:18:47 markpollack Exp $
- public interface IEventRegistryAware
- {
- ///
- /// Set the
- /// associated with the
- /// that created this
- /// object.
- ///
- ///
- ///
- /// This property will be set by the relevant
- /// after all of this
- /// object's dependencies have been resolved. This object can use the
- /// supplied
- /// immediately to publish or subscribe to one or more events.
- ///
+ /// This interface only applies to objects that have been instantiated
+ /// within the context of an
+ /// . This interface does
+ /// not typically need to be implemented by application code, but is rather
+ /// used by classes internal to Spring.NET.
+ ///
+ ///
+ /// Mark Pollack
+ /// Rick Evans
+ public interface IEventRegistryAware
+ {
+ ///
+ /// Set the
+ /// associated with the
+ /// that created this
+ /// object.
+ ///
+ ///
+ ///
+ /// This property will be set by the relevant
+ /// after all of this
+ /// object's dependencies have been resolved. This object can use the
+ /// supplied
+ /// immediately to publish or subscribe to one or more events.
+ ///
- /// Often used to wire subscribers to event publishers.
- ///
- ///
- ///
- /// The of delegate to create.
- ///
- ///
- /// The target subscriber object that contains the delegate implementation.
- ///
- ///
- /// referencing the delegate method on the subscriber.
- ///
- ///
- /// A delegate handler that can be added to an events list of handlers, or called directly.
- ///
- public static Delegate GetHandlerDelegate(
- Type delegateType, object targetSubscriber, MethodInfo targetSubscriberDelegateMethod)
- {
- return Delegate.CreateDelegate(
- delegateType, targetSubscriber, targetSubscriberDelegateMethod.Name);
- }
-
- ///
- /// Queries the input type for a signature matching the input
- /// signature.
- ///
- ///
- /// Typically used to query a potential subscriber to see if they implement an event handler.
- ///
- /// to match against
- /// to query
- ///
- /// matching input
- /// signature, or if there is no match.
- ///
- public static MethodInfo GetMethodInfoMatchingSignature(
- MethodInfo invoke, Type subscriberType)
- {
- ComposedCriteria criteria = new ComposedCriteria();
- criteria.Add(new MethodReturnTypeCriteria(invoke.ReturnType));
- criteria.Add(new MethodParametersCountCriteria(invoke.GetParameters().Length));
- criteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(invoke)));
-
- MemberInfo[] methods = subscriberType.FindMembers(
- MemberTypes.Method, ReflectionUtils.AllMembersCaseInsensitiveFlags,
- new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- criteria);
- if (methods != null
- && methods.Length > 0)
- {
- return methods[0] as MethodInfo;
- }
- return null;
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the EventManipulationUtilities class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly visible constructors.
- ///
+ /// Often used to wire subscribers to event publishers.
+ ///
+ ///
+ ///
+ /// The of delegate to create.
+ ///
+ ///
+ /// The target subscriber object that contains the delegate implementation.
+ ///
+ ///
+ /// referencing the delegate method on the subscriber.
+ ///
+ ///
+ /// A delegate handler that can be added to an events list of handlers, or called directly.
+ ///
+ public static Delegate GetHandlerDelegate(
+ Type delegateType, object targetSubscriber, MethodInfo targetSubscriberDelegateMethod)
+ {
+ return Delegate.CreateDelegate(
+ delegateType, targetSubscriber, targetSubscriberDelegateMethod.Name);
+ }
+
+ ///
+ /// Queries the input type for a signature matching the input
+ /// signature.
+ ///
+ ///
+ /// Typically used to query a potential subscriber to see if they implement an event handler.
+ ///
+ /// to match against
+ /// to query
+ ///
+ /// matching input
+ /// signature, or if there is no match.
+ ///
+ public static MethodInfo GetMethodInfoMatchingSignature(
+ MethodInfo invoke, Type subscriberType)
+ {
+ ComposedCriteria criteria = new ComposedCriteria();
+ criteria.Add(new MethodReturnTypeCriteria(invoke.ReturnType));
+ criteria.Add(new MethodParametersCountCriteria(invoke.GetParameters().Length));
+ criteria.Add(new MethodParametersCriteria(ReflectionUtils.GetParameterTypes(invoke)));
+
+ MemberInfo[] methods = subscriberType.FindMembers(
+ MemberTypes.Method, ReflectionUtils.AllMembersCaseInsensitiveFlags,
+ new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ criteria);
+ if (methods != null
+ && methods.Length > 0)
+ {
+ return methods[0] as MethodInfo;
+ }
+ return null;
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the EventManipulationUtilities class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible constructors.
+ ///
- /// All object definitions will have been loaded, but no objects will have
- /// been instantiated yet. This allows for overriding or adding properties
- /// even to eager-initializing objects.
- ///
- ///
- ///
- /// In case of errors.
- ///
- public abstract void PostProcessObjectFactory(
- IConfigurableListableObjectFactory factory);
-
- ///
- /// Resolves the supplied into a
- /// instance.
- ///
- /// The object that is to be resolved into a
- /// instance.
- /// The error context source.
- /// The error context string.
- /// A resolved .
- ///
- ///
- /// This (default) implementation supports resolving
- /// s and s.
- /// Only override this method if you want to key your type alias
- /// on something other than s
- /// and s.
- ///
+ /// All object definitions will have been loaded, but no objects will have
+ /// been instantiated yet. This allows for overriding or adding properties
+ /// even to eager-initializing objects.
+ ///
+ ///
+ ///
+ /// In case of errors.
+ ///
+ public abstract void PostProcessObjectFactory(
+ IConfigurableListableObjectFactory factory);
+
+ ///
+ /// Resolves the supplied into a
+ /// instance.
+ ///
+ /// The object that is to be resolved into a
+ /// instance.
+ /// The error context source.
+ /// The error context string.
+ /// A resolved .
+ ///
+ ///
+ /// This (default) implementation supports resolving
+ /// s and s.
+ /// Only override this method if you want to key your type alias
+ /// on something other than s
+ /// and s.
+ ///
- /// Please note that changing the value of this property after
- /// this factory object instance has been created by an enclosing
- /// Spring.NET IoC container really is a programming error. This
- /// property should really only be set once, prior to the invocation
- /// of the
- ///
- /// callback method.
- ///
- ///
- ///
- public bool IsSingleton
- {
- get { return this.isSingleton; }
- set { this.isSingleton = value; }
- }
-
- ///
- /// Return the of object that this
- /// creates, or
- /// if not known in advance.
- ///
- ///
- public abstract Type ObjectType { get; }
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- /// In the event of misconfiguration (such as the failure to set a
- /// required property) or if initialization fails.
- ///
- ///
- public virtual void AfterPropertiesSet()
- {
- if (this.isSingleton && this.singletonInstance == null)
- {
- this.singletonInstance = CreateInstance();
- }
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the object
- /// managed by this factory.
- ///
- ///
- /// An instance (possibly shared or independent) of the object managed by
- /// this factory.
- ///
- ///
- public object GetObject()
- {
- if (this.isSingleton)
- {
- return this.singletonInstance;
- }
- else
- {
- return CreateInstance();
- }
- }
-
- ///
- /// Template method that subclasses must override to construct
- /// the object returned by this factory.
- ///
- ///
- /// Invoked once immediately after the initialization of this
- /// in the case of
- /// a singleton; else, on each call to the
- ///
- /// method.
- ///
- ///
- /// If an exception occured during object creation.
- ///
- ///
- /// A distinct instance of the object created by this factory.
- ///
- protected abstract object CreateInstance();
-
- ///
- /// Performs cleanup on any cached singleton object.
- ///
- ///
- ///
- /// Only makes sense in the context of a singleton object.
- ///
+ /// Please note that changing the value of this property after
+ /// this factory object instance has been created by an enclosing
+ /// Spring.NET IoC container really is a programming error. This
+ /// property should really only be set once, prior to the invocation
+ /// of the
+ ///
+ /// callback method.
+ ///
+ ///
+ ///
+ public bool IsSingleton
+ {
+ get { return this.isSingleton; }
+ set { this.isSingleton = value; }
+ }
+
+ ///
+ /// Return the of object that this
+ /// creates, or
+ /// if not known in advance.
+ ///
+ ///
+ public abstract Type ObjectType { get; }
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ /// In the event of misconfiguration (such as the failure to set a
+ /// required property) or if initialization fails.
+ ///
+ ///
+ public virtual void AfterPropertiesSet()
+ {
+ if (this.isSingleton && this.singletonInstance == null)
+ {
+ this.singletonInstance = CreateInstance();
+ }
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the object
+ /// managed by this factory.
+ ///
+ ///
+ /// An instance (possibly shared or independent) of the object managed by
+ /// this factory.
+ ///
+ ///
+ public object GetObject()
+ {
+ if (this.isSingleton)
+ {
+ return this.singletonInstance;
+ }
+ else
+ {
+ return CreateInstance();
+ }
+ }
+
+ ///
+ /// Template method that subclasses must override to construct
+ /// the object returned by this factory.
+ ///
+ ///
+ /// Invoked once immediately after the initialization of this
+ /// in the case of
+ /// a singleton; else, on each call to the
+ ///
+ /// method.
+ ///
+ ///
+ /// If an exception occured during object creation.
+ ///
+ ///
+ /// A distinct instance of the object created by this factory.
+ ///
+ protected abstract object CreateInstance();
+
+ ///
+ /// Performs cleanup on any cached singleton object.
+ ///
+ ///
+ ///
+ /// Only makes sense in the context of a singleton object.
+ ///
- /// Currently supports reading custom configuration sections and returning them as
- /// objects.
- ///
- ///
- /// Simon White
- /// Mark Pollack
- /// $Id: ConfigurationReader.cs,v 1.18 2007/08/08 17:47:13 bbaia Exp $
- public sealed class ConfigurationReader
- {
- private const string ConfigSectionTypeAttribute = "type";
- private const string ConfigurationElement = "configuration";
- private const string ConfigSectionsElement = "configSections";
- private const string ConfigSectionElement = "section";
- private const string ConfigSectionNameAttribute = "name";
-
- private static readonly ILog _log = LogManager.GetLogger(typeof (ConfigurationReader));
-
- ///
- /// Reads the specified configuration section into a
- /// .
- ///
- /// The resource to read.
- /// The section name.
- ///
- /// A newly populated
- /// .
- ///
- ///
- /// If any errors are encountered while attempting to open a stream
- /// from the supplied .
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.1 and greater of the .NET Framework) the actual XML.
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.0 of the .NET Framework).
- ///
- ///
- /// If the configuration section was otherwise invalid.
- ///
- public static NameValueCollection Read(IResource resource, string configSection)
- {
- return ConfigurationReader.Read(resource, configSection, new NameValueCollection());
- }
-
- ///
- /// Reads the specified configuration section into the supplied
- /// .
- ///
- /// The resource to read.
- /// The section name.
- ///
- /// The collection that is to be populated. May be
- /// .
- ///
- ///
- /// A newly populated
- /// .
- ///
- ///
- /// If any errors are encountered while attempting to open a stream
- /// from the supplied .
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.1 and greater of the .NET Framework) the actual XML.
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.0 of the .NET Framework).
- ///
- ///
- /// If the configuration section was otherwise invalid.
- ///
- public static NameValueCollection Read(
- IResource resource, string configSection, NameValueCollection properties)
- {
- return ConfigurationReader.Read(resource, configSection, properties, true);
- }
-
- ///
- /// Reads the specified configuration section into the supplied
- /// .
- ///
- /// The resource to read.
- /// The section name.
- ///
- /// The collection that is to be populated. May be
- /// .
- ///
- ///
- /// If a key already exists, is its value to be appended to the current
- /// value or replaced?
- ///
- ///
- /// The populated
- /// .
- ///
- ///
- /// If any errors are encountered while attempting to open a stream
- /// from the supplied .
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.1 and greater of the .NET Framework) the actual XML.
- ///
- ///
- /// If any errors are encountered while loading or reading (this only applies to
- /// v1.0 of the .NET Framework).
- ///
- ///
- /// If the configuration section was otherwise invalid.
- ///
- public static NameValueCollection Read(
- IResource resource, string configSection, NameValueCollection properties, bool overrideValues)
- {
- if (properties == null)
- {
- properties = new NameValueCollection();
- }
- Stream stream = null;
- try
- {
- XmlDocument doc = new XmlDocument();
- stream = resource.InputStream;
- doc.Load(stream);
- NameValueCollection newProperties = ReadFromXmlDocument(doc, configSection);
- if(newProperties != null)
- {
- PopulateProperties(overrideValues, properties, newProperties);
- }
- }
- finally
- {
- if (stream != null)
- {
- try
- {
- stream.Close();
- }
- catch (IOException ex)
- {
- #region Instrumentation
-
- if (_log.IsWarnEnabled)
- {
- _log.Warn("Could not close stream from resource " + resource.Description, ex);
- }
-
- #endregion
- }
- }
- }
- return properties;
- }
-
- ///
- /// Read from the specified configuration from the supplied XML
- /// into a
- /// .
- ///
- ///
- ///
- /// Does not support section grouping. The supplied XML
- /// must already be loaded.
- ///
- ///
- ///
- /// The to read from.
- ///
- ///
- /// The configuration section name to read.
- ///
- ///
- /// A newly populated
- /// .
- ///
- ///
- /// If any errors are encountered while reading (this only applies to
- /// v1.1 and greater of the .NET Framework).
- ///
- ///
- /// If any errors are encountered while reading (this only applies to
- /// v1.0 of the .NET Framework).
- ///
- ///
- /// If the configuration section was otherwise invalid.
- ///
- public static NameValueCollection ReadFromXmlDocument(XmlDocument document,
- string configSectionName)
- {
- // find the config section declaration (if one exists)...
- XmlNode xmlConfig = document.SelectSingleNode(
- string.Format("//{0}//{1}//{2}[@{3}='{4}']",
- ConfigurationElement, ConfigSectionsElement,
- ConfigSectionElement, ConfigSectionNameAttribute, configSectionName));
-
- // create appropriate configuration section handler...
- NameValueSectionHandler handler = null;
- if (xmlConfig == null)
- {
- // none specified, so use the default...
- handler = new NameValueSectionHandler();
- }
- else
- {
- XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute];
- Type cshType = TypeResolutionUtils.ResolveType(xmlConfigType.Value);
- object o = ObjectUtils.InstantiateType(cshType);
- handler = o as NameValueSectionHandler;
- if (handler == null)
- {
- throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' not of type NameValueCollection.");
- }
-
- }
- XmlNode collectionNode = document.SelectSingleNode(
- string.Format("//{0}//{1}", ConfigurationElement, configSectionName));
- if (collectionNode == null)
- {
- throw ConfigurationUtils.CreateConfigurationException("Cannot read properties; config section '" + configSectionName + "' not found.");
- }
- else
- {
- return (NameValueCollection) handler.Create(null, null, collectionNode);
- }
- }
-
- ///
- /// Populates the supplied with values from
- /// a .NET application configuration file.
- ///
- ///
- /// The
- /// to add any key-value pairs to.
- ///
- ///
- /// The configuration section name in the a .NET application configuration
- /// file.
- ///
- ///
- /// If a key already exists, is its value to be appended to the current
- /// value or replaced?
- ///
- ///
- /// if the supplied
- /// was found.
- ///
- public static bool PopulateFromAppConfig(
- NameValueCollection properties, string configSectionName, bool overrideValues)
- {
- bool sectionFound = false;
-
- NameValueCollection newProperties
- = ConfigurationUtils.GetSection(configSectionName) as NameValueCollection;
-
- if (newProperties != null)
- {
- sectionFound = true;
- PopulateProperties(overrideValues, properties, newProperties);
- }
- return sectionFound;
- }
-
- private static void PopulateProperties(
- bool overrideValues, NameValueCollection properties, NameValueCollection newProperties)
- {
- if (!overrideValues)
- {
- properties.Add(newProperties);
- }
- else
- {
- foreach (string key in newProperties.AllKeys)
- {
- properties.Set(key, newProperties.Get(key));
- }
- }
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the ConfigurationReader class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly visible
- /// constructors.
- ///
+ /// Currently supports reading custom configuration sections and returning them as
+ /// objects.
+ ///
+ ///
+ /// Simon White
+ /// Mark Pollack
+ public sealed class ConfigurationReader
+ {
+ private const string ConfigSectionTypeAttribute = "type";
+ private const string ConfigurationElement = "configuration";
+ private const string ConfigSectionsElement = "configSections";
+ private const string ConfigSectionElement = "section";
+ private const string ConfigSectionNameAttribute = "name";
+
+ private static readonly ILog _log = LogManager.GetLogger(typeof (ConfigurationReader));
+
+ ///
+ /// Reads the specified configuration section into a
+ /// .
+ ///
+ /// The resource to read.
+ /// The section name.
+ ///
+ /// A newly populated
+ /// .
+ ///
+ ///
+ /// If any errors are encountered while attempting to open a stream
+ /// from the supplied .
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.1 and greater of the .NET Framework) the actual XML.
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.0 of the .NET Framework).
+ ///
+ ///
+ /// If the configuration section was otherwise invalid.
+ ///
+ public static NameValueCollection Read(IResource resource, string configSection)
+ {
+ return ConfigurationReader.Read(resource, configSection, new NameValueCollection());
+ }
+
+ ///
+ /// Reads the specified configuration section into the supplied
+ /// .
+ ///
+ /// The resource to read.
+ /// The section name.
+ ///
+ /// The collection that is to be populated. May be
+ /// .
+ ///
+ ///
+ /// A newly populated
+ /// .
+ ///
+ ///
+ /// If any errors are encountered while attempting to open a stream
+ /// from the supplied .
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.1 and greater of the .NET Framework) the actual XML.
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.0 of the .NET Framework).
+ ///
+ ///
+ /// If the configuration section was otherwise invalid.
+ ///
+ public static NameValueCollection Read(
+ IResource resource, string configSection, NameValueCollection properties)
+ {
+ return ConfigurationReader.Read(resource, configSection, properties, true);
+ }
+
+ ///
+ /// Reads the specified configuration section into the supplied
+ /// .
+ ///
+ /// The resource to read.
+ /// The section name.
+ ///
+ /// The collection that is to be populated. May be
+ /// .
+ ///
+ ///
+ /// If a key already exists, is its value to be appended to the current
+ /// value or replaced?
+ ///
+ ///
+ /// The populated
+ /// .
+ ///
+ ///
+ /// If any errors are encountered while attempting to open a stream
+ /// from the supplied .
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.1 and greater of the .NET Framework) the actual XML.
+ ///
+ ///
+ /// If any errors are encountered while loading or reading (this only applies to
+ /// v1.0 of the .NET Framework).
+ ///
+ ///
+ /// If the configuration section was otherwise invalid.
+ ///
+ public static NameValueCollection Read(
+ IResource resource, string configSection, NameValueCollection properties, bool overrideValues)
+ {
+ if (properties == null)
+ {
+ properties = new NameValueCollection();
+ }
+ Stream stream = null;
+ try
+ {
+ XmlDocument doc = new XmlDocument();
+ stream = resource.InputStream;
+ doc.Load(stream);
+ NameValueCollection newProperties = ReadFromXmlDocument(doc, configSection);
+ if(newProperties != null)
+ {
+ PopulateProperties(overrideValues, properties, newProperties);
+ }
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ try
+ {
+ stream.Close();
+ }
+ catch (IOException ex)
+ {
+ #region Instrumentation
+
+ if (_log.IsWarnEnabled)
+ {
+ _log.Warn("Could not close stream from resource " + resource.Description, ex);
+ }
+
+ #endregion
+ }
+ }
+ }
+ return properties;
+ }
+
+ ///
+ /// Read from the specified configuration from the supplied XML
+ /// into a
+ /// .
+ ///
+ ///
+ ///
+ /// Does not support section grouping. The supplied XML
+ /// must already be loaded.
+ ///
+ ///
+ ///
+ /// The to read from.
+ ///
+ ///
+ /// The configuration section name to read.
+ ///
+ ///
+ /// A newly populated
+ /// .
+ ///
+ ///
+ /// If any errors are encountered while reading (this only applies to
+ /// v1.1 and greater of the .NET Framework).
+ ///
+ ///
+ /// If any errors are encountered while reading (this only applies to
+ /// v1.0 of the .NET Framework).
+ ///
+ ///
+ /// If the configuration section was otherwise invalid.
+ ///
+ public static NameValueCollection ReadFromXmlDocument(XmlDocument document,
+ string configSectionName)
+ {
+ // find the config section declaration (if one exists)...
+ XmlNode xmlConfig = document.SelectSingleNode(
+ string.Format("//{0}//{1}//{2}[@{3}='{4}']",
+ ConfigurationElement, ConfigSectionsElement,
+ ConfigSectionElement, ConfigSectionNameAttribute, configSectionName));
+
+ // create appropriate configuration section handler...
+ NameValueSectionHandler handler = null;
+ if (xmlConfig == null)
+ {
+ // none specified, so use the default...
+ handler = new NameValueSectionHandler();
+ }
+ else
+ {
+ XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute];
+ Type cshType = TypeResolutionUtils.ResolveType(xmlConfigType.Value);
+ object o = ObjectUtils.InstantiateType(cshType);
+ handler = o as NameValueSectionHandler;
+ if (handler == null)
+ {
+ throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' not of type NameValueCollection.");
+ }
+
+ }
+ XmlNode collectionNode = document.SelectSingleNode(
+ string.Format("//{0}//{1}", ConfigurationElement, configSectionName));
+ if (collectionNode == null)
+ {
+ throw ConfigurationUtils.CreateConfigurationException("Cannot read properties; config section '" + configSectionName + "' not found.");
+ }
+ else
+ {
+ return (NameValueCollection) handler.Create(null, null, collectionNode);
+ }
+ }
+
+ ///
+ /// Populates the supplied with values from
+ /// a .NET application configuration file.
+ ///
+ ///
+ /// The
+ /// to add any key-value pairs to.
+ ///
+ ///
+ /// The configuration section name in the a .NET application configuration
+ /// file.
+ ///
+ ///
+ /// If a key already exists, is its value to be appended to the current
+ /// value or replaced?
+ ///
+ ///
+ /// if the supplied
+ /// was found.
+ ///
+ public static bool PopulateFromAppConfig(
+ NameValueCollection properties, string configSectionName, bool overrideValues)
+ {
+ bool sectionFound = false;
+
+ NameValueCollection newProperties
+ = ConfigurationUtils.GetSection(configSectionName) as NameValueCollection;
+
+ if (newProperties != null)
+ {
+ sectionFound = true;
+ PopulateProperties(overrideValues, properties, newProperties);
+ }
+ return sectionFound;
+ }
+
+ private static void PopulateProperties(
+ bool overrideValues, NameValueCollection properties, NameValueCollection newProperties)
+ {
+ if (!overrideValues)
+ {
+ properties.Add(newProperties);
+ }
+ else
+ {
+ foreach (string key in newProperties.AllKeys)
+ {
+ properties.Set(key, newProperties.Get(key));
+ }
+ }
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the ConfigurationReader class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible
+ /// constructors.
+ ///
- /// When the <connectionStrings> configuration section is processed by this class,
- /// two variables are defined for each connection string: one for connection string and
- /// the second one for the provider name.
- ///
- /// Variable names are generated by appending '.connectionString' and '.providerName'
- /// literals to the value of the name attribute of the connection string element.
- /// For example:
- ///
- ///
- ///
- ///
- ///
- ///
- /// will result in two variables being created: myConn.connectionString and myConn.providerName.
- /// You can reference these variables within your object definitions, just like any other variable.
+ /// When the <connectionStrings> configuration section is processed by this class,
+ /// two variables are defined for each connection string: one for connection string and
+ /// the second one for the provider name.
+ ///
+ /// Variable names are generated by appending '.connectionString' and '.providerName'
+ /// literals to the value of the name attribute of the connection string element.
+ /// For example:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// will result in two variables being created: myConn.connectionString and myConn.providerName.
+ /// You can reference these variables within your object definitions, just like any other variable.
- /// Supports values for a specific index or parameter name (case
- /// insensitive) in the constructor argument list, and generic matches by
- /// .
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: ConstructorArgumentValues.cs,v 1.16 2008/03/03 09:29:07 bbaia Exp $
- ///
- [Serializable]
- public class ConstructorArgumentValues
- {
- ///
- /// Can be used as an argument filler for the
- ///
- /// overload when one is not looking for an argument by index.
- ///
- public const int NoIndex = -1289; // yes, the number really is wholly arbitrary...
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- public ConstructorArgumentValues()
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The
- /// to be used to populate this instance.
- ///
- public ConstructorArgumentValues(ConstructorArgumentValues other)
- {
- AddAll(other);
- }
-
- #endregion
-
- #region Fields
-
- private CultureInfo enUSCultureInfo = new CultureInfo("en-US", false);
- private IDictionary _indexedArgumentValues = new Hashtable();
- private IList _genericArgumentValues = new LinkedList();
- private IDictionary _namedArgumentValues = new Hashtable();
-
- #endregion
-
- #region Properties
-
- ///
- /// Return the map of indexed argument values.
- ///
- ///
- /// An with
- /// indices as keys and
- /// s
- /// as values.
- ///
- public virtual IDictionary IndexedArgumentValues
- {
- get { return _indexedArgumentValues; }
- }
-
- ///
- /// Return the map of named argument values.
- ///
- ///
- /// An with
- /// named arguments as keys and
- /// s
- /// as values.
- ///
- public virtual IDictionary NamedArgumentValues
- {
- get { return _namedArgumentValues; }
- }
-
- ///
- /// Return the set of generic argument values.
- ///
- ///
- /// A of
- /// s.
- ///
- public virtual IList GenericArgumentValues
- {
- get { return _genericArgumentValues; }
-
- }
-
- ///
- /// Return the number of arguments held in this instance.
- ///
- public virtual int ArgumentCount
- {
- get
- {
- return IndexedArgumentValues.Count
- + GenericArgumentValues.Count
- + NamedArgumentValues.Count;
- }
-
- }
-
- ///
- /// Returns true if this holder does not contain any argument values,
- /// neither indexed ones nor generic ones.
- ///
- public virtual bool Empty
- {
- get
- {
- return IndexedArgumentValues.Count == 0
- && GenericArgumentValues.Count == 0
- && NamedArgumentValues.Count == 0;
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Copy all given argument values into this object.
- ///
- ///
- /// The
- /// to be used to populate this instance.
- ///
- public void AddAll(ConstructorArgumentValues other)
- {
- if (other != null)
- {
- foreach (object o in other.GenericArgumentValues)
- {
- GenericArgumentValues.Add(o);
- }
- foreach (DictionaryEntry entry in other.IndexedArgumentValues)
- {
- IndexedArgumentValues.Add(entry.Key, entry.Value);
- }
- foreach (DictionaryEntry entry in other.NamedArgumentValues)
- {
- NamedArgumentValues.Add(entry.Key, entry.Value);
- }
- }
- }
-
- ///
- /// Add argument value for the given index in the constructor argument list.
- ///
- ///
- /// The index in the constructor argument list.
- ///
- ///
- /// The argument value.
- ///
- public virtual void AddIndexedArgumentValue(int index, object value)
- {
- IndexedArgumentValues[index] = new ValueHolder(value);
- }
-
- ///
- /// Add argument value for the given index in the constructor argument list.
- ///
- /// The index in the constructor argument list.
- /// The argument value.
- ///
- /// The of the argument
- /// .
- ///
- public virtual void AddIndexedArgumentValue(int index, object value, string type)
- {
- IndexedArgumentValues[index] = new ValueHolder(value, type);
- }
-
- ///
- /// Add argument value for the given name in the constructor argument list.
- ///
- /// The name in the constructor argument list.
- /// The argument value.
- ///
- /// If the supplied is
- /// or is composed wholly of whitespace.
- ///
- public virtual void AddNamedArgumentValue(string name, object value)
- {
- AssertUtils.ArgumentHasText(name, "name");
- NamedArgumentValues[GetCanonicalNamedArgument(name)] = new ValueHolder(value);
- }
-
- ///
- /// Get argument value for the given index in the constructor argument list.
- ///
- /// The index in the constructor argument list.
- ///
- /// The required of the argument.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none set.
- ///
- public virtual ValueHolder GetIndexedArgumentValue(int index, Type requiredType)
- {
- ValueHolder valueHolder = (ValueHolder) IndexedArgumentValues[index];
- if (valueHolder != null)
- {
- if (valueHolder.Type == null
- || requiredType.FullName.Equals(valueHolder.Type)
- || requiredType.AssemblyQualifiedName.Equals(valueHolder.Type))
- {
- return valueHolder;
- }
- }
- return null;
- }
-
- ///
- /// Get argument value for the given name in the constructor argument list.
- ///
- /// The name in the constructor argument list.
- ///
- /// The
- ///
- /// for the argument, or if none set.
- ///
- public virtual ValueHolder GetNamedArgumentValue(string name)
- {
- ValueHolder valueHolder = null;
- if (name != null && ContainsNamedArgument(name))
- {
- valueHolder = (ValueHolder)NamedArgumentValues[GetCanonicalNamedArgument(name)];
- }
- return valueHolder;
- }
-
- ///
- /// Does this set of constructor arguments contain a named argument matching the
- /// supplied name?
- ///
- ///
- ///
- /// The comparison is performed in a case-insensitive fashion.
- ///
- ///
- /// The named argument to look up.
- ///
- /// if this set of constructor arguments
- /// contains a named argument matching the supplied
- /// name.
- ///
- public bool ContainsNamedArgument(string argument)
- {
- return NamedArgumentValues.Contains(GetCanonicalNamedArgument(argument));
- }
-
- ///
- /// Add generic argument value to be matched by type.
- ///
- ///
- /// The argument value.
- ///
- public virtual void AddGenericArgumentValue(object value)
- {
- GenericArgumentValues.Add(new ValueHolder(value));
- }
-
- ///
- /// Add generic argument value to be matched by type.
- ///
- /// The argument value.
- ///
- /// The of the argument
- /// .
- ///
- public virtual void AddGenericArgumentValue(object value, string type)
- {
- GenericArgumentValues.Add(new ValueHolder(value, type));
- }
-
- ///
- /// Look for a generic argument value that matches the given
- /// .
- ///
- ///
- /// The to match.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none set.
- ///
- public virtual ValueHolder GetGenericArgumentValue(Type requiredType)
- {
- return GetGenericArgumentValue(requiredType, null);
- }
-
- ///
- /// Look for a generic argument value that matches the given
- /// .
- ///
- ///
- /// The to match.
- ///
- ///
- /// A of
- ///
- /// objects that have already been used in the current resolution
- /// process and should therefore not be returned again; this allows one
- /// to return the next generic argument match in the case of multiple
- /// generic argument values of the same type.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none set.
- ///
- public virtual ValueHolder GetGenericArgumentValue(
- Type requiredType, ISet usedValues)
- {
- foreach (ValueHolder valueHolder in GenericArgumentValues)
- {
- if (usedValues == null || !usedValues.Contains(valueHolder))
- {
- if (requiredType != null)
- {
- if (StringUtils.HasText(valueHolder.Type))
- {
- if (valueHolder.Type.Equals(requiredType.FullName)
- || valueHolder.Type.Equals(requiredType.AssemblyQualifiedName))
- {
- return valueHolder;
- }
- }
- else if (requiredType.IsInstanceOfType(valueHolder.Value)
- || (requiredType.IsArray
- && typeof (IList).IsInstanceOfType(valueHolder.Value)))
- {
- return valueHolder;
- }
- }
- // if the value holder is (pretty much) untyped, that's ok to return...
- else if (StringUtils.IsNullOrEmpty(valueHolder.Type))
- {
- return valueHolder;
- }
- }
- }
- return null;
- }
-
- ///
- /// Look for an argument value that either corresponds to the given index
- /// in the constructor argument list or generically matches by
- /// .
- ///
- ///
- /// The index in the constructor argument list.
- ///
- ///
- /// The to match.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none is set.
- ///
- public virtual ValueHolder GetArgumentValue(int index, Type requiredType)
- {
- return GetArgumentValue(index, string.Empty, requiredType, null);
- }
-
- ///
- /// Look for an argument value that either corresponds to the given index
- /// in the constructor argument list or generically matches by
- /// .
- ///
- ///
- /// The index in the constructor argument list.
- ///
- ///
- /// The to match.
- ///
- ///
- /// A of
- ///
- /// objects that have already been used in the current resolution
- /// process and should therefore not be returned again; this allows one
- /// to return the next generic argument match in the case of multiple
- /// generic argument values of the same type.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none is set.
- ///
- public virtual ValueHolder GetArgumentValue(int index, Type requiredType, ISet usedValues)
- {
- return GetArgumentValue(index, string.Empty, requiredType, usedValues);
- }
-
- ///
- /// Look for an argument value that either corresponds to the given index
- /// in the constructor argument list or generically matches by
- /// .
- ///
- ///
- /// The name of the argument in the constructor argument list. May be
- /// , in which case generic matching by
- /// is assumed.
- ///
- ///
- /// The to match.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none is set.
- ///
- public virtual ValueHolder GetArgumentValue(string name, Type requiredType)
- {
- return GetArgumentValue(NoIndex, name, requiredType, null);
- }
-
- ///
- /// Look for an argument value that either corresponds to the given index
- /// in the constructor argument list or generically matches by
- /// .
- ///
- ///
- /// The name of the argument in the constructor argument list. May be
- /// , in which case generic matching by
- /// is assumed.
- ///
- ///
- /// The to match.
- ///
- ///
- /// A of
- ///
- /// objects that have already been used in the current resolution
- /// process and should therefore not be returned again; this allows one
- /// to return the next generic argument match in the case of multiple
- /// generic argument values of the same type.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none is set.
- ///
- public virtual ValueHolder GetArgumentValue(
- string name, Type requiredType, ISet usedValues)
- {
- return GetArgumentValue(NoIndex, name, requiredType, usedValues);
- }
-
- ///
- /// Look for an argument value that either corresponds to the given index
- /// in the constructor argument list, or to the named argument, or
- /// generically matches by .
- ///
- ///
- /// The index of the argument in the constructor argument list. May be
- /// negative, to denote the fact that we are not looking for an
- /// argument by index (see
- /// .
- ///
- ///
- /// The name of the argument in the constructor argument list. May be
- /// .
- ///
- ///
- /// The to match.
- ///
- ///
- /// A of
- ///
- /// objects that have already been used in the current resolution
- /// process and should therefore not be returned again; this allows one
- /// to return the next generic argument match in the case of multiple
- /// generic argument values of the same type.
- ///
- ///
- /// The
- ///
- /// for the argument, or if none is set.
- ///
- public virtual ValueHolder GetArgumentValue(
- int index, string name, Type requiredType, ISet usedValues)
- {
- ValueHolder valueHolder = null;
- if(index != NoIndex)
- {
- valueHolder = GetIndexedArgumentValue(index, requiredType);
- }
- if (valueHolder == null)
- {
- valueHolder = GetNamedArgumentValue(name);
- if (valueHolder == null)
- {
- valueHolder = GetGenericArgumentValue(requiredType, usedValues);
- }
- }
- return valueHolder;
- }
-
- private string GetCanonicalNamedArgument(string argument)
- {
- return argument != null ? argument.ToLower(enUSCultureInfo) : argument;
- }
-
- #endregion
-
- #region Inner Class : ValueHolder
-
- ///
- /// Holder for a constructor argument value, with an optional
- /// attribute indicating the target
- /// of the actual constructor argument.
- ///
- [Serializable]
- public class ValueHolder
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the ValueHolder class.
- ///
- ///
- /// The value of the constructor argument.
- ///
- internal ValueHolder(object value)
- {
- Value = value;
- }
-
- ///
- /// Creates a new instance of the ValueHolder class.
- ///
- ///
- /// The value of the constructor argument.
- ///
- ///
- /// The of the argument
- /// . Can also be one of the common
- /// aliases (int, bool,
- /// float, etc).
- ///
- internal ValueHolder(object value, string typeName)
- {
- Value = value;
- this.typeName = typeName;
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// A that represents the current
- /// .
- ///
- ///
- /// A that represents the current
- /// .
- ///
- public override string ToString()
- {
- return string.Format(CultureInfo.InvariantCulture,
- "'{0}' [{1}]", Value, Type);
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets and sets the value for the constructor argument.
- ///
- ///
- ///
- /// Only necessary for manipulating a registered value, for example in
- /// s.
- ///
+ /// Supports values for a specific index or parameter name (case
+ /// insensitive) in the constructor argument list, and generic matches by
+ /// .
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class ConstructorArgumentValues
+ {
+ ///
+ /// Can be used as an argument filler for the
+ ///
+ /// overload when one is not looking for an argument by index.
+ ///
+ public const int NoIndex = -1289; // yes, the number really is wholly arbitrary...
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ public ConstructorArgumentValues()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The
+ /// to be used to populate this instance.
+ ///
+ public ConstructorArgumentValues(ConstructorArgumentValues other)
+ {
+ AddAll(other);
+ }
+
+ #endregion
+
+ #region Fields
+
+ private CultureInfo enUSCultureInfo = new CultureInfo("en-US", false);
+ private IDictionary _indexedArgumentValues = new Hashtable();
+ private IList _genericArgumentValues = new LinkedList();
+ private IDictionary _namedArgumentValues = new Hashtable();
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Return the map of indexed argument values.
+ ///
+ ///
+ /// An with
+ /// indices as keys and
+ /// s
+ /// as values.
+ ///
+ public virtual IDictionary IndexedArgumentValues
+ {
+ get { return _indexedArgumentValues; }
+ }
+
+ ///
+ /// Return the map of named argument values.
+ ///
+ ///
+ /// An with
+ /// named arguments as keys and
+ /// s
+ /// as values.
+ ///
+ public virtual IDictionary NamedArgumentValues
+ {
+ get { return _namedArgumentValues; }
+ }
+
+ ///
+ /// Return the set of generic argument values.
+ ///
+ ///
+ /// A of
+ /// s.
+ ///
+ public virtual IList GenericArgumentValues
+ {
+ get { return _genericArgumentValues; }
+
+ }
+
+ ///
+ /// Return the number of arguments held in this instance.
+ ///
+ public virtual int ArgumentCount
+ {
+ get
+ {
+ return IndexedArgumentValues.Count
+ + GenericArgumentValues.Count
+ + NamedArgumentValues.Count;
+ }
+
+ }
+
+ ///
+ /// Returns true if this holder does not contain any argument values,
+ /// neither indexed ones nor generic ones.
+ ///
+ public virtual bool Empty
+ {
+ get
+ {
+ return IndexedArgumentValues.Count == 0
+ && GenericArgumentValues.Count == 0
+ && NamedArgumentValues.Count == 0;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Copy all given argument values into this object.
+ ///
+ ///
+ /// The
+ /// to be used to populate this instance.
+ ///
+ public void AddAll(ConstructorArgumentValues other)
+ {
+ if (other != null)
+ {
+ foreach (object o in other.GenericArgumentValues)
+ {
+ GenericArgumentValues.Add(o);
+ }
+ foreach (DictionaryEntry entry in other.IndexedArgumentValues)
+ {
+ IndexedArgumentValues.Add(entry.Key, entry.Value);
+ }
+ foreach (DictionaryEntry entry in other.NamedArgumentValues)
+ {
+ NamedArgumentValues.Add(entry.Key, entry.Value);
+ }
+ }
+ }
+
+ ///
+ /// Add argument value for the given index in the constructor argument list.
+ ///
+ ///
+ /// The index in the constructor argument list.
+ ///
+ ///
+ /// The argument value.
+ ///
+ public virtual void AddIndexedArgumentValue(int index, object value)
+ {
+ IndexedArgumentValues[index] = new ValueHolder(value);
+ }
+
+ ///
+ /// Add argument value for the given index in the constructor argument list.
+ ///
+ /// The index in the constructor argument list.
+ /// The argument value.
+ ///
+ /// The of the argument
+ /// .
+ ///
+ public virtual void AddIndexedArgumentValue(int index, object value, string type)
+ {
+ IndexedArgumentValues[index] = new ValueHolder(value, type);
+ }
+
+ ///
+ /// Add argument value for the given name in the constructor argument list.
+ ///
+ /// The name in the constructor argument list.
+ /// The argument value.
+ ///
+ /// If the supplied is
+ /// or is composed wholly of whitespace.
+ ///
+ public virtual void AddNamedArgumentValue(string name, object value)
+ {
+ AssertUtils.ArgumentHasText(name, "name");
+ NamedArgumentValues[GetCanonicalNamedArgument(name)] = new ValueHolder(value);
+ }
+
+ ///
+ /// Get argument value for the given index in the constructor argument list.
+ ///
+ /// The index in the constructor argument list.
+ ///
+ /// The required of the argument.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none set.
+ ///
+ public virtual ValueHolder GetIndexedArgumentValue(int index, Type requiredType)
+ {
+ ValueHolder valueHolder = (ValueHolder) IndexedArgumentValues[index];
+ if (valueHolder != null)
+ {
+ if (valueHolder.Type == null
+ || requiredType.FullName.Equals(valueHolder.Type)
+ || requiredType.AssemblyQualifiedName.Equals(valueHolder.Type))
+ {
+ return valueHolder;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Get argument value for the given name in the constructor argument list.
+ ///
+ /// The name in the constructor argument list.
+ ///
+ /// The
+ ///
+ /// for the argument, or if none set.
+ ///
+ public virtual ValueHolder GetNamedArgumentValue(string name)
+ {
+ ValueHolder valueHolder = null;
+ if (name != null && ContainsNamedArgument(name))
+ {
+ valueHolder = (ValueHolder)NamedArgumentValues[GetCanonicalNamedArgument(name)];
+ }
+ return valueHolder;
+ }
+
+ ///
+ /// Does this set of constructor arguments contain a named argument matching the
+ /// supplied name?
+ ///
+ ///
+ ///
+ /// The comparison is performed in a case-insensitive fashion.
+ ///
+ ///
+ /// The named argument to look up.
+ ///
+ /// if this set of constructor arguments
+ /// contains a named argument matching the supplied
+ /// name.
+ ///
+ public bool ContainsNamedArgument(string argument)
+ {
+ return NamedArgumentValues.Contains(GetCanonicalNamedArgument(argument));
+ }
+
+ ///
+ /// Add generic argument value to be matched by type.
+ ///
+ ///
+ /// The argument value.
+ ///
+ public virtual void AddGenericArgumentValue(object value)
+ {
+ GenericArgumentValues.Add(new ValueHolder(value));
+ }
+
+ ///
+ /// Add generic argument value to be matched by type.
+ ///
+ /// The argument value.
+ ///
+ /// The of the argument
+ /// .
+ ///
+ public virtual void AddGenericArgumentValue(object value, string type)
+ {
+ GenericArgumentValues.Add(new ValueHolder(value, type));
+ }
+
+ ///
+ /// Look for a generic argument value that matches the given
+ /// .
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none set.
+ ///
+ public virtual ValueHolder GetGenericArgumentValue(Type requiredType)
+ {
+ return GetGenericArgumentValue(requiredType, null);
+ }
+
+ ///
+ /// Look for a generic argument value that matches the given
+ /// .
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// A of
+ ///
+ /// objects that have already been used in the current resolution
+ /// process and should therefore not be returned again; this allows one
+ /// to return the next generic argument match in the case of multiple
+ /// generic argument values of the same type.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none set.
+ ///
+ public virtual ValueHolder GetGenericArgumentValue(
+ Type requiredType, ISet usedValues)
+ {
+ foreach (ValueHolder valueHolder in GenericArgumentValues)
+ {
+ if (usedValues == null || !usedValues.Contains(valueHolder))
+ {
+ if (requiredType != null)
+ {
+ if (StringUtils.HasText(valueHolder.Type))
+ {
+ if (valueHolder.Type.Equals(requiredType.FullName)
+ || valueHolder.Type.Equals(requiredType.AssemblyQualifiedName))
+ {
+ return valueHolder;
+ }
+ }
+ else if (requiredType.IsInstanceOfType(valueHolder.Value)
+ || (requiredType.IsArray
+ && typeof (IList).IsInstanceOfType(valueHolder.Value)))
+ {
+ return valueHolder;
+ }
+ }
+ // if the value holder is (pretty much) untyped, that's ok to return...
+ else if (StringUtils.IsNullOrEmpty(valueHolder.Type))
+ {
+ return valueHolder;
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Look for an argument value that either corresponds to the given index
+ /// in the constructor argument list or generically matches by
+ /// .
+ ///
+ ///
+ /// The index in the constructor argument list.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none is set.
+ ///
+ public virtual ValueHolder GetArgumentValue(int index, Type requiredType)
+ {
+ return GetArgumentValue(index, string.Empty, requiredType, null);
+ }
+
+ ///
+ /// Look for an argument value that either corresponds to the given index
+ /// in the constructor argument list or generically matches by
+ /// .
+ ///
+ ///
+ /// The index in the constructor argument list.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// A of
+ ///
+ /// objects that have already been used in the current resolution
+ /// process and should therefore not be returned again; this allows one
+ /// to return the next generic argument match in the case of multiple
+ /// generic argument values of the same type.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none is set.
+ ///
+ public virtual ValueHolder GetArgumentValue(int index, Type requiredType, ISet usedValues)
+ {
+ return GetArgumentValue(index, string.Empty, requiredType, usedValues);
+ }
+
+ ///
+ /// Look for an argument value that either corresponds to the given index
+ /// in the constructor argument list or generically matches by
+ /// .
+ ///
+ ///
+ /// The name of the argument in the constructor argument list. May be
+ /// , in which case generic matching by
+ /// is assumed.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none is set.
+ ///
+ public virtual ValueHolder GetArgumentValue(string name, Type requiredType)
+ {
+ return GetArgumentValue(NoIndex, name, requiredType, null);
+ }
+
+ ///
+ /// Look for an argument value that either corresponds to the given index
+ /// in the constructor argument list or generically matches by
+ /// .
+ ///
+ ///
+ /// The name of the argument in the constructor argument list. May be
+ /// , in which case generic matching by
+ /// is assumed.
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// A of
+ ///
+ /// objects that have already been used in the current resolution
+ /// process and should therefore not be returned again; this allows one
+ /// to return the next generic argument match in the case of multiple
+ /// generic argument values of the same type.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none is set.
+ ///
+ public virtual ValueHolder GetArgumentValue(
+ string name, Type requiredType, ISet usedValues)
+ {
+ return GetArgumentValue(NoIndex, name, requiredType, usedValues);
+ }
+
+ ///
+ /// Look for an argument value that either corresponds to the given index
+ /// in the constructor argument list, or to the named argument, or
+ /// generically matches by .
+ ///
+ ///
+ /// The index of the argument in the constructor argument list. May be
+ /// negative, to denote the fact that we are not looking for an
+ /// argument by index (see
+ /// .
+ ///
+ ///
+ /// The name of the argument in the constructor argument list. May be
+ /// .
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// A of
+ ///
+ /// objects that have already been used in the current resolution
+ /// process and should therefore not be returned again; this allows one
+ /// to return the next generic argument match in the case of multiple
+ /// generic argument values of the same type.
+ ///
+ ///
+ /// The
+ ///
+ /// for the argument, or if none is set.
+ ///
+ public virtual ValueHolder GetArgumentValue(
+ int index, string name, Type requiredType, ISet usedValues)
+ {
+ ValueHolder valueHolder = null;
+ if(index != NoIndex)
+ {
+ valueHolder = GetIndexedArgumentValue(index, requiredType);
+ }
+ if (valueHolder == null)
+ {
+ valueHolder = GetNamedArgumentValue(name);
+ if (valueHolder == null)
+ {
+ valueHolder = GetGenericArgumentValue(requiredType, usedValues);
+ }
+ }
+ return valueHolder;
+ }
+
+ private string GetCanonicalNamedArgument(string argument)
+ {
+ return argument != null ? argument.ToLower(enUSCultureInfo) : argument;
+ }
+
+ #endregion
+
+ #region Inner Class : ValueHolder
+
+ ///
+ /// Holder for a constructor argument value, with an optional
+ /// attribute indicating the target
+ /// of the actual constructor argument.
+ ///
+ [Serializable]
+ public class ValueHolder
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the ValueHolder class.
+ ///
+ ///
+ /// The value of the constructor argument.
+ ///
+ internal ValueHolder(object value)
+ {
+ Value = value;
+ }
+
+ ///
+ /// Creates a new instance of the ValueHolder class.
+ ///
+ ///
+ /// The value of the constructor argument.
+ ///
+ ///
+ /// The of the argument
+ /// . Can also be one of the common
+ /// aliases (int, bool,
+ /// float, etc).
+ ///
+ internal ValueHolder(object value, string typeName)
+ {
+ Value = value;
+ this.typeName = typeName;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// A that represents the current
+ /// .
+ ///
+ ///
+ /// A that represents the current
+ /// .
+ ///
+ public override string ToString()
+ {
+ return string.Format(CultureInfo.InvariantCulture,
+ "'{0}' [{1}]", Value, Type);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets and sets the value for the constructor argument.
+ ///
+ ///
+ ///
+ /// Only necessary for manipulating a registered value, for example in
+ /// s.
+ ///
- /// Because the
- ///
- /// class implements the
- ///
- /// interface, instances of this class that have been exposed in the
- /// scope of an
- /// will
- /// automatically be picked up by the application context and made
- /// available to the IoC container whenever type conversion is required. If
- /// one is using a
- ///
- /// object definition within the scope of an
- /// , no such automatic
- /// pickup of the
- ///
- /// is performed (custom converters will have to be added manually using the
- ///
- /// method). For most application scenarios, one will get better
- /// mileage using the
- /// abstraction.
- ///
- ///
- ///
- ///
- /// The following examples all assume XML based configuration, and use
- /// inner object definitions to define the custom
- /// objects (nominally to
- /// avoid polluting the object name space, but also because the
- /// configuration simply reads better that way).
- ///
- ///
- ///
- ///
- ///
- /// The following example illustrates a complete (albeit naieve) use case
- /// for this class, including a custom
- /// implementation, said
- /// converters domain class, and the XML configuration that hooks the
- /// converter in place and makes it available to a Spring.NET container for
- /// use during object resolution.
- ///
- ///
- /// The domain class is a simple data-only object that contains the data
- /// required to send an email message (such as the host and user account
- /// name). A developer would prefer to use a string of the form
- /// UserName=administrator,Password=r1l0k1l3y,Host=localhost to
- /// configure the mail settings and just let the container take care of the
- /// conversion.
- ///
- ///
- /// namespace ExampleNamespace
- /// {
- /// public sealed class MailSettings
- /// {
- /// private string _userName;
- /// private string _password;
- /// private string _host;
- ///
- /// public string Host
- /// {
- /// get { return _host; }
- /// set { _host = value; }
- /// }
- ///
- /// public string UserName
- /// {
- /// get { return _userName; }
- /// set { _userName = value; }
- /// }
- ///
- /// public string Password
- /// {
- /// get { return _password; }
- /// set { _password = value; }
- /// }
- /// }
- ///
- /// public sealed class MailSettingsConverter : TypeConverter
- /// {
- /// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- /// {
- /// if (typeof (string) == sourceType)
- /// {
- /// return true;
- /// }
- /// return base.CanConvertFrom(context, sourceType);
- /// }
- ///
- /// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
- /// {
- /// string text = value as string;
- /// if(text != null)
- /// {
- /// MailSettings mailSettings = new MailSettings();
- /// string[] tokens = text.Split(',');
- /// for (int i = 0; i < tokens.Length; ++i)
- /// {
- /// string token = tokens[i];
- /// string[] settings = token.Split('=');
- /// typeof(MailSettings).GetProperty(settings[0])
- /// .SetValue(mailSettings, settings[1], null);
- /// }
- /// return mailSettings;
- /// }
- /// return base.ConvertFrom(context, culture, value);
- /// }
- /// }
- ///
- /// // a very naieve class that uses the MailSettings class...
- /// public sealed class ExceptionLogger
- /// {
- /// private MailSettings _mailSettings;
- ///
- /// public MailSettings MailSettings {
- /// {
- /// set { _mailSettings = value; }
- /// }
- ///
- /// public void Log(object value)
- /// {
- /// Exception ex = value as Exception;
- /// if(ex != null)
- /// {
- /// // use _mailSettings instance...
- /// }
- /// }
- /// }
- /// }
- ///
- ///
- /// The attendant XML configuration for the above classes would be...
- ///
- /// The uses the type name
- /// of the class that requires conversion as the key, and an
- /// instance of the
- /// that will effect
- /// the conversion. Alternatively, the actual
- /// of the class that requires conversion
- /// can be used as the key.
- ///
- ///
- ///
- ///
- ///
- /// IDictionary converters = new Hashtable();
- /// converters.Add( "System.Date", new MyCustomDateConverter() );
- /// // a System.Type instance can also be used as the key...
- /// converters.Add( typeof(Color), new MyCustomRBGColorConverter() );
- ///
- ///
+ /// Because the
+ ///
+ /// class implements the
+ ///
+ /// interface, instances of this class that have been exposed in the
+ /// scope of an
+ /// will
+ /// automatically be picked up by the application context and made
+ /// available to the IoC container whenever type conversion is required. If
+ /// one is using a
+ ///
+ /// object definition within the scope of an
+ /// , no such automatic
+ /// pickup of the
+ ///
+ /// is performed (custom converters will have to be added manually using the
+ ///
+ /// method). For most application scenarios, one will get better
+ /// mileage using the
+ /// abstraction.
+ ///
+ ///
+ ///
+ ///
+ /// The following examples all assume XML based configuration, and use
+ /// inner object definitions to define the custom
+ /// objects (nominally to
+ /// avoid polluting the object name space, but also because the
+ /// configuration simply reads better that way).
+ ///
+ /// The following example illustrates a complete (albeit naieve) use case
+ /// for this class, including a custom
+ /// implementation, said
+ /// converters domain class, and the XML configuration that hooks the
+ /// converter in place and makes it available to a Spring.NET container for
+ /// use during object resolution.
+ ///
+ ///
+ /// The domain class is a simple data-only object that contains the data
+ /// required to send an email message (such as the host and user account
+ /// name). A developer would prefer to use a string of the form
+ /// UserName=administrator,Password=r1l0k1l3y,Host=localhost to
+ /// configure the mail settings and just let the container take care of the
+ /// conversion.
+ ///
+ ///
+ /// namespace ExampleNamespace
+ /// {
+ /// public sealed class MailSettings
+ /// {
+ /// private string _userName;
+ /// private string _password;
+ /// private string _host;
+ ///
+ /// public string Host
+ /// {
+ /// get { return _host; }
+ /// set { _host = value; }
+ /// }
+ ///
+ /// public string UserName
+ /// {
+ /// get { return _userName; }
+ /// set { _userName = value; }
+ /// }
+ ///
+ /// public string Password
+ /// {
+ /// get { return _password; }
+ /// set { _password = value; }
+ /// }
+ /// }
+ ///
+ /// public sealed class MailSettingsConverter : TypeConverter
+ /// {
+ /// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ /// {
+ /// if (typeof (string) == sourceType)
+ /// {
+ /// return true;
+ /// }
+ /// return base.CanConvertFrom(context, sourceType);
+ /// }
+ ///
+ /// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ /// {
+ /// string text = value as string;
+ /// if(text != null)
+ /// {
+ /// MailSettings mailSettings = new MailSettings();
+ /// string[] tokens = text.Split(',');
+ /// for (int i = 0; i < tokens.Length; ++i)
+ /// {
+ /// string token = tokens[i];
+ /// string[] settings = token.Split('=');
+ /// typeof(MailSettings).GetProperty(settings[0])
+ /// .SetValue(mailSettings, settings[1], null);
+ /// }
+ /// return mailSettings;
+ /// }
+ /// return base.ConvertFrom(context, culture, value);
+ /// }
+ /// }
+ ///
+ /// // a very naieve class that uses the MailSettings class...
+ /// public sealed class ExceptionLogger
+ /// {
+ /// private MailSettings _mailSettings;
+ ///
+ /// public MailSettings MailSettings {
+ /// {
+ /// set { _mailSettings = value; }
+ /// }
+ ///
+ /// public void Log(object value)
+ /// {
+ /// Exception ex = value as Exception;
+ /// if(ex != null)
+ /// {
+ /// // use _mailSettings instance...
+ /// }
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ /// The attendant XML configuration for the above classes would be...
+ ///
+ /// The uses the type name
+ /// of the class that requires conversion as the key, and an
+ /// instance of the
+ /// that will effect
+ /// the conversion. Alternatively, the actual
+ /// of the class that requires conversion
+ /// can be used as the key.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// IDictionary converters = new Hashtable();
+ /// converters.Add( "System.Date", new MyCustomDateConverter() );
+ /// // a System.Type instance can also be used as the key...
+ /// converters.Add( typeof(Color), new MyCustomRBGColorConverter() );
+ ///
+ ///
- /// Supports the creation of s for both
- /// instance and methods.
- ///
- ///
- /// Rick Evans
- /// $Id: DelegateFactoryObject.cs,v 1.6 2007/03/16 04:01:35 aseovic Exp $
- [Serializable]
- public class DelegateFactoryObject : AbstractFactoryObject
- {
- ///
- /// Callback method called once all factory properties have been set.
- ///
- ///
- /// In the event of misconfiguration (such as failure to set an essential
- /// property) or if initialization fails.
- ///
- ///
- public override void AfterPropertiesSet()
- {
- if (DelegateType == null)
- {
- throw new ArgumentException(
- "The 'DelegateType' property is required.");
- }
- if (!typeof (Delegate).IsAssignableFrom(DelegateType))
- {
- throw new ArgumentException(
- "The 'DelegateType' property must (obviously) be a Type derived from [System.Delegate].");
- }
- if (TargetType == null && TargetObject == null)
- {
- throw new ArgumentException(
- "Exactly one of either the 'TargetType' or 'TargetObject' properties is required.");
- }
- if (TargetType != null && TargetObject != null)
- {
- throw new ArgumentException(
- "Exactly one of either the 'TargetType' or 'TargetObject' properties is required (not both).");
- }
- if (StringUtils.IsNullOrEmpty(MethodName))
- {
- throw new ArgumentException(
- "The 'MethodName' property is required.");
- }
- base.AfterPropertiesSet();
- }
-
- ///
- /// Creates the delegate.
- ///
- ///
- /// If an exception occured during object creation.
- ///
- /// The object returned by this factory.
- ///
- protected override object CreateInstance()
- {
- Delegate instance = null;
- if (TargetType != null)
- {
- instance = Delegate.CreateDelegate(DelegateType, TargetType, MethodName);
- }
- else
- {
- instance = Delegate.CreateDelegate(DelegateType, TargetObject, MethodName);
- }
- return instance;
- }
-
- #region Properties
-
- ///
- /// The of
- /// created by this factory.
- ///
- ///
- ///
- /// Returns the
- /// if accessed prior to the method
- /// being called.
- ///
+ /// Supports the creation of s for both
+ /// instance and methods.
+ ///
+ ///
+ /// Rick Evans
+ [Serializable]
+ public class DelegateFactoryObject : AbstractFactoryObject
+ {
+ ///
+ /// Callback method called once all factory properties have been set.
+ ///
+ ///
+ /// In the event of misconfiguration (such as failure to set an essential
+ /// property) or if initialization fails.
+ ///
+ ///
+ public override void AfterPropertiesSet()
+ {
+ if (DelegateType == null)
+ {
+ throw new ArgumentException(
+ "The 'DelegateType' property is required.");
+ }
+ if (!typeof (Delegate).IsAssignableFrom(DelegateType))
+ {
+ throw new ArgumentException(
+ "The 'DelegateType' property must (obviously) be a Type derived from [System.Delegate].");
+ }
+ if (TargetType == null && TargetObject == null)
+ {
+ throw new ArgumentException(
+ "Exactly one of either the 'TargetType' or 'TargetObject' properties is required.");
+ }
+ if (TargetType != null && TargetObject != null)
+ {
+ throw new ArgumentException(
+ "Exactly one of either the 'TargetType' or 'TargetObject' properties is required (not both).");
+ }
+ if (StringUtils.IsNullOrEmpty(MethodName))
+ {
+ throw new ArgumentException(
+ "The 'MethodName' property is required.");
+ }
+ base.AfterPropertiesSet();
+ }
+
+ ///
+ /// Creates the delegate.
+ ///
+ ///
+ /// If an exception occured during object creation.
+ ///
+ /// The object returned by this factory.
+ ///
+ protected override object CreateInstance()
+ {
+ Delegate instance = null;
+ if (TargetType != null)
+ {
+ instance = Delegate.CreateDelegate(DelegateType, TargetType, MethodName);
+ }
+ else
+ {
+ instance = Delegate.CreateDelegate(DelegateType, TargetObject, MethodName);
+ }
+ return instance;
+ }
+
+ #region Properties
+
+ ///
+ /// The of
+ /// created by this factory.
+ ///
+ ///
+ ///
+ /// Returns the
+ /// if accessed prior to the method
+ /// being called.
+ ///
- /// Typically used for retrieving public constants.
- ///
- ///
- ///
- ///
- /// The following example retrieves the field value...
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// The previous example could also have been written using the convenience
- ///
- /// property, like so...
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// This class also implements the
- /// interface
- /// ().
- /// If the id (or name) of one's
- ///
- /// object definition is set to the
- /// of the field to be retrieved, then the id (or
- /// name) of one's object definition will be used for the name of the
- /// field lookup. See below for an example of this
- /// concise style of definition.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// The usage for retrieving instance fields is similar. No example is shown
- /// because public instance fields are generally bad practice; but if
- /// you have some legacy code that exposes public instance fields, or if you
- /// just really like coding public instance fields, then you can use this
- /// implementation to
- /// retrieve such field values.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: FieldRetrievingFactoryObject.cs,v 1.8 2007/07/31 18:16:49 bbaia Exp $
- [Serializable]
- public class FieldRetrievingFactoryObject : IFactoryObject, IInitializingObject, IObjectNameAware
- {
- private string targetField;
- private object targetObject;
- private Type targetType;
- private FieldInfo field;
- private string objectName;
- private string staticField;
-
- ///
- /// The of the
- /// field to be retrieved.
- ///
- public string StaticField
- {
- set { this.staticField = value; }
- }
-
- ///
- /// Set the name of the object in the object factory that created this object.
- ///
- ///
- /// The name of the object in the factory.
- ///
- ///
- ///
- /// In the context of the
- ///
- /// class, the
- ///
- /// value will be interepreted as the value of the
- ///
- /// property if no value has been explicitly assigned to the
- ///
- /// property. This allows for concise object definitions with just an id or name;
- /// see the class documentation for
- ///
- /// for an example of this style of usage.
- ///
- ///
- public string ObjectName
- {
- set { this.objectName = value; }
- }
-
- ///
- /// The name of the field the value of which is to be retrieved.
- ///
- ///
- ///
- /// If the
- ///
- /// has been set (and is not ), then the value of this property
- /// refers to an instance field name; it otherwise refers to a
- /// field name.
- ///
- ///
- public string TargetField
- {
- get { return targetField; }
- set { targetField = value; }
- }
-
- ///
- /// The object instance on which the field is defined.
- ///
- public object TargetObject
- {
- get { return targetObject; }
- set { targetObject = value; }
- }
-
- ///
- /// The on which the field is defined.
- ///
- public Type TargetType
- {
- get { return targetType; }
- set { targetType = value; }
- }
-
- ///
- /// The of object that this
- /// creates, or
- /// if not known in advance.
- ///
- public Type ObjectType
- {
- get { return (this.field == null) ? null : this.field.FieldType; }
- }
-
- ///
- /// Is the object managed by this factory a singleton or a prototype?
- ///
- public bool IsSingleton
- {
- get { return true; }
- }
-
- ///
- /// Invoked by an
- /// after it has set all object properties supplied
- /// (and satisfied
- /// and ApplicationContextAware).
- ///
- ///
- ///
- /// This method allows the object instance to perform initialization only
- /// possible when all object properties have been set and to throw an
- /// exception in the event of misconfiguration.
- ///
+ /// Typically used for retrieving public constants.
+ ///
+ ///
+ ///
+ ///
+ /// The following example retrieves the field value...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The previous example could also have been written using the convenience
+ ///
+ /// property, like so...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// This class also implements the
+ /// interface
+ /// ().
+ /// If the id (or name) of one's
+ ///
+ /// object definition is set to the
+ /// of the field to be retrieved, then the id (or
+ /// name) of one's object definition will be used for the name of the
+ /// field lookup. See below for an example of this
+ /// concise style of definition.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The usage for retrieving instance fields is similar. No example is shown
+ /// because public instance fields are generally bad practice; but if
+ /// you have some legacy code that exposes public instance fields, or if you
+ /// just really like coding public instance fields, then you can use this
+ /// implementation to
+ /// retrieve such field values.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [Serializable]
+ public class FieldRetrievingFactoryObject : IFactoryObject, IInitializingObject, IObjectNameAware
+ {
+ private string targetField;
+ private object targetObject;
+ private Type targetType;
+ private FieldInfo field;
+ private string objectName;
+ private string staticField;
+
+ ///
+ /// The of the
+ /// field to be retrieved.
+ ///
+ public string StaticField
+ {
+ set { this.staticField = value; }
+ }
+
+ ///
+ /// Set the name of the object in the object factory that created this object.
+ ///
+ ///
+ /// The name of the object in the factory.
+ ///
+ ///
+ ///
+ /// In the context of the
+ ///
+ /// class, the
+ ///
+ /// value will be interepreted as the value of the
+ ///
+ /// property if no value has been explicitly assigned to the
+ ///
+ /// property. This allows for concise object definitions with just an id or name;
+ /// see the class documentation for
+ ///
+ /// for an example of this style of usage.
+ ///
+ ///
+ public string ObjectName
+ {
+ set { this.objectName = value; }
+ }
+
+ ///
+ /// The name of the field the value of which is to be retrieved.
+ ///
+ ///
+ ///
+ /// If the
+ ///
+ /// has been set (and is not ), then the value of this property
+ /// refers to an instance field name; it otherwise refers to a
+ /// field name.
+ ///
+ ///
+ public string TargetField
+ {
+ get { return targetField; }
+ set { targetField = value; }
+ }
+
+ ///
+ /// The object instance on which the field is defined.
+ ///
+ public object TargetObject
+ {
+ get { return targetObject; }
+ set { targetObject = value; }
+ }
+
+ ///
+ /// The on which the field is defined.
+ ///
+ public Type TargetType
+ {
+ get { return targetType; }
+ set { targetType = value; }
+ }
+
+ ///
+ /// The of object that this
+ /// creates, or
+ /// if not known in advance.
+ ///
+ public Type ObjectType
+ {
+ get { return (this.field == null) ? null : this.field.FieldType; }
+ }
+
+ ///
+ /// Is the object managed by this factory a singleton or a prototype?
+ ///
+ public bool IsSingleton
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Invoked by an
+ /// after it has set all object properties supplied
+ /// (and satisfied
+ /// and ApplicationContextAware).
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform initialization only
+ /// possible when all object properties have been set and to throw an
+ /// exception in the event of misconfiguration.
+ ///
- /// The returned object instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The existing object instance.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The object instance to use, either the original or a wrapped one.
- ///
- ///
- /// If any post-processing failed.
- ///
- ///
- object ApplyObjectPostProcessorsBeforeInitialization (
- object instance, string name);
-
- ///
- /// Apply s
- /// to the given existing object instance, invoking their
- ///
- /// methods.
- ///
- ///
- ///
- /// The returned object instance may be a wrapper around the original.
- ///
+ /// The returned object instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The existing object instance.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The object instance to use, either the original or a wrapped one.
+ ///
+ ///
+ /// If any post-processing failed.
+ ///
+ ///
+ object ApplyObjectPostProcessorsBeforeInitialization (
+ object instance, string name);
+
+ ///
+ /// Apply s
+ /// to the given existing object instance, invoking their
+ ///
+ /// methods.
+ ///
+ ///
+ ///
+ /// The returned object instance may be a wrapper around the original.
+ ///
- /// Allows for framework-internal plug'n'play, e.g. in
- /// .
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- public interface IConfigurableListableObjectFactory
- : IListableObjectFactory,
- IConfigurableObjectFactory,
- IAutowireCapableObjectFactory
- {
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- IObjectDefinition GetObjectDefinition(string name);
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- /// Whether to search parent object factories.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- IObjectDefinition GetObjectDefinition(string name, bool includeAncestors);
-
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the supplied .
- ///
- ///
- /// The object instance that is to be so configured.
- ///
- ///
- /// The name of the object definition expressing the dependencies that are to
- /// be injected into the supplied instance.
- ///
- ///
- /// An object definition that should be used to configure object.
- ///
- ///
- object ConfigureObject(object target, string name, IObjectDefinition definition);
-
- ///
- /// Ensure that all non-lazy-init singletons are instantiated, also
- /// considering s.
- ///
- ///
- ///
- /// Typically invoked at the end of factory setup, if desired.
- ///
- ///
- /// As this is a startup method, it should destroy already created singletons if
- /// it fails, to avoid dangling resources. In other words, after invocation
- /// of that method, either all or no singletons at all should be
- /// instantiated.
- ///
+ /// Allows for framework-internal plug'n'play, e.g. in
+ /// .
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IConfigurableListableObjectFactory
+ : IListableObjectFactory,
+ IConfigurableObjectFactory,
+ IAutowireCapableObjectFactory
+ {
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ IObjectDefinition GetObjectDefinition(string name);
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ /// Whether to search parent object factories.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ IObjectDefinition GetObjectDefinition(string name, bool includeAncestors);
+
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the supplied .
+ ///
+ ///
+ /// The object instance that is to be so configured.
+ ///
+ ///
+ /// The name of the object definition expressing the dependencies that are to
+ /// be injected into the supplied instance.
+ ///
+ ///
+ /// An object definition that should be used to configure object.
+ ///
+ ///
+ object ConfigureObject(object target, string name, IObjectDefinition definition);
+
+ ///
+ /// Ensure that all non-lazy-init singletons are instantiated, also
+ /// considering s.
+ ///
+ ///
+ ///
+ /// Typically invoked at the end of factory setup, if desired.
+ ///
+ ///
+ /// As this is a startup method, it should destroy already created singletons if
+ /// it fails, to avoid dangling resources. In other words, after invocation
+ /// of that method, either all or no singletons at all should be
+ /// instantiated.
+ ///
- /// Provides the means to configure an object factory in addition to the
- /// object factory client methods in the
- /// interface.
- ///
- ///
- /// Allows for framework-internal plug'n'play even when needing access to object
- /// factory configuration methods.
- ///
- ///
- /// When disposed, it will destroy all cached singletons in this factory. Call
- /// when you want to shutdown
- /// the factory.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: IConfigurableObjectFactory.cs,v 1.14 2007/07/16 21:06:21 markpollack Exp $
- public interface IConfigurableObjectFactory : IHierarchicalObjectFactory
- {
- ///
- /// Set the parent of this object factory.
- ///
- ///
- ///
- /// Note that the parent shouldn't be changed: it should only be set outside
- /// a constructor if it isn't available when an object of this class is
- /// created.
- ///
- ///
- new IObjectFactory ParentObjectFactory { set; }
-
- ///
- /// Ignore the given dependency type for autowiring.
- ///
- ///
- ///
- /// To be invoked during factory configuration.
- ///
- ///
- /// This will typically be used for dependencies that are resolved
- /// in other ways, like
- /// through .
- ///
- ///
- ///
- /// The to be ignored.
- ///
- void IgnoreDependencyType(Type type);
-
-
- ///
- /// Determines whether the specified object name is currently in creation..
- ///
- /// Name of the object.
- ///
- /// true if the specified object name is currently in creation; otherwise, false.
- ///
- bool IsCurrentlyInCreation(string objectName);
-
- ///
- /// Add a new
- /// that will get applied to objects created by this factory.
- ///
- ///
- ///
- /// To be invoked during factory configuration.
- ///
- ///
- ///
- /// The
- /// to register.
- ///
- void AddObjectPostProcessor(IObjectPostProcessor processor);
-
- ///
- /// Returns the current number of registered
- /// s.
- ///
- ///
- /// The current number of registered
- /// s.
- ///
- int ObjectPostProcessorCount
- {
- get;
- }
-
- ///
- /// Given an object name, create an alias.
- ///
- ///
- ///
- /// This is typically used to support names that are illegal within
- /// XML ids (which are used for object names).
- ///
- ///
- /// Typically invoked during factory configuration, but can also be
- /// used for runtime registration of aliases. Therefore, a factory
- /// implementation should synchronize alias access.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The alias that will behave the same as the object name.
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// If the alias is already in use.
- ///
- void RegisterAlias(string name, string theAlias);
-
- ///
- /// Register the given existing object as singleton in the object factory,
- /// under the given object name.
- ///
- ///
- ///
- /// Typically invoked during factory configuration, but can also be
- /// used for runtime registration of singletons. Therefore, a factory
- /// implementation should synchronize singleton access; it will have
- /// to do this anyway if it supports lazy initialization of singletons.
- ///
- ///
- ///
- /// The name of the object.
- ///
- /// The existing object.
- ///
- /// If the singleton could not be registered.
- ///
- void RegisterSingleton(string name, object singleton);
-
- ///
- /// Register the given custom
- /// for all properties of the given .
- ///
- ///
- ///
- /// To be invoked during factory configuration.
- ///
- ///
- ///
- /// The required of the property.
- ///
- ///
- /// The to register.
- ///
- void RegisterCustomConverter(Type requiredType, TypeConverter converter);
-
- ///
- /// Does this object factory contains a singleton instance with the
- /// supplied ?
- ///
- ///
- ///
- /// Only checks already instantiated singletons; does not return
- /// for singleton object definitions that have
- /// not been instantiated yet.
- ///
- ///
- /// The main purpose of this method is to check manually registered
- /// singletons (). This
- /// method can also be used to check whether a singleton defined by an
- /// object definition has already been created.
- ///
- ///
- /// To check whether an object factory contains an object definition
- /// with a given name, use the
- ///
- /// method. Calling both
- ///
- /// and definitively answers
- /// the question of whether a specific object factory contains a
- /// singleton object with the given name.
- ///
- ///
- /// Use the
- ///
- /// method for general checks as to whether a factory knows about an
- /// object with a given name (regrdless of whether the object in
- /// question is a manually registed singleton instance or created by
- /// an object definition)... this also has the happy bonus of also
- /// checking any ancestor factories.
- ///
+ /// Provides the means to configure an object factory in addition to the
+ /// object factory client methods in the
+ /// interface.
+ ///
+ ///
+ /// Allows for framework-internal plug'n'play even when needing access to object
+ /// factory configuration methods.
+ ///
+ ///
+ /// When disposed, it will destroy all cached singletons in this factory. Call
+ /// when you want to shutdown
+ /// the factory.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IConfigurableObjectFactory : IHierarchicalObjectFactory
+ {
+ ///
+ /// Set the parent of this object factory.
+ ///
+ ///
+ ///
+ /// Note that the parent shouldn't be changed: it should only be set outside
+ /// a constructor if it isn't available when an object of this class is
+ /// created.
+ ///
+ ///
+ new IObjectFactory ParentObjectFactory { set; }
+
+ ///
+ /// Ignore the given dependency type for autowiring.
+ ///
+ ///
+ ///
+ /// To be invoked during factory configuration.
+ ///
+ ///
+ /// This will typically be used for dependencies that are resolved
+ /// in other ways, like
+ /// through .
+ ///
+ ///
+ ///
+ /// The to be ignored.
+ ///
+ void IgnoreDependencyType(Type type);
+
+
+ ///
+ /// Determines whether the specified object name is currently in creation..
+ ///
+ /// Name of the object.
+ ///
+ /// true if the specified object name is currently in creation; otherwise, false.
+ ///
+ bool IsCurrentlyInCreation(string objectName);
+
+ ///
+ /// Add a new
+ /// that will get applied to objects created by this factory.
+ ///
+ ///
+ ///
+ /// To be invoked during factory configuration.
+ ///
+ ///
+ ///
+ /// The
+ /// to register.
+ ///
+ void AddObjectPostProcessor(IObjectPostProcessor processor);
+
+ ///
+ /// Returns the current number of registered
+ /// s.
+ ///
+ ///
+ /// The current number of registered
+ /// s.
+ ///
+ int ObjectPostProcessorCount
+ {
+ get;
+ }
+
+ ///
+ /// Given an object name, create an alias.
+ ///
+ ///
+ ///
+ /// This is typically used to support names that are illegal within
+ /// XML ids (which are used for object names).
+ ///
+ ///
+ /// Typically invoked during factory configuration, but can also be
+ /// used for runtime registration of aliases. Therefore, a factory
+ /// implementation should synchronize alias access.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The alias that will behave the same as the object name.
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// If the alias is already in use.
+ ///
+ void RegisterAlias(string name, string theAlias);
+
+ ///
+ /// Register the given existing object as singleton in the object factory,
+ /// under the given object name.
+ ///
+ ///
+ ///
+ /// Typically invoked during factory configuration, but can also be
+ /// used for runtime registration of singletons. Therefore, a factory
+ /// implementation should synchronize singleton access; it will have
+ /// to do this anyway if it supports lazy initialization of singletons.
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ /// The existing object.
+ ///
+ /// If the singleton could not be registered.
+ ///
+ void RegisterSingleton(string name, object singleton);
+
+ ///
+ /// Register the given custom
+ /// for all properties of the given .
+ ///
+ ///
+ ///
+ /// To be invoked during factory configuration.
+ ///
+ ///
+ ///
+ /// The required of the property.
+ ///
+ ///
+ /// The to register.
+ ///
+ void RegisterCustomConverter(Type requiredType, TypeConverter converter);
+
+ ///
+ /// Does this object factory contains a singleton instance with the
+ /// supplied ?
+ ///
+ ///
+ ///
+ /// Only checks already instantiated singletons; does not return
+ /// for singleton object definitions that have
+ /// not been instantiated yet.
+ ///
+ ///
+ /// The main purpose of this method is to check manually registered
+ /// singletons (). This
+ /// method can also be used to check whether a singleton defined by an
+ /// object definition has already been created.
+ ///
+ ///
+ /// To check whether an object factory contains an object definition
+ /// with a given name, use the
+ ///
+ /// method. Calling both
+ ///
+ /// and definitively answers
+ /// the question of whether a specific object factory contains a
+ /// singleton object with the given name.
+ ///
+ ///
+ /// Use the
+ ///
+ /// method for general checks as to whether a factory knows about an
+ /// object with a given name (regrdless of whether the object in
+ /// question is a manually registed singleton instance or created by
+ /// an object definition)... this also has the happy bonus of also
+ /// checking any ancestor factories.
+ ///
- /// Typical use cases might include being used to suppress the default
- /// instantiation of specific target objects, perhaps in favour of creating
- /// proxies with special Spring.Aop.ITargetSources (pooling targets,
- /// lazily initializing targets, etc).
- ///
- /// The returned object may be a proxy to use instead of the target
- /// object, effectively suppressing the default instantiation of the
- /// target object.
- ///
- ///
- /// If the object is returned by this method is not
- /// , the object creation process will be
- /// short-circuited. The returned object will not be processed any
- /// further; in particular, no further
- ///
- /// callbacks will be applied to it. This mechanism is mainly intended
- /// for exposing a proxy instead of an actual target object.
- ///
- ///
- /// This callback will only be applied to object definitions with an
- /// object class. In particular, it will not be applied to
- /// objects with a "factory-method" (i.e. objects that are to be
- /// instantiated via a layer of indirection anyway).
- ///
+ /// Typical use cases might include being used to suppress the default
+ /// instantiation of specific target objects, perhaps in favour of creating
+ /// proxies with special Spring.Aop.ITargetSources (pooling targets,
+ /// lazily initializing targets, etc).
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor
+ {
+ ///
+ /// Apply this
+ ///
+ /// before the target object gets instantiated.
+ ///
+ ///
+ ///
+ /// The returned object may be a proxy to use instead of the target
+ /// object, effectively suppressing the default instantiation of the
+ /// target object.
+ ///
+ ///
+ /// If the object is returned by this method is not
+ /// , the object creation process will be
+ /// short-circuited. The returned object will not be processed any
+ /// further; in particular, no further
+ ///
+ /// callbacks will be applied to it. This mechanism is mainly intended
+ /// for exposing a proxy instead of an actual target object.
+ ///
+ ///
+ /// This callback will only be applied to object definitions with an
+ /// object class. In particular, it will not be applied to
+ /// objects with a "factory-method" (i.e. objects that are to be
+ /// instantiated via a layer of indirection anyway).
+ ///
- /// This is just a minimal interface: the main intention is to allow
- ///
- /// (like PropertyPlaceholderConfigurer) to access and modify property values.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: IObjectDefinition.cs,v 1.14 2007/07/30 17:52:22 markpollack Exp $
- public interface IObjectDefinition
- {
- ///
- /// Return the property values to be applied to a new instance of the object.
- ///
- MutablePropertyValues PropertyValues { get; }
-
- ///
- /// Return the constructor argument values for this object.
- ///
- ConstructorArgumentValues ConstructorArgumentValues { get; }
-
- ///
- /// Return the event handlers for any events exposed by this object.
- ///
- EventValues EventHandlerValues { get; }
-
- ///
- /// Return a description of the resource that this object definition
- /// came from (for the purpose of showing context in case of errors).
- ///
- string ResourceDescription { get; }
-
- ///
- /// Is this object definition a "template", i.e. not meant to be instantiated
- /// itself but rather just serving as an object definition for configuration
- /// templates used by .
- ///
- ///
- /// if this object definition is a "template".
- ///
- bool IsTemplate { get; }
-
- ///
- /// Is this object definition "abstract", i.e. not meant to be instantiated
- /// itself but rather just serving as parent for concrete child object
- /// definitions.
- ///
- ///
- /// if this object definition is "abstract".
- ///
- bool IsAbstract { get; }
-
- ///
- /// Return whether this a Singleton, with a single, shared instance
- /// returned on all calls.
- ///
- ///
- ///
- /// If , an object factory will apply the Prototype
- /// design pattern, with each caller requesting an instance getting an
- /// independent instance. How this is defined will depend on the
- /// object factory implementation. Singletons are the commoner type.
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup by object factories
- /// that perform eager initialization of singletons.
- ///
- ///
- bool IsLazyInit { get; }
-
- ///
- /// Returns the of the object definition (if any).
- ///
- ///
- /// A resolved object .
- ///
- ///
- /// If the of the object definition is not a
- /// resolved or .
- ///
- Type ObjectType { get; }
-
- ///
- /// Returns the of the
- /// of the object definition.
- ///
- /// Note that this does not have to be the actual type name used at runtime,
- /// in case of a child definition overrding/inheriting the the type name from its
- /// parent. It can be modifed during object factory post-processing, typically
- /// replacing the original class name with a parsed variant of it.
- /// Hence, do not consider this to be the definitive bean type at runtime
- /// but rather only use it for parsing purposes at the individual object
- /// definition level.
- ///
- string ObjectTypeName { get; set;}
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. Default is
- /// ,
- /// which means there's no autowire.
- ///
- ///
- AutoWiringMode AutowireMode { get; }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before.
- ///
- ///
- /// Note that dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies like statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- string[] DependsOn { get; }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default is , in which case there is no initializer method.
- ///
- ///
- string InitMethodName { get; }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default is , in which case there is no destroy method.
- ///
- ///
- string DestroyMethodName { get; }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The static method will be invoked on
- /// the specified .
- ///
+ /// This is just a minimal interface: the main intention is to allow
+ ///
+ /// (like PropertyPlaceholderConfigurer) to access and modify property values.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IObjectDefinition
+ {
+ ///
+ /// Return the property values to be applied to a new instance of the object.
+ ///
+ MutablePropertyValues PropertyValues { get; }
+
+ ///
+ /// Return the constructor argument values for this object.
+ ///
+ ConstructorArgumentValues ConstructorArgumentValues { get; }
+
+ ///
+ /// Return the event handlers for any events exposed by this object.
+ ///
+ EventValues EventHandlerValues { get; }
+
+ ///
+ /// Return a description of the resource that this object definition
+ /// came from (for the purpose of showing context in case of errors).
+ ///
+ string ResourceDescription { get; }
+
+ ///
+ /// Is this object definition a "template", i.e. not meant to be instantiated
+ /// itself but rather just serving as an object definition for configuration
+ /// templates used by .
+ ///
+ ///
+ /// if this object definition is a "template".
+ ///
+ bool IsTemplate { get; }
+
+ ///
+ /// Is this object definition "abstract", i.e. not meant to be instantiated
+ /// itself but rather just serving as parent for concrete child object
+ /// definitions.
+ ///
+ ///
+ /// if this object definition is "abstract".
+ ///
+ bool IsAbstract { get; }
+
+ ///
+ /// Return whether this a Singleton, with a single, shared instance
+ /// returned on all calls.
+ ///
+ ///
+ ///
+ /// If , an object factory will apply the Prototype
+ /// design pattern, with each caller requesting an instance getting an
+ /// independent instance. How this is defined will depend on the
+ /// object factory implementation. Singletons are the commoner type.
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup by object factories
+ /// that perform eager initialization of singletons.
+ ///
+ ///
+ bool IsLazyInit { get; }
+
+ ///
+ /// Returns the of the object definition (if any).
+ ///
+ ///
+ /// A resolved object .
+ ///
+ ///
+ /// If the of the object definition is not a
+ /// resolved or .
+ ///
+ Type ObjectType { get; }
+
+ ///
+ /// Returns the of the
+ /// of the object definition.
+ ///
+ /// Note that this does not have to be the actual type name used at runtime,
+ /// in case of a child definition overrding/inheriting the the type name from its
+ /// parent. It can be modifed during object factory post-processing, typically
+ /// replacing the original class name with a parsed variant of it.
+ /// Hence, do not consider this to be the definitive bean type at runtime
+ /// but rather only use it for parsing purposes at the individual object
+ /// definition level.
+ ///
+ string ObjectTypeName { get; set;}
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. Default is
+ /// ,
+ /// which means there's no autowire.
+ ///
+ ///
+ AutoWiringMode AutowireMode { get; }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before.
+ ///
+ ///
+ /// Note that dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies like statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ string[] DependsOn { get; }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no initializer method.
+ ///
+ ///
+ string InitMethodName { get; }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no destroy method.
+ ///
+ ///
+ string DestroyMethodName { get; }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The static method will be invoked on
+ /// the specified .
+ ///
- /// Application contexts can auto-detect
- /// IObjectFactoryPostProcessor objects in their object definitions and
- /// apply them before any other objects get created.
- ///
- ///
- /// Useful for custom config files targeted at system administrators that
- /// override object properties configured in the application context.
- ///
- ///
- /// See PropertyResourceConfigurer and its concrete implementations for
- /// out-of-the-box solutions that address such configuration needs.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.Net)
- public interface IObjectFactoryPostProcessor
- {
- ///
- /// Modify the application context's internal object factory after its
- /// standard initialization.
- ///
- ///
- ///
- /// All object definitions will have been loaded, but no objects will have
- /// been instantiated yet. This allows for overriding or adding properties
- /// even to eager-initializing objects.
- ///
+ /// Application contexts can auto-detect
+ /// IObjectFactoryPostProcessor objects in their object definitions and
+ /// apply them before any other objects get created.
+ ///
+ ///
+ /// Useful for custom config files targeted at system administrators that
+ /// override object properties configured in the application context.
+ ///
+ ///
+ /// See PropertyResourceConfigurer and its concrete implementations for
+ /// out-of-the-box solutions that address such configuration needs.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.Net)
+ public interface IObjectFactoryPostProcessor
+ {
+ ///
+ /// Modify the application context's internal object factory after its
+ /// standard initialization.
+ ///
+ ///
+ ///
+ /// All object definitions will have been loaded, but no objects will have
+ /// been instantiated yet. This allows for overriding or adding properties
+ /// even to eager-initializing objects.
+ ///
- /// Application contexts can auto-detect
- ///
- /// objects in their object definitions and apply them before any other
- /// objects get created. Plain object factories allow for programmatic
- /// registration of post-processors.
- ///
- ///
- /// Typically, post-processors that populate objects via marker interfaces
- /// or the like will implement
- /// ,
- /// and post-processors that wrap objects with proxies will normally implement
- /// .
- ///
- ///
- /// Juergen Hoeller
- /// Aleksandar Seovic (.NET)
- /// $Id: IObjectPostProcessor.cs,v 1.9 2007/08/22 08:49:39 markpollack Exp $
- ///
- public interface IObjectPostProcessor
- {
- ///
- /// Apply this
- /// to the given new object instance before any object initialization callbacks.
- ///
- ///
- ///
- /// The object will already be populated with property values.
- /// The returned object instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The new object instance.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The object instance to use, either the original or a wrapped one.
- ///
- ///
- /// In case of errors.
- ///
- object PostProcessBeforeInitialization(object instance, string name);
-
- ///
- /// Apply this to the
- /// given new object instance after any object initialization callbacks.
- ///
- ///
- ///
- /// The object will already be populated with property values. The returned object
- /// instance may be a wrapper around the original.
- ///
+ /// Application contexts can auto-detect
+ ///
+ /// objects in their object definitions and apply them before any other
+ /// objects get created. Plain object factories allow for programmatic
+ /// registration of post-processors.
+ ///
+ ///
+ /// Typically, post-processors that populate objects via marker interfaces
+ /// or the like will implement
+ /// ,
+ /// and post-processors that wrap objects with proxies will normally implement
+ /// .
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Aleksandar Seovic (.NET)
+ ///
+ public interface IObjectPostProcessor
+ {
+ ///
+ /// Apply this
+ /// to the given new object instance before any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// The object will already be populated with property values.
+ /// The returned object instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The new object instance.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The object instance to use, either the original or a wrapped one.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ object PostProcessBeforeInitialization(object instance, string name);
+
+ ///
+ /// Apply this to the
+ /// given new object instance after any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// The object will already be populated with property values. The returned object
+ /// instance may be a wrapper around the original.
+ ///
- /// The "variable sources" are objects containing name-value pairs
- /// that allow a variable value to be retrieved for the given name.
- ///
- /// Out of the box, Spring.NET supports a number of variable sources,
- /// that allow users to obtain variable values from .NET config files,
- /// Java-style property files, environment, registry, etc.
- ///
- /// Users can always write their own variable sources implementations,
- /// that will allow them to load variable values from the database or
- /// other proprietary data source.
+ /// The "variable sources" are objects containing name-value pairs
+ /// that allow a variable value to be retrieved for the given name.
+ ///
+ /// Out of the box, Spring.NET supports a number of variable sources,
+ /// that allow users to obtain variable values from .NET config files,
+ /// Java-style property files, environment, registry, etc.
+ ///
+ /// Users can always write their own variable sources implementations,
+ /// that will allow them to load variable values from the database or
+ /// other proprietary data source.
- /// The returned object may be a proxy to use instead of the target
- /// object, effectively suppressing the default instantiation of the
- /// target object.
- ///
- ///
- /// If the object is returned by this method is not
- /// , the object creation process will be
- /// short-circuited. The returned object will not be processed any
- /// further; in particular, no further
- ///
- /// callbacks will be applied to it. This mechanism is mainly intended
- /// for exposing a proxy instead of an actual target object.
- ///
- ///
- /// This callback will only be applied to object definitions with an
- /// object class. In particular, it will not be applied to
- /// objects with a "factory-method" (i.e. objects that are to be
- /// instantiated via a layer of indirection anyway).
- ///
- ///
- ///
- /// The of the target object that is to be
- /// instantiated.
- ///
- ///
- /// The name of the target object.
- ///
- ///
- /// The object to expose instead of a default instance of the target
- /// object.
- ///
- ///
- /// In the case of any errors.
- ///
- ///
- ///
- public virtual object PostProcessBeforeInstantiation(Type objectType, string objectName)
- {
- return null;
- }
-
- ///
- /// Perform operations after the object has been instantiated, via a constructor or factory method,
- /// but before Spring property population (from explicit properties or autowiring) occurs.
- ///
- /// The object instance created, but whose properties have not yet been set
- /// Name of the object.
- /// true if properties should be set on the object; false if property population
- /// should be skipped. Normal implementations should return true. Returning false will also
- /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being
- /// invoked on this object instance.
- public virtual bool PostProcessAfterInstantiation(object objectInstance, string objectName)
- {
- return true;
- }
-
- ///
- /// Post-process the given property values before the factory applies them
- /// to the given object.
- ///
- /// Allows for checking whether all dependencies have been
- /// satisfied, for example based on a "Required" annotation on bean property setters.
- /// Also allows for replacing the property values to apply, typically through
- /// creating a new MutablePropertyValues instance based on the original PropertyValues,
- /// adding or removing specific values.
- ///
- ///
- /// The property values that the factory is about to apply (never null).
- /// he relevant property infos for the target object (with ignored
- /// dependency types - which the factory handles specifically - already filtered out)
- /// The object instance created, but whose properties have not yet
- /// been set.
- /// Name of the object.
- /// The actual property values to apply to the given object (can be the
- /// passed-in PropertyValues instances0 or null to skip property population.
- public virtual IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, PropertyInfo[] pis, object objectInstance,
- string objectName)
- {
- return pvs;
- }
-
- #endregion
-
- #region IObjectPostProcessor Members
-
- ///
- /// Apply this
- /// to the given new object instance before any object initialization callbacks.
- ///
- ///
- ///
- /// The object will already be populated with property values.
- /// The returned object instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The new object instance.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The object instance to use, either the original or a wrapped one.
- ///
- ///
- /// In case of errors.
- ///
- public virtual object PostProcessBeforeInitialization(object instance, string name)
- {
- return instance;
- }
-
- ///
- /// Apply this to the
- /// given new object instance after any object initialization callbacks.
- ///
- ///
- ///
- /// The object will already be populated with property values. The returned object
- /// instance may be a wrapper around the original.
- ///
+ /// The returned object may be a proxy to use instead of the target
+ /// object, effectively suppressing the default instantiation of the
+ /// target object.
+ ///
+ ///
+ /// If the object is returned by this method is not
+ /// , the object creation process will be
+ /// short-circuited. The returned object will not be processed any
+ /// further; in particular, no further
+ ///
+ /// callbacks will be applied to it. This mechanism is mainly intended
+ /// for exposing a proxy instead of an actual target object.
+ ///
+ ///
+ /// This callback will only be applied to object definitions with an
+ /// object class. In particular, it will not be applied to
+ /// objects with a "factory-method" (i.e. objects that are to be
+ /// instantiated via a layer of indirection anyway).
+ ///
+ ///
+ ///
+ /// The of the target object that is to be
+ /// instantiated.
+ ///
+ ///
+ /// The name of the target object.
+ ///
+ ///
+ /// The object to expose instead of a default instance of the target
+ /// object.
+ ///
+ ///
+ /// In the case of any errors.
+ ///
+ ///
+ ///
+ public virtual object PostProcessBeforeInstantiation(Type objectType, string objectName)
+ {
+ return null;
+ }
+
+ ///
+ /// Perform operations after the object has been instantiated, via a constructor or factory method,
+ /// but before Spring property population (from explicit properties or autowiring) occurs.
+ ///
+ /// The object instance created, but whose properties have not yet been set
+ /// Name of the object.
+ /// true if properties should be set on the object; false if property population
+ /// should be skipped. Normal implementations should return true. Returning false will also
+ /// prevent any subsequent InstantiationAwareObjectPostProcessor instances from being
+ /// invoked on this object instance.
+ public virtual bool PostProcessAfterInstantiation(object objectInstance, string objectName)
+ {
+ return true;
+ }
+
+ ///
+ /// Post-process the given property values before the factory applies them
+ /// to the given object.
+ ///
+ /// Allows for checking whether all dependencies have been
+ /// satisfied, for example based on a "Required" annotation on bean property setters.
+ /// Also allows for replacing the property values to apply, typically through
+ /// creating a new MutablePropertyValues instance based on the original PropertyValues,
+ /// adding or removing specific values.
+ ///
+ ///
+ /// The property values that the factory is about to apply (never null).
+ /// he relevant property infos for the target object (with ignored
+ /// dependency types - which the factory handles specifically - already filtered out)
+ /// The object instance created, but whose properties have not yet
+ /// been set.
+ /// Name of the object.
+ /// The actual property values to apply to the given object (can be the
+ /// passed-in PropertyValues instances0 or null to skip property population.
+ public virtual IPropertyValues PostProcessPropertyValues(IPropertyValues pvs, PropertyInfo[] pis, object objectInstance,
+ string objectName)
+ {
+ return pvs;
+ }
+
+ #endregion
+
+ #region IObjectPostProcessor Members
+
+ ///
+ /// Apply this
+ /// to the given new object instance before any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// The object will already be populated with property values.
+ /// The returned object instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The new object instance.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The object instance to use, either the original or a wrapped one.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ public virtual object PostProcessBeforeInitialization(object instance, string name)
+ {
+ return instance;
+ }
+
+ ///
+ /// Apply this to the
+ /// given new object instance after any object initialization callbacks.
+ ///
+ ///
+ ///
+ /// The object will already be populated with property values. The returned object
+ /// instance may be a wrapper around the original.
+ ///
- /// Typically used for retrieving shared
- /// instances for common topics (such as the 'DAL', 'BLL', etc). The
- ///
- /// property determines the name of the
- /// Common.Logging logger.
- ///
+ /// Typically used for retrieving shared
+ /// instances for common topics (such as the 'DAL', 'BLL', etc). The
+ ///
+ /// property determines the name of the
+ /// Common.Logging logger.
+ ///
- /// Note that this class generally is expected to be used for accessing factory methods,
- /// and as such defaults to operating in singleton mode. The first request to
- ///
- /// by the owning object factory will cause a method invocation, the return
- /// value of which will be cached for all subsequent requests. The
- /// property may be set to
- /// , to cause this factory to invoke the target method each
- /// time it is asked for an object.
- ///
- ///
- /// A target method may be specified by setting the
- /// property to a string representing
- /// the method name, with specifying
- /// the that the method is defined on.
- /// Alternatively, a target instance method may be specified, by setting the
- /// property as the target object, and
- /// the property as the name of the
- /// method to call on that target object. Arguments for the method invocation may be
- /// specified by setting the property.
- ///
- ///
- /// Another (esoteric) use case for this factory object is when one needs to call a method
- /// that doesn't return any value (for example, a class method to
- /// force some sort of initialization to happen)... this use case is not supported by
- /// factory-methods, since a return value is needed to become the object.
- ///
- ///
- ///
- /// This class depends on the
- ///
- /// method being called after all properties have been set, as per the
- /// contract. If you are
- /// using this class outside of a Spring.NET IoC container, you must call one of either
- /// or
- /// yourself to ready the object's internal
- /// state, or you will get a nasty .
- ///
- ///
- ///
- ///
- ///
- /// The following example uses an instance of this class to call a
- /// factory method...
- ///
- /// The following example is similar to the preceding example; the only pertinent difference is the fact that
- /// a number of different objects are passed as arguments, demonstrating that not only simple value types
- /// are valid as elements of the argument list...
- ///
- /// Named parameters are also supported... this next example yields the same results as
- /// the preceding example (that did not use named arguments).
- ///
- /// The above example could also have been written using an anonymous inner object definition... if the
- /// object on which the method is to be invoked is not going to be used outside of the factory object
- /// definition, then this is the preferred idiom because it limits the scope of the object on which the
- /// method is to be invoked to the surrounding factory object.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Colin Sampaleanu
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// Simon White (.NET)
- /// $Id: MethodInvokingFactoryObject.cs,v 1.15 2007/03/16 04:01:38 aseovic Exp $
- ///
- ///
- [Serializable]
- public class MethodInvokingFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IInitializingObject
- {
- private bool singleton = true;
- private object singletonObject;
-
- ///
- /// If a singleton should be created, or a new object on each request.
- /// Defaults to .
- ///
- public bool IsSingleton
- {
- get { return singleton; }
- set { singleton = value; }
- }
-
- ///
- /// Return the return value of the method
- /// that this factory invokes, or if not
- /// known in advance.
- ///
- ///
- ///
- /// If the return value of the method that this factory is to invoke is
- /// , then the
- /// will be returned (in accordance with the
- /// contract that
- /// treats a value as a configuration error).
- ///
- ///
- ///
- public Type ObjectType
- {
- get
- {
- Type objectType = null;
- if (GetPreparedMethod() != null)
- {
- objectType = GetPreparedMethod().ReturnType;
- if (objectType.Equals(typeof (void)))
- {
- objectType = Void.GetType();
- }
- }
- return objectType;
- }
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the object
- /// managed by this factory.
- ///
- ///
- ///
- /// Returns the return value of the method that is to be invoked.
- ///
- ///
- /// Will return the same value each time if the
- ///
- /// property value is .
- ///
+ /// Note that this class generally is expected to be used for accessing factory methods,
+ /// and as such defaults to operating in singleton mode. The first request to
+ ///
+ /// by the owning object factory will cause a method invocation, the return
+ /// value of which will be cached for all subsequent requests. The
+ /// property may be set to
+ /// , to cause this factory to invoke the target method each
+ /// time it is asked for an object.
+ ///
+ ///
+ /// A target method may be specified by setting the
+ /// property to a string representing
+ /// the method name, with specifying
+ /// the that the method is defined on.
+ /// Alternatively, a target instance method may be specified, by setting the
+ /// property as the target object, and
+ /// the property as the name of the
+ /// method to call on that target object. Arguments for the method invocation may be
+ /// specified by setting the property.
+ ///
+ ///
+ /// Another (esoteric) use case for this factory object is when one needs to call a method
+ /// that doesn't return any value (for example, a class method to
+ /// force some sort of initialization to happen)... this use case is not supported by
+ /// factory-methods, since a return value is needed to become the object.
+ ///
+ ///
+ ///
+ /// This class depends on the
+ ///
+ /// method being called after all properties have been set, as per the
+ /// contract. If you are
+ /// using this class outside of a Spring.NET IoC container, you must call one of either
+ /// or
+ /// yourself to ready the object's internal
+ /// state, or you will get a nasty .
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The following example uses an instance of this class to call a
+ /// factory method...
+ ///
+ /// The following example is similar to the preceding example; the only pertinent difference is the fact that
+ /// a number of different objects are passed as arguments, demonstrating that not only simple value types
+ /// are valid as elements of the argument list...
+ ///
+ /// Named parameters are also supported... this next example yields the same results as
+ /// the preceding example (that did not use named arguments).
+ ///
+ /// The above example could also have been written using an anonymous inner object definition... if the
+ /// object on which the method is to be invoked is not going to be used outside of the factory object
+ /// definition, then this is the preferred idiom because it limits the scope of the object on which the
+ /// method is to be invoked to the surrounding factory object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Colin Sampaleanu
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ /// Simon White (.NET)
+ ///
+ ///
+ [Serializable]
+ public class MethodInvokingFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IInitializingObject
+ {
+ private bool singleton = true;
+ private object singletonObject;
+
+ ///
+ /// If a singleton should be created, or a new object on each request.
+ /// Defaults to .
+ ///
+ public bool IsSingleton
+ {
+ get { return singleton; }
+ set { singleton = value; }
+ }
+
+ ///
+ /// Return the return value of the method
+ /// that this factory invokes, or if not
+ /// known in advance.
+ ///
+ ///
+ ///
+ /// If the return value of the method that this factory is to invoke is
+ /// , then the
+ /// will be returned (in accordance with the
+ /// contract that
+ /// treats a value as a configuration error).
+ ///
+ ///
+ ///
+ public Type ObjectType
+ {
+ get
+ {
+ Type objectType = null;
+ if (GetPreparedMethod() != null)
+ {
+ objectType = GetPreparedMethod().ReturnType;
+ if (objectType.Equals(typeof (void)))
+ {
+ objectType = Void.GetType();
+ }
+ }
+ return objectType;
+ }
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the object
+ /// managed by this factory.
+ ///
+ ///
+ ///
+ /// Returns the return value of the method that is to be invoked.
+ ///
+ ///
+ /// Will return the same value each time if the
+ ///
+ /// property value is .
+ ///
- /// Recognized by
- ///
- /// for inner object definitions. Registered by
- /// ,
- /// which also uses it as general holder for a parsed object definition.
- ///
- ///
- /// Can also be used for programmatic registration of inner object
- /// definitions. If you don't care about the functionality offered by the
- /// interface and the like,
- /// registering
- /// or is good enough.
- ///
- ///
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: ObjectDefinitionHolder.cs,v 1.2 2007/08/07 22:05:20 markpollack Exp $
- [Serializable]
- public class ObjectDefinitionHolder
- {
- private IObjectDefinition objectDefinition;
- private string objectName;
- private string[] aliases;
-
- #region Constructor () / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The object definition to be held by this instance.
- ///
- ///
- /// The name of the object definition.
- ///
- public ObjectDefinitionHolder(IObjectDefinition definition, string name)
- : this(definition, name, StringUtils.EmptyStrings)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The object definition to be held by this instance.
- ///
- /// The name of the object.
- ///
- /// Any aliases for the supplied
- ///
- public ObjectDefinitionHolder(
- IObjectDefinition definition, string name, string[] aliases)
- {
- this.objectDefinition = definition;
- this.objectName = name;
- this.aliases = aliases == null ? StringUtils.EmptyStrings : aliases;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The held by this
- /// instance.
- ///
- public IObjectDefinition ObjectDefinition
- {
- get { return objectDefinition; }
- }
-
- ///
- /// The name of the object definition.
- ///
- public string ObjectName
- {
- get { return objectName; }
- }
-
- ///
- /// Any aliases for the object definition.
- ///
- ///
- ///
- /// Guaranteed to never return ; if the associated
- ///
- /// does not have any aliases associated with it, then an empty
- /// array will be returned.
- ///
+ /// Recognized by
+ ///
+ /// for inner object definitions. Registered by
+ /// ,
+ /// which also uses it as general holder for a parsed object definition.
+ ///
+ ///
+ /// Can also be used for programmatic registration of inner object
+ /// definitions. If you don't care about the functionality offered by the
+ /// interface and the like,
+ /// registering
+ /// or is good enough.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ [Serializable]
+ public class ObjectDefinitionHolder
+ {
+ private IObjectDefinition objectDefinition;
+ private string objectName;
+ private string[] aliases;
+
+ #region Constructor () / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The object definition to be held by this instance.
+ ///
+ ///
+ /// The name of the object definition.
+ ///
+ public ObjectDefinitionHolder(IObjectDefinition definition, string name)
+ : this(definition, name, StringUtils.EmptyStrings)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The object definition to be held by this instance.
+ ///
+ /// The name of the object.
+ ///
+ /// Any aliases for the supplied
+ ///
+ public ObjectDefinitionHolder(
+ IObjectDefinition definition, string name, string[] aliases)
+ {
+ this.objectDefinition = definition;
+ this.objectName = name;
+ this.aliases = aliases == null ? StringUtils.EmptyStrings : aliases;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The held by this
+ /// instance.
+ ///
+ public IObjectDefinition ObjectDefinition
+ {
+ get { return objectDefinition; }
+ }
+
+ ///
+ /// The name of the object definition.
+ ///
+ public string ObjectName
+ {
+ get { return objectName; }
+ }
+
+ ///
+ /// Any aliases for the object definition.
+ ///
+ ///
+ ///
+ /// Guaranteed to never return ; if the associated
+ ///
+ /// does not have any aliases associated with it, then an empty
+ /// array will be returned.
+ ///
- /// The primary motivation of this class is to avoid having a client object
- /// directly calling the
- ///
- /// method to get a prototype object out of an
- /// , which would be a
- /// violation of the inversion of control principle. With the use of this
- /// class, the client object can be fed an
- /// as a property
- /// that directly returns one target prototype object.
- ///
- ///
- /// The object referred to by the value of the
- ///
- /// property does not have to be a prototype object, but there is little
- /// to no point in using this class in conjunction with a singleton object.
- ///
- ///
- ///
- ///
- /// The following XML configuration snippet illustrates the use of this
- /// class...
- ///
+ /// The primary motivation of this class is to avoid having a client object
+ /// directly calling the
+ ///
+ /// method to get a prototype object out of an
+ /// , which would be a
+ /// violation of the inversion of control principle. With the use of this
+ /// class, the client object can be fed an
+ /// as a property
+ /// that directly returns one target prototype object.
+ ///
+ ///
+ /// The object referred to by the value of the
+ ///
+ /// property does not have to be a prototype object, but there is little
+ /// to no point in using this class in conjunction with a singleton object.
+ ///
+ ///
+ ///
+ ///
+ /// The following XML configuration snippet illustrates the use of this
+ /// class...
+ ///
- /// Usually, the target object will reside in a different object
- /// definition file, using this
- /// to link it in
- /// and expose it under a different name. Effectively, this corresponds
- /// to an alias for the target object.
- ///
- ///
- /// For XML based object definition files, a <alias>
- /// tag is available that effectively achieves the same.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: ObjectReferenceFactoryObject.cs,v 1.3 2007/03/16 04:01:38 aseovic Exp $
- ///
- [Serializable]
- public sealed class ObjectReferenceFactoryObject
- : IFactoryObject, IObjectFactoryAware
- {
- private string _targetObjectName;
- private IObjectFactory _objectFactory;
-
- ///
- /// The name of the target object.
- ///
- ///
- ///
- /// The target object may potentially be defined in a different object
- /// definition file.
- ///
+ /// Usually, the target object will reside in a different object
+ /// definition file, using this
+ /// to link it in
+ /// and expose it under a different name. Effectively, this corresponds
+ /// to an alias for the target object.
+ ///
+ ///
+ /// For XML based object definition files, a <alias>
+ /// tag is available that effectively achieves the same.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public sealed class ObjectReferenceFactoryObject
+ : IFactoryObject, IObjectFactoryAware
+ {
+ private string _targetObjectName;
+ private IObjectFactory _objectFactory;
+
+ ///
+ /// The name of the target object.
+ ///
+ ///
+ ///
+ /// The target object may potentially be defined in a different object
+ /// definition file.
+ ///
- /// Instances of this class override already existing values, and is
- /// thus best suited to replacing defaults. If you need to replace
- /// placeholder values, consider using the
- ///
- /// class instead.
- ///
- ///
- /// In contrast to the
- ///
- /// class, the original object definition can have default
- /// values or no values at all for such object properties. If an overriding
- /// configuration file does not have an entry for a certain object property,
- /// the default object value is left as is. Also note that it is not
- /// immediately obvious to discern which object definitions will be mutated by
- /// one or more
- /// s
- /// simply by looking at the object configuration.
- ///
- ///
- /// Each line in a referenced configuration file is expected to take the
- /// following form...
- ///
- ///
- ///
- ///
- ///
- /// The name.property key refers to the object name and the
- /// property that is to be overridden; and the value is the overridding
- /// value that will be inserted into the appropriate object definition's
- /// named property.
- ///
- ///
- /// Please note that in the case of multiple
- /// s
- /// that define different values for the same object definition value, the
- /// last overridden value will win (due to the fact that the values
- /// supplied by previous
- /// s
- /// will be overridden).
- ///
- ///
- ///
- ///
- /// The following XML context definition defines an object that has a number
- /// of properties, all of which have default values...
- ///
+ /// Instances of this class override already existing values, and is
+ /// thus best suited to replacing defaults. If you need to replace
+ /// placeholder values, consider using the
+ ///
+ /// class instead.
+ ///
+ ///
+ /// In contrast to the
+ ///
+ /// class, the original object definition can have default
+ /// values or no values at all for such object properties. If an overriding
+ /// configuration file does not have an entry for a certain object property,
+ /// the default object value is left as is. Also note that it is not
+ /// immediately obvious to discern which object definitions will be mutated by
+ /// one or more
+ /// s
+ /// simply by looking at the object configuration.
+ ///
+ ///
+ /// Each line in a referenced configuration file is expected to take the
+ /// following form...
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The name.property key refers to the object name and the
+ /// property that is to be overridden; and the value is the overridding
+ /// value that will be inserted into the appropriate object definition's
+ /// named property.
+ ///
+ ///
+ /// Please note that in the case of multiple
+ /// s
+ /// that define different values for the same object definition value, the
+ /// last overridden value will win (due to the fact that the values
+ /// supplied by previous
+ /// s
+ /// will be overridden).
+ ///
+ ///
+ ///
+ ///
+ /// The following XML context definition defines an object that has a number
+ /// of properties, all of which have default values...
+ ///
- /// The target object can be specified directly or via an object name (see
- /// example below).
- ///
- ///
- /// Please note that the
- /// is an implementation, and as such has
- /// to comply with the contract of the
- /// interface; more specifically, this means that the end result of the property lookup path
- /// evaluation cannot be (
- /// implementations are not permitted to return ). If the resut of a
- /// property lookup path evaluates to , an exception will be thrown.
- ///
- /// This would most likely be an inner object, but can of course be
- /// any object reference.
- ///
- ///
- ///
- /// The target object that the property path lookup is to be applied to.
- ///
- ///
- public object TargetObject
- {
- set { this.targetObjectWrapper = new ObjectWrapper(value); }
- }
-
- ///
- /// The (object) name of the target object that the property path lookup
- /// is to be applied to.
- ///
- ///
- ///
- /// Please note that any leading or trailing whitespace will be
- /// trimmed from this name prior to resolution. The implication of this is that
- /// one cannot use the
- /// class in conjunction with object names that start or end with whitespace.
- ///
- ///
- ///
- /// The (object) name of the target object that the property path lookup
- /// is to be applied to.
- ///
- ///
- public string TargetObjectName
- {
- set
- {
- if (value != null)
- {
- value = value.Trim();
- }
- this.targetObjectName = value;
- }
- }
-
- ///
- /// The property (lookup) path to be applied to the target object.
- ///
- ///
- ///
- /// Please note that any leading or trailing whitespace will be
- /// trimmed from this path prior to resolution. Whitespace is not a valid
- /// identifier for property names (in part or whole) in CLS-based languages,
- /// so this is a not unreasonable action. Please also note that whitespace
- /// that is embedded within the property path will be left as-is (which may
- /// or may not result in an error being thrown, depending on the context of
- /// the whitespace).
- ///
- ///
- ///
- ///
- /// Examples of such property lookup paths can be seen below; note that
- /// property lookup paths can be nested to an arbitrary level.
- ///
- ///
- /// name.length
- /// accountManager.account['the key'].name
- /// accounts[0].name
- ///
- ///
- ///
- /// The property (lookup) path to be applied to the target object.
- ///
- public string PropertyPath
- {
- set
- {
- if (value != null)
- {
- value = value.Trim();
- }
- this.propertyPath = value;
- }
- }
-
- ///
- /// The 'expected' of the result from evaluating the
- /// property path.
- ///
- ///
- ///
- /// This is not necessary for directly specified target objects, or
- /// singleton target objects, where the can
- /// be determined via reflection. Just specify this in case of a
- /// prototype target, provided that you need matching by type (for
- /// example, for autowiring).
- ///
- ///
- /// It is permissable to set the value of this property to
- /// (which in any case is the default value).
- ///
- ///
- ///
- /// The 'expected' of the result from evaluating the
- /// property path.
- ///
- public Type ResultType
- {
- set { this.resultType = value; }
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the object
- /// managed by this factory.
- ///
- ///
- /// An instance (possibly shared or independent) of the object managed by
- /// this factory.
- ///
- ///
- public object GetObject()
- {
- IObjectWrapper target = this.targetObjectWrapper;
- if (target == null)
- {
- // fetch the prototype object object...
- target = new ObjectWrapper(this.objectFactory[this.targetObjectName]);
- }
- object value = target.GetPropertyValue(this.propertyPath);
- if (value == null)
- {
- throw new FatalObjectException("PropertyPathFactoryObject is not allowed to return null, " +
- "but property value for path '" + this.propertyPath + "' is null.");
- }
- return value;
- }
-
- ///
- /// Return the of object that this
- /// creates, or
- /// if not known in advance.
- ///
- ///
- public Type ObjectType
- {
- get { return this.resultType; }
- }
-
- ///
- /// Is the object managed by this factory a singleton or a prototype?
- ///
- ///
- public bool IsSingleton
- {
- get { return false; }
- }
-
- ///
- /// Set the name of the object in the object factory that created this object.
- ///
- ///
- ///
- /// The object name of this
- ///
- /// will be interpreted as "objectName.property" pattern, if neither the
- ///
- ///
- /// have been supplied (set).
- ///
- ///
- /// This allows for concise object definitions with just an id or name.
- ///
+ /// The target object can be specified directly or via an object name (see
+ /// example below).
+ ///
+ ///
+ /// Please note that the
+ /// is an implementation, and as such has
+ /// to comply with the contract of the
+ /// interface; more specifically, this means that the end result of the property lookup path
+ /// evaluation cannot be (
+ /// implementations are not permitted to return ). If the resut of a
+ /// property lookup path evaluates to , an exception will be thrown.
+ ///
+ /// This would most likely be an inner object, but can of course be
+ /// any object reference.
+ ///
+ ///
+ ///
+ /// The target object that the property path lookup is to be applied to.
+ ///
+ ///
+ public object TargetObject
+ {
+ set { this.targetObjectWrapper = new ObjectWrapper(value); }
+ }
+
+ ///
+ /// The (object) name of the target object that the property path lookup
+ /// is to be applied to.
+ ///
+ ///
+ ///
+ /// Please note that any leading or trailing whitespace will be
+ /// trimmed from this name prior to resolution. The implication of this is that
+ /// one cannot use the
+ /// class in conjunction with object names that start or end with whitespace.
+ ///
+ ///
+ ///
+ /// The (object) name of the target object that the property path lookup
+ /// is to be applied to.
+ ///
+ ///
+ public string TargetObjectName
+ {
+ set
+ {
+ if (value != null)
+ {
+ value = value.Trim();
+ }
+ this.targetObjectName = value;
+ }
+ }
+
+ ///
+ /// The property (lookup) path to be applied to the target object.
+ ///
+ ///
+ ///
+ /// Please note that any leading or trailing whitespace will be
+ /// trimmed from this path prior to resolution. Whitespace is not a valid
+ /// identifier for property names (in part or whole) in CLS-based languages,
+ /// so this is a not unreasonable action. Please also note that whitespace
+ /// that is embedded within the property path will be left as-is (which may
+ /// or may not result in an error being thrown, depending on the context of
+ /// the whitespace).
+ ///
+ ///
+ ///
+ ///
+ /// Examples of such property lookup paths can be seen below; note that
+ /// property lookup paths can be nested to an arbitrary level.
+ ///
+ ///
+ /// name.length
+ /// accountManager.account['the key'].name
+ /// accounts[0].name
+ ///
+ ///
+ ///
+ /// The property (lookup) path to be applied to the target object.
+ ///
+ public string PropertyPath
+ {
+ set
+ {
+ if (value != null)
+ {
+ value = value.Trim();
+ }
+ this.propertyPath = value;
+ }
+ }
+
+ ///
+ /// The 'expected' of the result from evaluating the
+ /// property path.
+ ///
+ ///
+ ///
+ /// This is not necessary for directly specified target objects, or
+ /// singleton target objects, where the can
+ /// be determined via reflection. Just specify this in case of a
+ /// prototype target, provided that you need matching by type (for
+ /// example, for autowiring).
+ ///
+ ///
+ /// It is permissable to set the value of this property to
+ /// (which in any case is the default value).
+ ///
+ ///
+ ///
+ /// The 'expected' of the result from evaluating the
+ /// property path.
+ ///
+ public Type ResultType
+ {
+ set { this.resultType = value; }
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the object
+ /// managed by this factory.
+ ///
+ ///
+ /// An instance (possibly shared or independent) of the object managed by
+ /// this factory.
+ ///
+ ///
+ public object GetObject()
+ {
+ IObjectWrapper target = this.targetObjectWrapper;
+ if (target == null)
+ {
+ // fetch the prototype object object...
+ target = new ObjectWrapper(this.objectFactory[this.targetObjectName]);
+ }
+ object value = target.GetPropertyValue(this.propertyPath);
+ if (value == null)
+ {
+ throw new FatalObjectException("PropertyPathFactoryObject is not allowed to return null, " +
+ "but property value for path '" + this.propertyPath + "' is null.");
+ }
+ return value;
+ }
+
+ ///
+ /// Return the of object that this
+ /// creates, or
+ /// if not known in advance.
+ ///
+ ///
+ public Type ObjectType
+ {
+ get { return this.resultType; }
+ }
+
+ ///
+ /// Is the object managed by this factory a singleton or a prototype?
+ ///
+ ///
+ public bool IsSingleton
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Set the name of the object in the object factory that created this object.
+ ///
+ ///
+ ///
+ /// The object name of this
+ ///
+ /// will be interpreted as "objectName.property" pattern, if neither the
+ ///
+ ///
+ /// have been supplied (set).
+ ///
+ ///
+ /// This allows for concise object definitions with just an id or name.
+ ///
- /// The default placeholder syntax follows the NAnt style: ${...}.
- /// Instances of this class can be configured in the same way as any other
- /// object in a Spring.NET container, and so custom placeholder prefix
- /// and suffix values can be set via the
- /// and properties.
- ///
- ///
- ///
- /// The following example XML context definition defines an object that has
- /// a number of placeholders. The placeholders can easily be distinguished
- /// by the presence of the ${} characters.
- ///
- /// The associated XML configuration file for the above example containing the
- /// values for the placeholders would contain a snippet such as ..
- ///
- /// The preceding XML snippet listing the various property keys and their
- /// associated values needs to be inserted into the .NET config file of
- /// your application (or Web.config file for your ASP.NET web application,
- /// as the case may be), like so...
- ///
- ///
- /// checks simple property values, lists, dictionaries, sets, constructor
- /// values, object type name, and object names in
- /// runtime object references (
- /// ).
- /// Furthermore, placeholder values can also cross-reference other
- /// placeholders, in the manner of the following example where the
- /// rootPath property is cross-referenced by the subPath
- /// property.
- ///
- /// In contrast to the
- ///
- /// class, this configurer only permits the replacement of explicit
- /// placeholders in object definitions. Therefore, the original definition
- /// cannot specify any default values for its object properties, and the
- /// placeholder configuration file is expected to contain an entry for each
- /// defined placeholder. That is, if an object definition contains a
- /// placeholder ${foo}, there should be an associated
- /// <add key="foo" value="..."/> entry in the
- /// referenced placeholder configuration file. Default property values
- /// can be defined via the inherited
- ///
- /// collection to overcome any perceived limitation of this feature.
- ///
- ///
- /// If a configurer cannot resolve a placeholder, and the value of the
- ///
- /// property is currently set to , an
- ///
- /// will be thrown. If you want to resolve properties from multiple configuration
- /// resources, simply specify multiple resources via the
- ///
- /// property. Finally, please note that you can also define multiple
- ///
- /// instances, each with their own custom placeholder syntax.
- ///
- ///
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: PropertyPlaceholderConfigurer.cs,v 1.23 2007/08/02 22:18:32 markpollack Exp $
- ///
- ///
- ///
- [Serializable]
- public class PropertyPlaceholderConfigurer : PropertyResourceConfigurer
- {
- ///
- /// The default placeholder prefix.
- ///
- public const string DefaultPlaceholderPrefix = "${";
-
- ///
- /// The default placeholder suffix.
- ///
- public const string DefaultPlaceholderSuffix = "}";
-
- private ILog logger = LogManager.GetLogger(typeof (PropertyPlaceholderConfigurer));
- private bool ignoreUnresolvablePlaceholders = false;
- private string placeholderPrefix = DefaultPlaceholderPrefix;
- private string placeholderSuffix = DefaultPlaceholderSuffix;
-
- private EnvironmentVariableMode environmentVariableMode = EnvironmentVariableMode.Fallback;
-
-
- #region Properties
- ///
- /// The placeholder prefix (the default is ${).
- ///
- ///
- public string PlaceholderPrefix
- {
- set { placeholderPrefix = value; }
- }
-
- ///
- /// The placeholder suffix (the default is })
- ///
- ///
- public string PlaceholderSuffix
- {
- set { placeholderSuffix = value; }
- }
-
- ///
- /// Indicates whether unresolved placeholders should be ignored.
- ///
- public bool IgnoreUnresolvablePlaceholders
- {
- get { return ignoreUnresolvablePlaceholders; }
- set { ignoreUnresolvablePlaceholders = value; }
- }
-
- ///
- /// Controls how environment variables will be used to
- /// replace property placeholders.
- ///
- ///
- ///
- /// See the overview of the
- ///
- /// enumeration for the available options.
- ///
- ///
- public EnvironmentVariableMode EnvironmentVariableMode
- {
- set { environmentVariableMode = value; }
- }
-
- #endregion
-
- ///
- /// Apply the given properties to the supplied
- /// .
- ///
- ///
- /// The
- /// used by the application context.
- ///
- /// The properties to apply.
- ///
- /// If an error occured.
- ///
- protected override void ProcessProperties(
- IConfigurableListableObjectFactory factory, NameValueCollection props)
- {
- IVariableSource variableSource = new PlaceholderResolvingStringVariableSource(this, props);
- ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(variableSource);
-
- string[] objectDefinitionNames = factory.GetObjectDefinitionNames();
- for (int i = 0; i < objectDefinitionNames.Length; ++i)
- {
- string name = objectDefinitionNames[i];
- IObjectDefinition definition = factory.GetObjectDefinition(name);
- try
- {
- visitor.VisitObjectDefinition(definition);
- }
- catch (ObjectDefinitionStoreException ex)
- {
- throw new ObjectDefinitionStoreException(
- definition.ResourceDescription, name, ex.Message);
- }
- }
- }
-
-
-
-
-
-
- ///
- /// Parse values recursively to be able to resolve cross-references between
- /// placeholder values.
- ///
- ///
- /// The map of constructor arguments / property values.
- ///
- /// The string to be resolved.
- /// The placeholders that have already been visited
- /// during the current resolution attempt (used to detect circular references
- /// between placeholders). Only non-null if we're parsing a nested placeholder.
- ///
- /// If an error occurs.
- ///
- /// The resolved string.
- public virtual string ParseString(
- NameValueCollection properties, string strVal, ISet visitedPlaceholders)
- {
- int startIndex = strVal.IndexOf(placeholderPrefix);
- while (startIndex != -1)
- {
- int endIndex = strVal.IndexOf(
- placeholderSuffix, startIndex + placeholderPrefix.Length);
- if (endIndex != -1)
- {
- int pos = startIndex + placeholderPrefix.Length;
- string placeholder = strVal.Substring(pos, endIndex - pos);
- if (visitedPlaceholders.Contains(placeholder))
- {
- throw new ObjectDefinitionStoreException(
- string.Format(
- CultureInfo.InvariantCulture,
- "Circular placeholder reference '{0}' detected " +
- "in property definitions [{1}].",
- placeholder, properties));
- }
- visitedPlaceholders.Add(placeholder);
- string resolvedValue = ResolvePlaceholder(placeholder, properties, environmentVariableMode);
- if (resolvedValue != null)
- {
- resolvedValue = ParseString(properties, resolvedValue, visitedPlaceholders);
-
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue));
- }
-
- #endregion
-
- strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1);
- startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length);
- }
- else if (ignoreUnresolvablePlaceholders)
- {
- // simply return the unprocessed value...
- return strVal;
- }
- else
- {
- throw new ObjectDefinitionStoreException(string.Format(
- CultureInfo.InvariantCulture,
- "Could not resolve placeholder '{0}'.", placeholder));
- }
- visitedPlaceholders.Remove(placeholder);
- }
- else
- {
- startIndex = -1;
- }
- }
- return strVal;
- }
-
- ///
- /// Resolve the given placeholder using the given name value collection,
- /// performing an environment variables check according to the given mode.
- ///
- ///
- ///
- /// The default implementation delegates to
- ///
- /// before/afer the environment variable check. Subclasses can override
- /// this for custom resolution strategies, including customized points
- /// for the environment properties check.
- ///
- ///
- /// The placeholder to resolve
- ///
- /// The merged name value collection of this configurer.
- ///
- /// The environment variable mode.
- ///
- /// The resolved value or if none.
- ///
- ///
- protected virtual string ResolvePlaceholder(string placeholder,
- NameValueCollection props,
- EnvironmentVariableMode mode)
- {
- string propertyValue = null;
- if (mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Override)
- {
- propertyValue = Environment.GetEnvironmentVariable(placeholder);
- }
- if (propertyValue == null)
- {
- propertyValue = ResolvePlaceholder(placeholder, props);
- }
- if (propertyValue == null
- && mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Fallback)
- {
- propertyValue = Environment.GetEnvironmentVariable(placeholder);
- }
- return propertyValue;
- }
-
- ///
- /// Resolve the given placeholder using the given name value collection.
- ///
- ///
- ///
- /// This (the default) implementation simply looks up the value of the
- /// supplied key.
- ///
- ///
- /// Subclasses can override this for customized placeholder-to-key
- /// mappings or custom resolution strategies, possibly just using the
- /// given name value collection as fallback.
- ///
+ /// The default placeholder syntax follows the NAnt style: ${...}.
+ /// Instances of this class can be configured in the same way as any other
+ /// object in a Spring.NET container, and so custom placeholder prefix
+ /// and suffix values can be set via the
+ /// and properties.
+ ///
+ ///
+ ///
+ /// The following example XML context definition defines an object that has
+ /// a number of placeholders. The placeholders can easily be distinguished
+ /// by the presence of the ${} characters.
+ ///
+ /// The associated XML configuration file for the above example containing the
+ /// values for the placeholders would contain a snippet such as ..
+ ///
+ /// The preceding XML snippet listing the various property keys and their
+ /// associated values needs to be inserted into the .NET config file of
+ /// your application (or Web.config file for your ASP.NET web application,
+ /// as the case may be), like so...
+ ///
+ ///
+ /// checks simple property values, lists, dictionaries, sets, constructor
+ /// values, object type name, and object names in
+ /// runtime object references (
+ /// ).
+ /// Furthermore, placeholder values can also cross-reference other
+ /// placeholders, in the manner of the following example where the
+ /// rootPath property is cross-referenced by the subPath
+ /// property.
+ ///
+ /// In contrast to the
+ ///
+ /// class, this configurer only permits the replacement of explicit
+ /// placeholders in object definitions. Therefore, the original definition
+ /// cannot specify any default values for its object properties, and the
+ /// placeholder configuration file is expected to contain an entry for each
+ /// defined placeholder. That is, if an object definition contains a
+ /// placeholder ${foo}, there should be an associated
+ /// <add key="foo" value="..."/> entry in the
+ /// referenced placeholder configuration file. Default property values
+ /// can be defined via the inherited
+ ///
+ /// collection to overcome any perceived limitation of this feature.
+ ///
+ ///
+ /// If a configurer cannot resolve a placeholder, and the value of the
+ ///
+ /// property is currently set to , an
+ ///
+ /// will be thrown. If you want to resolve properties from multiple configuration
+ /// resources, simply specify multiple resources via the
+ ///
+ /// property. Finally, please note that you can also define multiple
+ ///
+ /// instances, each with their own custom placeholder syntax.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ ///
+ ///
+ ///
+ [Serializable]
+ public class PropertyPlaceholderConfigurer : PropertyResourceConfigurer
+ {
+ ///
+ /// The default placeholder prefix.
+ ///
+ public const string DefaultPlaceholderPrefix = "${";
+
+ ///
+ /// The default placeholder suffix.
+ ///
+ public const string DefaultPlaceholderSuffix = "}";
+
+ private ILog logger = LogManager.GetLogger(typeof (PropertyPlaceholderConfigurer));
+ private bool ignoreUnresolvablePlaceholders = false;
+ private string placeholderPrefix = DefaultPlaceholderPrefix;
+ private string placeholderSuffix = DefaultPlaceholderSuffix;
+
+ private EnvironmentVariableMode environmentVariableMode = EnvironmentVariableMode.Fallback;
+
+
+ #region Properties
+ ///
+ /// The placeholder prefix (the default is ${).
+ ///
+ ///
+ public string PlaceholderPrefix
+ {
+ set { placeholderPrefix = value; }
+ }
+
+ ///
+ /// The placeholder suffix (the default is })
+ ///
+ ///
+ public string PlaceholderSuffix
+ {
+ set { placeholderSuffix = value; }
+ }
+
+ ///
+ /// Indicates whether unresolved placeholders should be ignored.
+ ///
+ public bool IgnoreUnresolvablePlaceholders
+ {
+ get { return ignoreUnresolvablePlaceholders; }
+ set { ignoreUnresolvablePlaceholders = value; }
+ }
+
+ ///
+ /// Controls how environment variables will be used to
+ /// replace property placeholders.
+ ///
+ ///
+ ///
+ /// See the overview of the
+ ///
+ /// enumeration for the available options.
+ ///
+ ///
+ public EnvironmentVariableMode EnvironmentVariableMode
+ {
+ set { environmentVariableMode = value; }
+ }
+
+ #endregion
+
+ ///
+ /// Apply the given properties to the supplied
+ /// .
+ ///
+ ///
+ /// The
+ /// used by the application context.
+ ///
+ /// The properties to apply.
+ ///
+ /// If an error occured.
+ ///
+ protected override void ProcessProperties(
+ IConfigurableListableObjectFactory factory, NameValueCollection props)
+ {
+ IVariableSource variableSource = new PlaceholderResolvingStringVariableSource(this, props);
+ ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(variableSource);
+
+ string[] objectDefinitionNames = factory.GetObjectDefinitionNames();
+ for (int i = 0; i < objectDefinitionNames.Length; ++i)
+ {
+ string name = objectDefinitionNames[i];
+ IObjectDefinition definition = factory.GetObjectDefinition(name);
+ try
+ {
+ visitor.VisitObjectDefinition(definition);
+ }
+ catch (ObjectDefinitionStoreException ex)
+ {
+ throw new ObjectDefinitionStoreException(
+ definition.ResourceDescription, name, ex.Message);
+ }
+ }
+ }
+
+
+
+
+
+
+ ///
+ /// Parse values recursively to be able to resolve cross-references between
+ /// placeholder values.
+ ///
+ ///
+ /// The map of constructor arguments / property values.
+ ///
+ /// The string to be resolved.
+ /// The placeholders that have already been visited
+ /// during the current resolution attempt (used to detect circular references
+ /// between placeholders). Only non-null if we're parsing a nested placeholder.
+ ///
+ /// If an error occurs.
+ ///
+ /// The resolved string.
+ public virtual string ParseString(
+ NameValueCollection properties, string strVal, ISet visitedPlaceholders)
+ {
+ int startIndex = strVal.IndexOf(placeholderPrefix);
+ while (startIndex != -1)
+ {
+ int endIndex = strVal.IndexOf(
+ placeholderSuffix, startIndex + placeholderPrefix.Length);
+ if (endIndex != -1)
+ {
+ int pos = startIndex + placeholderPrefix.Length;
+ string placeholder = strVal.Substring(pos, endIndex - pos);
+ if (visitedPlaceholders.Contains(placeholder))
+ {
+ throw new ObjectDefinitionStoreException(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Circular placeholder reference '{0}' detected " +
+ "in property definitions [{1}].",
+ placeholder, properties));
+ }
+ visitedPlaceholders.Add(placeholder);
+ string resolvedValue = ResolvePlaceholder(placeholder, properties, environmentVariableMode);
+ if (resolvedValue != null)
+ {
+ resolvedValue = ParseString(properties, resolvedValue, visitedPlaceholders);
+
+ #region Instrumentation
+
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue));
+ }
+
+ #endregion
+
+ strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1);
+ startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length);
+ }
+ else if (ignoreUnresolvablePlaceholders)
+ {
+ // simply return the unprocessed value...
+ return strVal;
+ }
+ else
+ {
+ throw new ObjectDefinitionStoreException(string.Format(
+ CultureInfo.InvariantCulture,
+ "Could not resolve placeholder '{0}'.", placeholder));
+ }
+ visitedPlaceholders.Remove(placeholder);
+ }
+ else
+ {
+ startIndex = -1;
+ }
+ }
+ return strVal;
+ }
+
+ ///
+ /// Resolve the given placeholder using the given name value collection,
+ /// performing an environment variables check according to the given mode.
+ ///
+ ///
+ ///
+ /// The default implementation delegates to
+ ///
+ /// before/afer the environment variable check. Subclasses can override
+ /// this for custom resolution strategies, including customized points
+ /// for the environment properties check.
+ ///
+ ///
+ /// The placeholder to resolve
+ ///
+ /// The merged name value collection of this configurer.
+ ///
+ /// The environment variable mode.
+ ///
+ /// The resolved value or if none.
+ ///
+ ///
+ protected virtual string ResolvePlaceholder(string placeholder,
+ NameValueCollection props,
+ EnvironmentVariableMode mode)
+ {
+ string propertyValue = null;
+ if (mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Override)
+ {
+ propertyValue = Environment.GetEnvironmentVariable(placeholder);
+ }
+ if (propertyValue == null)
+ {
+ propertyValue = ResolvePlaceholder(placeholder, props);
+ }
+ if (propertyValue == null
+ && mode == Spring.Objects.Factory.Config.EnvironmentVariableMode.Fallback)
+ {
+ propertyValue = Environment.GetEnvironmentVariable(placeholder);
+ }
+ return propertyValue;
+ }
+
+ ///
+ /// Resolve the given placeholder using the given name value collection.
+ ///
+ ///
+ ///
+ /// This (the default) implementation simply looks up the value of the
+ /// supplied key.
+ ///
+ ///
+ /// Subclasses can override this for customized placeholder-to-key
+ /// mappings or custom resolution strategies, possibly just using the
+ /// given name value collection as fallback.
+ ///
- /// Useful for custom .NET .config files targetted at system administrators
- /// that override object properties configured in the application context.
- ///
- ///
- /// Two concrete implementations are provided in the Spring.NET core library:
- ///
- ///
- ///
- ///
- /// for <add key="placeholderKey" value="..."/> style
- /// overriding (pushing values from a .NET .config file into object
- /// definitions).
- ///
- ///
- ///
- ///
- ///
- /// for replacing "${...}" placeholders (pulling values from a .NET .config
- /// file into object definitions).
- ///
- ///
- ///
- ///
- ///
- /// Please refer to the API documentation for the concrete implementations
- /// listed above for example usage.
- ///
- ///
- /// Juergen Hoeller
- /// Simon White (.NET)
- ///
- ///
- /// $Id: PropertyResourceConfigurer.cs,v 1.19 2007/08/27 14:49:42 oakinger Exp $
- [Serializable]
- public abstract class PropertyResourceConfigurer
- : IObjectFactoryPostProcessor, IOrdered
- {
- ///
- /// The default configuration section name to use if none is explictly supplied.
- ///
- ///
- public const string DefaultConfigSectionName = "spring-config";
-
- #region Fields
-
- private static readonly ILog _log = LogManager.GetLogger(typeof(PropertyResourceConfigurer));
-
- private int _order = Int32.MaxValue; // default: same as non-Ordered
- private NameValueCollection _defaultProperties;
- private IResource[] _locations;
- private string[] _configSections;
- private bool _ignoreResourceNotFound = false;
- private bool _lastLocationOverrides = true;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected PropertyResourceConfigurer()
- {
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The policy for resolving conflicting property overrides from
- /// several resources.
- ///
- ///
- ///
- /// When merging conflicting property overrides from several resources,
- /// should append an override with the same key be appended to the
- /// current value, or should the property override from the last resource
- /// processed override previous values?
- ///
- ///
- /// The default value is ; i.e. a property
- /// override from the last resource to be processed overrides previous
- /// values.
- ///
- ///
- ///
- /// if the property override from the last resource
- /// processed overrides previous values.
- ///
- public bool LastLocationOverrides
- {
- set { _lastLocationOverrides = value; }
- }
-
- ///
- /// Return the order value of this object, where a higher value means greater in
- /// terms of sorting.
- ///
- /// The order value.
- ///
- public int Order
- {
- get { return _order; }
- set { _order = value; }
- }
-
- ///
- /// The default properties to be applied.
- ///
- ///
- ///
- /// These are to be considered defaults, to be overridden by values
- /// loaded from other resources.
- ///
- ///
- public NameValueCollection Properties
- {
- get { return _defaultProperties; }
- set { _defaultProperties = value; }
- }
-
- ///
- /// The location of the .NET .config file that contains the property
- /// overrides that are to be applied.
- ///
- public IResource Location
- {
- set { _locations = new IResource[] {value}; }
- }
-
- ///
- /// The locations of the .NET .config files containing the property
- /// overrides that are to be applied.
- ///
- public IResource[] Locations
- {
- set { _locations = value; }
- }
-
- ///
- /// The configuration sections to look for within the .config files.
- ///
- ///
- ///
- public string[] ConfigSections
- {
- get
- {
- if (_configSections == null
- || _configSections.Length == 0)
- {
- _configSections = new string[] {DefaultConfigSectionName};
- }
- return _configSections;
- }
- set { _configSections = value; }
- }
-
- ///
- /// Should a failure to find a .config file be ignored?
- ///
- ///
- ///
- /// is only appropriate if the .config file is
- /// completely optional. The default is .
- ///
- ///
- ///
- /// if a failure to find a .config file is to be
- /// ignored.
- ///
- public bool IgnoreResourceNotFound
- {
- set { _ignoreResourceNotFound = value; }
- }
-
- #endregion
-
- ///
- /// Modify the application context's internal object factory after its
- /// standard initialization.
- ///
- ///
- /// The object factory used by the application context.
- ///
- ///
- /// In case of errors.
- ///
- ///
- public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory)
- {
- try
- {
- NameValueCollection properties = new NameValueCollection();
- InitializeWithDefaultProperties(properties);
- LoadProperties(properties);
- ProcessProperties(factory, properties);
- }
- catch (Exception ex)
- {
- if (typeof(ObjectsException).IsInstanceOfType(ex))
- {
- throw;
- }
- else
- {
- throw new ObjectsException(
- "Errored while postprocessing an object factory.", ex);
- }
- }
- }
-
- ///
- /// Loads properties from the configuration sections
- /// specified in into .
- ///
- /// The instance to be filled with properties.
- protected virtual void LoadProperties(NameValueCollection properties)
- {
- string[] configSections = ConfigSections;
- if (_locations != null)
- {
- ValidateConfigSections(configSections);
- bool usingMultipleConfigSections = configSections.Length > 1;
- int sectionNameIndex = 0;
- foreach (IResource resource in _locations)
- {
- #region Instrumentation
-
- if (_log.IsDebugEnabled)
- {
- _log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Loading configuration from '{0}'.", resource));
- }
-
- #endregion
-
- string sectionName = configSections[sectionNameIndex];
- if (resource is ConfigSectionResource)
- {
- ConfigurationReader.PopulateFromAppConfig(
- properties, sectionName, _lastLocationOverrides);
- }
- else
- {
- if (resource.Exists)
- {
- ConfigurationReader.Read(
- resource, sectionName, properties, _lastLocationOverrides);
- }
- else
- {
- string errorMessage = "Could not load configuration from " + resource;
- if (_ignoreResourceNotFound)
- {
- #region Instrumentation
-
- if (_log.IsWarnEnabled)
- {
- _log.Warn(errorMessage);
- }
-
- #endregion
- }
- else
- {
- throw new ObjectInitializationException(errorMessage);
- }
- }
- }
- if (usingMultipleConfigSections)
- {
- ++sectionNameIndex;
- }
- }
- }
- else
- {
- foreach (string sectionName in configSections)
- {
- ConfigurationReader.PopulateFromAppConfig(
- properties, sectionName, _lastLocationOverrides);
- }
- }
- }
-
- ///
- /// Apply the given properties to the supplied
- /// .
- ///
- ///
- /// The
- /// used by the application context.
- ///
- /// The properties to apply.
- ///
- /// If an error occured.
- ///
- protected abstract void ProcessProperties(
- IConfigurableListableObjectFactory factory,
- NameValueCollection props);
-
- ///
- /// Validates the supplied .
- ///
- ///
- ///
- /// Basically, if external locations are specified, ensure that either
- /// one or a like number of config sections are also specified.
- ///
+ /// Useful for custom .NET .config files targetted at system administrators
+ /// that override object properties configured in the application context.
+ ///
+ ///
+ /// Two concrete implementations are provided in the Spring.NET core library:
+ ///
+ ///
+ ///
+ ///
+ /// for <add key="placeholderKey" value="..."/> style
+ /// overriding (pushing values from a .NET .config file into object
+ /// definitions).
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// for replacing "${...}" placeholders (pulling values from a .NET .config
+ /// file into object definitions).
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Please refer to the API documentation for the concrete implementations
+ /// listed above for example usage.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ ///
+ ///
+ [Serializable]
+ public abstract class PropertyResourceConfigurer
+ : IObjectFactoryPostProcessor, IOrdered
+ {
+ ///
+ /// The default configuration section name to use if none is explictly supplied.
+ ///
+ ///
+ public const string DefaultConfigSectionName = "spring-config";
+
+ #region Fields
+
+ private static readonly ILog _log = LogManager.GetLogger(typeof(PropertyResourceConfigurer));
+
+ private int _order = Int32.MaxValue; // default: same as non-Ordered
+ private NameValueCollection _defaultProperties;
+ private IResource[] _locations;
+ private string[] _configSections;
+ private bool _ignoreResourceNotFound = false;
+ private bool _lastLocationOverrides = true;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected PropertyResourceConfigurer()
+ {
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The policy for resolving conflicting property overrides from
+ /// several resources.
+ ///
+ ///
+ ///
+ /// When merging conflicting property overrides from several resources,
+ /// should append an override with the same key be appended to the
+ /// current value, or should the property override from the last resource
+ /// processed override previous values?
+ ///
+ ///
+ /// The default value is ; i.e. a property
+ /// override from the last resource to be processed overrides previous
+ /// values.
+ ///
+ ///
+ ///
+ /// if the property override from the last resource
+ /// processed overrides previous values.
+ ///
+ public bool LastLocationOverrides
+ {
+ set { _lastLocationOverrides = value; }
+ }
+
+ ///
+ /// Return the order value of this object, where a higher value means greater in
+ /// terms of sorting.
+ ///
+ /// The order value.
+ ///
+ public int Order
+ {
+ get { return _order; }
+ set { _order = value; }
+ }
+
+ ///
+ /// The default properties to be applied.
+ ///
+ ///
+ ///
+ /// These are to be considered defaults, to be overridden by values
+ /// loaded from other resources.
+ ///
+ ///
+ public NameValueCollection Properties
+ {
+ get { return _defaultProperties; }
+ set { _defaultProperties = value; }
+ }
+
+ ///
+ /// The location of the .NET .config file that contains the property
+ /// overrides that are to be applied.
+ ///
+ public IResource Location
+ {
+ set { _locations = new IResource[] {value}; }
+ }
+
+ ///
+ /// The locations of the .NET .config files containing the property
+ /// overrides that are to be applied.
+ ///
+ public IResource[] Locations
+ {
+ set { _locations = value; }
+ }
+
+ ///
+ /// The configuration sections to look for within the .config files.
+ ///
+ ///
+ ///
+ public string[] ConfigSections
+ {
+ get
+ {
+ if (_configSections == null
+ || _configSections.Length == 0)
+ {
+ _configSections = new string[] {DefaultConfigSectionName};
+ }
+ return _configSections;
+ }
+ set { _configSections = value; }
+ }
+
+ ///
+ /// Should a failure to find a .config file be ignored?
+ ///
+ ///
+ ///
+ /// is only appropriate if the .config file is
+ /// completely optional. The default is .
+ ///
+ ///
+ ///
+ /// if a failure to find a .config file is to be
+ /// ignored.
+ ///
+ public bool IgnoreResourceNotFound
+ {
+ set { _ignoreResourceNotFound = value; }
+ }
+
+ #endregion
+
+ ///
+ /// Modify the application context's internal object factory after its
+ /// standard initialization.
+ ///
+ ///
+ /// The object factory used by the application context.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ ///
+ public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory)
+ {
+ try
+ {
+ NameValueCollection properties = new NameValueCollection();
+ InitializeWithDefaultProperties(properties);
+ LoadProperties(properties);
+ ProcessProperties(factory, properties);
+ }
+ catch (Exception ex)
+ {
+ if (typeof(ObjectsException).IsInstanceOfType(ex))
+ {
+ throw;
+ }
+ else
+ {
+ throw new ObjectsException(
+ "Errored while postprocessing an object factory.", ex);
+ }
+ }
+ }
+
+ ///
+ /// Loads properties from the configuration sections
+ /// specified in into .
+ ///
+ /// The instance to be filled with properties.
+ protected virtual void LoadProperties(NameValueCollection properties)
+ {
+ string[] configSections = ConfigSections;
+ if (_locations != null)
+ {
+ ValidateConfigSections(configSections);
+ bool usingMultipleConfigSections = configSections.Length > 1;
+ int sectionNameIndex = 0;
+ foreach (IResource resource in _locations)
+ {
+ #region Instrumentation
+
+ if (_log.IsDebugEnabled)
+ {
+ _log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Loading configuration from '{0}'.", resource));
+ }
+
+ #endregion
+
+ string sectionName = configSections[sectionNameIndex];
+ if (resource is ConfigSectionResource)
+ {
+ ConfigurationReader.PopulateFromAppConfig(
+ properties, sectionName, _lastLocationOverrides);
+ }
+ else
+ {
+ if (resource.Exists)
+ {
+ ConfigurationReader.Read(
+ resource, sectionName, properties, _lastLocationOverrides);
+ }
+ else
+ {
+ string errorMessage = "Could not load configuration from " + resource;
+ if (_ignoreResourceNotFound)
+ {
+ #region Instrumentation
+
+ if (_log.IsWarnEnabled)
+ {
+ _log.Warn(errorMessage);
+ }
+
+ #endregion
+ }
+ else
+ {
+ throw new ObjectInitializationException(errorMessage);
+ }
+ }
+ }
+ if (usingMultipleConfigSections)
+ {
+ ++sectionNameIndex;
+ }
+ }
+ }
+ else
+ {
+ foreach (string sectionName in configSections)
+ {
+ ConfigurationReader.PopulateFromAppConfig(
+ properties, sectionName, _lastLocationOverrides);
+ }
+ }
+ }
+
+ ///
+ /// Apply the given properties to the supplied
+ /// .
+ ///
+ ///
+ /// The
+ /// used by the application context.
+ ///
+ /// The properties to apply.
+ ///
+ /// If an error occured.
+ ///
+ protected abstract void ProcessProperties(
+ IConfigurableListableObjectFactory factory,
+ NameValueCollection props);
+
+ ///
+ /// Validates the supplied .
+ ///
+ ///
+ ///
+ /// Basically, if external locations are specified, ensure that either
+ /// one or a like number of config sections are also specified.
+ ///
- /// Typically used for retrieving public property values.
- ///
- ///
- /// Rick Evans (.NET)
- /// $Id: PropertyRetrievingFactoryObject.cs,v 1.12 2007/07/31 18:16:49 bbaia Exp $
- [Serializable]
- public class PropertyRetrievingFactoryObject : AbstractFactoryObject, IInitializingObject
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public PropertyRetrievingFactoryObject()
- {
- Arguments = new object[] {};
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The of the static property
- /// to be retrieved.
- ///
- public string StaticProperty
- {
- set
- {
- AssertUtils.ArgumentNotNull(value, "StaticProperty");
- TypeAssemblyHolder info = new TypeAssemblyHolder(value);
- string typeName = info.TypeName;
- int indexWherePropertyStarts = 0;
- do
- {
- try
- {
- indexWherePropertyStarts = typeName.LastIndexOf('.');
-
- #region Sanity Check
-
- if (indexWherePropertyStarts == -1
- || indexWherePropertyStarts == typeName.Length)
- {
- throw new ArgumentException(
- "The value passed to the StaticProperty property must be a fully " +
- "qualified Type plus property name: " +
- "e.g. 'Example.MyExampleClass.MyProperty, MyAssembly'");
- }
-
- #endregion
-
- typeName = typeName.Substring(0, indexWherePropertyStarts);
- StringBuilder buffer = new StringBuilder(typeName);
- if (info.IsAssemblyQualified)
- {
- buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator);
- buffer.Append(info.AssemblyName);
- }
- TargetType = TypeResolutionUtils.ResolveType(buffer.ToString());
- }
- catch (TypeLoadException)
- {
- }
- } while (TargetType == null);
- TargetProperty = info.TypeName.Substring(indexWherePropertyStarts + 1);
- }
- }
-
- ///
- /// Arguments for the property invocation.
- ///
- ///
- ///
- /// If this property is not set, or the value passed to the setter invocation
- /// is a null or zero-length array, a property with no arguments is assumed.
- ///
- ///
- public object[] Arguments
- {
- get { return _arguments; }
- set
- {
- if (value != null)
- {
- this._arguments = value;
- }
- }
- }
-
- ///
- /// The name of the property the value of which is to be retrieved.
- ///
- ///
- ///
- /// Refers to either a property or a non-static property,
- /// depending on a target object being set.
- ///
+ /// Typically used for retrieving public property values.
+ ///
+ ///
+ /// Rick Evans (.NET)
+ [Serializable]
+ public class PropertyRetrievingFactoryObject : AbstractFactoryObject, IInitializingObject
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public PropertyRetrievingFactoryObject()
+ {
+ Arguments = new object[] {};
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The of the static property
+ /// to be retrieved.
+ ///
+ public string StaticProperty
+ {
+ set
+ {
+ AssertUtils.ArgumentNotNull(value, "StaticProperty");
+ TypeAssemblyHolder info = new TypeAssemblyHolder(value);
+ string typeName = info.TypeName;
+ int indexWherePropertyStarts = 0;
+ do
+ {
+ try
+ {
+ indexWherePropertyStarts = typeName.LastIndexOf('.');
+
+ #region Sanity Check
+
+ if (indexWherePropertyStarts == -1
+ || indexWherePropertyStarts == typeName.Length)
+ {
+ throw new ArgumentException(
+ "The value passed to the StaticProperty property must be a fully " +
+ "qualified Type plus property name: " +
+ "e.g. 'Example.MyExampleClass.MyProperty, MyAssembly'");
+ }
+
+ #endregion
+
+ typeName = typeName.Substring(0, indexWherePropertyStarts);
+ StringBuilder buffer = new StringBuilder(typeName);
+ if (info.IsAssemblyQualified)
+ {
+ buffer.Append(TypeAssemblyHolder.TypeAssemblySeparator);
+ buffer.Append(info.AssemblyName);
+ }
+ TargetType = TypeResolutionUtils.ResolveType(buffer.ToString());
+ }
+ catch (TypeLoadException)
+ {
+ }
+ } while (TargetType == null);
+ TargetProperty = info.TypeName.Substring(indexWherePropertyStarts + 1);
+ }
+ }
+
+ ///
+ /// Arguments for the property invocation.
+ ///
+ ///
+ ///
+ /// If this property is not set, or the value passed to the setter invocation
+ /// is a null or zero-length array, a property with no arguments is assumed.
+ ///
+ ///
+ public object[] Arguments
+ {
+ get { return _arguments; }
+ set
+ {
+ if (value != null)
+ {
+ this._arguments = value;
+ }
+ }
+ }
+
+ ///
+ /// The name of the property the value of which is to be retrieved.
+ ///
+ ///
+ ///
+ /// Refers to either a property or a non-static property,
+ /// depending on a target object being set.
+ ///
- /// Because the
- /// class implements the
- ///
- /// interface, instances of this class that have been exposed in the
- /// scope of an
- /// will
- /// automatically be picked up by the application context and made
- /// available to the IoC container whenever resolution of IResources is required.
- ///
- ///
- /// Mark Pollack
- /// $Id: ResourceHandlerConfigurer.cs,v 1.3 2007/08/08 17:47:13 bbaia Exp $
- ///
- ///
- [Serializable]
- public class ResourceHandlerConfigurer : AbstractConfigurer
- {
- private IDictionary resourceHandlers;
-
- ///
- /// The IResource implementations, i.e. resource handlers, to register.
- ///
- ///
- ///
- /// The has the
- /// contains the resource protocol name as the key and type as the value.
- /// The key name can either be a string or an object, in which case
- /// ToString() will be used to obtain the string name.
- /// The value can be the fully qualified name of the IResource
- /// implementation, a string, or
- /// an actual of the IResource class
- ///
- ///
+ /// Because the
+ /// class implements the
+ ///
+ /// interface, instances of this class that have been exposed in the
+ /// scope of an
+ /// will
+ /// automatically be picked up by the application context and made
+ /// available to the IoC container whenever resolution of IResources is required.
+ ///
+ ///
+ /// Mark Pollack
+ ///
+ ///
+ [Serializable]
+ public class ResourceHandlerConfigurer : AbstractConfigurer
+ {
+ private IDictionary resourceHandlers;
+
+ ///
+ /// The IResource implementations, i.e. resource handlers, to register.
+ ///
+ ///
+ ///
+ /// The has the
+ /// contains the resource protocol name as the key and type as the value.
+ /// The key name can either be a string or an object, in which case
+ /// ToString() will be used to obtain the string name.
+ /// The value can be the fully qualified name of the IResource
+ /// implementation, a string, or
+ /// an actual of the IResource class
+ ///
+ ///
- /// This is currently the preferred way of injecting resources into view
- /// tier components (such as Windows Forms GUIs and ASP.NET ASPX pages).
- /// A GUI component (typically a Windows Form) is injected with
- /// an instance, and can
- /// then proceed to use the various GetXxx() methods on the
- /// to retrieve images,
- /// strings, custom resources, etc.
- ///
- ///
- /// Mark Pollack
- /// $Id: ResourceManagerFactoryObject.cs,v 1.11 2007/03/16 04:01:39 aseovic Exp $
- ///
- ///
- ///
- [Serializable]
- public class ResourceManagerFactoryObject : AbstractFactoryObject
- {
- private string _baseName;
- private string _assemblyName;
-
- ///
- /// The root name of the resources.
- ///
- ///
- ///
- /// For example, the root name for the resource file named
- /// "MyResource.en-US.resources" is "MyResource".
- ///
+ /// This is currently the preferred way of injecting resources into view
+ /// tier components (such as Windows Forms GUIs and ASP.NET ASPX pages).
+ /// A GUI component (typically a Windows Form) is injected with
+ /// an instance, and can
+ /// then proceed to use the various GetXxx() methods on the
+ /// to retrieve images,
+ /// strings, custom resources, etc.
+ ///
+ ///
+ /// Mark Pollack
+ ///
+ ///
+ ///
+ [Serializable]
+ public class ResourceManagerFactoryObject : AbstractFactoryObject
+ {
+ private string _baseName;
+ private string _assemblyName;
+
+ ///
+ /// The root name of the resources.
+ ///
+ ///
+ ///
+ /// For example, the root name for the resource file named
+ /// "MyResource.en-US.resources" is "MyResource".
+ ///
- /// This does not mark this object as being a reference to
- /// another object in any parent factory.
- ///
- ///
- /// The name of the target object.
- public RuntimeObjectReference(string objectName)
- : this(objectName, false)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This variant constructor allows a client to specifiy whether or not
- /// this object is a reference to another object in a parent factory.
- ///
+ /// This does not mark this object as being a reference to
+ /// another object in any parent factory.
+ ///
+ ///
+ /// The name of the target object.
+ public RuntimeObjectReference(string objectName)
+ : this(objectName, false)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This variant constructor allows a client to specifiy whether or not
+ /// this object is a reference to another object in a parent factory.
+ ///
- /// Because the
- /// class implements the
- ///
- /// interface, instances of this class that have been exposed in the
- /// scope of an
- /// will
- /// automatically be picked up by the application context and made
- /// available to the IoC container whenever resolution of type aliases is required.
- ///
- ///
- /// Mark Pollack
- /// $Id: TypeAliasConfigurer.cs,v 1.6 2007/07/31 18:16:49 bbaia Exp $
- ///
- ///
- [Serializable]
- public class TypeAliasConfigurer : AbstractConfigurer
- {
- private IDictionary types;
-
-
- ///
- /// The type aliases to register.
- ///
- ///
- ///
- /// The has the
- /// contains the alias name as the key and type as the value.
- /// The key name can either be a string or an object, in which case
- /// ToString() will be used to obtain the string name.
- /// the value can be the fully qualified name of the type as a string or
- /// an actual of the class that
- /// being aliased.
- ///
+ /// Because the
+ /// class implements the
+ ///
+ /// interface, instances of this class that have been exposed in the
+ /// scope of an
+ /// will
+ /// automatically be picked up by the application context and made
+ /// available to the IoC container whenever resolution of type aliases is required.
+ ///
+ ///
+ /// Mark Pollack
+ ///
+ ///
+ [Serializable]
+ public class TypeAliasConfigurer : AbstractConfigurer
+ {
+ private IDictionary types;
+
+
+ ///
+ /// The type aliases to register.
+ ///
+ ///
+ ///
+ /// The has the
+ /// contains the alias name as the key and type as the value.
+ /// The key name can either be a string or an object, in which case
+ /// ToString() will be used to obtain the string name.
+ /// the value can be the fully qualified name of the type as a string or
+ /// an actual of the class that
+ /// being aliased.
+ ///
- /// Can be added to object definitions to explicitly specify
- /// a target type for a value,
- /// for example for collection
- /// elements.
- ///
- ///
- /// This holder just stores the value and the target
- /// . The actual conversion will be performed by
- /// the surrounding object factory.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: TypedStringValue.cs,v 1.5 2007/05/29 20:00:20 markpollack Exp $
- [Serializable]
- public class TypedStringValue
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- public TypedStringValue()
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value.
- public TypedStringValue(string value)
- {
- Value = value;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The value that is to be converted.
- ///
- ///
- /// The to convert to.
- ///
- ///
- /// If the supplied is
- /// .
- ///
- public TypedStringValue(string value, Type targetType)
- {
- Value = value;
- TargetType = targetType;
- }
-
- #endregion
-
- ///
- /// The value that is to be converted.
- ///
- ///
- ///
- /// Obviously if the
- ///
- /// is the , no conversion
- /// will actually be performed.
- ///
+ /// Can be added to object definitions to explicitly specify
+ /// a target type for a value,
+ /// for example for collection
+ /// elements.
+ ///
+ ///
+ /// This holder just stores the value and the target
+ /// . The actual conversion will be performed by
+ /// the surrounding object factory.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [Serializable]
+ public class TypedStringValue
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ public TypedStringValue()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ public TypedStringValue(string value)
+ {
+ Value = value;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The value that is to be converted.
+ ///
+ ///
+ /// The to convert to.
+ ///
+ ///
+ /// If the supplied is
+ /// .
+ ///
+ public TypedStringValue(string value, Type targetType)
+ {
+ Value = value;
+ TargetType = targetType;
+ }
+
+ #endregion
+
+ ///
+ /// The value that is to be converted.
+ ///
+ ///
+ ///
+ /// Obviously if the
+ ///
+ /// is the , no conversion
+ /// will actually be performed.
+ ///
- /// All object definitions will have been loaded, but no objects will have
- /// been instantiated yet. This allows for overriding or adding properties
- /// even to eager-initializing objects.
- ///
- ///
- ///
- /// In case of errors.
- ///
- public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory)
- {
- try
- {
- ProcessProperties(factory);
- }
- catch (Exception ex)
- {
- if (typeof (ObjectsException).IsInstanceOfType(ex))
- {
- throw;
- }
- else
- {
- throw new ObjectsException(
- "Errored while postprocessing an object factory.", ex);
- }
- }
- }
-
- #endregion
-
- #region IOrdered Members
-
- ///
- /// Return the order value of this object, where a higher value means greater in
- /// terms of sorting.
- ///
- /// The order value.
- ///
- public int Order
- {
- get { return order; }
- set { order = value; }
- }
-
- #endregion
-
- ///
- /// Apply the property replacement using the specified s for all
- /// object in the supplied
- /// .
- ///
- ///
- /// The
- /// used by the application context.
- ///
- ///
- /// If an error occured.
- ///
- protected virtual void ProcessProperties(IConfigurableListableObjectFactory factory)
- {
- IVariableSource compositeVariableSource =
- new PlaceholderResolvingCompositeVariableSource(variableSourceList, ignoreUnresolvablePlaceholders);
- ObjectDefinitionVisitor visitor = new ObjectDefinitionVisitor(compositeVariableSource);
-
- string[] objectDefinitionNames = factory.GetObjectDefinitionNames();
- for (int i = 0; i < objectDefinitionNames.Length; ++i)
- {
- string name = objectDefinitionNames[i];
- IObjectDefinition definition = factory.GetObjectDefinition(name);
- try
- {
- visitor.VisitObjectDefinition(definition);
- }
- catch (ObjectDefinitionStoreException ex)
- {
- throw new ObjectDefinitionStoreException(
- definition.ResourceDescription, name, ex.Message);
- }
- }
- }
- }
-
- #region Helper class
- internal class PlaceholderResolvingCompositeVariableSource : IVariableSource
- {
- private string placeholderPrefix = "${";
- private string placeholderSuffix = "}";
- private bool ignoreUnresolvablePlaceholders;
-
- private ILog logger = LogManager.GetLogger(typeof (PlaceholderResolvingCompositeVariableSource));
-
- private IList variableSourceList;
-
- public PlaceholderResolvingCompositeVariableSource(IList variableSourceList, bool ignoreUnresolvablePlaceholders)
- {
- this.variableSourceList = variableSourceList;
- this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
- }
-
- #region IVariableSource Members
-
- public string ResolveVariable(string rawStringValue)
- {
- return ParseAndResolveVariable(rawStringValue, new HashedSet());
- }
-
-
- //TODO handle resolved values at are not string - identify this case as only 1 placeholder present?
-
- private string ParseAndResolveVariable(string strVal, ISet visitedPlaceholders)
- {
- int startIndex = strVal.IndexOf(placeholderPrefix);
- while (startIndex != -1)
- {
- int endIndex = strVal.IndexOf(
- placeholderSuffix, startIndex + placeholderPrefix.Length);
- if (endIndex != -1)
- {
- int pos = startIndex + placeholderPrefix.Length;
- string placeholder = strVal.Substring(pos, endIndex - pos);
- if (visitedPlaceholders.Contains(placeholder))
- {
- throw new ObjectDefinitionStoreException(
- string.Format(
- CultureInfo.InvariantCulture,
- "Circular placeholder reference '{0}' detected. ",
- placeholder));
- }
- visitedPlaceholders.Add(placeholder);
- string resolvedValue = ResolvePlaceholderVariable(placeholder);
- if (resolvedValue != null)
- {
- resolvedValue = ParseAndResolveVariable(resolvedValue, visitedPlaceholders);
-
- #region Instrumentation
-
- if (logger.IsDebugEnabled)
- {
- logger.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Resolving placeholder '{0}' to '{1}'.", placeholder, resolvedValue));
- }
-
- #endregion
-
- strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1);
- startIndex = strVal.IndexOf(placeholderPrefix, startIndex + resolvedValue.Length);
- }
- else if (ignoreUnresolvablePlaceholders)
- {
- // simply return the unprocessed value...
- return strVal;
- }
- else
- {
- throw new ObjectDefinitionStoreException(string.Format(
- CultureInfo.InvariantCulture,
- "Could not resolve placeholder '{0}'.", placeholder));
- }
- visitedPlaceholders.Remove(placeholder);
- }
- else
- {
- startIndex = -1;
- }
- }
- return strVal;
- }
-
- private string ResolvePlaceholderVariable(string variableName)
- {
- foreach (IVariableSource variableSource in variableSourceList)
- {
- //TODO handle resolved values at are not strings?
-
- object resolvedValue = variableSource.ResolveVariable(variableName);
- if (resolvedValue is string)
- {
- }
- if (resolvedValue != null)
- {
- if (resolvedValue is string)
- {
- return resolvedValue as string;
- }
- else
- {
- logger.Warn("Placeholder " + variableSource + " resolved to object type [" + resolvedValue.GetType() + "]. Only string type currently supported");
- }
- }
- }
- return null;
- }
-
- #endregion
- }
-
- #endregion
+#region License
+
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using Common.Logging;
+using Spring.Collections;
+using Spring.Core;
+
+namespace Spring.Objects.Factory.Config
+{
+ ///
+ /// Resolves placeholder values in one or more object definitions
+ ///
+ ///
+ /// The placeholder syntax follows the NAnt style: ${...}.
+ /// Placeholders values are resolved against a list of
+ /// s. In case of multiple definitions
+ /// for the same property placeholder name, the first one in the
+ /// list is used.
+ /// Variable substitution is performed on simple property values,
+ /// lists, dictionaries, sets, constructor
+ /// values, object type name, and object names in
+ /// runtime object references (
+ /// ).
+ /// Furthermore, placeholder values can also cross-reference other
+ /// placeholders, in the manner of the following example where the
+ /// rootPath property is cross-referenced by the subPath
+ /// property.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// If a configurer cannot resolve a placeholder, and the value of the
+ ///
+ /// property is currently set to , an
+ ///
+ /// will be thrown.
+ ///
+ /// Mark Pollack
+ public class VariablePlaceholderConfigurer : IObjectFactoryPostProcessor, IOrdered
+ {
+ #region Fields
+ private int order = Int32.MaxValue; // default: same as non-Ordered
+
+ private bool ignoreUnresolvablePlaceholders;
+
+ private IList variableSourceList;
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Sets the list of s that will be used to resolve placeholder names.
+ ///
+ /// A list of s.
+ public IList VariableSources
+ {
+ set { variableSourceList = value; }
+ }
+
+ ///
+ /// Sets that will be used to resolve placeholder names.
+ ///
+ /// A instance.
+ public IVariableSource VariableSource
+ {
+ set
+ {
+ variableSourceList = new ArrayList();
+ variableSourceList.Add(value);
+ }
+ }
+
+ ///
+ /// Indicates whether unresolved placeholders should be ignored.
+ ///
+ public bool IgnoreUnresolvablePlaceholders
+ {
+ set { ignoreUnresolvablePlaceholders = value; }
+ }
+
+ #endregion
+
+ #region IObjectFactoryPostProcessor Members
+
+ ///
+ /// Modify the application context's internal object factory after its
+ /// standard initialization.
+ ///
+ /// The object factory used by the application context.
+ ///
+ ///
+ /// All object definitions will have been loaded, but no objects will have
+ /// been instantiated yet. This allows for overriding or adding properties
+ /// even to eager-initializing objects.
+ ///
- /// This is usually indicated by any of the variants of the
- ///
- /// method returning .
- ///
- ///
- /// A circular reference with an
- /// cannot be solved by eagerly caching singleton instances (as is the
- /// case with normal objects. The reason is that every
- /// needs to be fully
- /// initialized before it can return the created object, while only specific
- /// normal objects need to be initialized - that is, if a collaborating object
- /// actually invokes them on initialization instead of just storing the reference.
- ///
+ /// This is usually indicated by any of the variants of the
+ ///
+ /// method returning .
+ ///
+ ///
+ /// A circular reference with an
+ /// cannot be solved by eagerly caching singleton instances (as is the
+ /// case with normal objects. The reason is that every
+ /// needs to be fully
+ /// initialized before it can return the created object, while only specific
+ /// normal objects need to be initialized - that is, if a collaborating object
+ /// actually invokes them on initialization instead of just storing the reference.
+ ///
- /// If an object implements this interface, it is used as a factory,
- /// not directly as an object. s
- /// can support singletons and prototypes
- /// ()...
- /// please note that an
- /// itself can only ever be a singleton. It is a logic error to configure an
- /// itself to be a prototype.
- ///
+ /// If an object implements this interface, it is used as a factory,
+ /// not directly as an object. s
+ /// can support singletons and prototypes
+ /// ()...
+ /// please note that an
+ /// itself can only ever be a singleton. It is a logic error to configure an
+ /// itself to be a prototype.
+ ///
- /// An implementation of the
- ///
- /// method might perform some additional custom initialization (over and above that
- /// performed by the constructor), or merely check that all mandatory properties
- /// have been set (this last example is a very typical use case of this interface).
- ///
- ///
- /// The use of the
- /// interface
- /// by non-Spring.NET framework code can be avoided (and is generally
- /// discouraged). The Spring.NET container provides support for a generic
- /// initialization method given to the object definition in the object
- /// configuration store (be it XML, or a database, etc). This requires
- /// slightly more configuration (one attribute-value pair in the case of
- /// XML configuration), but removes any dependency on Spring.NET from the
- /// class definition.
- ///
- ///
- /// Rod Johnson
- /// Rick Evans (.NET)
- /// $Id: IInitializingObject.cs,v 1.8 2006/04/09 07:18:48 markpollack Exp $
- ///
- public interface IInitializingObject
- {
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
+ /// An implementation of the
+ ///
+ /// method might perform some additional custom initialization (over and above that
+ /// performed by the constructor), or merely check that all mandatory properties
+ /// have been set (this last example is a very typical use case of this interface).
+ ///
+ ///
+ /// The use of the
+ /// interface
+ /// by non-Spring.NET framework code can be avoided (and is generally
+ /// discouraged). The Spring.NET container provides support for a generic
+ /// initialization method given to the object definition in the object
+ /// configuration store (be it XML, or a database, etc). This requires
+ /// slightly more configuration (one attribute-value pair in the case of
+ /// XML configuration), but removes any dependency on Spring.NET from the
+ /// class definition.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rick Evans (.NET)
+ ///
+ public interface IInitializingObject
+ {
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
- /// implementations that preload
- /// all their objects (for example, DOM-based XML factories) may implement this
- /// interface. This interface is discussed in
- /// "Expert One-on-One J2EE Design and Development", by Rod Johnson.
- ///
- ///
- /// If this is an ,
- /// the return values will not take any
- /// hierarchy into account, but
- /// will relate only to the objects defined in the current factory.
- /// Use the helper class to
- /// get all objects.
- ///
- ///
- /// With the exception of
- /// ,
- /// the methods and properties in this interface are not designed for frequent
- /// invocation. Implementations may be slow.
- ///
- ///
- /// Rod Johnson
- /// Rick Evans (.NET)
- /// $Id: IListableObjectFactory.cs,v 1.12 2007/07/29 19:39:27 markpollack Exp $
- public interface IListableObjectFactory : IObjectFactory
- {
- ///
- /// Check if this object factory contains an object definition with the given name.
- ///
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- /// Ignores any singleton objects that have been registered by other means
- /// than object definitions.
- ///
- ///
- /// The name of the object to look for.
- ///
- /// if this object factory contains an object
- /// definition with the given name.
- ///
- bool ContainsObjectDefinition(string name);
-
- ///
- /// Return the number of objects defined in the factory.
- ///
- ///
- /// The number of objects defined in the factory.
- ///
- int ObjectDefinitionCount { get; }
-
-
- ///
- /// Return the names of all objects defined in this factory.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- string[] GetObjectDefinitionNames();
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- ///
- /// Does consider objects created by s,
- /// or rather it considers the type of objects created by
- /// (which means that
- /// s will be instantiated).
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- string[] GetObjectNamesForType(Type type);
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- ///
- /// Does consider objects created by s,
- /// or rather it considers the type of objects created by
- /// (which means that
- /// s will be instantiated).
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s).
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- string[] GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects);
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- ///
- /// This version of the
- /// method matches all kinds of object definitions, be they singletons, prototypes, or
- /// s. Typically, the results
- /// of this method call will be the same as a call to
- /// IListableObjectFactory.GetObjectsOfType(type,true,true) .
- ///
+ /// implementations that preload
+ /// all their objects (for example, DOM-based XML factories) may implement this
+ /// interface. This interface is discussed in
+ /// "Expert One-on-One J2EE Design and Development", by Rod Johnson.
+ ///
+ ///
+ /// If this is an ,
+ /// the return values will not take any
+ /// hierarchy into account, but
+ /// will relate only to the objects defined in the current factory.
+ /// Use the helper class to
+ /// get all objects.
+ ///
+ ///
+ /// With the exception of
+ /// ,
+ /// the methods and properties in this interface are not designed for frequent
+ /// invocation. Implementations may be slow.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rick Evans (.NET)
+ public interface IListableObjectFactory : IObjectFactory
+ {
+ ///
+ /// Check if this object factory contains an object definition with the given name.
+ ///
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ /// Ignores any singleton objects that have been registered by other means
+ /// than object definitions.
+ ///
+ ///
+ /// The name of the object to look for.
+ ///
+ /// if this object factory contains an object
+ /// definition with the given name.
+ ///
+ bool ContainsObjectDefinition(string name);
+
+ ///
+ /// Return the number of objects defined in the factory.
+ ///
+ ///
+ /// The number of objects defined in the factory.
+ ///
+ int ObjectDefinitionCount { get; }
+
+
+ ///
+ /// Return the names of all objects defined in this factory.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ string[] GetObjectDefinitionNames();
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ ///
+ /// Does consider objects created by s,
+ /// or rather it considers the type of objects created by
+ /// (which means that
+ /// s will be instantiated).
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ string[] GetObjectNamesForType(Type type);
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ ///
+ /// Does consider objects created by s,
+ /// or rather it considers the type of objects created by
+ /// (which means that
+ /// s will be instantiated).
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s).
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ string[] GetObjectNamesForType(Type type, bool includePrototypes, bool includeFactoryObjects);
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ ///
+ /// This version of the
+ /// method matches all kinds of object definitions, be they singletons, prototypes, or
+ /// s. Typically, the results
+ /// of this method call will be the same as a call to
+ /// IListableObjectFactory.GetObjectsOfType(type,true,true) .
+ ///
- /// This is the basic client view of a Spring.NET IoC container; further interfaces
- /// such as and
- ///
- /// are available for specific purposes such as enumeration and configuration.
- ///
- ///
- /// This is the root interface to be implemented by objects that can hold a number
- /// of object definitions, each uniquely identified by a
- /// name. An independent instance of any of these objects can be obtained
- /// (the Prototype design pattern), or a single shared instance can be obtained
- /// (a superior alternative to the Singleton design pattern, in which the instance is a
- /// singleton in the scope of the factory). Which type of instance
- /// will be returned depends on the object factory configuration - the API is the same.
- /// The Singleton approach is more useful and hence more common in practice.
- ///
- ///
- /// The point of this approach is that the IObjectFactory is a central registry of
- /// application components, and centralizes the configuring of application components
- /// (no more do individual objects need to read properties files, for example).
- /// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a
- /// discussion of the benefits of this approach.
- ///
- ///
- /// Normally an IObjectFactory will load object definitions stored in a configuration
- /// source (such as an XML document), and use the
- /// namespace to configure the objects. However, an implementation could simply return
- /// .NET objects it creates as necessary directly in .NET code. There are no
- /// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties
- /// file etc. Implementations are encouraged to support references amongst objects,
- /// to either Singletons or Prototypes.
- ///
- ///
- /// In contrast to the methods in
- /// , all of the methods
- /// in this interface will also check parent factories if this is an
- /// . If an object is
- /// not found in this factory instance, the immediate parent is asked. Objects in
- /// this factory instance are supposed to override objects of the same name in any
- /// parent factory.
- ///
- ///
- /// Object factories are supposed to support the standard object lifecycle interfaces
- /// as far as possible. The maximum set of initialization methods and their standard
- /// order is:
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: IObjectFactory.cs,v 1.17 2007/07/30 15:41:32 markpollack Exp $
- public interface IObjectFactory : IDisposable
- {
- ///
- /// Is this object a singleton?
- ///
- ///
- ///
- /// That is, will
- /// always return the same object?
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to query.
- /// True if the named object is a singleton.
- ///
- /// If there's no such object definition.
- ///
- bool IsSingleton(string name);
-
-
- ///
- /// Determines whether the specified object name is prototype. That is, will GetObject
- /// always return independent instances?
- ///
- /// This method returning false does not clearly indicate a singleton object.
- /// It indicated non-independent instances, which may correspond to a scoped object as
- /// well. use the IsSingleton property to explicitly check for a shared
- /// singleton instance.
- /// Translates aliases back to the corresponding canonical object name. Will ask the
- /// parent factory if the object can not be found in this factory instance.
- ///
- ///
- ///
- /// The name of the object to query
- ///
- /// true if the specified object name will always deliver independent instances; otherwise, false.
- ///
- /// if there is no object with the given name.
- bool IsPrototype(string name);
-
- ///
- /// Does this object factory contain an object with the given name?
- ///
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to query.
- /// True if an object with the given name is defined.
- bool ContainsObject(string name);
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The object name to check for aliases.
- /// The aliases, or an empty array if none.
- ///
- /// If there's no such object definition.
- ///
- string[] GetAliases(string name);
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// This is the indexer for the
- /// interface.
- ///
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- object this[string name] { get; }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- object GetObject(string name);
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. If there is no factory method and the
- /// arguments are not null, then match the argument values by type and
- /// call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the supplied is .
- ///
- object GetObject(string name, object[] arguments);
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- object GetObject(string name, Type requiredType, object[] arguments);
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// Provides a measure of type safety by throwing an exception if the object is
- /// not of the required .
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- ///
- /// the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- object GetObject(string name, Type requiredType);
-
- ///
- /// Determine the type of the object with the given name.
- ///
- ///
- ///
- /// More specifically, checks the type of object that
- /// would return.
- /// For an , returns the type
- /// of object that the creates.
- ///
- ///
- /// The name of the object to query.
- ///
- /// The type of the object or if not determinable.
- ///
- Type GetType(string name);
-
-
-
- ///
- /// Determines whether the object with the given name matches the specified type.
- ///
- /// More specifically, check whether a GetObject call for the given name
- /// would return an object that is assignable to the specified target type.
- /// Translates aliases back to the corresponding canonical bean name.
- /// Will ask the parent factory if the bean cannot be found in this factory instance.
- ///
- /// The name of the object to query.
- /// Type of the target to match against.
- ///
- /// true if the object type matches; otherwise, false
- /// if it doesn't match or cannot be determined yet.
- ///
- /// Ff there is no object with the given name
- ///
- bool IsTypeMatch(string name, Type targetType);
-
- ///
- /// Injects dependencies into the supplied instance
- /// using the named object definition.
- ///
- ///
- ///
- /// In addition to being generally useful, typically this method is used to provide
- /// dependency injection functionality for objects that are instantiated outwith the
- /// control of a developer. A case in point is the way that the current (1.1)
- /// ASP.NET classes instantiate web controls... the instantiation takes place within
- /// a private method of a compiled page, and thus cannot be hooked into the
- /// typical Spring.NET IOC container lifecycle for dependency injection.
- ///
+ /// This is the basic client view of a Spring.NET IoC container; further interfaces
+ /// such as and
+ ///
+ /// are available for specific purposes such as enumeration and configuration.
+ ///
+ ///
+ /// This is the root interface to be implemented by objects that can hold a number
+ /// of object definitions, each uniquely identified by a
+ /// name. An independent instance of any of these objects can be obtained
+ /// (the Prototype design pattern), or a single shared instance can be obtained
+ /// (a superior alternative to the Singleton design pattern, in which the instance is a
+ /// singleton in the scope of the factory). Which type of instance
+ /// will be returned depends on the object factory configuration - the API is the same.
+ /// The Singleton approach is more useful and hence more common in practice.
+ ///
+ ///
+ /// The point of this approach is that the IObjectFactory is a central registry of
+ /// application components, and centralizes the configuring of application components
+ /// (no more do individual objects need to read properties files, for example).
+ /// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a
+ /// discussion of the benefits of this approach.
+ ///
+ ///
+ /// Normally an IObjectFactory will load object definitions stored in a configuration
+ /// source (such as an XML document), and use the
+ /// namespace to configure the objects. However, an implementation could simply return
+ /// .NET objects it creates as necessary directly in .NET code. There are no
+ /// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties
+ /// file etc. Implementations are encouraged to support references amongst objects,
+ /// to either Singletons or Prototypes.
+ ///
+ ///
+ /// In contrast to the methods in
+ /// , all of the methods
+ /// in this interface will also check parent factories if this is an
+ /// . If an object is
+ /// not found in this factory instance, the immediate parent is asked. Objects in
+ /// this factory instance are supposed to override objects of the same name in any
+ /// parent factory.
+ ///
+ ///
+ /// Object factories are supposed to support the standard object lifecycle interfaces
+ /// as far as possible. The maximum set of initialization methods and their standard
+ /// order is:
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IObjectFactory : IDisposable
+ {
+ ///
+ /// Is this object a singleton?
+ ///
+ ///
+ ///
+ /// That is, will
+ /// always return the same object?
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to query.
+ /// True if the named object is a singleton.
+ ///
+ /// If there's no such object definition.
+ ///
+ bool IsSingleton(string name);
+
+
+ ///
+ /// Determines whether the specified object name is prototype. That is, will GetObject
+ /// always return independent instances?
+ ///
+ /// This method returning false does not clearly indicate a singleton object.
+ /// It indicated non-independent instances, which may correspond to a scoped object as
+ /// well. use the IsSingleton property to explicitly check for a shared
+ /// singleton instance.
+ /// Translates aliases back to the corresponding canonical object name. Will ask the
+ /// parent factory if the object can not be found in this factory instance.
+ ///
+ ///
+ ///
+ /// The name of the object to query
+ ///
+ /// true if the specified object name will always deliver independent instances; otherwise, false.
+ ///
+ /// if there is no object with the given name.
+ bool IsPrototype(string name);
+
+ ///
+ /// Does this object factory contain an object with the given name?
+ ///
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to query.
+ /// True if an object with the given name is defined.
+ bool ContainsObject(string name);
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The object name to check for aliases.
+ /// The aliases, or an empty array if none.
+ ///
+ /// If there's no such object definition.
+ ///
+ string[] GetAliases(string name);
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// This is the indexer for the
+ /// interface.
+ ///
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ object this[string name] { get; }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ object GetObject(string name);
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. If there is no factory method and the
+ /// arguments are not null, then match the argument values by type and
+ /// call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ object GetObject(string name, object[] arguments);
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ object GetObject(string name, Type requiredType, object[] arguments);
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// Provides a measure of type safety by throwing an exception if the object is
+ /// not of the required .
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ ///
+ /// the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ object GetObject(string name, Type requiredType);
+
+ ///
+ /// Determine the type of the object with the given name.
+ ///
+ ///
+ ///
+ /// More specifically, checks the type of object that
+ /// would return.
+ /// For an , returns the type
+ /// of object that the creates.
+ ///
+ ///
+ /// The name of the object to query.
+ ///
+ /// The type of the object or if not determinable.
+ ///
+ Type GetType(string name);
+
+
+
+ ///
+ /// Determines whether the object with the given name matches the specified type.
+ ///
+ /// More specifically, check whether a GetObject call for the given name
+ /// would return an object that is assignable to the specified target type.
+ /// Translates aliases back to the corresponding canonical bean name.
+ /// Will ask the parent factory if the bean cannot be found in this factory instance.
+ ///
+ /// The name of the object to query.
+ /// Type of the target to match against.
+ ///
+ /// true if the object type matches; otherwise, false
+ /// if it doesn't match or cannot be determined yet.
+ ///
+ /// Ff there is no object with the given name
+ ///
+ bool IsTypeMatch(string name, Type targetType);
+
+ ///
+ /// Injects dependencies into the supplied instance
+ /// using the named object definition.
+ ///
+ ///
+ ///
+ /// In addition to being generally useful, typically this method is used to provide
+ /// dependency injection functionality for objects that are instantiated outwith the
+ /// control of a developer. A case in point is the way that the current (1.1)
+ /// ASP.NET classes instantiate web controls... the instantiation takes place within
+ /// a private method of a compiled page, and thus cannot be hooked into the
+ /// typical Spring.NET IOC container lifecycle for dependency injection.
+ ///
- /// For example, objects can look up collaborating objects via the factory.
- ///
- ///
- /// Note that most objects will choose to receive references to collaborating
- /// objects via respective properties and / or an appropriate constructor.
- ///
- ///
- /// For a list of all object lifecycle methods, see the
- /// API documentation.
- ///
- ///
- /// Rod Johnson
- /// Rick Evans (.NET)
- /// $Id: IObjectFactoryAware.cs,v 1.6 2006/04/09 07:18:48 markpollack Exp $
- public interface IObjectFactoryAware
- {
- ///
- /// Callback that supplies the owning factory to an object instance.
- ///
- ///
- /// Owning
- /// (may not be ). The object can immediately
- /// call methods on the factory.
- ///
- ///
- ///
- /// Invoked after population of normal object properties but before an init
- /// callback like 's
- ///
- /// method or a custom init-method.
- ///
+ /// For example, objects can look up collaborating objects via the factory.
+ ///
+ ///
+ /// Note that most objects will choose to receive references to collaborating
+ /// objects via respective properties and / or an appropriate constructor.
+ ///
+ ///
+ /// For a list of all object lifecycle methods, see the
+ /// API documentation.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rick Evans (.NET)
+ public interface IObjectFactoryAware
+ {
+ ///
+ /// Callback that supplies the owning factory to an object instance.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an init
+ /// callback like 's
+ ///
+ /// method or a custom init-method.
+ ///
- /// Note that most objects will choose to receive references to collaborating
- /// objects via respective properties.
- ///
- ///
- /// For a list of all object lifecycle methods, see the
- /// API documentation.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- public interface IObjectNameAware
- {
-
- ///
- /// Set the name of the object in the object factory that created this object.
- ///
- ///
- /// The name of the object in the factory.
- ///
- ///
- ///
- /// Invoked after population of normal object properties but before an init
- /// callback like 's
- ///
- /// method or a custom init-method.
- ///
+ /// Note that most objects will choose to receive references to collaborating
+ /// objects via respective properties.
+ ///
+ ///
+ /// For a list of all object lifecycle methods, see the
+ /// API documentation.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IObjectNameAware
+ {
+
+ ///
+ /// Set the name of the object in the object factory that created this object.
+ ///
+ ///
+ /// The name of the object in the factory.
+ ///
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an init
+ /// callback like 's
+ ///
+ /// method or a custom init-method.
+ ///
- /// An example of a situation when this exception would be thrown is
- /// in the case of an XML document containing object definitions being
- /// malformed.
- ///
+ /// An example of a situation when this exception would be thrown is
+ /// in the case of an XML document containing object definitions being
+ /// malformed.
+ ///
- /// The nesting hierarchy of an object factory is taken into account by the various methods
- /// exposed by this class.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: ObjectFactoryUtils.cs,v 1.17 2007/07/31 03:47:39 markpollack Exp $
- public sealed class ObjectFactoryUtils
- {
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such has no publicly visible
- /// constructors.
- ///
- ///
- private ObjectFactoryUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// Used to dereference an
- /// and distinguish it from managed objects created by the factory.
- ///
- ///
- ///
- /// For example, if the managed object identified as foo is a
- /// factory, getting &foo will return the factory, not the
- /// instance returned by the factory.
- ///
- ///
- public const string FactoryObjectPrefix = "&";
-
- ///
- /// Count all object definitions in any hierarchy in which this
- /// factory participates.
- ///
- ///
- ///
- /// Includes counts of ancestor object factories.
- ///
- ///
- /// Objects that are "overridden" (specified in a descendant factory
- /// with the same name) are counted only once.
- ///
- ///
- /// The object factory.
- ///
- /// The count of objects including those defined in ancestor factories.
- ///
- public static int CountObjectsIncludingAncestors(IListableObjectFactory factory)
- {
- return ObjectNamesIncludingAncestors(factory).Length;
- }
-
- ///
- /// Return all object names in the factory, including ancestor factories.
- ///
- /// The object factory.
- /// The array of object names, or an empty array if none.
- public static string[] ObjectNamesIncludingAncestors(IListableObjectFactory factory)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectDefinitionNames());
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesIncludingAncestors(pof);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- private static string[] ToArrayOfObjectNames(Set result)
- {
- Array resultArray = Array.CreateInstance(typeof (string), result.Count);
- result.CopyTo(resultArray, 0);
- return (string[]) resultArray;
- }
-
- ///
- /// Get all object names for the given type, including those defined in ancestor
- /// factories.
- ///
- ///
- ///
- /// Will return unique names in case of overridden object definitions.
- ///
- ///
- /// Does consider objects created by s
- /// if is set to true,
- /// which means that s will get initialized.
- ///
- ///
- ///
- /// If this isn't also an
- /// ,
- /// this method will return the same as it's own
- ///
- /// method.
- ///
- ///
- /// The that objects must match.
- ///
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// The array of object names, or an empty array if none.
- ///
- public static string[] ObjectNamesForTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects));
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- ///
- /// Get all object names for the given type, including those defined in ancestor
- /// factories.
- ///
- ///
- ///
- /// Will return unique names in case of overridden object definitions.
- ///
- ///
- /// Does consider objects created by s,
- /// or rather it considers the type of objects created by
- /// (which means that
- /// s will be instantiated).
- ///
- ///
- ///
- /// If this isn't also an
- /// ,
- /// this method will return the same as it's own
- ///
- /// method.
- ///
- ///
- /// The that objects must match.
- ///
- ///
- /// The array of object names, or an empty array if none.
- ///
- public static string[] ObjectNamesForTypeIncludingAncestors(
- IListableObjectFactory factory, Type type)
- {
- Set result = new HashedSet();
- result.AddAll(factory.GetObjectNamesForType(type));
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type);
- result.AddAll(parentsResult);
- }
- return ToArrayOfObjectNames(result);
- }
-
- private static IListableObjectFactory GetParentFactoryIfAny(IListableObjectFactory factory)
- {
- IHierarchicalObjectFactory hierFactory = factory as IHierarchicalObjectFactory;
- if (hierFactory != null)
- {
- return
- hierFactory.ParentObjectFactory as IListableObjectFactory;
- }
- return null;
- }
-
- ///
- /// Return all objects of the given type or subtypes, also picking up objects
- /// defined in ancestor object factories if the current object factory is an
- /// .
- ///
- ///
- ///
- /// The return list will only contain objects of this type.
- /// Useful convenience method when we don't care about object names.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the objects could not be created.
- ///
- ///
- /// The of object instances, or an
- /// empty if none.
- ///
- public static IDictionary ObjectsOfTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- Hashtable result = new Hashtable();
- foreach (DictionaryEntry entry in
- factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects))
- {
- result.Add(entry.Key, entry.Value);
- }
- IListableObjectFactory pof = GetParentFactoryIfAny(factory);
- if (pof != null)
- {
- IDictionary parentResult
- = ObjectsOfTypeIncludingAncestors(
- pof, type, includePrototypes, includeFactoryObjects);
- foreach (object instance in parentResult.Keys)
- {
- if (!result.ContainsKey(instance))
- {
- result.Add(instance, parentResult[instance]);
- }
- }
- }
- return result;
- }
-
- ///
- /// Return a single object of the given type or subtypes, also picking up objects defined
- /// in ancestor object factories if the current object factory is an
- /// .
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If more than one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfTypeIncludingAncestors(
- IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- IDictionary objectsOfType
- = ObjectsOfTypeIncludingAncestors(
- factory, type, includePrototypes, includeFactoryObjects);
- return GrabTheOnlyObject(objectsOfType, type);
- }
-
- private static object GrabTheOnlyObject(IDictionary objectsOfType, Type type)
- {
- if (objectsOfType.Count == 1)
- {
- return ObjectUtils.EnumerateFirstElement(objectsOfType.Values);
- }
- else
- {
- throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count);
- }
- }
-
- ///
- /// Return a single object of the given type or subtypes, not looking in
- /// ancestor factories.
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// Whether to include prototype objects too or just singletons
- /// (also applies to instances).
- ///
- ///
- /// Whether to include instances
- /// too or just normal objects.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If not exactly one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfType(IListableObjectFactory factory, Type type,
- bool includePrototypes, bool includeFactoryObjects)
- {
- IDictionary objectsOfType
- = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
- return GrabTheOnlyObject(objectsOfType, type);
- }
-
- ///
- /// Return a single object of the given type or subtypes, not looking in
- /// ancestor factories.
- ///
- ///
- ///
- /// Useful convenience method when we expect a single object and don't care
- /// about the object name.
- /// This version of ObjectOfType automatically includes prototypes and
- /// instances.
- ///
- ///
- /// The object factory.
- /// The of object to match.
- ///
- /// If the object could not be created.
- ///
- ///
- /// If not exactly one instance of an object was found.
- ///
- ///
- /// A single object of the given type or subtypes.
- ///
- public static object ObjectOfType(IListableObjectFactory factory, Type type)
- {
- return ObjectOfType(factory, type, true, true);
- }
-
- ///
- /// Return the object name, stripping out the factory dereference prefix if necessary.
- ///
- /// The name of the object.
- /// The object name sans any factory dereference prefix.
- public static string TransformedObjectName(string name)
- {
- AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null.");
- string objectName = name;
- if (ObjectFactoryUtils.IsFactoryDereference(objectName))
- {
- objectName = objectName.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length);
- }
- return objectName;
- }
-
- ///
- /// Given an (object) name, builds a corresponding factory object name such that
- /// the return value can be used as a lookup name for a factory object.
- ///
- ///
- /// The name to be used to build the resulting factory object name.
- ///
- ///
- /// The transformed into its factory object name
- /// equivalent.
- ///
- ///
- ///
- public static string BuildFactoryObjectName(string objectName)
- {
- return ObjectFactoryUtils.FactoryObjectPrefix + objectName;
- }
-
- ///
- /// Is the supplied a factory dereference?
- ///
- ///
- ///
- /// That is, does the supplied begin with
- /// the
- /// ?
- ///
+ /// The nesting hierarchy of an object factory is taken into account by the various methods
+ /// exposed by this class.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public sealed class ObjectFactoryUtils
+ {
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such has no publicly visible
+ /// constructors.
+ ///
+ ///
+ private ObjectFactoryUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// Used to dereference an
+ /// and distinguish it from managed objects created by the factory.
+ ///
+ ///
+ ///
+ /// For example, if the managed object identified as foo is a
+ /// factory, getting &foo will return the factory, not the
+ /// instance returned by the factory.
+ ///
+ ///
+ public const string FactoryObjectPrefix = "&";
+
+ ///
+ /// Count all object definitions in any hierarchy in which this
+ /// factory participates.
+ ///
+ ///
+ ///
+ /// Includes counts of ancestor object factories.
+ ///
+ ///
+ /// Objects that are "overridden" (specified in a descendant factory
+ /// with the same name) are counted only once.
+ ///
+ ///
+ /// The object factory.
+ ///
+ /// The count of objects including those defined in ancestor factories.
+ ///
+ public static int CountObjectsIncludingAncestors(IListableObjectFactory factory)
+ {
+ return ObjectNamesIncludingAncestors(factory).Length;
+ }
+
+ ///
+ /// Return all object names in the factory, including ancestor factories.
+ ///
+ /// The object factory.
+ /// The array of object names, or an empty array if none.
+ public static string[] ObjectNamesIncludingAncestors(IListableObjectFactory factory)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectDefinitionNames());
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesIncludingAncestors(pof);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ private static string[] ToArrayOfObjectNames(Set result)
+ {
+ Array resultArray = Array.CreateInstance(typeof (string), result.Count);
+ result.CopyTo(resultArray, 0);
+ return (string[]) resultArray;
+ }
+
+ ///
+ /// Get all object names for the given type, including those defined in ancestor
+ /// factories.
+ ///
+ ///
+ ///
+ /// Will return unique names in case of overridden object definitions.
+ ///
+ ///
+ /// Does consider objects created by s
+ /// if is set to true,
+ /// which means that s will get initialized.
+ ///
+ ///
+ ///
+ /// If this isn't also an
+ /// ,
+ /// this method will return the same as it's own
+ ///
+ /// method.
+ ///
+ ///
+ /// The that objects must match.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// The array of object names, or an empty array if none.
+ ///
+ public static string[] ObjectNamesForTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectNamesForType(type, includePrototypes, includeFactoryObjects));
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type, includePrototypes, includeFactoryObjects);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ ///
+ /// Get all object names for the given type, including those defined in ancestor
+ /// factories.
+ ///
+ ///
+ ///
+ /// Will return unique names in case of overridden object definitions.
+ ///
+ ///
+ /// Does consider objects created by s,
+ /// or rather it considers the type of objects created by
+ /// (which means that
+ /// s will be instantiated).
+ ///
+ ///
+ ///
+ /// If this isn't also an
+ /// ,
+ /// this method will return the same as it's own
+ ///
+ /// method.
+ ///
+ ///
+ /// The that objects must match.
+ ///
+ ///
+ /// The array of object names, or an empty array if none.
+ ///
+ public static string[] ObjectNamesForTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type)
+ {
+ Set result = new HashedSet();
+ result.AddAll(factory.GetObjectNamesForType(type));
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ string[] parentsResult = ObjectNamesForTypeIncludingAncestors(pof, type);
+ result.AddAll(parentsResult);
+ }
+ return ToArrayOfObjectNames(result);
+ }
+
+ private static IListableObjectFactory GetParentFactoryIfAny(IListableObjectFactory factory)
+ {
+ IHierarchicalObjectFactory hierFactory = factory as IHierarchicalObjectFactory;
+ if (hierFactory != null)
+ {
+ return
+ hierFactory.ParentObjectFactory as IListableObjectFactory;
+ }
+ return null;
+ }
+
+ ///
+ /// Return all objects of the given type or subtypes, also picking up objects
+ /// defined in ancestor object factories if the current object factory is an
+ /// .
+ ///
+ ///
+ ///
+ /// The return list will only contain objects of this type.
+ /// Useful convenience method when we don't care about object names.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the objects could not be created.
+ ///
+ ///
+ /// The of object instances, or an
+ /// empty if none.
+ ///
+ public static IDictionary ObjectsOfTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ Hashtable result = new Hashtable();
+ foreach (DictionaryEntry entry in
+ factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects))
+ {
+ result.Add(entry.Key, entry.Value);
+ }
+ IListableObjectFactory pof = GetParentFactoryIfAny(factory);
+ if (pof != null)
+ {
+ IDictionary parentResult
+ = ObjectsOfTypeIncludingAncestors(
+ pof, type, includePrototypes, includeFactoryObjects);
+ foreach (object instance in parentResult.Keys)
+ {
+ if (!result.ContainsKey(instance))
+ {
+ result.Add(instance, parentResult[instance]);
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, also picking up objects defined
+ /// in ancestor object factories if the current object factory is an
+ /// .
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If more than one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfTypeIncludingAncestors(
+ IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ IDictionary objectsOfType
+ = ObjectsOfTypeIncludingAncestors(
+ factory, type, includePrototypes, includeFactoryObjects);
+ return GrabTheOnlyObject(objectsOfType, type);
+ }
+
+ private static object GrabTheOnlyObject(IDictionary objectsOfType, Type type)
+ {
+ if (objectsOfType.Count == 1)
+ {
+ return ObjectUtils.EnumerateFirstElement(objectsOfType.Values);
+ }
+ else
+ {
+ throw new NoSuchObjectDefinitionException(type, "Expected single object but found " + objectsOfType.Count);
+ }
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, not looking in
+ /// ancestor factories.
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// Whether to include prototype objects too or just singletons
+ /// (also applies to instances).
+ ///
+ ///
+ /// Whether to include instances
+ /// too or just normal objects.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If not exactly one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfType(IListableObjectFactory factory, Type type,
+ bool includePrototypes, bool includeFactoryObjects)
+ {
+ IDictionary objectsOfType
+ = factory.GetObjectsOfType(type, includePrototypes, includeFactoryObjects);
+ return GrabTheOnlyObject(objectsOfType, type);
+ }
+
+ ///
+ /// Return a single object of the given type or subtypes, not looking in
+ /// ancestor factories.
+ ///
+ ///
+ ///
+ /// Useful convenience method when we expect a single object and don't care
+ /// about the object name.
+ /// This version of ObjectOfType automatically includes prototypes and
+ /// instances.
+ ///
+ ///
+ /// The object factory.
+ /// The of object to match.
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If not exactly one instance of an object was found.
+ ///
+ ///
+ /// A single object of the given type or subtypes.
+ ///
+ public static object ObjectOfType(IListableObjectFactory factory, Type type)
+ {
+ return ObjectOfType(factory, type, true, true);
+ }
+
+ ///
+ /// Return the object name, stripping out the factory dereference prefix if necessary.
+ ///
+ /// The name of the object.
+ /// The object name sans any factory dereference prefix.
+ public static string TransformedObjectName(string name)
+ {
+ AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null.");
+ string objectName = name;
+ if (ObjectFactoryUtils.IsFactoryDereference(objectName))
+ {
+ objectName = objectName.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length);
+ }
+ return objectName;
+ }
+
+ ///
+ /// Given an (object) name, builds a corresponding factory object name such that
+ /// the return value can be used as a lookup name for a factory object.
+ ///
+ ///
+ /// The name to be used to build the resulting factory object name.
+ ///
+ ///
+ /// The transformed into its factory object name
+ /// equivalent.
+ ///
+ ///
+ ///
+ public static string BuildFactoryObjectName(string objectName)
+ {
+ return ObjectFactoryUtils.FactoryObjectPrefix + objectName;
+ }
+
+ ///
+ /// Is the supplied a factory dereference?
+ ///
+ ///
+ ///
+ /// That is, does the supplied begin with
+ /// the
+ /// ?
+ ///
- /// Provides object creation, initialization and wiring, supporting
- /// autowiring and constructor resolution. Handles runtime object
- /// references, managed collections, and object destruction.
- ///
- ///
- /// The main template method to be implemented by subclasses is
- /// ,
- /// used for autowiring by type. Note that this class does not implement object
- /// definition registry capabilities
- /// (
- /// does).
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: AbstractAutowireCapableObjectFactory.cs,v 1.90 2008/05/29 12:13:27 oakinger Exp $
- [Serializable]
- public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory
- {
- #region Constants
-
- ///
- /// The used during the invocation and
- /// searching for of methods.
- ///
- protected const BindingFlags MethodResolutionFlags =
- BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase;
-
- #endregion
-
- ///
- /// The instance for this class.
- ///
- private readonly ILog log = LogManager.GetLogger(typeof(AbstractAutowireCapableObjectFactory));
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- protected AbstractAutowireCapableObjectFactory(bool caseSensitive)
- : this(caseSensitive, null)
- { }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- /// The parent object factory, or if none.
- protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
- : base(caseSensitive, parentFactory)
- {
- this.IgnoreDependencyInterface(typeof(IObjectFactoryAware));
- this.IgnoreDependencyInterface(typeof(IObjectNameAware));
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The
- /// implementation to be used to instantiate managed objects.
- ///
- protected IInstantiationStrategy InstantiationStrategy
- {
- get { return instantiationStrategy; }
- set { instantiationStrategy = value; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Predict the eventual object type (of the processed object instance) for the
- /// specified object.
- ///
- /// Name of the object.
- /// The merged object definition to determine the type for.
- ///
- /// The type of the object, or null if not predictable
- ///
- protected override Type PredictObjectType(string objectName, RootObjectDefinition mod)
- {
- Type objectType;
- if (StringUtils.HasText(mod.FactoryMethodName))
- {
- objectType = GetTypeForFactoryMethod(objectName, mod);
- }
- else
- {
- objectType = ResolveObjectType(mod, objectName);
- }
- return objectType;
- }
-
- ///
- /// Determines the of the object defined
- /// by the supplied object .
- ///
- ///
- /// The name associated with the supplied object .
- ///
- ///
- /// The
- /// that the is to be determined for.
- ///
- ///
- /// The of the object defined by the supplied
- /// object ; or if the
- /// cannot be determined.
- ///
- protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
- {
- if (StringUtils.HasText(definition.FactoryObjectName) && definition.IsSingleton && !definition.IsLazyInit)
- {
- return GetObject(objectName).GetType();
- }
-
- Type factoryType = null;
- bool isStatic = true;
-
- if (StringUtils.HasText(definition.FactoryObjectName))
- {
- // check declared factory method return type on factory type...
- factoryType = GetType(definition.FactoryObjectName);
- isStatic = false;
- }
- else
- {
- factoryType = ResolveObjectType(definition, objectName);
- }
- if (factoryType == null)
- {
- return null;
- }
-
- // If all factory methods have the same return type, return that type.
- // Can't clearly figure out exact method due to type converting / autowiring!
- int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count;
- MethodInfo[] candidates = factoryType.GetMethods();
- ISet returnTypes = new HybridSet();
- foreach (MethodInfo factoryMethod in candidates)
- {
-#if NET_2_0
- GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
- if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName)
- && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs
- && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length)
- {
- if (genericArgsInfo.ContainsGenericArguments)
- {
- string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
- Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
- for (int j = 0; j < unresolvedGenericArgs.Length; j++)
- {
- genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
- }
- returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType);
- }
- else
- {
- returnTypes.Add(factoryMethod.ReturnType);
- }
- }
-#else
- if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(definition.FactoryMethodName)
- && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs)
- {
- returnTypes.Add(factoryMethod.ReturnType);
- }
-#endif
- }
- if (returnTypes.Count == 1)
- {
- // clear return type found: all factory methods return same type...
- return (Type)ObjectUtils.EnumerateFirstElement(returnTypes);
- }
- else
- {
- // ambiguous return types found: return null to indicate "not determinable"...
- return null;
- }
- }
-
- ///
- /// Apply the property values of the object definition with the supplied
- /// to the supplied .
- ///
- ///
- /// The existing object that the property values for the named object will
- /// be applied to.
- ///
- ///
- /// The name of the object definition associated with the property values that are
- /// to be applied.
- ///
- public override void ApplyObjectPropertyValues(object instance, string name)
- {
- RootObjectDefinition definition = GetMergedObjectDefinition(name, true);
- if (definition != null)
- {
- log.Debug(string.Format("configuring object '{0}' using definition '{1}'", instance, name));
- ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues);
- }
- }
-
- ///
- /// Apply any
- /// s.
- ///
- ///
- ///
- /// The returned instance may be a wrapper around the original.
- ///
- ///
- ///
- /// The of the object that is to be
- /// instantiated.
- ///
- ///
- /// The name of the object that is to be instantiated.
- ///
- ///
- /// An instance to use in place of the original instance.
- ///
- ///
- /// In case of errors.
- ///
- protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("Invoking IInstantiationAwareObjectPostProcessors before " + "the instantiation of '{0}'.", objectName));
- }
-
- #endregion
-
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- object theObject = inProc.PostProcessBeforeInstantiation(objectType, objectName);
- if (theObject != null)
- {
- return theObject;
- }
- }
- }
- return null;
- }
-
- ///
- /// Apply the given property values, resolving any runtime references
- /// to other objects in this object factory.
- ///
- ///
- /// The object name passed for better exception information.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- ///
- /// The new property values.
- ///
- ///
- ///
- /// Must use deep copy, so that we don't permanently modify this property.
- ///
- ///
- protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
- {
- if (properties == null || properties.PropertyValues.Length == 0)
- {
- return;
- }
- MutablePropertyValues deepCopy = new MutablePropertyValues(properties);
- PropertyValue[] copiedProperties = deepCopy.PropertyValues;
- for (int i = 0; i < copiedProperties.Length; ++i)
- {
- PropertyValue copiedProperty = copiedProperties[i];
- object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value);
- PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression);
- // update mutable copy...
- deepCopy.SetPropertyValueAt(propertyValue, i);
- }
- // set the (possibly resolved) deep copy properties...
- try
- {
- wrapper.SetPropertyValues(deepCopy);
- }
- catch (ObjectsException ex)
- {
- // improve the message by showing the context...
- throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex);
- }
- }
-
- ///
- /// Return an array of object-type property names that are unsatisfied.
- ///
- ///
- ///
- /// These are probably unsatisfied references to other objects in the
- /// factory. Does not include simple properties like primitives or
- /// s.
- ///
- ///
- ///
- /// An array of object-type property names that are unsatisfied.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected string[] UnsatisfiedObjectProperties(RootObjectDefinition definition, IObjectWrapper wrapper)
- {
- ArrayList result = new ArrayList();
- ISet ignoredTypes = IgnoredDependencyTypes;
- PropertyInfo[] properties = wrapper.GetPropertyInfos();
- foreach (PropertyInfo property in properties)
- {
- string name = property.Name;
- if (property.CanWrite && !ignoredTypes.Contains(property.PropertyType) && !result.Contains(name)
- && !ObjectUtils.IsSimpleProperty(property.PropertyType))
- {
- result.Add(name);
- }
- }
- return (string[])result.ToArray(typeof(string));
- }
-
- ///
- /// Destroy all cached singletons in this factory.
- ///
- ///
- ///
- /// To be called on shutdown of a factory.
- ///
- ///
- public override void Dispose()
- {
- base.Dispose();
- foreach (object o in _disposableInnerObjects)
- {
- DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o);
- }
- _disposableInnerObjects.Clear();
- }
-
- ///
- /// Populate the object instance in the given
- /// with the property values from the
- /// object definition.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper)
- {
- // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
- // state of the bean before properties are set. This can be used, for example,
- // to support styles of field injection.
- bool continueWithPropertyPopulation = true;
-
- if (HasInstantiationAwareBeanPostProcessors)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name))
- {
- continueWithPropertyPopulation = false;
- break;
- }
- }
- }
- }
- if (!continueWithPropertyPopulation)
- {
- return;
- }
-
- IPropertyValues properties = definition.PropertyValues;
-
- if (wrapper == null)
- {
- if (properties.PropertyValues.Length > 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription,
- name, "Cannot apply property values to null instance.");
- }
- else
- {
- // skip property population phase for null instance
- return;
- }
- }
-
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType)
- {
- MutablePropertyValues mpvs = new MutablePropertyValues(properties);
- // add property values based on autowire by name if it's applied
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByName)
- {
- AutowireByName(name, definition, wrapper, mpvs);
- }
- // add property values based on autowire by type if it's applied
- if (definition.ResolvedAutowireMode == AutoWiringMode.ByType)
- {
- AutowireByType(name, definition, wrapper, mpvs);
- }
- properties = mpvs;
- }
- //DependencyCheck(name, definition, wrapper, properties);
-
-
- bool hasInstAwareOpps = HasInstantiationAwareBeanPostProcessors;
- bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None);
-
-
- if (hasInstAwareOpps || needsDepCheck)
- {
- PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
- if (hasInstAwareOpps)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor =
- processor as IInstantiationAwareObjectPostProcessor;
- if (instantiationAwareObjectPostProcessor != null)
- {
- properties =
- instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance,
- name);
- if (properties == null)
- {
- return;
- }
- }
- }
- }
-
- if (needsDepCheck)
- {
- CheckDependencies(name, definition, filteredPropInfo, properties);
- }
-
- }
-
- ApplyPropertyValues(name, definition, wrapper, properties);
- }
-
- ///
- /// Wires up any exposed events in the object instance in the given
- /// with any event handler
- /// values from the .
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper)
- {
- foreach (string eventName in definition.EventHandlerValues.Events)
- {
- foreach (IEventHandlerValue handlerValue
- in definition.EventHandlerValues[eventName])
- {
- object handler = null;
- if (handlerValue.Source is RuntimeObjectReference)
- {
- RuntimeObjectReference roref = (RuntimeObjectReference)handlerValue.Source;
- handler = ResolveReference(definition, name, eventName, roref);
- }
- else if (handlerValue.Source is Type)
- {
- // a static Type event is being wired up; simply pass on the Type
- handler = handlerValue.Source;
- }
- else if (handlerValue.Source is string)
- {
- // a static Type event is being wired up; we need to resolve the Type
- handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string);
- }
- else
- {
- throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources.");
- }
- handlerValue.Wire(handler, wrapper.WrappedInstance);
- }
- }
- }
-
- ///
- /// Fills in any missing property values with references to
- /// other objects in this factory if autowire is set to
- /// .
- ///
- ///
- /// The object name to be autowired by .
- ///
- ///
- /// The definition of the named object to update through autowiring.
- ///
- ///
- /// The wrapping the target object (and
- /// from which we can rip out information concerning the object).
- ///
- ///
- /// The property values to register wired objects with.
- ///
- protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
- {
- string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
- foreach (string propertyName in propertyNames)
- {
- // look for a matching type
- if (ContainsObject(propertyName))
- {
- object o = GetObject(propertyName);
- properties.Add(propertyName, o);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name,
- propertyName));
- }
-
- #endregion
- }
- else
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name));
- }
-
- #endregion
- }
- }
- }
-
- ///
- /// Defines "autowire by type" (object properties by type) behavior.
- ///
- ///
- ///
- /// This is like PicoContainer default, in which there must be exactly one object
- /// of the property type in the object factory. This makes object factories simple
- /// to configure for small namespaces, but doesn't work as well as standard Spring
- /// behavior for bigger applications.
- ///
- ///
- ///
- /// The object name to be autowired by .
- ///
- ///
- /// The definition of the named object to update through autowiring.
- ///
- ///
- /// The wrapping the target object (and
- /// from which we can rip out information concerning the object).
- ///
- ///
- /// The property values to register wired objects with.
- ///
- protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
- {
- string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
- foreach (string propertyName in propertyNames)
- {
- // look for a matching type
- Type requiredType = wrapper.GetPropertyType(propertyName);
- IDictionary matchingObjects = FindMatchingObjects(requiredType);
- if (matchingObjects != null && matchingObjects.Count == 1)
- {
- properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values));
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name,
- propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys)));
- }
-
- #endregion
- }
- else if (matchingObjects != null && matchingObjects.Count > 1)
- {
- throw new UnsatisfiedDependencyException(string.Empty, name, propertyName,
- string.Format(CultureInfo.InvariantCulture,
- "There are {0} objects of Type [{1}] for autowire by "
- + "type, when there should have been just 1 to be able to "
- + "autowire property '{2}' of object '{3}'.", matchingObjects.Count,
- requiredType, propertyName, name));
- }
- else
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.",
- propertyName, name));
- }
-
- #endregion
- }
- }
- }
-
- ///
- /// Ignore the given dependency type for autowiring
- ///
- ///
- /// This will typically be used by application contexts to register
- /// dependencies that are resolved in other ways, like IOjbectFactory through
- /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware.
- /// By default, IObjectFactoryAware and IObjectName interfaces are ignored.
- /// For further types to ignore, invoke this method for each type.
- ///
- /// .
- public void IgnoreDependencyInterface(Type type)
- {
- ignoredDependencyInterfaces.Add(type);
- }
-
- ///
- /// Create an object instance for the given object definition.
- ///
- /// The name of the object.
- ///
- /// The object definition for the object that is to be instantiated.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. It is invalid to use a non- arguments value
- /// in any other case.
- ///
- ///
- /// A new instance of the object.
- ///
- ///
- /// In case of errors.
- ///
- ///
- ///
- /// Delegates to the
- ///
- /// method version with the allowEagerCaching parameter set to true.
- ///
- ///
- /// The object definition will already have been merged with the parent
- /// definition in case of a child definition.
- ///
- ///
- /// All the other methods in this class invoke this method, although objects
- /// may be cached after being instantiated by this method. All object
- /// instantiation within this class is performed by this method.
- ///
- ///
- protected override object CreateObject(string name, RootObjectDefinition definition, object[] arguments)
- {
- return CreateObject(name, definition, arguments, true);
- }
-
- ///
- /// Create an object instance for the given object definition.
- ///
- /// The name of the object.
- ///
- /// The object definition for the object that is to be instantiated.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. It is invalid to use a non- arguments value
- /// in any other case.
- ///
- ///
- /// Whether eager caching of singletons is allowed... typically true for
- /// singlton objects, but never true for inner object definitions.
- ///
- ///
- /// A new instance of the object.
- ///
- ///
- /// In case of errors.
- ///
- ///
- ///
- /// The object definition will already have been merged with the parent
- /// definition in case of a child definition.
- ///
- ///
- /// All the other methods in this class invoke this method, although objects
- /// may be cached after being instantiated by this method. All object
- /// instantiation within this class is performed by this method.
- ///
- ///
- protected virtual object CreateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching)
- {
- // guarantee the initialization of objects that the current one depends on..
- if (definition.DependsOn != null && definition.DependsOn.Length > 0)
- {
- foreach (string dependant in definition.DependsOn)
- {
- GetObject(dependant);
- }
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Creating instance of Object '{0}' with merged definition [{1}].", name, definition));
- }
-
- #endregion
-
- // Make sure object type is actually resolved at this point.
- ResolveObjectType(definition, name);
-
- try
- {
- definition.PrepareMethodOverrides();
- }
- catch (ObjectDefinitionValidationException ex)
- {
- throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
- "Validation of method overrides failed. " + ex.Message, ex);
- }
-
- // return IObjectDefinition instance itself for an abstract object-definition
- if (definition.IsTemplate)
- {
- return definition;
- }
-
-
-
- object instance = null;
-
-
- IObjectWrapper instanceWrapper = null;
- bool eagerlyCached = false;
- try
- {
- // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance....
- if (definition.HasObjectType)
- {
- instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name);
- if (instance != null)
- {
- return instance;
- }
- }
-
-
- instanceWrapper = CreateObjectInstance(name, definition, arguments);
- instance = instanceWrapper.WrappedInstance;
-
- // eagerly cache singletons to be able to resolve circular references
- // even when triggered by lifecycle interfaces like IObjectFactoryAware.
- if (allowEagerCaching && definition.IsSingleton)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("Eagerly caching object '" + name + "' to allow for resolving potential circular references");
- }
- AddEagerlyCachedSingleton(name, definition, instance);
- eagerlyCached = true;
- }
-
- instance = ConfigureObject(name, definition, instanceWrapper);
- }
- catch (ObjectCreationException)
- {
- if (eagerlyCached)
- {
- RemoveEagerlyCachedSingleton(name, definition);
- }
- throw;
- }
- catch (Exception ex)
- {
- if (eagerlyCached)
- {
- RemoveEagerlyCachedSingleton(name, definition);
- }
- throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex);
- }
- return instance;
- }
-
- ///
- /// Add the created, but yet unpopulated singleton to the singleton cache
- /// to be able to resolve circular references
- ///
- /// the name of the object to add to the cache.
- /// the definition used to create and populated the object.
- /// the raw object instance.
- ///
- /// Derived classes may override this method to select the right cache based on the object definition.
- ///
- protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance)
- {
- base.AddSingleton(objectName, rawSingletonInstance);
- }
-
- ///
- /// Remove the specified singleton from the singleton cache that has
- /// been added before by a call to
- ///
- /// the name of the object to remove from the cache.
- /// the definition used to create and populated the object.
- ///
- /// Derived classes may override this method to select the right cache based on the object definition.
- ///
- protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition)
- {
- base.RemoveSingleton(objectName);
- }
-
- ///
- /// Creates an instance from the passed in
- /// using constructor
- ///
- /// The name of the object to create - used for error messages.
- /// The describing the object to be created.
- /// optional arguments to pass to the constructor
- /// An wrapping the already instantiated object
- protected IObjectWrapper CreateObjectInstance(string name, RootObjectDefinition definition, object[] arguments)
- {
- IObjectWrapper instanceWrapper;
- if (StringUtils.HasText(definition.FactoryMethodName))
- {
- instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments);
- }
- //Handle case when arguments are passed in explicitly.
- else if (arguments != null && arguments.Length > 0)
- {
- instanceWrapper = AutowireConstructor(name, definition, arguments);
- }
- else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor ||
- definition.HasConstructorArgumentValues)
- {
- instanceWrapper = AutowireConstructor(name, definition);
- }
- else
- {
- instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this));
- InitObjectWrapper(instanceWrapper);
- }
- return instanceWrapper;
- }
-
- ///
- /// Instantiate an object instance using a named factory method.
- ///
- ///
- ///
- /// The method may be static, if the
- /// parameter specifies a class, rather than a
- /// instance, or an
- /// instance variable on a factory object itself configured using Dependency
- /// Injection.
- ///
- ///
- /// Implementation requires iterating over the static or instance methods
- /// with the name specified in the supplied
- /// (the method may be overloaded) and trying to match with the parameters.
- /// We don't have the types attached to constructor args, so trial and error
- /// is the only way to go here.
- ///
- ///
- ///
- /// The name associated with the supplied .
- ///
- ///
- /// The definition describing the instance that is to be instantiated.
- ///
- ///
- /// Any arguments to the factory method that is to be invoked.
- ///
- ///
- /// The result of the factory method invocation (the instance).
- ///
- protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
- {
- ConstructorArgumentValues cargs = definition.ConstructorArgumentValues;
- ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
- int expectedArgCount = 0;
-
- // we don't have arguments passed in programmatically, so we need to resolve the
- // arguments specified in the constructor arguments held in the object definition...
- if (arguments == null || arguments.Length == 0)
- {
- expectedArgCount = cargs.ArgumentCount;
- ResolveConstructorArguments(name, definition, resolvedValues);
- }
- else
- {
- // if we have constructor args, don't need to resolve them...
- expectedArgCount = arguments.Length;
- }
- ObjectWrapper wrapper = new ObjectWrapper();
- InitObjectWrapper(wrapper);
- bool isStatic = true;
- Type factoryClass = null;
- if (StringUtils.HasText(definition.FactoryObjectName))
- {
- // it's an instance method on the factory object's class...
- factoryClass = GetObject(definition.FactoryObjectName).GetType();
- isStatic = false;
- }
- else
- {
- // it's a static factory method on the object class...
- factoryClass = definition.ObjectType;
- }
-
-#if NET_2_0
- GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
-
- MethodInfo[] factoryMethods = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass);
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- // try all matching methods to see if they match the constructor arguments...
- for (int i = 0; i < factoryMethods.Length; i++)
- {
- unsatisfiedDependencyExceptionData = null;
- MethodInfo factoryMethod = factoryMethods[i];
-
- if (genericArgsInfo.ContainsGenericArguments)
- {
- string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
- if (factoryMethod.GetGenericArguments().Length != unresolvedGenericArgs.Length)
- continue;
-
- Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
- for (int j = 0; j < unresolvedGenericArgs.Length; j++)
- {
- genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
- }
- factoryMethod = factoryMethod.MakeGenericMethod(genericArgs);
- }
-#else
- MethodInfo[] factoryMethods = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass);
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- // try all matching methods to see if they match the constructor arguments...
- foreach(MethodInfo factoryMethod in factoryMethods)
- {
-#endif
- if (arguments == null || arguments.Length == 0)
- {
- // try to create the required arguments...
- arguments = CreateArgumentArray(name, definition, resolvedValues, factoryMethod, out unsatisfiedDependencyExceptionData);
- if (arguments == null)
- {
- // if we failed to match this method, keep
- // trying new overloaded factory methods...
- continue;
- }
- }
- // if we get here, we found a factory method...
-
- if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethod }, arguments) == null)
- {
- continue;
- }
-
-
- object objectInstance = InstantiationStrategy.Instantiate(definition, name, this, factoryMethod, arguments);
- wrapper.WrappedInstance = objectInstance;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethod));
- }
-
- #endregion
-
- return wrapper;
- }
-
-
-
- // if we get here, we didn't match any method...
- throw new ObjectDefinitionStoreException(
- string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName,
- factoryClass));
- }
-
- ///
- /// Returns an array of all of those
- /// methods exposed on the
- /// that match the supplied criteria.
- ///
- ///
- /// Methods that have this name (can be in the form of a regular expression).
- ///
- ///
- /// Methods that have exactly this many arguments.
- ///
- ///
- /// Methods that are static / instance.
- ///
- ///
- /// The on which the methods (if any) are to be found.
- ///
- ///
- /// An array of all of those
- /// methods exposed on the
- /// that match the supplied criteria.
- ///
- private static MethodInfo[] FindMethods(string methodName, int expectedArgumentCount, bool isStatic, Type searchType)
- {
- ComposedCriteria methodCriteria = new ComposedCriteria();
- methodCriteria.Add(new MethodNameMatchCriteria(methodName));
- methodCriteria.Add(new MethodParametersCountCriteria(expectedArgumentCount));
- BindingFlags methodFlags = BindingFlags.Public | BindingFlags.IgnoreCase | (isStatic ? BindingFlags.Static : BindingFlags.Instance);
- MemberInfo[] methods =
- searchType.FindMembers(MemberTypes.Method, methodFlags, new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- methodCriteria);
- return (MethodInfo[])ArrayList.Adapter(methods).ToArray(typeof(MethodInfo));
- }
-
- ///
- /// Create an array of arguments to invoke a constructor or static factory method,
- /// given the resolved constructor arguments values.
- ///
- /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
- /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using
- /// exceptions for flow control as in the original implementation.
- private object[] CreateArgumentArray(string name, RootObjectDefinition definition,
- ConstructorArgumentValues resolvedValues, MethodBase methodOrCtor, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
- {
- string methodType = (methodOrCtor is ConstructorInfo) ? "constructor" : "factory method";
- unsatisfiedDependencyExceptionData = null;
- ParameterInfo[] argTypes = methodOrCtor.GetParameters();
- object[] args = new object[argTypes.Length];
- ISet alreadyUsedValues = new HybridSet();
- for (int j = 0; j < argTypes.Length; ++j)
- {
- Type parameterType = argTypes[j].ParameterType;
- string parameterName = argTypes[j].Name;
- ConstructorArgumentValues.ValueHolder valueHolder = null;
- if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
- {
- valueHolder = resolvedValues.GetArgumentValue(parameterName, parameterType, alreadyUsedValues);
- }
- else
- {
- valueHolder = resolvedValues.GetArgumentValue(j, parameterType, alreadyUsedValues);
- }
- if (valueHolder != null)
- {
- try
- {
- args[j] = TypeConversionUtils.ConvertValueIfNecessary(parameterType, valueHolder.Value, null);
- alreadyUsedValues.Add(valueHolder);
- }
- catch (TypeMismatchException ex)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
- methodType, valueHolder.Value,
- parameterType, ex.Message);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
-
- return null;
- }
- }
- else
- {
- if (definition.ResolvedAutowireMode != AutoWiringMode.Constructor)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "Ambiguous {0} argument types - " +
- "Did you specify the correct object references as {0} arguments?",
- methodType);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
- return null;
- }
- IDictionary matchingObjects = FindMatchingObjects(parameterType);
- if (matchingObjects == null || matchingObjects.Count != 1)
- {
- string errorMessage = String.Format(CultureInfo.InvariantCulture,
- "There are '{0}' objects of type [{1}] for autowiring "
- +
- "{2}. There should have been exactly 1 to be able to "
- +
- "autowire the '{3}' argument on the {2} of object '{4}'.",
- (matchingObjects == null
- ? 0
- : matchingObjects.Count),
- parameterType, methodType,
- parameterName, name);
- unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
-
- return null;
- }
- DictionaryEntry entry = (DictionaryEntry)ObjectUtils.EnumerateFirstElement(matchingObjects);
- args[j] = entry.Value;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture,
- "Autowiring '{0}' argument by type from object name '{1}' via {2} to "
- + "object named '{3}'.", parameterName, name, methodType, entry.Key));
- }
-
- #endregion
- }
- }
-
- return args;
- }
-
- ///
- /// Explicitly construct the object using the supplied constructor arguments.
- /// Constructor arguments are matched by type.
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- /// Array of constructor argument values.
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, object[] args)
- {
- ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
- for (int i = 0; i < args.Length; i++)
- {
- //This is assigning ctor arguments by type.
- resolvedValues.AddGenericArgumentValue(args[i]);
- }
- return AutowireConstructor(name, definition, resolvedValues);
- }
-
- ///
- /// "autowire constructor" (with constructor arguments by type) behaviour.
- ///
- /// Passes an empty collection of constructor argument values
- /// to overloaded method.
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition)
- {
- return AutowireConstructor(name, definition, new ConstructorArgumentValues());
- }
-
- ///
- /// "autowire constructor" (with constructor arguments by type) behaviour.
- ///
- ///
- ///
- /// Also applied if explicit constructor argument values are specified,
- /// matching all remaining arguments with objects from the object factory.
- ///
- ///
- /// This corresponds to constructor injection: in this mode, a Spring.NET
- /// object factory is able to host components that expect constructor-based
- /// dependency resolution.
- ///
- ///
- ///
- /// The name of the object to autowire by type.
- ///
- ///
- /// The object definition to update through autowiring.
- ///
- ///
- /// The collection on constructor argument values.
- ///
- ///
- /// An for the new instance.
- ///
- protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorArgumentValues argumentValues)
- {
- int minNrOfArgs = ResolveConstructorArguments(name, definition, argumentValues);
- ConstructorInfo[] constructors = AutowireUtils.GetConstructors(definition, minNrOfArgs);
- if (constructors == null || constructors.Length == 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- string.Format(CultureInfo.InvariantCulture,
- "'{0}' constructor arguments specified but no matching constructor found "
- + "in object '{1}' (hint: specify argument indexes, names, or "
- + "types to avoid ambiguities).", minNrOfArgs, name));
- }
- ObjectWrapper wrapper = new ObjectWrapper();
- InitObjectWrapper(wrapper);
- ConstructorInfo constructorToUse = null;
- object[] argsToUse = null;
- int weighting = Int32.MaxValue;
- UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
- for (int i = 0; i < constructors.Length; ++i)
- {
- unsatisfiedDependencyExceptionData = null;
- ConstructorInfo constructor = constructors[i];
- if (constructorToUse != null &&
- constructorToUse.GetParameters().Length > constructor.GetParameters().Length)
- {
- // already found greedy constructor that can be satisfied, so
- // don't look any further, there are only less greedy constructors left...
- break;
- }
-
- object[] args = CreateArgumentArray(name, definition, argumentValues, constructor, out unsatisfiedDependencyExceptionData);
- if (args == null)
- {
- if (i == constructors.Length - 1 && constructorToUse == null)
- {
- throw new UnsatisfiedDependencyException(definition.ResourceDescription,
- name,
- unsatisfiedDependencyExceptionData.ParameterIndex,
- unsatisfiedDependencyExceptionData.ParameterType,
- unsatisfiedDependencyExceptionData.ErrorMessage);
- }
- // try next constructor...
- continue;
- }
-
- int typeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(constructor.GetParameters(), args);
- if (typeDiffWeight < weighting)
- {
- constructorToUse = constructor;
- argsToUse = args;
- weighting = typeDiffWeight;
- }
- }
-
- if (constructorToUse == null)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name, "Could not resolve matching constructor.");
- }
- wrapper.WrappedInstance = InstantiationStrategy.Instantiate(definition, name, this, constructorToUse, argsToUse);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", name, constructorToUse));
- }
-
- #endregion
-
- return wrapper;
- }
-
- ///
- /// Resolves the
- /// of the supplied .
- ///
- ///
- ///
- /// 'Resolve' can be taken to mean that all of the s
- /// constructor arguments is resolved into a concrete object that can be plugged
- /// into one of the s constructors. Runtime object
- /// references to other objects in this (or a parent) factory are resolved,
- /// type conversion is performed, etc.
- ///
- ///
- /// These resolved values are plugged into the supplied
- /// object, because we wouldn't want to touch
- /// the s constructor arguments in case it (or any of
- /// its constructor arguments) is a prototype object definition.
- ///
- ///
- /// This method is also used for handling invocations of static factory methods.
- ///
- ///
- ///
- /// The name of the object that is being resolved by this factory.
- ///
- ///
- /// The definition associated with the above .
- ///
- ///
- /// Where the resolved constructor arguments will be placed.
- ///
- ///
- /// The minimum number of arguments that any constructor for the supplied
- /// must have.
- ///
- private int ResolveConstructorArguments(string name, RootObjectDefinition definition, ConstructorArgumentValues resolvedValues)
- {
- int minNrOfArgs = 0;
- if (definition.ConstructorArgumentValues != null)
- {
- minNrOfArgs = definition.ConstructorArgumentValues.ArgumentCount;
- foreach (DictionaryEntry de in definition.ConstructorArgumentValues.IndexedArgumentValues)
- {
- int index = (int)de.Key;
- if (index < 0)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name, "Invalid constructor argument index: " + index);
- }
- if (index > minNrOfArgs)
- {
- minNrOfArgs = index + 1;
- }
- string argName = "constructor argument with index " + index;
- ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)de.Value;
- object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
- resolvedValues.AddIndexedArgumentValue(index, resolvedValue,
- StringUtils.HasText(valueHolder.Type)
- ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
- : null);
- }
- foreach (ConstructorArgumentValues.ValueHolder valueHolder in definition.ConstructorArgumentValues.GenericArgumentValues)
- {
- string argName = "constructor argument";
- object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
- resolvedValues.AddGenericArgumentValue(resolvedValue,
- StringUtils.HasText(valueHolder.Type)
- ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
- : null);
- }
- foreach (DictionaryEntry namedArgumentEntry in definition.ConstructorArgumentValues.NamedArgumentValues)
- {
- string argumentName = (string)namedArgumentEntry.Key;
- string syntheticArgumentName = "constructor argument with name " + argumentName;
- ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)namedArgumentEntry.Value;
- object resolvedValue = ResolveValueIfNecessary(name, definition, syntheticArgumentName, valueHolder.Value);
- resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue);
- }
- }
- return minNrOfArgs;
- }
-
- ///
- /// Perform a dependency check that all properties exposed have been set, if desired.
- ///
- ///
- ///
- /// Dependency checks can be objects (collaborating objects), simple (primitives
- /// and ), or all (both).
- ///
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The wrapping the target object.
- ///
- ///
- /// The property values to be checked.
- ///
- ///
- /// If all of the checked dependencies were not satisfied.
- ///
- protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
- {
- DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
- if (dependencyCheck == DependencyCheckingMode.None)
- {
- return;
- }
-
- PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
- if (HasInstantiationAwareBeanPostProcessors)
- {
- foreach (IObjectPostProcessor processor in ObjectPostProcessors)
- {
- IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
- if (inProc != null)
- {
- properties =
- inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name);
- if (properties == null)
- {
- return;
- }
- }
- }
- }
-
-
- CheckDependencies(name, definition, filteredPropInfo, properties);
- }
-
- private static void CheckDependencies(string name, IConfigurableObjectDefinition definition, PropertyInfo[] filteredPropInfo, IPropertyValues properties)
- {
- DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
- foreach (PropertyInfo property in filteredPropInfo)
- {
- if (property.CanWrite && properties.GetPropertyValue(property.Name) == null)
- {
- bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType);
- bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple)
- || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects);
- if (unsatisfied)
- {
- throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, property.Name,
- "Set this property value or disable dependency checking for this object.");
- }
- }
- }
- }
-
- ///
- /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding
- /// ignored dependency types.
- ///
- /// The object wrapper the object was created with.
- /// The filtered PropertyInfos
- private PropertyInfo[] FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper)
- {
- lock (filteredPropertyDescriptorsCache)
- {
- PropertyInfo[] filtered = (PropertyInfo[])filteredPropertyDescriptorsCache[wrapper.WrappedType];
- if (filtered == null)
- {
-
- ArrayList list = new ArrayList(wrapper.GetPropertyInfos());
- for (int i = list.Count - 1; i >= 0; i--)
- {
- PropertyInfo pi = (PropertyInfo)list[i];
- if (IsExcludedFromDependencyCheck(pi))
- {
- list.RemoveAt(i);
- }
- }
-
- filtered = (PropertyInfo[])list.ToArray(typeof(PropertyInfo));
- filteredPropertyDescriptorsCache.Add(wrapper.WrappedType, filtered);
- }
- return filtered;
- }
-
- }
-
- private bool IsExcludedFromDependencyCheck(PropertyInfo pi)
- {
- bool b1 = !pi.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi);
- bool b2 = IgnoredDependencyTypes.Contains(pi.PropertyType);
- bool b3 = AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
- return b1 || b2 || b3;
- /*
- return AutowireUtils.IsExcludedFromDependencyCheck(pi) ||
- IgnoredDependencyTypes.Contains(pi.PropertyType) ||
- AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
- */
- }
-
- ///
- /// Give an object a chance to react now all its properties are set,
- /// and a chance to know about its owning object factory (this object).
- ///
- ///
- ///
- /// This means checking whether the object implements
- /// and / or
- /// , and invoking the
- /// necessary callback(s) if it does.
- ///
- ///
- /// Custom init methods are resolved in a case-insensitive manner.
- ///
- ///
- ///
- /// The new object instance we may need to initialise.
- ///
- ///
- /// The name the object has in the factory. Used for logging output.
- ///
- ///
- /// The definition of the target object instance.
- ///
- protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition)
- {
- if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name));
- }
-
- #endregion
-
- ((IInitializingObject)target).AfterPropertiesSet();
- }
- if (StringUtils.HasText(definition.InitMethodName))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.",
- definition.InitMethodName, name));
- }
-
- #endregion
-
- try
- {
- MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null);
- if (targetMethod == null)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Could not find the named initialization method '" + definition.InitMethodName + "'.");
- }
- targetMethod.Invoke(target, ObjectUtils.EmptyObjects);
- }
- catch (TargetInvocationException ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException());
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex);
- }
- }
- }
-
- ///
- /// Invoke the specified custom destroy method on the given object.
- ///
- ///
- ///
- /// This implementation invokes a no-arg method if found, else checking
- /// for a method with a single boolean argument (passing in "true",
- /// assuming a "force" parameter), else logging an error.
- ///
- ///
- /// Can be overridden in subclasses for custom resolution of destroy
- /// methods with arguments.
- ///
- ///
- /// Custom destroy methods are resolved in a case-insensitive manner.
- ///
- /// Must destroy objects that depend on the given object before the object itself.
- /// Should not throw any exceptions.
- ///
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The target object instance to destroyed.
- ///
- protected override void DestroyObject(string name, object target)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Destroying dependant objects for object '" + name + "'");
- }
-
- #endregion
-
- DestroyDependantObjects(name);
- if (target is IDisposable)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling Dispose () on object with name '{0}'.", name));
- }
-
- #endregion
-
- try
- {
- ((IDisposable)target).Dispose();
- }
- catch (Exception ex)
- {
- #region Instrumentation
-
- log.Error("Destroy() on object with name '" + name + "' threw an exception.", ex);
-
- #endregion
- }
- }
- RootObjectDefinition rootDefinition = GetMergedObjectDefinition(name, false);
- if (rootDefinition != null && StringUtils.HasText(rootDefinition.DestroyMethodName))
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Calling custom destroy method '" + rootDefinition.DestroyMethodName + "' on object with name '" + name + "'.");
- }
-
- #endregion
-
- InvokeCustomDestroyMethod(name, target, rootDefinition.DestroyMethodName);
- }
- }
-
- ///
- /// Destroys all of the objects registered as dependant on the
- /// object (definition) identified by the supplied .
- ///
- ///
- /// The name of the root object (definition) that is itself being destroyed.
- ///
- private void DestroyDependantObjects(string name)
- {
- string[] dependingObjects = GetDependingObjectNames(name);
- foreach (string doName in dependingObjects)
- {
- DestroySingleton(doName);
- }
- }
-
- ///
- /// Given a property value, return a value, resolving any references to other
- /// objects in the factory if necessary.
- ///
- ///
- ///
- /// The value could be :
- ///
- ///
- ///
- /// An ,
- /// which leads to the creation of a corresponding new object instance.
- /// Singleton flags and names of such "inner objects" are always ignored: inner objects
- /// are anonymous prototypes.
- ///
- ///
- ///
- ///
- /// A , which must
- /// be resolved.
- ///
- ///
- ///
- ///
- /// An . This is a
- /// special placeholder collection that may contain
- /// s or
- /// collections that will need to be resolved.
- ///
- ///
- ///
- ///
- /// An ordinary object or , in which case it's left alone.
- ///
- ///
- ///
- ///
- ///
- ///
- /// The name of the object that is having the value of one of its properties resolved.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The value of the property that is being resolved.
- ///
- protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue)
- {
- object resolvedValue = null;
- // we must check the argument value to see whether it requires a runtime
- // reference to another object to be resolved.
- // if it does, we'll attempt to instantiate the object and set the reference.
- if (argumentValue is ObjectDefinitionHolder)
- {
- // contains an IObjectDefinition with name and aliases...
- ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue;
- resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton);
- }
- else if (argumentValue is IObjectDefinition)
- {
- // resolve plain IObjectDefinition, without contained name: use dummy name...
- IObjectDefinition def = (IObjectDefinition)argumentValue;
- resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton);
-
- }
- else if (argumentValue is RuntimeObjectReference)
- {
- RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue;
- resolvedValue = ResolveReference(definition, name, argumentName, roref);
- }
- else if (argumentValue is ExpressionHolder)
- {
- ExpressionHolder expHolder = (ExpressionHolder)argumentValue;
- object context = null;
- IDictionary variables = null;
-
- if (expHolder.Properties != null)
- {
- PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context");
- context = contextProperty == null
- ? null
- : ResolveValueIfNecessary(name, definition, "Context",
- contextProperty.Value);
- PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables");
- object vars = (variablesProperty == null
- ? null
- : ResolveValueIfNecessary(name, definition, "Variables",
- variablesProperty.Value));
- if (vars is IDictionary)
- {
- variables = (IDictionary)vars;
- }
- else
- {
- if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary");
- }
- }
-
- if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
- // add 'this' objectfactory reference to variables
- variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this);
-
- resolvedValue = expHolder.Expression.GetValue(context, variables);
- }
- else if (argumentValue is IManagedCollection)
- {
- resolvedValue =
- ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName,
- new ManagedCollectionElementResolver(ResolveValueIfNecessary));
- }
- else if (argumentValue is TypedStringValue)
- {
- TypedStringValue tsv = (TypedStringValue)argumentValue;
- try
- {
- Type resolvedTargetType = ResolveTargetType(tsv);
- if (resolvedTargetType != null)
- {
- resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null);
- }
- else
- {
- resolvedValue = tsv.Value;
- }
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- "Error converted typed String value for " + argumentName, ex);
- }
-
- }
- else
- {
- // no need to resolve value...
- resolvedValue = argumentValue;
- }
- return resolvedValue;
- }
-
- ///
- /// Resolve the target type of the passed .
- ///
- /// The who's target type is to be resolved
- /// The resolved target type, if any. otherwise.
- protected virtual Type ResolveTargetType(TypedStringValue value)
- {
- if (value.HasTargetType)
- {
- return value.TargetType;
- }
- else
- {
- return null;
- }
- }
- ///
- /// Resolves an inner object definition.
- ///
- ///
- /// The name of the object that surrounds this inner object definition.
- ///
- ///
- /// The name of the inner object definition... note: this is a synthetic
- /// name assigned by the factory (since it makes no sense for inner object
- /// definitions to have names).
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The definition of the inner object that is to be resolved.
- ///
- ///
- /// if the owner of the property is a singleton.
- ///
- ///
- /// The resolved object as defined by the inner object definition.
- ///
- protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition,
- bool singletonOwner)
- {
- RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition);
- mod.IsSingleton = singletonOwner;
- object instance;
- object result;
- try
- {
- instance = CreateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false);
- result = GetObjectForInstance(innerObjectName, instance);
- }
- catch (ObjectsException ex)
- {
- throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName);
- }
- if (singletonOwner && instance is IDisposable)
- {
- // keep a reference to the inner object instance, to be able to destroy
- // it on factory shutdown...
- _disposableInnerObjects.Add(instance);
- }
- return result;
- }
-
- ///
- /// Resolve a reference to another object in the factory.
- ///
- ///
- /// The name of the object that is having the value of one of its properties resolved.
- ///
- ///
- /// The definition of the named object.
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The runtime reference containing the value of the property.
- ///
- /// A reference to another object in the factory.
- protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.",
- argumentName, name, reference.ObjectName));
- }
-
- #endregion
-
- try
- {
- if (reference.IsToParent)
- {
- if (null == ParentObjectFactory)
- {
- throw new ObjectCreationException(definition.ResourceDescription, name,
- string.Format(
- "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.",
- reference.ObjectName));
- }
- return ParentObjectFactory.GetObject(reference.ObjectName);
- }
- return GetObject(reference.ObjectName);
- }
- catch (ObjectsException ex)
- {
- throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName);
- }
- }
-
- ///
- /// Find object instances that match the required .
- ///
- ///
- ///
- /// Called by autowiring. If a subclass cannot obtain information about object
- /// names by , a corresponding exception should be thrown.
- ///
+ /// Provides object creation, initialization and wiring, supporting
+ /// autowiring and constructor resolution. Handles runtime object
+ /// references, managed collections, and object destruction.
+ ///
+ ///
+ /// The main template method to be implemented by subclasses is
+ /// ,
+ /// used for autowiring by type. Note that this class does not implement object
+ /// definition registry capabilities
+ /// (
+ /// does).
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [Serializable]
+ public abstract class AbstractAutowireCapableObjectFactory : AbstractObjectFactory, IAutowireCapableObjectFactory
+ {
+ #region Constants
+
+ ///
+ /// The used during the invocation and
+ /// searching for of methods.
+ ///
+ protected const BindingFlags MethodResolutionFlags =
+ BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase;
+
+ #endregion
+
+ ///
+ /// The instance for this class.
+ ///
+ private readonly ILog log = LogManager.GetLogger(typeof(AbstractAutowireCapableObjectFactory));
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ protected AbstractAutowireCapableObjectFactory(bool caseSensitive)
+ : this(caseSensitive, null)
+ { }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ /// The parent object factory, or if none.
+ protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
+ : base(caseSensitive, parentFactory)
+ {
+ this.IgnoreDependencyInterface(typeof(IObjectFactoryAware));
+ this.IgnoreDependencyInterface(typeof(IObjectNameAware));
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The
+ /// implementation to be used to instantiate managed objects.
+ ///
+ protected IInstantiationStrategy InstantiationStrategy
+ {
+ get { return instantiationStrategy; }
+ set { instantiationStrategy = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Predict the eventual object type (of the processed object instance) for the
+ /// specified object.
+ ///
+ /// Name of the object.
+ /// The merged object definition to determine the type for.
+ ///
+ /// The type of the object, or null if not predictable
+ ///
+ protected override Type PredictObjectType(string objectName, RootObjectDefinition mod)
+ {
+ Type objectType;
+ if (StringUtils.HasText(mod.FactoryMethodName))
+ {
+ objectType = GetTypeForFactoryMethod(objectName, mod);
+ }
+ else
+ {
+ objectType = ResolveObjectType(mod, objectName);
+ }
+ return objectType;
+ }
+
+ ///
+ /// Determines the of the object defined
+ /// by the supplied object .
+ ///
+ ///
+ /// The name associated with the supplied object .
+ ///
+ ///
+ /// The
+ /// that the is to be determined for.
+ ///
+ ///
+ /// The of the object defined by the supplied
+ /// object ; or if the
+ /// cannot be determined.
+ ///
+ protected override Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
+ {
+ if (StringUtils.HasText(definition.FactoryObjectName) && definition.IsSingleton && !definition.IsLazyInit)
+ {
+ return GetObject(objectName).GetType();
+ }
+
+ Type factoryType = null;
+ bool isStatic = true;
+
+ if (StringUtils.HasText(definition.FactoryObjectName))
+ {
+ // check declared factory method return type on factory type...
+ factoryType = GetType(definition.FactoryObjectName);
+ isStatic = false;
+ }
+ else
+ {
+ factoryType = ResolveObjectType(definition, objectName);
+ }
+ if (factoryType == null)
+ {
+ return null;
+ }
+
+ // If all factory methods have the same return type, return that type.
+ // Can't clearly figure out exact method due to type converting / autowiring!
+ int minNrOfArgs = definition.ConstructorArgumentValues.GenericArgumentValues.Count;
+ MethodInfo[] candidates = factoryType.GetMethods();
+ ISet returnTypes = new HybridSet();
+ foreach (MethodInfo factoryMethod in candidates)
+ {
+#if NET_2_0
+ GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
+ if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(genericArgsInfo.GenericMethodName)
+ && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs
+ && factoryMethod.GetGenericArguments().Length == genericArgsInfo.GetGenericArguments().Length)
+ {
+ if (genericArgsInfo.ContainsGenericArguments)
+ {
+ string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
+ Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
+ for (int j = 0; j < unresolvedGenericArgs.Length; j++)
+ {
+ genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
+ }
+ returnTypes.Add(factoryMethod.MakeGenericMethod(genericArgs).ReturnType);
+ }
+ else
+ {
+ returnTypes.Add(factoryMethod.ReturnType);
+ }
+ }
+#else
+ if (factoryMethod.IsStatic == isStatic && factoryMethod.Name.Equals(definition.FactoryMethodName)
+ && ReflectionUtils.GetParameterTypes(factoryMethod).Length >= minNrOfArgs)
+ {
+ returnTypes.Add(factoryMethod.ReturnType);
+ }
+#endif
+ }
+ if (returnTypes.Count == 1)
+ {
+ // clear return type found: all factory methods return same type...
+ return (Type)ObjectUtils.EnumerateFirstElement(returnTypes);
+ }
+ else
+ {
+ // ambiguous return types found: return null to indicate "not determinable"...
+ return null;
+ }
+ }
+
+ ///
+ /// Apply the property values of the object definition with the supplied
+ /// to the supplied .
+ ///
+ ///
+ /// The existing object that the property values for the named object will
+ /// be applied to.
+ ///
+ ///
+ /// The name of the object definition associated with the property values that are
+ /// to be applied.
+ ///
+ public override void ApplyObjectPropertyValues(object instance, string name)
+ {
+ RootObjectDefinition definition = GetMergedObjectDefinition(name, true);
+ if (definition != null)
+ {
+ log.Debug(string.Format("configuring object '{0}' using definition '{1}'", instance, name));
+ ApplyPropertyValues(name, definition, new ObjectWrapper(instance), definition.PropertyValues);
+ }
+ }
+
+ ///
+ /// Apply any
+ /// s.
+ ///
+ ///
+ ///
+ /// The returned instance may be a wrapper around the original.
+ ///
+ ///
+ ///
+ /// The of the object that is to be
+ /// instantiated.
+ ///
+ ///
+ /// The name of the object that is to be instantiated.
+ ///
+ ///
+ /// An instance to use in place of the original instance.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ protected object ApplyObjectPostProcessorsBeforeInstantiation(Type objectType, string objectName)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("Invoking IInstantiationAwareObjectPostProcessors before " + "the instantiation of '{0}'.", objectName));
+ }
+
+ #endregion
+
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ object theObject = inProc.PostProcessBeforeInstantiation(objectType, objectName);
+ if (theObject != null)
+ {
+ return theObject;
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Apply the given property values, resolving any runtime references
+ /// to other objects in this object factory.
+ ///
+ ///
+ /// The object name passed for better exception information.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ ///
+ /// The new property values.
+ ///
+ ///
+ ///
+ /// Must use deep copy, so that we don't permanently modify this property.
+ ///
+ ///
+ protected void ApplyPropertyValues(string name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
+ {
+ if (properties == null || properties.PropertyValues.Length == 0)
+ {
+ return;
+ }
+ MutablePropertyValues deepCopy = new MutablePropertyValues(properties);
+ PropertyValue[] copiedProperties = deepCopy.PropertyValues;
+ for (int i = 0; i < copiedProperties.Length; ++i)
+ {
+ PropertyValue copiedProperty = copiedProperties[i];
+ object value = ResolveValueIfNecessary(name, definition, copiedProperty.Name, copiedProperty.Value);
+ PropertyValue propertyValue = new PropertyValue(copiedProperty.Name, value, copiedProperty.Expression);
+ // update mutable copy...
+ deepCopy.SetPropertyValueAt(propertyValue, i);
+ }
+ // set the (possibly resolved) deep copy properties...
+ try
+ {
+ wrapper.SetPropertyValues(deepCopy);
+ }
+ catch (ObjectsException ex)
+ {
+ // improve the message by showing the context...
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Error setting property values: " + ex.Message, ex);
+ }
+ }
+
+ ///
+ /// Return an array of object-type property names that are unsatisfied.
+ ///
+ ///
+ ///
+ /// These are probably unsatisfied references to other objects in the
+ /// factory. Does not include simple properties like primitives or
+ /// s.
+ ///
+ ///
+ ///
+ /// An array of object-type property names that are unsatisfied.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected string[] UnsatisfiedObjectProperties(RootObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ ArrayList result = new ArrayList();
+ ISet ignoredTypes = IgnoredDependencyTypes;
+ PropertyInfo[] properties = wrapper.GetPropertyInfos();
+ foreach (PropertyInfo property in properties)
+ {
+ string name = property.Name;
+ if (property.CanWrite && !ignoredTypes.Contains(property.PropertyType) && !result.Contains(name)
+ && !ObjectUtils.IsSimpleProperty(property.PropertyType))
+ {
+ result.Add(name);
+ }
+ }
+ return (string[])result.ToArray(typeof(string));
+ }
+
+ ///
+ /// Destroy all cached singletons in this factory.
+ ///
+ ///
+ ///
+ /// To be called on shutdown of a factory.
+ ///
+ ///
+ public override void Dispose()
+ {
+ base.Dispose();
+ foreach (object o in _disposableInnerObjects)
+ {
+ DestroyObject(string.Format(CultureInfo.InvariantCulture, "(Inner object of Type '{0}')", o.GetType().FullName), o);
+ }
+ _disposableInnerObjects.Clear();
+ }
+
+ ///
+ /// Populate the object instance in the given
+ /// with the property values from the
+ /// object definition.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected void PopulateObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
+ // state of the bean before properties are set. This can be used, for example,
+ // to support styles of field injection.
+ bool continueWithPropertyPopulation = true;
+
+ if (HasInstantiationAwareBeanPostProcessors)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ if (!inProc.PostProcessAfterInstantiation(wrapper.WrappedInstance, name))
+ {
+ continueWithPropertyPopulation = false;
+ break;
+ }
+ }
+ }
+ }
+ if (!continueWithPropertyPopulation)
+ {
+ return;
+ }
+
+ IPropertyValues properties = definition.PropertyValues;
+
+ if (wrapper == null)
+ {
+ if (properties.PropertyValues.Length > 0)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription,
+ name, "Cannot apply property values to null instance.");
+ }
+ else
+ {
+ // skip property population phase for null instance
+ return;
+ }
+ }
+
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByName || definition.ResolvedAutowireMode == AutoWiringMode.ByType)
+ {
+ MutablePropertyValues mpvs = new MutablePropertyValues(properties);
+ // add property values based on autowire by name if it's applied
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByName)
+ {
+ AutowireByName(name, definition, wrapper, mpvs);
+ }
+ // add property values based on autowire by type if it's applied
+ if (definition.ResolvedAutowireMode == AutoWiringMode.ByType)
+ {
+ AutowireByType(name, definition, wrapper, mpvs);
+ }
+ properties = mpvs;
+ }
+ //DependencyCheck(name, definition, wrapper, properties);
+
+
+ bool hasInstAwareOpps = HasInstantiationAwareBeanPostProcessors;
+ bool needsDepCheck = (definition.DependencyCheck != DependencyCheckingMode.None);
+
+
+ if (hasInstAwareOpps || needsDepCheck)
+ {
+ PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
+ if (hasInstAwareOpps)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor instantiationAwareObjectPostProcessor =
+ processor as IInstantiationAwareObjectPostProcessor;
+ if (instantiationAwareObjectPostProcessor != null)
+ {
+ properties =
+ instantiationAwareObjectPostProcessor.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance,
+ name);
+ if (properties == null)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ if (needsDepCheck)
+ {
+ CheckDependencies(name, definition, filteredPropInfo, properties);
+ }
+
+ }
+
+ ApplyPropertyValues(name, definition, wrapper, properties);
+ }
+
+ ///
+ /// Wires up any exposed events in the object instance in the given
+ /// with any event handler
+ /// values from the .
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ protected void WireEvents(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper)
+ {
+ foreach (string eventName in definition.EventHandlerValues.Events)
+ {
+ foreach (IEventHandlerValue handlerValue
+ in definition.EventHandlerValues[eventName])
+ {
+ object handler = null;
+ if (handlerValue.Source is RuntimeObjectReference)
+ {
+ RuntimeObjectReference roref = (RuntimeObjectReference)handlerValue.Source;
+ handler = ResolveReference(definition, name, eventName, roref);
+ }
+ else if (handlerValue.Source is Type)
+ {
+ // a static Type event is being wired up; simply pass on the Type
+ handler = handlerValue.Source;
+ }
+ else if (handlerValue.Source is string)
+ {
+ // a static Type event is being wired up; we need to resolve the Type
+ handler = TypeResolutionUtils.ResolveType(handlerValue.Source as string);
+ }
+ else
+ {
+ throw new FatalObjectException("Currently, only references to other objects and Types are " + "supported as event sources.");
+ }
+ handlerValue.Wire(handler, wrapper.WrappedInstance);
+ }
+ }
+ }
+
+ ///
+ /// Fills in any missing property values with references to
+ /// other objects in this factory if autowire is set to
+ /// .
+ ///
+ ///
+ /// The object name to be autowired by .
+ ///
+ ///
+ /// The definition of the named object to update through autowiring.
+ ///
+ ///
+ /// The wrapping the target object (and
+ /// from which we can rip out information concerning the object).
+ ///
+ ///
+ /// The property values to register wired objects with.
+ ///
+ protected void AutowireByName(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
+ {
+ string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
+ foreach (string propertyName in propertyNames)
+ {
+ // look for a matching type
+ if (ContainsObject(propertyName))
+ {
+ object o = GetObject(propertyName);
+ properties.Add(propertyName, o);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Added autowiring by name from object name '{0}' via " + "property '{1}' to object named '{1}'.", name,
+ propertyName));
+ }
+
+ #endregion
+ }
+ else
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Not autowiring property '{0}' of object '{1}' by name: " + "no matching object found.", propertyName, name));
+ }
+
+ #endregion
+ }
+ }
+ }
+
+ ///
+ /// Defines "autowire by type" (object properties by type) behavior.
+ ///
+ ///
+ ///
+ /// This is like PicoContainer default, in which there must be exactly one object
+ /// of the property type in the object factory. This makes object factories simple
+ /// to configure for small namespaces, but doesn't work as well as standard Spring
+ /// behavior for bigger applications.
+ ///
+ ///
+ ///
+ /// The object name to be autowired by .
+ ///
+ ///
+ /// The definition of the named object to update through autowiring.
+ ///
+ ///
+ /// The wrapping the target object (and
+ /// from which we can rip out information concerning the object).
+ ///
+ ///
+ /// The property values to register wired objects with.
+ ///
+ protected void AutowireByType(string name, RootObjectDefinition definition, IObjectWrapper wrapper, MutablePropertyValues properties)
+ {
+ string[] propertyNames = UnsatisfiedObjectProperties(definition, wrapper);
+ foreach (string propertyName in propertyNames)
+ {
+ // look for a matching type
+ Type requiredType = wrapper.GetPropertyType(propertyName);
+ IDictionary matchingObjects = FindMatchingObjects(requiredType);
+ if (matchingObjects != null && matchingObjects.Count == 1)
+ {
+ properties.Add(propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Values));
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Autowiring by type from object name '{0}' via property " + "'{1}' to object named '{2}'.", name,
+ propertyName, ObjectUtils.EnumerateFirstElement(matchingObjects.Keys)));
+ }
+
+ #endregion
+ }
+ else if (matchingObjects != null && matchingObjects.Count > 1)
+ {
+ throw new UnsatisfiedDependencyException(string.Empty, name, propertyName,
+ string.Format(CultureInfo.InvariantCulture,
+ "There are {0} objects of Type [{1}] for autowire by "
+ + "type, when there should have been just 1 to be able to "
+ + "autowire property '{2}' of object '{3}'.", matchingObjects.Count,
+ requiredType, propertyName, name));
+ }
+ else
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Not autowiring property '{0}' of object '{1}': no matching object found.",
+ propertyName, name));
+ }
+
+ #endregion
+ }
+ }
+ }
+
+ ///
+ /// Ignore the given dependency type for autowiring
+ ///
+ ///
+ /// This will typically be used by application contexts to register
+ /// dependencies that are resolved in other ways, like IOjbectFactory through
+ /// IObjectFactoryAware or IApplicationContext through IApplicationContextAware.
+ /// By default, IObjectFactoryAware and IObjectName interfaces are ignored.
+ /// For further types to ignore, invoke this method for each type.
+ ///
+ /// .
+ public void IgnoreDependencyInterface(Type type)
+ {
+ ignoredDependencyInterfaces.Add(type);
+ }
+
+ ///
+ /// Create an object instance for the given object definition.
+ ///
+ /// The name of the object.
+ ///
+ /// The object definition for the object that is to be instantiated.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. It is invalid to use a non- arguments value
+ /// in any other case.
+ ///
+ ///
+ /// A new instance of the object.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ ///
+ ///
+ /// Delegates to the
+ ///
+ /// method version with the allowEagerCaching parameter set to true.
+ ///
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
+ ///
+ protected override object CreateObject(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ return CreateObject(name, definition, arguments, true);
+ }
+
+ ///
+ /// Create an object instance for the given object definition.
+ ///
+ /// The name of the object.
+ ///
+ /// The object definition for the object that is to be instantiated.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. It is invalid to use a non- arguments value
+ /// in any other case.
+ ///
+ ///
+ /// Whether eager caching of singletons is allowed... typically true for
+ /// singlton objects, but never true for inner object definitions.
+ ///
+ ///
+ /// A new instance of the object.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ ///
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
+ ///
+ protected virtual object CreateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching)
+ {
+ // guarantee the initialization of objects that the current one depends on..
+ if (definition.DependsOn != null && definition.DependsOn.Length > 0)
+ {
+ foreach (string dependant in definition.DependsOn)
+ {
+ GetObject(dependant);
+ }
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Creating instance of Object '{0}' with merged definition [{1}].", name, definition));
+ }
+
+ #endregion
+
+ // Make sure object type is actually resolved at this point.
+ ResolveObjectType(definition, name);
+
+ try
+ {
+ definition.PrepareMethodOverrides();
+ }
+ catch (ObjectDefinitionValidationException ex)
+ {
+ throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
+ "Validation of method overrides failed. " + ex.Message, ex);
+ }
+
+ // return IObjectDefinition instance itself for an abstract object-definition
+ if (definition.IsTemplate)
+ {
+ return definition;
+ }
+
+
+
+ object instance = null;
+
+
+ IObjectWrapper instanceWrapper = null;
+ bool eagerlyCached = false;
+ try
+ {
+ // Give IInstantiationAwareObjectPostProcessors a chance to return a proxy instead of the target instance....
+ if (definition.HasObjectType)
+ {
+ instance = ApplyObjectPostProcessorsBeforeInstantiation(definition.ObjectType, name);
+ if (instance != null)
+ {
+ return instance;
+ }
+ }
+
+
+ instanceWrapper = CreateObjectInstance(name, definition, arguments);
+ instance = instanceWrapper.WrappedInstance;
+
+ // eagerly cache singletons to be able to resolve circular references
+ // even when triggered by lifecycle interfaces like IObjectFactoryAware.
+ if (allowEagerCaching && definition.IsSingleton)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Eagerly caching object '" + name + "' to allow for resolving potential circular references");
+ }
+ AddEagerlyCachedSingleton(name, definition, instance);
+ eagerlyCached = true;
+ }
+
+ instance = ConfigureObject(name, definition, instanceWrapper);
+ }
+ catch (ObjectCreationException)
+ {
+ if (eagerlyCached)
+ {
+ RemoveEagerlyCachedSingleton(name, definition);
+ }
+ throw;
+ }
+ catch (Exception ex)
+ {
+ if (eagerlyCached)
+ {
+ RemoveEagerlyCachedSingleton(name, definition);
+ }
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Initialization of object failed : " + ex.Message, ex);
+ }
+ return instance;
+ }
+
+ ///
+ /// Add the created, but yet unpopulated singleton to the singleton cache
+ /// to be able to resolve circular references
+ ///
+ /// the name of the object to add to the cache.
+ /// the definition used to create and populated the object.
+ /// the raw object instance.
+ ///
+ /// Derived classes may override this method to select the right cache based on the object definition.
+ ///
+ protected virtual void AddEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition, object rawSingletonInstance)
+ {
+ base.AddSingleton(objectName, rawSingletonInstance);
+ }
+
+ ///
+ /// Remove the specified singleton from the singleton cache that has
+ /// been added before by a call to
+ ///
+ /// the name of the object to remove from the cache.
+ /// the definition used to create and populated the object.
+ ///
+ /// Derived classes may override this method to select the right cache based on the object definition.
+ ///
+ protected virtual void RemoveEagerlyCachedSingleton(string objectName, IObjectDefinition objectDefinition)
+ {
+ base.RemoveSingleton(objectName);
+ }
+
+ ///
+ /// Creates an instance from the passed in
+ /// using constructor
+ ///
+ /// The name of the object to create - used for error messages.
+ /// The describing the object to be created.
+ /// optional arguments to pass to the constructor
+ /// An wrapping the already instantiated object
+ protected IObjectWrapper CreateObjectInstance(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ IObjectWrapper instanceWrapper;
+ if (StringUtils.HasText(definition.FactoryMethodName))
+ {
+ instanceWrapper = InstantiateUsingFactoryMethod(name, definition, arguments);
+ }
+ //Handle case when arguments are passed in explicitly.
+ else if (arguments != null && arguments.Length > 0)
+ {
+ instanceWrapper = AutowireConstructor(name, definition, arguments);
+ }
+ else if (definition.ResolvedAutowireMode == AutoWiringMode.Constructor ||
+ definition.HasConstructorArgumentValues)
+ {
+ instanceWrapper = AutowireConstructor(name, definition);
+ }
+ else
+ {
+ instanceWrapper = new ObjectWrapper(InstantiationStrategy.Instantiate(definition, name, this));
+ InitObjectWrapper(instanceWrapper);
+ }
+ return instanceWrapper;
+ }
+
+ ///
+ /// Instantiate an object instance using a named factory method.
+ ///
+ ///
+ ///
+ /// The method may be static, if the
+ /// parameter specifies a class, rather than a
+ /// instance, or an
+ /// instance variable on a factory object itself configured using Dependency
+ /// Injection.
+ ///
+ ///
+ /// Implementation requires iterating over the static or instance methods
+ /// with the name specified in the supplied
+ /// (the method may be overloaded) and trying to match with the parameters.
+ /// We don't have the types attached to constructor args, so trial and error
+ /// is the only way to go here.
+ ///
+ ///
+ ///
+ /// The name associated with the supplied .
+ ///
+ ///
+ /// The definition describing the instance that is to be instantiated.
+ ///
+ ///
+ /// Any arguments to the factory method that is to be invoked.
+ ///
+ ///
+ /// The result of the factory method invocation (the instance).
+ ///
+ protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
+ {
+ ConstructorArgumentValues cargs = definition.ConstructorArgumentValues;
+ ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
+ int expectedArgCount = 0;
+
+ // we don't have arguments passed in programmatically, so we need to resolve the
+ // arguments specified in the constructor arguments held in the object definition...
+ if (arguments == null || arguments.Length == 0)
+ {
+ expectedArgCount = cargs.ArgumentCount;
+ ResolveConstructorArguments(name, definition, resolvedValues);
+ }
+ else
+ {
+ // if we have constructor args, don't need to resolve them...
+ expectedArgCount = arguments.Length;
+ }
+ ObjectWrapper wrapper = new ObjectWrapper();
+ InitObjectWrapper(wrapper);
+ bool isStatic = true;
+ Type factoryClass = null;
+ if (StringUtils.HasText(definition.FactoryObjectName))
+ {
+ // it's an instance method on the factory object's class...
+ factoryClass = GetObject(definition.FactoryObjectName).GetType();
+ isStatic = false;
+ }
+ else
+ {
+ // it's a static factory method on the object class...
+ factoryClass = definition.ObjectType;
+ }
+
+#if NET_2_0
+ GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName);
+
+ MethodInfo[] factoryMethods = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass);
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ // try all matching methods to see if they match the constructor arguments...
+ for (int i = 0; i < factoryMethods.Length; i++)
+ {
+ unsatisfiedDependencyExceptionData = null;
+ MethodInfo factoryMethod = factoryMethods[i];
+
+ if (genericArgsInfo.ContainsGenericArguments)
+ {
+ string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
+ if (factoryMethod.GetGenericArguments().Length != unresolvedGenericArgs.Length)
+ continue;
+
+ Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
+ for (int j = 0; j < unresolvedGenericArgs.Length; j++)
+ {
+ genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
+ }
+ factoryMethod = factoryMethod.MakeGenericMethod(genericArgs);
+ }
+#else
+ MethodInfo[] factoryMethods = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass);
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ // try all matching methods to see if they match the constructor arguments...
+ foreach(MethodInfo factoryMethod in factoryMethods)
+ {
+#endif
+ if (arguments == null || arguments.Length == 0)
+ {
+ // try to create the required arguments...
+ arguments = CreateArgumentArray(name, definition, resolvedValues, factoryMethod, out unsatisfiedDependencyExceptionData);
+ if (arguments == null)
+ {
+ // if we failed to match this method, keep
+ // trying new overloaded factory methods...
+ continue;
+ }
+ }
+ // if we get here, we found a factory method...
+
+ if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethod }, arguments) == null)
+ {
+ continue;
+ }
+
+
+ object objectInstance = InstantiationStrategy.Instantiate(definition, name, this, factoryMethod, arguments);
+ wrapper.WrappedInstance = objectInstance;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethod));
+ }
+
+ #endregion
+
+ return wrapper;
+ }
+
+
+
+ // if we get here, we didn't match any method...
+ throw new ObjectDefinitionStoreException(
+ string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName,
+ factoryClass));
+ }
+
+ ///
+ /// Returns an array of all of those
+ /// methods exposed on the
+ /// that match the supplied criteria.
+ ///
+ ///
+ /// Methods that have this name (can be in the form of a regular expression).
+ ///
+ ///
+ /// Methods that have exactly this many arguments.
+ ///
+ ///
+ /// Methods that are static / instance.
+ ///
+ ///
+ /// The on which the methods (if any) are to be found.
+ ///
+ ///
+ /// An array of all of those
+ /// methods exposed on the
+ /// that match the supplied criteria.
+ ///
+ private static MethodInfo[] FindMethods(string methodName, int expectedArgumentCount, bool isStatic, Type searchType)
+ {
+ ComposedCriteria methodCriteria = new ComposedCriteria();
+ methodCriteria.Add(new MethodNameMatchCriteria(methodName));
+ methodCriteria.Add(new MethodParametersCountCriteria(expectedArgumentCount));
+ BindingFlags methodFlags = BindingFlags.Public | BindingFlags.IgnoreCase | (isStatic ? BindingFlags.Static : BindingFlags.Instance);
+ MemberInfo[] methods =
+ searchType.FindMembers(MemberTypes.Method, methodFlags, new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ methodCriteria);
+ return (MethodInfo[])ArrayList.Adapter(methods).ToArray(typeof(MethodInfo));
+ }
+
+ ///
+ /// Create an array of arguments to invoke a constructor or static factory method,
+ /// given the resolved constructor arguments values.
+ ///
+ /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
+ /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using
+ /// exceptions for flow control as in the original implementation.
+ private object[] CreateArgumentArray(string name, RootObjectDefinition definition,
+ ConstructorArgumentValues resolvedValues, MethodBase methodOrCtor, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
+ {
+ string methodType = (methodOrCtor is ConstructorInfo) ? "constructor" : "factory method";
+ unsatisfiedDependencyExceptionData = null;
+ ParameterInfo[] argTypes = methodOrCtor.GetParameters();
+ object[] args = new object[argTypes.Length];
+ ISet alreadyUsedValues = new HybridSet();
+ for (int j = 0; j < argTypes.Length; ++j)
+ {
+ Type parameterType = argTypes[j].ParameterType;
+ string parameterName = argTypes[j].Name;
+ ConstructorArgumentValues.ValueHolder valueHolder = null;
+ if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
+ {
+ valueHolder = resolvedValues.GetArgumentValue(parameterName, parameterType, alreadyUsedValues);
+ }
+ else
+ {
+ valueHolder = resolvedValues.GetArgumentValue(j, parameterType, alreadyUsedValues);
+ }
+ if (valueHolder != null)
+ {
+ try
+ {
+ args[j] = TypeConversionUtils.ConvertValueIfNecessary(parameterType, valueHolder.Value, null);
+ alreadyUsedValues.Add(valueHolder);
+ }
+ catch (TypeMismatchException ex)
+ {
+ string errorMessage = String.Format(CultureInfo.InvariantCulture,
+ "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
+ methodType, valueHolder.Value,
+ parameterType, ex.Message);
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
+
+
+ return null;
+ }
+ }
+ else
+ {
+ if (definition.ResolvedAutowireMode != AutoWiringMode.Constructor)
+ {
+ string errorMessage = String.Format(CultureInfo.InvariantCulture,
+ "Ambiguous {0} argument types - " +
+ "Did you specify the correct object references as {0} arguments?",
+ methodType);
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
+
+ return null;
+ }
+ IDictionary matchingObjects = FindMatchingObjects(parameterType);
+ if (matchingObjects == null || matchingObjects.Count != 1)
+ {
+ string errorMessage = String.Format(CultureInfo.InvariantCulture,
+ "There are '{0}' objects of type [{1}] for autowiring "
+ +
+ "{2}. There should have been exactly 1 to be able to "
+ +
+ "autowire the '{3}' argument on the {2} of object '{4}'.",
+ (matchingObjects == null
+ ? 0
+ : matchingObjects.Count),
+ parameterType, methodType,
+ parameterName, name);
+ unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(j, parameterType, errorMessage);
+
+ return null;
+ }
+ DictionaryEntry entry = (DictionaryEntry)ObjectUtils.EnumerateFirstElement(matchingObjects);
+ args[j] = entry.Value;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture,
+ "Autowiring '{0}' argument by type from object name '{1}' via {2} to "
+ + "object named '{3}'.", parameterName, name, methodType, entry.Key));
+ }
+
+ #endregion
+ }
+ }
+
+ return args;
+ }
+
+ ///
+ /// Explicitly construct the object using the supplied constructor arguments.
+ /// Constructor arguments are matched by type.
+ ///
+ ///
+ /// The name of the object to autowire by type.
+ ///
+ ///
+ /// The object definition to update through autowiring.
+ ///
+ /// Array of constructor argument values.
+ ///
+ /// An for the new instance.
+ ///
+ protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, object[] args)
+ {
+ ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
+ for (int i = 0; i < args.Length; i++)
+ {
+ //This is assigning ctor arguments by type.
+ resolvedValues.AddGenericArgumentValue(args[i]);
+ }
+ return AutowireConstructor(name, definition, resolvedValues);
+ }
+
+ ///
+ /// "autowire constructor" (with constructor arguments by type) behaviour.
+ ///
+ /// Passes an empty collection of constructor argument values
+ /// to overloaded method.
+ ///
+ ///
+ /// The name of the object to autowire by type.
+ ///
+ ///
+ /// The object definition to update through autowiring.
+ ///
+ ///
+ /// An for the new instance.
+ ///
+ protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition)
+ {
+ return AutowireConstructor(name, definition, new ConstructorArgumentValues());
+ }
+
+ ///
+ /// "autowire constructor" (with constructor arguments by type) behaviour.
+ ///
+ ///
+ ///
+ /// Also applied if explicit constructor argument values are specified,
+ /// matching all remaining arguments with objects from the object factory.
+ ///
+ ///
+ /// This corresponds to constructor injection: in this mode, a Spring.NET
+ /// object factory is able to host components that expect constructor-based
+ /// dependency resolution.
+ ///
+ ///
+ ///
+ /// The name of the object to autowire by type.
+ ///
+ ///
+ /// The object definition to update through autowiring.
+ ///
+ ///
+ /// The collection on constructor argument values.
+ ///
+ ///
+ /// An for the new instance.
+ ///
+ protected IObjectWrapper AutowireConstructor(string name, RootObjectDefinition definition, ConstructorArgumentValues argumentValues)
+ {
+ int minNrOfArgs = ResolveConstructorArguments(name, definition, argumentValues);
+ ConstructorInfo[] constructors = AutowireUtils.GetConstructors(definition, minNrOfArgs);
+ if (constructors == null || constructors.Length == 0)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ string.Format(CultureInfo.InvariantCulture,
+ "'{0}' constructor arguments specified but no matching constructor found "
+ + "in object '{1}' (hint: specify argument indexes, names, or "
+ + "types to avoid ambiguities).", minNrOfArgs, name));
+ }
+ ObjectWrapper wrapper = new ObjectWrapper();
+ InitObjectWrapper(wrapper);
+ ConstructorInfo constructorToUse = null;
+ object[] argsToUse = null;
+ int weighting = Int32.MaxValue;
+ UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
+ for (int i = 0; i < constructors.Length; ++i)
+ {
+ unsatisfiedDependencyExceptionData = null;
+ ConstructorInfo constructor = constructors[i];
+ if (constructorToUse != null &&
+ constructorToUse.GetParameters().Length > constructor.GetParameters().Length)
+ {
+ // already found greedy constructor that can be satisfied, so
+ // don't look any further, there are only less greedy constructors left...
+ break;
+ }
+
+ object[] args = CreateArgumentArray(name, definition, argumentValues, constructor, out unsatisfiedDependencyExceptionData);
+ if (args == null)
+ {
+ if (i == constructors.Length - 1 && constructorToUse == null)
+ {
+ throw new UnsatisfiedDependencyException(definition.ResourceDescription,
+ name,
+ unsatisfiedDependencyExceptionData.ParameterIndex,
+ unsatisfiedDependencyExceptionData.ParameterType,
+ unsatisfiedDependencyExceptionData.ErrorMessage);
+ }
+ // try next constructor...
+ continue;
+ }
+
+ int typeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(constructor.GetParameters(), args);
+ if (typeDiffWeight < weighting)
+ {
+ constructorToUse = constructor;
+ argsToUse = args;
+ weighting = typeDiffWeight;
+ }
+ }
+
+ if (constructorToUse == null)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Could not resolve matching constructor.");
+ }
+ wrapper.WrappedInstance = InstantiationStrategy.Instantiate(definition, name, this, constructorToUse, argsToUse);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", name, constructorToUse));
+ }
+
+ #endregion
+
+ return wrapper;
+ }
+
+ ///
+ /// Resolves the
+ /// of the supplied .
+ ///
+ ///
+ ///
+ /// 'Resolve' can be taken to mean that all of the s
+ /// constructor arguments is resolved into a concrete object that can be plugged
+ /// into one of the s constructors. Runtime object
+ /// references to other objects in this (or a parent) factory are resolved,
+ /// type conversion is performed, etc.
+ ///
+ ///
+ /// These resolved values are plugged into the supplied
+ /// object, because we wouldn't want to touch
+ /// the s constructor arguments in case it (or any of
+ /// its constructor arguments) is a prototype object definition.
+ ///
+ ///
+ /// This method is also used for handling invocations of static factory methods.
+ ///
+ ///
+ ///
+ /// The name of the object that is being resolved by this factory.
+ ///
+ ///
+ /// The definition associated with the above .
+ ///
+ ///
+ /// Where the resolved constructor arguments will be placed.
+ ///
+ ///
+ /// The minimum number of arguments that any constructor for the supplied
+ /// must have.
+ ///
+ private int ResolveConstructorArguments(string name, RootObjectDefinition definition, ConstructorArgumentValues resolvedValues)
+ {
+ int minNrOfArgs = 0;
+ if (definition.ConstructorArgumentValues != null)
+ {
+ minNrOfArgs = definition.ConstructorArgumentValues.ArgumentCount;
+ foreach (DictionaryEntry de in definition.ConstructorArgumentValues.IndexedArgumentValues)
+ {
+ int index = (int)de.Key;
+ if (index < 0)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name, "Invalid constructor argument index: " + index);
+ }
+ if (index > minNrOfArgs)
+ {
+ minNrOfArgs = index + 1;
+ }
+ string argName = "constructor argument with index " + index;
+ ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)de.Value;
+ object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
+ resolvedValues.AddIndexedArgumentValue(index, resolvedValue,
+ StringUtils.HasText(valueHolder.Type)
+ ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
+ : null);
+ }
+ foreach (ConstructorArgumentValues.ValueHolder valueHolder in definition.ConstructorArgumentValues.GenericArgumentValues)
+ {
+ string argName = "constructor argument";
+ object resolvedValue = ResolveValueIfNecessary(name, definition, argName, valueHolder.Value);
+ resolvedValues.AddGenericArgumentValue(resolvedValue,
+ StringUtils.HasText(valueHolder.Type)
+ ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName
+ : null);
+ }
+ foreach (DictionaryEntry namedArgumentEntry in definition.ConstructorArgumentValues.NamedArgumentValues)
+ {
+ string argumentName = (string)namedArgumentEntry.Key;
+ string syntheticArgumentName = "constructor argument with name " + argumentName;
+ ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder)namedArgumentEntry.Value;
+ object resolvedValue = ResolveValueIfNecessary(name, definition, syntheticArgumentName, valueHolder.Value);
+ resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue);
+ }
+ }
+ return minNrOfArgs;
+ }
+
+ ///
+ /// Perform a dependency check that all properties exposed have been set, if desired.
+ ///
+ ///
+ ///
+ /// Dependency checks can be objects (collaborating objects), simple (primitives
+ /// and ), or all (both).
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The wrapping the target object.
+ ///
+ ///
+ /// The property values to be checked.
+ ///
+ ///
+ /// If all of the checked dependencies were not satisfied.
+ ///
+ protected void DependencyCheck(string name, IConfigurableObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
+ {
+ DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
+ if (dependencyCheck == DependencyCheckingMode.None)
+ {
+ return;
+ }
+
+ PropertyInfo[] filteredPropInfo = FilterPropertyInfoForDependencyCheck(wrapper);
+ if (HasInstantiationAwareBeanPostProcessors)
+ {
+ foreach (IObjectPostProcessor processor in ObjectPostProcessors)
+ {
+ IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor;
+ if (inProc != null)
+ {
+ properties =
+ inProc.PostProcessPropertyValues(properties, filteredPropInfo, wrapper.WrappedInstance, name);
+ if (properties == null)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+
+ CheckDependencies(name, definition, filteredPropInfo, properties);
+ }
+
+ private static void CheckDependencies(string name, IConfigurableObjectDefinition definition, PropertyInfo[] filteredPropInfo, IPropertyValues properties)
+ {
+ DependencyCheckingMode dependencyCheck = definition.DependencyCheck;
+ foreach (PropertyInfo property in filteredPropInfo)
+ {
+ if (property.CanWrite && properties.GetPropertyValue(property.Name) == null)
+ {
+ bool isSimple = ObjectUtils.IsSimpleProperty(property.PropertyType);
+ bool unsatisfied = (dependencyCheck == DependencyCheckingMode.All) || (isSimple && dependencyCheck == DependencyCheckingMode.Simple)
+ || (!isSimple && dependencyCheck == DependencyCheckingMode.Objects);
+ if (unsatisfied)
+ {
+ throw new UnsatisfiedDependencyException(definition.ResourceDescription, name, property.Name,
+ "Set this property value or disable dependency checking for this object.");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Extract a filtered set of PropertyInfos from the given IObjectWrapper, excluding
+ /// ignored dependency types.
+ ///
+ /// The object wrapper the object was created with.
+ /// The filtered PropertyInfos
+ private PropertyInfo[] FilterPropertyInfoForDependencyCheck(IObjectWrapper wrapper)
+ {
+ lock (filteredPropertyDescriptorsCache)
+ {
+ PropertyInfo[] filtered = (PropertyInfo[])filteredPropertyDescriptorsCache[wrapper.WrappedType];
+ if (filtered == null)
+ {
+
+ ArrayList list = new ArrayList(wrapper.GetPropertyInfos());
+ for (int i = list.Count - 1; i >= 0; i--)
+ {
+ PropertyInfo pi = (PropertyInfo)list[i];
+ if (IsExcludedFromDependencyCheck(pi))
+ {
+ list.RemoveAt(i);
+ }
+ }
+
+ filtered = (PropertyInfo[])list.ToArray(typeof(PropertyInfo));
+ filteredPropertyDescriptorsCache.Add(wrapper.WrappedType, filtered);
+ }
+ return filtered;
+ }
+
+ }
+
+ private bool IsExcludedFromDependencyCheck(PropertyInfo pi)
+ {
+ bool b1 = !pi.CanWrite; //AutowireUtils.IsExcludedFromDependencyCheck(pi);
+ bool b2 = IgnoredDependencyTypes.Contains(pi.PropertyType);
+ bool b3 = AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
+ return b1 || b2 || b3;
+ /*
+ return AutowireUtils.IsExcludedFromDependencyCheck(pi) ||
+ IgnoredDependencyTypes.Contains(pi.PropertyType) ||
+ AutowireUtils.IsSetterDefinedInInterface(pi, ignoredDependencyInterfaces);
+ */
+ }
+
+ ///
+ /// Give an object a chance to react now all its properties are set,
+ /// and a chance to know about its owning object factory (this object).
+ ///
+ ///
+ ///
+ /// This means checking whether the object implements
+ /// and / or
+ /// , and invoking the
+ /// necessary callback(s) if it does.
+ ///
+ ///
+ /// Custom init methods are resolved in a case-insensitive manner.
+ ///
+ ///
+ ///
+ /// The new object instance we may need to initialise.
+ ///
+ ///
+ /// The name the object has in the factory. Used for logging output.
+ ///
+ ///
+ /// The definition of the target object instance.
+ ///
+ protected virtual void InvokeInitMethods(object target, string name, IConfigurableObjectDefinition definition)
+ {
+ if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IInitializingObject), target))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling AfterPropertiesSet() on object with name '{0}'.", name));
+ }
+
+ #endregion
+
+ ((IInitializingObject)target).AfterPropertiesSet();
+ }
+ if (StringUtils.HasText(definition.InitMethodName))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Calling custom init method '{0} on object with name '{1}'.",
+ definition.InitMethodName, name));
+ }
+
+ #endregion
+
+ try
+ {
+ MethodInfo targetMethod = target.GetType().GetMethod(definition.InitMethodName, MethodResolutionFlags, null, Type.EmptyTypes, null);
+ if (targetMethod == null)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Could not find the named initialization method '" + definition.InitMethodName + "'.");
+ }
+ targetMethod.Invoke(target, ObjectUtils.EmptyObjects);
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Initialization method '" + definition.InitMethodName + "' threw exception", ex.GetBaseException());
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Invocation of initialization method '" + definition.InitMethodName + "' failed", ex);
+ }
+ }
+ }
+
+ ///
+ /// Invoke the specified custom destroy method on the given object.
+ ///
+ ///
+ ///
+ /// This implementation invokes a no-arg method if found, else checking
+ /// for a method with a single boolean argument (passing in "true",
+ /// assuming a "force" parameter), else logging an error.
+ ///
+ ///
+ /// Can be overridden in subclasses for custom resolution of destroy
+ /// methods with arguments.
+ ///
+ ///
+ /// Custom destroy methods are resolved in a case-insensitive manner.
+ ///
+ /// Must destroy objects that depend on the given object before the object itself.
+ /// Should not throw any exceptions.
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The target object instance to destroyed.
+ ///
+ protected override void DestroyObject(string name, object target)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Destroying dependant objects for object '" + name + "'");
+ }
+
+ #endregion
+
+ DestroyDependantObjects(name);
+ if (target is IDisposable)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture, "Calling Dispose () on object with name '{0}'.", name));
+ }
+
+ #endregion
+
+ try
+ {
+ ((IDisposable)target).Dispose();
+ }
+ catch (Exception ex)
+ {
+ #region Instrumentation
+
+ log.Error("Destroy() on object with name '" + name + "' threw an exception.", ex);
+
+ #endregion
+ }
+ }
+ RootObjectDefinition rootDefinition = GetMergedObjectDefinition(name, false);
+ if (rootDefinition != null && StringUtils.HasText(rootDefinition.DestroyMethodName))
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Calling custom destroy method '" + rootDefinition.DestroyMethodName + "' on object with name '" + name + "'.");
+ }
+
+ #endregion
+
+ InvokeCustomDestroyMethod(name, target, rootDefinition.DestroyMethodName);
+ }
+ }
+
+ ///
+ /// Destroys all of the objects registered as dependant on the
+ /// object (definition) identified by the supplied .
+ ///
+ ///
+ /// The name of the root object (definition) that is itself being destroyed.
+ ///
+ private void DestroyDependantObjects(string name)
+ {
+ string[] dependingObjects = GetDependingObjectNames(name);
+ foreach (string doName in dependingObjects)
+ {
+ DestroySingleton(doName);
+ }
+ }
+
+ ///
+ /// Given a property value, return a value, resolving any references to other
+ /// objects in the factory if necessary.
+ ///
+ ///
+ ///
+ /// The value could be :
+ ///
+ ///
+ ///
+ /// An ,
+ /// which leads to the creation of a corresponding new object instance.
+ /// Singleton flags and names of such "inner objects" are always ignored: inner objects
+ /// are anonymous prototypes.
+ ///
+ ///
+ ///
+ ///
+ /// A , which must
+ /// be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An . This is a
+ /// special placeholder collection that may contain
+ /// s or
+ /// collections that will need to be resolved.
+ ///
+ ///
+ ///
+ ///
+ /// An ordinary object or , in which case it's left alone.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The name of the object that is having the value of one of its properties resolved.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The value of the property that is being resolved.
+ ///
+ protected object ResolveValueIfNecessary(string name, RootObjectDefinition definition, string argumentName, object argumentValue)
+ {
+ object resolvedValue = null;
+ // we must check the argument value to see whether it requires a runtime
+ // reference to another object to be resolved.
+ // if it does, we'll attempt to instantiate the object and set the reference.
+ if (argumentValue is ObjectDefinitionHolder)
+ {
+ // contains an IObjectDefinition with name and aliases...
+ ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue;
+ resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton);
+ }
+ else if (argumentValue is IObjectDefinition)
+ {
+ // resolve plain IObjectDefinition, without contained name: use dummy name...
+ IObjectDefinition def = (IObjectDefinition)argumentValue;
+ resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton);
+
+ }
+ else if (argumentValue is RuntimeObjectReference)
+ {
+ RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue;
+ resolvedValue = ResolveReference(definition, name, argumentName, roref);
+ }
+ else if (argumentValue is ExpressionHolder)
+ {
+ ExpressionHolder expHolder = (ExpressionHolder)argumentValue;
+ object context = null;
+ IDictionary variables = null;
+
+ if (expHolder.Properties != null)
+ {
+ PropertyValue contextProperty = expHolder.Properties.GetPropertyValue("Context");
+ context = contextProperty == null
+ ? null
+ : ResolveValueIfNecessary(name, definition, "Context",
+ contextProperty.Value);
+ PropertyValue variablesProperty = expHolder.Properties.GetPropertyValue("Variables");
+ object vars = (variablesProperty == null
+ ? null
+ : ResolveValueIfNecessary(name, definition, "Variables",
+ variablesProperty.Value));
+ if (vars is IDictionary)
+ {
+ variables = (IDictionary)vars;
+ }
+ else
+ {
+ if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary");
+ }
+ }
+
+ if (variables == null) variables = CollectionsUtil.CreateCaseInsensitiveHashtable();
+ // add 'this' objectfactory reference to variables
+ variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, this);
+
+ resolvedValue = expHolder.Expression.GetValue(context, variables);
+ }
+ else if (argumentValue is IManagedCollection)
+ {
+ resolvedValue =
+ ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName,
+ new ManagedCollectionElementResolver(ResolveValueIfNecessary));
+ }
+ else if (argumentValue is TypedStringValue)
+ {
+ TypedStringValue tsv = (TypedStringValue)argumentValue;
+ try
+ {
+ Type resolvedTargetType = ResolveTargetType(tsv);
+ if (resolvedTargetType != null)
+ {
+ resolvedValue = TypeConversionUtils.ConvertValueIfNecessary(tsv.TargetType, tsv.Value, null);
+ }
+ else
+ {
+ resolvedValue = tsv.Value;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ "Error converted typed String value for " + argumentName, ex);
+ }
+
+ }
+ else
+ {
+ // no need to resolve value...
+ resolvedValue = argumentValue;
+ }
+ return resolvedValue;
+ }
+
+ ///
+ /// Resolve the target type of the passed .
+ ///
+ /// The who's target type is to be resolved
+ /// The resolved target type, if any. otherwise.
+ protected virtual Type ResolveTargetType(TypedStringValue value)
+ {
+ if (value.HasTargetType)
+ {
+ return value.TargetType;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ ///
+ /// Resolves an inner object definition.
+ ///
+ ///
+ /// The name of the object that surrounds this inner object definition.
+ ///
+ ///
+ /// The name of the inner object definition... note: this is a synthetic
+ /// name assigned by the factory (since it makes no sense for inner object
+ /// definitions to have names).
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The definition of the inner object that is to be resolved.
+ ///
+ ///
+ /// if the owner of the property is a singleton.
+ ///
+ ///
+ /// The resolved object as defined by the inner object definition.
+ ///
+ protected object ResolveInnerObjectDefinition(string name, string innerObjectName, string argumentName, IObjectDefinition definition,
+ bool singletonOwner)
+ {
+ RootObjectDefinition mod = GetMergedObjectDefinition(innerObjectName, definition);
+ mod.IsSingleton = singletonOwner;
+ object instance;
+ object result;
+ try
+ {
+ instance = CreateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false);
+ result = GetObjectForInstance(innerObjectName, instance);
+ }
+ catch (ObjectsException ex)
+ {
+ throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, innerObjectName);
+ }
+ if (singletonOwner && instance is IDisposable)
+ {
+ // keep a reference to the inner object instance, to be able to destroy
+ // it on factory shutdown...
+ _disposableInnerObjects.Add(instance);
+ }
+ return result;
+ }
+
+ ///
+ /// Resolve a reference to another object in the factory.
+ ///
+ ///
+ /// The name of the object that is having the value of one of its properties resolved.
+ ///
+ ///
+ /// The definition of the named object.
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The runtime reference containing the value of the property.
+ ///
+ /// A reference to another object in the factory.
+ protected object ResolveReference(IConfigurableObjectDefinition definition, string name, string argumentName, RuntimeObjectReference reference)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(CultureInfo.InvariantCulture, "Resolving reference from property '{0}' in object '{1}' to object '{2}'.",
+ argumentName, name, reference.ObjectName));
+ }
+
+ #endregion
+
+ try
+ {
+ if (reference.IsToParent)
+ {
+ if (null == ParentObjectFactory)
+ {
+ throw new ObjectCreationException(definition.ResourceDescription, name,
+ string.Format(
+ "Can't resolve reference to '{0}' in parent factory: " + "no parent factory available.",
+ reference.ObjectName));
+ }
+ return ParentObjectFactory.GetObject(reference.ObjectName);
+ }
+ return GetObject(reference.ObjectName);
+ }
+ catch (ObjectsException ex)
+ {
+ throw ObjectCreationException.GetObjectCreationException(ex, name, argumentName, definition.ResourceDescription, reference.ObjectName);
+ }
+ }
+
+ ///
+ /// Find object instances that match the required .
+ ///
+ ///
+ ///
+ /// Called by autowiring. If a subclass cannot obtain information about object
+ /// names by , a corresponding exception should be thrown.
+ ///
- /// This class is reserved for internal use within the framework; it is
- /// not intended to be used by application developers using Spring.NET.
- ///
- ///
- /// Rick Evans
- /// $Id: AbstractMethodReplacer.cs,v 1.3 2007/07/30 17:52:22 markpollack Exp $
- public abstract class AbstractMethodReplacer : IMethodReplacer
- {
- private IConfigurableObjectDefinition objectDefinition;
- private IObjectFactory objectFactory;
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such has no
- /// publicly visible constructors.
- ///
+ /// This class is reserved for internal use within the framework; it is
+ /// not intended to be used by application developers using Spring.NET.
+ ///
+ ///
+ /// Rick Evans
+ public abstract class AbstractMethodReplacer : IMethodReplacer
+ {
+ private IConfigurableObjectDefinition objectDefinition;
+ private IObjectFactory objectFactory;
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such has no
+ /// publicly visible constructors.
+ ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition() : this(null, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties)
- {
- constructorArgumentValues =
- (arguments != null) ? arguments : new ConstructorArgumentValues();
- propertyValues =
- (properties != null) ? properties : new MutablePropertyValues();
- eventHandlerValues = new EventValues();
- DependsOn = StringUtils.EmptyStrings;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The object definition used to initialise the member fields of this
- /// instance.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- protected AbstractObjectDefinition(IObjectDefinition other)
- {
- AssertUtils.ArgumentNotNull(other, "other");
- AbstractObjectDefinition aod = other as AbstractObjectDefinition;
- if (aod != null)
- {
- if (aod.HasObjectType)
- {
- ObjectType = other.ObjectType;
- }
- else
- {
- ObjectTypeName = other.ObjectTypeName;
- }
- MethodOverrides = new MethodOverrides(aod.MethodOverrides);
- DependencyCheck = aod.DependencyCheck;
- }
- IsAbstract = other.IsAbstract;
- IsSingleton = other.IsSingleton;
- IsLazyInit = other.IsLazyInit;
- ConstructorArgumentValues
- = new ConstructorArgumentValues(other.ConstructorArgumentValues);
- PropertyValues = new MutablePropertyValues(other.PropertyValues);
- EventHandlerValues = new EventValues(other.EventHandlerValues);
-
- InitMethodName = other.InitMethodName;
- DestroyMethodName = other.DestroyMethodName;
- DependsOn = new string[other.DependsOn.Length];
- Array.Copy(other.DependsOn, DependsOn, other.DependsOn.Length);
- FactoryMethodName = other.FactoryMethodName;
- FactoryObjectName = other.FactoryObjectName;
- AutowireMode = other.AutowireMode;
- ResourceDescription = other.ResourceDescription;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The property values that are to be applied to the object
- /// upon creation.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned to the property value.
- ///
- ///
- ///
- /// The property values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public MutablePropertyValues PropertyValues
- {
- get { return propertyValues; }
- set { propertyValues = value == null ? new MutablePropertyValues() : value; }
- }
-
- ///
- /// Does this definition have any
- /// ?
- ///
- ///
- /// if this definition has at least one
- /// .
- ///
- public bool HasMethodOverrides
- {
- get { return !MethodOverrides.IsEmpty; }
- }
-
- ///
- /// The constructor argument values for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned.
- ///
- ///
- ///
- /// The constructor argument values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public ConstructorArgumentValues ConstructorArgumentValues
- {
- get { return constructorArgumentValues; }
- set { constructorArgumentValues = value == null ? new ConstructorArgumentValues() : value; }
- }
-
- ///
- /// The event handler values for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned.
- ///
- ///
- ///
- /// The event handler values (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public EventValues EventHandlerValues
- {
- get { return eventHandlerValues; }
- set { eventHandlerValues = value == null ? new EventValues() : value; }
- }
-
- ///
- /// The method overrides (if any) for this object.
- ///
- ///
- ///
- /// Setting the value of this property to
- /// will merely result in a new (and empty)
- ///
- /// collection being assigned to the property value.
- ///
- ///
- ///
- /// The method overrides (if any) for this object; may be an
- /// empty collection but is guaranteed not to be
- /// .
- ///
- public MethodOverrides MethodOverrides
- {
- get { return methodOverrides; }
- set { methodOverrides = value == null ? new MethodOverrides() : value; }
- }
-
- ///
- /// Is this definition a singleton, with
- /// a single, shared instance returned on all calls to an enclosing
- /// container (typically an
- /// or
- /// ).
- ///
- ///
- ///
- /// If , an object factory will apply the
- /// prototype design pattern, with each caller requesting an
- /// instance getting an independent instance. How this is defined
- /// will depend on the object factory implementation. singletons
- /// are the commoner type.
- ///
- ///
- ///
- public virtual bool IsSingleton
- {
- get { return isSingleton; }
- set
- {
- isSingleton = value;
- isPrototype = !value;
- }
- }
-
- ///
- /// Gets a value indicating whether this instance is prototype, with an independent instance
- /// returned for each call.
- ///
- ///
- /// true if this instance is prototype; otherwise, false.
- ///
- public virtual bool IsPrototype
- {
- get { return isPrototype; }
- }
-
- ///
- /// Is this object lazily initialized?
- ///
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup
- /// by object factories that perform eager initialization of
- /// singletons.
- ///
- ///
- public bool IsLazyInit
- {
- get { return isLazyInit; }
- set { isLazyInit = value; }
- }
-
- ///
- /// Is this object definition a "template", i.e. not meant to be instantiated
- /// itself but rather just serving as an object definition for configuration
- /// templates used by .
- ///
- ///
- /// if this object definition is a "template".
- ///
- public bool IsTemplate
- {
- get
- {
- return (
- isAbstract ||
- (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName))
- );
- }
- }
-
- ///
- /// Is this object definition "abstract", i.e. not meant to be
- /// instantiated itself but rather just serving as a parent for concrete
- /// child object definitions.
- ///
- ///
- /// if this object definition is "abstract".
- ///
- public bool IsAbstract
- {
- get { return isAbstract; }
- set { isAbstract = value; }
- }
-
- ///
- /// The of the object definition (if any).
- ///
- ///
- /// A resolved object .
- ///
- ///
- /// If the of the object definition is not a
- /// resolved or .
- ///
- ///
- public Type ObjectType
- {
- get
- {
- if (!HasObjectType)
- {
- throw new ApplicationException(
- "Object definition does not carry a resolved System.Type");
- }
- return (Type) objectType;
- }
- set { objectType = value; }
- }
-
- ///
- /// Is the of the object definition a resolved
- /// ?
- ///
- public bool HasObjectType
- {
- get { return objectType is Type; }
- }
-
- ///
- /// Returns the of the
- /// of the object definition (if any).
- ///
- public string ObjectTypeName
- {
- get
- {
- if (objectType is Type)
- {
- return ((Type) objectType).FullName;
- }
- else
- {
- return objectType as string;
- }
- }
- set { objectType = value; }
- }
-
- ///
- /// A description of the resource that this object definition
- /// came from (for the purpose of showing context in case of errors).
- ///
- public string ResourceDescription
- {
- get { return resourceDescription; }
- set { resourceDescription = value; }
- }
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. The default is
- /// ,
- /// which means that no autowiring will be performed.
- ///
- ///
- public AutoWiringMode AutowireMode
- {
- get { return autowireMode; }
- set { autowireMode = value; }
- }
-
- ///
- /// Gets the resolved autowire mode.
- ///
- ///
- ///
- /// This resolves
- ///
- /// to one of
- ///
- /// or
- /// .
- ///
- ///
- public AutoWiringMode ResolvedAutowireMode
- {
- get
- {
- if (AutowireMode == AutoWiringMode.AutoDetect)
- {
- // Work out whether to apply setter autowiring or constructor autowiring.
- // If it has a no-arg constructor it's deemed to be setter autowiring,
- // otherwise we'll try constructor autowiring.
- ConstructorInfo[] constructors =
- ObjectType.GetConstructors();
- foreach (ConstructorInfo ctor in constructors)
- {
- if (ctor.GetParameters().Length == 0)
- {
- return AutoWiringMode.ByType;
- }
- }
- return AutoWiringMode.Constructor;
- }
- else
- {
- return AutowireMode;
- }
- }
- }
-
- ///
- /// The dependency checking mode.
- ///
- ///
- ///
- /// The default is
- /// .
- ///
- ///
- public DependencyCheckingMode DependencyCheck
- {
- get { return dependencyCheck; }
- set { dependencyCheck = value; }
- }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before this object definition.
- ///
- ///
- /// Dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies such as statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- public string[] DependsOn
- {
- get { return dependsOn; }
- set { dependsOn = value == null ? StringUtils.EmptyStrings : value; }
- }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default value is the constant,
- /// in which case there is no initializer method.
- ///
- ///
- public string InitMethodName
- {
- get { return initMethodName; }
- set { initMethodName = value; }
- }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default value is the constant,
- /// in which case there is no destroy method.
- ///
- ///
- public string DestroyMethodName
- {
- get { return destroyMethodName; }
- set { destroyMethodName = value; }
- }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The
- /// method will be invoked on the specified
- /// .
- ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition() : this(null, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition(ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ {
+ constructorArgumentValues =
+ (arguments != null) ? arguments : new ConstructorArgumentValues();
+ propertyValues =
+ (properties != null) ? properties : new MutablePropertyValues();
+ eventHandlerValues = new EventValues();
+ DependsOn = StringUtils.EmptyStrings;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The object definition used to initialise the member fields of this
+ /// instance.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinition(IObjectDefinition other)
+ {
+ AssertUtils.ArgumentNotNull(other, "other");
+ AbstractObjectDefinition aod = other as AbstractObjectDefinition;
+ if (aod != null)
+ {
+ if (aod.HasObjectType)
+ {
+ ObjectType = other.ObjectType;
+ }
+ else
+ {
+ ObjectTypeName = other.ObjectTypeName;
+ }
+ MethodOverrides = new MethodOverrides(aod.MethodOverrides);
+ DependencyCheck = aod.DependencyCheck;
+ }
+ IsAbstract = other.IsAbstract;
+ IsSingleton = other.IsSingleton;
+ IsLazyInit = other.IsLazyInit;
+ ConstructorArgumentValues
+ = new ConstructorArgumentValues(other.ConstructorArgumentValues);
+ PropertyValues = new MutablePropertyValues(other.PropertyValues);
+ EventHandlerValues = new EventValues(other.EventHandlerValues);
+
+ InitMethodName = other.InitMethodName;
+ DestroyMethodName = other.DestroyMethodName;
+ DependsOn = new string[other.DependsOn.Length];
+ Array.Copy(other.DependsOn, DependsOn, other.DependsOn.Length);
+ FactoryMethodName = other.FactoryMethodName;
+ FactoryObjectName = other.FactoryObjectName;
+ AutowireMode = other.AutowireMode;
+ ResourceDescription = other.ResourceDescription;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The property values that are to be applied to the object
+ /// upon creation.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned to the property value.
+ ///
+ ///
+ ///
+ /// The property values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public MutablePropertyValues PropertyValues
+ {
+ get { return propertyValues; }
+ set { propertyValues = value == null ? new MutablePropertyValues() : value; }
+ }
+
+ ///
+ /// Does this definition have any
+ /// ?
+ ///
+ ///
+ /// if this definition has at least one
+ /// .
+ ///
+ public bool HasMethodOverrides
+ {
+ get { return !MethodOverrides.IsEmpty; }
+ }
+
+ ///
+ /// The constructor argument values for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned.
+ ///
+ ///
+ ///
+ /// The constructor argument values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public ConstructorArgumentValues ConstructorArgumentValues
+ {
+ get { return constructorArgumentValues; }
+ set { constructorArgumentValues = value == null ? new ConstructorArgumentValues() : value; }
+ }
+
+ ///
+ /// The event handler values for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned.
+ ///
+ ///
+ ///
+ /// The event handler values (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public EventValues EventHandlerValues
+ {
+ get { return eventHandlerValues; }
+ set { eventHandlerValues = value == null ? new EventValues() : value; }
+ }
+
+ ///
+ /// The method overrides (if any) for this object.
+ ///
+ ///
+ ///
+ /// Setting the value of this property to
+ /// will merely result in a new (and empty)
+ ///
+ /// collection being assigned to the property value.
+ ///
+ ///
+ ///
+ /// The method overrides (if any) for this object; may be an
+ /// empty collection but is guaranteed not to be
+ /// .
+ ///
+ public MethodOverrides MethodOverrides
+ {
+ get { return methodOverrides; }
+ set { methodOverrides = value == null ? new MethodOverrides() : value; }
+ }
+
+ ///
+ /// Is this definition a singleton, with
+ /// a single, shared instance returned on all calls to an enclosing
+ /// container (typically an
+ /// or
+ /// ).
+ ///
+ ///
+ ///
+ /// If , an object factory will apply the
+ /// prototype design pattern, with each caller requesting an
+ /// instance getting an independent instance. How this is defined
+ /// will depend on the object factory implementation. singletons
+ /// are the commoner type.
+ ///
+ ///
+ ///
+ public virtual bool IsSingleton
+ {
+ get { return isSingleton; }
+ set
+ {
+ isSingleton = value;
+ isPrototype = !value;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this instance is prototype, with an independent instance
+ /// returned for each call.
+ ///
+ ///
+ /// true if this instance is prototype; otherwise, false.
+ ///
+ public virtual bool IsPrototype
+ {
+ get { return isPrototype; }
+ }
+
+ ///
+ /// Is this object lazily initialized?
+ ///
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup
+ /// by object factories that perform eager initialization of
+ /// singletons.
+ ///
+ ///
+ public bool IsLazyInit
+ {
+ get { return isLazyInit; }
+ set { isLazyInit = value; }
+ }
+
+ ///
+ /// Is this object definition a "template", i.e. not meant to be instantiated
+ /// itself but rather just serving as an object definition for configuration
+ /// templates used by .
+ ///
+ ///
+ /// if this object definition is a "template".
+ ///
+ public bool IsTemplate
+ {
+ get
+ {
+ return (
+ isAbstract ||
+ (objectType == null && StringUtils.IsNullOrEmpty(factoryObjectName))
+ );
+ }
+ }
+
+ ///
+ /// Is this object definition "abstract", i.e. not meant to be
+ /// instantiated itself but rather just serving as a parent for concrete
+ /// child object definitions.
+ ///
+ ///
+ /// if this object definition is "abstract".
+ ///
+ public bool IsAbstract
+ {
+ get { return isAbstract; }
+ set { isAbstract = value; }
+ }
+
+ ///
+ /// The of the object definition (if any).
+ ///
+ ///
+ /// A resolved object .
+ ///
+ ///
+ /// If the of the object definition is not a
+ /// resolved or .
+ ///
+ ///
+ public Type ObjectType
+ {
+ get
+ {
+ if (!HasObjectType)
+ {
+ throw new ApplicationException(
+ "Object definition does not carry a resolved System.Type");
+ }
+ return (Type) objectType;
+ }
+ set { objectType = value; }
+ }
+
+ ///
+ /// Is the of the object definition a resolved
+ /// ?
+ ///
+ public bool HasObjectType
+ {
+ get { return objectType is Type; }
+ }
+
+ ///
+ /// Returns the of the
+ /// of the object definition (if any).
+ ///
+ public string ObjectTypeName
+ {
+ get
+ {
+ if (objectType is Type)
+ {
+ return ((Type) objectType).FullName;
+ }
+ else
+ {
+ return objectType as string;
+ }
+ }
+ set { objectType = value; }
+ }
+
+ ///
+ /// A description of the resource that this object definition
+ /// came from (for the purpose of showing context in case of errors).
+ ///
+ public string ResourceDescription
+ {
+ get { return resourceDescription; }
+ set { resourceDescription = value; }
+ }
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. The default is
+ /// ,
+ /// which means that no autowiring will be performed.
+ ///
+ ///
+ public AutoWiringMode AutowireMode
+ {
+ get { return autowireMode; }
+ set { autowireMode = value; }
+ }
+
+ ///
+ /// Gets the resolved autowire mode.
+ ///
+ ///
+ ///
+ /// This resolves
+ ///
+ /// to one of
+ ///
+ /// or
+ /// .
+ ///
+ ///
+ public AutoWiringMode ResolvedAutowireMode
+ {
+ get
+ {
+ if (AutowireMode == AutoWiringMode.AutoDetect)
+ {
+ // Work out whether to apply setter autowiring or constructor autowiring.
+ // If it has a no-arg constructor it's deemed to be setter autowiring,
+ // otherwise we'll try constructor autowiring.
+ ConstructorInfo[] constructors =
+ ObjectType.GetConstructors();
+ foreach (ConstructorInfo ctor in constructors)
+ {
+ if (ctor.GetParameters().Length == 0)
+ {
+ return AutoWiringMode.ByType;
+ }
+ }
+ return AutoWiringMode.Constructor;
+ }
+ else
+ {
+ return AutowireMode;
+ }
+ }
+ }
+
+ ///
+ /// The dependency checking mode.
+ ///
+ ///
+ ///
+ /// The default is
+ /// .
+ ///
+ ///
+ public DependencyCheckingMode DependencyCheck
+ {
+ get { return dependencyCheck; }
+ set { dependencyCheck = value; }
+ }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before this object definition.
+ ///
+ ///
+ /// Dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies such as statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ public string[] DependsOn
+ {
+ get { return dependsOn; }
+ set { dependsOn = value == null ? StringUtils.EmptyStrings : value; }
+ }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default value is the constant,
+ /// in which case there is no initializer method.
+ ///
+ ///
+ public string InitMethodName
+ {
+ get { return initMethodName; }
+ set { initMethodName = value; }
+ }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default value is the constant,
+ /// in which case there is no destroy method.
+ ///
+ ///
+ public string DestroyMethodName
+ {
+ get { return destroyMethodName; }
+ set { destroyMethodName = value; }
+ }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The
+ /// method will be invoked on the specified
+ /// .
+ ///
- /// Provides common properties like the object registry to work on.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: AbstractObjectDefinitionReader.cs,v 1.14 2008/01/10 14:32:24 bbaia Exp $
- public abstract class AbstractObjectDefinitionReader : IObjectDefinitionReader
- {
- #region Constants
-
- ///
- /// The shared instance for this class (and derived classes).
- ///
- protected static readonly ILog log =
- LogManager.GetLogger(typeof (AbstractObjectDefinitionReader));
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The
- /// instance that this reader works on.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- protected AbstractObjectDefinitionReader(IObjectDefinitionRegistry registry)
- : this(registry, AppDomain.CurrentDomain)
- {
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The
- /// instance that this reader works on.
- ///
- ///
- /// The against which any class names
- /// will be resolved into instances.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
+ /// Provides common properties like the object registry to work on.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public abstract class AbstractObjectDefinitionReader : IObjectDefinitionReader
+ {
+ #region Constants
+
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ protected static readonly ILog log =
+ LogManager.GetLogger(typeof (AbstractObjectDefinitionReader));
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The
+ /// instance that this reader works on.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ protected AbstractObjectDefinitionReader(IObjectDefinitionRegistry registry)
+ : this(registry, AppDomain.CurrentDomain)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The
+ /// instance that this reader works on.
+ ///
+ ///
+ /// The against which any class names
+ /// will be resolved into instances.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
- /// This class provides singleton / prototype determination, singleton caching,
- /// object definition aliasing,
- /// handling, and object definition merging for child object definitions.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: AbstractObjectFactory.cs,v 1.77 2008/05/29 12:13:27 oakinger Exp $
- [Serializable]
- public abstract class AbstractObjectFactory : IConfigurableObjectFactory
- {
- ///
- /// Marker object to be temporarily registered in the singleton cache,
- /// while instantiating an object (in order to be able to detect circular references).
- ///
- private static readonly object CURRENTLY_IN_CREATION = new Object();
-
- ///
- /// The instance for this class.
- ///
- private readonly ILog log = LogManager.GetLogger(typeof(AbstractObjectFactory));
-
- ///
- /// Used as value in hashtable that keeps track of singleton names currently in the
- /// process of being created. Would not be necessary if we created a case insensitive implementation of
- /// ISet.
- ///
- private static object emptyObject = new object();
-
-
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This constructor implicitly creates an
- ///
- /// that treats the names of objects in this factory in a case-sensitive fashion.
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- protected AbstractObjectFactory() : this(true)
- {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- ///
- /// if the names of objects in this factory are to be treated in a
- /// case-sensitive fashion.
- ///
- protected AbstractObjectFactory(bool caseSensitive)
- {
- this.log = LogManager.GetLogger(this.GetType());
- if (caseSensitive)
- {
- this.aliasMap = new SynchronizedHashtable();
- this.singletonCache = new Hashtable();
- this.singletonsInCreation = new Hashtable();
- }
- else
- {
- this.aliasMap = new SynchronizedHashtable(CollectionsUtil.CreateCaseInsensitiveHashtable());
- this.singletonCache = CollectionsUtil.CreateCaseInsensitiveHashtable();
- this.singletonsInCreation = CollectionsUtil.CreateCaseInsensitiveHashtable();
- }
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- ///
- /// if the names of objects in this factory are to be treated in a
- /// case-sensitive fashion.
- ///
- ///
- /// Any parent object factory; may be .
- ///
- protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) : this(caseSensitive)
- {
- ParentObjectFactory = parentFactory;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets the of
- /// s
- /// that will be applied to objects created by this factory.
- ///
- public IList ObjectPostProcessors
- {
- get { return objectPostProcessors; }
- }
-
- ///
- /// Gets the set of classes that will be ignored for autowiring.
- ///
- ///
- ///
- /// The elements of this are
- /// s.
- ///
- ///
- public ISet IgnoredDependencyTypes
- {
- get { return ignoreDependencyTypes; }
- }
-
- ///
- /// Returns, whether this object factory instance contains objects.
- ///
- protected bool HasInstantiationAwareBeanPostProcessors
- {
- get { return hasInstantiationAwareBeanPostProcessors; }
- }
-
- ///
- /// Returns, whether this object factory instance contains objects.
- ///
- protected bool HasDestructionAwareBeanPostProcessors
- {
- get { return hasDestructionAwareBeanPostProcessors; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public object GetObject(string name, Type requiredType, object[] arguments)
- {
- string objectName = TransformedObjectName(name);
- object instance = null;
- // eagerly check singleton cache for manually registered singletons...
- object sharedInstance = GetSingleton(objectName);
-
- if (sharedInstance != null)
- {
- #region Instrumentation
-
- if (IsSingletonCurrentlyInCreation(objectName))
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("Returning eagerly cached instance of singleton object '" + objectName +
- "' that is not fully initialized yet - a consequence of a circular reference");
- }
- }
- else
- {
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName));
- }
- }
-
- #endregion
-
- instance = GetObjectForInstance(name, sharedInstance);
- }
- else
- {
- // check if object definition exists
- RootObjectDefinition mergedObjectDefinition = null;
- mergedObjectDefinition = GetMergedObjectDefinition(objectName, false);
- if (mergedObjectDefinition == null)
- {
- if (ParentObjectFactory != null)
- {
- return ParentObjectFactory.GetObject(name, requiredType, arguments);
- }
- throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]");
- }
-
- CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments);
-
- // return IObjectDefinition instance itself for an abstract object-definition
- if (mergedObjectDefinition.IsAbstract)
- {
- instance = mergedObjectDefinition;
- }
- else if (mergedObjectDefinition.IsSingleton)
- {
- // create object instance...
- sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments);
- instance = GetObjectForInstance(name, sharedInstance);
- }
- else
- {
- // it's a prototype, so create a new instance...
- instance = CreateObject(name, mergedObjectDefinition, arguments);
- }
- }
- // check that any required type matches the type of the actual object instance...
- if (requiredType != null && !requiredType.IsAssignableFrom(instance.GetType()))
- {
- throw new ObjectNotOfRequiredTypeException(name, requiredType, instance);
- }
- return instance;
- }
-
-
-
- ///
- /// Apply the property values of the object definition with the supplied
- /// to the supplied .
- ///
- ///
- ///
- /// The object definition can either define a fully self-contained object,
- /// reusing it's property values, or just property values meant to be used
- /// for existing object instances.
- ///
- ///
- ///
- /// The existing object that the property values for the named object will
- /// be applied to.
- ///
- ///
- /// The name of the object definition associated with the property values that are
- /// to be applied.
- ///
- ///
- /// In case of errors.
- ///
- public virtual void ApplyObjectPropertyValues(object instance, string name)
- {
- // explicit no-op...
- }
-
- ///
- /// Initializes the given with the
- /// custom s registered with
- /// this factory.
- ///
- ///
- /// The to initialise.
- ///
- protected void InitObjectWrapper(IObjectWrapper wrapper)
- {
- }
-
- ///
- /// Create an object instance for the given object definition.
- ///
- ///
- ///
- /// The object definition will already have been merged with the parent
- /// definition in case of a child definition.
- ///
- ///
- /// All the other methods in this class invoke this method, although objects
- /// may be cached after being instantiated by this method. All object
- /// instantiation within this class is performed by this method.
- ///
- ///
- /// The name of the object.
- ///
- /// The object definition for the object that is to be instantiated.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not ,
- /// then match the argument values by type and call the object's constructor.
- ///
- ///
- /// A new instance of the object.
- ///
- ///
- /// In case of errors.
- ///
- protected abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments);
-
- ///
- /// Destroy the target object.
- ///
- ///
- ///
- /// Must destroy objects that depend on the given object before the object itself,
- /// nor throw an exception.
- ///
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// The target object instance to destroyed.
- ///
- protected abstract void DestroyObject(string name, object target);
-
- ///
- /// Does this object factory contain an object definition with the
- /// supplied ?
- ///
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- /// Invoked by
- ///
- /// when no cached singleton instance is found.
- ///
- ///
- ///
- /// The name of the object to look for.
- ///
- ///
- /// if this object factory contains an object
- /// definition with the supplied .
- ///
- public abstract bool ContainsObjectDefinition(string name);
-
- ///
- /// Adds the supplied (object) to this factory's
- /// singleton cache.
- ///
- ///
- ///
- /// To be called for eager registration of singletons, e.g. to be able to
- /// resolve circular references.
- ///
- ///
- /// If a singleton has already been registered under the same name as
- /// the supplied , then the old singleton will
- /// be replaced.
- ///
- ///
- /// The name of the object.
- /// The singleton object.
- ///
- /// If the argument is
- /// or consists wholly of whitespace characters; or if the
- /// is .
- ///
- protected virtual void AddSingleton(string name, object singleton)
- {
- AssertUtils.ArgumentHasText(name, "The object name must not be empty.");
- AssertUtils.ArgumentNotNull(singleton, "singleton");
- lock (singletonCache)
- {
- singletonCache[name] = singleton;
- }
- }
-
- ///
- /// Return the object name, stripping out the factory dereference prefix if
- /// necessary, and resolving aliases to canonical names.
- ///
- ///
- /// The transformed name of the object.
- ///
- protected string TransformedObjectName(string name)
- {
- string objectName = ObjectFactoryUtils.TransformedObjectName(name);
- // handle aliasing...
- lock (aliasMap)
- {
- string canonicalName = (string) aliasMap[objectName];
- return canonicalName != null ? canonicalName : objectName;
- }
- }
-
- ///
- /// Ensures, that the given name is prefixed with
- /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing
- /// the object name during
- ///
- protected string OriginalObjectName(string name)
- {
- string objectName = TransformedObjectName(name);
- if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix))
- {
- objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName;
- }
- return objectName;
- }
-
- ///
- /// Determines whether the specified name is defined as an alias as opposed
- /// to the name of an actual object definition.
- ///
- /// The object name to check.
- ///
- /// true if the specified name is alias; otherwise, false.
- ///
- protected bool IsAlias(string name)
- {
- lock (aliasMap)
- {
- return aliasMap.Contains(name);
- }
- }
-
- ///
- /// Return a ,
- /// even by traversing parent if the parameter is a child definition.
- ///
- ///
- /// The name of the object.
- ///
- ///
- /// Are ancestors to be included in the merge?
- ///
- ///
- ///
- /// Will ask the parent object factory if not found in this instance.
- ///
- ///
- ///
- /// A merged
- /// with overridden properties.
- ///
- public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors)
- {
- return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors));
- }
-
- ///
- /// Return a ,
- /// even by traversing parent if the parameter is a child definition.
- ///
- ///
- /// A merged
- /// with overridden properties.
- ///
- protected virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition definition)
- {
- if (definition == null)
- {
- return null;
- }
- else if (definition is RootObjectDefinition)
- {
- return (RootObjectDefinition) definition;
- }
- else if (definition is ChildObjectDefinition)
- {
- ChildObjectDefinition childDefinition = (ChildObjectDefinition) definition;
- RootObjectDefinition parentDefinition = null;
- if (!name.Equals(childDefinition.ParentName))
- {
- parentDefinition =
- GetMergedObjectDefinition(TransformedObjectName(childDefinition.ParentName), true);
- }
- else
- {
- if (ParentObjectFactory is AbstractObjectFactory)
- {
- parentDefinition =
- ((AbstractObjectFactory) ParentObjectFactory).GetMergedObjectDefinition(
- childDefinition.ParentName, true);
- }
- }
- if (parentDefinition == null)
- {
- throw new NoSuchObjectDefinitionException(childDefinition.ParentName,
- string.Format(
- "Parent name '{0}' is equal to object name '{1}' - "
- +
- "cannot be resolved without an AbstractObjectFactory parent.",
- childDefinition.ParentName, name));
- }
-
- RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition);
- rootDefinition.OverrideFrom(childDefinition);
- return rootDefinition;
- }
- else
- {
- throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
- "Definition is neither a RootObjectDefinition nor a ChildObjectDefinition.");
- }
- }
-/*
- ///
- /// Merges the object definitions.
- ///
- /// Object definition name.
- /// The parent definition.
- /// The child definition.
- /// Merged object definition.
- protected virtual RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition,
- IObjectDefinition childDefinition)
- {
- RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition);
- rootDefinition.OverrideFrom(childDefinition);
- return rootDefinition;
- }
-*/
- ///
- /// Creates the root object definition.
- ///
- /// The template definition to base root definition on.
- /// Root object definition.
- protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition)
- {
- return new RootObjectDefinition(templateDefinition);
- }
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public abstract IObjectDefinition GetObjectDefinition(string name);
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- /// Whether to search parent object factories.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors);
-
- ///
- /// Gets the type for the given FactoryObject.
- ///
- /// The factory object instance to check.
- /// the FactoryObject's object type
- protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject)
- {
- try
- {
- return factoryObject.ObjectType;
- }
- catch (Exception ex)
- {
- log.Warn("FactoryObject threw exception from ObjectType, despite the contract saying " +
- "that it should return null if the type of its object cannot be determined yet", ex);
- return null;
- }
- }
-
- ///
- /// Gets the object type for the given FactoryObject definition, as far as possible.
- /// Only called if there is no singleton instance registered for the target object already.
- ///
- ///
- /// The default implementation creates the FactoryObject via GetObject
- /// to call its ObjectType property. Subclasses are encouraged to optimize
- /// this, typically by just instantiating the FactoryObject but not populating it yet,
- /// trying whether its ObjectType property already returns a type.
- /// If no type found, a full FactoryObject creation as performed by this implementation
- /// should be used as fallback.
- ///
- /// Name of the object.
- /// The merged object definition for the object.
- /// The type for the object if determinable, or null otherwise
- protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod)
- {
- if (!mod.IsSingleton)
- {
- return null;
- }
- try
- {
- IFactoryObject factoryObject = GetFactoryObject(objectName);
- return GetTypeForFactoryObject(factoryObject);
- } catch (ObjectCreationException ex)
- {
- // Can only happen when getting a FactoryObject.
- log.Debug("Ignoring object creation exception on FactoryObject type check", ex);
- return null;
- }
- }
-
- ///
- /// Predict the eventual object type (of the processed object instance) for the
- /// specified object.
- ///
- ///
- /// Does not need to handle FactoryObjects specifically, since it is only
- /// supposed to operate on the raw object type.
- /// This implementation is simplistic in that it is not able to
- /// handle factory methods and InstantiationAwareBeanPostProcessors.
- /// It only predicts the object type correctly for a standard object.
- /// To be overridden in subclasses, applying more sophisticated type detection.
- ///
- /// Name of the object.
- /// The merged object definition to determine the type for.
- /// The type of the object, or null if not predictable
- protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod)
- {
- if (StringUtils.HasText(mod.FactoryObjectName))
- {
- return null;
- }
- return ResolveObjectType(mod, objectName);
- }
-
- ///
- /// Get the object for the given object instance, either the object
- /// instance itself or its created object in case of an
- /// .
- ///
- ///
- /// The name that may include the factory dereference prefix.
- ///
- /// The object instance.
- ///
- /// The singleton instance of the object.
- ///
- protected virtual object GetObjectForInstance(string name, object instance)
- {
- //string objectName = TransformedObjectName(name);
-
- // don't let calling code try to dereference the
- // object factory if the object isn't a factory
- if (IsFactoryDereference(name) && !(instance is IFactoryObject))
- {
- throw new ObjectIsNotAFactoryException(TransformedObjectName(name), instance);
- }
-
- // now we have the object instance, which may be a normal object
- // or an IFactoryObject. If it's an IFactoryObject, we use it to
- // create an object instance, unless the caller actually wants
- // a reference to the factory.
- if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFactoryObject), instance))
- {
- if (!IsFactoryDereference(name))
- {
-
- // return object instance from factory...
- IFactoryObject factory = (IFactoryObject) instance;
- string objectName = TransformedObjectName(name);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("Object with name '{0}' is a factory object.", objectName));
- }
-
- #endregion
-
- RootObjectDefinition rod =
- (ContainsObjectDefinition(objectName) ? GetMergedObjectDefinition(objectName,true) : null);
- instance = GetObjectFromFactoryObject(factory, objectName, rod);
-
- if (instance == null)
- {
- throw new FactoryObjectNotInitializedException(TransformedObjectName(name),
- "Factory object returned null object - "
- + "possible cause: not fully initialized due to "
- + "circular object reference.");
- }
- }
- else
- {
- // the user wants the factory itself...
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format("Calling code asked for IFactoryObject instance for name '{0}'.",
- TransformedObjectName(name)));
- }
- }
- }
- return instance;
- }
-
- ///
- /// Obtain an object to expose from the given IFactoryObject.
- ///
- /// The IFactoryObject instance.
- /// Name of the object.
- /// The merged object definition.
- /// The object obtained from the IFactoryObject
- /// If IFactoryObject object creation failed.
- private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod)
- {
- object instance;
-
- try
- {
- instance = factory.GetObject();
- }
- catch (FactoryObjectNotInitializedException ex)
- {
- throw new ObjectCurrentlyInCreationException(
- rod.ResourceDescription, objectName, ex);
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(rod.ResourceDescription, objectName,
- "FactoryObject threw exception on object creation.", ex);
- }
-
- // Do not accept a null value for a FactoryBean that's not fully
- // initialized yet: Many FactoryBeans just return null then.
- if (instance == null && IsSingletonCurrentlyInCreation(objectName)) {
- throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName,
- "FactoryObject which is currently in creation returned null from GetObject.");
- }
-
- if (factory is IConfigurableFactoryObject)
- {
- IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject)factory;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName)));
- }
-
- #endregion
-
- if (configurableFactory.ProductTemplate != null)
- {
- instance = ConfigureObject(instance,
- String.Format("{0}.ProductTemplate", objectName),
- configurableFactory.ProductTemplate);
- }
- }
-
- if (instance != null)
- {
- try
- {
- instance = PostProcessObjectFromFactoryObject(instance, objectName);
- }
- catch (Exception ex) {
- throw new ObjectCreationException(rod.ResourceDescription, objectName,
- "Post-processing of the FactoryObject's object failed.", ex);
- }
- }
-
- return instance;
- }
-
- ///
- /// Post-process the given object that has been obtained from the FactoryObject.
- /// The resulting object will be exposed for object references.
- ///
- /// The default implementation simply returns the given object
- /// as-is. Subclasses may override this, for example, to apply
- /// post-processors.
- /// The instance obtained from the IFactoryObject.
- /// Name of the object.
- /// The object instance to expose
- /// if any post-processing failed.
- protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName)
- {
- return instance;
- }
-
- ///
- /// Convenience method to pull an
- /// from this factory.
- ///
- ///
- /// The name of the factory object to be retrieved. If this name is not a valid
- /// name, it will be converted
- /// into one.
- ///
- ///
- /// The associated with the
- /// supplied .
- ///
- protected IFactoryObject GetFactoryObject(string objectName)
- {
- if (!ObjectFactoryUtils.IsFactoryDereference(objectName))
- {
- objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName);
- }
- return (IFactoryObject) GetObject(objectName);
- }
-
- ///
- /// Is the supplied a factory object dereference?
- ///
- protected bool IsFactoryDereference(string name)
- {
- return ObjectFactoryUtils.IsFactoryDereference(name);
- }
-
- ///
- /// Determines whether the type of the given object definition matches the
- /// specified target type.
- ///
- /// Allows for lazy load of the actual object type, provided that the
- /// type match can be determined otherwise.
- /// The default implementation simply delegates to the standard
- /// ResolveObjectType method. Subclasses may override this to use
- /// a differnt strategy.
- ///
- /// Name of the object (for error handling purposes).
- /// The merged object definition to determine the type for.
- /// Type to match against (never null).
- ///
- /// true if object definition matches tye specified target type; otherwise, false.
- ///
- /// if we failed to load the type."
- protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType)
- {
- Type objectType = ResolveObjectType(rod, objectName);
- return (objectType != null && targetType.IsAssignableFrom(objectType));
- }
-
- ///
- /// Resolves the type of the object for the specified object definition resolving
- /// an object type name to a Type (if necessary) and storing the resolved Type
- /// in the object definition for further use.
- ///
- /// The merged object definition to dertermine the type for.
- /// Name of the object (for error handling purposes).
- ///
- protected Type ResolveObjectType(RootObjectDefinition rod, string objectName)
- {
- try
- {
- if (rod.HasObjectType)
- {
- return rod.ObjectType;
- }
- return rod.ResolveObjectType();
- } catch (TypeLoadException e)
- {
- throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e);
- }
- }
-
- ///
- /// Is the object (definition) with the supplied an
- /// ?
- ///
- /// The name of the object to be checked.
- ///
- /// the object (definition) with the supplied
- /// an ?
- ///
- protected bool IsFactoryObject(string name)
- {
- string objectName = TransformedObjectName(name);
- object objectInstance = GetSingleton(objectName);
- //TODO investigate
- if (IsSingletonCurrentlyInCreation(name))
- {
- throw new ObjectCurrentlyInCreationException(objectName);
- }
-
- if (objectInstance != null)
- {
- return (objectInstance is IFactoryObject);
- }
- else
- {
- RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false);
- if (definition != null)
- {
- return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType));
- }
- else
- {
- if (parentObjectFactory != null)
- {
- return ((AbstractObjectFactory) parentObjectFactory).IsFactoryObject(name);
- }
- else
- {
- throw new NoSuchObjectDefinitionException(objectName,
- "Cannot find definition for object [" + objectName
- + "]");
- }
- }
- }
- }
-
- ///
- /// Remove the object identified by the supplied
- /// from this factory's singleton cache.
- ///
- ///
- /// The name of the object that is to be removed from the singleton
- /// cache.
- ///
- ///
- /// If the argument is or
- /// consists wholly of whitespace characters.
- ///
- protected void RemoveSingleton(string name)
- {
- AssertUtils.ArgumentHasText(name, "name");
- lock (singletonCache)
- {
- this.singletonCache.Remove(name);
- }
- }
-
- ///
- /// Return the names of objects in the singleton cache that match the given
- /// object type (including subclasses).
- ///
- ///
- /// The class or interface to match, or for all object names.
- ///
- ///
- ///
- /// Will not consider s
- /// as the type of their created objects is not known before instantiation.
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- ///
- /// The names of objects in the singleton cache that match the given
- /// object type (including subclasses), or an empty array if none.
- ///
- public virtual string[] GetSingletonNames(Type type)
- {
- lock (singletonCache)
- {
- ArrayList matches = new ArrayList();
- foreach (string name in singletonCache.Keys)
- {
- object singletonObject = singletonCache[name];
- if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType())
- && !matches.Contains(name))
- {
- matches.Add(name);
- }
- }
- return (string[]) matches.ToArray(typeof(string));
- }
- }
-
- ///
- /// Determines whether the object with the given name matches the specified type.
- ///
- /// More specifically, check whether a GetObject call for the given name
- /// would return an object that is assignable to the specified target type.
- /// Translates aliases back to the corresponding canonical bean name.
- /// Will ask the parent factory if the bean cannot be found in this factory instance.
- ///
- /// The name of the object to query.
- /// Type of the target to match against.
- ///
- /// true if the object type matches; otherwise, false
- /// if it doesn't match or cannot be determined yet.
- ///
- /// Ff there is no object with the given name
- ///
- public bool IsTypeMatch(string name, Type targetType)
- {
- string objectName = TransformedObjectName(name);
- Type typeToMatch = (targetType != null ? targetType : typeof (object));
-
- //Check manually registered singletons.
- object objectInstance = GetSingleton(objectName);
- if (objectInstance != null)
- {
- if (objectInstance is IFactoryObject)
- {
- if (!IsFactoryDereference(name))
- {
- Type type = GetTypeForFactoryObject((IFactoryObject)objectInstance);
- return (type != null && typeToMatch.IsAssignableFrom(type));
- }
- else
- {
- return typeToMatch.IsAssignableFrom(objectInstance.GetType());
- }
- }
- else
- {
- return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType());
- }
- }
- else
- {
- // No singleton instance found -> check object definition
- IObjectFactory parentFactory = ParentObjectFactory;
- if (parentFactory != null && !ContainsObjectDefinition(name))
- {
- // No object definition found in this factory -> delegate to parent
- return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType);
- }
-
- RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false);
- Type objectType = PredictObjectType(objectName, mod);
-
- if (objectType == null)
- {
- return false;
- }
-
- // Check object class whether we're dealing with a FactoryObject
- if (typeof(IFactoryObject).IsAssignableFrom(objectType))
- {
- if (!IsFactoryDereference(name))
- {
- // If it's a FactoryObject, we want to look at what it creates, not the factory class.
- Type type = GetTypeForFactoryObject(objectName, mod);
- return (type != null && typeToMatch.IsAssignableFrom(type));
- }
- else
- {
- return typeToMatch.IsAssignableFrom(objectType);
- }
- }
- else
- {
- return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType);
- }
- }
- }
-
- ///
- /// Determines the of the object with the
- /// supplied .
- ///
- ///
- ///
- /// More specifically, checks the of object that
- /// would return.
- /// For an , returns the
- /// of object that the
- /// creates.
- ///
- ///
- /// Please note that (prototype) objects created via a factory method or
- /// objects are handled
- /// slightly differently, in that we don't want to needlessly create
- /// instances of such objects just to determine the
- /// of object that they create.
- ///
- ///
- /// The name of the object to query.
- ///
- /// The of the object or
- /// if not determinable.
- ///
- public virtual Type GetType(string name)
- {
- string objectName = TransformedObjectName(name);
-
- // check manually registered singletons...
- object objectInstance = GetSingleton(objectName);
-
- if (objectInstance != null)
- {
- IFactoryObject factoryObject = objectInstance as IFactoryObject;
- if (factoryObject != null & !IsFactoryDereference(objectName))
- {
- return GetTypeForFactoryObject(factoryObject);
- }
- else
- {
- return objectInstance.GetType();
- }
- }
- else
- {
- // No singleton instance found -> check bean definition.
- IObjectFactory parentFactory = ParentObjectFactory;
- if (parentFactory != null && !ContainsObjectDefinition(objectName))
- {
- // No bean definition found in this factory -> delegate to parent.
- return parentFactory.GetType(this.OriginalObjectName(name));
- }
-
- RootObjectDefinition mod = this.GetMergedObjectDefinition(objectName, false);
- Type objectType = PredictObjectType(objectName, mod);
-
- if (objectType != null && typeof (IFactoryObject).IsAssignableFrom(objectType))
- {
- if (!IsFactoryDereference(name))
- {
- // If it's a FactoryBean, we want to look at what it creates, not the factory class.
- return GetTypeForFactoryObject(objectName, mod);
- }
- else
- {
- return objectType;
- }
- }
- else
- {
- return (!IsFactoryDereference(name) ? objectType : null);
- }
- }
- }
-
- ///
- /// Determines the of the object defined
- /// by the supplied object .
- ///
- ///
- ///
- /// This, the default, implementation returns
- /// to indicate that the type cannot be determined. Subclasses are
- /// encouraged to try to determine the actual return
- /// here, matching their strategy of resolving
- /// factory methods in the
- ///
- /// implementation.
- ///
- ///
- ///
- /// The name associated with the supplied object .
- ///
- ///
- /// The
- /// that the is to be determined for.
- ///
- ///
- /// The of the object defined by the supplied
- /// object ; or if the
- /// cannot be determined.
- ///
- protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
- {
- return null;
- }
-
- ///
- /// Returns the names of the objects in the singleton cache.
- ///
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- /// The names of the objects in the singleton cache.
- public virtual string[] GetSingletonNames()
- {
- lock (singletonCache)
- {
- return (string[]) new ArrayList(singletonCache.Keys).ToArray(typeof(string));
- }
- }
-
- ///
- /// Returns the number of objects in the singleton cache.
- ///
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- /// The number of objects in the singleton cache.
- public virtual int GetSingletonCount()
- {
- lock (singletonCache)
- {
- return singletonCache.Count;
- }
- }
-
- ///
- /// Destroys the named singleton object.
- ///
- ///
- ///
- /// Delegates to
- ///
- /// if a corresponding singleton instance is found.
- ///
- ///
- ///
- /// The name of the singleton object that is to be destroyed.
- ///
- ///
- protected virtual void DestroySingleton(string name)
- {
- lock (singletonCache)
- {
- object tempObject = singletonCache[name];
- singletonCache.Remove(name);
-
- object singletonInstance = tempObject;
- if (singletonInstance != null)
- {
- DestroyObject(name, singletonInstance);
- }
- }
- }
-
- ///
- /// Check the supplied merged object definition for any possible
- /// validation errors.
- ///
- ///
- /// The object definition to be checked for validation errors.
- ///
- ///
- /// The name of the object associated with the supplied object definition.
- ///
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- ///
- /// In the case of object validation errors.
- ///
- protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, String objectName,
- Type requiredType, params object[] arguments)
- {
- // check if required type can match according to the object definition;
- // this is only possible at this early stage for conventional objects!
- if (mergedObjectDefinition.HasObjectType)
- {
- Type objectType = mergedObjectDefinition.ObjectType;
- if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)
- && !typeof(IFactoryObject).IsAssignableFrom(objectType)
- && !requiredType.IsAssignableFrom(objectType))
- {
- throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType);
- }
- }
- // check validity of the usage of the args parameter; this can
- // only be used for prototypes constructed via a factory method...
- if (arguments != null && arguments.Length > 0)
- {
- if (mergedObjectDefinition.IsSingleton)
- {
- throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when "
- + "referring to a singleton object definition.");
- }
- //MLP lets skip this check for now.
- /*
- else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName))
- {
- throw new ObjectDefinitionStoreException(
- "Can only specify arguments in the GetObject () method in " +
- "conjunction with a factory method.");
- }
- */
- }
- }
-
- ///
- /// Gets the temporary object that is placed
- /// into the singleton cache during object resolution.
- ///
- protected object TemporarySingletonPlaceHolder
- {
- get { return CURRENTLY_IN_CREATION; }
- }
-
- #endregion
-
- #region Fields
-
- ///
- /// Parent object factory, for object inheritance support
- ///
- private IObjectFactory parentObjectFactory;
-
- ///
- /// Dependency types to ignore on dependency check and autowire, as Set of
- /// Type objects: for example, string. Default is none.
- ///
- private ISet ignoreDependencyTypes = new HybridSet();
-
-
- ///
- /// ObjectPostProcessors to apply in CreateObject
- ///
- private IList objectPostProcessors = new ArrayList();
-
- ///
- /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered
- ///
- private bool hasInstantiationAwareBeanPostProcessors;
-
- ///
- /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered
- ///
- private bool hasDestructionAwareBeanPostProcessors;
-
- private IDictionary aliasMap;
- private IDictionary singletonCache;
- private IDictionary singletonsInCreation;
-
- #endregion
-
- #region IHierarchicalObjectFactory Members
-
- ///
- /// The parent object factory, or if there is none.
- ///
- ///
- /// The parent object factory, or if there is none.
- ///
- public IObjectFactory ParentObjectFactory
- {
- get { return parentObjectFactory; }
- set { parentObjectFactory = value; }
- }
-
- #endregion
-
- #region IObjectFactory Members
-
- ///
- /// Is this object a singleton?
- ///
- ///
- public bool IsSingleton(string name)
- {
- string objectName = TransformedObjectName(name);
- object objectInstance = this.GetSingleton(objectName);
- if (objectInstance != null)
- {
- IFactoryObject factoryObject = objectInstance as IFactoryObject;
- if (factoryObject != null)
- {
- return IsFactoryDereference(name) || factoryObject.IsSingleton;
- }
- else
- {
- return !IsFactoryDereference(name);
- }
- }
- else
- {
- // No singleton instance found -> check object definition
- IObjectFactory pof = ParentObjectFactory;
- if (pof != null && !ContainsObjectDefinition(objectName))
- {
- // No object definition found in this factory -> delegate to parent
- return pof.IsSingleton(OriginalObjectName(name));
- }
- RootObjectDefinition od = GetMergedObjectDefinition(objectName, false);
-
- // In case of IFactoryObject, return singleton status of created object if not a dereference
- if (od.IsSingleton)
- {
- if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject)))
- {
- if (IsFactoryDereference(name))
- {
- return true;
- }
- IFactoryObject factoryObject =
- (IFactoryObject) GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName));
- return factoryObject.IsSingleton;
- }
- else
- {
- return !IsFactoryDereference(name);
- }
- }
- else
- {
- return false;
- }
- }
- }
-
- ///
- /// Determines whether the specified object name is prototype. That is, will GetObject
- /// always return independent instances?
- ///
- /// The name of the object to query
- ///
- /// true if the specified object name will always deliver independent instances; otherwise, false.
- ///
- /// This method returning false does not clearly indicate a singleton object.
- /// It indicated non-independent instances, which may correspond to a scoped object as
- /// well. use the IsSingleton property to explicitly check for a shared
- /// singleton instance.
- /// Translates aliases back to the corresponding canonical object name. Will ask the
- /// parent factory if the object can not be found in this factory instance.
- ///
- ///
- /// if there is no object with the given name.
- public bool IsPrototype(string name)
- {
- string objectName = TransformedObjectName(name);
- IObjectFactory parentFactory = ParentObjectFactory;
- if (parentFactory != null && !this.ContainsObjectDefinition(objectName))
- {
- // No object definition found in this factory -> delegate to parent
- return parentFactory.IsPrototype(OriginalObjectName(name));
- }
-
- RootObjectDefinition od = GetMergedObjectDefinition(objectName, false);
-
- // In case of FactoryObject, return singleton status of created object if not a dereference
- if (od.IsPrototype)
- {
- return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject)));
- }
- else
- {
- // not a prototype, however factory object may still produce a prototype object
- if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof (IFactoryObject)))
- {
- IFactoryObject factoryObject = GetFactoryObject(objectName);
- return (!factoryObject.IsSingleton);
- }
- else
- {
- return false;
- }
- }
- }
-
- ///
- /// Does this object factory contain an object with the given name?
- ///
- ///
- /// This method does not (and it should not) check if the specified
- /// object exists in one of the parent object factories. If it did,
- /// message sources and event registries within application context
- /// hierarchy would have circular references, which would cause stack
- /// overflows during message lookup, for example. (A. Seovic)
- ///
- /// .
- public bool ContainsObject(string name)
- {
- string objectName = TransformedObjectName(name);
- lock (singletonCache)
- {
- if (singletonCache.Contains(objectName))
- {
- return true;
- }
- }
- if (ContainsObjectDefinition(objectName))
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- /// .
- public string[] GetAliases(string name)
- {
- string objectName = TransformedObjectName(name);
- // check if object actually exists in this object factory...
- bool isInSingletonCache = false;
- lock(singletonCache)
- {
- isInSingletonCache = singletonCache.Contains(objectName);
- }
- if (isInSingletonCache || ContainsObjectDefinition(objectName))
- {
- // if found, gather aliases...
- ArrayList matches = new ArrayList();
- lock (aliasMap)
- {
- foreach (DictionaryEntry aliasEntry in aliasMap)
- {
- if (aliasEntry.Value.Equals(objectName))
- {
- matches.Add(aliasEntry.Key);
- }
- }
- }
- return (string[]) matches.ToArray(typeof(string));
- }
- else
- {
- // not found, so check parent...
- if (ParentObjectFactory != null)
- {
- return ParentObjectFactory.GetAliases(objectName);
- }
- throw new NoSuchObjectDefinitionException(objectName, ToString());
- }
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// .
- public object this[string name]
- {
- get { return GetObject(name); }
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// .
- public object GetObject(string name)
- {
- return GetObject(name, typeof(object), ObjectUtils.EmptyObjects);
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
+ /// This class provides singleton / prototype determination, singleton caching,
+ /// object definition aliasing,
+ /// handling, and object definition merging for child object definitions.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [Serializable]
+ public abstract class AbstractObjectFactory : IConfigurableObjectFactory
+ {
+ ///
+ /// Marker object to be temporarily registered in the singleton cache,
+ /// while instantiating an object (in order to be able to detect circular references).
+ ///
+ private static readonly object CURRENTLY_IN_CREATION = new Object();
+
+ ///
+ /// The instance for this class.
+ ///
+ private readonly ILog log = LogManager.GetLogger(typeof(AbstractObjectFactory));
+
+ ///
+ /// Used as value in hashtable that keeps track of singleton names currently in the
+ /// process of being created. Would not be necessary if we created a case insensitive implementation of
+ /// ISet.
+ ///
+ private static object emptyObject = new object();
+
+
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This constructor implicitly creates an
+ ///
+ /// that treats the names of objects in this factory in a case-sensitive fashion.
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ protected AbstractObjectFactory() : this(true)
+ {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ ///
+ /// if the names of objects in this factory are to be treated in a
+ /// case-sensitive fashion.
+ ///
+ protected AbstractObjectFactory(bool caseSensitive)
+ {
+ this.log = LogManager.GetLogger(this.GetType());
+ if (caseSensitive)
+ {
+ this.aliasMap = new SynchronizedHashtable();
+ this.singletonCache = new Hashtable();
+ this.singletonsInCreation = new Hashtable();
+ }
+ else
+ {
+ this.aliasMap = new SynchronizedHashtable(CollectionsUtil.CreateCaseInsensitiveHashtable());
+ this.singletonCache = CollectionsUtil.CreateCaseInsensitiveHashtable();
+ this.singletonsInCreation = CollectionsUtil.CreateCaseInsensitiveHashtable();
+ }
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ ///
+ /// if the names of objects in this factory are to be treated in a
+ /// case-sensitive fashion.
+ ///
+ ///
+ /// Any parent object factory; may be .
+ ///
+ protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) : this(caseSensitive)
+ {
+ ParentObjectFactory = parentFactory;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets the of
+ /// s
+ /// that will be applied to objects created by this factory.
+ ///
+ public IList ObjectPostProcessors
+ {
+ get { return objectPostProcessors; }
+ }
+
+ ///
+ /// Gets the set of classes that will be ignored for autowiring.
+ ///
+ ///
+ ///
+ /// The elements of this are
+ /// s.
+ ///
+ ///
+ public ISet IgnoredDependencyTypes
+ {
+ get { return ignoreDependencyTypes; }
+ }
+
+ ///
+ /// Returns, whether this object factory instance contains objects.
+ ///
+ protected bool HasInstantiationAwareBeanPostProcessors
+ {
+ get { return hasInstantiationAwareBeanPostProcessors; }
+ }
+
+ ///
+ /// Returns, whether this object factory instance contains objects.
+ ///
+ protected bool HasDestructionAwareBeanPostProcessors
+ {
+ get { return hasDestructionAwareBeanPostProcessors; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public object GetObject(string name, Type requiredType, object[] arguments)
+ {
+ string objectName = TransformedObjectName(name);
+ object instance = null;
+ // eagerly check singleton cache for manually registered singletons...
+ object sharedInstance = GetSingleton(objectName);
+
+ if (sharedInstance != null)
+ {
+ #region Instrumentation
+
+ if (IsSingletonCurrentlyInCreation(objectName))
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Returning eagerly cached instance of singleton object '" + objectName +
+ "' that is not fully initialized yet - a consequence of a circular reference");
+ }
+ }
+ else
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName));
+ }
+ }
+
+ #endregion
+
+ instance = GetObjectForInstance(name, sharedInstance);
+ }
+ else
+ {
+ // check if object definition exists
+ RootObjectDefinition mergedObjectDefinition = null;
+ mergedObjectDefinition = GetMergedObjectDefinition(objectName, false);
+ if (mergedObjectDefinition == null)
+ {
+ if (ParentObjectFactory != null)
+ {
+ return ParentObjectFactory.GetObject(name, requiredType, arguments);
+ }
+ throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]");
+ }
+
+ CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments);
+
+ // return IObjectDefinition instance itself for an abstract object-definition
+ if (mergedObjectDefinition.IsAbstract)
+ {
+ instance = mergedObjectDefinition;
+ }
+ else if (mergedObjectDefinition.IsSingleton)
+ {
+ // create object instance...
+ sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments);
+ instance = GetObjectForInstance(name, sharedInstance);
+ }
+ else
+ {
+ // it's a prototype, so create a new instance...
+ instance = CreateObject(name, mergedObjectDefinition, arguments);
+ }
+ }
+ // check that any required type matches the type of the actual object instance...
+ if (requiredType != null && !requiredType.IsAssignableFrom(instance.GetType()))
+ {
+ throw new ObjectNotOfRequiredTypeException(name, requiredType, instance);
+ }
+ return instance;
+ }
+
+
+
+ ///
+ /// Apply the property values of the object definition with the supplied
+ /// to the supplied .
+ ///
+ ///
+ ///
+ /// The object definition can either define a fully self-contained object,
+ /// reusing it's property values, or just property values meant to be used
+ /// for existing object instances.
+ ///
+ ///
+ ///
+ /// The existing object that the property values for the named object will
+ /// be applied to.
+ ///
+ ///
+ /// The name of the object definition associated with the property values that are
+ /// to be applied.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ public virtual void ApplyObjectPropertyValues(object instance, string name)
+ {
+ // explicit no-op...
+ }
+
+ ///
+ /// Initializes the given with the
+ /// custom s registered with
+ /// this factory.
+ ///
+ ///
+ /// The to initialise.
+ ///
+ protected void InitObjectWrapper(IObjectWrapper wrapper)
+ {
+ }
+
+ ///
+ /// Create an object instance for the given object definition.
+ ///
+ ///
+ ///
+ /// The object definition will already have been merged with the parent
+ /// definition in case of a child definition.
+ ///
+ ///
+ /// All the other methods in this class invoke this method, although objects
+ /// may be cached after being instantiated by this method. All object
+ /// instantiation within this class is performed by this method.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ /// The object definition for the object that is to be instantiated.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not ,
+ /// then match the argument values by type and call the object's constructor.
+ ///
+ ///
+ /// A new instance of the object.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ protected abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments);
+
+ ///
+ /// Destroy the target object.
+ ///
+ ///
+ ///
+ /// Must destroy objects that depend on the given object before the object itself,
+ /// nor throw an exception.
+ ///
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// The target object instance to destroyed.
+ ///
+ protected abstract void DestroyObject(string name, object target);
+
+ ///
+ /// Does this object factory contain an object definition with the
+ /// supplied ?
+ ///
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ /// Invoked by
+ ///
+ /// when no cached singleton instance is found.
+ ///
+ ///
+ ///
+ /// The name of the object to look for.
+ ///
+ ///
+ /// if this object factory contains an object
+ /// definition with the supplied .
+ ///
+ public abstract bool ContainsObjectDefinition(string name);
+
+ ///
+ /// Adds the supplied (object) to this factory's
+ /// singleton cache.
+ ///
+ ///
+ ///
+ /// To be called for eager registration of singletons, e.g. to be able to
+ /// resolve circular references.
+ ///
+ ///
+ /// If a singleton has already been registered under the same name as
+ /// the supplied , then the old singleton will
+ /// be replaced.
+ ///
+ ///
+ /// The name of the object.
+ /// The singleton object.
+ ///
+ /// If the argument is
+ /// or consists wholly of whitespace characters; or if the
+ /// is .
+ ///
+ protected virtual void AddSingleton(string name, object singleton)
+ {
+ AssertUtils.ArgumentHasText(name, "The object name must not be empty.");
+ AssertUtils.ArgumentNotNull(singleton, "singleton");
+ lock (singletonCache)
+ {
+ singletonCache[name] = singleton;
+ }
+ }
+
+ ///
+ /// Return the object name, stripping out the factory dereference prefix if
+ /// necessary, and resolving aliases to canonical names.
+ ///
+ ///
+ /// The transformed name of the object.
+ ///
+ protected string TransformedObjectName(string name)
+ {
+ string objectName = ObjectFactoryUtils.TransformedObjectName(name);
+ // handle aliasing...
+ lock (aliasMap)
+ {
+ string canonicalName = (string) aliasMap[objectName];
+ return canonicalName != null ? canonicalName : objectName;
+ }
+ }
+
+ ///
+ /// Ensures, that the given name is prefixed with
+ /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing
+ /// the object name during
+ ///
+ protected string OriginalObjectName(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix))
+ {
+ objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName;
+ }
+ return objectName;
+ }
+
+ ///
+ /// Determines whether the specified name is defined as an alias as opposed
+ /// to the name of an actual object definition.
+ ///
+ /// The object name to check.
+ ///
+ /// true if the specified name is alias; otherwise, false.
+ ///
+ protected bool IsAlias(string name)
+ {
+ lock (aliasMap)
+ {
+ return aliasMap.Contains(name);
+ }
+ }
+
+ ///
+ /// Return a ,
+ /// even by traversing parent if the parameter is a child definition.
+ ///
+ ///
+ /// The name of the object.
+ ///
+ ///
+ /// Are ancestors to be included in the merge?
+ ///
+ ///
+ ///
+ /// Will ask the parent object factory if not found in this instance.
+ ///
+ ///
+ ///
+ /// A merged
+ /// with overridden properties.
+ ///
+ public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors)
+ {
+ return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors));
+ }
+
+ ///
+ /// Return a ,
+ /// even by traversing parent if the parameter is a child definition.
+ ///
+ ///
+ /// A merged
+ /// with overridden properties.
+ ///
+ protected virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition definition)
+ {
+ if (definition == null)
+ {
+ return null;
+ }
+ else if (definition is RootObjectDefinition)
+ {
+ return (RootObjectDefinition) definition;
+ }
+ else if (definition is ChildObjectDefinition)
+ {
+ ChildObjectDefinition childDefinition = (ChildObjectDefinition) definition;
+ RootObjectDefinition parentDefinition = null;
+ if (!name.Equals(childDefinition.ParentName))
+ {
+ parentDefinition =
+ GetMergedObjectDefinition(TransformedObjectName(childDefinition.ParentName), true);
+ }
+ else
+ {
+ if (ParentObjectFactory is AbstractObjectFactory)
+ {
+ parentDefinition =
+ ((AbstractObjectFactory) ParentObjectFactory).GetMergedObjectDefinition(
+ childDefinition.ParentName, true);
+ }
+ }
+ if (parentDefinition == null)
+ {
+ throw new NoSuchObjectDefinitionException(childDefinition.ParentName,
+ string.Format(
+ "Parent name '{0}' is equal to object name '{1}' - "
+ +
+ "cannot be resolved without an AbstractObjectFactory parent.",
+ childDefinition.ParentName, name));
+ }
+
+ RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition);
+ rootDefinition.OverrideFrom(childDefinition);
+ return rootDefinition;
+ }
+ else
+ {
+ throw new ObjectDefinitionStoreException(definition.ResourceDescription, name,
+ "Definition is neither a RootObjectDefinition nor a ChildObjectDefinition.");
+ }
+ }
+/*
+ ///
+ /// Merges the object definitions.
+ ///
+ /// Object definition name.
+ /// The parent definition.
+ /// The child definition.
+ /// Merged object definition.
+ protected virtual RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition,
+ IObjectDefinition childDefinition)
+ {
+ RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition);
+ rootDefinition.OverrideFrom(childDefinition);
+ return rootDefinition;
+ }
+*/
+ ///
+ /// Creates the root object definition.
+ ///
+ /// The template definition to base root definition on.
+ /// Root object definition.
+ protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition)
+ {
+ return new RootObjectDefinition(templateDefinition);
+ }
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public abstract IObjectDefinition GetObjectDefinition(string name);
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ /// Whether to search parent object factories.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors);
+
+ ///
+ /// Gets the type for the given FactoryObject.
+ ///
+ /// The factory object instance to check.
+ /// the FactoryObject's object type
+ protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject)
+ {
+ try
+ {
+ return factoryObject.ObjectType;
+ }
+ catch (Exception ex)
+ {
+ log.Warn("FactoryObject threw exception from ObjectType, despite the contract saying " +
+ "that it should return null if the type of its object cannot be determined yet", ex);
+ return null;
+ }
+ }
+
+ ///
+ /// Gets the object type for the given FactoryObject definition, as far as possible.
+ /// Only called if there is no singleton instance registered for the target object already.
+ ///
+ ///
+ /// The default implementation creates the FactoryObject via GetObject
+ /// to call its ObjectType property. Subclasses are encouraged to optimize
+ /// this, typically by just instantiating the FactoryObject but not populating it yet,
+ /// trying whether its ObjectType property already returns a type.
+ /// If no type found, a full FactoryObject creation as performed by this implementation
+ /// should be used as fallback.
+ ///
+ /// Name of the object.
+ /// The merged object definition for the object.
+ /// The type for the object if determinable, or null otherwise
+ protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod)
+ {
+ if (!mod.IsSingleton)
+ {
+ return null;
+ }
+ try
+ {
+ IFactoryObject factoryObject = GetFactoryObject(objectName);
+ return GetTypeForFactoryObject(factoryObject);
+ } catch (ObjectCreationException ex)
+ {
+ // Can only happen when getting a FactoryObject.
+ log.Debug("Ignoring object creation exception on FactoryObject type check", ex);
+ return null;
+ }
+ }
+
+ ///
+ /// Predict the eventual object type (of the processed object instance) for the
+ /// specified object.
+ ///
+ ///
+ /// Does not need to handle FactoryObjects specifically, since it is only
+ /// supposed to operate on the raw object type.
+ /// This implementation is simplistic in that it is not able to
+ /// handle factory methods and InstantiationAwareBeanPostProcessors.
+ /// It only predicts the object type correctly for a standard object.
+ /// To be overridden in subclasses, applying more sophisticated type detection.
+ ///
+ /// Name of the object.
+ /// The merged object definition to determine the type for.
+ /// The type of the object, or null if not predictable
+ protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod)
+ {
+ if (StringUtils.HasText(mod.FactoryObjectName))
+ {
+ return null;
+ }
+ return ResolveObjectType(mod, objectName);
+ }
+
+ ///
+ /// Get the object for the given object instance, either the object
+ /// instance itself or its created object in case of an
+ /// .
+ ///
+ ///
+ /// The name that may include the factory dereference prefix.
+ ///
+ /// The object instance.
+ ///
+ /// The singleton instance of the object.
+ ///
+ protected virtual object GetObjectForInstance(string name, object instance)
+ {
+ //string objectName = TransformedObjectName(name);
+
+ // don't let calling code try to dereference the
+ // object factory if the object isn't a factory
+ if (IsFactoryDereference(name) && !(instance is IFactoryObject))
+ {
+ throw new ObjectIsNotAFactoryException(TransformedObjectName(name), instance);
+ }
+
+ // now we have the object instance, which may be a normal object
+ // or an IFactoryObject. If it's an IFactoryObject, we use it to
+ // create an object instance, unless the caller actually wants
+ // a reference to the factory.
+ if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFactoryObject), instance))
+ {
+ if (!IsFactoryDereference(name))
+ {
+
+ // return object instance from factory...
+ IFactoryObject factory = (IFactoryObject) instance;
+ string objectName = TransformedObjectName(name);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("Object with name '{0}' is a factory object.", objectName));
+ }
+
+ #endregion
+
+ RootObjectDefinition rod =
+ (ContainsObjectDefinition(objectName) ? GetMergedObjectDefinition(objectName,true) : null);
+ instance = GetObjectFromFactoryObject(factory, objectName, rod);
+
+ if (instance == null)
+ {
+ throw new FactoryObjectNotInitializedException(TransformedObjectName(name),
+ "Factory object returned null object - "
+ + "possible cause: not fully initialized due to "
+ + "circular object reference.");
+ }
+ }
+ else
+ {
+ // the user wants the factory itself...
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format("Calling code asked for IFactoryObject instance for name '{0}'.",
+ TransformedObjectName(name)));
+ }
+ }
+ }
+ return instance;
+ }
+
+ ///
+ /// Obtain an object to expose from the given IFactoryObject.
+ ///
+ /// The IFactoryObject instance.
+ /// Name of the object.
+ /// The merged object definition.
+ /// The object obtained from the IFactoryObject
+ /// If IFactoryObject object creation failed.
+ private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod)
+ {
+ object instance;
+
+ try
+ {
+ instance = factory.GetObject();
+ }
+ catch (FactoryObjectNotInitializedException ex)
+ {
+ throw new ObjectCurrentlyInCreationException(
+ rod.ResourceDescription, objectName, ex);
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(rod.ResourceDescription, objectName,
+ "FactoryObject threw exception on object creation.", ex);
+ }
+
+ // Do not accept a null value for a FactoryBean that's not fully
+ // initialized yet: Many FactoryBeans just return null then.
+ if (instance == null && IsSingletonCurrentlyInCreation(objectName)) {
+ throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName,
+ "FactoryObject which is currently in creation returned null from GetObject.");
+ }
+
+ if (factory is IConfigurableFactoryObject)
+ {
+ IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject)factory;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName)));
+ }
+
+ #endregion
+
+ if (configurableFactory.ProductTemplate != null)
+ {
+ instance = ConfigureObject(instance,
+ String.Format("{0}.ProductTemplate", objectName),
+ configurableFactory.ProductTemplate);
+ }
+ }
+
+ if (instance != null)
+ {
+ try
+ {
+ instance = PostProcessObjectFromFactoryObject(instance, objectName);
+ }
+ catch (Exception ex) {
+ throw new ObjectCreationException(rod.ResourceDescription, objectName,
+ "Post-processing of the FactoryObject's object failed.", ex);
+ }
+ }
+
+ return instance;
+ }
+
+ ///
+ /// Post-process the given object that has been obtained from the FactoryObject.
+ /// The resulting object will be exposed for object references.
+ ///
+ /// The default implementation simply returns the given object
+ /// as-is. Subclasses may override this, for example, to apply
+ /// post-processors.
+ /// The instance obtained from the IFactoryObject.
+ /// Name of the object.
+ /// The object instance to expose
+ /// if any post-processing failed.
+ protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName)
+ {
+ return instance;
+ }
+
+ ///
+ /// Convenience method to pull an
+ /// from this factory.
+ ///
+ ///
+ /// The name of the factory object to be retrieved. If this name is not a valid
+ /// name, it will be converted
+ /// into one.
+ ///
+ ///
+ /// The associated with the
+ /// supplied .
+ ///
+ protected IFactoryObject GetFactoryObject(string objectName)
+ {
+ if (!ObjectFactoryUtils.IsFactoryDereference(objectName))
+ {
+ objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName);
+ }
+ return (IFactoryObject) GetObject(objectName);
+ }
+
+ ///
+ /// Is the supplied a factory object dereference?
+ ///
+ protected bool IsFactoryDereference(string name)
+ {
+ return ObjectFactoryUtils.IsFactoryDereference(name);
+ }
+
+ ///
+ /// Determines whether the type of the given object definition matches the
+ /// specified target type.
+ ///
+ /// Allows for lazy load of the actual object type, provided that the
+ /// type match can be determined otherwise.
+ /// The default implementation simply delegates to the standard
+ /// ResolveObjectType method. Subclasses may override this to use
+ /// a differnt strategy.
+ ///
+ /// Name of the object (for error handling purposes).
+ /// The merged object definition to determine the type for.
+ /// Type to match against (never null).
+ ///
+ /// true if object definition matches tye specified target type; otherwise, false.
+ ///
+ /// if we failed to load the type."
+ protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType)
+ {
+ Type objectType = ResolveObjectType(rod, objectName);
+ return (objectType != null && targetType.IsAssignableFrom(objectType));
+ }
+
+ ///
+ /// Resolves the type of the object for the specified object definition resolving
+ /// an object type name to a Type (if necessary) and storing the resolved Type
+ /// in the object definition for further use.
+ ///
+ /// The merged object definition to dertermine the type for.
+ /// Name of the object (for error handling purposes).
+ ///
+ protected Type ResolveObjectType(RootObjectDefinition rod, string objectName)
+ {
+ try
+ {
+ if (rod.HasObjectType)
+ {
+ return rod.ObjectType;
+ }
+ return rod.ResolveObjectType();
+ } catch (TypeLoadException e)
+ {
+ throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e);
+ }
+ }
+
+ ///
+ /// Is the object (definition) with the supplied an
+ /// ?
+ ///
+ /// The name of the object to be checked.
+ ///
+ /// the object (definition) with the supplied
+ /// an ?
+ ///
+ protected bool IsFactoryObject(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ object objectInstance = GetSingleton(objectName);
+ //TODO investigate
+ if (IsSingletonCurrentlyInCreation(name))
+ {
+ throw new ObjectCurrentlyInCreationException(objectName);
+ }
+
+ if (objectInstance != null)
+ {
+ return (objectInstance is IFactoryObject);
+ }
+ else
+ {
+ RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false);
+ if (definition != null)
+ {
+ return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType));
+ }
+ else
+ {
+ if (parentObjectFactory != null)
+ {
+ return ((AbstractObjectFactory) parentObjectFactory).IsFactoryObject(name);
+ }
+ else
+ {
+ throw new NoSuchObjectDefinitionException(objectName,
+ "Cannot find definition for object [" + objectName
+ + "]");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Remove the object identified by the supplied
+ /// from this factory's singleton cache.
+ ///
+ ///
+ /// The name of the object that is to be removed from the singleton
+ /// cache.
+ ///
+ ///
+ /// If the argument is or
+ /// consists wholly of whitespace characters.
+ ///
+ protected void RemoveSingleton(string name)
+ {
+ AssertUtils.ArgumentHasText(name, "name");
+ lock (singletonCache)
+ {
+ this.singletonCache.Remove(name);
+ }
+ }
+
+ ///
+ /// Return the names of objects in the singleton cache that match the given
+ /// object type (including subclasses).
+ ///
+ ///
+ /// The class or interface to match, or for all object names.
+ ///
+ ///
+ ///
+ /// Will not consider s
+ /// as the type of their created objects is not known before instantiation.
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ ///
+ /// The names of objects in the singleton cache that match the given
+ /// object type (including subclasses), or an empty array if none.
+ ///
+ public virtual string[] GetSingletonNames(Type type)
+ {
+ lock (singletonCache)
+ {
+ ArrayList matches = new ArrayList();
+ foreach (string name in singletonCache.Keys)
+ {
+ object singletonObject = singletonCache[name];
+ if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType())
+ && !matches.Contains(name))
+ {
+ matches.Add(name);
+ }
+ }
+ return (string[]) matches.ToArray(typeof(string));
+ }
+ }
+
+ ///
+ /// Determines whether the object with the given name matches the specified type.
+ ///
+ /// More specifically, check whether a GetObject call for the given name
+ /// would return an object that is assignable to the specified target type.
+ /// Translates aliases back to the corresponding canonical bean name.
+ /// Will ask the parent factory if the bean cannot be found in this factory instance.
+ ///
+ /// The name of the object to query.
+ /// Type of the target to match against.
+ ///
+ /// true if the object type matches; otherwise, false
+ /// if it doesn't match or cannot be determined yet.
+ ///
+ /// Ff there is no object with the given name
+ ///
+ public bool IsTypeMatch(string name, Type targetType)
+ {
+ string objectName = TransformedObjectName(name);
+ Type typeToMatch = (targetType != null ? targetType : typeof (object));
+
+ //Check manually registered singletons.
+ object objectInstance = GetSingleton(objectName);
+ if (objectInstance != null)
+ {
+ if (objectInstance is IFactoryObject)
+ {
+ if (!IsFactoryDereference(name))
+ {
+ Type type = GetTypeForFactoryObject((IFactoryObject)objectInstance);
+ return (type != null && typeToMatch.IsAssignableFrom(type));
+ }
+ else
+ {
+ return typeToMatch.IsAssignableFrom(objectInstance.GetType());
+ }
+ }
+ else
+ {
+ return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType());
+ }
+ }
+ else
+ {
+ // No singleton instance found -> check object definition
+ IObjectFactory parentFactory = ParentObjectFactory;
+ if (parentFactory != null && !ContainsObjectDefinition(name))
+ {
+ // No object definition found in this factory -> delegate to parent
+ return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType);
+ }
+
+ RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false);
+ Type objectType = PredictObjectType(objectName, mod);
+
+ if (objectType == null)
+ {
+ return false;
+ }
+
+ // Check object class whether we're dealing with a FactoryObject
+ if (typeof(IFactoryObject).IsAssignableFrom(objectType))
+ {
+ if (!IsFactoryDereference(name))
+ {
+ // If it's a FactoryObject, we want to look at what it creates, not the factory class.
+ Type type = GetTypeForFactoryObject(objectName, mod);
+ return (type != null && typeToMatch.IsAssignableFrom(type));
+ }
+ else
+ {
+ return typeToMatch.IsAssignableFrom(objectType);
+ }
+ }
+ else
+ {
+ return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType);
+ }
+ }
+ }
+
+ ///
+ /// Determines the of the object with the
+ /// supplied .
+ ///
+ ///
+ ///
+ /// More specifically, checks the of object that
+ /// would return.
+ /// For an , returns the
+ /// of object that the
+ /// creates.
+ ///
+ ///
+ /// Please note that (prototype) objects created via a factory method or
+ /// objects are handled
+ /// slightly differently, in that we don't want to needlessly create
+ /// instances of such objects just to determine the
+ /// of object that they create.
+ ///
+ ///
+ /// The name of the object to query.
+ ///
+ /// The of the object or
+ /// if not determinable.
+ ///
+ public virtual Type GetType(string name)
+ {
+ string objectName = TransformedObjectName(name);
+
+ // check manually registered singletons...
+ object objectInstance = GetSingleton(objectName);
+
+ if (objectInstance != null)
+ {
+ IFactoryObject factoryObject = objectInstance as IFactoryObject;
+ if (factoryObject != null & !IsFactoryDereference(objectName))
+ {
+ return GetTypeForFactoryObject(factoryObject);
+ }
+ else
+ {
+ return objectInstance.GetType();
+ }
+ }
+ else
+ {
+ // No singleton instance found -> check bean definition.
+ IObjectFactory parentFactory = ParentObjectFactory;
+ if (parentFactory != null && !ContainsObjectDefinition(objectName))
+ {
+ // No bean definition found in this factory -> delegate to parent.
+ return parentFactory.GetType(this.OriginalObjectName(name));
+ }
+
+ RootObjectDefinition mod = this.GetMergedObjectDefinition(objectName, false);
+ Type objectType = PredictObjectType(objectName, mod);
+
+ if (objectType != null && typeof (IFactoryObject).IsAssignableFrom(objectType))
+ {
+ if (!IsFactoryDereference(name))
+ {
+ // If it's a FactoryBean, we want to look at what it creates, not the factory class.
+ return GetTypeForFactoryObject(objectName, mod);
+ }
+ else
+ {
+ return objectType;
+ }
+ }
+ else
+ {
+ return (!IsFactoryDereference(name) ? objectType : null);
+ }
+ }
+ }
+
+ ///
+ /// Determines the of the object defined
+ /// by the supplied object .
+ ///
+ ///
+ ///
+ /// This, the default, implementation returns
+ /// to indicate that the type cannot be determined. Subclasses are
+ /// encouraged to try to determine the actual return
+ /// here, matching their strategy of resolving
+ /// factory methods in the
+ ///
+ /// implementation.
+ ///
+ ///
+ ///
+ /// The name associated with the supplied object .
+ ///
+ ///
+ /// The
+ /// that the is to be determined for.
+ ///
+ ///
+ /// The of the object defined by the supplied
+ /// object ; or if the
+ /// cannot be determined.
+ ///
+ protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
+ {
+ return null;
+ }
+
+ ///
+ /// Returns the names of the objects in the singleton cache.
+ ///
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ /// The names of the objects in the singleton cache.
+ public virtual string[] GetSingletonNames()
+ {
+ lock (singletonCache)
+ {
+ return (string[]) new ArrayList(singletonCache.Keys).ToArray(typeof(string));
+ }
+ }
+
+ ///
+ /// Returns the number of objects in the singleton cache.
+ ///
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ /// The number of objects in the singleton cache.
+ public virtual int GetSingletonCount()
+ {
+ lock (singletonCache)
+ {
+ return singletonCache.Count;
+ }
+ }
+
+ ///
+ /// Destroys the named singleton object.
+ ///
+ ///
+ ///
+ /// Delegates to
+ ///
+ /// if a corresponding singleton instance is found.
+ ///
+ ///
+ ///
+ /// The name of the singleton object that is to be destroyed.
+ ///
+ ///
+ protected virtual void DestroySingleton(string name)
+ {
+ lock (singletonCache)
+ {
+ object tempObject = singletonCache[name];
+ singletonCache.Remove(name);
+
+ object singletonInstance = tempObject;
+ if (singletonInstance != null)
+ {
+ DestroyObject(name, singletonInstance);
+ }
+ }
+ }
+
+ ///
+ /// Check the supplied merged object definition for any possible
+ /// validation errors.
+ ///
+ ///
+ /// The object definition to be checked for validation errors.
+ ///
+ ///
+ /// The name of the object associated with the supplied object definition.
+ ///
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ ///
+ /// In the case of object validation errors.
+ ///
+ protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, String objectName,
+ Type requiredType, params object[] arguments)
+ {
+ // check if required type can match according to the object definition;
+ // this is only possible at this early stage for conventional objects!
+ if (mergedObjectDefinition.HasObjectType)
+ {
+ Type objectType = mergedObjectDefinition.ObjectType;
+ if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)
+ && !typeof(IFactoryObject).IsAssignableFrom(objectType)
+ && !requiredType.IsAssignableFrom(objectType))
+ {
+ throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType);
+ }
+ }
+ // check validity of the usage of the args parameter; this can
+ // only be used for prototypes constructed via a factory method...
+ if (arguments != null && arguments.Length > 0)
+ {
+ if (mergedObjectDefinition.IsSingleton)
+ {
+ throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when "
+ + "referring to a singleton object definition.");
+ }
+ //MLP lets skip this check for now.
+ /*
+ else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName))
+ {
+ throw new ObjectDefinitionStoreException(
+ "Can only specify arguments in the GetObject () method in " +
+ "conjunction with a factory method.");
+ }
+ */
+ }
+ }
+
+ ///
+ /// Gets the temporary object that is placed
+ /// into the singleton cache during object resolution.
+ ///
+ protected object TemporarySingletonPlaceHolder
+ {
+ get { return CURRENTLY_IN_CREATION; }
+ }
+
+ #endregion
+
+ #region Fields
+
+ ///
+ /// Parent object factory, for object inheritance support
+ ///
+ private IObjectFactory parentObjectFactory;
+
+ ///
+ /// Dependency types to ignore on dependency check and autowire, as Set of
+ /// Type objects: for example, string. Default is none.
+ ///
+ private ISet ignoreDependencyTypes = new HybridSet();
+
+
+ ///
+ /// ObjectPostProcessors to apply in CreateObject
+ ///
+ private IList objectPostProcessors = new ArrayList();
+
+ ///
+ /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered
+ ///
+ private bool hasInstantiationAwareBeanPostProcessors;
+
+ ///
+ /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered
+ ///
+ private bool hasDestructionAwareBeanPostProcessors;
+
+ private IDictionary aliasMap;
+ private IDictionary singletonCache;
+ private IDictionary singletonsInCreation;
+
+ #endregion
+
+ #region IHierarchicalObjectFactory Members
+
+ ///
+ /// The parent object factory, or if there is none.
+ ///
+ ///
+ /// The parent object factory, or if there is none.
+ ///
+ public IObjectFactory ParentObjectFactory
+ {
+ get { return parentObjectFactory; }
+ set { parentObjectFactory = value; }
+ }
+
+ #endregion
+
+ #region IObjectFactory Members
+
+ ///
+ /// Is this object a singleton?
+ ///
+ ///
+ public bool IsSingleton(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ object objectInstance = this.GetSingleton(objectName);
+ if (objectInstance != null)
+ {
+ IFactoryObject factoryObject = objectInstance as IFactoryObject;
+ if (factoryObject != null)
+ {
+ return IsFactoryDereference(name) || factoryObject.IsSingleton;
+ }
+ else
+ {
+ return !IsFactoryDereference(name);
+ }
+ }
+ else
+ {
+ // No singleton instance found -> check object definition
+ IObjectFactory pof = ParentObjectFactory;
+ if (pof != null && !ContainsObjectDefinition(objectName))
+ {
+ // No object definition found in this factory -> delegate to parent
+ return pof.IsSingleton(OriginalObjectName(name));
+ }
+ RootObjectDefinition od = GetMergedObjectDefinition(objectName, false);
+
+ // In case of IFactoryObject, return singleton status of created object if not a dereference
+ if (od.IsSingleton)
+ {
+ if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject)))
+ {
+ if (IsFactoryDereference(name))
+ {
+ return true;
+ }
+ IFactoryObject factoryObject =
+ (IFactoryObject) GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName));
+ return factoryObject.IsSingleton;
+ }
+ else
+ {
+ return !IsFactoryDereference(name);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Determines whether the specified object name is prototype. That is, will GetObject
+ /// always return independent instances?
+ ///
+ /// The name of the object to query
+ ///
+ /// true if the specified object name will always deliver independent instances; otherwise, false.
+ ///
+ /// This method returning false does not clearly indicate a singleton object.
+ /// It indicated non-independent instances, which may correspond to a scoped object as
+ /// well. use the IsSingleton property to explicitly check for a shared
+ /// singleton instance.
+ /// Translates aliases back to the corresponding canonical object name. Will ask the
+ /// parent factory if the object can not be found in this factory instance.
+ ///
+ ///
+ /// if there is no object with the given name.
+ public bool IsPrototype(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ IObjectFactory parentFactory = ParentObjectFactory;
+ if (parentFactory != null && !this.ContainsObjectDefinition(objectName))
+ {
+ // No object definition found in this factory -> delegate to parent
+ return parentFactory.IsPrototype(OriginalObjectName(name));
+ }
+
+ RootObjectDefinition od = GetMergedObjectDefinition(objectName, false);
+
+ // In case of FactoryObject, return singleton status of created object if not a dereference
+ if (od.IsPrototype)
+ {
+ return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject)));
+ }
+ else
+ {
+ // not a prototype, however factory object may still produce a prototype object
+ if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof (IFactoryObject)))
+ {
+ IFactoryObject factoryObject = GetFactoryObject(objectName);
+ return (!factoryObject.IsSingleton);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Does this object factory contain an object with the given name?
+ ///
+ ///
+ /// This method does not (and it should not) check if the specified
+ /// object exists in one of the parent object factories. If it did,
+ /// message sources and event registries within application context
+ /// hierarchy would have circular references, which would cause stack
+ /// overflows during message lookup, for example. (A. Seovic)
+ ///
+ /// .
+ public bool ContainsObject(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ lock (singletonCache)
+ {
+ if (singletonCache.Contains(objectName))
+ {
+ return true;
+ }
+ }
+ if (ContainsObjectDefinition(objectName))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ /// .
+ public string[] GetAliases(string name)
+ {
+ string objectName = TransformedObjectName(name);
+ // check if object actually exists in this object factory...
+ bool isInSingletonCache = false;
+ lock(singletonCache)
+ {
+ isInSingletonCache = singletonCache.Contains(objectName);
+ }
+ if (isInSingletonCache || ContainsObjectDefinition(objectName))
+ {
+ // if found, gather aliases...
+ ArrayList matches = new ArrayList();
+ lock (aliasMap)
+ {
+ foreach (DictionaryEntry aliasEntry in aliasMap)
+ {
+ if (aliasEntry.Value.Equals(objectName))
+ {
+ matches.Add(aliasEntry.Key);
+ }
+ }
+ }
+ return (string[]) matches.ToArray(typeof(string));
+ }
+ else
+ {
+ // not found, so check parent...
+ if (ParentObjectFactory != null)
+ {
+ return ParentObjectFactory.GetAliases(objectName);
+ }
+ throw new NoSuchObjectDefinitionException(objectName, ToString());
+ }
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// .
+ public object this[string name]
+ {
+ get { return GetObject(name); }
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// .
+ public object GetObject(string name)
+ {
+ return GetObject(name, typeof(object), ObjectUtils.EmptyObjects);
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
- /// This is a utility class, and as such has no publicly
- /// visible constructors.
- ///
- ///
- private AutowireUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// Gets those s
- /// that are applicable for autowiring the supplied .
- ///
- ///
- /// The
- /// (definition) that is being autowired by constructor.
- ///
- ///
- /// The absolute minimum number of arguments that any returned constructor
- /// must have. If this parameter is equal to zero (0), then all constructors
- /// are valid (regardless of their argument count), including any default
- /// constructor.
- ///
- ///
- /// Those s
- /// that are applicable for autowiring the supplied .
- ///
- public static ConstructorInfo[] GetConstructors(
- IObjectDefinition definition, int minimumArgumentCount)
- {
- const BindingFlags flags =
- BindingFlags.Public | BindingFlags.NonPublic
- | BindingFlags.Instance | BindingFlags.DeclaredOnly;
- ConstructorInfo[] constructors = null;
- if (minimumArgumentCount > 0)
- {
- MemberInfo[] ctors = definition.ObjectType.FindMembers(
- MemberTypes.Constructor,
- flags,
- new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- new MinimumArgumentCountCriteria(minimumArgumentCount));
- constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof (ConstructorInfo));
- }
- else
- {
- constructors = definition.ObjectType.GetConstructors(flags);
- }
- AutowireUtils.SortConstructors(constructors);
- return constructors;
- }
-
- ///
- /// Determine a weight that represents the class hierarchy difference between types and
- /// arguments.
- ///
- ///
- ///
- /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase
- /// the result - all direct matches means weight zero (0). A match between the argument type
- /// and a MyInteger instance argument would increase the weight by
- /// 1, due to the superclass () being one (1) steps up in the
- /// class hierarchy being the last one that still matches the required type.
- ///
- ///
- /// Therefore, with an argument of type , a
- /// constructor taking a argument would be
- /// preferred to a constructor taking an argument
- /// which would be preferred to a constructor taking an
- /// argument which would in turn be preferred
- /// to a constructor taking an argument.
- ///
- ///
- /// All argument weights get accumulated.
- ///
- ///
- ///
- /// The argument s to match.
- ///
- /// The arguments to match.
- /// The accumulated weight for all arguments.
- public static int GetTypeDifferenceWeight(ParameterInfo[] argTypes, object[] args)
- {
- if (argTypes.Length != args.Length)
- {
- throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths.");
- }
- int result = 0;
- for (int i = 0; i < argTypes.Length; i++)
- {
- Type theParameterType = argTypes[i].ParameterType;
- if (!ObjectUtils.IsAssignable(theParameterType, args[i]))
- {
- return Int32.MaxValue;
- }
- if (args[i] != null
- && !(args[i].GetType().Equals(theParameterType)))
- {
- Type superType = args[i].GetType().BaseType;
- while (superType != null)
- {
- if (theParameterType.IsAssignableFrom(superType))
- {
- ++result;
- superType = superType.BaseType;
- }
- else
- {
- superType = null;
- }
- }
- }
- }
- return result;
- }
-
- ///
- /// Determines whether the given object property is excluded from dependency checks.
- ///
- /// The PropertyInfo of the object property.
- ///
- /// true if is excluded from dependency check; otherwise, false.
- ///
- public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi)
- {
- return (pi.GetSetMethod() == null) ? false : true;
- }
-
- ///
- /// Sorts the supplied , preferring
- /// public constructors and "greedy" ones (that have lots of arguments).
- ///
- ///
- ///
- /// The result will contain public constructors first, with a decreasing number
- /// of arguments, then non-public constructors, again with a decreasing number
- /// of arguments.
- ///
+ /// This is a utility class, and as such has no publicly
+ /// visible constructors.
+ ///
+ ///
+ private AutowireUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// Gets those s
+ /// that are applicable for autowiring the supplied .
+ ///
+ ///
+ /// The
+ /// (definition) that is being autowired by constructor.
+ ///
+ ///
+ /// The absolute minimum number of arguments that any returned constructor
+ /// must have. If this parameter is equal to zero (0), then all constructors
+ /// are valid (regardless of their argument count), including any default
+ /// constructor.
+ ///
+ ///
+ /// Those s
+ /// that are applicable for autowiring the supplied .
+ ///
+ public static ConstructorInfo[] GetConstructors(
+ IObjectDefinition definition, int minimumArgumentCount)
+ {
+ const BindingFlags flags =
+ BindingFlags.Public | BindingFlags.NonPublic
+ | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+ ConstructorInfo[] constructors = null;
+ if (minimumArgumentCount > 0)
+ {
+ MemberInfo[] ctors = definition.ObjectType.FindMembers(
+ MemberTypes.Constructor,
+ flags,
+ new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ new MinimumArgumentCountCriteria(minimumArgumentCount));
+ constructors = (ConstructorInfo[]) ArrayList.Adapter(ctors).ToArray(typeof (ConstructorInfo));
+ }
+ else
+ {
+ constructors = definition.ObjectType.GetConstructors(flags);
+ }
+ AutowireUtils.SortConstructors(constructors);
+ return constructors;
+ }
+
+ ///
+ /// Determine a weight that represents the class hierarchy difference between types and
+ /// arguments.
+ ///
+ ///
+ ///
+ /// A direct match, i.e. type MyInteger -> arg of class MyInteger, does not increase
+ /// the result - all direct matches means weight zero (0). A match between the argument type
+ /// and a MyInteger instance argument would increase the weight by
+ /// 1, due to the superclass () being one (1) steps up in the
+ /// class hierarchy being the last one that still matches the required type.
+ ///
+ ///
+ /// Therefore, with an argument of type , a
+ /// constructor taking a argument would be
+ /// preferred to a constructor taking an argument
+ /// which would be preferred to a constructor taking an
+ /// argument which would in turn be preferred
+ /// to a constructor taking an argument.
+ ///
+ ///
+ /// All argument weights get accumulated.
+ ///
+ ///
+ ///
+ /// The argument s to match.
+ ///
+ /// The arguments to match.
+ /// The accumulated weight for all arguments.
+ public static int GetTypeDifferenceWeight(ParameterInfo[] argTypes, object[] args)
+ {
+ if (argTypes.Length != args.Length)
+ {
+ throw new ArgumentException("Cannot calculate the type difference weight for argument types and arguments with differing lengths.");
+ }
+ int result = 0;
+ for (int i = 0; i < argTypes.Length; i++)
+ {
+ Type theParameterType = argTypes[i].ParameterType;
+ if (!ObjectUtils.IsAssignable(theParameterType, args[i]))
+ {
+ return Int32.MaxValue;
+ }
+ if (args[i] != null
+ && !(args[i].GetType().Equals(theParameterType)))
+ {
+ Type superType = args[i].GetType().BaseType;
+ while (superType != null)
+ {
+ if (theParameterType.IsAssignableFrom(superType))
+ {
+ ++result;
+ superType = superType.BaseType;
+ }
+ else
+ {
+ superType = null;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Determines whether the given object property is excluded from dependency checks.
+ ///
+ /// The PropertyInfo of the object property.
+ ///
+ /// true if is excluded from dependency check; otherwise, false.
+ ///
+ public static Boolean IsExcludedFromDependencyCheck(PropertyInfo pi)
+ {
+ return (pi.GetSetMethod() == null) ? false : true;
+ }
+
+ ///
+ /// Sorts the supplied , preferring
+ /// public constructors and "greedy" ones (that have lots of arguments).
+ ///
+ ///
+ ///
+ /// The result will contain public constructors first, with a decreasing number
+ /// of arguments, then non-public constructors, again with a decreasing number
+ /// of arguments.
+ ///
- /// Will use the
- /// of the parent object definition if none is specified, but can also
- /// override it. In the latter case, the child's
- ///
- /// must be compatible with the parent, i.e. accept the parent's property values
- /// and constructor argument values (if any).
- ///
- ///
- /// A will
- /// inherit all of the ,
- /// , and
- /// from it's parent
- /// object definition, with the option to add new values. If the
- /// ,
- /// ,
- /// and / or
- ///
- /// properties are specified, they will override the corresponding parent settings.
- ///
- ///
- /// The remaining settings will always be taken from the child definition:
- /// ,
- /// ,
- /// ,
- /// ,
- /// and
- ///
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- ///
- [Serializable]
- public class ChildObjectDefinition : AbstractObjectDefinition
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The name of the parent object.
- ///
- public ChildObjectDefinition(string parentName)
- {
- this.parentName = parentName;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The name of the parent object.
- ///
- ///
- /// The additional property values (if any) of the child.
- ///
- public ChildObjectDefinition(string parentName, MutablePropertyValues properties)
- : base(null, properties)
- {
- this.parentName = parentName;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The name of the parent object.
- ///
- ///
- /// The
- /// to be applied to a new instance of the object.
- ///
- ///
- /// The additional property values (if any) of the child.
- ///
- public ChildObjectDefinition(
- string parentName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
- : base(arguments, properties)
- {
- this.parentName = parentName;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The name of the parent object.
- ///
- ///
- /// The class of the object to instantiate.
- ///
- ///
- /// The
- /// to be applied to a new instance of the object.
- ///
- ///
- /// The additional property values (if any) of the child.
- ///
- public ChildObjectDefinition(
- string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties)
- : base(arguments, properties)
- {
- this.parentName = parentName;
- ObjectType = type;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The name of the parent object.
- ///
- ///
- /// The of the object to
- /// instantiate.
- ///
- ///
- /// The
- /// to be applied to a new instance of the object.
- ///
- ///
- /// The additional property values (if any) of the child.
- ///
- public ChildObjectDefinition(
- string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
- : base(arguments, properties)
- {
- this.parentName = parentName;
- ObjectTypeName = typeName;
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The name of the parent object definition.
- ///
- ///
- ///
- /// This value is required.
- ///
- ///
- ///
- /// The name of the parent object definition.
- ///
- public string ParentName
- {
- get { return parentName; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Validate this object definition.
- ///
- ///
- ///
- /// A common cause of validation failures is a missing value for the
- ///
- /// property; by
- /// their very nature require that the
- ///
- /// be set.
- ///
+ /// Will use the
+ /// of the parent object definition if none is specified, but can also
+ /// override it. In the latter case, the child's
+ ///
+ /// must be compatible with the parent, i.e. accept the parent's property values
+ /// and constructor argument values (if any).
+ ///
+ ///
+ /// A will
+ /// inherit all of the ,
+ /// , and
+ /// from it's parent
+ /// object definition, with the option to add new values. If the
+ /// ,
+ /// ,
+ /// and / or
+ ///
+ /// properties are specified, they will override the corresponding parent settings.
+ ///
+ ///
+ /// The remaining settings will always be taken from the child definition:
+ /// ,
+ /// ,
+ /// ,
+ /// ,
+ /// and
+ ///
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class ChildObjectDefinition : AbstractObjectDefinition
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The name of the parent object.
+ ///
+ public ChildObjectDefinition(string parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The name of the parent object.
+ ///
+ ///
+ /// The additional property values (if any) of the child.
+ ///
+ public ChildObjectDefinition(string parentName, MutablePropertyValues properties)
+ : base(null, properties)
+ {
+ this.parentName = parentName;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The name of the parent object.
+ ///
+ ///
+ /// The
+ /// to be applied to a new instance of the object.
+ ///
+ ///
+ /// The additional property values (if any) of the child.
+ ///
+ public ChildObjectDefinition(
+ string parentName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ : base(arguments, properties)
+ {
+ this.parentName = parentName;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The name of the parent object.
+ ///
+ ///
+ /// The class of the object to instantiate.
+ ///
+ ///
+ /// The
+ /// to be applied to a new instance of the object.
+ ///
+ ///
+ /// The additional property values (if any) of the child.
+ ///
+ public ChildObjectDefinition(
+ string parentName, Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ : base(arguments, properties)
+ {
+ this.parentName = parentName;
+ ObjectType = type;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The name of the parent object.
+ ///
+ ///
+ /// The of the object to
+ /// instantiate.
+ ///
+ ///
+ /// The
+ /// to be applied to a new instance of the object.
+ ///
+ ///
+ /// The additional property values (if any) of the child.
+ ///
+ public ChildObjectDefinition(
+ string parentName, string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ : base(arguments, properties)
+ {
+ this.parentName = parentName;
+ ObjectTypeName = typeName;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The name of the parent object definition.
+ ///
+ ///
+ ///
+ /// This value is required.
+ ///
+ ///
+ ///
+ /// The name of the parent object definition.
+ ///
+ public string ParentName
+ {
+ get { return parentName; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Validate this object definition.
+ ///
+ ///
+ ///
+ /// A common cause of validation failures is a missing value for the
+ ///
+ /// property; by
+ /// their very nature require that the
+ ///
+ /// be set.
+ ///
- /// This class is a full-fledged object factory based on object definitions
- /// that is usable straight out of the box.
- ///
- ///
- /// Can be used as an object factory in and of itself, or as a superclass
- /// for custom object factory implementations. Note that readers for
- /// specific object definition formats are typically implemented separately
- /// rather than as object factory subclasses.
- ///
- ///
- /// For an alternative implementation of the
- /// interface,
- /// have a look at the
- ///
- /// class, which manages existing object instances rather than creating new
- /// ones based on object definitions.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- ///
- /// $Id: DefaultListableObjectFactory.cs,v 1.42 2007/10/10 19:17:07 bbaia Exp $
- [Serializable]
- public class DefaultListableObjectFactory :
- AbstractAutowireCapableObjectFactory,
- IConfigurableListableObjectFactory,
- IObjectDefinitionRegistry
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public DefaultListableObjectFactory() : this(true, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- public DefaultListableObjectFactory(bool caseSensitive) : this(caseSensitive, null)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// The parent object factory.
- public DefaultListableObjectFactory(IObjectFactory parentFactory)
- : this(true, parentFactory)
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// Flag specifying whether to make this object factory case sensitive or not.
- /// The parent object factory.
- public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
- : base(caseSensitive, parentFactory)
- {
- if (caseSensitive)
- {
- objectDefinitionMap = new Hashtable();
- }
- else
- {
- objectDefinitionMap = CollectionsUtil.CreateCaseInsensitiveHashtable();
- }
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Should object definitions registered under the same name as an
- /// existing object definition be allowed?
- ///
- ///
- ///
- /// If , then the new object definition will
- /// replace (override) the existing object definition. If
- /// , an exception will be thrown when
- /// an attempt is made to register an object definition under the same
- /// name as an already existing object definition.
- ///
- ///
- /// The default is .
- ///
- ///
- ///
- /// is the registration of an object definition
- /// under the same name as an existing object definition is allowed.
- ///
- public bool AllowObjectDefinitionOverriding
- {
- get { return allowObjectDefinitionOverriding; }
- set { allowObjectDefinitionOverriding = value; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Find object instances that match the .
- ///
- ///
- ///
- /// Called by autowiring. If a subclass cannot obtain information about object
- /// names by , a corresponding exception should be thrown.
- ///
- ///
- ///
- /// The type of the objects to look up.
- ///
- ///
- /// An of object names and object
- /// instances that match the , or
- /// if none is found.
- ///
- ///
- /// In case of errors.
- ///
- protected override IDictionary FindMatchingObjects(Type requiredType)
- {
- return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(
- this, requiredType, true, true);
- }
-
- ///
- /// Return the names of the objects that depend on the given object.
- ///
- ///
- ///
- /// Called by the
- ///
- /// so that dependant objects are able to be disposed of first.
- ///
+ /// This class is a full-fledged object factory based on object definitions
+ /// that is usable straight out of the box.
+ ///
+ ///
+ /// Can be used as an object factory in and of itself, or as a superclass
+ /// for custom object factory implementations. Note that readers for
+ /// specific object definition formats are typically implemented separately
+ /// rather than as object factory subclasses.
+ ///
+ ///
+ /// For an alternative implementation of the
+ /// interface,
+ /// have a look at the
+ ///
+ /// class, which manages existing object instances rather than creating new
+ /// ones based on object definitions.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class DefaultListableObjectFactory :
+ AbstractAutowireCapableObjectFactory,
+ IConfigurableListableObjectFactory,
+ IObjectDefinitionRegistry
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public DefaultListableObjectFactory() : this(true, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ public DefaultListableObjectFactory(bool caseSensitive) : this(caseSensitive, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// The parent object factory.
+ public DefaultListableObjectFactory(IObjectFactory parentFactory)
+ : this(true, parentFactory)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ /// The parent object factory.
+ public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
+ : base(caseSensitive, parentFactory)
+ {
+ if (caseSensitive)
+ {
+ objectDefinitionMap = new Hashtable();
+ }
+ else
+ {
+ objectDefinitionMap = CollectionsUtil.CreateCaseInsensitiveHashtable();
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Should object definitions registered under the same name as an
+ /// existing object definition be allowed?
+ ///
+ ///
+ ///
+ /// If , then the new object definition will
+ /// replace (override) the existing object definition. If
+ /// , an exception will be thrown when
+ /// an attempt is made to register an object definition under the same
+ /// name as an already existing object definition.
+ ///
+ ///
+ /// The default is .
+ ///
+ ///
+ ///
+ /// is the registration of an object definition
+ /// under the same name as an existing object definition is allowed.
+ ///
+ public bool AllowObjectDefinitionOverriding
+ {
+ get { return allowObjectDefinitionOverriding; }
+ set { allowObjectDefinitionOverriding = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Find object instances that match the .
+ ///
+ ///
+ ///
+ /// Called by autowiring. If a subclass cannot obtain information about object
+ /// names by , a corresponding exception should be thrown.
+ ///
+ ///
+ ///
+ /// The type of the objects to look up.
+ ///
+ ///
+ /// An of object names and object
+ /// instances that match the , or
+ /// if none is found.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ protected override IDictionary FindMatchingObjects(Type requiredType)
+ {
+ return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(
+ this, requiredType, true, true);
+ }
+
+ ///
+ /// Return the names of the objects that depend on the given object.
+ ///
+ ///
+ ///
+ /// Called by the
+ ///
+ /// so that dependant objects are able to be disposed of first.
+ ///
- /// This class is reserved for internal use within the framework; it is
- /// not intended to be used by application developers using Spring.NET.
- ///
+ /// This class is reserved for internal use within the framework; it is
+ /// not intended to be used by application developers using Spring.NET.
+ ///
- /// If , an object factory will apply the Prototype
- /// design pattern, with each caller requesting an instance getting an
- /// independent instance. How this is defined will depend on the
- /// object factory implementation. Singletons are the commoner type.
- ///
- ///
- new bool IsSingleton { get; set; }
-
- ///
- /// Is this object lazily initialized?
- ///
- ///
- /// Only applicable to a singleton object.
- ///
- ///
- /// If , it will get instantiated on startup by object factories
- /// that perform eager initialization of singletons.
- ///
- ///
- new bool IsLazyInit { get; set; }
-
- ///
- /// The autowire mode as specified in the object definition.
- ///
- ///
- ///
- /// This determines whether any automagical detection and setting of
- /// object references will happen. Default is
- /// ,
- /// which means there's no autowire.
- ///
- ///
- new AutoWiringMode AutowireMode { get; set; }
-
- ///
- /// The dependency check code.
- ///
- DependencyCheckingMode DependencyCheck { get; set; }
-
- ///
- /// The object names that this object depends on.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects get initialized
- /// before.
- ///
- ///
- /// Note that dependencies are normally expressed through object properties
- /// or constructor arguments. This property should just be necessary for
- /// other kinds of dependencies like statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- new string[] DependsOn { get; set; }
-
- ///
- /// The name of the initializer method.
- ///
- ///
- ///
- /// The default is , in which case there is no initializer method.
- ///
- ///
- new string InitMethodName { get; set; }
-
- ///
- /// Return the name of the destroy method.
- ///
- ///
- ///
- /// The default is , in which case there is no destroy method.
- ///
- ///
- new string DestroyMethodName { get; set; }
-
- ///
- /// The name of the factory method to use (if any).
- ///
- ///
- ///
- /// This method will be invoked with constructor arguments, or with no
- /// arguments if none are specified. The static method will be invoked on
- /// the specified .
- ///
+ /// If , an object factory will apply the Prototype
+ /// design pattern, with each caller requesting an instance getting an
+ /// independent instance. How this is defined will depend on the
+ /// object factory implementation. Singletons are the commoner type.
+ ///
+ ///
+ new bool IsSingleton { get; set; }
+
+ ///
+ /// Is this object lazily initialized?
+ ///
+ ///
+ /// Only applicable to a singleton object.
+ ///
+ ///
+ /// If , it will get instantiated on startup by object factories
+ /// that perform eager initialization of singletons.
+ ///
+ ///
+ new bool IsLazyInit { get; set; }
+
+ ///
+ /// The autowire mode as specified in the object definition.
+ ///
+ ///
+ ///
+ /// This determines whether any automagical detection and setting of
+ /// object references will happen. Default is
+ /// ,
+ /// which means there's no autowire.
+ ///
+ ///
+ new AutoWiringMode AutowireMode { get; set; }
+
+ ///
+ /// The dependency check code.
+ ///
+ DependencyCheckingMode DependencyCheck { get; set; }
+
+ ///
+ /// The object names that this object depends on.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects get initialized
+ /// before.
+ ///
+ ///
+ /// Note that dependencies are normally expressed through object properties
+ /// or constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies like statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ new string[] DependsOn { get; set; }
+
+ ///
+ /// The name of the initializer method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no initializer method.
+ ///
+ ///
+ new string InitMethodName { get; set; }
+
+ ///
+ /// Return the name of the destroy method.
+ ///
+ ///
+ ///
+ /// The default is , in which case there is no destroy method.
+ ///
+ ///
+ new string DestroyMethodName { get; set; }
+
+ ///
+ /// The name of the factory method to use (if any).
+ ///
+ ///
+ ///
+ /// This method will be invoked with constructor arguments, or with no
+ /// arguments if none are specified. The static method will be invoked on
+ /// the specified .
+ ///
- /// 'A special placeholder collection' means that the elements of this
- /// collection can be placeholders for objects that will be resolved later by
- /// a Spring.NET IoC container, i.e. the elements themselves will be
- /// resolved at runtime by the enclosing IoC container.
- ///
- ///
- /// The core Spring.NET library already provides three implementations of this interface
- /// straight out of the box; they are...
- ///
- /// If you have a custom collection class (i.e. a class that either implements the
- /// directly or derives from a class that does)
- /// that you would like to expose as a special placeholder collection (i.e. one that can
- /// have s as elements
- /// that will be resolved at runtime by an appropriate Spring.NET IoC container, just
- /// implement this interface.
- ///
- ///
- ///
- ///
- /// Lets say one has a Bag class (i.e. a collection that supports bag style semantics).
- ///
- ///
- /// using System;
- ///
- /// using Spring.Objects.Factory.Support;
- ///
- /// namespace MyNamespace
- /// {
- /// public sealed class Bag : ICollection
- /// {
- /// // ICollection implementation elided for clarity...
- ///
- /// public void Add(object o)
- /// {
- /// // implementation elided for clarity...
- /// }
- /// }
- ///
- /// public class ManagedBag : Bag, IManagedCollection
- /// {
- /// public ICollection Resolve(
- /// string objectName, RootObjectDefinition definition,
- /// string propertyName, ManagedCollectionElementResolver resolver)
- /// {
- /// Bag newBag = new Bag();
- /// string elementName = propertyName + "[bag-element]";
- /// foreach(object element in this)
- /// {
- /// object resolvedElement = resolver(objectName, definition, elementName, element);
- /// newBag.Add(resolvedElement);
- /// }
- /// return newBag;
- /// }
- /// }
- /// }
- ///
- ///
- /// Rick Evans
- /// $Id: IManagedCollection.cs,v 1.5 2007/03/16 03:05:37 bbaia Exp $
- public interface IManagedCollection : ICollection
- {
- ///
- /// Resolves this managed collection at runtime.
- ///
- ///
- /// The name of the top level object that is having the value of one of it's
- /// collection properties resolved.
- ///
- ///
- /// The definition of the named top level object.
- ///
- ///
- /// The name of the property the value of which is being resolved.
- ///
- ///
- /// The callback that will actually do the donkey work of resolving
- /// this managed collection.
- ///
- /// A fully resolved collection.
- ICollection Resolve(string objectName, RootObjectDefinition definition,
- string propertyName, ManagedCollectionElementResolver resolver);
- }
-
- ///
- /// Resolves a single element value of a managed collection.
- ///
- ///
- ///
- /// If the does not need to be resolved or
- /// converted to an appropriate , the
- /// will be returned as-is.
- ///
+ /// 'A special placeholder collection' means that the elements of this
+ /// collection can be placeholders for objects that will be resolved later by
+ /// a Spring.NET IoC container, i.e. the elements themselves will be
+ /// resolved at runtime by the enclosing IoC container.
+ ///
+ ///
+ /// The core Spring.NET library already provides three implementations of this interface
+ /// straight out of the box; they are...
+ ///
+ /// If you have a custom collection class (i.e. a class that either implements the
+ /// directly or derives from a class that does)
+ /// that you would like to expose as a special placeholder collection (i.e. one that can
+ /// have s as elements
+ /// that will be resolved at runtime by an appropriate Spring.NET IoC container, just
+ /// implement this interface.
+ ///
+ ///
+ ///
+ ///
+ /// Lets say one has a Bag class (i.e. a collection that supports bag style semantics).
+ ///
+ ///
+ /// using System;
+ ///
+ /// using Spring.Objects.Factory.Support;
+ ///
+ /// namespace MyNamespace
+ /// {
+ /// public sealed class Bag : ICollection
+ /// {
+ /// // ICollection implementation elided for clarity...
+ ///
+ /// public void Add(object o)
+ /// {
+ /// // implementation elided for clarity...
+ /// }
+ /// }
+ ///
+ /// public class ManagedBag : Bag, IManagedCollection
+ /// {
+ /// public ICollection Resolve(
+ /// string objectName, RootObjectDefinition definition,
+ /// string propertyName, ManagedCollectionElementResolver resolver)
+ /// {
+ /// Bag newBag = new Bag();
+ /// string elementName = propertyName + "[bag-element]";
+ /// foreach(object element in this)
+ /// {
+ /// object resolvedElement = resolver(objectName, definition, elementName, element);
+ /// newBag.Add(resolvedElement);
+ /// }
+ /// return newBag;
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ /// Rick Evans
+ public interface IManagedCollection : ICollection
+ {
+ ///
+ /// Resolves this managed collection at runtime.
+ ///
+ ///
+ /// The name of the top level object that is having the value of one of it's
+ /// collection properties resolved.
+ ///
+ ///
+ /// The definition of the named top level object.
+ ///
+ ///
+ /// The name of the property the value of which is being resolved.
+ ///
+ ///
+ /// The callback that will actually do the donkey work of resolving
+ /// this managed collection.
+ ///
+ /// A fully resolved collection.
+ ICollection Resolve(string objectName, RootObjectDefinition definition,
+ string propertyName, ManagedCollectionElementResolver resolver);
+ }
+
+ ///
+ /// Resolves a single element value of a managed collection.
+ ///
+ ///
+ ///
+ /// If the does not need to be resolved or
+ /// converted to an appropriate , the
+ /// will be returned as-is.
+ ///
- /// Encapsulates the notion of the Method-Injection form of Dependency
- /// Injection.
- ///
- ///
- /// Methods that are dependency injected with implementations of this
- /// interface may be (but need not be) , in which
- /// case the container will create a concrete subclass of the
- /// class prior to instantiation.
- ///
- ///
- /// Do not use this mechanism as a means of AOP. See the reference
- /// manual for examples of appropriate usages of this interface.
- ///
+ /// Encapsulates the notion of the Method-Injection form of Dependency
+ /// Injection.
+ ///
+ ///
+ /// Methods that are dependency injected with implementations of this
+ /// interface may be (but need not be) , in which
+ /// case the container will create a concrete subclass of the
+ /// class prior to instantiation.
+ ///
+ ///
+ /// Do not use this mechanism as a means of AOP. See the reference
+ /// manual for examples of appropriate usages of this interface.
+ ///
- /// Typically implemented by object factories that work with the
- ///
- /// hierarchy internally.
- ///
- ///
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- public interface IObjectDefinitionRegistry
- {
- ///
- /// Return the number of objects defined in the registry.
- ///
- ///
- /// The number of objects defined in the registry.
- ///
- int ObjectDefinitionCount
- {
- get;
- }
-
- ///
- /// Return the names of all objects defined in this registry.
- ///
- ///
- /// The names of all objects defined in this registry, or an empty array
- /// if none defined
- ///
- string [] GetObjectDefinitionNames ();
-
- ///
- /// Check if this registry contains a object definition with the given name.
- ///
- ///
- /// The name of the object to look for.
- ///
- ///
- /// True if this object factory contains an object definition with the
- /// given name.
- ///
- bool ContainsObjectDefinition (string name);
-
- ///
- /// Returns the
- ///
- /// for the given object name.
- ///
- ///
- /// The name of the object to find a definition for.
- ///
- ///
- /// The for
- /// the given name (never null).
- ///
- ///
- /// If the object definition cannot be resolved.
- ///
- ///
- /// In case of errors.
- ///
- IObjectDefinition GetObjectDefinition (string name);
-
- ///
- /// Register a new object definition with this registry.
- /// Must support
- ///
- /// and .
- ///
- ///
- /// The name of the object instance to register.
- ///
- ///
- /// The definition of the object instance to register.
- ///
- ///
- ///
- /// Must support
- /// and
- /// .
- ///
- ///
- ///
- /// If the object definition is invalid.
- ///
- void RegisterObjectDefinition (string name, IObjectDefinition definition);
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- /// the object name to check for aliases
- ///
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this
- /// factory instance.
- ///
+ /// Typically implemented by object factories that work with the
+ ///
+ /// hierarchy internally.
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public interface IObjectDefinitionRegistry
+ {
+ ///
+ /// Return the number of objects defined in the registry.
+ ///
+ ///
+ /// The number of objects defined in the registry.
+ ///
+ int ObjectDefinitionCount
+ {
+ get;
+ }
+
+ ///
+ /// Return the names of all objects defined in this registry.
+ ///
+ ///
+ /// The names of all objects defined in this registry, or an empty array
+ /// if none defined
+ ///
+ string [] GetObjectDefinitionNames ();
+
+ ///
+ /// Check if this registry contains a object definition with the given name.
+ ///
+ ///
+ /// The name of the object to look for.
+ ///
+ ///
+ /// True if this object factory contains an object definition with the
+ /// given name.
+ ///
+ bool ContainsObjectDefinition (string name);
+
+ ///
+ /// Returns the
+ ///
+ /// for the given object name.
+ ///
+ ///
+ /// The name of the object to find a definition for.
+ ///
+ ///
+ /// The for
+ /// the given name (never null).
+ ///
+ ///
+ /// If the object definition cannot be resolved.
+ ///
+ ///
+ /// In case of errors.
+ ///
+ IObjectDefinition GetObjectDefinition (string name);
+
+ ///
+ /// Register a new object definition with this registry.
+ /// Must support
+ ///
+ /// and .
+ ///
+ ///
+ /// The name of the object instance to register.
+ ///
+ ///
+ /// The definition of the object instance to register.
+ ///
+ ///
+ ///
+ /// Must support
+ /// and
+ /// .
+ ///
+ ///
+ ///
+ /// If the object definition is invalid.
+ ///
+ void RegisterObjectDefinition (string name, IObjectDefinition definition);
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ /// the object name to check for aliases
+ ///
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this
+ /// factory instance.
+ ///
- /// This class is Spring.NET's implementation of Dependency Lookup via
- /// Method Injection.
- ///
- ///
- /// This class is reserved for internal use within the framework; it is
- /// not intended to be used by application developers using Spring.NET.
- ///
+ /// This class is Spring.NET's implementation of Dependency Lookup via
+ /// Method Injection.
+ ///
+ ///
+ /// This class is reserved for internal use within the framework; it is
+ /// not intended to be used by application developers using Spring.NET.
+ ///
- /// Classes that want to take advantage of method injection must meet some
- /// stringent criteria. Every method that is to be method injected
- /// must be defined as either or
- /// . An
- /// will be thrown if these criteria are not met.
- ///
- ///
- /// Rick Evans
- /// $Id: MethodInjectingInstantiationStrategy.cs,v 1.13 2008/05/02 16:44:44 markpollack Exp $
- [Serializable]
- public class MethodInjectingInstantiationStrategy : SimpleInstantiationStrategy
- {
- ///
- /// The name of the dynamic assembly that holds dynamically created code
- ///
- private const string DYNAMIC_ASSEMBLY_NAME = "Spring.MethodInjected";
-
- ///
- /// A cache of generated instances, keyed on
- /// the object name for which the was generated.
- ///
- private IDictionary typeCache = new Hashtable();
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied ,
- /// injecting methods as appropriate.
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the
- /// or zero length string if we're autowiring an
- /// object that doesn't belong to the supplied
- /// .
- ///
- ///
- /// The owning
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- ///
- protected override object InstantiateWithMethodInjection(
- RootObjectDefinition definition, string objectName, IObjectFactory factory)
- {
- return DoInstantiate(definition, objectName, factory, Type.EmptyTypes, ObjectUtils.EmptyObjects);
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied ,
- /// injecting methods as appropriate.
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the
- /// or zero length string if we're autowiring an
- /// object that doesn't belong to the supplied
- /// .
- ///
- ///
- /// The owning
- ///
- ///
- /// The to be used to instantiate
- /// the object.
- ///
- ///
- /// Any arguments to the supplied . May be null.
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- ///
- protected override object InstantiateWithMethodInjection(
- RootObjectDefinition definition, string objectName, IObjectFactory factory, ConstructorInfo constructor, object[] arguments)
- {
- return DoInstantiate(definition, objectName, factory, ReflectionUtils.GetParameterTypes(constructor), arguments);
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied ,
- /// injecting methods as appropriate.
- ///
- ///
- ///
- /// This method dynamically generates a subclass that supports method
- /// injection for the supplied . It then
- /// instantiates an new instance of said type using the constructor
- /// identified by the supplied ,
- /// passing the supplied to said
- /// constructor. It then manually injects (generic) method replacement
- /// and method lookup instances (of
- /// ) into
- /// the new instance: those methods that are 'method-injected' will
- /// then delegate to the approriate
- ///
- /// instance to effect the actual method injection.
- ///
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the
- /// or zero length string if we're autowiring an
- /// object that doesn't belong to the supplied
- /// .
- ///
- ///
- /// The owning
- ///
- ///
- /// The parameter s to use to find the
- /// appropriate constructor to invoke.
- ///
- ///
- /// The aguments that are to be passed to the appropriate constructor
- /// when the object is being instantiated.
- ///
- ///
- /// A new instance of the defined by the
- /// supplied .
- ///
- private object DoInstantiate(
- RootObjectDefinition definition, string objectName, IObjectFactory factory, Type[] ctorParameterTypes, object[] arguments)
- {
- Type type = GetGeneratedType(objectName, definition);
- object instance = type.GetConstructor(ctorParameterTypes).Invoke(arguments);
- IObjectWrapper wrapper = new ObjectWrapper(instance);
- wrapper.SetPropertyValue(
- MethodInjectingTypeBuilder.MethodReplacementPropertyName,
- new DelegatingMethodReplacer(definition, factory));
- wrapper.SetPropertyValue(
- MethodInjectingTypeBuilder.MethodLookupPropertyName,
- new LookupMethodReplacer(definition, factory));
- return instance;
- }
-
- private Type GetGeneratedType(string objectName, RootObjectDefinition definition)
- {
- lock (typeCache.SyncRoot)
- {
- Type generatedType = (Type) typeCache[objectName];
- if (generatedType == null)
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(CultureInfo.InvariantCulture,
- "Generating a subclass of the [{0}] class for the '{1}' " +
- "object definition for the purposes of method injection.",
- definition.ObjectType, objectName));
- }
-
- #endregion
-
- ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(DYNAMIC_ASSEMBLY_NAME);
- generatedType = new MethodInjectingTypeBuilder(module, definition).BuildType();
- typeCache[objectName] = generatedType;
- }
- return generatedType;
- }
- }
-
- #region Inner Class : MethodInjectingTypeBuilder
-
- ///
- /// A factory that generates subclasses of those
- /// classes that have been configured for the Method-Injection form of
- /// Dependency Injection.
- ///
- ///
- ///
- /// This class is designed as for one-shot usage; i.e. it must
- /// be used to generate exactly one method injected subclass and
- /// then discarded (it maintains state in instance fields).
- ///
- ///
- private sealed class MethodInjectingTypeBuilder
- {
- ///
- /// The name of the generated
- /// property (for method replacement).
- ///
- ///
- ///
- /// Exists so that clients of this class can use this name to set properties reflectively
- /// on the dynamically generated subclass.
- ///
- ///
- internal const string MethodReplacementPropertyName = "MethodReplacement";
-
- ///
- /// The name of the generated
- /// property (for method lookup).
- ///
- ///
- ///
- /// Exists so that clients of this class can use this name to set properties reflectively
- /// on the dynamically generated subclass.
- ///
- ///
- internal const string MethodLookupPropertyName = "MethodLookup";
-
- private RootObjectDefinition objectDefinition;
- private FieldBuilder methodReplacementField;
- private FieldBuilder methodLookupField;
- private ModuleBuilder module;
-
- private readonly MethodInfo MethodReplacerImplementMethod
- = typeof (IMethodReplacer).GetMethod("Implement", new Type[] {typeof (object), typeof (MethodInfo), typeof (object[])});
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The in which
- /// the generated is to be defined.
- ///
- ///
- /// The object definition that is the target of the method injection.
- ///
- ///
- /// If either of the supplied arguments is .
- ///
- public MethodInjectingTypeBuilder(ModuleBuilder module, RootObjectDefinition objectDefinition)
- {
- AssertUtils.ArgumentNotNull(module, "module");
- AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
- this.module = module;
- this.objectDefinition = objectDefinition;
- }
-
- ///
- /// Builds a suitable for Method-Injection.
- ///
- ///
- /// A suitable for Method-Injection.
- ///
- public Type BuildType()
- {
- TypeBuilder typeBuilder = DefineType();
- DefineFields(typeBuilder);
- DefineConstructors(typeBuilder);
- DefineProperties(typeBuilder);
- DefineMethods(typeBuilder);
- return typeBuilder.CreateType();
- }
-
- private Type BaseType
- {
- get { return this.objectDefinition.ObjectType; }
- }
-
- private TypeBuilder DefineProperties(TypeBuilder typeBuilder)
- {
- DefineWritePropertyForMethodReplacement(typeBuilder, MethodReplacementPropertyName, this.methodReplacementField);
- DefineWritePropertyForMethodReplacement(typeBuilder, MethodLookupPropertyName, this.methodLookupField);
- return typeBuilder;
- }
-
- private TypeBuilder DefineType()
- {
- // Generates unique type name
- string generatedSubclassName = String.Format("{0}_{1}",
- BaseType.FullName, Guid.NewGuid().ToString("N"));
- return this.module.DefineType(
- generatedSubclassName, TypeAttributes.BeforeFieldInit | TypeAttributes.Public, BaseType);
- }
-
- private TypeBuilder DefineFields(TypeBuilder typeBuilder)
- {
- methodReplacementField = typeBuilder.DefineField("methodReplacement", typeof (IMethodReplacer), FieldAttributes.Private);
- methodLookupField = typeBuilder.DefineField("methodLookup", typeof (IMethodReplacer), FieldAttributes.Private);
- return typeBuilder;
- }
-
- private TypeBuilder DefineConstructors(TypeBuilder typeBuilder)
- {
- ConstructorInfo[] constructors = BaseType.GetConstructors(
- BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- for (int i = 0; i < constructors.Length; ++i)
- {
- ConstructorInfo constructor = constructors[i];
- if (constructor.IsPublic || constructor.IsFamily)
- {
- MethodAttributes attributes = MethodAttributes.Public |
- MethodAttributes.HideBySig | MethodAttributes.SpecialName |
- MethodAttributes.RTSpecialName;
- ConstructorBuilder cb = typeBuilder.DefineConstructor(attributes,
- constructor.CallingConvention,
- ReflectionUtils.GetParameterTypes(constructor.GetParameters()));
- ILGenerator il = cb.GetILGenerator();
- int paramCount = constructor.GetParameters().Length;
- il.Emit(OpCodes.Ldarg_0);
- for (int j = 1; j <= paramCount; ++j)
- {
- il.Emit(OpCodes.Ldarg_S, j);
- }
- il.Emit(OpCodes.Call, constructor);
- il.Emit(OpCodes.Ret);
- }
- }
- return typeBuilder;
- }
-
- ///
- /// Defines overrides for those methods that are configured with an appropriate
- /// .
- ///
- ///
- /// The overarching that is defining
- /// the generated .
- ///
- private TypeBuilder DefineMethods(TypeBuilder typeBuilder)
- {
- MethodInfo[] methods = BaseType.GetMethods(
- BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
- for (int i = 0; i < methods.Length; ++i)
- {
- MethodInfo method = methods[i];
- MethodOverride methodOverride
- = this.objectDefinition.MethodOverrides.GetOverride(method);
- if (methodOverride != null)
- {
- if (!method.IsVirtual || method.IsFinal)
- {
- throw new ObjectCreationException(
- "A replaced method must be marked as either abstract or virtual.");
- }
- FieldBuilder field = null;
- if (methodOverride is ReplacedMethodOverride)
- {
- field = this.methodReplacementField;
- }
- else
- {
- // lookup methods cannot have any arguments...
- if (method.GetParameters().Length > 0)
- {
- throw new ObjectCreationException(
- "The signature of a lookup method cannot have any arguments.");
- }
- // lookup methods cannot return void...
- if (method.ReturnType == typeof (void))
- {
- throw new ObjectCreationException(
- "A lookup method cannot be declared with a void return type.");
- }
- field = this.methodLookupField;
- }
- DefineReplacedMethod(typeBuilder, method, field);
- }
- }
- return typeBuilder;
- }
-
- ///
- /// Override the supplied with the logic
- /// encapsulated by the
- ///
- /// defined by the supplied .
- ///
- ///
- /// The builder for the subclass that is being generated.
- ///
- ///
- /// The method on the superclass that is to be overridden.
- ///
- ///
- /// The field defining the
- ///
- /// that the overridden method will delegate to to do the 'actual'
- /// method injection logic.
- ///
- private void DefineReplacedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder field)
- {
- ParameterInfo[] methodParameters = method.GetParameters();
- MethodBuilder methodBuilder
- = typeBuilder.DefineMethod(method.Name,
- CalculateMethodAttributes(method),
- method.CallingConvention,
- method.ReturnType,
- ReflectionUtils.GetParameterTypes(methodParameters));
- DefineOverrideMethodParameters(methodParameters, methodBuilder);
- ILGenerator il = methodBuilder.GetILGenerator();
- LocalBuilder returnValue = DefineReturnValueIfAny(method, il);
- // prepare the invocation of the 'Implement' method for the 'field' (an IMethodReplacer)...
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldfld, field);
- PushArguments(methodParameters, il);
- // invoke the 'Implement' method of the IMethodReplacer in the 'field'...
- il.Emit(OpCodes.Callvirt, MethodReplacerImplementMethod);
- SetupTheReturnValueIfAny(returnValue, il);
- il.Emit(OpCodes.Ret);
- }
-
- ///
- /// Defines the parameters to the method that is being overridden.
- ///
- ///
- ///
- /// Since we are simply overridding a method (in this method
- /// injection context), all we do here is simply copy the
- /// parameters (since we want a method with the exact same parameters).
- ///
+ /// Classes that want to take advantage of method injection must meet some
+ /// stringent criteria. Every method that is to be method injected
+ /// must be defined as either or
+ /// . An
+ /// will be thrown if these criteria are not met.
+ ///
+ ///
+ /// Rick Evans
+ [Serializable]
+ public class MethodInjectingInstantiationStrategy : SimpleInstantiationStrategy
+ {
+ ///
+ /// The name of the dynamic assembly that holds dynamically created code
+ ///
+ private const string DYNAMIC_ASSEMBLY_NAME = "Spring.MethodInjected";
+
+ ///
+ /// A cache of generated instances, keyed on
+ /// the object name for which the was generated.
+ ///
+ private IDictionary typeCache = new Hashtable();
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied ,
+ /// injecting methods as appropriate.
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the
+ /// or zero length string if we're autowiring an
+ /// object that doesn't belong to the supplied
+ /// .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ ///
+ protected override object InstantiateWithMethodInjection(
+ RootObjectDefinition definition, string objectName, IObjectFactory factory)
+ {
+ return DoInstantiate(definition, objectName, factory, Type.EmptyTypes, ObjectUtils.EmptyObjects);
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied ,
+ /// injecting methods as appropriate.
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the
+ /// or zero length string if we're autowiring an
+ /// object that doesn't belong to the supplied
+ /// .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// The to be used to instantiate
+ /// the object.
+ ///
+ ///
+ /// Any arguments to the supplied . May be null.
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ ///
+ protected override object InstantiateWithMethodInjection(
+ RootObjectDefinition definition, string objectName, IObjectFactory factory, ConstructorInfo constructor, object[] arguments)
+ {
+ return DoInstantiate(definition, objectName, factory, ReflectionUtils.GetParameterTypes(constructor), arguments);
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied ,
+ /// injecting methods as appropriate.
+ ///
+ ///
+ ///
+ /// This method dynamically generates a subclass that supports method
+ /// injection for the supplied . It then
+ /// instantiates an new instance of said type using the constructor
+ /// identified by the supplied ,
+ /// passing the supplied to said
+ /// constructor. It then manually injects (generic) method replacement
+ /// and method lookup instances (of
+ /// ) into
+ /// the new instance: those methods that are 'method-injected' will
+ /// then delegate to the approriate
+ ///
+ /// instance to effect the actual method injection.
+ ///
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the
+ /// or zero length string if we're autowiring an
+ /// object that doesn't belong to the supplied
+ /// .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// The parameter s to use to find the
+ /// appropriate constructor to invoke.
+ ///
+ ///
+ /// The aguments that are to be passed to the appropriate constructor
+ /// when the object is being instantiated.
+ ///
+ ///
+ /// A new instance of the defined by the
+ /// supplied .
+ ///
+ private object DoInstantiate(
+ RootObjectDefinition definition, string objectName, IObjectFactory factory, Type[] ctorParameterTypes, object[] arguments)
+ {
+ Type type = GetGeneratedType(objectName, definition);
+ object instance = type.GetConstructor(ctorParameterTypes).Invoke(arguments);
+ IObjectWrapper wrapper = new ObjectWrapper(instance);
+ wrapper.SetPropertyValue(
+ MethodInjectingTypeBuilder.MethodReplacementPropertyName,
+ new DelegatingMethodReplacer(definition, factory));
+ wrapper.SetPropertyValue(
+ MethodInjectingTypeBuilder.MethodLookupPropertyName,
+ new LookupMethodReplacer(definition, factory));
+ return instance;
+ }
+
+ private Type GetGeneratedType(string objectName, RootObjectDefinition definition)
+ {
+ lock (typeCache.SyncRoot)
+ {
+ Type generatedType = (Type) typeCache[objectName];
+ if (generatedType == null)
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(CultureInfo.InvariantCulture,
+ "Generating a subclass of the [{0}] class for the '{1}' " +
+ "object definition for the purposes of method injection.",
+ definition.ObjectType, objectName));
+ }
+
+ #endregion
+
+ ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(DYNAMIC_ASSEMBLY_NAME);
+ generatedType = new MethodInjectingTypeBuilder(module, definition).BuildType();
+ typeCache[objectName] = generatedType;
+ }
+ return generatedType;
+ }
+ }
+
+ #region Inner Class : MethodInjectingTypeBuilder
+
+ ///
+ /// A factory that generates subclasses of those
+ /// classes that have been configured for the Method-Injection form of
+ /// Dependency Injection.
+ ///
+ ///
+ ///
+ /// This class is designed as for one-shot usage; i.e. it must
+ /// be used to generate exactly one method injected subclass and
+ /// then discarded (it maintains state in instance fields).
+ ///
+ ///
+ private sealed class MethodInjectingTypeBuilder
+ {
+ ///
+ /// The name of the generated
+ /// property (for method replacement).
+ ///
+ ///
+ ///
+ /// Exists so that clients of this class can use this name to set properties reflectively
+ /// on the dynamically generated subclass.
+ ///
+ ///
+ internal const string MethodReplacementPropertyName = "MethodReplacement";
+
+ ///
+ /// The name of the generated
+ /// property (for method lookup).
+ ///
+ ///
+ ///
+ /// Exists so that clients of this class can use this name to set properties reflectively
+ /// on the dynamically generated subclass.
+ ///
+ ///
+ internal const string MethodLookupPropertyName = "MethodLookup";
+
+ private RootObjectDefinition objectDefinition;
+ private FieldBuilder methodReplacementField;
+ private FieldBuilder methodLookupField;
+ private ModuleBuilder module;
+
+ private readonly MethodInfo MethodReplacerImplementMethod
+ = typeof (IMethodReplacer).GetMethod("Implement", new Type[] {typeof (object), typeof (MethodInfo), typeof (object[])});
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The in which
+ /// the generated is to be defined.
+ ///
+ ///
+ /// The object definition that is the target of the method injection.
+ ///
+ ///
+ /// If either of the supplied arguments is .
+ ///
+ public MethodInjectingTypeBuilder(ModuleBuilder module, RootObjectDefinition objectDefinition)
+ {
+ AssertUtils.ArgumentNotNull(module, "module");
+ AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
+ this.module = module;
+ this.objectDefinition = objectDefinition;
+ }
+
+ ///
+ /// Builds a suitable for Method-Injection.
+ ///
+ ///
+ /// A suitable for Method-Injection.
+ ///
+ public Type BuildType()
+ {
+ TypeBuilder typeBuilder = DefineType();
+ DefineFields(typeBuilder);
+ DefineConstructors(typeBuilder);
+ DefineProperties(typeBuilder);
+ DefineMethods(typeBuilder);
+ return typeBuilder.CreateType();
+ }
+
+ private Type BaseType
+ {
+ get { return this.objectDefinition.ObjectType; }
+ }
+
+ private TypeBuilder DefineProperties(TypeBuilder typeBuilder)
+ {
+ DefineWritePropertyForMethodReplacement(typeBuilder, MethodReplacementPropertyName, this.methodReplacementField);
+ DefineWritePropertyForMethodReplacement(typeBuilder, MethodLookupPropertyName, this.methodLookupField);
+ return typeBuilder;
+ }
+
+ private TypeBuilder DefineType()
+ {
+ // Generates unique type name
+ string generatedSubclassName = String.Format("{0}_{1}",
+ BaseType.FullName, Guid.NewGuid().ToString("N"));
+ return this.module.DefineType(
+ generatedSubclassName, TypeAttributes.BeforeFieldInit | TypeAttributes.Public, BaseType);
+ }
+
+ private TypeBuilder DefineFields(TypeBuilder typeBuilder)
+ {
+ methodReplacementField = typeBuilder.DefineField("methodReplacement", typeof (IMethodReplacer), FieldAttributes.Private);
+ methodLookupField = typeBuilder.DefineField("methodLookup", typeof (IMethodReplacer), FieldAttributes.Private);
+ return typeBuilder;
+ }
+
+ private TypeBuilder DefineConstructors(TypeBuilder typeBuilder)
+ {
+ ConstructorInfo[] constructors = BaseType.GetConstructors(
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ for (int i = 0; i < constructors.Length; ++i)
+ {
+ ConstructorInfo constructor = constructors[i];
+ if (constructor.IsPublic || constructor.IsFamily)
+ {
+ MethodAttributes attributes = MethodAttributes.Public |
+ MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.RTSpecialName;
+ ConstructorBuilder cb = typeBuilder.DefineConstructor(attributes,
+ constructor.CallingConvention,
+ ReflectionUtils.GetParameterTypes(constructor.GetParameters()));
+ ILGenerator il = cb.GetILGenerator();
+ int paramCount = constructor.GetParameters().Length;
+ il.Emit(OpCodes.Ldarg_0);
+ for (int j = 1; j <= paramCount; ++j)
+ {
+ il.Emit(OpCodes.Ldarg_S, j);
+ }
+ il.Emit(OpCodes.Call, constructor);
+ il.Emit(OpCodes.Ret);
+ }
+ }
+ return typeBuilder;
+ }
+
+ ///
+ /// Defines overrides for those methods that are configured with an appropriate
+ /// .
+ ///
+ ///
+ /// The overarching that is defining
+ /// the generated .
+ ///
+ private TypeBuilder DefineMethods(TypeBuilder typeBuilder)
+ {
+ MethodInfo[] methods = BaseType.GetMethods(
+ BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
+ for (int i = 0; i < methods.Length; ++i)
+ {
+ MethodInfo method = methods[i];
+ MethodOverride methodOverride
+ = this.objectDefinition.MethodOverrides.GetOverride(method);
+ if (methodOverride != null)
+ {
+ if (!method.IsVirtual || method.IsFinal)
+ {
+ throw new ObjectCreationException(
+ "A replaced method must be marked as either abstract or virtual.");
+ }
+ FieldBuilder field = null;
+ if (methodOverride is ReplacedMethodOverride)
+ {
+ field = this.methodReplacementField;
+ }
+ else
+ {
+ // lookup methods cannot have any arguments...
+ if (method.GetParameters().Length > 0)
+ {
+ throw new ObjectCreationException(
+ "The signature of a lookup method cannot have any arguments.");
+ }
+ // lookup methods cannot return void...
+ if (method.ReturnType == typeof (void))
+ {
+ throw new ObjectCreationException(
+ "A lookup method cannot be declared with a void return type.");
+ }
+ field = this.methodLookupField;
+ }
+ DefineReplacedMethod(typeBuilder, method, field);
+ }
+ }
+ return typeBuilder;
+ }
+
+ ///
+ /// Override the supplied with the logic
+ /// encapsulated by the
+ ///
+ /// defined by the supplied .
+ ///
+ ///
+ /// The builder for the subclass that is being generated.
+ ///
+ ///
+ /// The method on the superclass that is to be overridden.
+ ///
+ ///
+ /// The field defining the
+ ///
+ /// that the overridden method will delegate to to do the 'actual'
+ /// method injection logic.
+ ///
+ private void DefineReplacedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder field)
+ {
+ ParameterInfo[] methodParameters = method.GetParameters();
+ MethodBuilder methodBuilder
+ = typeBuilder.DefineMethod(method.Name,
+ CalculateMethodAttributes(method),
+ method.CallingConvention,
+ method.ReturnType,
+ ReflectionUtils.GetParameterTypes(methodParameters));
+ DefineOverrideMethodParameters(methodParameters, methodBuilder);
+ ILGenerator il = methodBuilder.GetILGenerator();
+ LocalBuilder returnValue = DefineReturnValueIfAny(method, il);
+ // prepare the invocation of the 'Implement' method for the 'field' (an IMethodReplacer)...
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldfld, field);
+ PushArguments(methodParameters, il);
+ // invoke the 'Implement' method of the IMethodReplacer in the 'field'...
+ il.Emit(OpCodes.Callvirt, MethodReplacerImplementMethod);
+ SetupTheReturnValueIfAny(returnValue, il);
+ il.Emit(OpCodes.Ret);
+ }
+
+ ///
+ /// Defines the parameters to the method that is being overridden.
+ ///
+ ///
+ ///
+ /// Since we are simply overridding a method (in this method
+ /// injection context), all we do here is simply copy the
+ /// parameters (since we want a method with the exact same parameters).
+ ///
- /// Note that the override mechanism is not intended as a generic means of
- /// inserting crosscutting code: use AOP for that.
- ///
- ///
- /// Rod Johnson
- /// Rick Evans (.NET)
- /// $Id: MethodOverride.cs,v 1.9 2007/08/22 08:52:03 markpollack Exp $
- [Serializable]
- public abstract class MethodOverride
- {
- private readonly string methodName;
- private bool isOverloaded = true;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is an class, and as such exposes no
- /// public constructors.
- ///
- ///
- ///
- /// The name of the method that is to be overridden.
- ///
- ///
- /// If the supplied is or
- /// contains only whitespace character(s).
- ///
- protected MethodOverride(string methodName)
- {
- AssertUtils.ArgumentHasText(methodName, "methodName");
- this.methodName = methodName.Trim();
- }
-
- ///
- /// The name of the method that is to be overridden.
- ///
- public string MethodName
- {
- get { return methodName; }
- }
-
- ///
- /// Is the method that is ot be injected
- /// ()
- /// to be considered as overloaded?
- ///
- ///
- ///
- /// If (the default), then argument type matching
- /// will be performed (because one would not want to override the wrong
- /// method).
- ///
- ///
- /// Setting the value of this property to can be used
- /// to optimize runtime performance (ever so slightly).
- ///
- ///
- public bool IsOverloaded
- {
- get { return isOverloaded; }
- set { isOverloaded = value; }
- }
-
- ///
- /// Does this
- /// match the supplied ?
- ///
- ///
- ///
- /// By 'match' one means does this particular
- ///
- /// instance apply to the supplied ?
- ///
- ///
- /// This allows for argument list checking as well as method name checking.
- ///
+ /// Note that the override mechanism is not intended as a generic means of
+ /// inserting crosscutting code: use AOP for that.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rick Evans (.NET)
+ [Serializable]
+ public abstract class MethodOverride
+ {
+ private readonly string methodName;
+ private bool isOverloaded = true;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no
+ /// public constructors.
+ ///
+ ///
+ ///
+ /// The name of the method that is to be overridden.
+ ///
+ ///
+ /// If the supplied is or
+ /// contains only whitespace character(s).
+ ///
+ protected MethodOverride(string methodName)
+ {
+ AssertUtils.ArgumentHasText(methodName, "methodName");
+ this.methodName = methodName.Trim();
+ }
+
+ ///
+ /// The name of the method that is to be overridden.
+ ///
+ public string MethodName
+ {
+ get { return methodName; }
+ }
+
+ ///
+ /// Is the method that is ot be injected
+ /// ()
+ /// to be considered as overloaded?
+ ///
+ ///
+ ///
+ /// If (the default), then argument type matching
+ /// will be performed (because one would not want to override the wrong
+ /// method).
+ ///
+ ///
+ /// Setting the value of this property to can be used
+ /// to optimize runtime performance (ever so slightly).
+ ///
+ ///
+ public bool IsOverloaded
+ {
+ get { return isOverloaded; }
+ set { isOverloaded = value; }
+ }
+
+ ///
+ /// Does this
+ /// match the supplied ?
+ ///
+ ///
+ ///
+ /// By 'match' one means does this particular
+ ///
+ /// instance apply to the supplied ?
+ ///
+ ///
+ /// This allows for argument list checking as well as method name checking.
+ ///
- ///
- ///
- /// The instance supplying initial overrides for this new instance.
- ///
- public MethodOverrides(MethodOverrides other)
- {
- AddAll(other);
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The collection of method overrides.
- ///
- public ISet Overrides
- {
- get { return _overrides; }
- }
-
- ///
- /// Returns true if this instance contains no overrides.
- ///
- public bool IsEmpty
- {
- get { return Overrides.IsEmpty; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Copy all given method overrides into this object.
- ///
- ///
- /// The overrides to be copied into this object.
- ///
- public void AddAll(MethodOverrides other)
- {
- if (other != null)
- {
- Overrides.AddAll(other.Overrides);
- _overloadedMethodNames.AddAll(other._overloadedMethodNames);
- }
- }
-
- ///
- /// Adds the supplied to the overrides contained
- /// within this instance.
- ///
- ///
- /// The to be
- /// added.
- ///
- public void Add(MethodOverride theOverride)
- {
- Overrides.Add(theOverride);
- }
-
- ///
- /// Adds the supplied to the overloaded method names
- /// contained within this instance.
- ///
- ///
- /// The overloaded method name to be added.
- ///
- public void AddOverloadedMethodName(string methodName)
- {
- _overloadedMethodNames.Add(methodName);
- }
-
- ///
- /// Returns true if the supplied is present within
- /// the overloaded method names contained within this instance.
- ///
- ///
- /// The overloaded method name to be checked.
- ///
- ///
- /// True if the supplied is present within
- /// the overloaded method names contained within this instance.
- ///
- public bool IsOverloadedMethodName(string methodName)
- {
- return _overloadedMethodNames.Contains(methodName);
- }
-
- ///
- /// Return the override for the given method, if any.
- ///
- ///
- /// The method to check for overrides for.
- ///
- ///
- /// the override for the given method, if any.
- ///
- public MethodOverride GetOverride(MethodInfo method)
- {
- foreach (MethodOverride ovr in Overrides)
- {
- if (ovr.Matches(method))
- {
- return ovr;
- }
- }
- return null;
- }
-
- ///
- /// Returns an that can iterate
- /// through a collection.
- ///
- ///
- ///
- /// The returned is the
- /// exposed by the
- ///
- /// property.
- ///
+ ///
+ ///
+ /// The instance supplying initial overrides for this new instance.
+ ///
+ public MethodOverrides(MethodOverrides other)
+ {
+ AddAll(other);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The collection of method overrides.
+ ///
+ public ISet Overrides
+ {
+ get { return _overrides; }
+ }
+
+ ///
+ /// Returns true if this instance contains no overrides.
+ ///
+ public bool IsEmpty
+ {
+ get { return Overrides.IsEmpty; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Copy all given method overrides into this object.
+ ///
+ ///
+ /// The overrides to be copied into this object.
+ ///
+ public void AddAll(MethodOverrides other)
+ {
+ if (other != null)
+ {
+ Overrides.AddAll(other.Overrides);
+ _overloadedMethodNames.AddAll(other._overloadedMethodNames);
+ }
+ }
+
+ ///
+ /// Adds the supplied to the overrides contained
+ /// within this instance.
+ ///
+ ///
+ /// The to be
+ /// added.
+ ///
+ public void Add(MethodOverride theOverride)
+ {
+ Overrides.Add(theOverride);
+ }
+
+ ///
+ /// Adds the supplied to the overloaded method names
+ /// contained within this instance.
+ ///
+ ///
+ /// The overloaded method name to be added.
+ ///
+ public void AddOverloadedMethodName(string methodName)
+ {
+ _overloadedMethodNames.Add(methodName);
+ }
+
+ ///
+ /// Returns true if the supplied is present within
+ /// the overloaded method names contained within this instance.
+ ///
+ ///
+ /// The overloaded method name to be checked.
+ ///
+ ///
+ /// True if the supplied is present within
+ /// the overloaded method names contained within this instance.
+ ///
+ public bool IsOverloadedMethodName(string methodName)
+ {
+ return _overloadedMethodNames.Contains(methodName);
+ }
+
+ ///
+ /// Return the override for the given method, if any.
+ ///
+ ///
+ /// The method to check for overrides for.
+ ///
+ ///
+ /// the override for the given method, if any.
+ ///
+ public MethodOverride GetOverride(MethodInfo method)
+ {
+ foreach (MethodOverride ovr in Overrides)
+ {
+ if (ovr.Matches(method))
+ {
+ return ovr;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Returns an that can iterate
+ /// through a collection.
+ ///
+ ///
+ ///
+ /// The returned is the
+ /// exposed by the
+ ///
+ /// property.
+ ///
- /// If a name or parent object definition
- /// name is not unique, "#1", "#2" etc will be appended, until such
- /// time that the name becomes unique.
- ///
- ///
- public const string GeneratedObjectIdSeparator = "#";
-
- ///
- /// Registers the supplied with the
- /// supplied .
- ///
- ///
- ///
- /// This is a convenience method that registers the
- ///
- /// of the supplied under the
- ///
- /// property value of said . If the
- /// supplied has any
- /// ,
- /// then those aliases will also be registered with the supplied
- /// .
- ///
- ///
- ///
- /// The object definition holder containing the
- /// that
- /// is to be registered.
- ///
- ///
- /// The registry that the supplied
- /// is to be registered with.
- ///
- ///
- /// If either of the supplied arguments is .
- ///
- ///
- /// If the could not be registered
- /// with the .
- ///
- public static void RegisterObjectDefinition(
- ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry)
- {
- AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
- AssertUtils.ArgumentNotNull(registry, "registry");
-
- registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition);
- string[] aliases = objectDefinition.Aliases;
- for (int i = 0; i < aliases.Length; ++i)
- {
- string alias = aliases[i];
- registry.RegisterAlias(objectDefinition.ObjectName, alias);
- }
- }
-
- ///
- /// Generates an object definition name for the supplied
- /// that is guaranteed to be unique
- /// within the scope of the supplied .
- ///
- ///
- /// The
- /// that requires a generated name.
- ///
- ///
- /// The
- ///
- /// that the supplied is to be
- /// registered with (needed so that the uniqueness of any generated
- /// name can be guaranteed).
- ///
- ///
- /// An object definition name for the supplied
- /// that is guaranteed to be unique
- /// within the scope of the supplied and
- /// never .
- ///
- ///
- /// If either of the or
- /// arguments is .
- ///
- ///
- /// If a unique name cannot be generated.
- ///
- public static string GenerateObjectName(
- IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry)
- {
- AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
- AssertUtils.ArgumentNotNull(registry, "registry");
-
- string starterName = objectDefinition.ObjectTypeName;
- if (StringUtils.IsNullOrEmpty(starterName))
- {
- if (objectDefinition is ChildObjectDefinition)
- {
- starterName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child";
- }
- else if (objectDefinition.FactoryObjectName != null)
- {
- starterName = objectDefinition.FactoryObjectName + "$created";
- }
- }
- if (StringUtils.IsNullOrEmpty(starterName))
- {
- throw new ObjectDefinitionStoreException(
- objectDefinition.ResourceDescription, String.Empty,
- "Unnamed object definition specifies neither 'Type' nor 'Parent' " +
- "nor 'FactoryObject' property values so a unique name cannot be generated.");
- }
- String generatedName = starterName;
- int counter = 0;
- while (registry.ContainsObjectDefinition(generatedName))
- {
- generatedName = new StringBuilder(starterName)
- .Append(GeneratedObjectIdSeparator).Append(++counter).ToString();
- }
- return generatedName;
- }
-
- ///
- /// Factory method for getting concrete
- /// instances.
- ///
- ///
- /// The name of the event handler method. This may be straight text, a regular
- /// expression, , or empty.
- ///
- ///
- /// The name of the event being wired. This too may be straight text, a regular
- /// expression, , or empty.
- ///
- ///
- /// A concrete
- /// instance.
- ///
- public static IEventHandlerValue CreateEventHandlerValue(
- string methodName, string eventName)
- {
- bool weAreAutowiring = false;
- if (StringUtils.HasText(eventName))
- {
- // does the value contain regular expression characters? mmm, totally trent...
- if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+"))
- {
- // wildcarded event name
- weAreAutowiring = true;
- }
- }
- else
- {
- // we're definitely autowiring based on the event name
- weAreAutowiring = true;
- }
- if (!weAreAutowiring)
- {
- if (StringUtils.HasText(methodName))
- {
- // does the value contain the string ${event}?
- if (methodName.IndexOf("${event}") >= 0)
- {
- // wildcarded method name
- weAreAutowiring = true;
- }
- }
- else
- {
- // we're definitely autowiring based on the method name
- weAreAutowiring = true;
- }
- }
- IEventHandlerValue myHandler;
- if (weAreAutowiring)
- {
- myHandler = new AutoWiringEventHandlerValue();
- }
- else
- {
- myHandler = new InstanceEventHandlerValue();
- }
- myHandler.EventName = eventName;
- myHandler.MethodName = methodName;
- return myHandler;
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
+ /// If a name or parent object definition
+ /// name is not unique, "#1", "#2" etc will be appended, until such
+ /// time that the name becomes unique.
+ ///
+ ///
+ public const string GeneratedObjectIdSeparator = "#";
+
+ ///
+ /// Registers the supplied with the
+ /// supplied .
+ ///
+ ///
+ ///
+ /// This is a convenience method that registers the
+ ///
+ /// of the supplied under the
+ ///
+ /// property value of said . If the
+ /// supplied has any
+ /// ,
+ /// then those aliases will also be registered with the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// The object definition holder containing the
+ /// that
+ /// is to be registered.
+ ///
+ ///
+ /// The registry that the supplied
+ /// is to be registered with.
+ ///
+ ///
+ /// If either of the supplied arguments is .
+ ///
+ ///
+ /// If the could not be registered
+ /// with the .
+ ///
+ public static void RegisterObjectDefinition(
+ ObjectDefinitionHolder objectDefinition, IObjectDefinitionRegistry registry)
+ {
+ AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
+ AssertUtils.ArgumentNotNull(registry, "registry");
+
+ registry.RegisterObjectDefinition(objectDefinition.ObjectName, objectDefinition.ObjectDefinition);
+ string[] aliases = objectDefinition.Aliases;
+ for (int i = 0; i < aliases.Length; ++i)
+ {
+ string alias = aliases[i];
+ registry.RegisterAlias(objectDefinition.ObjectName, alias);
+ }
+ }
+
+ ///
+ /// Generates an object definition name for the supplied
+ /// that is guaranteed to be unique
+ /// within the scope of the supplied .
+ ///
+ ///
+ /// The
+ /// that requires a generated name.
+ ///
+ ///
+ /// The
+ ///
+ /// that the supplied is to be
+ /// registered with (needed so that the uniqueness of any generated
+ /// name can be guaranteed).
+ ///
+ ///
+ /// An object definition name for the supplied
+ /// that is guaranteed to be unique
+ /// within the scope of the supplied and
+ /// never .
+ ///
+ ///
+ /// If either of the or
+ /// arguments is .
+ ///
+ ///
+ /// If a unique name cannot be generated.
+ ///
+ public static string GenerateObjectName(
+ IConfigurableObjectDefinition objectDefinition, IObjectDefinitionRegistry registry)
+ {
+ AssertUtils.ArgumentNotNull(objectDefinition, "objectDefinition");
+ AssertUtils.ArgumentNotNull(registry, "registry");
+
+ string starterName = objectDefinition.ObjectTypeName;
+ if (StringUtils.IsNullOrEmpty(starterName))
+ {
+ if (objectDefinition is ChildObjectDefinition)
+ {
+ starterName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child";
+ }
+ else if (objectDefinition.FactoryObjectName != null)
+ {
+ starterName = objectDefinition.FactoryObjectName + "$created";
+ }
+ }
+ if (StringUtils.IsNullOrEmpty(starterName))
+ {
+ throw new ObjectDefinitionStoreException(
+ objectDefinition.ResourceDescription, String.Empty,
+ "Unnamed object definition specifies neither 'Type' nor 'Parent' " +
+ "nor 'FactoryObject' property values so a unique name cannot be generated.");
+ }
+ String generatedName = starterName;
+ int counter = 0;
+ while (registry.ContainsObjectDefinition(generatedName))
+ {
+ generatedName = new StringBuilder(starterName)
+ .Append(GeneratedObjectIdSeparator).Append(++counter).ToString();
+ }
+ return generatedName;
+ }
+
+ ///
+ /// Factory method for getting concrete
+ /// instances.
+ ///
+ ///
+ /// The name of the event handler method. This may be straight text, a regular
+ /// expression, , or empty.
+ ///
+ ///
+ /// The name of the event being wired. This too may be straight text, a regular
+ /// expression, , or empty.
+ ///
+ ///
+ /// A concrete
+ /// instance.
+ ///
+ public static IEventHandlerValue CreateEventHandlerValue(
+ string methodName, string eventName)
+ {
+ bool weAreAutowiring = false;
+ if (StringUtils.HasText(eventName))
+ {
+ // does the value contain regular expression characters? mmm, totally trent...
+ if (Regex.IsMatch(eventName, @"[\*\.\[\]\{\},\(\)\$\^\+]+"))
+ {
+ // wildcarded event name
+ weAreAutowiring = true;
+ }
+ }
+ else
+ {
+ // we're definitely autowiring based on the event name
+ weAreAutowiring = true;
+ }
+ if (!weAreAutowiring)
+ {
+ if (StringUtils.HasText(methodName))
+ {
+ // does the value contain the string ${event}?
+ if (methodName.IndexOf("${event}") >= 0)
+ {
+ // wildcarded method name
+ weAreAutowiring = true;
+ }
+ }
+ else
+ {
+ // we're definitely autowiring based on the method name
+ weAreAutowiring = true;
+ }
+ }
+ IEventHandlerValue myHandler;
+ if (weAreAutowiring)
+ {
+ myHandler = new AutoWiringEventHandlerValue();
+ }
+ else
+ {
+ myHandler = new InstanceEventHandlerValue();
+ }
+ myHandler.EventName = eventName;
+ myHandler.MethodName = methodName;
+ return myHandler;
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
- ///
- public const string SingletonKey = "(singleton)";
-
- ///
- /// Special string added to distinguish if the object will be
- /// lazily initialised.
- ///
- ///
- ///
- /// Default is false.
- ///
- ///
- ///
- ///
- /// owner.(lazy-init)=true
- ///
- ///
- public const string LazyInitKey = "(lazy-init)";
-
- ///
- /// Reserved "property" to indicate the parent of a child object definition.
- ///
- public const string ParentKey = "parent";
-
- ///
- /// Property suffix for references to other objects in the current
- /// : e.g.
- /// owner.dog(ref)=fido.
- ///
- ///
- ///
- /// Whether this is a reference to a singleton or a prototype
- /// will depend on the definition of the target object.
- ///
- ///
- public const string RefSuffix = "(ref)";
-
- ///
- /// Prefix before values referencing other objects.
- ///
- public const string RefPrefix = "*";
-
- private string _defaultParentObject = string.Empty;
-
- private IObjectDefinitionFactory _objectDefinitionFactory = new DefaultObjectDefinitionFactory();
-
- ///
- /// Name of default parent object
- ///
- public string DefaultParentObject
- {
- get { return _defaultParentObject; }
- set { this._defaultParentObject = value; }
- }
-
- ///
- /// Gets or sets object definition factory to use.
- ///
- public IObjectDefinitionFactory ObjectDefinitionFactory
- {
- get { return _objectDefinitionFactory; }
- set { _objectDefinitionFactory = value; }
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The
- /// instance that this reader works on.
- ///
- public PropertiesObjectDefinitionReader(IObjectDefinitionRegistry registry)
- : base(registry)
- {}
-
- ///
- /// Load object definitions from the supplied .
- ///
- ///
- /// The resource for the object definitions that are to be loaded.
- ///
- ///
- /// The number of object definitions that were loaded.
- ///
- ///
- /// In the case of loading or parsing errors.
- ///
- public override int LoadObjectDefinitions(IResource resource)
- {
- return LoadObjectDefinitions(resource, string.Empty);
- }
-
- ///
- /// Load object definitions from the specified properties file.
- ///
- ///
- /// The resource descriptor for the properties file.
- ///
- ///
- /// The match or filter for object definition names, e.g. 'objects.'
- ///
- /// in case of loading or parsing errors
- /// the number of object definitions found
- public int LoadObjectDefinitions(IResource resource, string prefix)
- {
- Properties props = new Properties();
- try
- {
- Stream str = resource.InputStream;
- try
- {
- props.Load(str);
- }
- finally
- {
- str.Close();
- }
- return RegisterObjectDefinitions(props, prefix, resource.Description);
- }
- catch (IOException ex)
- {
- throw new ObjectDefinitionStoreException("IOException parsing properties from " + resource, ex);
- }
- }
-
- ///
- /// Register object definitions contained in a
- /// , using all property keys (i.e.
- /// not filtering by prefix).
- ///
- ///
- /// The containing object definitions.
- ///
- ///
- /// In case of loading or parsing errors.
- ///
- /// The number of object definitions registered.
- public int RegisterObjectDefinitions(ResourceSet rs)
- {
- return RegisterObjectDefinitions(rs, string.Empty);
- }
-
- ///
- /// Register object definitions contained in a
- /// .
- ///
- ///
- ///
- /// Similar syntax as for an .
- /// This method is useful to enable standard .NET internationalization support.
- ///
- ///
- ///
- /// The containing object definitions.
- ///
- ///
- /// The match or filter for object definition names, e.g. 'objects.'
- ///
- ///
- /// In case of loading or parsing errors.
- ///
- /// The number of object definitions registered.
- public int RegisterObjectDefinitions(ResourceSet rs, string prefix)
- {
-#if ! NET_1_0
- // Simply create a map and call overloaded method
- IDictionary id = new Hashtable();
- foreach (DictionaryEntry de in rs)
- {
- id.Add(de.Key, de.Value);
- }
- return RegisterObjectDefinitions(id, prefix);
-#else
- throw new NotSupportedException("Operation not supported on NET 1.0");
-#endif
- }
-
- ///
- /// Register object definitions contained in an
- /// , using all property keys
- /// (i.e. not filtering by prefix).
- ///
- ///
- /// The containing object definitions.
- ///
- ///
- /// In case of loading or parsing errors.
- ///
- /// The number of object definitions registered.
- public int RegisterObjectDefinitions(IDictionary id)
- {
- return RegisterObjectDefinitions(id, string.Empty);
- }
-
- ///
- /// Registers object definitions contained in an
- /// using all property keys ( i.e. not filtering by prefix )
- ///
- /// The containing
- /// object definitions.
- ///
- ///
- /// In case of loading or parsing errors.
- ///
- /// The number of object definitions registered.
- public int RegisterObjectDefinitions(NameValueCollection nameValueCollection)
- {
- IDictionary id = new Hashtable();
- foreach (DictionaryEntry de in nameValueCollection)
- {
- id.Add(de.Key, de.Value);
- }
-
- return RegisterObjectDefinitions(id);
- }
-
- ///
- /// Register object definitions contained in a
- /// .
- ///
- ///
- ///
- /// Ignores ineligible properties.
- ///
- ///
- /// IDictionary name -> property (String or Object). Property values
- /// will be strings if coming from a Properties file etc. Property names
- /// (keys) must be strings. Type keys must be strings.
- ///
- ///
- /// The match or filter within the keys in the map: e.g. 'objects.'
- ///
- ///
- /// In case of loading or parsing errors.
- ///
- /// The number of object definitions found.
- public int RegisterObjectDefinitions(IDictionary id, string prefix)
- {
- return RegisterObjectDefinitions(id, prefix, "(no description)");
- }
-
- ///
- /// Register object definitions contained in a
- /// .
- ///
- ///
- ///
+ ///
+ public const string SingletonKey = "(singleton)";
+
+ ///
+ /// Special string added to distinguish if the object will be
+ /// lazily initialised.
+ ///
+ ///
+ ///
+ /// Default is false.
+ ///
+ ///
+ ///
+ ///
+ /// owner.(lazy-init)=true
+ ///
+ ///
+ public const string LazyInitKey = "(lazy-init)";
+
+ ///
+ /// Reserved "property" to indicate the parent of a child object definition.
+ ///
+ public const string ParentKey = "parent";
+
+ ///
+ /// Property suffix for references to other objects in the current
+ /// : e.g.
+ /// owner.dog(ref)=fido.
+ ///
+ ///
+ ///
+ /// Whether this is a reference to a singleton or a prototype
+ /// will depend on the definition of the target object.
+ ///
+ ///
+ public const string RefSuffix = "(ref)";
+
+ ///
+ /// Prefix before values referencing other objects.
+ ///
+ public const string RefPrefix = "*";
+
+ private string _defaultParentObject = string.Empty;
+
+ private IObjectDefinitionFactory _objectDefinitionFactory = new DefaultObjectDefinitionFactory();
+
+ ///
+ /// Name of default parent object
+ ///
+ public string DefaultParentObject
+ {
+ get { return _defaultParentObject; }
+ set { this._defaultParentObject = value; }
+ }
+
+ ///
+ /// Gets or sets object definition factory to use.
+ ///
+ public IObjectDefinitionFactory ObjectDefinitionFactory
+ {
+ get { return _objectDefinitionFactory; }
+ set { _objectDefinitionFactory = value; }
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The
+ /// instance that this reader works on.
+ ///
+ public PropertiesObjectDefinitionReader(IObjectDefinitionRegistry registry)
+ : base(registry)
+ {}
+
+ ///
+ /// Load object definitions from the supplied .
+ ///
+ ///
+ /// The resource for the object definitions that are to be loaded.
+ ///
+ ///
+ /// The number of object definitions that were loaded.
+ ///
+ ///
+ /// In the case of loading or parsing errors.
+ ///
+ public override int LoadObjectDefinitions(IResource resource)
+ {
+ return LoadObjectDefinitions(resource, string.Empty);
+ }
+
+ ///
+ /// Load object definitions from the specified properties file.
+ ///
+ ///
+ /// The resource descriptor for the properties file.
+ ///
+ ///
+ /// The match or filter for object definition names, e.g. 'objects.'
+ ///
+ /// in case of loading or parsing errors
+ /// the number of object definitions found
+ public int LoadObjectDefinitions(IResource resource, string prefix)
+ {
+ Properties props = new Properties();
+ try
+ {
+ Stream str = resource.InputStream;
+ try
+ {
+ props.Load(str);
+ }
+ finally
+ {
+ str.Close();
+ }
+ return RegisterObjectDefinitions(props, prefix, resource.Description);
+ }
+ catch (IOException ex)
+ {
+ throw new ObjectDefinitionStoreException("IOException parsing properties from " + resource, ex);
+ }
+ }
+
+ ///
+ /// Register object definitions contained in a
+ /// , using all property keys (i.e.
+ /// not filtering by prefix).
+ ///
+ ///
+ /// The containing object definitions.
+ ///
+ ///
+ /// In case of loading or parsing errors.
+ ///
+ /// The number of object definitions registered.
+ public int RegisterObjectDefinitions(ResourceSet rs)
+ {
+ return RegisterObjectDefinitions(rs, string.Empty);
+ }
+
+ ///
+ /// Register object definitions contained in a
+ /// .
+ ///
+ ///
+ ///
+ /// Similar syntax as for an .
+ /// This method is useful to enable standard .NET internationalization support.
+ ///
+ ///
+ ///
+ /// The containing object definitions.
+ ///
+ ///
+ /// The match or filter for object definition names, e.g. 'objects.'
+ ///
+ ///
+ /// In case of loading or parsing errors.
+ ///
+ /// The number of object definitions registered.
+ public int RegisterObjectDefinitions(ResourceSet rs, string prefix)
+ {
+#if ! NET_1_0
+ // Simply create a map and call overloaded method
+ IDictionary id = new Hashtable();
+ foreach (DictionaryEntry de in rs)
+ {
+ id.Add(de.Key, de.Value);
+ }
+ return RegisterObjectDefinitions(id, prefix);
+#else
+ throw new NotSupportedException("Operation not supported on NET 1.0");
+#endif
+ }
+
+ ///
+ /// Register object definitions contained in an
+ /// , using all property keys
+ /// (i.e. not filtering by prefix).
+ ///
+ ///
+ /// The containing object definitions.
+ ///
+ ///
+ /// In case of loading or parsing errors.
+ ///
+ /// The number of object definitions registered.
+ public int RegisterObjectDefinitions(IDictionary id)
+ {
+ return RegisterObjectDefinitions(id, string.Empty);
+ }
+
+ ///
+ /// Registers object definitions contained in an
+ /// using all property keys ( i.e. not filtering by prefix )
+ ///
+ /// The containing
+ /// object definitions.
+ ///
+ ///
+ /// In case of loading or parsing errors.
+ ///
+ /// The number of object definitions registered.
+ public int RegisterObjectDefinitions(NameValueCollection nameValueCollection)
+ {
+ IDictionary id = new Hashtable();
+ foreach (DictionaryEntry de in nameValueCollection)
+ {
+ id.Add(de.Key, de.Value);
+ }
+
+ return RegisterObjectDefinitions(id);
+ }
+
+ ///
+ /// Register object definitions contained in a
+ /// .
+ ///
+ ///
+ ///
+ /// Ignores ineligible properties.
+ ///
+ ///
+ /// IDictionary name -> property (String or Object). Property values
+ /// will be strings if coming from a Properties file etc. Property names
+ /// (keys) must be strings. Type keys must be strings.
+ ///
+ ///
+ /// The match or filter within the keys in the map: e.g. 'objects.'
+ ///
+ ///
+ /// In case of loading or parsing errors.
+ ///
+ /// The number of object definitions found.
+ public int RegisterObjectDefinitions(IDictionary id, string prefix)
+ {
+ return RegisterObjectDefinitions(id, prefix, "(no description)");
+ }
+
+ ///
+ /// Register object definitions contained in a
+ /// .
+ ///
+ ///
+ ///
- /// This is the most common type of object definition;
- /// instances
- /// do not derive from a parent
- /// , and usually
- /// (but not always - see below) have an
- ///
- /// and (optionally) some
- /// and
- /// .
- ///
- ///
- /// Note that
- /// instances do not have to specify an
- /// :
- /// This can be useful for deriving
- /// instances
- /// from such definitions, each with it's own
- /// ,
- /// inheriting common property values and other settings from the parent.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: RootObjectDefinition.cs,v 1.20 2007/03/16 04:01:43 aseovic Exp $
- ///
- [Serializable]
- public class RootObjectDefinition : AbstractObjectDefinition
- {
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public RootObjectDefinition()
- {}
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The of the object to instantiate.
- ///
- public RootObjectDefinition(Type type)
- {
- ObjectType = type;
- }
-
- ///
- /// Creates a new instance of the
- ///
- /// class.
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// if this object definition defines a singleton object.
- ///
- public RootObjectDefinition(Type type, bool singleton)
- {
- ObjectType = type;
- IsSingleton = singleton;
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// for a singleton, providing property values and constructor arguments.
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// The
- /// to be applied to a new instance of the object.
- ///
- ///
- /// The to be applied to
- /// a new instance of the object.
- ///
- public RootObjectDefinition(
- Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties)
- : base(arguments, properties)
- {
- ObjectType = type;
- }
-
-
- ///
- /// Creates a new instance of the
- /// class
- /// for a singleton using the supplied
- /// .
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// The autowiring mode.
- ///
- public RootObjectDefinition(Type type, AutoWiringMode autowireMode)
- {
- ObjectType = type;
- AutowireMode = autowireMode;
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// for a singleton using the supplied
- /// .
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// The autowiring mode.
- ///
- ///
- /// Whether to perform a dependency check for objects (not
- /// applicable to autowiring a constructor, thus ignored there)
- ///
- public RootObjectDefinition(
- Type type, AutoWiringMode autowireMode, bool dependencyCheck)
- {
- ObjectType = type;
- AutowireMode = autowireMode;
- if (dependencyCheck
- && ResolvedAutowireMode != AutoWiringMode.Constructor)
- {
- DependencyCheck = DependencyCheckingMode.Objects;
- }
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// with the given singleton status, providing property values.
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// The to be applied to
- /// a new instance of the object.
- ///
- public RootObjectDefinition(
- Type type, MutablePropertyValues properties) : base(null, properties)
- {
- ObjectType = type;
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// with the given singleton status, providing property values.
- ///
- ///
- /// The of the object to instantiate.
- ///
- ///
- /// The to be applied to
- /// a new instance of the object.
- ///
- ///
- /// if this object definition defines a singleton object.
- ///
- public RootObjectDefinition(
- Type type, MutablePropertyValues properties, bool singleton) : base(null, properties)
- {
- ObjectType = type;
- IsSingleton = singleton;
- }
-
- ///
- /// Creates a new instance of the
- /// class
- /// for a singleton, providing property values and constructor arguments.
- ///
- ///
- ///
- /// Takes an object class name to avoid eager loading of the object class.
- ///
- ///
- ///
- /// The assembly qualified of the object to instantiate.
- ///
- ///
- /// The to be applied to
- /// a new instance of the object.
- ///
- ///
- /// The
- /// to be applied to a new instance of the object.
- ///
- public RootObjectDefinition(
- string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
- : base(arguments, properties)
- {
- ObjectTypeName = typeName;
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
+ /// This is the most common type of object definition;
+ /// instances
+ /// do not derive from a parent
+ /// , and usually
+ /// (but not always - see below) have an
+ ///
+ /// and (optionally) some
+ /// and
+ /// .
+ ///
+ ///
+ /// Note that
+ /// instances do not have to specify an
+ /// :
+ /// This can be useful for deriving
+ /// instances
+ /// from such definitions, each with it's own
+ /// ,
+ /// inheriting common property values and other settings from the parent.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class RootObjectDefinition : AbstractObjectDefinition
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public RootObjectDefinition()
+ {}
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ public RootObjectDefinition(Type type)
+ {
+ ObjectType = type;
+ }
+
+ ///
+ /// Creates a new instance of the
+ ///
+ /// class.
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// if this object definition defines a singleton object.
+ ///
+ public RootObjectDefinition(Type type, bool singleton)
+ {
+ ObjectType = type;
+ IsSingleton = singleton;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// for a singleton, providing property values and constructor arguments.
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// The
+ /// to be applied to a new instance of the object.
+ ///
+ ///
+ /// The to be applied to
+ /// a new instance of the object.
+ ///
+ public RootObjectDefinition(
+ Type type, ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ : base(arguments, properties)
+ {
+ ObjectType = type;
+ }
+
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// for a singleton using the supplied
+ /// .
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// The autowiring mode.
+ ///
+ public RootObjectDefinition(Type type, AutoWiringMode autowireMode)
+ {
+ ObjectType = type;
+ AutowireMode = autowireMode;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// for a singleton using the supplied
+ /// .
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// The autowiring mode.
+ ///
+ ///
+ /// Whether to perform a dependency check for objects (not
+ /// applicable to autowiring a constructor, thus ignored there)
+ ///
+ public RootObjectDefinition(
+ Type type, AutoWiringMode autowireMode, bool dependencyCheck)
+ {
+ ObjectType = type;
+ AutowireMode = autowireMode;
+ if (dependencyCheck
+ && ResolvedAutowireMode != AutoWiringMode.Constructor)
+ {
+ DependencyCheck = DependencyCheckingMode.Objects;
+ }
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// with the given singleton status, providing property values.
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// The to be applied to
+ /// a new instance of the object.
+ ///
+ public RootObjectDefinition(
+ Type type, MutablePropertyValues properties) : base(null, properties)
+ {
+ ObjectType = type;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// with the given singleton status, providing property values.
+ ///
+ ///
+ /// The of the object to instantiate.
+ ///
+ ///
+ /// The to be applied to
+ /// a new instance of the object.
+ ///
+ ///
+ /// if this object definition defines a singleton object.
+ ///
+ public RootObjectDefinition(
+ Type type, MutablePropertyValues properties, bool singleton) : base(null, properties)
+ {
+ ObjectType = type;
+ IsSingleton = singleton;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// for a singleton, providing property values and constructor arguments.
+ ///
+ ///
+ ///
+ /// Takes an object class name to avoid eager loading of the object class.
+ ///
+ ///
+ ///
+ /// The assembly qualified of the object to instantiate.
+ ///
+ ///
+ /// The to be applied to
+ /// a new instance of the object.
+ ///
+ ///
+ /// The
+ /// to be applied to a new instance of the object.
+ ///
+ public RootObjectDefinition(
+ string typeName, ConstructorArgumentValues arguments, MutablePropertyValues properties)
+ : base(arguments, properties)
+ {
+ ObjectTypeName = typeName;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
- /// Does not support method injection, although it provides hooks for subclasses
- /// to override to add method injection support, for example by overriding methods.
- ///
- ///
- /// Rod Johnson
- /// Rick Evans (.NET)
- /// $Id: SimpleInstantiationStrategy.cs,v 1.18 2008/04/07 00:30:34 bbaia Exp $
- ///
- [Serializable]
- public class SimpleInstantiationStrategy : IInstantiationStrategy
- {
- ///
- /// The shared instance for this class (and derived classes).
- ///
- protected static readonly ILog log =
- LogManager.GetLogger(typeof (SimpleInstantiationStrategy));
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied .
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the null
- /// or zero length string if we're autowiring an object that doesn't belong
- /// to the supplied .
- ///
- ///
- /// The owning
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- public virtual object Instantiate(
- RootObjectDefinition definition, string name, IObjectFactory factory)
- {
- AssertUtils.ArgumentNotNull(definition, "definition");
- AssertUtils.ArgumentNotNull(factory, "factory");
- if (definition.HasMethodOverrides)
- {
- return InstantiateWithMethodInjection(definition, name, factory);
- }
- else
- {
- Type objectType = definition.HasObjectType
- ? definition.ObjectType
- : TypeResolutionUtils.ResolveType(definition.ObjectTypeName);
- ConstructorInfo constructor = GetZeroArgConstructorInfo(objectType);
- return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects);
- }
- }
-
- ///
- /// Gets the zero arg ConstructorInfo object, if the type offers such functionality.
- ///
- /// The type.
- /// Zero argument ConstructorInfo
- ///
- /// If the type does not have a zero-arg constructor.
- ///
- private ConstructorInfo GetZeroArgConstructorInfo(Type type)
- {
- const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
- BindingFlags.Instance | BindingFlags.DeclaredOnly;
-
- ConstructorInfo constructor = type.GetConstructor(flags, null, Type.EmptyTypes, null);
- if (constructor == null)
- {
- throw new FatalReflectionException(string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a no-argument constructor [{0}].", type));
- }
- return constructor;
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied .
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the null
- /// or zero length string if we're autowiring an object that doesn't belong
- /// to the supplied .
- ///
- ///
- /// The owning
- ///
- ///
- /// The to be used to instantiate
- /// the object.
- ///
- ///
- /// Any arguments to the supplied . May be null.
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- public virtual object Instantiate(
- RootObjectDefinition definition, string name, IObjectFactory factory,
- ConstructorInfo constructor, object[] arguments)
- {
- if (definition.HasMethodOverrides)
- {
- return InstantiateWithMethodInjection(definition, name, factory, constructor, arguments);
- }
- else
- {
- return ObjectUtils.InstantiateType(constructor, arguments);
- }
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied .
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be the null
- /// or zero length string if we're autowiring an object that doesn't belong
- /// to the supplied .
- ///
- ///
- /// The owning
- ///
- ///
- /// The to be used to get the object.
- ///
- ///
- /// Any arguments to the supplied . May be null.
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- public virtual object Instantiate(
- RootObjectDefinition definition, string name, IObjectFactory factory,
- MethodInfo factoryMethod, object[] arguments)
- {
- object instance = null;
- object target = null;
- if (StringUtils.HasText(definition.FactoryObjectName))
- {
- target = factory[definition.FactoryObjectName];
- }
- try
- {
- // the target will be null if using a static factory method
- instance = factoryMethod.Invoke(target, arguments);
- }
- catch (TargetInvocationException ex)
- {
- string msg = string.Format(
- CultureInfo.InvariantCulture,
- "Factory method '{0}' threw an Exception.", factoryMethod);
-
- #region Instrumentation
-
- if (log.IsWarnEnabled)
- {
- log.Warn(msg, ex.InnerException);
- }
-
- #endregion
-
- throw new ObjectDefinitionStoreException(msg, ex.InnerException);
- }
- catch (Exception ex)
- {
- throw new ObjectDefinitionStoreException(string.Format(
- CultureInfo.InvariantCulture,
- "Factory method '{0}' threw an Exception.", factoryMethod), ex);
- }
- return instance;
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied ,
- /// injecting methods as appropriate.
- ///
- ///
- ///
- /// The default implementation of this method is to throw a
- /// .
- ///
- ///
- /// Derived classes can override this method if they can instantiate an object
- /// with the Method Injection specified in the supplied
- /// . Instantiation should use a no-arg constructor.
- ///
- ///
- ///
- /// The definition of the object that is to be instantiated.
- ///
- ///
- /// The name associated with the object definition. The name can be a
- /// or zero length string if we're autowiring an object that
- /// doesn't belong to the supplied .
- ///
- ///
- /// The owning
- ///
- ///
- /// An instance of the object described by the supplied
- /// from the supplied .
- ///
- protected virtual object InstantiateWithMethodInjection(
- RootObjectDefinition definition, string objectName, IObjectFactory factory)
- {
- throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy");
- }
-
- ///
- /// Instantiate an instance of the object described by the supplied
- /// from the supplied ,
- /// injecting methods as appropriate.
- ///
- ///
- ///
- /// The default implementation of this method is to throw a
- /// .
- ///
- ///
- /// Derived classes can override this method if they can instantiate an object
- /// with the Method Injection specified in the supplied
- /// . Instantiation should use the supplied
- /// and attendant .
- ///
+ /// Does not support method injection, although it provides hooks for subclasses
+ /// to override to add method injection support, for example by overriding methods.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class SimpleInstantiationStrategy : IInstantiationStrategy
+ {
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ protected static readonly ILog log =
+ LogManager.GetLogger(typeof (SimpleInstantiationStrategy));
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the null
+ /// or zero length string if we're autowiring an object that doesn't belong
+ /// to the supplied .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ public virtual object Instantiate(
+ RootObjectDefinition definition, string name, IObjectFactory factory)
+ {
+ AssertUtils.ArgumentNotNull(definition, "definition");
+ AssertUtils.ArgumentNotNull(factory, "factory");
+ if (definition.HasMethodOverrides)
+ {
+ return InstantiateWithMethodInjection(definition, name, factory);
+ }
+ else
+ {
+ Type objectType = definition.HasObjectType
+ ? definition.ObjectType
+ : TypeResolutionUtils.ResolveType(definition.ObjectTypeName);
+ ConstructorInfo constructor = GetZeroArgConstructorInfo(objectType);
+ return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects);
+ }
+ }
+
+ ///
+ /// Gets the zero arg ConstructorInfo object, if the type offers such functionality.
+ ///
+ /// The type.
+ /// Zero argument ConstructorInfo
+ ///
+ /// If the type does not have a zero-arg constructor.
+ ///
+ private ConstructorInfo GetZeroArgConstructorInfo(Type type)
+ {
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+ ConstructorInfo constructor = type.GetConstructor(flags, null, Type.EmptyTypes, null);
+ if (constructor == null)
+ {
+ throw new FatalReflectionException(string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a no-argument constructor [{0}].", type));
+ }
+ return constructor;
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the null
+ /// or zero length string if we're autowiring an object that doesn't belong
+ /// to the supplied .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// The to be used to instantiate
+ /// the object.
+ ///
+ ///
+ /// Any arguments to the supplied . May be null.
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ public virtual object Instantiate(
+ RootObjectDefinition definition, string name, IObjectFactory factory,
+ ConstructorInfo constructor, object[] arguments)
+ {
+ if (definition.HasMethodOverrides)
+ {
+ return InstantiateWithMethodInjection(definition, name, factory, constructor, arguments);
+ }
+ else
+ {
+ return ObjectUtils.InstantiateType(constructor, arguments);
+ }
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be the null
+ /// or zero length string if we're autowiring an object that doesn't belong
+ /// to the supplied .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// The to be used to get the object.
+ ///
+ ///
+ /// Any arguments to the supplied . May be null.
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ public virtual object Instantiate(
+ RootObjectDefinition definition, string name, IObjectFactory factory,
+ MethodInfo factoryMethod, object[] arguments)
+ {
+ object instance = null;
+ object target = null;
+ if (StringUtils.HasText(definition.FactoryObjectName))
+ {
+ target = factory[definition.FactoryObjectName];
+ }
+ try
+ {
+ // the target will be null if using a static factory method
+ instance = factoryMethod.Invoke(target, arguments);
+ }
+ catch (TargetInvocationException ex)
+ {
+ string msg = string.Format(
+ CultureInfo.InvariantCulture,
+ "Factory method '{0}' threw an Exception.", factoryMethod);
+
+ #region Instrumentation
+
+ if (log.IsWarnEnabled)
+ {
+ log.Warn(msg, ex.InnerException);
+ }
+
+ #endregion
+
+ throw new ObjectDefinitionStoreException(msg, ex.InnerException);
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectDefinitionStoreException(string.Format(
+ CultureInfo.InvariantCulture,
+ "Factory method '{0}' threw an Exception.", factoryMethod), ex);
+ }
+ return instance;
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied ,
+ /// injecting methods as appropriate.
+ ///
+ ///
+ ///
+ /// The default implementation of this method is to throw a
+ /// .
+ ///
+ ///
+ /// Derived classes can override this method if they can instantiate an object
+ /// with the Method Injection specified in the supplied
+ /// . Instantiation should use a no-arg constructor.
+ ///
+ ///
+ ///
+ /// The definition of the object that is to be instantiated.
+ ///
+ ///
+ /// The name associated with the object definition. The name can be a
+ /// or zero length string if we're autowiring an object that
+ /// doesn't belong to the supplied .
+ ///
+ ///
+ /// The owning
+ ///
+ ///
+ /// An instance of the object described by the supplied
+ /// from the supplied .
+ ///
+ protected virtual object InstantiateWithMethodInjection(
+ RootObjectDefinition definition, string objectName, IObjectFactory factory)
+ {
+ throw new InvalidOperationException("Method Injection not supported in SimpleInstantiationStrategy");
+ }
+
+ ///
+ /// Instantiate an instance of the object described by the supplied
+ /// from the supplied ,
+ /// injecting methods as appropriate.
+ ///
+ ///
+ ///
+ /// The default implementation of this method is to throw a
+ /// .
+ ///
+ ///
+ /// Derived classes can override this method if they can instantiate an object
+ /// with the Method Injection specified in the supplied
+ /// . Instantiation should use the supplied
+ /// and attendant .
+ ///
- /// Does not have support for prototype objects, aliases, and post startup object
- /// configuration.
- ///
- ///
- /// Serves as a simple example implementation of the
- /// interface, that manages existing object instances as opposed to creating new ones
- /// based on object definitions.
- ///
- ///
- /// The
- /// method is not supported by this class; this class deals exclusively with
- /// existing singleton instances, thus the methods mentioned previously make little sense in this context.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: StaticListableObjectFactory.cs,v 1.24 2007/12/05 00:28:05 bbaia Exp $
- [Serializable]
- public class StaticListableObjectFactory : IListableObjectFactory
- {
- ///
- /// Map from object name to object instance.
- ///
- private Hashtable objects = new Hashtable();
-
- ///
- /// Return the number of objects defined in the factory.
- ///
- ///
- /// The number of objects defined in the factory.
- ///
- public int ObjectDefinitionCount
- {
- get { return objects.Count; }
- }
-
- ///
- /// Return an instance of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- public object this[string name]
- {
- get { return GetObject(name); }
- }
-
- ///
- /// Return an instance of the given object name.
- ///
- /// The name of the object to return.
- /// The instance of the object.
- ///
- /// is not currently supported.
- ///
- ///
- public object GetObject(string name)
- {
- object instance = objects[name];
- if (instance is IFactoryObject)
- {
- if (instance is IConfigurableFactoryObject)
- {
- throw new NotSupportedException();
- }
- try
- {
- return ((IFactoryObject) instance).GetObject();
- }
- catch (Exception ex)
- {
- throw new ObjectCreationException(name,
- "IFactoryObject threw an exception on object creation", ex);
- }
- }
- if (instance == null)
- {
- throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString());
- }
- return instance;
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- ///
- ///
- /// This method allows an object factory to be used as a replacement for the
- /// Singleton or Prototype design pattern.
- ///
- ///
- /// Note that callers should retain references to returned objects. There is no
- /// guarantee that this method will be implemented to be efficient. For example,
- /// it may be synchronized, or may need to run an RDBMS query.
- ///
- ///
- /// Will ask the parent factory if the object cannot be found in this factory
- /// instance.
- ///
- ///
- /// The name of the object to return.
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a static factory method. If there is no factory method and the
- /// arguments are not null, then match the argument values by type and
- /// call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the supplied is .
- ///
- public object GetObject(string name, object[] arguments)
- {
- throw new NotSupportedException("StaticListableObjectFactory does not support this method.");
- }
-
- ///
- /// Return an instance (possibly shared or independent) of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// The the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- ///
- /// The arguments to use if creating a prototype using explicit arguments to
- /// a factory method. If there is no factory method and the
- /// supplied array is not , then
- /// match the argument values by type and call the object's constructor.
- ///
- /// The instance of the object.
- ///
- /// If there's no such object definition.
- ///
- ///
- /// If the object could not be created.
- ///
- ///
- /// If the object is not of the required type.
- ///
- ///
- /// If the supplied is .
- ///
- ///
- public object GetObject(string name, Type requiredType, object[] arguments)
- {
- throw new NotSupportedException("StaticListableObjectFactory does not support this method.");
- }
-
- ///
- /// Return an instance of the given object name.
- ///
- /// The name of the object to return.
- ///
- /// the object may match. Can be an interface or
- /// superclass of the actual class. For example, if the value is the
- /// class, this method will succeed whatever the
- /// class of the returned instance.
- ///
- /// The instance of the object.
- ///
- public object GetObject(string name, Type requiredType)
- {
- object instance = GetObject(name);
- if (!requiredType.IsAssignableFrom(instance.GetType()))
- {
- throw new ObjectNotOfRequiredTypeException(name, requiredType, instance);
- }
- return instance;
- }
-
- ///
- /// Does this object factory contain an object with the given name?
- ///
- /// The name of the object to query.
- /// True if an object with the given name is defined.
- public bool ContainsObject(string name)
- {
- return objects.ContainsKey(name);
- }
-
- ///
- /// Is this object a singleton?
- ///
- ///
- ///
- /// That is, will
- /// or
- /// always return the same object?
- ///
- ///
- /// The name of the object to query.
- /// True if the named object is a singleton.
- ///
- /// If there's no such object definition.
- ///
- public bool IsSingleton(string name)
- {
- bool isSingleton = true;
- object instance = GetObject(name);
- // in case of IFactoryObject, return singleton status of created object
- if (instance is IFactoryObject)
- {
- isSingleton = ((IFactoryObject) instance).IsSingleton;
- }
- return isSingleton;
- }
-
-
- ///
- /// Determines whether the specified object name is prototype. That is, will GetObject
- /// always return independent instances?
- ///
- /// This method returning false does not clearly indicate a singleton object.
- /// It indicated non-independent instances, which may correspond to a scoped object as
- /// well. use the IsSingleton property to explicitly check for a shared
- /// singleton instance.
- /// Translates aliases back to the corresponding canonical object name. Will ask the
- /// parent factory if the object can not be found in this factory instance.
- ///
- ///
- ///
- /// The name of the object to query
- ///
- /// true if the specified object name will always deliver independent instances; otherwise, false.
- ///
- /// if there is no object with the given name.
- public bool IsPrototype(string name)
- {
- bool isPrototype = true;
- object instance = GetObject(name);
- if (instance is IFactoryObject)
- {
- isPrototype = !((IFactoryObject) instance).IsSingleton;
- }
- return isPrototype;
-
- }
-
- ///
- /// Determine the type of the object with the given name.
- ///
- ///
- ///
- /// More specifically, checks the type of object that
- /// would return.
- /// For an , returns the type
- /// of object that the creates.
- ///
- ///
- /// The name of the object to query.
- ///
- /// The of the object or if
- /// not determinable.
- ///
- public Type GetType(string name)
- {
- string objectName = ObjectFactoryUtils.TransformedObjectName(name);
- object instance = objects[objectName];
- if (instance == null)
- {
- throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString());
- }
- if (instance is IFactoryObject && !ObjectFactoryUtils.IsFactoryDereference(name))
- {
- return ((IFactoryObject) instance).ObjectType;
- }
- return instance.GetType();
- }
-
-
- ///
- /// Determines whether the object with the given name matches the specified type.
- ///
- /// The name of the object to query.
- /// Type of the target to match against.
- ///
- /// true if the object type matches; otherwise, false
- /// if it doesn't match or cannot be determined yet.
- ///
- /// Ff there is no object with the given name
- ///
- public bool IsTypeMatch(string name, Type targetType)
- {
- Type type = GetType(name);
- return (targetType == null || (type != null && targetType.IsAssignableFrom(type)));
- }
-
- private string GrabDefinedObjectsString()
- {
- return "Defined objects are [" +
- StringUtils.CollectionToDelimitedString(objects.Keys, ",") + "]";
- }
-
- ///
- /// Return the aliases for the given object name, if defined.
- ///
- /// The object name to check for aliases.
- /// The aliases, or an empty array if none.
- ///
- /// If there's no such object definition.
- ///
- public string[] GetAliases(string name)
- {
- return StringUtils.EmptyStrings;
- }
-
- ///
- /// Not supported.
- ///
- /// The name of the object.
- ///
- /// The registered
- /// .
- ///
- ///
- /// Always, as object definitions are not supported by this
- /// implementation.
- ///
- public IObjectDefinition GetObjectDefinition(string name)
- {
- throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions.");
- }
-
- ///
- /// Return the registered
- /// for the
- /// given object, allowing access to its property values and constructor
- /// argument values.
- ///
- /// The name of the object.
- /// Whether to search parent object factories.
- ///
- /// The registered
- /// .
- ///
- ///
- /// If there is no object with the given name.
- ///
- ///
- /// In the case of errors.
- ///
- public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
- {
- throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions.");
- }
-
-
- ///
- /// Return the names of all objects defined in this factory.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- public string[] GetObjectDefinitionNames()
- {
- ArrayList names = new ArrayList(objects.Keys);
- return (string[]) names.ToArray(typeof (string));
- }
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- ///
- /// Will not consider s,
- /// as the type of their created objects is not known before instantiation.
- ///
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- public string[] GetObjectDefinitionNames(Type type)
- {
- ArrayList matches = new ArrayList();
- foreach (string name in objects.Keys)
- {
- Type t = objects[name].GetType();
- if (type.IsAssignableFrom(t))
- {
- matches.Add(name);
- }
- }
- return (string[]) matches.ToArray(typeof (string));
- }
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- ///
- /// Does consider objects created by s,
- /// or rather it considers the type of objects created by
- /// (which means that
- /// s will be instantiated).
- ///
- ///
- /// Does not consider any hierarchy this factory may participate in.
- ///
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- public string[] GetObjectNamesForType(Type type)
- {
- return GetObjectNamesForType(type, true, true);
- }
-
- ///
- /// Return the names of objects matching the given
- /// (including subclasses), judging from the object definitions.
- ///
- ///
- ///
- /// Since this implementation of the
- ///
- /// interface does not support the notion of ptototype objects, the
- /// parameter is ignored.
- ///
- ///
- ///
- /// The (class or interface) to match, or
- /// for all object names.
- ///
- ///
- /// Whether to include prototype objects too or just singletons (also applies to
- /// s). Ignored.
- ///
- ///
- /// Whether to include s too
- /// or just normal objects.
- ///
- ///
- /// The names of all objects defined in this factory, or an empty array if none
- /// are defined.
- ///
- ///
- public string[] GetObjectNamesForType(
- Type type, bool includePrototypes, bool includeFactoryObjects)
- {
- bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type));
- IList matches = new ArrayList();
- foreach (string name in objects.Keys)
- {
- object instance = objects[name];
- if (instance is IFactoryObject && !isFactoryType)
- {
- if(includeFactoryObjects)
- {
- Type objectType = ((IFactoryObject) instance).ObjectType;
- if (objectType != null && type.IsAssignableFrom(objectType))
- {
- matches.Add(name);
- }
- }
- }
- else
- {
- if (type.IsInstanceOfType(instance))
- {
- matches.Add(name);
- }
- }
- }
- return (string[]) ArrayList.Adapter(matches).ToArray(typeof(string));
- }
-
- ///
- /// Tests whether this object factory contains an object definition for the
- /// specified object name.
- ///
- /// The object name to query.
- ///
- /// True if an object defintion is contained within this object factory.
- ///
- public bool ContainsObjectDefinition(string name)
- {
- return objects.ContainsKey(name);
- }
-
- ///
- /// Return the object instances that match the given object
- /// (including subclasses), judging from either object
- /// definitions or the value of
- /// in the case of
- /// s.
- ///
- ///
- ///
- /// This version of the
- /// method matches all kinds of object definitions, be they singletons, prototypes, or
- /// s. Typically, the results
- /// of this method call will be the same as a call to
- /// IListableObjectFactory.GetObjectsOfType(type,true,true) .
- ///
+ /// Does not have support for prototype objects, aliases, and post startup object
+ /// configuration.
+ ///
+ ///
+ /// Serves as a simple example implementation of the
+ /// interface, that manages existing object instances as opposed to creating new ones
+ /// based on object definitions.
+ ///
+ ///
+ /// The
+ /// method is not supported by this class; this class deals exclusively with
+ /// existing singleton instances, thus the methods mentioned previously make little sense in this context.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ [Serializable]
+ public class StaticListableObjectFactory : IListableObjectFactory
+ {
+ ///
+ /// Map from object name to object instance.
+ ///
+ private Hashtable objects = new Hashtable();
+
+ ///
+ /// Return the number of objects defined in the factory.
+ ///
+ ///
+ /// The number of objects defined in the factory.
+ ///
+ public int ObjectDefinitionCount
+ {
+ get { return objects.Count; }
+ }
+
+ ///
+ /// Return an instance of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ public object this[string name]
+ {
+ get { return GetObject(name); }
+ }
+
+ ///
+ /// Return an instance of the given object name.
+ ///
+ /// The name of the object to return.
+ /// The instance of the object.
+ ///
+ /// is not currently supported.
+ ///
+ ///
+ public object GetObject(string name)
+ {
+ object instance = objects[name];
+ if (instance is IFactoryObject)
+ {
+ if (instance is IConfigurableFactoryObject)
+ {
+ throw new NotSupportedException();
+ }
+ try
+ {
+ return ((IFactoryObject) instance).GetObject();
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectCreationException(name,
+ "IFactoryObject threw an exception on object creation", ex);
+ }
+ }
+ if (instance == null)
+ {
+ throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString());
+ }
+ return instance;
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ ///
+ ///
+ /// This method allows an object factory to be used as a replacement for the
+ /// Singleton or Prototype design pattern.
+ ///
+ ///
+ /// Note that callers should retain references to returned objects. There is no
+ /// guarantee that this method will be implemented to be efficient. For example,
+ /// it may be synchronized, or may need to run an RDBMS query.
+ ///
+ ///
+ /// Will ask the parent factory if the object cannot be found in this factory
+ /// instance.
+ ///
+ ///
+ /// The name of the object to return.
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a static factory method. If there is no factory method and the
+ /// arguments are not null, then match the argument values by type and
+ /// call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public object GetObject(string name, object[] arguments)
+ {
+ throw new NotSupportedException("StaticListableObjectFactory does not support this method.");
+ }
+
+ ///
+ /// Return an instance (possibly shared or independent) of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// The the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ ///
+ /// The arguments to use if creating a prototype using explicit arguments to
+ /// a factory method. If there is no factory method and the
+ /// supplied array is not , then
+ /// match the argument values by type and call the object's constructor.
+ ///
+ /// The instance of the object.
+ ///
+ /// If there's no such object definition.
+ ///
+ ///
+ /// If the object could not be created.
+ ///
+ ///
+ /// If the object is not of the required type.
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ public object GetObject(string name, Type requiredType, object[] arguments)
+ {
+ throw new NotSupportedException("StaticListableObjectFactory does not support this method.");
+ }
+
+ ///
+ /// Return an instance of the given object name.
+ ///
+ /// The name of the object to return.
+ ///
+ /// the object may match. Can be an interface or
+ /// superclass of the actual class. For example, if the value is the
+ /// class, this method will succeed whatever the
+ /// class of the returned instance.
+ ///
+ /// The instance of the object.
+ ///
+ public object GetObject(string name, Type requiredType)
+ {
+ object instance = GetObject(name);
+ if (!requiredType.IsAssignableFrom(instance.GetType()))
+ {
+ throw new ObjectNotOfRequiredTypeException(name, requiredType, instance);
+ }
+ return instance;
+ }
+
+ ///
+ /// Does this object factory contain an object with the given name?
+ ///
+ /// The name of the object to query.
+ /// True if an object with the given name is defined.
+ public bool ContainsObject(string name)
+ {
+ return objects.ContainsKey(name);
+ }
+
+ ///
+ /// Is this object a singleton?
+ ///
+ ///
+ ///
+ /// That is, will
+ /// or
+ /// always return the same object?
+ ///
+ ///
+ /// The name of the object to query.
+ /// True if the named object is a singleton.
+ ///
+ /// If there's no such object definition.
+ ///
+ public bool IsSingleton(string name)
+ {
+ bool isSingleton = true;
+ object instance = GetObject(name);
+ // in case of IFactoryObject, return singleton status of created object
+ if (instance is IFactoryObject)
+ {
+ isSingleton = ((IFactoryObject) instance).IsSingleton;
+ }
+ return isSingleton;
+ }
+
+
+ ///
+ /// Determines whether the specified object name is prototype. That is, will GetObject
+ /// always return independent instances?
+ ///
+ /// This method returning false does not clearly indicate a singleton object.
+ /// It indicated non-independent instances, which may correspond to a scoped object as
+ /// well. use the IsSingleton property to explicitly check for a shared
+ /// singleton instance.
+ /// Translates aliases back to the corresponding canonical object name. Will ask the
+ /// parent factory if the object can not be found in this factory instance.
+ ///
+ ///
+ ///
+ /// The name of the object to query
+ ///
+ /// true if the specified object name will always deliver independent instances; otherwise, false.
+ ///
+ /// if there is no object with the given name.
+ public bool IsPrototype(string name)
+ {
+ bool isPrototype = true;
+ object instance = GetObject(name);
+ if (instance is IFactoryObject)
+ {
+ isPrototype = !((IFactoryObject) instance).IsSingleton;
+ }
+ return isPrototype;
+
+ }
+
+ ///
+ /// Determine the type of the object with the given name.
+ ///
+ ///
+ ///
+ /// More specifically, checks the type of object that
+ /// would return.
+ /// For an , returns the type
+ /// of object that the creates.
+ ///
+ ///
+ /// The name of the object to query.
+ ///
+ /// The of the object or if
+ /// not determinable.
+ ///
+ public Type GetType(string name)
+ {
+ string objectName = ObjectFactoryUtils.TransformedObjectName(name);
+ object instance = objects[objectName];
+ if (instance == null)
+ {
+ throw new NoSuchObjectDefinitionException(name, GrabDefinedObjectsString());
+ }
+ if (instance is IFactoryObject && !ObjectFactoryUtils.IsFactoryDereference(name))
+ {
+ return ((IFactoryObject) instance).ObjectType;
+ }
+ return instance.GetType();
+ }
+
+
+ ///
+ /// Determines whether the object with the given name matches the specified type.
+ ///
+ /// The name of the object to query.
+ /// Type of the target to match against.
+ ///
+ /// true if the object type matches; otherwise, false
+ /// if it doesn't match or cannot be determined yet.
+ ///
+ /// Ff there is no object with the given name
+ ///
+ public bool IsTypeMatch(string name, Type targetType)
+ {
+ Type type = GetType(name);
+ return (targetType == null || (type != null && targetType.IsAssignableFrom(type)));
+ }
+
+ private string GrabDefinedObjectsString()
+ {
+ return "Defined objects are [" +
+ StringUtils.CollectionToDelimitedString(objects.Keys, ",") + "]";
+ }
+
+ ///
+ /// Return the aliases for the given object name, if defined.
+ ///
+ /// The object name to check for aliases.
+ /// The aliases, or an empty array if none.
+ ///
+ /// If there's no such object definition.
+ ///
+ public string[] GetAliases(string name)
+ {
+ return StringUtils.EmptyStrings;
+ }
+
+ ///
+ /// Not supported.
+ ///
+ /// The name of the object.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// Always, as object definitions are not supported by this
+ /// implementation.
+ ///
+ public IObjectDefinition GetObjectDefinition(string name)
+ {
+ throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions.");
+ }
+
+ ///
+ /// Return the registered
+ /// for the
+ /// given object, allowing access to its property values and constructor
+ /// argument values.
+ ///
+ /// The name of the object.
+ /// Whether to search parent object factories.
+ ///
+ /// The registered
+ /// .
+ ///
+ ///
+ /// If there is no object with the given name.
+ ///
+ ///
+ /// In the case of errors.
+ ///
+ public IObjectDefinition GetObjectDefinition(string name, bool includeAncestors)
+ {
+ throw new NotSupportedException("StaticListableObjectFactory does not contain object definitions.");
+ }
+
+
+ ///
+ /// Return the names of all objects defined in this factory.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ public string[] GetObjectDefinitionNames()
+ {
+ ArrayList names = new ArrayList(objects.Keys);
+ return (string[]) names.ToArray(typeof (string));
+ }
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ ///
+ /// Will not consider s,
+ /// as the type of their created objects is not known before instantiation.
+ ///
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ public string[] GetObjectDefinitionNames(Type type)
+ {
+ ArrayList matches = new ArrayList();
+ foreach (string name in objects.Keys)
+ {
+ Type t = objects[name].GetType();
+ if (type.IsAssignableFrom(t))
+ {
+ matches.Add(name);
+ }
+ }
+ return (string[]) matches.ToArray(typeof (string));
+ }
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ ///
+ /// Does consider objects created by s,
+ /// or rather it considers the type of objects created by
+ /// (which means that
+ /// s will be instantiated).
+ ///
+ ///
+ /// Does not consider any hierarchy this factory may participate in.
+ ///
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ public string[] GetObjectNamesForType(Type type)
+ {
+ return GetObjectNamesForType(type, true, true);
+ }
+
+ ///
+ /// Return the names of objects matching the given
+ /// (including subclasses), judging from the object definitions.
+ ///
+ ///
+ ///
+ /// Since this implementation of the
+ ///
+ /// interface does not support the notion of ptototype objects, the
+ /// parameter is ignored.
+ ///
+ ///
+ ///
+ /// The (class or interface) to match, or
+ /// for all object names.
+ ///
+ ///
+ /// Whether to include prototype objects too or just singletons (also applies to
+ /// s). Ignored.
+ ///
+ ///
+ /// Whether to include s too
+ /// or just normal objects.
+ ///
+ ///
+ /// The names of all objects defined in this factory, or an empty array if none
+ /// are defined.
+ ///
+ ///
+ public string[] GetObjectNamesForType(
+ Type type, bool includePrototypes, bool includeFactoryObjects)
+ {
+ bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type));
+ IList matches = new ArrayList();
+ foreach (string name in objects.Keys)
+ {
+ object instance = objects[name];
+ if (instance is IFactoryObject && !isFactoryType)
+ {
+ if(includeFactoryObjects)
+ {
+ Type objectType = ((IFactoryObject) instance).ObjectType;
+ if (objectType != null && type.IsAssignableFrom(objectType))
+ {
+ matches.Add(name);
+ }
+ }
+ }
+ else
+ {
+ if (type.IsInstanceOfType(instance))
+ {
+ matches.Add(name);
+ }
+ }
+ }
+ return (string[]) ArrayList.Adapter(matches).ToArray(typeof(string));
+ }
+
+ ///
+ /// Tests whether this object factory contains an object definition for the
+ /// specified object name.
+ ///
+ /// The object name to query.
+ ///
+ /// True if an object defintion is contained within this object factory.
+ ///
+ public bool ContainsObjectDefinition(string name)
+ {
+ return objects.ContainsKey(name);
+ }
+
+ ///
+ /// Return the object instances that match the given object
+ /// (including subclasses), judging from either object
+ /// definitions or the value of
+ /// in the case of
+ /// s.
+ ///
+ ///
+ ///
+ /// This version of the
+ /// method matches all kinds of object definitions, be they singletons, prototypes, or
+ /// s. Typically, the results
+ /// of this method call will be the same as a call to
+ /// IListableObjectFactory.GetObjectsOfType(type,true,true) .
+ ///
- /// This method is never invoked if the parser is namespace aware
- /// and was called to process the root node.
- ///
- ///
- public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
- {
- AbstractObjectDefinition definition = ParseInternal(element, parserContext);
-
- if (!parserContext.IsNested)
- {
- string id = null;
- try
- {
- id = ResolveId(element, definition, parserContext);
- if (!StringUtils.HasText(id))
- {
- parserContext.ReaderContext.ReportException(element, "null",
- "Id is required for element '" + element.LocalName + "' when used as a top-level tag", null);
- }
- ObjectDefinitionHolder holder = new ObjectDefinitionHolder(definition, id);
- RegisterObjectDefinition(holder, parserContext.Registry);
- }
- catch (ObjectDefinitionStoreException ex)
- {
- parserContext.ReaderContext.ReportException(element, id, ex.Message);
- return null;
- }
- }
- return definition;
-
-
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Resolves the ID for the supplied .
- ///
- ///
- /// When using generation, a name is generated automatically.
- /// Otherwise, the ID is extracted from the "id" attribute, potentially with a
- /// fallback to a generated id.
- ///
- /// The element that the object definition has been built from.
- /// The object definition to be registered.
- /// The the object encapsulating the current state of the parsing process;
- /// provides access to a
- /// the resolved id
- ///
- /// if no unique name could be generated for the given object definition
- ///
- protected virtual string ResolveId(XmlElement element, AbstractObjectDefinition definition, ParserContext parserContext)
- {
-
- if (ShouldGenerateId) {
- return parserContext.ReaderContext.GenerateObjectName(definition);
- }
- else {
- string id = element.GetAttribute(ID_ATTRIBUTE);
- if (!StringUtils.HasText(id) && ShouldGenerateIdAsFallback) {
- id = parserContext.ReaderContext.GenerateObjectName(definition);
- }
- return id;
- }
- }
-
- ///
- /// Registers the supplied with the supplied
- /// .
- ///
- /// Subclasses can override this method to control whether or not the supplied
- /// is actually even registered, or to
- /// register even more objects.
- ///
- /// The default implementation registers the supplied
- /// with the supplied only if the IsNested
- /// parameter is false, because one typically does not want inner objects
- /// to be registered as top level objects.
- ///
- ///
- ///
- /// The object definition to be registered.
- /// The registry that the bean is to be registered with.
- protected virtual void RegisterObjectDefinition(ObjectDefinitionHolder definition, IObjectDefinitionRegistry registry)
- {
- ObjectDefinitionReaderUtils.RegisterObjectDefinition(definition, registry);
- }
-
- #endregion
-
-
- #region Abstract Methods
-
- ///
- /// Central template method to actually parse the supplied XmlElement
- /// into one or more IObjectDefinitions.
- ///
- /// The element that is to be parsed into one or more s
- /// The the object encapsulating the current state of the parsing process;
- /// provides access to a
- /// The primary IObjectDefinition resulting from the parsing of the supplied XmlElement
- protected abstract AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext);
-
- #endregion
- }
-}
+#region License
+
+/*
+ * Copyright 2002-2007 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.Xml;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Util;
+#endregion
+
+namespace Spring.Objects.Factory.Xml
+{
+
+
+ ///
+ /// Abstract implementation providing
+ /// a number of convenience methods and a
+ /// template method
+ /// that subclasses must override to provide the actual parsing logic.
+ ///
+ ///
+ /// Use this implementation when you want
+ /// to parse some arbitrarily complex XML into one or more
+ /// ObjectDefinitions. If you just want to parse some
+ /// XML into a single IObjectDefinition, you may wish to consider
+ /// the simpler convenience extensions of this class, namely
+ /// and
+ ///
+ ///
+ /// Rob Harrop
+ /// Juergen Hoeller
+ /// Rick Evans
+ /// Mark Pollack (.NET)
+ public abstract class AbstractObjectDefinitionParser : IObjectDefinitionParser
+ {
+ ///
+ /// Constant for the ID attribute
+ ///
+ public static readonly string ID_ATTRIBUTE = "id";
+
+ #region Properties
+
+ ///
+ /// Gets a value indicating whether an ID should be generated instead of read
+ /// from the passed in XmlElement.
+ ///
+ /// Note that this flag is about always generating an ID; the parser
+ /// won't even check for an "id" attribute in this case.
+ ///
+ /// true if should generate id; otherwise, false.
+ protected virtual bool ShouldGenerateId
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Gets a value indicating whether an ID should be generated instead if the
+ /// passed in XmlElement does not specify an "id" attribute explicitly.
+ ///
+ /// Disabled by default; subclasses can override this to enable ID generation
+ /// as fallback: The parser will first check for an "id" attribute in this case,
+ /// only falling back to a generated ID if no value was specified.
+ ///
+ /// true if should generate id if no value was specified; otherwise, false.
+ ///
+ protected virtual bool ShouldGenerateIdAsFallback
+ {
+ get { return false; }
+ }
+
+ #endregion
+
+ #region IObjectDefinitionParser Members
+
+
+ ///
+ /// Parse the specified XmlElement and register the resulting
+ /// ObjectDefinitions with the IObjectDefinitionRegistry
+ /// embedded in the supplied
+ ///
+ /// The element to be parsed.
+ /// TThe object encapsulating the current state of the parsing process.
+ /// Provides access to a IObjectDefinitionRegistry
+ /// The primary object definition.
+ ///
+ ///
+ /// This method is never invoked if the parser is namespace aware
+ /// and was called to process the root node.
+ ///
- /// Navigates through an XML resource and invokes parsers registered
- /// with the .
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: DefaultObjectDefinitionDocumentReader.cs,v 1.9 2007/08/27 14:49:43 oakinger Exp $
- public class DefaultObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader
- {
- #region Constants
-
- ///
- /// The shared instance for this class (and derived classes).
- ///
- protected static readonly ILog log =
- LogManager.GetLogger(typeof(DefaultObjectDefinitionDocumentReader));
-
- #endregion
-
- #region Fields
-
- private XmlReaderContext readerContext;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the DefaultObjectDefinitionDocumentReader class.
- ///
- public DefaultObjectDefinitionDocumentReader()
- {
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Gets the reader context.
- ///
- /// The reader context.
- public XmlReaderContext ReaderContext
- {
- get { return readerContext; }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Read object definitions from the given DOM element, and register
- /// them with the given object registry.
- ///
- /// The DOM element containing object definitions, usually the
- /// root (document) element.
- /// The current context of the reader. Includes
- /// the resource being parsed
- ///
- /// The number of object definitions that were loaded.
- ///
- ///
- /// In case of parsing errors.
- ///
- public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext)
- {
- //int objectDefinitionCounter = 0;
-
- this.readerContext = readerContext;
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Loading object definitions.");
- }
-
- #endregion
-
- XmlElement root = doc.DocumentElement;
-
- ObjectDefinitionParserHelper parserHelper = CreateHelper(readerContext, root);
-
-
- PreProcessXml(root);
-
- ParseObjectDefinitions(root, parserHelper);
-
- PostProcessXml(root);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(
- "Found {0} <{1}> elements defining objects.",
- readerContext.Registry.ObjectDefinitionCount,
- ObjectDefinitionConstants.ObjectElement));
- }
-
- #endregion
- }
-
- ///
- /// Parses object definitions starting at the given
- /// using the passed .
- ///
- /// The root element to start parsing from.
- /// The instance to use.
- protected virtual void ParseObjectDefinitions(XmlElement root, ObjectDefinitionParserHelper helper)
- {
- foreach (XmlNode node in root.ChildNodes)
- {
- if (node.NodeType == XmlNodeType.Element)
- {
- XmlElement element = (XmlElement) node;
- INamespaceParser parser = GetNamespaceParser(element, helper);
- ParserContext parserContext = new ParserContext(helper.ReaderContext, helper);
- parser.ParseElement(element, parserContext);
- }
- }
- }
-
- ///
- /// Parses the default element.
- ///
- /// The element.
- /// The helper.
- private void ParseDefaultElement(XmlElement element, ObjectDefinitionParserHelper helper)
- {
- if (element.LocalName == ObjectDefinitionConstants.ImportElement)
- {
- ImportObjectDefinitionResource(element);
- }
- else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
- {
- ParseAlias(element, ReaderContext.Registry);
- }
- else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
- {
- RegisterObjectDefinition(element, helper);
- }
- }
-
- ///
- /// Loads external XML object definitions from the resource described by the supplied
- /// .
- ///
- /// The XML element describing the resource.
- ///
- /// If the resource could not be imported.
- ///
- protected virtual void ImportObjectDefinitionResource(XmlElement resource)
- {
- string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
- try
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Attempting to import object definitions from '{0}'.", location));
- }
-
- #endregion
-
- IResource importResource = ReaderContext.Resource.CreateRelative(location);
- ReaderContext.Reader.LoadObjectDefinitions(importResource);
- }
- catch (IOException ex)
- {
- ReaderContext.ReportException(resource, null, string.Format(
- CultureInfo.InvariantCulture,
- "Invalid relative resource location '{0}' to import object definitions from.",
- location), ex);
- }
- }
-
- ///
- /// Parses the given alias element, registering the alias with the registry.
- ///
- /// The alias element.
- /// The registry.
- protected virtual void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
- {
- string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
- registry.RegisterAlias(name, alias);
- }
-
- ///
- /// Parse an object definition and register it with the object factory..
- ///
- /// The element containing the object definition.
- /// The helper.
- ///
- protected virtual void RegisterObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper)
- {
- ObjectDefinitionHolder holder = null;
- try
- {
- INamespaceParser parser = GetNamespaceParser(element, helper);
-
- //holder = ParseObjectDefinition(element, parserContext);
- //holder = helper.ParseObjectDefinitionElement(element);
- if (holder == null)
- {
- return;
- }
- }
- catch (Exception ex)
- {
- throw new ObjectDefinitionStoreException(
- string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(
- CultureInfo.InvariantCulture,
- "Registering object definition with id '{0}'.", holder.ObjectName));
- }
-
- #endregion
-
- ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, ReaderContext.Registry);
- }
-
- ///
- ///
- /// Allow the XML to be extensible by processing any custom element types last,
- /// after we finished processing the objct definitions. This method is a natural
- /// extension point for any other custom post-processing of the XML.
- ///
- /// The default implementation is empty. Subclasses can override this method to
- /// convert custom elements into standard Spring object definitions, for example.
- /// Implementors have access to the parser's object definition reader and the
- /// underlying XML resource, through the corresponding properties.
- ///
- ///
- /// The root.
- protected virtual void PostProcessXml(XmlElement root)
- {
- }
-
- ///
- /// Allow the XML to be extensible by processing any custom element types first,
- /// before we start to process the object definitions.
- ///
- /// This method is a natural
- /// extension point for any other custom pre-processing of the XML.
- ///
The default implementation is empty. Subclasses can override this method to
- /// convert custom elements into standard Spring object definitions, for example.
- /// Implementors have access to the parser's object definition reader and the
- /// underlying XML resource, through the corresponding properties.
- ///
+ /// Navigates through an XML resource and invokes parsers registered
+ /// with the .
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public class DefaultObjectDefinitionDocumentReader : IObjectDefinitionDocumentReader
+ {
+ #region Constants
+
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ protected static readonly ILog log =
+ LogManager.GetLogger(typeof(DefaultObjectDefinitionDocumentReader));
+
+ #endregion
+
+ #region Fields
+
+ private XmlReaderContext readerContext;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the DefaultObjectDefinitionDocumentReader class.
+ ///
+ public DefaultObjectDefinitionDocumentReader()
+ {
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets the reader context.
+ ///
+ /// The reader context.
+ public XmlReaderContext ReaderContext
+ {
+ get { return readerContext; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Read object definitions from the given DOM element, and register
+ /// them with the given object registry.
+ ///
+ /// The DOM element containing object definitions, usually the
+ /// root (document) element.
+ /// The current context of the reader. Includes
+ /// the resource being parsed
+ ///
+ /// The number of object definitions that were loaded.
+ ///
+ ///
+ /// In case of parsing errors.
+ ///
+ public void RegisterObjectDefinitions(XmlDocument doc, XmlReaderContext readerContext)
+ {
+ //int objectDefinitionCounter = 0;
+
+ this.readerContext = readerContext;
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Loading object definitions.");
+ }
+
+ #endregion
+
+ XmlElement root = doc.DocumentElement;
+
+ ObjectDefinitionParserHelper parserHelper = CreateHelper(readerContext, root);
+
+
+ PreProcessXml(root);
+
+ ParseObjectDefinitions(root, parserHelper);
+
+ PostProcessXml(root);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(
+ "Found {0} <{1}> elements defining objects.",
+ readerContext.Registry.ObjectDefinitionCount,
+ ObjectDefinitionConstants.ObjectElement));
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Parses object definitions starting at the given
+ /// using the passed .
+ ///
+ /// The root element to start parsing from.
+ /// The instance to use.
+ protected virtual void ParseObjectDefinitions(XmlElement root, ObjectDefinitionParserHelper helper)
+ {
+ foreach (XmlNode node in root.ChildNodes)
+ {
+ if (node.NodeType == XmlNodeType.Element)
+ {
+ XmlElement element = (XmlElement) node;
+ INamespaceParser parser = GetNamespaceParser(element, helper);
+ ParserContext parserContext = new ParserContext(helper.ReaderContext, helper);
+ parser.ParseElement(element, parserContext);
+ }
+ }
+ }
+
+ ///
+ /// Parses the default element.
+ ///
+ /// The element.
+ /// The helper.
+ private void ParseDefaultElement(XmlElement element, ObjectDefinitionParserHelper helper)
+ {
+ if (element.LocalName == ObjectDefinitionConstants.ImportElement)
+ {
+ ImportObjectDefinitionResource(element);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
+ {
+ ParseAlias(element, ReaderContext.Registry);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
+ {
+ RegisterObjectDefinition(element, helper);
+ }
+ }
+
+ ///
+ /// Loads external XML object definitions from the resource described by the supplied
+ /// .
+ ///
+ /// The XML element describing the resource.
+ ///
+ /// If the resource could not be imported.
+ ///
+ protected virtual void ImportObjectDefinitionResource(XmlElement resource)
+ {
+ string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
+ try
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Attempting to import object definitions from '{0}'.", location));
+ }
+
+ #endregion
+
+ IResource importResource = ReaderContext.Resource.CreateRelative(location);
+ ReaderContext.Reader.LoadObjectDefinitions(importResource);
+ }
+ catch (IOException ex)
+ {
+ ReaderContext.ReportException(resource, null, string.Format(
+ CultureInfo.InvariantCulture,
+ "Invalid relative resource location '{0}' to import object definitions from.",
+ location), ex);
+ }
+ }
+
+ ///
+ /// Parses the given alias element, registering the alias with the registry.
+ ///
+ /// The alias element.
+ /// The registry.
+ protected virtual void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
+ {
+ string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
+ registry.RegisterAlias(name, alias);
+ }
+
+ ///
+ /// Parse an object definition and register it with the object factory..
+ ///
+ /// The element containing the object definition.
+ /// The helper.
+ ///
+ protected virtual void RegisterObjectDefinition(XmlElement element, ObjectDefinitionParserHelper helper)
+ {
+ ObjectDefinitionHolder holder = null;
+ try
+ {
+ INamespaceParser parser = GetNamespaceParser(element, helper);
+
+ //holder = ParseObjectDefinition(element, parserContext);
+ //holder = helper.ParseObjectDefinitionElement(element);
+ if (holder == null)
+ {
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectDefinitionStoreException(
+ string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Registering object definition with id '{0}'.", holder.ObjectName));
+ }
+
+ #endregion
+
+ ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, ReaderContext.Registry);
+ }
+
+ ///
+ ///
+ /// Allow the XML to be extensible by processing any custom element types last,
+ /// after we finished processing the objct definitions. This method is a natural
+ /// extension point for any other custom post-processing of the XML.
+ ///
+ /// The default implementation is empty. Subclasses can override this method to
+ /// convert custom elements into standard Spring object definitions, for example.
+ /// Implementors have access to the parser's object definition reader and the
+ /// underlying XML resource, through the corresponding properties.
+ ///
+ ///
+ /// The root.
+ protected virtual void PostProcessXml(XmlElement root)
+ {
+ }
+
+ ///
+ /// Allow the XML to be extensible by processing any custom element types first,
+ /// before we start to process the object definitions.
+ ///
+ /// This method is a natural
+ /// extension point for any other custom pre-processing of the XML.
+ ///
The default implementation is empty. Subclasses can override this method to
+ /// convert custom elements into standard Spring object definitions, for example.
+ /// Implementors have access to the parser's object definition reader and the
+ /// underlying XML resource, through the corresponding properties.
+ ///
- /// Does not have to be fully assembly qualified, but it is recommended
- /// that the names of one's objects are
- /// specified explicitly.
- ///
- ///
- public const string TypeAttribute = "type";
-
- ///
- /// The name or alias of the parent object definition that a child
- /// object definition inherits from.
- ///
- public const string ParentAttribute = "parent";
-
- ///
- /// Objects can be identified by an id, to enable reference checking.
- ///
- ///
- ///
- /// There are constraints on a valid XML id: if you want to reference
- /// your object in .NET code using a name that's illegal as an XML id,
- /// use the optional "name" attribute
- /// ().
- /// If neither given, the objects name is
- /// used as id.
- ///
- ///
- public const string IdAttribute = "id";
-
- ///
- /// Can be used to create one or more aliases illegal in an id.
- ///
- ///
- ///
- /// Multiple aliases can be separated by any number of spaces,
- /// semicolons, or commas
- /// ().
- ///
- ///
- /// Always optional.
- ///
- ///
- public const string NameAttribute = "name";
-
- ///
- /// Is this object a "singleton" (one shared instance, which will
- /// be returned by all calls to
- /// with the id), or a
- /// "prototype" (independent instance resulting from each call to
- /// ).
- ///
- ///
- ///
- /// Singletons are most commonly used, and are ideal for multi-threaded
- /// service objects.
- ///
- ///
- ///
- public const string SingletonAttribute = "singleton";
-
- ///
- /// Controls object scope. Only applicable to ASP.NET web applications.
- ///
- ///
- ///
- /// Scope can be defined as either application, session or request. It
- /// defines when "singleton" instances are initialized, but has no
- /// effect on prototype definitions.
- ///
- ///
- public const string ScopeAttribute = "scope";
-
- ///
- /// The names of the objects that this object depends on being
- /// initialized.
- ///
- ///
- ///
- /// The object factory will guarantee that these objects
- /// get initialized before this object definition.
- ///
- ///
- /// Dependencies are normally expressed through object properties or
- /// constructor arguments. This property should just be necessary for
- /// other kinds of dependencies such as statics (*ugh*) or database
- /// preparation on startup.
- ///
- ///
- public const string DependsOnAttribute = "depends-on";
-
- ///
- /// Optional attribute for the name of the custom initialization method
- /// to invoke after setting object properties.
- ///
- ///
- ///
- /// The method must have no arguments.
- ///
- ///
- public const string InitMethodAttribute = "init-method";
-
- ///
- /// Optional attribute for the name of the custom destroy method to
- /// invoke on object factory shutdown.
- ///
- ///
- ///
- /// Valid destroy methods have either of the following signatures...
- ///
- /// void MethodName()
- /// void MethodName(bool force)
- ///
- ///
- ///
- /// Only invoked on singleton objects!
- ///
- ///
- public const string DestroyMethodAttribute = "destroy-method";
-
- ///
- /// A constructor argument : the constructor-arg tag can have an
- /// optional type attribute, to specify the exact type of the
- /// constructor argument
- ///
- ///
- ///
- /// Only needed to avoid ambiguities, e.g. in case of 2 single
- /// argument constructors that can both be converted from a
- /// .
- ///
- ///
- public const string ConstructorArgElement = "constructor-arg";
-
- ///
- /// The constructor-arg tag can have an optional index attribute,
- /// to specify the exact index in the constructor argument list.
- ///
- ///
- ///
- /// Only needed to avoid ambiguities, e.g. in case of 2 arguments of
- /// the same type.
- ///
- ///
- public const string IndexAttribute = "index";
-
- ///
- /// The constructor-arg tag can have an optional named parameter
- /// attribute, to specify a named parameter in the constructor
- /// argument list.
- ///
- public const string ArgumentNameAttribute = "name";
-
- ///
- /// Is this object "abstract", i.e. not meant to be instantiated itself
- /// but rather just serving as parent for concrete child object
- /// definitions?
- ///
- ///
- ///
- /// Default is . Specify
- /// to tell the object factory to not try to instantiate that
- /// particular object in any case.
- ///
- ///
- public const string AbstractAttribute = "abstract";
-
- ///
- /// A property definition : object definitions can have zero or more
- /// properties.
- ///
- ///
- ///
- /// Spring.NET supports primitives, references to other objects in the
- /// same or related factories, lists, dictionaries, and name value
- /// collections.
- ///
- ///
- public const string PropertyElement = "property";
-
- ///
- /// A reference to another managed object or static
- /// .
- ///
- public const string RefElement = "ref";
-
- ///
- /// ID refs must specify a name of the target object.
- ///
- public const string IdRefElement = "idref";
-
- ///
- /// A reference to the name of another managed object in the same
- /// context.
- ///
- public const string ObjectRefAttribute = "object";
-
- ///
- /// A reference to the name of another managed object in the same
- /// context.
- ///
- ///
- ///
- /// Local references, using the "local" attribute, have to use object
- /// ids; they can be checked by a parser, thus should be preferred for
- /// references within the same object factory XML file.
- ///
- ///
- public const string LocalRefAttribute = "local";
-
- ///
- /// Alternative to type attribute for factory-method usage.
- ///
- ///
- ///
- /// If this is specified, no type attribute should be used. This should
- /// be set to the name of an object in the current or ancestor
- /// factories that contains the relevant factory method. This allows
- /// the factory itself to be configured using Dependency Injection, and
- /// an instance (rather than static) method to be used.
- ///
- ///
- public const string FactoryObjectAttribute = "factory-object";
-
- ///
- /// Optional attribute specifying the name of a factory method to use
- /// to create this object.
- ///
- ///
- ///
- /// Use constructor-arg elements to specify arguments to the factory
- /// method, if it takes arguments. Autowiring does not apply to
- /// factory methods.
- ///
- ///
- /// If the "type" attribute is present, the factory method will be a
- /// static method on the type specified by the "type" attribute on
- /// this object definition. Often this will be the same type as that
- /// of the constructed object - for example, when the factory method
- /// is used as an alternative to a constructor. However, it may be on
- /// a different type. In that case, the created object will *not* be
- /// of the type specified in the "type" attribute. This is analogous
- /// to behaviour.
- ///
- ///
- /// If the "factory-object" attribute is present, the "type" attribute
- /// is not used, and the factory method will be an instance method on
- /// the object returned from a
- ///
- /// call with the specified object name. The factory object may be
- /// defined as a singleton or a prototype.
- ///
- ///
- /// The factory method can have any number of arguments. Use indexed
- /// constructor-arg elements in conjunction with the factory-method
- /// attribute.
- ///
- ///
- /// Setter Injection can be used in conjunction with a factory method.
- /// Method Injection cannot, as the factory method returns an instance,
- /// which will be used when the container creates the object.
- ///
- ///
- public const string FactoryMethodAttribute = "factory-method";
-
- ///
- /// A list can contain multiple inner object, ref, collection, or
- /// value elements.
- ///
- ///
- ///
- /// Lists are untyped, pending generics support, although references
- /// will be strongly typed.
- ///
- ///
- /// A list can also map to an array type. The necessary conversion is
- /// automatically performed by the
- /// .
- ///
- ///
- public const string ListElement = "list";
-
- ///
- /// A set can contain multiple inner object, ref, collection, or value
- /// elements.
- ///
- ///
- ///
- /// Sets are untyped, pending generics support, although references
- /// will be strongly typed.
- ///
- ///
- public const string SetElement = "set";
-
- ///
- /// A Spring.NET map is a mapping from a string key to object (a .NET
- /// ).
- ///
- ///
- ///
- /// Dictionaries may be empty.
- ///
- ///
- public const string DictionaryElement = "dictionary";
-
- ///
- /// A lookup key (for a dictionary or name / value collection).
- ///
- public const string KeyAttribute = "key";
-
- ///
- /// A lookup key (for a dictionary or name / value collection).
- ///
- public const string KeyElement = "key";
-
- ///
- /// Contains a string representation of a value.
- ///
- ///
- ///
- /// This is used by name-value, ctor argument, and property elements.
- ///
- ///
- public const string ValueAttribute = "value";
-
- ///
- /// Contains delimiters that should be used to split delimited string values.
- ///
- ///
- ///
- /// This is used by name-value element.
- ///
- ///
- public const string DelimitersAttribute = "delimiters";
-
- ///
- /// A reference to another objects.
- ///
- ///
- ///
- /// Used as a convenience shortcut on property and constructor-arg
- /// elements to refer to other objects.
- ///
- ///
- public const string RefAttribute = "ref";
-
- ///
- /// Contains a string representation of an expression.
- ///
- ///
- ///
- /// This is used by ctor argument and property elements.
- ///
- ///
- public const string ExpressionAttribute = "expression";
-
- ///
- /// A map entry can be an inner object, ref, collection, or value.
- ///
- ///
- ///
- /// The name of the property is given by the "key" attribute.
- ///
- ///
- public const string EntryElement = "entry";
-
- ///
- /// Contains a string representation of a property value.
- ///
- ///
- ///
- /// The property may be a string, or may be converted to the
- /// required using the
- ///
- /// machinery. This makes it possible for application developers to
- /// write custom
- /// implementations that can convert strings to objects.
- ///
- ///
- /// This is recommended for simple objects only. Configure more complex
- /// objects by setting properties to references to other objects.
- ///
- ///
- public const string ValueElement = "value";
-
- ///
- /// Contains a string representation of an expression.
- ///
- public const string ExpressionElement = "expression";
-
- ///
- /// Denotes value.
- ///
- ///
- ///
- /// Necessary because an empty "value" tag will resolve to an empty
- /// , which will not be resolved to
- /// value unless a special
- /// does so.
- ///
- ///
- public const string NullElement = "null";
-
- ///
- /// 'name-values' elements differ from dictionary elements in that
- /// values must be strings.
- ///
- ///
- ///
- /// May be empty.
- ///
- ///
- public const string NameValuesElement = "name-values";
-
- ///
- /// Element content is the string value of the property.
- ///
- ///
- ///
- /// The "key" attribute is the name of the property.
- ///
- ///
- public const string AddElement = "add";
-
- ///
- /// The lazy initialization mode for an individual object definition.
- ///
- public const string LazyInitAttribute = "lazy-init";
-
- ///
- /// The dependency checking mode for an individual object definition.
- ///
- public const string DependencyCheckAttribute = "dependency-check";
-
- ///
- /// Defines a subscription to one or more events published by one or
- /// more event sources.
- ///
- public const string ListenerElement = "listener";
-
- ///
- /// The name of an event handling method.
- ///
- ///
- ///
- /// Defaults to On${event}.
- /// Note : this default will probably change before the first 1.0
- /// release.
- ///
- ///
- public const string ListenerMethodAttribute = "method";
-
- ///
- /// The name of an event.
- ///
- public const string ListenerEventAttribute = "event";
-
- ///
- /// The autowiring mode for an individual object definition.
- ///
- public const string AutowireAttribute = "autowire";
-
- ///
- /// Shortcut alternative to specifying a key element in a
- /// dictionary entry element with <ref object="..."/>.
- ///
- public const string DictionaryKeyRefShortcutAttribute = "key-ref";
-
- ///
- /// Shortcut alternative to specifying a value element in a
- /// dictionary entry element with <ref object="..."/>.
- ///
- public const string DictionaryValueRefShortcutAttribute = "value-ref";
-
- ///
- /// The string of characters that delimit object names.
- ///
- public const string ObjectNameDelimiters = ",; ";
-
- ///
- /// A lookup method causes the IoC container to override a given method and return
- /// the object with the name given in the attendant object attribute.
- ///
- ///
- ///
- /// This is a form of Method Injection.
- ///
- ///
- /// It's particularly useful as an alternative to implementing the
- /// interface,
- /// in order to be able to make
- ///
- /// calls for non-singleton instances at runtime. In this case, Method Injection
- /// is a less invasive alternative.
- ///
- ///
- public const string LookupMethodElement = "lookup-method";
-
- ///
- /// The name of a lookup method. This method must take no arguments.
- ///
- public const string LookupMethodNameAttribute = "name";
-
- ///
- /// The name of the object in the IoC container that the lookup method
- /// must resolve to.
- ///
- ///
- ///
- /// Often this object will be a prototype, in which case the lookup method
- /// will return a distinct instance on every invocation. This is useful
- /// for single-threaded objects.
- ///
- ///
- public const string LookupMethodObjectNameAttribute = "object";
-
- ///
- /// A replaced method causes the IoC container to override a given method
- /// with an (arbitrary) implementation at runtime.
- ///
- ///
- ///
- /// This (again) is a form of Method Injection.
- ///
- ///
- public const string ReplacedMethodElement = "replaced-method";
-
- ///
- /// Name of the method whose implementation should be replaced by the
- /// IoC container.
- ///
- ///
- ///
- /// If this method is not overloaded, there's no need to use arg-type
- /// subelements.
- ///
- ///
- /// If this method is overloaded, arg-type subelements must be
- /// used for all override definitions for the method.
- ///
- ///
- public const string ReplacedMethodNameAttribute = "name";
-
- ///
- /// The object name of an implementation of the
- /// interface.
- ///
- ///
- ///
- /// This may be a singleton or prototype. If it's a prototype, a new
- /// instance will be used for each method replacement. Singleton usage
- /// is the norm.
- ///
- ///
- public const string ReplacedMethodReplacerNameAttribute = "replacer";
-
- ///
- /// Subelement of replaced-method identifying an argument for a
- /// replaced method in the event of method overloading.
- ///
- ///
- public const string ReplacedMethodArgumentTypeElement = "arg-type";
-
- ///
- /// Specification of the of an overloaded method
- /// argument as a .
- ///
- ///
- ///
- /// For convenience, this may be a substring of the FQN. E.g. all the following would match
- /// :
- ///
+ /// Does not have to be fully assembly qualified, but it is recommended
+ /// that the names of one's objects are
+ /// specified explicitly.
+ ///
+ ///
+ public const string TypeAttribute = "type";
+
+ ///
+ /// The name or alias of the parent object definition that a child
+ /// object definition inherits from.
+ ///
+ public const string ParentAttribute = "parent";
+
+ ///
+ /// Objects can be identified by an id, to enable reference checking.
+ ///
+ ///
+ ///
+ /// There are constraints on a valid XML id: if you want to reference
+ /// your object in .NET code using a name that's illegal as an XML id,
+ /// use the optional "name" attribute
+ /// ().
+ /// If neither given, the objects name is
+ /// used as id.
+ ///
+ ///
+ public const string IdAttribute = "id";
+
+ ///
+ /// Can be used to create one or more aliases illegal in an id.
+ ///
+ ///
+ ///
+ /// Multiple aliases can be separated by any number of spaces,
+ /// semicolons, or commas
+ /// ().
+ ///
+ ///
+ /// Always optional.
+ ///
+ ///
+ public const string NameAttribute = "name";
+
+ ///
+ /// Is this object a "singleton" (one shared instance, which will
+ /// be returned by all calls to
+ /// with the id), or a
+ /// "prototype" (independent instance resulting from each call to
+ /// ).
+ ///
+ ///
+ ///
+ /// Singletons are most commonly used, and are ideal for multi-threaded
+ /// service objects.
+ ///
+ ///
+ ///
+ public const string SingletonAttribute = "singleton";
+
+ ///
+ /// Controls object scope. Only applicable to ASP.NET web applications.
+ ///
+ ///
+ ///
+ /// Scope can be defined as either application, session or request. It
+ /// defines when "singleton" instances are initialized, but has no
+ /// effect on prototype definitions.
+ ///
+ ///
+ public const string ScopeAttribute = "scope";
+
+ ///
+ /// The names of the objects that this object depends on being
+ /// initialized.
+ ///
+ ///
+ ///
+ /// The object factory will guarantee that these objects
+ /// get initialized before this object definition.
+ ///
+ ///
+ /// Dependencies are normally expressed through object properties or
+ /// constructor arguments. This property should just be necessary for
+ /// other kinds of dependencies such as statics (*ugh*) or database
+ /// preparation on startup.
+ ///
+ ///
+ public const string DependsOnAttribute = "depends-on";
+
+ ///
+ /// Optional attribute for the name of the custom initialization method
+ /// to invoke after setting object properties.
+ ///
+ ///
+ ///
+ /// The method must have no arguments.
+ ///
+ ///
+ public const string InitMethodAttribute = "init-method";
+
+ ///
+ /// Optional attribute for the name of the custom destroy method to
+ /// invoke on object factory shutdown.
+ ///
+ ///
+ ///
+ /// Valid destroy methods have either of the following signatures...
+ ///
+ /// void MethodName()
+ /// void MethodName(bool force)
+ ///
+ ///
+ ///
+ /// Only invoked on singleton objects!
+ ///
+ ///
+ public const string DestroyMethodAttribute = "destroy-method";
+
+ ///
+ /// A constructor argument : the constructor-arg tag can have an
+ /// optional type attribute, to specify the exact type of the
+ /// constructor argument
+ ///
+ ///
+ ///
+ /// Only needed to avoid ambiguities, e.g. in case of 2 single
+ /// argument constructors that can both be converted from a
+ /// .
+ ///
+ ///
+ public const string ConstructorArgElement = "constructor-arg";
+
+ ///
+ /// The constructor-arg tag can have an optional index attribute,
+ /// to specify the exact index in the constructor argument list.
+ ///
+ ///
+ ///
+ /// Only needed to avoid ambiguities, e.g. in case of 2 arguments of
+ /// the same type.
+ ///
+ ///
+ public const string IndexAttribute = "index";
+
+ ///
+ /// The constructor-arg tag can have an optional named parameter
+ /// attribute, to specify a named parameter in the constructor
+ /// argument list.
+ ///
+ public const string ArgumentNameAttribute = "name";
+
+ ///
+ /// Is this object "abstract", i.e. not meant to be instantiated itself
+ /// but rather just serving as parent for concrete child object
+ /// definitions?
+ ///
+ ///
+ ///
+ /// Default is . Specify
+ /// to tell the object factory to not try to instantiate that
+ /// particular object in any case.
+ ///
+ ///
+ public const string AbstractAttribute = "abstract";
+
+ ///
+ /// A property definition : object definitions can have zero or more
+ /// properties.
+ ///
+ ///
+ ///
+ /// Spring.NET supports primitives, references to other objects in the
+ /// same or related factories, lists, dictionaries, and name value
+ /// collections.
+ ///
+ ///
+ public const string PropertyElement = "property";
+
+ ///
+ /// A reference to another managed object or static
+ /// .
+ ///
+ public const string RefElement = "ref";
+
+ ///
+ /// ID refs must specify a name of the target object.
+ ///
+ public const string IdRefElement = "idref";
+
+ ///
+ /// A reference to the name of another managed object in the same
+ /// context.
+ ///
+ public const string ObjectRefAttribute = "object";
+
+ ///
+ /// A reference to the name of another managed object in the same
+ /// context.
+ ///
+ ///
+ ///
+ /// Local references, using the "local" attribute, have to use object
+ /// ids; they can be checked by a parser, thus should be preferred for
+ /// references within the same object factory XML file.
+ ///
+ ///
+ public const string LocalRefAttribute = "local";
+
+ ///
+ /// Alternative to type attribute for factory-method usage.
+ ///
+ ///
+ ///
+ /// If this is specified, no type attribute should be used. This should
+ /// be set to the name of an object in the current or ancestor
+ /// factories that contains the relevant factory method. This allows
+ /// the factory itself to be configured using Dependency Injection, and
+ /// an instance (rather than static) method to be used.
+ ///
+ ///
+ public const string FactoryObjectAttribute = "factory-object";
+
+ ///
+ /// Optional attribute specifying the name of a factory method to use
+ /// to create this object.
+ ///
+ ///
+ ///
+ /// Use constructor-arg elements to specify arguments to the factory
+ /// method, if it takes arguments. Autowiring does not apply to
+ /// factory methods.
+ ///
+ ///
+ /// If the "type" attribute is present, the factory method will be a
+ /// static method on the type specified by the "type" attribute on
+ /// this object definition. Often this will be the same type as that
+ /// of the constructed object - for example, when the factory method
+ /// is used as an alternative to a constructor. However, it may be on
+ /// a different type. In that case, the created object will *not* be
+ /// of the type specified in the "type" attribute. This is analogous
+ /// to behaviour.
+ ///
+ ///
+ /// If the "factory-object" attribute is present, the "type" attribute
+ /// is not used, and the factory method will be an instance method on
+ /// the object returned from a
+ ///
+ /// call with the specified object name. The factory object may be
+ /// defined as a singleton or a prototype.
+ ///
+ ///
+ /// The factory method can have any number of arguments. Use indexed
+ /// constructor-arg elements in conjunction with the factory-method
+ /// attribute.
+ ///
+ ///
+ /// Setter Injection can be used in conjunction with a factory method.
+ /// Method Injection cannot, as the factory method returns an instance,
+ /// which will be used when the container creates the object.
+ ///
+ ///
+ public const string FactoryMethodAttribute = "factory-method";
+
+ ///
+ /// A list can contain multiple inner object, ref, collection, or
+ /// value elements.
+ ///
+ ///
+ ///
+ /// Lists are untyped, pending generics support, although references
+ /// will be strongly typed.
+ ///
+ ///
+ /// A list can also map to an array type. The necessary conversion is
+ /// automatically performed by the
+ /// .
+ ///
+ ///
+ public const string ListElement = "list";
+
+ ///
+ /// A set can contain multiple inner object, ref, collection, or value
+ /// elements.
+ ///
+ ///
+ ///
+ /// Sets are untyped, pending generics support, although references
+ /// will be strongly typed.
+ ///
+ ///
+ public const string SetElement = "set";
+
+ ///
+ /// A Spring.NET map is a mapping from a string key to object (a .NET
+ /// ).
+ ///
+ ///
+ ///
+ /// Dictionaries may be empty.
+ ///
+ ///
+ public const string DictionaryElement = "dictionary";
+
+ ///
+ /// A lookup key (for a dictionary or name / value collection).
+ ///
+ public const string KeyAttribute = "key";
+
+ ///
+ /// A lookup key (for a dictionary or name / value collection).
+ ///
+ public const string KeyElement = "key";
+
+ ///
+ /// Contains a string representation of a value.
+ ///
+ ///
+ ///
+ /// This is used by name-value, ctor argument, and property elements.
+ ///
+ ///
+ public const string ValueAttribute = "value";
+
+ ///
+ /// Contains delimiters that should be used to split delimited string values.
+ ///
+ ///
+ ///
+ /// This is used by name-value element.
+ ///
+ ///
+ public const string DelimitersAttribute = "delimiters";
+
+ ///
+ /// A reference to another objects.
+ ///
+ ///
+ ///
+ /// Used as a convenience shortcut on property and constructor-arg
+ /// elements to refer to other objects.
+ ///
+ ///
+ public const string RefAttribute = "ref";
+
+ ///
+ /// Contains a string representation of an expression.
+ ///
+ ///
+ ///
+ /// This is used by ctor argument and property elements.
+ ///
+ ///
+ public const string ExpressionAttribute = "expression";
+
+ ///
+ /// A map entry can be an inner object, ref, collection, or value.
+ ///
+ ///
+ ///
+ /// The name of the property is given by the "key" attribute.
+ ///
+ ///
+ public const string EntryElement = "entry";
+
+ ///
+ /// Contains a string representation of a property value.
+ ///
+ ///
+ ///
+ /// The property may be a string, or may be converted to the
+ /// required using the
+ ///
+ /// machinery. This makes it possible for application developers to
+ /// write custom
+ /// implementations that can convert strings to objects.
+ ///
+ ///
+ /// This is recommended for simple objects only. Configure more complex
+ /// objects by setting properties to references to other objects.
+ ///
+ ///
+ public const string ValueElement = "value";
+
+ ///
+ /// Contains a string representation of an expression.
+ ///
+ public const string ExpressionElement = "expression";
+
+ ///
+ /// Denotes value.
+ ///
+ ///
+ ///
+ /// Necessary because an empty "value" tag will resolve to an empty
+ /// , which will not be resolved to
+ /// value unless a special
+ /// does so.
+ ///
+ ///
+ public const string NullElement = "null";
+
+ ///
+ /// 'name-values' elements differ from dictionary elements in that
+ /// values must be strings.
+ ///
+ ///
+ ///
+ /// May be empty.
+ ///
+ ///
+ public const string NameValuesElement = "name-values";
+
+ ///
+ /// Element content is the string value of the property.
+ ///
+ ///
+ ///
+ /// The "key" attribute is the name of the property.
+ ///
+ ///
+ public const string AddElement = "add";
+
+ ///
+ /// The lazy initialization mode for an individual object definition.
+ ///
+ public const string LazyInitAttribute = "lazy-init";
+
+ ///
+ /// The dependency checking mode for an individual object definition.
+ ///
+ public const string DependencyCheckAttribute = "dependency-check";
+
+ ///
+ /// Defines a subscription to one or more events published by one or
+ /// more event sources.
+ ///
+ public const string ListenerElement = "listener";
+
+ ///
+ /// The name of an event handling method.
+ ///
+ ///
+ ///
+ /// Defaults to On${event}.
+ /// Note : this default will probably change before the first 1.0
+ /// release.
+ ///
+ ///
+ public const string ListenerMethodAttribute = "method";
+
+ ///
+ /// The name of an event.
+ ///
+ public const string ListenerEventAttribute = "event";
+
+ ///
+ /// The autowiring mode for an individual object definition.
+ ///
+ public const string AutowireAttribute = "autowire";
+
+ ///
+ /// Shortcut alternative to specifying a key element in a
+ /// dictionary entry element with <ref object="..."/>.
+ ///
+ public const string DictionaryKeyRefShortcutAttribute = "key-ref";
+
+ ///
+ /// Shortcut alternative to specifying a value element in a
+ /// dictionary entry element with <ref object="..."/>.
+ ///
+ public const string DictionaryValueRefShortcutAttribute = "value-ref";
+
+ ///
+ /// The string of characters that delimit object names.
+ ///
+ public const string ObjectNameDelimiters = ",; ";
+
+ ///
+ /// A lookup method causes the IoC container to override a given method and return
+ /// the object with the name given in the attendant object attribute.
+ ///
+ ///
+ ///
+ /// This is a form of Method Injection.
+ ///
+ ///
+ /// It's particularly useful as an alternative to implementing the
+ /// interface,
+ /// in order to be able to make
+ ///
+ /// calls for non-singleton instances at runtime. In this case, Method Injection
+ /// is a less invasive alternative.
+ ///
+ ///
+ public const string LookupMethodElement = "lookup-method";
+
+ ///
+ /// The name of a lookup method. This method must take no arguments.
+ ///
+ public const string LookupMethodNameAttribute = "name";
+
+ ///
+ /// The name of the object in the IoC container that the lookup method
+ /// must resolve to.
+ ///
+ ///
+ ///
+ /// Often this object will be a prototype, in which case the lookup method
+ /// will return a distinct instance on every invocation. This is useful
+ /// for single-threaded objects.
+ ///
+ ///
+ public const string LookupMethodObjectNameAttribute = "object";
+
+ ///
+ /// A replaced method causes the IoC container to override a given method
+ /// with an (arbitrary) implementation at runtime.
+ ///
+ ///
+ ///
+ /// This (again) is a form of Method Injection.
+ ///
+ ///
+ public const string ReplacedMethodElement = "replaced-method";
+
+ ///
+ /// Name of the method whose implementation should be replaced by the
+ /// IoC container.
+ ///
+ ///
+ ///
+ /// If this method is not overloaded, there's no need to use arg-type
+ /// subelements.
+ ///
+ ///
+ /// If this method is overloaded, arg-type subelements must be
+ /// used for all override definitions for the method.
+ ///
+ ///
+ public const string ReplacedMethodNameAttribute = "name";
+
+ ///
+ /// The object name of an implementation of the
+ /// interface.
+ ///
+ ///
+ ///
+ /// This may be a singleton or prototype. If it's a prototype, a new
+ /// instance will be used for each method replacement. Singleton usage
+ /// is the norm.
+ ///
+ ///
+ public const string ReplacedMethodReplacerNameAttribute = "replacer";
+
+ ///
+ /// Subelement of replaced-method identifying an argument for a
+ /// replaced method in the event of method overloading.
+ ///
+ ///
+ public const string ReplacedMethodArgumentTypeElement = "arg-type";
+
+ ///
+ /// Specification of the of an overloaded method
+ /// argument as a .
+ ///
+ ///
+ ///
+ /// For convenience, this may be a substring of the FQN. E.g. all the following would match
+ /// :
+ ///
- /// Applications will typically want to use an
- /// , and instantiate it
- /// via the use of the
- /// class (which is similar in functionality to this class). This class is
- /// provided for those times when only an
- /// is required.
- ///
- /// Creates an instance of the class XmlObjectFactory
- ///
- ///
- ///
+ /// Applications will typically want to use an
+ /// , and instantiate it
+ /// via the use of the
+ /// class (which is similar in functionality to this class). This class is
+ /// provided for those times when only an
+ /// is required.
+ ///
+ /// Creates an instance of the class XmlObjectFactory
+ ///
+ ///
+ ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: ObjectsNamespaceParser.cs,v 1.7 2007/11/26 14:15:54 bbaia Exp $
- [
- NamespaceParser(
- Namespace = "http://www.springframework.net",
- SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser),
- SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-1.1.xsd"
- )
- ]
- public class ObjectsNamespaceParser : INamespaceParser
- {
- ///
- /// The namespace URI for the standard Spring.NET object definition schema.
- ///
- public const string Namespace = "http://www.springframework.net";
-
- ///
- /// The shared instance for this class (and derived classes).
- ///
- protected static readonly ILog log =
- LogManager.GetLogger(typeof(ObjectsNamespaceParser));
-
- #region IXmlObjectDefinitionParser Members
-
- ///
- /// Invoked by after construction but before any
- /// elements have been parsed.
- ///
- /// This is a NoOp
- public void Init()
- {
-
- }
-
- #endregion
-
-
- ///
- /// Parse the specified element and register any resulting
- /// IObjectDefinitions with the IObjectDefinitionRegistry that is
- /// embedded in the supplied ParserContext.
- ///
- /// The element to be parsed into one or more IObjectDefinitions
- /// The object encapsulating the current state of the parsing
- /// process.
- ///
- /// The primary IObjectDefinition (can be null as explained above)
- ///
- ///
- /// Implementations should return the primary IObjectDefinition
- /// that results from the parse phase if they wish to used nested
- /// inside (for example) a <property> tag.
- /// Implementations may return null if they will not
- /// be used in a nested scenario.
- ///
- ///
- public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
- {
-
- if (element.LocalName == ObjectDefinitionConstants.ImportElement)
- {
- ImportObjectDefinitionResource(element, parserContext);
- }
- else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
- {
- ParseAlias(element, parserContext.ReaderContext.Registry);
- }
- else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
- {
- RegisterObjectDefinition(element, parserContext);
- }
-
- return null;
- }
-
-
- ///
- /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder,
- /// returning the decorated definition.
- ///
- /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on
- /// whether a custom attribute or element is being parsed.
- /// Implementations may choose to return a completely new definition,
- /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory.
- ///
- /// The supplied ParserContext can be used to register any additional objects needed to support
- /// the main definition.
- ///
- /// The source element or attribute that is to be parsed.
- /// The current object definition.
- /// The object encapsulating the current state of the parsing
- /// process.
- /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory),
- /// or simply the original object definition if no decoration is required. A null value is strickly
- /// speaking invalid, but will leniently treated like the case where the original object definition
- /// gets returned.
- public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition,
- ParserContext parserContext)
- {
- return null;
- }
-
- private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
- {
- string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
- registry.RegisterAlias(name, alias);
- }
-
-
-
-
- ///
- /// Loads external XML object definitions from the resource described by the supplied
- /// .
- ///
- /// The XML element describing the resource.
- /// The parser context.
- ///
- /// If the resource could not be imported.
- ///
- protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext)
- {
- string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
- try
- {
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- CultureInfo.InvariantCulture,
- "Attempting to import object definitions from '{0}'.", location));
- }
-
- #endregion
-
- IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location);
- parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource);
- }
- catch (IOException ex)
- {
- parserContext.ReaderContext.ReportException(resource, null, string.Format(
- CultureInfo.InvariantCulture,
- "Invalid relative resource location '{0}' to import object definitions from.",
- location), ex);
- }
- }
-
-
- /// Parses an event listener definition.
- ///
- /// The name associated with the object that the event handler is being defined on.
- ///
- /// The events being populated.
- ///
- /// The element containing the event listener definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual void ParseEventListenerDefinition(
- string name, EventValues events, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- // get an appropriate IEventHandlerValue instance based upon the
- // attribute values of the listener element...
- IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue(
- element.GetAttribute(ObjectDefinitionConstants.ListenerMethodAttribute),
- element.GetAttribute(ObjectDefinitionConstants.ListenerEventAttribute));
-
- // and then get the source of the event (another managed object instance
- // or a Type reference (i.e. a static event exposed on a class)...
- XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement;
-
- XmlAttribute sourceAtt = sourceElement.Attributes[0];
- if (StringUtils.IsNullOrEmpty(sourceAtt.Value))
- {
- parserHelper.ReaderContext.ReportFatalException(sourceElement, string.Format(
- CultureInfo.InvariantCulture,
- "The single attribute of the <{0}/> element cannot be empty. Specify the " +
- "object id (alias) or the full, assembly qualified Type name that is the " +
- "source of the event.",
- ObjectDefinitionConstants.RefElement));
- return;
- }
- switch (sourceAtt.LocalName)
- {
- case ObjectDefinitionConstants.LocalRefAttribute:
- case ObjectDefinitionConstants.ObjectRefAttribute:
- // we're wiring up to an event exposed on another managed object (instance)
- RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value);
- myHandler.Source = ror;
- break;
- case ObjectDefinitionConstants.TypeAttribute:
- // we're wiring up to a static event exposed on a Type (class)
- myHandler.Source = parserHelper.ReaderContext.Reader.Domain == null ?
- (object) sourceAtt.Value :
- (object)TypeResolutionUtils.ResolveType(sourceAtt.Value);
- break;
- }
- events.AddHandler(myHandler);
- }
-
-
-
- ///
- /// Parse an object definition and register it with the object factory..
- ///
- /// The element containing the object definition.
- /// The parser context.
- ///
- protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext)
- {
- ObjectDefinitionHolder holder = null;
- try
- {
- holder = ParseObjectDefinition(element, parserContext);
- if (holder == null)
- {
- return;
- }
- }
- catch (Exception ex)
- {
- throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
- }
-
-
- holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(
- string.Format(
- CultureInfo.InvariantCulture,
- "Registering object definition with id '{0}'.", holder.ObjectName));
- }
-
- #endregion
-
- ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry);
- }
-
-
- ///
- /// Parse a standard object definition into a
- /// ,
- /// including object name and aliases.
- ///
- /// The element containing the object definition.
- /// The parser context.
- ///
- /// The object (definition) wrapped within an
- ///
- /// instance.
- ///
- ///
- ///
- /// Object elements specify their canonical name via the "id" attribute
- /// and their aliases as a delimited "name" attribute.
- ///
- ///
- /// If no "id" is specified, uses the first name in the "name" attribute
- /// as the canonical name, registering all others as aliases.
- ///
- ///
- protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext)
- {
- string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
- string name = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- ArrayList aliases = new ArrayList();
- if (StringUtils.HasText(name))
- {
- aliases.AddRange(GetObjectNames(name));
- }
- // if we ain't got an id, check if object is page definition or assign any existing (first) alias...
- if (StringUtils.IsNullOrEmpty(id))
- {
- id = CalculateId(element, aliases);
- }
-
-
- IConfigurableObjectDefinition definition = ParseObjectDefinition(element, id, parserContext.ParserHelper);
- if (StringUtils.IsNullOrEmpty(id))
- {
- id = ObjectDefinitionReaderUtils.GenerateObjectName(definition, parserContext.Registry);
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format(
- "Neither XML '{0}' nor '{1}' specified - using object " +
- "class name [{2}] as the id.",
- id, ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute));
- }
-
- #endregion
- }
- string[] aliasesArray = (string[]) aliases.ToArray(typeof(string));
- return new ObjectDefinitionHolder(definition, id, aliasesArray);
- }
-
- ///
- /// Calculates an id for an object definition.
- ///
- ///
- ///
- /// Called when an object definition has not been explicitly defined
- /// with an id.
- ///
- ///
- ///
- /// The element containing the object definition.
- ///
- ///
- /// The list of names defined for the object; may be
- /// or even empty.
- ///
- ///
- /// A calculated object definition id.
- ///
- protected virtual string CalculateId(XmlElement element, ArrayList aliases)
- {
- string id = null;
- if (aliases.Count > 0)
- {
- string firstAlias = aliases[0] as string;
- aliases.RemoveAt(0);
- id = firstAlias;
- }
-
- #region Instrumentation
-
- if (log.IsDebugEnabled)
- {
- StringBuilder buffer = new StringBuilder();
- foreach (string alias in aliases)
- {
- buffer.Append(alias).Append(",");
- }
- log.Debug(string.Format("No XML 'id' specified - using '{0}' as the id and '{1}' as aliases.",
- id, buffer.ToString()));
- }
-
- #endregion
-
- return id;
- }
-
- ///
- /// Parse a standard object definition.
- ///
- /// The element containing the object definition.
- /// The id of the object definition.
- /// parsing state holder
- /// The object (definition).
- protected virtual IConfigurableObjectDefinition ParseObjectDefinition(
- XmlElement element, string id, ObjectDefinitionParserHelper parserHelper)
- {
- string typeName = null;
- try
- {
- if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute))
- {
- typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- if (StringUtils.IsNullOrEmpty(typeName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, id,
- "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + typeName + "'.");
- }
- }
- string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
-
-
- AbstractObjectDefinition od
- = parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
- typeName, parent, parserHelper.ReaderContext.Reader.Domain);
-
-
- MutablePropertyValues pvs = GetPropertyValueSubElements(id, element, parserHelper);
- ConstructorArgumentValues arguments
- = GetConstructorArgSubElements(id, element, parserHelper);
- EventValues events = GetEventHandlerSubElements(id, element, parserHelper);
- MethodOverrides methodOverrides = GetMethodOverrideSubElements(id, element, parserHelper);
-
- bool isPage = StringUtils.HasText(typeName) && typeName!= null && typeName.ToLower().EndsWith(".aspx");
- if (!isPage)
- {
- od.ConstructorArgumentValues = arguments;
- }
-
- od.PropertyValues = pvs;
- od.MethodOverrides = methodOverrides;
- od.EventHandlerValues = events;
- if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute))
- {
- string dependsOn = element.GetAttribute(ObjectDefinitionConstants.DependsOnAttribute);
- od.DependsOn = GetObjectNames(dependsOn);
- }
- od.FactoryMethodName = element.GetAttribute(ObjectDefinitionConstants.FactoryMethodAttribute);
- od.FactoryObjectName = element.GetAttribute(ObjectDefinitionConstants.FactoryObjectAttribute);
- string dependencyCheck = element.GetAttribute(ObjectDefinitionConstants.DependencyCheckAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck))
- {
- dependencyCheck = parserHelper.Defaults.DependencyCheck;
- }
- od.DependencyCheck = GetDependencyCheck(dependencyCheck);
- string autowire = element.GetAttribute(ObjectDefinitionConstants.AutowireAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(autowire))
- {
- autowire = parserHelper.Defaults.Autowire;
- }
- od.AutowireMode = GetAutowireMode(autowire);
- string initMethodName = element.GetAttribute(ObjectDefinitionConstants.InitMethodAttribute);
- if (StringUtils.HasText(initMethodName))
- {
- od.InitMethodName = initMethodName;
- }
- string destroyMethodName = element.GetAttribute(ObjectDefinitionConstants.DestroyMethodAttribute);
- if (StringUtils.HasText(destroyMethodName))
- {
- od.DestroyMethodName = destroyMethodName;
- }
- if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute))
- {
- od.IsSingleton = IsTrueStringValue(element.GetAttribute(ObjectDefinitionConstants.SingletonAttribute).ToLower(CultureInfo.CurrentCulture));
- }
- string lazyInit = element.GetAttribute(ObjectDefinitionConstants.LazyInitAttribute);
- if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton)
- {
- // just apply default to singletons, as lazy-init has no meaning for prototypes...
- lazyInit = parserHelper.Defaults.LazyInit;
- }
- od.IsLazyInit = IsTrueStringValue(lazyInit);
-
- // try to get the line info
- string resourceDescription = parserHelper.ReaderContext.Resource.Description;
- if (StringUtils.HasText(resourceDescription))
- {
- int line = ConfigurationUtils.GetLineNumber(element);
- if (line > 0)
- {
- resourceDescription += " line " + line;
- }
- }
- od.ResourceDescription = resourceDescription;
-
- string isAbstract = element.GetAttribute(ObjectDefinitionConstants.AbstractAttribute);
- if (StringUtils.HasText(isAbstract))
- {
- od.IsAbstract = IsTrueStringValue(isAbstract);
- }
- return od;
- }
- catch (TypeLoadException ex)
- {
- parserHelper.ReaderContext.ReportException(
- element,
- id,
- string.Format(
- "Object class [{0}] not found.",
- typeName),
- ex);
- }
- catch (ApplicationException ex)
- {
- parserHelper.ReaderContext.ReportException(element, id, string.Empty, ex);
- }
- return null;
- }
-
- ///
- /// Parse method override argument subelements of the given object element.
- ///
- protected MethodOverrides GetMethodOverrideSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- MethodOverrides overrides = new MethodOverrides();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement))
- {
- ParseLookupMethodElement(name, overrides, (XmlElement) node, parserHelper);
- }
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement))
- {
- ParseReplacedMethodElement(name, overrides, (XmlElement) node, parserHelper);
- }
- return overrides;
- }
-
- ///
- /// Parse element and add parsed element to
- ///
- protected void ParseLookupMethodElement(
- string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string methodName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodNameAttribute);
- string targetObjectName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodObjectNameAttribute);
- if (StringUtils.IsNullOrEmpty(methodName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
- }
- if (StringUtils.IsNullOrEmpty(targetObjectName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
- }
- overrides.Add(new LookupMethodOverride(methodName, targetObjectName));
- }
-
- ///
- /// Parse element and add parsed element to
- ///
- protected void ParseReplacedMethodElement(
- string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string methodName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodNameAttribute);
- string targetReplacerObjectName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute);
- if (StringUtils.IsNullOrEmpty(methodName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
- }
- if (StringUtils.IsNullOrEmpty(targetReplacerObjectName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
- }
- ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName);
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement))
- {
- XmlElement argElement = (XmlElement) node;
- string match = argElement.GetAttribute(ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute);
- if (StringUtils.IsNullOrEmpty(match))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("The '{0}' attribute is required for the '{1}' element.",
- ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement));
- }
- theOverride.AddTypeIdentifier(match);
- }
- overrides.Add(theOverride);
- }
-
- ///
- /// Parse constructor argument subelements of the given object element.
- ///
- protected ConstructorArgumentValues GetConstructorArgSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- ConstructorArgumentValues arguments = new ConstructorArgumentValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement))
- {
- ParseConstructorArgElement(name, arguments, (XmlElement) node, parserHelper);
- }
- return arguments;
- }
-
- ///
- /// Parse event handler subelements of the given object element.
- ///
- protected EventValues GetEventHandlerSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- EventValues events = new EventValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement))
- {
- ParseEventListenerDefinition(name, events, (XmlElement) node, parserHelper);
- }
- return events;
- }
-
- ///
- /// Parse property value subelements of the given object element.
- ///
- ///
- /// The name of the object (definition) associated with the property element (s)
- ///
- ///
- /// The element containing the top level object definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- ///
- /// The property (s) associated with the object (definition).
- ///
- protected virtual MutablePropertyValues GetPropertyValueSubElements(
- string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- MutablePropertyValues properties = new MutablePropertyValues();
- foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement))
- {
- ParsePropertyElement(name, properties, (XmlElement) node, parserHelper);
- }
- return properties;
- }
-
- ///
- /// Parse a constructor-arg element.
- ///
- ///
- /// The name of the object (definition) associated with the ctor arg.
- ///
- ///
- /// The list of constructor args associated with the object (definition).
- ///
- ///
- /// The name of the element containing the ctor arg definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual void ParseConstructorArgElement(
- string name, ConstructorArgumentValues arguments, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- object val = GetPropertyValue(element, name, parserHelper);
- string indexAttr = element.GetAttribute(ObjectDefinitionConstants.IndexAttribute);
- string typeAttr = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- string nameAttr = element.GetAttribute(ObjectDefinitionConstants.ArgumentNameAttribute);
-
- // only one of the 'index' or 'name' attributes can be present
- if (StringUtils.HasText(indexAttr)
- && StringUtils.HasText(nameAttr))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "Only one of the 'index' or 'name' attributes can be present per constructor argument.");
- }
- if (StringUtils.HasText(indexAttr))
- {
- try
- {
- int index = int.Parse(indexAttr, CultureInfo.CurrentCulture);
- if (index < 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "'index' cannot be lower than 0");
- }
- if (StringUtils.HasText(typeAttr))
- {
- arguments.AddIndexedArgumentValue(index, val, typeAttr);
- }
- else
- {
- arguments.AddIndexedArgumentValue(index, val);
- }
- }
- catch (FormatException)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- "Attribute 'index' of tag 'constructor-arg' must be an integer value.");
- }
- }
- else if (StringUtils.HasText(nameAttr))
- {
- if (StringUtils.HasText(typeAttr))
- {
- if (log.IsWarnEnabled)
- {
- log.Warn("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element.");
- }
- }
- arguments.AddNamedArgumentValue(nameAttr, val);
- }
- else
- {
- if (StringUtils.HasText(typeAttr))
- {
- arguments.AddGenericArgumentValue(val, typeAttr);
- }
- else
- {
- arguments.AddGenericArgumentValue(val);
- }
- }
- }
-
- ///
- /// Parse a property element.
- ///
- ///
- /// The name of the object (definition) associated with the property.
- ///
- ///
- /// The list of properties associated with the object (definition).
- ///
- ///
- /// The name of the element containing the property definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected void ParsePropertyElement(
- string name, MutablePropertyValues properties, XmlElement element, ObjectDefinitionParserHelper parserHelper)
- {
- string propertyName = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
- if (StringUtils.IsNullOrEmpty(propertyName))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "The 'property' element must have a 'name' attribute");
- }
- object val = GetPropertyValue(element, name, parserHelper);
- properties.Add(new PropertyValue(propertyName, val));
- }
-
- ///
- /// Get the value of a property element (may be a list).
- ///
- ///
- /// Please note that even though this method is named GetPropertyValue,
- /// it is called by both the property and constructor argument element
- /// handlers.
- ///
- ///
- /// The property element.
- ///
- /// The name of the object associated with the property.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual object GetPropertyValue(
- XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute];
- if (inlineValueAtt != null)
- {
- return inlineValueAtt.Value;
- }
- XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute];
- if (inlineRefAtt != null)
- {
- return new RuntimeObjectReference(inlineRefAtt.Value);
- }
- XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
- if (inlineExpressionAtt != null)
- {
- return new ExpressionHolder(inlineExpressionAtt.Value);
- }
-
- // should only have one element child: value, ref, collection...
- XmlNodeList nodes = element.ChildNodes;
- XmlElement valueRefOrCollectionElement = null;
- for (int i = 0; i < nodes.Count; ++i)
- {
- XmlElement candidateEle = nodes.Item(i) as XmlElement;
- if (candidateEle != null)
- {
- if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name))
- {
- // keep going: we don't use this value for now...
- }
- else
- {
- // child element is what we're looking for...
- valueRefOrCollectionElement = candidateEle;
- }
- }
- }
- if (valueRefOrCollectionElement == null)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "The '' element must have a subelement such as 'value' or 'ref'.");
- }
- return ParsePropertySubElement(valueRefOrCollectionElement, name, parserHelper);
- }
-
- ///
- /// Parse a value, ref or collection subelement of a property element.
- ///
- ///
- /// Subelement of property element; we don't know which yet.
- ///
- ///
- /// The name of the object (definition) associated with the top level property.
- ///
- ///
- /// The namespace-aware parser.
- ///
- protected virtual object ParsePropertySubElement(
- XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- if (element.Name.Equals(ObjectDefinitionConstants.ObjectElement))
- {
- return ParseObjectDefinition(element, "(inner object definition)", parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.RefElement))
- {
- return GetReference(element, parserHelper, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.IdRefElement))
- {
- return GetObjectReference(element, parserHelper, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ListElement))
- {
- return GetList(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.SetElement))
- {
- return GetSet(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.DictionaryElement))
- {
- return GetDictionary(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.NameValuesElement))
- {
- return GetNameValues(element, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ValueElement))
- {
- return GetValue(element, name);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.ExpressionElement))
- {
- return GetExpression(element, name, parserHelper);
- }
- else if (element.Name.Equals(ObjectDefinitionConstants.NullElement))
- {
- // it's a distinguished null value...
- return null;
- }
- else
- {
- // it may match another Parser
- INamespaceParser otherParser = GetParser(element.NamespaceURI);
- if (otherParser != null)
- {
- // The other parser uses nestings tags and thus returns the definition
- // of the parsed object.
- return otherParser.ParseElement(element, new ParserContext(parserHelper.ReaderContext, parserHelper));
- }
- }
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Unknown subelement of : <" + element.Name + ">");
- }
-
- private static INamespaceParser GetParser(string nspace)
- {
- // finds the configuration parser for the given namespace
- try
- {
- return NamespaceParserRegistry.GetParser(nspace);
- }
- catch (Exception)
- {
- // The parser for the given namespace is not found
- return null;
- }
- }
-
- private static object GetObjectReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
- {
- // a generic reference to any name of any object
- string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // a reference to the id of another object in the same XML file
- objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Either 'object' or 'local' is required for an idref");
- }
- }
- return objectRef;
- }
-
- private object GetReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
- {
- // is it a generic reference to any name of any object?
- string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // is it a reference to the id of another object in the same XML file?
- objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- // is it a reference to the id of another object in a parent context?
- objectRef = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
- if (StringUtils.IsNullOrEmpty(objectRef))
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource,
- name,
- "Either 'object' or 'local' is required for a reference");
- }
- return new RuntimeObjectReference(objectRef, true);
- }
- }
- return new RuntimeObjectReference(objectRef);
- }
-
- private object GetValue(XmlElement element, string name)
- {
- string valueType = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
- if (StringUtils.IsNullOrEmpty(valueType))
- {
- return GetTextValue(element, name);
- }
- else
- {
- Type resolvedValueType = TypeResolutionUtils.ResolveType(valueType);
- if (resolvedValueType == typeof(string))
- {
- return GetTextValue(element, name);
- }
- else
- {
- return new TypedStringValue(GetTextValue(element, name), resolvedValueType);
- }
- }
- }
-
- private object GetExpression(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- string expression = element.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
- ExpressionHolder holder = new ExpressionHolder(expression);
- holder.Properties = GetPropertyValueSubElements(name, element, parserHelper);
- return holder;
- }
-
- ///
- /// Gets a list definition.
- ///
- ///
- /// The element describing the list definition.
- ///
- ///
- /// The name of the object (definition) associated with the list definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The list definition.
- protected virtual IList GetList(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedList list = new ManagedList();
-
- string elementTypeName = element.GetAttribute("element-type");
- if (StringUtils.HasText(elementTypeName))
- {
- list.ElementTypeName = elementTypeName;
- }
-
- foreach (XmlNode node in element.ChildNodes)
- {
- XmlElement ele = node as XmlElement;
- if (ele != null)
- {
- list.Add(ParsePropertySubElement(ele, name, parserHelper));
- }
- }
- return list;
- }
-
- ///
- /// Gets a set definition.
- ///
- ///
- /// The element describing the set definition.
- ///
- ///
- /// The name of the object (definition) associated with the set definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The set definition.
- protected Set GetSet(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedSet theSet = new ManagedSet();
- string elementTypeName = element.GetAttribute("element-type");
- if (StringUtils.HasText(elementTypeName))
- {
- theSet.ElementTypeName = elementTypeName;
- }
- foreach (XmlNode node in element.ChildNodes)
- {
- XmlElement ele = node as XmlElement;
- if (ele != null)
- {
- object sub = ParsePropertySubElement(ele, name, parserHelper);
- theSet.Add(sub);
- }
- }
- return theSet;
- }
-
- ///
- /// Gets a dictionary definition.
- ///
- ///
- /// The element describing the dictionary definition.
- ///
- ///
- /// The name of the object (definition) associated with the dictionary definition.
- ///
- ///
- /// The namespace-aware parser.
- ///
- /// The dictionary definition.
- protected IDictionary GetDictionary(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
- {
- ManagedDictionary dictionary = new ManagedDictionary();
- string keyTypeName = element.GetAttribute("key-type");
- string valueTypeName = element.GetAttribute("value-type");
- if (StringUtils.HasText(keyTypeName))
- {
- dictionary.KeyTypeName = keyTypeName;
- }
- if (StringUtils.HasText(valueTypeName))
- {
- dictionary.ValueTypeName = valueTypeName;
- }
-
- XmlNodeList entryElements = SelectNodes(element, ObjectDefinitionConstants.EntryElement);
- foreach (XmlElement entryEle in entryElements)
- {
- #region Key
-
- object key = null;
-
- XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute];
- if (keyAtt != null)
- {
- key = keyAtt.Value;
- }
- else
- {
- // ok, we're not using the 'key' attribute; lets check for the ref shortcut...
- XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute];
- if (keyRefAtt != null)
- {
- key = new RuntimeObjectReference(keyRefAtt.Value);
- }
- else
- {
- // so check for the 'key' element...
- XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
- if (keyNode == null)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " +
- "is required for the <{3}/> element.",
- ObjectDefinitionConstants.KeyElement,
- ObjectDefinitionConstants.KeyAttribute,
- ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute,
- ObjectDefinitionConstants.EntryElement));
- }
- XmlElement keyElement = (XmlElement) keyNode;
- XmlNodeList keyNodes = keyElement.GetElementsByTagName("*");
- if (keyNodes == null || keyNodes.Count == 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("Malformed <{0}/> element... the value of the key must be " +
- "specified as a child value-style element.",
- ObjectDefinitionConstants.KeyElement));
- }
- key = ParsePropertySubElement((XmlElement) keyNodes.Item(0), name, parserHelper);
- }
- }
-
- #endregion
-
- #region Value
-
- XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute];
- if (inlineValueAtt != null)
- {
- // ok, we're using the value attribute shortcut...
- dictionary[key] = inlineValueAtt.Value;
- }
- else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null)
- {
- // ok, we're using the value-ref attribute shortcut...
- XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute];
- RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value);
- dictionary[key] = ror;
- }
- else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null)
- {
- // ok, we're using the expression attribute shortcut...
- XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
- ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value);
- dictionary[key] = expHolder;
- }
- else
- {
- XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
- if (keyNode != null)
- {
- entryEle.RemoveChild(keyNode);
- }
- // ok, we're using the original full-on value element...
- XmlNodeList valueElements = entryEle.GetElementsByTagName("*");
- if (valueElements == null || valueElements.Count == 0)
- {
- throw new ObjectDefinitionStoreException(
- parserHelper.ReaderContext.Resource, name,
- string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " +
- "is required for the <{2}/> element.",
- ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement));
- }
- dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserHelper);
- }
-
- #endregion
- }
- return dictionary;
- }
-
- ///
- /// Selects sub-elements with a given
- /// name.
- ///
- ///
- ///
- /// Uses a namespace manager if necessary.
- ///
- ///
- ///
- /// The element to be searched in.
- ///
- ///
- /// The name of the child nodes to look for.
- ///
- ///
- /// The child s of the supplied
- /// with the supplied
- /// .
- ///
- protected XmlNodeList SelectNodes(XmlElement element, string childElementName)
- {
- XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
- nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
- return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
- }
-
- ///
- /// Selects a single sub-element with a given
- /// name.
- ///
- ///
- ///
- /// Uses a namespace manager if necessary.
- ///
- ///
- ///
- /// The element to be searched in.
- ///
- ///
- /// The name of the child node to look for.
- ///
- ///
- /// The first child of the supplied
- /// with the supplied
- /// .
- ///
- protected XmlNode SelectSingleNode(XmlElement element, string childElementName)
- {
- XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
- nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
- return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
- }
-
- ///
- /// Gets a name value collection mapping definition.
- ///
- ///
- /// The element describing the name value collection mapping definition.
- ///
- ///
- /// The name of the object (definition) associated with the
- /// name value collection mapping definition.
- ///
- /// The name value collection definition.
- protected NameValueCollection GetNameValues(XmlElement element, string name)
- {
- NameValueCollection nvc = new NameValueCollection();
- XmlNodeList addElements = element.GetElementsByTagName(ObjectDefinitionConstants.AddElement);
- foreach (XmlElement addElement in addElements)
- {
- string key = addElement.GetAttribute(ObjectDefinitionConstants.KeyAttribute);
- string value = addElement.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
- string delimiters = addElement.GetAttribute(ObjectDefinitionConstants.DelimitersAttribute);
-
- if (StringUtils.HasText(delimiters))
- {
- string[] values = value.Split(delimiters.ToCharArray());
- foreach (string v in values)
- {
- nvc.Add(key, v);
- }
- }
- else
- {
- nvc[key] = value;
- }
- }
- return nvc;
- }
-
- ///
- /// Returns the text of the supplied ,
- /// or the empty string value if said is empty.
- ///
- ///
- ///
- /// If the supplied is ,
- /// then the empty string value will be returned.
- ///
- ///
- protected string GetTextValue(XmlElement element, string name)
- {
- if (element == null || StringUtils.IsNullOrEmpty(element.InnerText))
- {
- return String.Empty;
- }
- return element.InnerText;
- }
-
- ///
- /// Strips the dependency check value out of the supplied string.
- ///
- ///
- ///
- /// If the supplied is an invalid dependency
- /// checking mode, the invalid value will be logged and this method will
- /// return the value.
- /// No exception will be raised.
- ///
- /// If the supplied is an invalid autowiring mode,
- /// the invalid value will be logged and this method will return the
- /// value. No exception will be raised.
- ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ [
+ NamespaceParser(
+ Namespace = "http://www.springframework.net",
+ SchemaLocationAssemblyHint = typeof(ObjectsNamespaceParser),
+ SchemaLocation = "/Spring.Objects.Factory.Xml/spring-objects-1.1.xsd"
+ )
+ ]
+ public class ObjectsNamespaceParser : INamespaceParser
+ {
+ ///
+ /// The namespace URI for the standard Spring.NET object definition schema.
+ ///
+ public const string Namespace = "http://www.springframework.net";
+
+ ///
+ /// The shared instance for this class (and derived classes).
+ ///
+ protected static readonly ILog log =
+ LogManager.GetLogger(typeof(ObjectsNamespaceParser));
+
+ #region IXmlObjectDefinitionParser Members
+
+ ///
+ /// Invoked by after construction but before any
+ /// elements have been parsed.
+ ///
+ /// This is a NoOp
+ public void Init()
+ {
+
+ }
+
+ #endregion
+
+
+ ///
+ /// Parse the specified element and register any resulting
+ /// IObjectDefinitions with the IObjectDefinitionRegistry that is
+ /// embedded in the supplied ParserContext.
+ ///
+ /// The element to be parsed into one or more IObjectDefinitions
+ /// The object encapsulating the current state of the parsing
+ /// process.
+ ///
+ /// The primary IObjectDefinition (can be null as explained above)
+ ///
+ ///
+ /// Implementations should return the primary IObjectDefinition
+ /// that results from the parse phase if they wish to used nested
+ /// inside (for example) a <property> tag.
+ /// Implementations may return null if they will not
+ /// be used in a nested scenario.
+ ///
+ ///
+ public virtual IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+
+ if (element.LocalName == ObjectDefinitionConstants.ImportElement)
+ {
+ ImportObjectDefinitionResource(element, parserContext);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.AliasElement)
+ {
+ ParseAlias(element, parserContext.ReaderContext.Registry);
+ }
+ else if (element.LocalName == ObjectDefinitionConstants.ObjectElement)
+ {
+ RegisterObjectDefinition(element, parserContext);
+ }
+
+ return null;
+ }
+
+
+ ///
+ /// Parse the specified XmlNode and decorate the supplied ObjectDefinitionHolder,
+ /// returning the decorated definition.
+ ///
+ /// The XmlNode may either be an XmlAttribute or an XmlElement, depending on
+ /// whether a custom attribute or element is being parsed.
+ /// Implementations may choose to return a completely new definition,
+ /// which will replace the original definition in the resulting IApplicationContext/IObjectFactory.
+ ///
+ /// The supplied ParserContext can be used to register any additional objects needed to support
+ /// the main definition.
+ ///
+ /// The source element or attribute that is to be parsed.
+ /// The current object definition.
+ /// The object encapsulating the current state of the parsing
+ /// process.
+ /// The decorated definition (to be registered in the IApplicationContext/IObjectFactory),
+ /// or simply the original object definition if no decoration is required. A null value is strickly
+ /// speaking invalid, but will leniently treated like the case where the original object definition
+ /// gets returned.
+ public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition,
+ ParserContext parserContext)
+ {
+ return null;
+ }
+
+ private void ParseAlias(XmlElement aliasElement, IObjectDefinitionRegistry registry)
+ {
+ string name = aliasElement.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ string alias = aliasElement.GetAttribute(ObjectDefinitionConstants.AliasAttribute);
+ registry.RegisterAlias(name, alias);
+ }
+
+
+
+
+ ///
+ /// Loads external XML object definitions from the resource described by the supplied
+ /// .
+ ///
+ /// The XML element describing the resource.
+ /// The parser context.
+ ///
+ /// If the resource could not be imported.
+ ///
+ protected virtual void ImportObjectDefinitionResource(XmlElement resource, ParserContext parserContext)
+ {
+ string location = resource.GetAttribute(ObjectDefinitionConstants.ImportResourceAttribute);
+ try
+ {
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ CultureInfo.InvariantCulture,
+ "Attempting to import object definitions from '{0}'.", location));
+ }
+
+ #endregion
+
+ IResource importResource = parserContext.ReaderContext.Resource.CreateRelative(location);
+ parserContext.ReaderContext.Reader.LoadObjectDefinitions(importResource);
+ }
+ catch (IOException ex)
+ {
+ parserContext.ReaderContext.ReportException(resource, null, string.Format(
+ CultureInfo.InvariantCulture,
+ "Invalid relative resource location '{0}' to import object definitions from.",
+ location), ex);
+ }
+ }
+
+
+ /// Parses an event listener definition.
+ ///
+ /// The name associated with the object that the event handler is being defined on.
+ ///
+ /// The events being populated.
+ ///
+ /// The element containing the event listener definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual void ParseEventListenerDefinition(
+ string name, EventValues events, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ // get an appropriate IEventHandlerValue instance based upon the
+ // attribute values of the listener element...
+ IEventHandlerValue myHandler = ObjectDefinitionReaderUtils.CreateEventHandlerValue(
+ element.GetAttribute(ObjectDefinitionConstants.ListenerMethodAttribute),
+ element.GetAttribute(ObjectDefinitionConstants.ListenerEventAttribute));
+
+ // and then get the source of the event (another managed object instance
+ // or a Type reference (i.e. a static event exposed on a class)...
+ XmlElement sourceElement = this.SelectSingleNode(element, ObjectDefinitionConstants.RefElement) as XmlElement;
+
+ XmlAttribute sourceAtt = sourceElement.Attributes[0];
+ if (StringUtils.IsNullOrEmpty(sourceAtt.Value))
+ {
+ parserHelper.ReaderContext.ReportFatalException(sourceElement, string.Format(
+ CultureInfo.InvariantCulture,
+ "The single attribute of the <{0}/> element cannot be empty. Specify the " +
+ "object id (alias) or the full, assembly qualified Type name that is the " +
+ "source of the event.",
+ ObjectDefinitionConstants.RefElement));
+ return;
+ }
+ switch (sourceAtt.LocalName)
+ {
+ case ObjectDefinitionConstants.LocalRefAttribute:
+ case ObjectDefinitionConstants.ObjectRefAttribute:
+ // we're wiring up to an event exposed on another managed object (instance)
+ RuntimeObjectReference ror = new RuntimeObjectReference(sourceAtt.Value);
+ myHandler.Source = ror;
+ break;
+ case ObjectDefinitionConstants.TypeAttribute:
+ // we're wiring up to a static event exposed on a Type (class)
+ myHandler.Source = parserHelper.ReaderContext.Reader.Domain == null ?
+ (object) sourceAtt.Value :
+ (object)TypeResolutionUtils.ResolveType(sourceAtt.Value);
+ break;
+ }
+ events.AddHandler(myHandler);
+ }
+
+
+
+ ///
+ /// Parse an object definition and register it with the object factory..
+ ///
+ /// The element containing the object definition.
+ /// The parser context.
+ ///
+ protected void RegisterObjectDefinition(XmlElement element, ParserContext parserContext)
+ {
+ ObjectDefinitionHolder holder = null;
+ try
+ {
+ holder = ParseObjectDefinition(element, parserContext);
+ if (holder == null)
+ {
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ObjectDefinitionStoreException(string.Format("Failed parsing object definition '{0}'", element.OuterXml), ex);
+ }
+
+
+ holder = parserContext.ParserHelper.DecorateObjectDefinitionIfRequired(element, holder);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Registering object definition with id '{0}'.", holder.ObjectName));
+ }
+
+ #endregion
+
+ ObjectDefinitionReaderUtils.RegisterObjectDefinition(holder, parserContext.ReaderContext.Registry);
+ }
+
+
+ ///
+ /// Parse a standard object definition into a
+ /// ,
+ /// including object name and aliases.
+ ///
+ /// The element containing the object definition.
+ /// The parser context.
+ ///
+ /// The object (definition) wrapped within an
+ ///
+ /// instance.
+ ///
+ ///
+ ///
+ /// Object elements specify their canonical name via the "id" attribute
+ /// and their aliases as a delimited "name" attribute.
+ ///
+ ///
+ /// If no "id" is specified, uses the first name in the "name" attribute
+ /// as the canonical name, registering all others as aliases.
+ ///
+ ///
+ protected ObjectDefinitionHolder ParseObjectDefinition(XmlElement element, ParserContext parserContext)
+ {
+ string id = element.GetAttribute(ObjectDefinitionConstants.IdAttribute);
+ string name = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ ArrayList aliases = new ArrayList();
+ if (StringUtils.HasText(name))
+ {
+ aliases.AddRange(GetObjectNames(name));
+ }
+ // if we ain't got an id, check if object is page definition or assign any existing (first) alias...
+ if (StringUtils.IsNullOrEmpty(id))
+ {
+ id = CalculateId(element, aliases);
+ }
+
+
+ IConfigurableObjectDefinition definition = ParseObjectDefinition(element, id, parserContext.ParserHelper);
+ if (StringUtils.IsNullOrEmpty(id))
+ {
+ id = ObjectDefinitionReaderUtils.GenerateObjectName(definition, parserContext.Registry);
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format(
+ "Neither XML '{0}' nor '{1}' specified - using object " +
+ "class name [{2}] as the id.",
+ id, ObjectDefinitionConstants.IdAttribute, ObjectDefinitionConstants.NameAttribute));
+ }
+
+ #endregion
+ }
+ string[] aliasesArray = (string[]) aliases.ToArray(typeof(string));
+ return new ObjectDefinitionHolder(definition, id, aliasesArray);
+ }
+
+ ///
+ /// Calculates an id for an object definition.
+ ///
+ ///
+ ///
+ /// Called when an object definition has not been explicitly defined
+ /// with an id.
+ ///
+ ///
+ ///
+ /// The element containing the object definition.
+ ///
+ ///
+ /// The list of names defined for the object; may be
+ /// or even empty.
+ ///
+ ///
+ /// A calculated object definition id.
+ ///
+ protected virtual string CalculateId(XmlElement element, ArrayList aliases)
+ {
+ string id = null;
+ if (aliases.Count > 0)
+ {
+ string firstAlias = aliases[0] as string;
+ aliases.RemoveAt(0);
+ id = firstAlias;
+ }
+
+ #region Instrumentation
+
+ if (log.IsDebugEnabled)
+ {
+ StringBuilder buffer = new StringBuilder();
+ foreach (string alias in aliases)
+ {
+ buffer.Append(alias).Append(",");
+ }
+ log.Debug(string.Format("No XML 'id' specified - using '{0}' as the id and '{1}' as aliases.",
+ id, buffer.ToString()));
+ }
+
+ #endregion
+
+ return id;
+ }
+
+ ///
+ /// Parse a standard object definition.
+ ///
+ /// The element containing the object definition.
+ /// The id of the object definition.
+ /// parsing state holder
+ /// The object (definition).
+ protected virtual IConfigurableObjectDefinition ParseObjectDefinition(
+ XmlElement element, string id, ObjectDefinitionParserHelper parserHelper)
+ {
+ string typeName = null;
+ try
+ {
+ if (element.HasAttribute(ObjectDefinitionConstants.TypeAttribute))
+ {
+ typeName = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ if (StringUtils.IsNullOrEmpty(typeName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, id,
+ "The 'type' attribute does not need to be present, but if it is it must not be empty: got '" + typeName + "'.");
+ }
+ }
+ string parent = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
+
+
+ AbstractObjectDefinition od
+ = parserHelper.ReaderContext.ObjectDefinitionFactory.CreateObjectDefinition(
+ typeName, parent, parserHelper.ReaderContext.Reader.Domain);
+
+
+ MutablePropertyValues pvs = GetPropertyValueSubElements(id, element, parserHelper);
+ ConstructorArgumentValues arguments
+ = GetConstructorArgSubElements(id, element, parserHelper);
+ EventValues events = GetEventHandlerSubElements(id, element, parserHelper);
+ MethodOverrides methodOverrides = GetMethodOverrideSubElements(id, element, parserHelper);
+
+ bool isPage = StringUtils.HasText(typeName) && typeName!= null && typeName.ToLower().EndsWith(".aspx");
+ if (!isPage)
+ {
+ od.ConstructorArgumentValues = arguments;
+ }
+
+ od.PropertyValues = pvs;
+ od.MethodOverrides = methodOverrides;
+ od.EventHandlerValues = events;
+ if (element.HasAttribute(ObjectDefinitionConstants.DependsOnAttribute))
+ {
+ string dependsOn = element.GetAttribute(ObjectDefinitionConstants.DependsOnAttribute);
+ od.DependsOn = GetObjectNames(dependsOn);
+ }
+ od.FactoryMethodName = element.GetAttribute(ObjectDefinitionConstants.FactoryMethodAttribute);
+ od.FactoryObjectName = element.GetAttribute(ObjectDefinitionConstants.FactoryObjectAttribute);
+ string dependencyCheck = element.GetAttribute(ObjectDefinitionConstants.DependencyCheckAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(dependencyCheck))
+ {
+ dependencyCheck = parserHelper.Defaults.DependencyCheck;
+ }
+ od.DependencyCheck = GetDependencyCheck(dependencyCheck);
+ string autowire = element.GetAttribute(ObjectDefinitionConstants.AutowireAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(autowire))
+ {
+ autowire = parserHelper.Defaults.Autowire;
+ }
+ od.AutowireMode = GetAutowireMode(autowire);
+ string initMethodName = element.GetAttribute(ObjectDefinitionConstants.InitMethodAttribute);
+ if (StringUtils.HasText(initMethodName))
+ {
+ od.InitMethodName = initMethodName;
+ }
+ string destroyMethodName = element.GetAttribute(ObjectDefinitionConstants.DestroyMethodAttribute);
+ if (StringUtils.HasText(destroyMethodName))
+ {
+ od.DestroyMethodName = destroyMethodName;
+ }
+ if (element.HasAttribute(ObjectDefinitionConstants.SingletonAttribute))
+ {
+ od.IsSingleton = IsTrueStringValue(element.GetAttribute(ObjectDefinitionConstants.SingletonAttribute).ToLower(CultureInfo.CurrentCulture));
+ }
+ string lazyInit = element.GetAttribute(ObjectDefinitionConstants.LazyInitAttribute);
+ if (ObjectDefinitionConstants.DefaultValue.Equals(lazyInit) && od.IsSingleton)
+ {
+ // just apply default to singletons, as lazy-init has no meaning for prototypes...
+ lazyInit = parserHelper.Defaults.LazyInit;
+ }
+ od.IsLazyInit = IsTrueStringValue(lazyInit);
+
+ // try to get the line info
+ string resourceDescription = parserHelper.ReaderContext.Resource.Description;
+ if (StringUtils.HasText(resourceDescription))
+ {
+ int line = ConfigurationUtils.GetLineNumber(element);
+ if (line > 0)
+ {
+ resourceDescription += " line " + line;
+ }
+ }
+ od.ResourceDescription = resourceDescription;
+
+ string isAbstract = element.GetAttribute(ObjectDefinitionConstants.AbstractAttribute);
+ if (StringUtils.HasText(isAbstract))
+ {
+ od.IsAbstract = IsTrueStringValue(isAbstract);
+ }
+ return od;
+ }
+ catch (TypeLoadException ex)
+ {
+ parserHelper.ReaderContext.ReportException(
+ element,
+ id,
+ string.Format(
+ "Object class [{0}] not found.",
+ typeName),
+ ex);
+ }
+ catch (ApplicationException ex)
+ {
+ parserHelper.ReaderContext.ReportException(element, id, string.Empty, ex);
+ }
+ return null;
+ }
+
+ ///
+ /// Parse method override argument subelements of the given object element.
+ ///
+ protected MethodOverrides GetMethodOverrideSubElements(
+ string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ MethodOverrides overrides = new MethodOverrides();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.LookupMethodElement))
+ {
+ ParseLookupMethodElement(name, overrides, (XmlElement) node, parserHelper);
+ }
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodElement))
+ {
+ ParseReplacedMethodElement(name, overrides, (XmlElement) node, parserHelper);
+ }
+ return overrides;
+ }
+
+ ///
+ /// Parse element and add parsed element to
+ ///
+ protected void ParseLookupMethodElement(
+ string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ string methodName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodNameAttribute);
+ string targetObjectName = element.GetAttribute(ObjectDefinitionConstants.LookupMethodObjectNameAttribute);
+ if (StringUtils.IsNullOrEmpty(methodName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.LookupMethodNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
+ }
+ if (StringUtils.IsNullOrEmpty(targetObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.LookupMethodObjectNameAttribute, ObjectDefinitionConstants.LookupMethodElement));
+ }
+ overrides.Add(new LookupMethodOverride(methodName, targetObjectName));
+ }
+
+ ///
+ /// Parse element and add parsed element to
+ ///
+ protected void ParseReplacedMethodElement(
+ string name, MethodOverrides overrides, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ string methodName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodNameAttribute);
+ string targetReplacerObjectName = element.GetAttribute(ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute);
+ if (StringUtils.IsNullOrEmpty(methodName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
+ }
+ if (StringUtils.IsNullOrEmpty(targetReplacerObjectName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodReplacerNameAttribute, ObjectDefinitionConstants.ReplacedMethodElement));
+ }
+ ReplacedMethodOverride theOverride = new ReplacedMethodOverride(methodName, targetReplacerObjectName);
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement))
+ {
+ XmlElement argElement = (XmlElement) node;
+ string match = argElement.GetAttribute(ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute);
+ if (StringUtils.IsNullOrEmpty(match))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("The '{0}' attribute is required for the '{1}' element.",
+ ObjectDefinitionConstants.ReplacedMethodArgumentTypeMatchAttribute, ObjectDefinitionConstants.ReplacedMethodArgumentTypeElement));
+ }
+ theOverride.AddTypeIdentifier(match);
+ }
+ overrides.Add(theOverride);
+ }
+
+ ///
+ /// Parse constructor argument subelements of the given object element.
+ ///
+ protected ConstructorArgumentValues GetConstructorArgSubElements(
+ string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ ConstructorArgumentValues arguments = new ConstructorArgumentValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ConstructorArgElement))
+ {
+ ParseConstructorArgElement(name, arguments, (XmlElement) node, parserHelper);
+ }
+ return arguments;
+ }
+
+ ///
+ /// Parse event handler subelements of the given object element.
+ ///
+ protected EventValues GetEventHandlerSubElements(
+ string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ EventValues events = new EventValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.ListenerElement))
+ {
+ ParseEventListenerDefinition(name, events, (XmlElement) node, parserHelper);
+ }
+ return events;
+ }
+
+ ///
+ /// Parse property value subelements of the given object element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the property element (s)
+ ///
+ ///
+ /// The element containing the top level object definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ ///
+ /// The property (s) associated with the object (definition).
+ ///
+ protected virtual MutablePropertyValues GetPropertyValueSubElements(
+ string name, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ MutablePropertyValues properties = new MutablePropertyValues();
+ foreach (XmlNode node in this.SelectNodes(element, ObjectDefinitionConstants.PropertyElement))
+ {
+ ParsePropertyElement(name, properties, (XmlElement) node, parserHelper);
+ }
+ return properties;
+ }
+
+ ///
+ /// Parse a constructor-arg element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the ctor arg.
+ ///
+ ///
+ /// The list of constructor args associated with the object (definition).
+ ///
+ ///
+ /// The name of the element containing the ctor arg definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual void ParseConstructorArgElement(
+ string name, ConstructorArgumentValues arguments, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ object val = GetPropertyValue(element, name, parserHelper);
+ string indexAttr = element.GetAttribute(ObjectDefinitionConstants.IndexAttribute);
+ string typeAttr = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ string nameAttr = element.GetAttribute(ObjectDefinitionConstants.ArgumentNameAttribute);
+
+ // only one of the 'index' or 'name' attributes can be present
+ if (StringUtils.HasText(indexAttr)
+ && StringUtils.HasText(nameAttr))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ "Only one of the 'index' or 'name' attributes can be present per constructor argument.");
+ }
+ if (StringUtils.HasText(indexAttr))
+ {
+ try
+ {
+ int index = int.Parse(indexAttr, CultureInfo.CurrentCulture);
+ if (index < 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ "'index' cannot be lower than 0");
+ }
+ if (StringUtils.HasText(typeAttr))
+ {
+ arguments.AddIndexedArgumentValue(index, val, typeAttr);
+ }
+ else
+ {
+ arguments.AddIndexedArgumentValue(index, val);
+ }
+ }
+ catch (FormatException)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ "Attribute 'index' of tag 'constructor-arg' must be an integer value.");
+ }
+ }
+ else if (StringUtils.HasText(nameAttr))
+ {
+ if (StringUtils.HasText(typeAttr))
+ {
+ if (log.IsWarnEnabled)
+ {
+ log.Warn("The 'type' attribute is redundant when the 'name' attribute has been used on a constructor argument element.");
+ }
+ }
+ arguments.AddNamedArgumentValue(nameAttr, val);
+ }
+ else
+ {
+ if (StringUtils.HasText(typeAttr))
+ {
+ arguments.AddGenericArgumentValue(val, typeAttr);
+ }
+ else
+ {
+ arguments.AddGenericArgumentValue(val);
+ }
+ }
+ }
+
+ ///
+ /// Parse a property element.
+ ///
+ ///
+ /// The name of the object (definition) associated with the property.
+ ///
+ ///
+ /// The list of properties associated with the object (definition).
+ ///
+ ///
+ /// The name of the element containing the property definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected void ParsePropertyElement(
+ string name, MutablePropertyValues properties, XmlElement element, ObjectDefinitionParserHelper parserHelper)
+ {
+ string propertyName = element.GetAttribute(ObjectDefinitionConstants.NameAttribute);
+ if (StringUtils.IsNullOrEmpty(propertyName))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "The 'property' element must have a 'name' attribute");
+ }
+ object val = GetPropertyValue(element, name, parserHelper);
+ properties.Add(new PropertyValue(propertyName, val));
+ }
+
+ ///
+ /// Get the value of a property element (may be a list).
+ ///
+ ///
+ /// Please note that even though this method is named GetPropertyValue,
+ /// it is called by both the property and constructor argument element
+ /// handlers.
+ ///
+ ///
+ /// The property element.
+ ///
+ /// The name of the object associated with the property.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual object GetPropertyValue(
+ XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ XmlAttribute inlineValueAtt = element.Attributes[ObjectDefinitionConstants.ValueAttribute];
+ if (inlineValueAtt != null)
+ {
+ return inlineValueAtt.Value;
+ }
+ XmlAttribute inlineRefAtt = element.Attributes[ObjectDefinitionConstants.RefAttribute];
+ if (inlineRefAtt != null)
+ {
+ return new RuntimeObjectReference(inlineRefAtt.Value);
+ }
+ XmlAttribute inlineExpressionAtt = element.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
+ if (inlineExpressionAtt != null)
+ {
+ return new ExpressionHolder(inlineExpressionAtt.Value);
+ }
+
+ // should only have one element child: value, ref, collection...
+ XmlNodeList nodes = element.ChildNodes;
+ XmlElement valueRefOrCollectionElement = null;
+ for (int i = 0; i < nodes.Count; ++i)
+ {
+ XmlElement candidateEle = nodes.Item(i) as XmlElement;
+ if (candidateEle != null)
+ {
+ if (ObjectDefinitionConstants.DescriptionElement.Equals(candidateEle.Name))
+ {
+ // keep going: we don't use this value for now...
+ }
+ else
+ {
+ // child element is what we're looking for...
+ valueRefOrCollectionElement = candidateEle;
+ }
+ }
+ }
+ if (valueRefOrCollectionElement == null)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "The '' element must have a subelement such as 'value' or 'ref'.");
+ }
+ return ParsePropertySubElement(valueRefOrCollectionElement, name, parserHelper);
+ }
+
+ ///
+ /// Parse a value, ref or collection subelement of a property element.
+ ///
+ ///
+ /// Subelement of property element; we don't know which yet.
+ ///
+ ///
+ /// The name of the object (definition) associated with the top level property.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ protected virtual object ParsePropertySubElement(
+ XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ if (element.Name.Equals(ObjectDefinitionConstants.ObjectElement))
+ {
+ return ParseObjectDefinition(element, "(inner object definition)", parserHelper);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.RefElement))
+ {
+ return GetReference(element, parserHelper, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.IdRefElement))
+ {
+ return GetObjectReference(element, parserHelper, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ListElement))
+ {
+ return GetList(element, name, parserHelper);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.SetElement))
+ {
+ return GetSet(element, name, parserHelper);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.DictionaryElement))
+ {
+ return GetDictionary(element, name, parserHelper);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.NameValuesElement))
+ {
+ return GetNameValues(element, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ValueElement))
+ {
+ return GetValue(element, name);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.ExpressionElement))
+ {
+ return GetExpression(element, name, parserHelper);
+ }
+ else if (element.Name.Equals(ObjectDefinitionConstants.NullElement))
+ {
+ // it's a distinguished null value...
+ return null;
+ }
+ else
+ {
+ // it may match another Parser
+ INamespaceParser otherParser = GetParser(element.NamespaceURI);
+ if (otherParser != null)
+ {
+ // The other parser uses nestings tags and thus returns the definition
+ // of the parsed object.
+ return otherParser.ParseElement(element, new ParserContext(parserHelper.ReaderContext, parserHelper));
+ }
+ }
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "Unknown subelement of : <" + element.Name + ">");
+ }
+
+ private static INamespaceParser GetParser(string nspace)
+ {
+ // finds the configuration parser for the given namespace
+ try
+ {
+ return NamespaceParserRegistry.GetParser(nspace);
+ }
+ catch (Exception)
+ {
+ // The parser for the given namespace is not found
+ return null;
+ }
+ }
+
+ private static object GetObjectReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
+ {
+ // a generic reference to any name of any object
+ string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // a reference to the id of another object in the same XML file
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "Either 'object' or 'local' is required for an idref");
+ }
+ }
+ return objectRef;
+ }
+
+ private object GetReference(XmlElement element, ObjectDefinitionParserHelper parserHelper, string name)
+ {
+ // is it a generic reference to any name of any object?
+ string objectRef = element.GetAttribute(ObjectDefinitionConstants.ObjectRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // is it a reference to the id of another object in the same XML file?
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.LocalRefAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ // is it a reference to the id of another object in a parent context?
+ objectRef = element.GetAttribute(ObjectDefinitionConstants.ParentAttribute);
+ if (StringUtils.IsNullOrEmpty(objectRef))
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource,
+ name,
+ "Either 'object' or 'local' is required for a reference");
+ }
+ return new RuntimeObjectReference(objectRef, true);
+ }
+ }
+ return new RuntimeObjectReference(objectRef);
+ }
+
+ private object GetValue(XmlElement element, string name)
+ {
+ string valueType = element.GetAttribute(ObjectDefinitionConstants.TypeAttribute);
+ if (StringUtils.IsNullOrEmpty(valueType))
+ {
+ return GetTextValue(element, name);
+ }
+ else
+ {
+ Type resolvedValueType = TypeResolutionUtils.ResolveType(valueType);
+ if (resolvedValueType == typeof(string))
+ {
+ return GetTextValue(element, name);
+ }
+ else
+ {
+ return new TypedStringValue(GetTextValue(element, name), resolvedValueType);
+ }
+ }
+ }
+
+ private object GetExpression(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ string expression = element.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
+ ExpressionHolder holder = new ExpressionHolder(expression);
+ holder.Properties = GetPropertyValueSubElements(name, element, parserHelper);
+ return holder;
+ }
+
+ ///
+ /// Gets a list definition.
+ ///
+ ///
+ /// The element describing the list definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the list definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The list definition.
+ protected virtual IList GetList(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ ManagedList list = new ManagedList();
+
+ string elementTypeName = element.GetAttribute("element-type");
+ if (StringUtils.HasText(elementTypeName))
+ {
+ list.ElementTypeName = elementTypeName;
+ }
+
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ XmlElement ele = node as XmlElement;
+ if (ele != null)
+ {
+ list.Add(ParsePropertySubElement(ele, name, parserHelper));
+ }
+ }
+ return list;
+ }
+
+ ///
+ /// Gets a set definition.
+ ///
+ ///
+ /// The element describing the set definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the set definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The set definition.
+ protected Set GetSet(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ ManagedSet theSet = new ManagedSet();
+ string elementTypeName = element.GetAttribute("element-type");
+ if (StringUtils.HasText(elementTypeName))
+ {
+ theSet.ElementTypeName = elementTypeName;
+ }
+ foreach (XmlNode node in element.ChildNodes)
+ {
+ XmlElement ele = node as XmlElement;
+ if (ele != null)
+ {
+ object sub = ParsePropertySubElement(ele, name, parserHelper);
+ theSet.Add(sub);
+ }
+ }
+ return theSet;
+ }
+
+ ///
+ /// Gets a dictionary definition.
+ ///
+ ///
+ /// The element describing the dictionary definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the dictionary definition.
+ ///
+ ///
+ /// The namespace-aware parser.
+ ///
+ /// The dictionary definition.
+ protected IDictionary GetDictionary(XmlElement element, string name, ObjectDefinitionParserHelper parserHelper)
+ {
+ ManagedDictionary dictionary = new ManagedDictionary();
+ string keyTypeName = element.GetAttribute("key-type");
+ string valueTypeName = element.GetAttribute("value-type");
+ if (StringUtils.HasText(keyTypeName))
+ {
+ dictionary.KeyTypeName = keyTypeName;
+ }
+ if (StringUtils.HasText(valueTypeName))
+ {
+ dictionary.ValueTypeName = valueTypeName;
+ }
+
+ XmlNodeList entryElements = SelectNodes(element, ObjectDefinitionConstants.EntryElement);
+ foreach (XmlElement entryEle in entryElements)
+ {
+ #region Key
+
+ object key = null;
+
+ XmlAttribute keyAtt = entryEle.Attributes[ObjectDefinitionConstants.KeyAttribute];
+ if (keyAtt != null)
+ {
+ key = keyAtt.Value;
+ }
+ else
+ {
+ // ok, we're not using the 'key' attribute; lets check for the ref shortcut...
+ XmlAttribute keyRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute];
+ if (keyRefAtt != null)
+ {
+ key = new RuntimeObjectReference(keyRefAtt.Value);
+ }
+ else
+ {
+ // so check for the 'key' element...
+ XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
+ if (keyNode == null)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("One of either the '{0}' element, or the the '{1}' or '{2}' attributes " +
+ "is required for the <{3}/> element.",
+ ObjectDefinitionConstants.KeyElement,
+ ObjectDefinitionConstants.KeyAttribute,
+ ObjectDefinitionConstants.DictionaryKeyRefShortcutAttribute,
+ ObjectDefinitionConstants.EntryElement));
+ }
+ XmlElement keyElement = (XmlElement) keyNode;
+ XmlNodeList keyNodes = keyElement.GetElementsByTagName("*");
+ if (keyNodes == null || keyNodes.Count == 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("Malformed <{0}/> element... the value of the key must be " +
+ "specified as a child value-style element.",
+ ObjectDefinitionConstants.KeyElement));
+ }
+ key = ParsePropertySubElement((XmlElement) keyNodes.Item(0), name, parserHelper);
+ }
+ }
+
+ #endregion
+
+ #region Value
+
+ XmlAttribute inlineValueAtt = entryEle.Attributes[ObjectDefinitionConstants.ValueAttribute];
+ if (inlineValueAtt != null)
+ {
+ // ok, we're using the value attribute shortcut...
+ dictionary[key] = inlineValueAtt.Value;
+ }
+ else if (entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute] != null)
+ {
+ // ok, we're using the value-ref attribute shortcut...
+ XmlAttribute inlineValueRefAtt = entryEle.Attributes[ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute];
+ RuntimeObjectReference ror = new RuntimeObjectReference(inlineValueRefAtt.Value);
+ dictionary[key] = ror;
+ }
+ else if (entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute] != null)
+ {
+ // ok, we're using the expression attribute shortcut...
+ XmlAttribute inlineExpressionAtt = entryEle.Attributes[ObjectDefinitionConstants.ExpressionAttribute];
+ ExpressionHolder expHolder = new ExpressionHolder(inlineExpressionAtt.Value);
+ dictionary[key] = expHolder;
+ }
+ else
+ {
+ XmlNode keyNode = SelectSingleNode(entryEle, ObjectDefinitionConstants.KeyElement);
+ if (keyNode != null)
+ {
+ entryEle.RemoveChild(keyNode);
+ }
+ // ok, we're using the original full-on value element...
+ XmlNodeList valueElements = entryEle.GetElementsByTagName("*");
+ if (valueElements == null || valueElements.Count == 0)
+ {
+ throw new ObjectDefinitionStoreException(
+ parserHelper.ReaderContext.Resource, name,
+ string.Format("One of either the '{0}' or '{1}' attributes, or a value-style element " +
+ "is required for the <{2}/> element.",
+ ObjectDefinitionConstants.ValueAttribute, ObjectDefinitionConstants.DictionaryValueRefShortcutAttribute, ObjectDefinitionConstants.EntryElement));
+ }
+ dictionary[key] = ParsePropertySubElement((XmlElement)valueElements.Item(0), name, parserHelper);
+ }
+
+ #endregion
+ }
+ return dictionary;
+ }
+
+ ///
+ /// Selects sub-elements with a given
+ /// name.
+ ///
+ ///
+ ///
+ /// Uses a namespace manager if necessary.
+ ///
+ ///
+ ///
+ /// The element to be searched in.
+ ///
+ ///
+ /// The name of the child nodes to look for.
+ ///
+ ///
+ /// The child s of the supplied
+ /// with the supplied
+ /// .
+ ///
+ protected XmlNodeList SelectNodes(XmlElement element, string childElementName)
+ {
+ XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
+ nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
+ return element.SelectNodes(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
+ }
+
+ ///
+ /// Selects a single sub-element with a given
+ /// name.
+ ///
+ ///
+ ///
+ /// Uses a namespace manager if necessary.
+ ///
+ ///
+ ///
+ /// The element to be searched in.
+ ///
+ ///
+ /// The name of the child node to look for.
+ ///
+ ///
+ /// The first child of the supplied
+ /// with the supplied
+ /// .
+ ///
+ protected XmlNode SelectSingleNode(XmlElement element, string childElementName)
+ {
+ XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable());
+ nsManager.AddNamespace(GetNamespacePrefix(element), element.NamespaceURI);
+ return element.SelectSingleNode(GetNamespacePrefix(element) + ":" + childElementName, nsManager);
+ }
+
+ ///
+ /// Gets a name value collection mapping definition.
+ ///
+ ///
+ /// The element describing the name value collection mapping definition.
+ ///
+ ///
+ /// The name of the object (definition) associated with the
+ /// name value collection mapping definition.
+ ///
+ /// The name value collection definition.
+ protected NameValueCollection GetNameValues(XmlElement element, string name)
+ {
+ NameValueCollection nvc = new NameValueCollection();
+ XmlNodeList addElements = element.GetElementsByTagName(ObjectDefinitionConstants.AddElement);
+ foreach (XmlElement addElement in addElements)
+ {
+ string key = addElement.GetAttribute(ObjectDefinitionConstants.KeyAttribute);
+ string value = addElement.GetAttribute(ObjectDefinitionConstants.ValueAttribute);
+ string delimiters = addElement.GetAttribute(ObjectDefinitionConstants.DelimitersAttribute);
+
+ if (StringUtils.HasText(delimiters))
+ {
+ string[] values = value.Split(delimiters.ToCharArray());
+ foreach (string v in values)
+ {
+ nvc.Add(key, v);
+ }
+ }
+ else
+ {
+ nvc[key] = value;
+ }
+ }
+ return nvc;
+ }
+
+ ///
+ /// Returns the text of the supplied ,
+ /// or the empty string value if said is empty.
+ ///
+ ///
+ ///
+ /// If the supplied is ,
+ /// then the empty string value will be returned.
+ ///
+ ///
+ protected string GetTextValue(XmlElement element, string name)
+ {
+ if (element == null || StringUtils.IsNullOrEmpty(element.InnerText))
+ {
+ return String.Empty;
+ }
+ return element.InnerText;
+ }
+
+ ///
+ /// Strips the dependency check value out of the supplied string.
+ ///
+ ///
+ ///
+ /// If the supplied is an invalid dependency
+ /// checking mode, the invalid value will be logged and this method will
+ /// return the value.
+ /// No exception will be raised.
+ ///
+ /// If the supplied is an invalid autowiring mode,
+ /// the invalid value will be logged and this method will return the
+ /// value. No exception will be raised.
+ ///
- /// Typically applied to a
- /// instance.
- ///
- ///
- /// This class registers each object definition with the given object factory superclass,
- /// and relies on the latter's implementation of the
- /// interface.
- ///
- ///
- /// It supports singletons, prototypes, and references to either of these kinds of object.
- ///
+ /// Typically applied to a
+ /// instance.
+ ///
+ ///
+ /// This class registers each object definition with the given object factory superclass,
+ /// and relies on the latter's implementation of the
+ /// interface.
+ ///
+ ///
+ /// It supports singletons, prototypes, and references to either of these kinds of object.
+ ///
- /// Delegates to
- ///
- /// underneath; effectively equivalent to using a
- /// for a
- /// .
- ///
- ///
- /// objects doesn't need to be the root element of
- /// the XML document: this class will parse all object definition elements in the
- /// XML stream.
- ///
- ///
- /// This class registers each object definition with the
- ///
- /// superclass, and relies on the latter's implementation of the
- /// interface. It supports
- /// singletons, prototypes and references to either of these kinds of object.
- ///
+ /// Delegates to
+ ///
+ /// underneath; effectively equivalent to using a
+ /// for a
+ /// .
+ ///
+ ///
+ /// objects doesn't need to be the root element of
+ /// the XML document: this class will parse all object definition elements in the
+ /// XML stream.
+ ///
+ ///
+ /// This class registers each object definition with the
+ ///
+ /// superclass, and relies on the latter's implementation of the
+ /// interface. It supports
+ /// singletons, prototypes and references to either of these kinds of object.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ ///
+ [Serializable]
+ public class XmlObjectFactory : DefaultListableObjectFactory
+ {
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the class,
+ /// with the given resource, which must be parsable using DOM.
+ ///
+ ///
+ /// The XML resource to load object definitions from.
+ ///
+ ///
+ /// In the case of loading or parsing errors.
+ ///
+ public XmlObjectFactory(IResource resource) : this(resource, true, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the class,
+ /// with the given resource, which must be parsable using DOM.
+ ///
+ ///
+ /// The XML resource to load object definitions from.
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ ///
+ /// In the case of loading or parsing errors.
+ ///
+ public XmlObjectFactory(IResource resource, bool caseSensitive) : this(resource, caseSensitive, null)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the class,
+ /// with the given resource, which must be parsable using DOM, and the
+ /// given parent factory.
+ ///
+ ///
+ /// The XML resource to load object definitions from.
+ ///
+ /// The parent object factory (may be ).
+ ///
+ /// In the case of loading or parsing errors.
+ ///
+ public XmlObjectFactory(
+ IResource resource, IObjectFactory parentFactory)
+ : this(resource, true, parentFactory)
+ {}
+
+ ///
+ /// Creates a new instance of the class,
+ /// with the given resource, which must be parsable using DOM, and the
+ /// given parent factory.
+ ///
+ ///
+ /// The XML resource to load object definitions from.
+ ///
+ /// Flag specifying whether to make this object factory case sensitive or not.
+ /// The parent object factory (may be ).
+ ///
+ /// In the case of loading or parsing errors.
+ ///
+ public XmlObjectFactory(
+ IResource resource, bool caseSensitive, IObjectFactory parentFactory)
+ : base(caseSensitive, parentFactory)
+ {
+ ObjectDefinitionReader.LoadObjectDefinitions(resource);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets object definition reader to use.
+ ///
+ protected virtual IObjectDefinitionReader ObjectDefinitionReader
+ {
+ get
+ {
+ return new XmlObjectDefinitionReader(this);
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs
index 2cc7a2a0..27abf435 100644
--- a/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs
+++ b/src/Spring/Spring.Core/Objects/Factory/Xml/XmlReaderContext.cs
@@ -1,239 +1,238 @@
-#region License
-
-/*
- * Copyright 2002-2007 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.Xml;
-using Spring.Core.IO;
-using Spring.Objects.Factory.Config;
-using Spring.Objects.Factory.Parsing;
-using Spring.Objects.Factory.Support;
-using Spring.Util;
-
-namespace Spring.Objects.Factory.Xml
-{
- ///
- /// Extension of specific to use with an
- /// XmlObjectDefinitionReader.
- ///
- /// In future will contain access to IXmlParserRegistry
- /// $Id: XmlReaderContext.cs,v 1.6 2007/08/27 13:57:43 oakinger Exp $
- public class XmlReaderContext : ReaderContext
- {
-
- //TODO: Should have a ref to NamespaceParserRegistry, i.e. NamespaceHandlerResolver here....
-
- private IObjectDefinitionReader reader;
-
- private IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
-
- ///
- /// The maximum length of any XML fragment displayed in the error message
- /// reporting.
- ///
- ///
- ///
- /// Hopefully this will display enough context so that a user
- /// can pinpoint the cause of the error.
- ///
- ///
- private const int MaxXmlErrorFragmentLength = 255;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The resource.
- /// The reader.
- public XmlReaderContext(IResource resource, IObjectDefinitionReader reader) : base(resource)
- {
- this.reader = reader;
-
- }
-
-
- ///
- /// Gets the reader.
- ///
- /// The reader.
- public IObjectDefinitionReader Reader
- {
- get { return reader; }
- }
-
- ///
- /// Gets the resource loader.
- ///
- /// The resource loader.
- public IResourceLoader ResourceLoader
- {
- get { return reader.ResourceLoader; }
- }
-
- ///
- /// Gets the registry.
- ///
- /// The registry.
- public IObjectDefinitionRegistry Registry
- {
- get
- {
- return reader.Registry;
- }
- }
-
-
- ///
- /// Gets or sets the object definition factory.
- ///
- /// The object definition factory.
- public IObjectDefinitionFactory ObjectDefinitionFactory
- {
- get { return objectDefinitionFactory; }
- set { objectDefinitionFactory = value; }
- }
-
-
-
- ///
- /// Generates the name of the object.
- ///
- /// The object definition.
- /// the generated object name
- public string GenerateObjectName(IObjectDefinition objectDefinition)
- {
- return reader.ObjectNameGenerator.GenerateObjectName(objectDefinition, Registry);
- }
-
- ///
- /// Registers the name of the with generated.
- ///
- /// The object definition.
- /// the generated object name
- public string RegisterWithGeneratedName(IObjectDefinition objectDefinition)
- {
- string generatedName = GenerateObjectName(objectDefinition);
- Registry.RegisterObjectDefinition(generatedName, objectDefinition);
- return generatedName;
- }
-
- ///
- /// Reports a parse error by loading a
- /// with helpful contextual
- /// information and throwing said exception.
- ///
- ///
- ///
- /// Derived classes can of course override this method in order to implement
- /// validators capable of displaying a full list of errors found in the
- /// definition.
- ///
- ///
- ///
- /// The node that triggered the parse error.
- ///
- ///
- /// The name of the object that triggered the exception.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// Always throws an instance of this exception class, that will
- /// contain helpful contextual infomation about the parse error.
- ///
- ///
- public void ReportException(XmlNode node, string name, string message)
- {
- ReportException(node, name, message, null);
- }
-
- ///
- /// Reports a parse error by loading a
- /// with helpful contextual
- /// information and throwing said exception.
- ///
- ///
- ///
- /// Derived classes can of course override this method in order to implement
- /// validators capable of displaying a full list of errors found in the
- /// definition.
- ///
- ///
- ///
- /// The node that triggered the parse error.
- ///
- ///
- /// The name of the object that triggered the exception.
- ///
- ///
- /// A message about the error.
- ///
- ///
- /// The root cause of the parse error (if any - may be ).
- ///
- ///
- /// Always throws an instance of this exception class, that will
- /// contain helpful contextual infomation about the parse error.
- ///
- public virtual void ReportException(
- XmlNode node, string name, string message, Exception cause)
- {
- string xmlFragment;
-
- if (node is XmlAttribute)
- {
- xmlFragment = ((XmlAttribute)node).OwnerElement.OuterXml;
- }
- else
- {
- xmlFragment = node.OuterXml;
- }
- if (xmlFragment.Length > MaxXmlErrorFragmentLength)
- {
- xmlFragment = xmlFragment.Substring(0, MaxXmlErrorFragmentLength) + "...";
- }
-
- string resourceDescription = Resource.Description;
- int line = ConfigurationUtils.GetLineNumber(node);
- if (line > 0)
- {
- string atLine = " at line " + line;
- resourceDescription += atLine;
- }
- throw new ObjectDefinitionStoreException(
- resourceDescription, name, message + Environment.NewLine + xmlFragment, cause);
- }
-
- ///
- /// This method can be overwritten in order to implement validators
- /// capable of displaying a full list of errors found in the definition.
- ///
- ///
- /// The node that triggered the parse error.
- ///
- ///
- /// A message about the exception.
- ///
- public virtual void ReportFatalException(XmlNode node, string message)
- {
- throw new FatalObjectException(message);
- }
-
- }
-}
+#region License
+
+/*
+ * Copyright 2002-2007 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.Xml;
+using Spring.Core.IO;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Parsing;
+using Spring.Objects.Factory.Support;
+using Spring.Util;
+
+namespace Spring.Objects.Factory.Xml
+{
+ ///
+ /// Extension of specific to use with an
+ /// XmlObjectDefinitionReader.
+ ///
+ /// In future will contain access to IXmlParserRegistry
+ public class XmlReaderContext : ReaderContext
+ {
+
+ //TODO: Should have a ref to NamespaceParserRegistry, i.e. NamespaceHandlerResolver here....
+
+ private IObjectDefinitionReader reader;
+
+ private IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
+
+ ///
+ /// The maximum length of any XML fragment displayed in the error message
+ /// reporting.
+ ///
+ ///
+ ///
+ /// Hopefully this will display enough context so that a user
+ /// can pinpoint the cause of the error.
+ ///
+ ///
+ private const int MaxXmlErrorFragmentLength = 255;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The resource.
+ /// The reader.
+ public XmlReaderContext(IResource resource, IObjectDefinitionReader reader) : base(resource)
+ {
+ this.reader = reader;
+
+ }
+
+
+ ///
+ /// Gets the reader.
+ ///
+ /// The reader.
+ public IObjectDefinitionReader Reader
+ {
+ get { return reader; }
+ }
+
+ ///
+ /// Gets the resource loader.
+ ///
+ /// The resource loader.
+ public IResourceLoader ResourceLoader
+ {
+ get { return reader.ResourceLoader; }
+ }
+
+ ///
+ /// Gets the registry.
+ ///
+ /// The registry.
+ public IObjectDefinitionRegistry Registry
+ {
+ get
+ {
+ return reader.Registry;
+ }
+ }
+
+
+ ///
+ /// Gets or sets the object definition factory.
+ ///
+ /// The object definition factory.
+ public IObjectDefinitionFactory ObjectDefinitionFactory
+ {
+ get { return objectDefinitionFactory; }
+ set { objectDefinitionFactory = value; }
+ }
+
+
+
+ ///
+ /// Generates the name of the object.
+ ///
+ /// The object definition.
+ /// the generated object name
+ public string GenerateObjectName(IObjectDefinition objectDefinition)
+ {
+ return reader.ObjectNameGenerator.GenerateObjectName(objectDefinition, Registry);
+ }
+
+ ///
+ /// Registers the name of the with generated.
+ ///
+ /// The object definition.
+ /// the generated object name
+ public string RegisterWithGeneratedName(IObjectDefinition objectDefinition)
+ {
+ string generatedName = GenerateObjectName(objectDefinition);
+ Registry.RegisterObjectDefinition(generatedName, objectDefinition);
+ return generatedName;
+ }
+
+ ///
+ /// Reports a parse error by loading a
+ /// with helpful contextual
+ /// information and throwing said exception.
+ ///
+ ///
+ ///
+ /// Derived classes can of course override this method in order to implement
+ /// validators capable of displaying a full list of errors found in the
+ /// definition.
+ ///
+ ///
+ ///
+ /// The node that triggered the parse error.
+ ///
+ ///
+ /// The name of the object that triggered the exception.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// Always throws an instance of this exception class, that will
+ /// contain helpful contextual infomation about the parse error.
+ ///
+ ///
+ public void ReportException(XmlNode node, string name, string message)
+ {
+ ReportException(node, name, message, null);
+ }
+
+ ///
+ /// Reports a parse error by loading a
+ /// with helpful contextual
+ /// information and throwing said exception.
+ ///
+ ///
+ ///
+ /// Derived classes can of course override this method in order to implement
+ /// validators capable of displaying a full list of errors found in the
+ /// definition.
+ ///
- /// Typically not directly used by application code but rather implicitly
- /// via an .
- ///
- ///
- /// Implementing classes have the ability to get and set property values
- /// (individually or in bulk), get property descriptors and query the
- /// readability and writability of properties.
- ///
- ///
- /// This interface supports nested properties enabling the setting
- /// of properties on subproperties to an unlimited depth.
- ///
- ///
- /// If a property update causes an exception, a
- /// will be thrown. Bulk
- /// updates continue after exceptions are encountered, throwing an exception
- /// wrapping all exceptions encountered during the update.
- ///
- ///
- /// implementations can be used
- /// repeatedly, with their "target" or wrapped object changed.
- ///
- ///
- /// Rod Johnson
- /// Mark Pollack (.NET)
- /// $Id: IObjectWrapper.cs,v 1.15 2007/07/31 21:43:52 markpollack Exp $
- ///
- public interface IObjectWrapper
- {
- ///
- /// The object wrapped by the wrapper (cannot be ).
- ///
- ///
- ///
- /// Implementations are required to allow the type of the wrapped
- /// object to change.
- ///
- ///
- /// The object wrapped by this wrapper.
- object WrappedInstance { get; set; }
-
- ///
- /// Convenience method to return the
- /// of the wrapped object.
- ///
- /// The of the wrapped object.
- Type WrappedType { get; }
-
- /// Get the value of a property.
- ///
- /// The name of the property to get the value of. May be nested.
- ///
- /// The value of the property.
- ///
- /// if the property isn't readable, or if the getting the value throws
- /// an exception.
- ///
- object GetPropertyValue(string theProperty);
-
- ///
- /// Get the for a particular
- /// property.
- ///
- ///
- /// The property to be retrieved.
- ///
- ///
- /// The for the particular
- /// property.
- ///
- PropertyInfo GetPropertyInfo(string theProperty);
-
- ///
- /// Get the for a particular property.
- ///
- ///
- /// The property the of which is to be retrieved.
- ///
- ///
- /// The for a particular property..
- ///
- Type GetPropertyType(string theProperty);
-
- ///
- /// Get all of the instances for
- /// all of the properties of the wrapped object.
- ///
- ///
- /// An array of instances.
- ///
- PropertyInfo[] GetPropertyInfos();
-
- ///
- /// Set a property value.
- ///
- ///
- ///
- /// This is the preferred way to update an individual property.
- ///
- ///
- /// The new property value.
- void SetPropertyValue(PropertyValue propertyValue);
-
- ///
- /// Set a property value.
- ///
- ///
- ///
- /// This method is provided for convenience only. The
- ///
- /// method is more powerful.
- ///
- ///
- ///
- /// The name of the property to set value of.
- ///
- /// The new property value.
- void SetPropertyValue(string theProperty, object propertyValue);
-
- /// Set a number of property values in bulk.
- ///
- ///
- /// This is the preferred way to perform a bulk update.
- ///
- ///
- /// Note that performing a bulk update differs from performing a single update,
- /// in that an implementation of this class will continue to update properties
- /// if a recoverable error (such as a vetoed property change or a type
- /// mismatch, but not an invalid property name or the like) is
- /// encountered, throwing a
- /// containing
- /// all the individual errors. This exception can be examined later to see all
- /// binding errors. Properties that were successfully updated stay changed.
- ///
- ///
- /// Does not allow the setting of unknown fields. Equivalent to
- ///
- /// with an argument of false for the second parameter.
- ///
- ///
- ///
- /// The collection of instances to
- /// set on the wrapped object.
- ///
- void SetPropertyValues(IPropertyValues values);
-
- ///
- /// Set a number of property values in bulk with full control over behavior.
- ///
- ///
- ///
- /// Note that performing a bulk update differs from performing a single update,
- /// in that an implementation of this class will continue to update properties
- /// if a recoverable error (such as a vetoed property change or a type
- /// mismatch, but not an invalid property name or the like) is
- /// encountered, throwing a
- /// containing
- /// all the individual errors. This exception can be examined later to see all
- /// binding errors. Properties that were successfully updated stay changed.
- ///
- ///
Does not allow the setting of unknown fields.
- ///
+ /// Typically not directly used by application code but rather implicitly
+ /// via an .
+ ///
+ ///
+ /// Implementing classes have the ability to get and set property values
+ /// (individually or in bulk), get property descriptors and query the
+ /// readability and writability of properties.
+ ///
+ ///
+ /// This interface supports nested properties enabling the setting
+ /// of properties on subproperties to an unlimited depth.
+ ///
+ ///
+ /// If a property update causes an exception, a
+ /// will be thrown. Bulk
+ /// updates continue after exceptions are encountered, throwing an exception
+ /// wrapping all exceptions encountered during the update.
+ ///
+ ///
+ /// implementations can be used
+ /// repeatedly, with their "target" or wrapped object changed.
+ ///
+ ///
+ /// Rod Johnson
+ /// Mark Pollack (.NET)
+ public interface IObjectWrapper
+ {
+ ///
+ /// The object wrapped by the wrapper (cannot be ).
+ ///
+ ///
+ ///
+ /// Implementations are required to allow the type of the wrapped
+ /// object to change.
+ ///
+ ///
+ /// The object wrapped by this wrapper.
+ object WrappedInstance { get; set; }
+
+ ///
+ /// Convenience method to return the
+ /// of the wrapped object.
+ ///
+ /// The of the wrapped object.
+ Type WrappedType { get; }
+
+ /// Get the value of a property.
+ ///
+ /// The name of the property to get the value of. May be nested.
+ ///
+ /// The value of the property.
+ ///
+ /// if the property isn't readable, or if the getting the value throws
+ /// an exception.
+ ///
+ object GetPropertyValue(string theProperty);
+
+ ///
+ /// Get the for a particular
+ /// property.
+ ///
+ ///
+ /// The property to be retrieved.
+ ///
+ ///
+ /// The for the particular
+ /// property.
+ ///
+ PropertyInfo GetPropertyInfo(string theProperty);
+
+ ///
+ /// Get the for a particular property.
+ ///
+ ///
+ /// The property the of which is to be retrieved.
+ ///
+ ///
+ /// The for a particular property..
+ ///
+ Type GetPropertyType(string theProperty);
+
+ ///
+ /// Get all of the instances for
+ /// all of the properties of the wrapped object.
+ ///
+ ///
+ /// An array of instances.
+ ///
+ PropertyInfo[] GetPropertyInfos();
+
+ ///
+ /// Set a property value.
+ ///
+ ///
+ ///
+ /// This is the preferred way to update an individual property.
+ ///
+ ///
+ /// The new property value.
+ void SetPropertyValue(PropertyValue propertyValue);
+
+ ///
+ /// Set a property value.
+ ///
+ ///
+ ///
+ /// This method is provided for convenience only. The
+ ///
+ /// method is more powerful.
+ ///
+ ///
+ ///
+ /// The name of the property to set value of.
+ ///
+ /// The new property value.
+ void SetPropertyValue(string theProperty, object propertyValue);
+
+ /// Set a number of property values in bulk.
+ ///
+ ///
+ /// This is the preferred way to perform a bulk update.
+ ///
+ ///
+ /// Note that performing a bulk update differs from performing a single update,
+ /// in that an implementation of this class will continue to update properties
+ /// if a recoverable error (such as a vetoed property change or a type
+ /// mismatch, but not an invalid property name or the like) is
+ /// encountered, throwing a
+ /// containing
+ /// all the individual errors. This exception can be examined later to see all
+ /// binding errors. Properties that were successfully updated stay changed.
+ ///
+ ///
+ /// Does not allow the setting of unknown fields. Equivalent to
+ ///
+ /// with an argument of false for the second parameter.
+ ///
+ ///
+ ///
+ /// The collection of instances to
+ /// set on the wrapped object.
+ ///
+ void SetPropertyValues(IPropertyValues values);
+
+ ///
+ /// Set a number of property values in bulk with full control over behavior.
+ ///
+ ///
+ ///
+ /// Note that performing a bulk update differs from performing a single update,
+ /// in that an implementation of this class will continue to update properties
+ /// if a recoverable error (such as a vetoed property change or a type
+ /// mismatch, but not an invalid property name or the like) is
+ /// encountered, throwing a
+ /// containing
+ /// all the individual errors. This exception can be examined later to see all
+ /// binding errors. Properties that were successfully updated stay changed.
+ ///
+ ///
Does not allow the setting of unknown fields.
+ ///
- /// Allows simple manipulation of properties, and provides constructors to
- /// support deep copy and construction from a number of collection types such as
- /// and
- /// .
- ///
- ///
- /// Rod Johnson
- /// Mark Pollack (.NET)
- /// Rick Evans (.NET)
- /// $Id: MutablePropertyValues.cs,v 1.15 2007/03/16 04:01:29 aseovic Exp $
- [Serializable]
- public class MutablePropertyValues : IPropertyValues
- {
- #region Fields
-
- ///
- /// The list of objects.
- ///
- private IList propertyValuesList = new ArrayList();
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// The returned instance is initially empty...
- /// s can be added with the various
- /// overloaded ,
- /// ,
- /// ,
- /// and
- /// methods.
- ///
- ///
- ///
- ///
- public MutablePropertyValues ()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- ///
- /// Deep copy constructor. Guarantees
- /// references are independent, although it can't deep copy objects currently
- /// referenced by individual objects.
- ///
- ///
- public MutablePropertyValues (IPropertyValues other)
- {
- if (other != null)
- {
- AddAll (other.PropertyValues);
- }
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The with property values
- /// keyed by property name, which must be a .
- ///
- public MutablePropertyValues (IDictionary map)
- {
- AddAll (map);
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// Property to retrieve the array of property values.
- ///
- public PropertyValue[] PropertyValues
- {
- get { return (PropertyValue[]) ArrayList.Adapter (propertyValuesList).ToArray (typeof (PropertyValue)); }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Overloaded version of Add that takes a property name and a property value.
- ///
- ///
- /// The name of the property.
- ///
- ///
- /// The value of the property.
- ///
- public void Add (string propertyName, object propertyValue)
- {
- Add (new PropertyValue (propertyName, propertyValue));
- }
-
- ///
- /// Add the supplied object,
- /// replacing any existing one for the respective property.
- ///
- ///
- /// The object to add.
- ///
- public void Add (PropertyValue pv)
- {
- for (int i = 0; i < propertyValuesList.Count; ++i)
- {
- PropertyValue currentPv = (PropertyValue) propertyValuesList [i];
- if (currentPv.Name.Equals (pv.Name))
- {
- propertyValuesList[i] = pv;
- return ;
- }
- }
- propertyValuesList.Add (pv);
- }
-
- ///
- /// Add all property values from the given
- /// .
- ///
- ///
- /// The map of property values, the keys of which must be
- /// s.
- ///
- public void AddAll (IDictionary map)
- {
- if (map != null)
- {
- foreach (string key in map.Keys)
- {
- Add (new PropertyValue (key, map [key]));
- }
- }
- }
-
- ///
- /// Add all property values from the given
- /// .
- ///
- ///
- /// The list of s to be added.
- ///
- public void AddAll (IList values)
- {
- if (values != null)
- {
- foreach (PropertyValue value in values)
- {
- Add (value);
- }
- }
- }
-
- ///
- /// Remove the given , if contained.
- ///
- ///
- /// The to remove.
- ///
- public void Remove (PropertyValue pv)
- {
- propertyValuesList.Remove (pv);
- }
-
- ///
- /// Removes the named , if contained.
- ///
- ///
- /// The name of the property.
- ///
- public void Remove (string propertyName)
- {
- Remove (GetPropertyValue (propertyName));
- }
-
- ///
- /// Modify a object held in this object. Indexed from 0.
- ///
- public void SetPropertyValueAt (PropertyValue pv, int i)
- {
- propertyValuesList [i] = pv;
- }
-
- ///
- /// Return the property value given the name.
- ///
- ///
- /// The property name is checked in a case-insensitive fashion.
- ///
- ///
- /// The name of the property.
- ///
- ///
- /// The property value.
- ///
- public PropertyValue GetPropertyValue (string propertyName)
- {
- string propertyNameLowered = propertyName.ToLower (CultureInfo.CurrentCulture);
- foreach (PropertyValue pv in propertyValuesList)
- {
- if (pv.Name.ToLower(CultureInfo.CurrentCulture).Equals (propertyNameLowered))
- {
- return pv;
- }
- }
- return null;
- }
-
- ///
- /// Does the container of properties contain one of this name.
- ///
- /// The name of the property to search for.
- ///
- /// True if the property is contained in this collection, false otherwise.
- ///
- public bool Contains (string propertyName)
- {
- return GetPropertyValue (propertyName) != null;
- }
-
- ///
- /// Return the difference (changes, additions, but not removals) of
- /// property values between the supplied argument and the values
- /// contained in the collection.
- ///
- /// Another property values collection.
- ///
- /// The collection of property values that are different than the supplied one.
- ///
- public IPropertyValues ChangesSince (IPropertyValues old)
- {
- MutablePropertyValues changes = new MutablePropertyValues ();
- if (old == this)
- {
- return changes;
- }
- // for each property value in this (the newer set)
- foreach (PropertyValue newProperty in propertyValuesList)
- {
- PropertyValue oldProperty = old.GetPropertyValue (newProperty.Name);
- if (oldProperty == null)
- {
- // if there wasn't an old one, add it
- changes.Add (newProperty);
- }
- else if (!oldProperty.Equals (newProperty))
- {
- // it's changed
- changes.Add (newProperty);
- }
- }
- return changes;
- }
-
- ///
- /// Returns an that can iterate
- /// through a collection.
- ///
- ///
- ///
- /// The returned is the
- /// exposed by the
- ///
- /// property.
- ///
+ /// Allows simple manipulation of properties, and provides constructors to
+ /// support deep copy and construction from a number of collection types such as
+ /// and
+ /// .
+ ///
+ ///
+ /// Rod Johnson
+ /// Mark Pollack (.NET)
+ /// Rick Evans (.NET)
+ [Serializable]
+ public class MutablePropertyValues : IPropertyValues
+ {
+ #region Fields
+
+ ///
+ /// The list of objects.
+ ///
+ private IList propertyValuesList = new ArrayList();
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// The returned instance is initially empty...
+ /// s can be added with the various
+ /// overloaded ,
+ /// ,
+ /// ,
+ /// and
+ /// methods.
+ ///
+ ///
+ ///
+ ///
+ public MutablePropertyValues ()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ ///
+ /// Deep copy constructor. Guarantees
+ /// references are independent, although it can't deep copy objects currently
+ /// referenced by individual objects.
+ ///
+ ///
+ public MutablePropertyValues (IPropertyValues other)
+ {
+ if (other != null)
+ {
+ AddAll (other.PropertyValues);
+ }
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The with property values
+ /// keyed by property name, which must be a .
+ ///
+ public MutablePropertyValues (IDictionary map)
+ {
+ AddAll (map);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Property to retrieve the array of property values.
+ ///
+ public PropertyValue[] PropertyValues
+ {
+ get { return (PropertyValue[]) ArrayList.Adapter (propertyValuesList).ToArray (typeof (PropertyValue)); }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Overloaded version of Add that takes a property name and a property value.
+ ///
+ ///
+ /// The name of the property.
+ ///
+ ///
+ /// The value of the property.
+ ///
+ public void Add (string propertyName, object propertyValue)
+ {
+ Add (new PropertyValue (propertyName, propertyValue));
+ }
+
+ ///
+ /// Add the supplied object,
+ /// replacing any existing one for the respective property.
+ ///
+ ///
+ /// The object to add.
+ ///
+ public void Add (PropertyValue pv)
+ {
+ for (int i = 0; i < propertyValuesList.Count; ++i)
+ {
+ PropertyValue currentPv = (PropertyValue) propertyValuesList [i];
+ if (currentPv.Name.Equals (pv.Name))
+ {
+ propertyValuesList[i] = pv;
+ return ;
+ }
+ }
+ propertyValuesList.Add (pv);
+ }
+
+ ///
+ /// Add all property values from the given
+ /// .
+ ///
+ ///
+ /// The map of property values, the keys of which must be
+ /// s.
+ ///
+ public void AddAll (IDictionary map)
+ {
+ if (map != null)
+ {
+ foreach (string key in map.Keys)
+ {
+ Add (new PropertyValue (key, map [key]));
+ }
+ }
+ }
+
+ ///
+ /// Add all property values from the given
+ /// .
+ ///
+ ///
+ /// The list of s to be added.
+ ///
+ public void AddAll (IList values)
+ {
+ if (values != null)
+ {
+ foreach (PropertyValue value in values)
+ {
+ Add (value);
+ }
+ }
+ }
+
+ ///
+ /// Remove the given , if contained.
+ ///
+ ///
+ /// The to remove.
+ ///
+ public void Remove (PropertyValue pv)
+ {
+ propertyValuesList.Remove (pv);
+ }
+
+ ///
+ /// Removes the named , if contained.
+ ///
+ ///
+ /// The name of the property.
+ ///
+ public void Remove (string propertyName)
+ {
+ Remove (GetPropertyValue (propertyName));
+ }
+
+ ///
+ /// Modify a object held in this object. Indexed from 0.
+ ///
+ public void SetPropertyValueAt (PropertyValue pv, int i)
+ {
+ propertyValuesList [i] = pv;
+ }
+
+ ///
+ /// Return the property value given the name.
+ ///
+ ///
+ /// The property name is checked in a case-insensitive fashion.
+ ///
+ ///
+ /// The name of the property.
+ ///
+ ///
+ /// The property value.
+ ///
+ public PropertyValue GetPropertyValue (string propertyName)
+ {
+ string propertyNameLowered = propertyName.ToLower (CultureInfo.CurrentCulture);
+ foreach (PropertyValue pv in propertyValuesList)
+ {
+ if (pv.Name.ToLower(CultureInfo.CurrentCulture).Equals (propertyNameLowered))
+ {
+ return pv;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Does the container of properties contain one of this name.
+ ///
+ /// The name of the property to search for.
+ ///
+ /// True if the property is contained in this collection, false otherwise.
+ ///
+ public bool Contains (string propertyName)
+ {
+ return GetPropertyValue (propertyName) != null;
+ }
+
+ ///
+ /// Return the difference (changes, additions, but not removals) of
+ /// property values between the supplied argument and the values
+ /// contained in the collection.
+ ///
+ /// Another property values collection.
+ ///
+ /// The collection of property values that are different than the supplied one.
+ ///
+ public IPropertyValues ChangesSince (IPropertyValues old)
+ {
+ MutablePropertyValues changes = new MutablePropertyValues ();
+ if (old == this)
+ {
+ return changes;
+ }
+ // for each property value in this (the newer set)
+ foreach (PropertyValue newProperty in propertyValuesList)
+ {
+ PropertyValue oldProperty = old.GetPropertyValue (newProperty.Name);
+ if (oldProperty == null)
+ {
+ // if there wasn't an old one, add it
+ changes.Add (newProperty);
+ }
+ else if (!oldProperty.Equals (newProperty))
+ {
+ // it's changed
+ changes.Add (newProperty);
+ }
+ }
+ return changes;
+ }
+
+ ///
+ /// Returns an that can iterate
+ /// through a collection.
+ ///
+ ///
+ ///
+ /// The returned is the
+ /// exposed by the
+ ///
+ /// property.
+ ///
- /// will convert
- /// and array
- /// values to the corresponding target arrays, if necessary. Custom
- /// s that deal with
- /// s or arrays can be written against a
- /// comma delimited as
- /// arrays are converted in such a format if the array itself is not assignable.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Jean-Pierre Pawlak
- /// Mark Pollack (.NET)
- /// Aleksandar Seovic(.NET)
- /// $Id: ObjectWrapper.cs,v 1.72 2007/07/31 08:18:20 markpollack Exp $
- [Serializable]
- public class ObjectWrapper : IObjectWrapper
- {
- private ILog Log = LogManager.GetLogger(typeof(ObjectWrapper));
-
- #region Fields
-
- /// The wrapped object.
- private object wrappedObject;
-
- ///
- /// The ILog instance for this class. We'll create a lot of these objects,
- /// so we don't want a new instance every time.
- ///
- private static readonly ILog log = LogManager.GetLogger(typeof(ObjectWrapper));
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// The wrapped target instance will need to be set afterwards.
- ///
- ///
- ///
- public ObjectWrapper()
- {}
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- /// The object wrapped by this .
- ///
- ///
- /// If the supplied is .
- ///
- public ObjectWrapper(object instance)
- {
- WrappedInstance = instance;
- }
-
- ///
- /// Creates a new instance of the class,
- /// instantiating a new instance of the specified and using
- /// it as the .
- ///
- ///
- ///
- /// Please note that the passed as the
- /// argument must have a no-argument constructor.
- /// If it does not, an exception will be thrown when this class attempts
- /// to instantiate the supplied using it's
- /// (non-existent) constructor.
- ///
- ///
- ///
- /// The to instantiate and wrap.
- ///
- ///
- /// If the is , or if the
- /// invocation of the s default (no-arg) constructor
- /// fails (due to invalid arguments, insufficient permissions, etc).
- ///
- public ObjectWrapper(Type type) : this(true)
- {
- try
- {
- WrappedInstance = ObjectUtils.InstantiateType(type);
- } catch (FatalReflectionException e)
- {
- throw new FatalObjectException(e.Message, e);
- }
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The object wrapped by this .
- ///
- ///
- /// If the object cannot be changed; or an attempt is made to set the
- /// value of this property to .
- ///
- public object WrappedInstance
- {
- get { return wrappedObject; }
- set
- {
- if (value == null)
- {
- throw new FatalObjectException("Wraped instance cannot be null.");
- }
- this.wrappedObject = value;
- }
- }
-
- ///
- /// Convenience method to return the of the wrapped object.
- ///
- ///
- ///
- /// Do not use this (convenience) method prior to setting the
- /// property.
- ///
- ///
- ///
- /// The of the wrapped object.
- ///
- ///
- /// If the property
- /// is .
- ///
- public Type WrappedType
- {
- get { return WrappedInstance.GetType(); }
- }
-
- #endregion
-
- #region Methods
-
- /// Gets the value of a property.
- ///
- /// The name of the property to get the value of.
- ///
- /// The value of the property.
- ///
- /// If there is no such property, if the property isn't readable, or
- /// if getting the property value throws an 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);
- }
- }
-
- /// Gets the value of a property.
- ///
- /// The property expression that should be used to retrieve the property value.
- ///
- /// The value of the property.
- ///
- /// If there is no such property, if the property isn't readable, or
- /// if getting the property value throws an exception.
- ///
- public virtual object GetPropertyValue(IExpression propertyExpression)
- {
- return propertyExpression.GetValue(this.wrappedObject);
- }
-
- ///
- /// Sets a property value.
- ///
- ///
- ///
- /// This method is provided for convenience only. The
- ///
- /// method is more powerful.
- ///
- ///
- ///
- /// The name of the property to set value of.
- ///
- /// The new value.
- 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);
- }
- }
-
- ///
- /// Sets a property value.
- ///
- ///
- /// The property expression that should be used to set the property value.
- ///
- /// The new value.
- public virtual void SetPropertyValue(IExpression propertyExpression, object val)
- {
- propertyExpression.SetValue(this.wrappedObject, val);
- }
-
- ///
- /// Sets a property value.
- ///
- ///
- ///
- /// This is the preferred way to update an individual property.
- ///
- ///
- ///
- /// The object containing new property value.
- ///
- public virtual void SetPropertyValue(PropertyValue pv)
- {
- SetPropertyValue(pv.Expression, pv.Value);
- }
-
- /// Set a number of property values in bulk.
- ///
- ///
- /// Does not allow unknown fields. Equivalent to
- ///
- /// with and for
- /// arguments.
- ///
- ///
- ///
- /// The to set on the target
- /// object.
- ///
- ///
- /// If an error is encountered while setting a property.
- ///
- ///
- /// On a mismatch while setting a property, insufficient permissions, etc.
- ///
- ///
- public virtual void SetPropertyValues(IPropertyValues pvs)
- {
- SetPropertyValues(pvs, false);
- }
-
- ///
- /// Perform a bulk update with full control over behavior.
- ///
- ///
- ///
- /// 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 .
- ///
+ /// will convert
+ /// and array
+ /// values to the corresponding target arrays, if necessary. Custom
+ /// s that deal with
+ /// s or arrays can be written against a
+ /// comma delimited as
+ /// arrays are converted in such a format if the array itself is not assignable.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Jean-Pierre Pawlak
+ /// Mark Pollack (.NET)
+ /// Aleksandar Seovic(.NET)
+ [Serializable]
+ public class ObjectWrapper : IObjectWrapper
+ {
+ private ILog Log = LogManager.GetLogger(typeof(ObjectWrapper));
+
+ #region Fields
+
+ /// The wrapped object.
+ private object wrappedObject;
+
+ ///
+ /// The ILog instance for this class. We'll create a lot of these objects,
+ /// so we don't want a new instance every time.
+ ///
+ private static readonly ILog log = LogManager.GetLogger(typeof(ObjectWrapper));
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// The wrapped target instance will need to be set afterwards.
+ ///
+ ///
+ ///
+ public ObjectWrapper()
+ {}
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ /// The object wrapped by this .
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public ObjectWrapper(object instance)
+ {
+ WrappedInstance = instance;
+ }
+
+ ///
+ /// Creates a new instance of the class,
+ /// instantiating a new instance of the specified and using
+ /// it as the .
+ ///
+ ///
+ ///
+ /// Please note that the passed as the
+ /// argument must have a no-argument constructor.
+ /// If it does not, an exception will be thrown when this class attempts
+ /// to instantiate the supplied using it's
+ /// (non-existent) constructor.
+ ///
+ ///
+ ///
+ /// The to instantiate and wrap.
+ ///
+ ///
+ /// If the is , or if the
+ /// invocation of the s default (no-arg) constructor
+ /// fails (due to invalid arguments, insufficient permissions, etc).
+ ///
+ public ObjectWrapper(Type type) : this(true)
+ {
+ try
+ {
+ WrappedInstance = ObjectUtils.InstantiateType(type);
+ } catch (FatalReflectionException e)
+ {
+ throw new FatalObjectException(e.Message, e);
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The object wrapped by this .
+ ///
+ ///
+ /// If the object cannot be changed; or an attempt is made to set the
+ /// value of this property to .
+ ///
+ public object WrappedInstance
+ {
+ get { return wrappedObject; }
+ set
+ {
+ if (value == null)
+ {
+ throw new FatalObjectException("Wraped instance cannot be null.");
+ }
+ this.wrappedObject = value;
+ }
+ }
+
+ ///
+ /// Convenience method to return the of the wrapped object.
+ ///
+ ///
+ ///
+ /// Do not use this (convenience) method prior to setting the
+ /// property.
+ ///
+ ///
+ ///
+ /// The of the wrapped object.
+ ///
+ ///
+ /// If the property
+ /// is .
+ ///
+ public Type WrappedType
+ {
+ get { return WrappedInstance.GetType(); }
+ }
+
+ #endregion
+
+ #region Methods
+
+ /// Gets the value of a property.
+ ///
+ /// The name of the property to get the value of.
+ ///
+ /// The value of the property.
+ ///
+ /// If there is no such property, if the property isn't readable, or
+ /// if getting the property value throws an 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);
+ }
+ }
+
+ /// Gets the value of a property.
+ ///
+ /// The property expression that should be used to retrieve the property value.
+ ///
+ /// The value of the property.
+ ///
+ /// If there is no such property, if the property isn't readable, or
+ /// if getting the property value throws an exception.
+ ///
+ public virtual object GetPropertyValue(IExpression propertyExpression)
+ {
+ return propertyExpression.GetValue(this.wrappedObject);
+ }
+
+ ///
+ /// Sets a property value.
+ ///
+ ///
+ ///
+ /// This method is provided for convenience only. The
+ ///
+ /// method is more powerful.
+ ///
+ ///
+ ///
+ /// The name of the property to set value of.
+ ///
+ /// The new value.
+ 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);
+ }
+ }
+
+ ///
+ /// Sets a property value.
+ ///
+ ///
+ /// The property expression that should be used to set the property value.
+ ///
+ /// The new value.
+ public virtual void SetPropertyValue(IExpression propertyExpression, object val)
+ {
+ propertyExpression.SetValue(this.wrappedObject, val);
+ }
+
+ ///
+ /// Sets a property value.
+ ///
+ ///
+ ///
+ /// This is the preferred way to update an individual property.
+ ///
+ ///
+ ///
+ /// The object containing new property value.
+ ///
+ public virtual void SetPropertyValue(PropertyValue pv)
+ {
+ SetPropertyValue(pv.Expression, pv.Value);
+ }
+
+ /// Set a number of property values in bulk.
+ ///
+ ///
+ /// Does not allow unknown fields. Equivalent to
+ ///
+ /// with and for
+ /// arguments.
+ ///
+ ///
+ ///
+ /// The to set on the target
+ /// object.
+ ///
+ ///
+ /// If an error is encountered while setting a property.
+ ///
+ ///
+ /// On a mismatch while setting a property, insufficient permissions, etc.
+ ///
+ ///
+ public virtual void SetPropertyValues(IPropertyValues pvs)
+ {
+ SetPropertyValues(pvs, false);
+ }
+
+ ///
+ /// Perform a bulk update with full control over behavior.
+ ///
+ ///
+ ///
+ /// 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 .
+ ///
- /// An object of this class is created at the beginning of the binding
- /// process, and errors added to it as necessary.
- ///
- ///
- /// The binding process continues when it encounters application-level
- /// s, applying those changes
- /// that can be applied and storing rejected changes in an instance of this class.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Mark Pollack (.NET)
- /// $Id: PropertyAccessExceptionsException.cs,v 1.15 2007/07/31 00:26:30 markpollack Exp $
- [Serializable]
- public class PropertyAccessExceptionsException : ObjectsException
- {
- #region Constants
-
- private static PropertyAccessException[] EmptyPropertyAccessExceptions
- = new PropertyAccessException[] {};
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the PropertyAccessExceptionsException class.
- ///
- public PropertyAccessExceptionsException()
- {
- }
-
- ///
- /// Creates a new instance of the PropertyAccessExceptionsException class.
- ///
- ///
- /// A message about the exception.
- ///
- public PropertyAccessExceptionsException(string message)
- : base(message)
- {
- }
-
- ///
- /// Creates a new instance of the PropertyAccessExceptionsException class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception that is being wrapped.
- ///
- public PropertyAccessExceptionsException(string message, Exception rootCause)
- : base(message, rootCause)
- {
- }
-
- ///
- /// Create new empty PropertyAccessExceptionsException.
- /// We'll add errors to it as we attempt to bind properties.
- ///
- public PropertyAccessExceptionsException(
- IObjectWrapper objectWrapper,
- PropertyAccessException[] propertyAccessExceptions)
- : base(string.Empty)
- {
- _objectWrapper = objectWrapper;
- _propertyAccessExceptions
- = propertyAccessExceptions == null ?
- EmptyPropertyAccessExceptions :
- propertyAccessExceptions;
- }
-
- ///
- /// Creates a new instance of the PropertyAccessExceptionsException class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected PropertyAccessExceptionsException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- #endregion
-
- ///
- /// Return the that generated
- /// this exception.
- ///
- public IObjectWrapper ObjectWrapper
- {
- get { return _objectWrapper; }
- }
-
- ///
- /// Return the object we're binding to.
- ///
- public object BindObject
- {
- get { return ObjectWrapper.WrappedInstance; }
- }
-
- ///
- /// If this returns zero (0), no errors were encountered during binding.
- ///
- public int ExceptionCount
- {
- get { return PropertyAccessExceptions.Length; }
- }
-
- ///
- /// Return an array of the s
- /// stored in this object.
- ///
- ///
- ///
- /// Will return the empty array (not ) if there were no errors.
- ///
+ /// An object of this class is created at the beginning of the binding
+ /// process, and errors added to it as necessary.
+ ///
+ ///
+ /// The binding process continues when it encounters application-level
+ /// s, applying those changes
+ /// that can be applied and storing rejected changes in an instance of this class.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ [Serializable]
+ public class PropertyAccessExceptionsException : ObjectsException
+ {
+ #region Constants
+
+ private static PropertyAccessException[] EmptyPropertyAccessExceptions
+ = new PropertyAccessException[] {};
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the PropertyAccessExceptionsException class.
+ ///
+ public PropertyAccessExceptionsException()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the PropertyAccessExceptionsException class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public PropertyAccessExceptionsException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the PropertyAccessExceptionsException class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception that is being wrapped.
+ ///
+ public PropertyAccessExceptionsException(string message, Exception rootCause)
+ : base(message, rootCause)
+ {
+ }
+
+ ///
+ /// Create new empty PropertyAccessExceptionsException.
+ /// We'll add errors to it as we attempt to bind properties.
+ ///
+ public PropertyAccessExceptionsException(
+ IObjectWrapper objectWrapper,
+ PropertyAccessException[] propertyAccessExceptions)
+ : base(string.Empty)
+ {
+ _objectWrapper = objectWrapper;
+ _propertyAccessExceptions
+ = propertyAccessExceptions == null ?
+ EmptyPropertyAccessExceptions :
+ propertyAccessExceptions;
+ }
+
+ ///
+ /// Creates a new instance of the PropertyAccessExceptionsException class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected PropertyAccessExceptionsException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ #endregion
+
+ ///
+ /// Return the that generated
+ /// this exception.
+ ///
+ public IObjectWrapper ObjectWrapper
+ {
+ get { return _objectWrapper; }
+ }
+
+ ///
+ /// Return the object we're binding to.
+ ///
+ public object BindObject
+ {
+ get { return ObjectWrapper.WrappedInstance; }
+ }
+
+ ///
+ /// If this returns zero (0), no errors were encountered during binding.
+ ///
+ public int ExceptionCount
+ {
+ get { return PropertyAccessExceptions.Length; }
+ }
+
+ ///
+ /// Return an array of the s
+ /// stored in this object.
+ ///
+ ///
+ ///
+ /// Will return the empty array (not ) if there were no errors.
+ ///
- /// Using an object here, rather than just storing all properties in a
- /// map keyed by property name, allows for more flexibility, and the
- /// ability to handle indexed properties in a special way if necessary.
- ///
- ///
- /// Note that the value doesn't need to be the final required
- /// : an
- /// implementation must
- /// handle any necessary conversion, as this object doesn't know anything
- /// about the objects it will be applied to.
- ///
- ///
- /// Rod Johnson
- /// Mark Pollack (.NET)
- /// $Id: PropertyValue.cs,v 1.15 2007/07/31 00:08:42 markpollack Exp $
- [Serializable]
- public class PropertyValue
- {
- private string propertyName;
- private IExpression propertyExpression;
- private object propertyValue;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// The name of the property.
- ///
- /// The value of the property (possibly before type conversion).
- ///
- ///
- /// If the supplied is or
- /// contains only whitespace character(s).
- ///
- public PropertyValue(string name, object val)
- {
- AssertUtils.ArgumentHasText(name, "name");
-
- propertyName = name;
- propertyValue = val;
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- /// The name of the property.
- ///
- /// The value of the property (possibly before type conversion).
- ///
- /// Pre-parsed property name.
- ///
- /// If the supplied or
- /// is , or if the name contains only whitespace characters.
- ///
- public PropertyValue(string name, object val, IExpression expression)
- {
- AssertUtils.ArgumentHasText(name, "name");
-
- propertyName = name;
- propertyExpression = expression;
- propertyValue = val;
- }
-
- /// The name of the property.
- /// The name of the property.
- public string Name
- {
- get { return propertyName; }
- }
-
- ///
- /// Parsed property expression.
- ///
- public IExpression Expression
- {
- get
- {
- if (propertyExpression == null)
- {
- try
- {
- propertyExpression = ObjectWrapper.GetPropertyExpression(propertyName);
- }
- 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);
- }
- }
- return propertyExpression;
- }
- }
-
- ///
- /// Return the value of the property.
- ///
- ///
- ///
- /// Note that type conversion will not have occurred here.
- /// It is the responsibility of the
- /// implementation to
- /// perform type conversion.
- ///
+ /// Using an object here, rather than just storing all properties in a
+ /// map keyed by property name, allows for more flexibility, and the
+ /// ability to handle indexed properties in a special way if necessary.
+ ///
+ ///
+ /// Note that the value doesn't need to be the final required
+ /// : an
+ /// implementation must
+ /// handle any necessary conversion, as this object doesn't know anything
+ /// about the objects it will be applied to.
+ ///
+ ///
+ /// Rod Johnson
+ /// Mark Pollack (.NET)
+ [Serializable]
+ public class PropertyValue
+ {
+ private string propertyName;
+ private IExpression propertyExpression;
+ private object propertyValue;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// The name of the property.
+ ///
+ /// The value of the property (possibly before type conversion).
+ ///
+ ///
+ /// If the supplied is or
+ /// contains only whitespace character(s).
+ ///
+ public PropertyValue(string name, object val)
+ {
+ AssertUtils.ArgumentHasText(name, "name");
+
+ propertyName = name;
+ propertyValue = val;
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ /// The name of the property.
+ ///
+ /// The value of the property (possibly before type conversion).
+ ///
+ /// Pre-parsed property name.
+ ///
+ /// If the supplied or
+ /// is , or if the name contains only whitespace characters.
+ ///
+ public PropertyValue(string name, object val, IExpression expression)
+ {
+ AssertUtils.ArgumentHasText(name, "name");
+
+ propertyName = name;
+ propertyExpression = expression;
+ propertyValue = val;
+ }
+
+ /// The name of the property.
+ /// The name of the property.
+ public string Name
+ {
+ get { return propertyName; }
+ }
+
+ ///
+ /// Parsed property expression.
+ ///
+ public IExpression Expression
+ {
+ get
+ {
+ if (propertyExpression == null)
+ {
+ try
+ {
+ propertyExpression = ObjectWrapper.GetPropertyExpression(propertyName);
+ }
+ 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);
+ }
+ }
+ return propertyExpression;
+ }
+ }
+
+ ///
+ /// Return the value of the property.
+ ///
+ ///
+ ///
+ /// Note that type conversion will not have occurred here.
+ /// It is the responsibility of the
+ /// implementation to
+ /// perform type conversion.
+ ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- protected AbstractEventHandlerValue() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The object (possibly unresolved) that is exposing the event.
- ///
- ///
- /// The name of the method on the handler that is going to handle the event.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ protected AbstractEventHandlerValue() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The object (possibly unresolved) that is exposing the event.
+ ///
+ ///
+ /// The name of the method on the handler that is going to handle the event.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
- /// This is an class, and as such exposes no public constructors.
- ///
- ///
- protected AbstractWiringEventHandlerValue()
- {
- }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The object (possibly unresolved) that is exposing the event.
- ///
- ///
- /// The name of the method on the handler that is going to handle the event.
- ///
- ///
- ///
- /// This is an class, and as such exposes no public constructors.
- ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
+ ///
+ protected AbstractWiringEventHandlerValue()
+ {
+ }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The object (possibly unresolved) that is exposing the event.
+ ///
+ ///
+ /// The name of the method on the handler that is going to handle the event.
+ ///
+ ///
+ ///
+ /// This is an class, and as such exposes no public constructors.
+ ///
- /// This class merely marshals the matching of handler methods to the events exposed
- /// by an event source, and then delegates to a concrete
- /// implementation (such as
- /// or
- /// ) to do the heavy lifting of
- /// actually wiring a handler method to an event.
- ///
- ///
- /// Note : the order in which handler's are wired up to events is non-deterministic.
- ///
+ /// This class merely marshals the matching of handler methods to the events exposed
+ /// by an event source, and then delegates to a concrete
+ /// implementation (such as
+ /// or
+ /// ) to do the heavy lifting of
+ /// actually wiring a handler method to an event.
+ ///
+ ///
+ /// Note : the order in which handler's are wired up to events is non-deterministic.
+ ///
- /// Typically not used directly but via its subclasses such as
- /// .
- ///
- ///
- /// Usage: specify either the and
- /// or the
- /// and
- /// properties respectively, and
- /// (optionally) any arguments to the method. Then call the
- /// method to prepare the invoker.
- /// Once prepared, the invoker can be invoked any number of times.
- ///
- ///
- ///
- ///
- /// The following example uses the class to invoke the
- /// ToString() method on the Foo class using a mixture of both named and unnamed
- /// arguments.
- ///
- ///
- /// public class Foo
- /// {
- /// public string ToString(string name, int age, string address)
- /// {
- /// return string.Format("{0}, {1} years old, {2}", name, age, address);
- /// }
- ///
- /// public static void Main()
- /// {
- /// Foo foo = new Foo();
- /// MethodInvoker invoker = new MethodInvoker();
- /// invoker.Arguments = new object [] {"Kaneda", "18 Kaosu Gardens, Nakatani Drive, Okinanawa"};
- /// invoker.AddNamedArgument("age", 29);
- /// invoker.Prepare();
- /// // at this point, the arguments that will be passed to the method invocation
- /// // will have been resolved into the following ordered array : {"Kaneda", 29, "18 Kaosu Gardens, Nakatani Drive, Okinanawa"}
- /// string details = (string) invoker.Invoke();
- /// Console.WriteLine (details);
- /// // will print out 'Kaneda, 29 years old, 18 Kaosu Gardens, Nakatani Drive, Okinanawa'
- /// }
- /// }
- ///
- ///
- /// Colin Sampaleanu
- /// Juergen Hoeller
- /// Simon White (.NET)
- /// $Id: MethodInvoker.cs,v 1.7 2007/08/04 01:05:15 bbaia Exp $
- public class MethodInvoker
- {
- #region Fields
-
- ///
- /// The value returned from the invocation of a method that returns void.
- ///
- public static readonly Missing Void = Missing.Value;
-
- private Type _targetType;
- private object _targetObject;
- private string _targetMethod;
- private object[] _arguments;
- private IDictionary _namedArguments;
- private object[] _preparedArguments;
-
- ///
- /// The method that will be invoked.
- ///
- private MethodInfo _methodObject;
-
- ///
- /// The used to search for
- /// the method to be invoked.
- ///
- private const BindingFlags MethodSearchingFlags =
- BindingFlags.Instance |
- BindingFlags.Static |
- BindingFlags.Public |
- BindingFlags.NonPublic |
- BindingFlags.IgnoreCase;
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- ///
- /// Creates a new instance of the class.
- ///
- public MethodInvoker()
- {
- Arguments = new object[] {};
- NamedArguments = new Hashtable();
- PreparedArguments = new object[] {};
- }
-
- #endregion
-
- #region Properties
-
- ///
- /// The target on which to call the target method.
- ///
- ///
- ///
- /// Only necessary when the target method is ;
- /// else, a target object needs to be specified.
- ///
- ///
- public Type TargetType
- {
- get { return _targetType; }
- set { this._targetType = value; }
- }
-
- ///
- /// The target object on which to call the target method.
- ///
- ///
- ///
- /// Only necessary when the target method is not ;
- /// else, a target class is sufficient.
- ///
- ///
- public object TargetObject
- {
- get { return _targetObject; }
- set { this._targetObject = value; }
- }
-
- ///
- /// The name of the method to be invoked.
- ///
- ///
- ///
- /// Refers to either a method
- /// or a non- method, depending on
- /// whether or not a target object has been set.
- ///
- ///
- ///
- public string TargetMethod
- {
- get { return _targetMethod; }
- set { this._targetMethod = value; }
- }
-
- ///
- /// Arguments for the method invocation.
- ///
- ///
- ///
- /// Ordering is significant... the order of the arguments in this
- /// property must match the ordering of the various parameters on the target
- /// method. There does however exist a small possibility for confusion when
- /// the arguments in this property are supplied in addition to one or more named
- /// arguments. In this case, each named argument is slotted into the index position
- /// corresponding to the named argument... once once all named arguments have been
- /// resolved, the arguments in this property are slotted into any remaining (empty)
- /// slots in the method parameter list (see the example in the overview of the
- /// class if this is not clear).
- ///
- ///
- /// If this property is not set, or the value passed to the setter invocation
- /// is or a zero-length array, a method with no (un-named) arguments is assumed.
- ///
- ///
- ///
- public object[] Arguments
- {
- get { return _arguments; }
- set
- {
- if (value != null)
- {
- this._arguments = value;
- }
- else
- {
- this._arguments = new object[] {};
- }
- }
- }
-
- ///
- /// The resolved arguments for the method invocation.
- ///
- ///
- ///
- /// This property is not set until the target method has been resolved via a call to the
- /// method). It is a combination of the
- /// named and plain vanilla arguments properties, and it is this object array that
- /// will actually be passed to the invocation of the target method.
- ///
- ///
- /// Setting the value of this property to results in basically clearing out any
- /// previously prepared arguments... another call to the
- /// method will then be required to prepare the arguments again (or the prepared arguments
- /// can be set explicitly if so desired).
- ///
- ///
- ///
- ///
- protected object[] PreparedArguments
- {
- get { return _preparedArguments; }
- set
- {
- if (value != null)
- {
- this._preparedArguments = value;
- }
- else
- {
- this._preparedArguments = new object[] {};
- }
- }
- }
-
- ///
- /// Named arguments for the method invocation.
- ///
- ///
- ///
- /// The keys of this dictionary are the () names of the
- /// method arguments, and the () values are the actual
- /// argument values themselves.
- ///
- ///
- /// If this property is not set, or the value passed to the setter invocation
- /// is a reference, a method with no named arguments is assumed.
- ///
- /// The method can be invoked any number of times afterwards.
- ///
- ///
- ///
- /// If all required properties are not set, or a matching argument could not be found
- /// for a named argument (typically down to a typo).
- ///
- ///
- /// If the specified method could not be found.
- ///
- public virtual void Prepare()
- {
- if (_targetMethod == null)
- {
- throw new ArgumentException("The 'TargetMethod' property is required.");
- }
- if (_targetType == null && _targetObject == null)
- {
- throw new ArgumentException("One of either the 'TargetType' or 'TargetObject' properties is required.");
- }
- _methodObject = FindTheMethodToInvoke();
- if (TargetObject == null && !_methodObject.IsStatic)
- {
- throw new ArgumentException(
- "The target method cannot be an instance method without a corresponding target instance on which to invoke it.");
- }
- PrepareArguments();
- }
-
- private void PrepareArguments()
- {
- _preparedArguments = new object[ArgumentCount];
- // ok, lets prepare any named arguments first...
- if (NamedArguments.Count > 0)
- {
- // lets slot in all of the named arguments first...
- ParameterInfo[] parameters = _methodObject.GetParameters();
- // lets figure out the index og each of the method parameters...
- IDictionary argumentNamesToIndexes = new Hashtable();
- for (int i = 0; i < parameters.Length; ++i)
- {
- ParameterInfo parameter = parameters[i];
- argumentNamesToIndexes[parameter.Name.ToLower(CultureInfo.InvariantCulture)] = i;
- }
- int THE_ARGUMENT_IS_PREPARED = -12;
- foreach (DictionaryEntry namedArgument in NamedArguments)
- {
- string argumentName = ((string) namedArgument.Key).ToLower(CultureInfo.InvariantCulture);
- object argumentValue = namedArgument.Value;
- if (!argumentNamesToIndexes.Contains(argumentName))
- {
- // whoa (Nelly); the named argument does not exist on the method...
- throw new ArgumentException(string.Format(
- CultureInfo.InvariantCulture,
- "The named argument '{0}' could not be found on the '{1}' method of class [{2}].",
- argumentName, _methodObject.Name, _methodObject.DeclaringType.FullName));
-
- }
- // look up the index of where in the prepared args array we're gonna stick the named argument value
- int namedArgumentsIndex = (int) argumentNamesToIndexes[argumentName];
- PreparedArguments[namedArgumentsIndex] = argumentValue;
- // we've prepped this index position, so mark it as so...
- argumentNamesToIndexes[argumentName] = THE_ARGUMENT_IS_PREPARED;
- }
- // and then fill in any remaining blanks with the plain vanilla arguments...
- int plainVanillaIndex = 0;
- int[] sortedIndexes = (int[]) new ArrayList(argumentNamesToIndexes.Values).ToArray(typeof (int));
- Array.Sort(sortedIndexes);
- foreach (int argumentIndex in sortedIndexes)
- {
- // have we previously prepped a named argument at this index position?
- if (argumentIndex == THE_ARGUMENT_IS_PREPARED)
- {
- continue;
- }
- // lets stick a plain vanilla argument in at this index position (in the order that they have been supplied)...
- PreparedArguments[argumentIndex] = Arguments[plainVanillaIndex++];
- }
- }
- else
- {
- PreparedArguments = Arguments;
- }
- }
-
- ///
- /// Searches for and returns the method that is to be invoked.
- ///
- ///
- /// The return value of this method call will subsequently be returned from the
- /// .
- ///
- /// The method that is to be invoked.
- ///
- /// If no method could be found.
- ///
- ///
- /// If more than one method was found.
- ///
- protected virtual MethodInfo FindTheMethodToInvoke()
- {
- MethodInfo theMethod = null;
- Type targetType = (TargetObject != null) ? TargetObject.GetType() : TargetType;
-#if NET_2_0
- GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod);
-#endif
- // if we don't have any named arguments, we can try to get the exact method first...
- if (NamedArguments.Count == 0)
- {
- ComposedCriteria searchCriteria = new ComposedCriteria();
-#if NET_2_0
- searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
- searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
- searchCriteria.Add(new MethodGenericArgumentsCountCriteria(
- genericInfo.GetGenericArguments().Length));
-#else
- searchCriteria.Add(new MethodNameMatchCriteria(TargetMethod));
- searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
-#endif
- searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetTypes(Arguments)));
-
- MemberInfo[] matchingMethods = targetType.FindMembers(
- MemberTypes.Method,
- MethodSearchingFlags,
- new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- searchCriteria);
-
- if (matchingMethods != null && matchingMethods.Length == 1)
- {
- theMethod = matchingMethods[0] as MethodInfo;
- }
- }
- if (theMethod == null)
- {
- // search for a method with a matching signature...
- ComposedCriteria searchCriteria = new ComposedCriteria();
-#if NET_2_0
- searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
- searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
- searchCriteria.Add(new MethodGenericArgumentsCountCriteria(
- genericInfo.GetGenericArguments().Length));
-#else
- searchCriteria.Add(new MethodNameMatchCriteria(TargetMethod));
- searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
-#endif
- MemberInfo[] matchingMethods = targetType.FindMembers(
- MemberTypes.Method,
- MethodSearchingFlags,
- new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
- searchCriteria);
-
- if (matchingMethods == null
- || matchingMethods.Length == 0)
- {
- throw new MissingMethodException(targetType.Name, TargetMethod);
- }
- if (matchingMethods.Length > 1)
- {
- throw new ArgumentException(string.Format(
- CultureInfo.InvariantCulture,
- "Unable to determine which exact method to call; found '{0}' matches.",
- matchingMethods.Length));
- }
- theMethod = matchingMethods[0] as MethodInfo;
- }
-#if NET_2_0
- if (genericInfo.ContainsGenericArguments)
- {
- string[] unresolvedGenericArgs = genericInfo.GetGenericArguments();
- Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
- for (int j = 0; j < unresolvedGenericArgs.Length; j++)
- {
- genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
- }
- theMethod = theMethod.MakeGenericMethod(genericArgs);
- }
-#endif
- return theMethod;
- }
-
- ///
- /// Adds the named argument to this instances mapping of argument names to argument values.
- ///
- ///
- /// The name of an argument on the method that is to be invoked.
- ///
- ///
- /// The value of the named argument on the method that is to be invoked.
- ///
- public void AddNamedArgument(string argumentName, object argument)
- {
- if (NamedArguments.Contains(argumentName))
- {
- NamedArguments.Remove(argumentName);
- }
- NamedArguments.Add(argumentName, argument);
- }
-
- private int ArgumentCount
- {
- get { return Arguments.Length + NamedArguments.Count; }
- }
-
- ///
- /// Returns the prepared object that
- /// will be invoked.
- ///
- ///
- ///
- /// A possible use case is to determine the return of the method.
- ///
- ///
- ///
- /// The prepared object that
- /// will be invoked.
- ///
- public MethodInfo GetPreparedMethod()
- {
- return this._methodObject;
- }
-
- ///
- /// Invoke the specified method.
- ///
- ///
- ///
- /// The invoker needs to have been prepared beforehand (via a call to the
- /// method).
- ///
+ /// Typically not used directly but via its subclasses such as
+ /// .
+ ///
+ ///
+ /// Usage: specify either the and
+ /// or the
+ /// and
+ /// properties respectively, and
+ /// (optionally) any arguments to the method. Then call the
+ /// method to prepare the invoker.
+ /// Once prepared, the invoker can be invoked any number of times.
+ ///
+ ///
+ ///
+ ///
+ /// The following example uses the class to invoke the
+ /// ToString() method on the Foo class using a mixture of both named and unnamed
+ /// arguments.
+ ///
+ ///
+ /// public class Foo
+ /// {
+ /// public string ToString(string name, int age, string address)
+ /// {
+ /// return string.Format("{0}, {1} years old, {2}", name, age, address);
+ /// }
+ ///
+ /// public static void Main()
+ /// {
+ /// Foo foo = new Foo();
+ /// MethodInvoker invoker = new MethodInvoker();
+ /// invoker.Arguments = new object [] {"Kaneda", "18 Kaosu Gardens, Nakatani Drive, Okinanawa"};
+ /// invoker.AddNamedArgument("age", 29);
+ /// invoker.Prepare();
+ /// // at this point, the arguments that will be passed to the method invocation
+ /// // will have been resolved into the following ordered array : {"Kaneda", 29, "18 Kaosu Gardens, Nakatani Drive, Okinanawa"}
+ /// string details = (string) invoker.Invoke();
+ /// Console.WriteLine (details);
+ /// // will print out 'Kaneda, 29 years old, 18 Kaosu Gardens, Nakatani Drive, Okinanawa'
+ /// }
+ /// }
+ ///
+ ///
+ /// Colin Sampaleanu
+ /// Juergen Hoeller
+ /// Simon White (.NET)
+ public class MethodInvoker
+ {
+ #region Fields
+
+ ///
+ /// The value returned from the invocation of a method that returns void.
+ ///
+ public static readonly Missing Void = Missing.Value;
+
+ private Type _targetType;
+ private object _targetObject;
+ private string _targetMethod;
+ private object[] _arguments;
+ private IDictionary _namedArguments;
+ private object[] _preparedArguments;
+
+ ///
+ /// The method that will be invoked.
+ ///
+ private MethodInfo _methodObject;
+
+ ///
+ /// The used to search for
+ /// the method to be invoked.
+ ///
+ private const BindingFlags MethodSearchingFlags =
+ BindingFlags.Instance |
+ BindingFlags.Static |
+ BindingFlags.Public |
+ BindingFlags.NonPublic |
+ BindingFlags.IgnoreCase;
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public MethodInvoker()
+ {
+ Arguments = new object[] {};
+ NamedArguments = new Hashtable();
+ PreparedArguments = new object[] {};
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// The target on which to call the target method.
+ ///
+ ///
+ ///
+ /// Only necessary when the target method is ;
+ /// else, a target object needs to be specified.
+ ///
+ ///
+ public Type TargetType
+ {
+ get { return _targetType; }
+ set { this._targetType = value; }
+ }
+
+ ///
+ /// The target object on which to call the target method.
+ ///
+ ///
+ ///
+ /// Only necessary when the target method is not ;
+ /// else, a target class is sufficient.
+ ///
+ ///
+ public object TargetObject
+ {
+ get { return _targetObject; }
+ set { this._targetObject = value; }
+ }
+
+ ///
+ /// The name of the method to be invoked.
+ ///
+ ///
+ ///
+ /// Refers to either a method
+ /// or a non- method, depending on
+ /// whether or not a target object has been set.
+ ///
+ ///
+ ///
+ public string TargetMethod
+ {
+ get { return _targetMethod; }
+ set { this._targetMethod = value; }
+ }
+
+ ///
+ /// Arguments for the method invocation.
+ ///
+ ///
+ ///
+ /// Ordering is significant... the order of the arguments in this
+ /// property must match the ordering of the various parameters on the target
+ /// method. There does however exist a small possibility for confusion when
+ /// the arguments in this property are supplied in addition to one or more named
+ /// arguments. In this case, each named argument is slotted into the index position
+ /// corresponding to the named argument... once once all named arguments have been
+ /// resolved, the arguments in this property are slotted into any remaining (empty)
+ /// slots in the method parameter list (see the example in the overview of the
+ /// class if this is not clear).
+ ///
+ ///
+ /// If this property is not set, or the value passed to the setter invocation
+ /// is or a zero-length array, a method with no (un-named) arguments is assumed.
+ ///
+ ///
+ ///
+ public object[] Arguments
+ {
+ get { return _arguments; }
+ set
+ {
+ if (value != null)
+ {
+ this._arguments = value;
+ }
+ else
+ {
+ this._arguments = new object[] {};
+ }
+ }
+ }
+
+ ///
+ /// The resolved arguments for the method invocation.
+ ///
+ ///
+ ///
+ /// This property is not set until the target method has been resolved via a call to the
+ /// method). It is a combination of the
+ /// named and plain vanilla arguments properties, and it is this object array that
+ /// will actually be passed to the invocation of the target method.
+ ///
+ ///
+ /// Setting the value of this property to results in basically clearing out any
+ /// previously prepared arguments... another call to the
+ /// method will then be required to prepare the arguments again (or the prepared arguments
+ /// can be set explicitly if so desired).
+ ///
+ ///
+ ///
+ ///
+ protected object[] PreparedArguments
+ {
+ get { return _preparedArguments; }
+ set
+ {
+ if (value != null)
+ {
+ this._preparedArguments = value;
+ }
+ else
+ {
+ this._preparedArguments = new object[] {};
+ }
+ }
+ }
+
+ ///
+ /// Named arguments for the method invocation.
+ ///
+ ///
+ ///
+ /// The keys of this dictionary are the () names of the
+ /// method arguments, and the () values are the actual
+ /// argument values themselves.
+ ///
+ ///
+ /// If this property is not set, or the value passed to the setter invocation
+ /// is a reference, a method with no named arguments is assumed.
+ ///
+ /// The method can be invoked any number of times afterwards.
+ ///
+ ///
+ ///
+ /// If all required properties are not set, or a matching argument could not be found
+ /// for a named argument (typically down to a typo).
+ ///
+ ///
+ /// If the specified method could not be found.
+ ///
+ public virtual void Prepare()
+ {
+ if (_targetMethod == null)
+ {
+ throw new ArgumentException("The 'TargetMethod' property is required.");
+ }
+ if (_targetType == null && _targetObject == null)
+ {
+ throw new ArgumentException("One of either the 'TargetType' or 'TargetObject' properties is required.");
+ }
+ _methodObject = FindTheMethodToInvoke();
+ if (TargetObject == null && !_methodObject.IsStatic)
+ {
+ throw new ArgumentException(
+ "The target method cannot be an instance method without a corresponding target instance on which to invoke it.");
+ }
+ PrepareArguments();
+ }
+
+ private void PrepareArguments()
+ {
+ _preparedArguments = new object[ArgumentCount];
+ // ok, lets prepare any named arguments first...
+ if (NamedArguments.Count > 0)
+ {
+ // lets slot in all of the named arguments first...
+ ParameterInfo[] parameters = _methodObject.GetParameters();
+ // lets figure out the index og each of the method parameters...
+ IDictionary argumentNamesToIndexes = new Hashtable();
+ for (int i = 0; i < parameters.Length; ++i)
+ {
+ ParameterInfo parameter = parameters[i];
+ argumentNamesToIndexes[parameter.Name.ToLower(CultureInfo.InvariantCulture)] = i;
+ }
+ int THE_ARGUMENT_IS_PREPARED = -12;
+ foreach (DictionaryEntry namedArgument in NamedArguments)
+ {
+ string argumentName = ((string) namedArgument.Key).ToLower(CultureInfo.InvariantCulture);
+ object argumentValue = namedArgument.Value;
+ if (!argumentNamesToIndexes.Contains(argumentName))
+ {
+ // whoa (Nelly); the named argument does not exist on the method...
+ throw new ArgumentException(string.Format(
+ CultureInfo.InvariantCulture,
+ "The named argument '{0}' could not be found on the '{1}' method of class [{2}].",
+ argumentName, _methodObject.Name, _methodObject.DeclaringType.FullName));
+
+ }
+ // look up the index of where in the prepared args array we're gonna stick the named argument value
+ int namedArgumentsIndex = (int) argumentNamesToIndexes[argumentName];
+ PreparedArguments[namedArgumentsIndex] = argumentValue;
+ // we've prepped this index position, so mark it as so...
+ argumentNamesToIndexes[argumentName] = THE_ARGUMENT_IS_PREPARED;
+ }
+ // and then fill in any remaining blanks with the plain vanilla arguments...
+ int plainVanillaIndex = 0;
+ int[] sortedIndexes = (int[]) new ArrayList(argumentNamesToIndexes.Values).ToArray(typeof (int));
+ Array.Sort(sortedIndexes);
+ foreach (int argumentIndex in sortedIndexes)
+ {
+ // have we previously prepped a named argument at this index position?
+ if (argumentIndex == THE_ARGUMENT_IS_PREPARED)
+ {
+ continue;
+ }
+ // lets stick a plain vanilla argument in at this index position (in the order that they have been supplied)...
+ PreparedArguments[argumentIndex] = Arguments[plainVanillaIndex++];
+ }
+ }
+ else
+ {
+ PreparedArguments = Arguments;
+ }
+ }
+
+ ///
+ /// Searches for and returns the method that is to be invoked.
+ ///
+ ///
+ /// The return value of this method call will subsequently be returned from the
+ /// .
+ ///
+ /// The method that is to be invoked.
+ ///
+ /// If no method could be found.
+ ///
+ ///
+ /// If more than one method was found.
+ ///
+ protected virtual MethodInfo FindTheMethodToInvoke()
+ {
+ MethodInfo theMethod = null;
+ Type targetType = (TargetObject != null) ? TargetObject.GetType() : TargetType;
+#if NET_2_0
+ GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod);
+#endif
+ // if we don't have any named arguments, we can try to get the exact method first...
+ if (NamedArguments.Count == 0)
+ {
+ ComposedCriteria searchCriteria = new ComposedCriteria();
+#if NET_2_0
+ searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
+ searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
+ searchCriteria.Add(new MethodGenericArgumentsCountCriteria(
+ genericInfo.GetGenericArguments().Length));
+#else
+ searchCriteria.Add(new MethodNameMatchCriteria(TargetMethod));
+ searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
+#endif
+ searchCriteria.Add(new MethodParametersCriteria(ReflectionUtils.GetTypes(Arguments)));
+
+ MemberInfo[] matchingMethods = targetType.FindMembers(
+ MemberTypes.Method,
+ MethodSearchingFlags,
+ new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ searchCriteria);
+
+ if (matchingMethods != null && matchingMethods.Length == 1)
+ {
+ theMethod = matchingMethods[0] as MethodInfo;
+ }
+ }
+ if (theMethod == null)
+ {
+ // search for a method with a matching signature...
+ ComposedCriteria searchCriteria = new ComposedCriteria();
+#if NET_2_0
+ searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
+ searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
+ searchCriteria.Add(new MethodGenericArgumentsCountCriteria(
+ genericInfo.GetGenericArguments().Length));
+#else
+ searchCriteria.Add(new MethodNameMatchCriteria(TargetMethod));
+ searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
+#endif
+ MemberInfo[] matchingMethods = targetType.FindMembers(
+ MemberTypes.Method,
+ MethodSearchingFlags,
+ new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
+ searchCriteria);
+
+ if (matchingMethods == null
+ || matchingMethods.Length == 0)
+ {
+ throw new MissingMethodException(targetType.Name, TargetMethod);
+ }
+ if (matchingMethods.Length > 1)
+ {
+ throw new ArgumentException(string.Format(
+ CultureInfo.InvariantCulture,
+ "Unable to determine which exact method to call; found '{0}' matches.",
+ matchingMethods.Length));
+ }
+ theMethod = matchingMethods[0] as MethodInfo;
+ }
+#if NET_2_0
+ if (genericInfo.ContainsGenericArguments)
+ {
+ string[] unresolvedGenericArgs = genericInfo.GetGenericArguments();
+ Type[] genericArgs = new Type[unresolvedGenericArgs.Length];
+ for (int j = 0; j < unresolvedGenericArgs.Length; j++)
+ {
+ genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
+ }
+ theMethod = theMethod.MakeGenericMethod(genericArgs);
+ }
+#endif
+ return theMethod;
+ }
+
+ ///
+ /// Adds the named argument to this instances mapping of argument names to argument values.
+ ///
+ ///
+ /// The name of an argument on the method that is to be invoked.
+ ///
+ ///
+ /// The value of the named argument on the method that is to be invoked.
+ ///
+ public void AddNamedArgument(string argumentName, object argument)
+ {
+ if (NamedArguments.Contains(argumentName))
+ {
+ NamedArguments.Remove(argumentName);
+ }
+ NamedArguments.Add(argumentName, argument);
+ }
+
+ private int ArgumentCount
+ {
+ get { return Arguments.Length + NamedArguments.Count; }
+ }
+
+ ///
+ /// Returns the prepared object that
+ /// will be invoked.
+ ///
+ ///
+ ///
+ /// A possible use case is to determine the return of the method.
+ ///
+ ///
+ ///
+ /// The prepared object that
+ /// will be invoked.
+ ///
+ public MethodInfo GetPreparedMethod()
+ {
+ return this._methodObject;
+ }
+
+ ///
+ /// Invoke the specified method.
+ ///
+ ///
+ ///
+ /// The invoker needs to have been prepared beforehand (via a call to the
+ /// method).
+ ///
- /// Based on the Jakarta Commons Pool API.
- ///
- ///
- /// Federico Spinazzi
- /// $Id: IObjectPool.cs,v 1.5 2005/08/13 18:04:54 springboy Exp $
- ///
- public interface IObjectPool
- {
- ///
- /// Obtain an instance from the pool.
- ///
- ///
- ///
- /// By contract, clients must return the borrowed
- /// instance using
- /// or a related method as defined in an implementation or
- /// sub-interface.
- ///
- ///
- /// An instance from the pool.
- ///
- /// In case the pool is unusable.
- ///
- ///
- object BorrowObject();
-
- ///
- /// Return an instance to the pool.
- ///
- ///
- ///
- /// By contract, the object must have been obtained using
- ///
- /// or a related method as defined in an implementation or sub-interface.
- ///
- ///
- /// The instance to be returned to the pool.
- ///
- void ReturnObject(object target);
-
- ///
- /// Create an object using the factory set by
- /// the property
- /// or other implementation dependent mechanism
- /// and place it into the pool.
- ///
- ///
- ///
- /// This is an optional operation. AddObject is useful for "pre-loading" a
- /// pool with idle objects.
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- void AddObject();
-
- ///
- /// Close the pool and free any resources associated with it.
- ///
- void Close();
-
- ///
- /// Clear objects sitting idle in the pool, releasing any
- /// associated resources.
- ///
- ///
- ///
- /// This is an optional operation.
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- void Clear();
-
- ///
- /// Gets the number of instances currently borrowed from the pool.
- ///
- ///
- ///
- /// This is an optional operation.
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- int NumActive { get; }
-
- ///
- /// Gets the number of instances currently idle in the pool.
- ///
- ///
- ///
- /// This is an optional operation.
- ///
- ///
- /// This may be considered an approximation of the number of objects
- /// that can be borrowed without creating any new instances.
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- int NumIdle { get; }
-
- ///
- /// Set the factory used to create new instances.
- ///
- ///
- ///
+ /// Based on the Jakarta Commons Pool API.
+ ///
+ ///
+ /// Federico Spinazzi
+ ///
+ public interface IObjectPool
+ {
+ ///
+ /// Obtain an instance from the pool.
+ ///
+ ///
+ ///
+ /// By contract, clients must return the borrowed
+ /// instance using
+ /// or a related method as defined in an implementation or
+ /// sub-interface.
+ ///
+ ///
+ /// An instance from the pool.
+ ///
+ /// In case the pool is unusable.
+ ///
+ ///
+ object BorrowObject();
+
+ ///
+ /// Return an instance to the pool.
+ ///
+ ///
+ ///
+ /// By contract, the object must have been obtained using
+ ///
+ /// or a related method as defined in an implementation or sub-interface.
+ ///
+ ///
+ /// The instance to be returned to the pool.
+ ///
+ void ReturnObject(object target);
+
+ ///
+ /// Create an object using the factory set by
+ /// the property
+ /// or other implementation dependent mechanism
+ /// and place it into the pool.
+ ///
+ ///
+ ///
+ /// This is an optional operation. AddObject is useful for "pre-loading" a
+ /// pool with idle objects.
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ void AddObject();
+
+ ///
+ /// Close the pool and free any resources associated with it.
+ ///
+ void Close();
+
+ ///
+ /// Clear objects sitting idle in the pool, releasing any
+ /// associated resources.
+ ///
+ ///
+ ///
+ /// This is an optional operation.
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ void Clear();
+
+ ///
+ /// Gets the number of instances currently borrowed from the pool.
+ ///
+ ///
+ ///
+ /// This is an optional operation.
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ int NumActive { get; }
+
+ ///
+ /// Gets the number of instances currently idle in the pool.
+ ///
+ ///
+ ///
+ /// This is an optional operation.
+ ///
+ ///
+ /// This may be considered an approximation of the number of objects
+ /// that can be borrowed without creating any new instances.
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ int NumIdle { get; }
+
+ ///
+ /// Set the factory used to create new instances.
+ ///
+ ///
+ ///
- /// The following methods summarize the contract between an
- /// and an
- /// an .
- ///
- ///
- ///
- ///
- /// is called whenever a new instance is needed.
- ///
- ///
- ///
- /// is invoked on every instance before it is returned from
- /// the pool.
- ///
- ///
- ///
- /// is invoked on every instance when it is returned to the pool.
- ///
- ///
- ///
- /// is invoked on every instance when it is being dropped from the
- /// pool (see
- ///
- ///
- ///
- ///
- /// Based on the Jakarta Commons Pool API.
- ///
- ///
- /// Federico Spinazzi
- /// $Id: IPoolableObjectFactory.cs,v 1.5 2005/11/18 17:29:32 gcaprio Exp $
- ///
- public interface IPoolableObjectFactory
- {
- ///
- /// Creates an instance that can be returned by the pool.
- ///
- ///
- /// An instance that can be returned by the pool.
- ///
- object MakeObject();
-
- ///
- /// Destroys an instance no longer needed by the pool.
- ///
- ///
- ///
- /// Invoked on every instance when it is being "dropped"
- /// from the pool (whether due to the return value from a call to the
- ///
- /// method, or for reasons specific to the pool implementation.)
- ///
- ///
- /// The instance to be destroyed.
- void DestroyObject(object obj);
-
- ///
- /// Ensures that the instance is safe to be returned by the pool.
- /// Returns false if this object should be destroyed.
- ///
- ///
- ///
- /// Invoked in an implementation-specific fashion to determine if an
- /// instance is still valid to be returned by the pool.
- /// It will only be invoked on an "activated" instance.
- ///
- ///
- /// The instance to validate.
- ///
- /// if this object is not valid and
- /// should be dropped from the pool, otherwise .
- ///
- bool ValidateObject(object obj);
-
- ///
- /// Reinitialize an instance to be returned by the pool.
- ///
- ///
- ///
- /// Invoked on every instance before it is returned from the pool.
- ///
- ///
- /// The instance to be activated.
- void ActivateObject(object obj);
-
- ///
- /// Uninitialize an instance to be returned to the pool.
- ///
- ///
- ///
- /// Invoked on every instance when it is returned to the pool.
- ///
+ /// The following methods summarize the contract between an
+ /// and an
+ /// an .
+ ///
+ ///
+ ///
+ ///
+ /// is called whenever a new instance is needed.
+ ///
+ ///
+ ///
+ /// is invoked on every instance before it is returned from
+ /// the pool.
+ ///
+ ///
+ ///
+ /// is invoked on every instance when it is returned to the pool.
+ ///
+ ///
+ ///
+ /// is invoked on every instance when it is being dropped from the
+ /// pool (see
+ ///
+ ///
+ ///
+ ///
+ /// Based on the Jakarta Commons Pool API.
+ ///
+ ///
+ /// Federico Spinazzi
+ ///
+ public interface IPoolableObjectFactory
+ {
+ ///
+ /// Creates an instance that can be returned by the pool.
+ ///
+ ///
+ /// An instance that can be returned by the pool.
+ ///
+ object MakeObject();
+
+ ///
+ /// Destroys an instance no longer needed by the pool.
+ ///
+ ///
+ ///
+ /// Invoked on every instance when it is being "dropped"
+ /// from the pool (whether due to the return value from a call to the
+ ///
+ /// method, or for reasons specific to the pool implementation.)
+ ///
+ ///
+ /// The instance to be destroyed.
+ void DestroyObject(object obj);
+
+ ///
+ /// Ensures that the instance is safe to be returned by the pool.
+ /// Returns false if this object should be destroyed.
+ ///
+ ///
+ ///
+ /// Invoked in an implementation-specific fashion to determine if an
+ /// instance is still valid to be returned by the pool.
+ /// It will only be invoked on an "activated" instance.
+ ///
+ ///
+ /// The instance to validate.
+ ///
+ /// if this object is not valid and
+ /// should be dropped from the pool, otherwise .
+ ///
+ bool ValidateObject(object obj);
+
+ ///
+ /// Reinitialize an instance to be returned by the pool.
+ ///
+ ///
+ ///
+ /// Invoked on every instance before it is returned from the pool.
+ ///
+ ///
+ /// The instance to be activated.
+ void ActivateObject(object obj);
+
+ ///
+ /// Uninitialize an instance to be returned to the pool.
+ ///
+ ///
+ ///
+ /// Invoked on every instance when it is returned to the pool.
+ ///
- /// Based on the implementation found in Concurrent Programming in Java,
- /// 2nd ed., by Doug Lea.
- ///
- ///
- /// Doug Lea
- /// Federico Spinazzi
- /// Mark Pollack
- /// $Id: SimplePool.cs,v 1.4 2006/09/15 19:06:07 markpollack Exp $
- public class SimplePool : IObjectPool
- {
- private readonly IPoolableObjectFactory factory;
- private bool closed;
- private IList free = new ArrayList();
- private IList busy = new ArrayList(); // linear search !!
-
- ///
- /// Set of permits
- ///
- internal readonly Semaphore available;
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The factory used to instantiate and manage the lifecycle of pooled objects.
- ///
- /// The initial size of the pool.
- ///
- /// If the supplied is .
- ///
- ///
- /// If the supplied is less than or equal to zero.
- ///
- public SimplePool(IPoolableObjectFactory factory, int size)
- {
- AssertUtils.ArgumentNotNull(factory, "factory");
- this.available = new Semaphore(size);
- this.factory = factory;
- InitItems(size);
- }
-
- ///
- /// Obtain an instance from the pool.
- ///
- ///
- /// In case the pool is unusable.
- ///
- ///
- ///
- public object BorrowObject()
- {
- available.Acquire();
- return DoBorrow();
- }
-
- ///
- /// Return an instance to the pool.
- ///
- /// The instance to be returned to the pool.
- ///
- ///
- public void ReturnObject(object target)
- {
- if (DoReturn(target))
- {
- available.Release();
- }
- }
-
- ///
- /// Create an object using the factory set by
- /// the property
- /// or other implementation dependent mechanism
- /// and place it into the pool.
- ///
- ///
- ///
- /// This implementation always throws a
- /// .
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- public void AddObject()
- {
- throw new NotSupportedException();
- }
-
- ///
- /// Synchronized borrow logic.
- ///
- ///
- protected object DoBorrow()
- {
- lock (this)
- {
- while (free.Count > 0)
- {
- int i = free.Count - 1;
- object o = free[i];
- free.RemoveAt(i);
- factory.ActivateObject(o);
- if (factory.ValidateObject(o))
- {
- busy.Add(o);
- return o;
- }
- }
- if (!closed)
- {
- throw new PoolException("No more valid objects in pool.");
- }
- else
- {
- throw new PoolException("Pool was closed and is unusable.");
- }
- }
- }
-
- ///
- /// Synchronized release logic.
- ///
- ///
- /// The object to release to the pool.
- ///
- ///
- /// if the object was not a busy one.
- ///
- protected bool DoReturn(object target)
- {
- lock (this)
- {
- if (busy.Contains(target))
- {
- busy.Remove(target);
- factory.PassivateObject(target);
- free.Add(target);
- return true;
- }
- return false;
- }
- }
-
- ///
- /// Instantiates the supplied number of instances and adds
- /// them to the pool.
- ///
- ///
- /// The initial number of objects to build.
- ///
- ///
- /// If the supplied number of is
- /// less than or equal to zero.
- ///
- protected void InitItems(int initialInstances)
- {
- if(initialInstances <= 0)
- {
- throw new ArgumentException("Cannot pool a negative number of instances.", "initialInstances");
- }
- for (int i = 0; i < initialInstances; ++i)
- {
- free.Add(factory.MakeObject());
- }
- }
-
- ///
- /// Close the pool and free any resources associated with it.
- ///
- public void Close()
- {
- lock (this)
- {
- for (IEnumerator e = busy.GetEnumerator();
- e.MoveNext();
- e = busy.GetEnumerator())
- {
- ReturnObject(e.Current);
- }
- foreach (object o in free)
- {
- factory.DestroyObject(o);
- }
- MakeNotUsable();
- }
- }
-
- ///
- /// Clear objects sitting idle in the pool, releasing any
- /// associated resources.
- ///
- ///
- ///
- /// This implementation always throws a
- /// .
- ///
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- public void Clear()
- {
- throw new NotSupportedException();
- }
-
- ///
- /// Change the state of the pool to unusable.
- ///
- private void MakeNotUsable()
- {
- free = busy = new ArrayList();
- closed = true;
- }
-
- ///
- /// Gets the number of instances currently borrowed from the pool.
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- ///
- public int NumActive
- {
- get { return this.busy.Count; }
- }
-
- ///
- /// Gets the number of instances currently idle in the pool.
- ///
- ///
- /// If the implementation does not support the operation.
- ///
- ///
- public int NumIdle
- {
- get { return this.free.Count; }
- }
-
- ///
- /// Set the factory used to create new instances.
- ///
- ///
- ///
- /// This implementation always throws a
- /// .
- ///
+ /// Based on the implementation found in Concurrent Programming in Java,
+ /// 2nd ed., by Doug Lea.
+ ///
+ ///
+ /// Doug Lea
+ /// Federico Spinazzi
+ /// Mark Pollack
+ public class SimplePool : IObjectPool
+ {
+ private readonly IPoolableObjectFactory factory;
+ private bool closed;
+ private IList free = new ArrayList();
+ private IList busy = new ArrayList(); // linear search !!
+
+ ///
+ /// Set of permits
+ ///
+ internal readonly Semaphore available;
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The factory used to instantiate and manage the lifecycle of pooled objects.
+ ///
+ /// The initial size of the pool.
+ ///
+ /// If the supplied is .
+ ///
+ ///
+ /// If the supplied is less than or equal to zero.
+ ///
+ public SimplePool(IPoolableObjectFactory factory, int size)
+ {
+ AssertUtils.ArgumentNotNull(factory, "factory");
+ this.available = new Semaphore(size);
+ this.factory = factory;
+ InitItems(size);
+ }
+
+ ///
+ /// Obtain an instance from the pool.
+ ///
+ ///
+ /// In case the pool is unusable.
+ ///
+ ///
+ ///
+ public object BorrowObject()
+ {
+ available.Acquire();
+ return DoBorrow();
+ }
+
+ ///
+ /// Return an instance to the pool.
+ ///
+ /// The instance to be returned to the pool.
+ ///
+ ///
+ public void ReturnObject(object target)
+ {
+ if (DoReturn(target))
+ {
+ available.Release();
+ }
+ }
+
+ ///
+ /// Create an object using the factory set by
+ /// the property
+ /// or other implementation dependent mechanism
+ /// and place it into the pool.
+ ///
+ ///
+ ///
+ /// This implementation always throws a
+ /// .
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ public void AddObject()
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Synchronized borrow logic.
+ ///
+ ///
+ protected object DoBorrow()
+ {
+ lock (this)
+ {
+ while (free.Count > 0)
+ {
+ int i = free.Count - 1;
+ object o = free[i];
+ free.RemoveAt(i);
+ factory.ActivateObject(o);
+ if (factory.ValidateObject(o))
+ {
+ busy.Add(o);
+ return o;
+ }
+ }
+ if (!closed)
+ {
+ throw new PoolException("No more valid objects in pool.");
+ }
+ else
+ {
+ throw new PoolException("Pool was closed and is unusable.");
+ }
+ }
+ }
+
+ ///
+ /// Synchronized release logic.
+ ///
+ ///
+ /// The object to release to the pool.
+ ///
+ ///
+ /// if the object was not a busy one.
+ ///
+ protected bool DoReturn(object target)
+ {
+ lock (this)
+ {
+ if (busy.Contains(target))
+ {
+ busy.Remove(target);
+ factory.PassivateObject(target);
+ free.Add(target);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ ///
+ /// Instantiates the supplied number of instances and adds
+ /// them to the pool.
+ ///
+ ///
+ /// The initial number of objects to build.
+ ///
+ ///
+ /// If the supplied number of is
+ /// less than or equal to zero.
+ ///
+ protected void InitItems(int initialInstances)
+ {
+ if(initialInstances <= 0)
+ {
+ throw new ArgumentException("Cannot pool a negative number of instances.", "initialInstances");
+ }
+ for (int i = 0; i < initialInstances; ++i)
+ {
+ free.Add(factory.MakeObject());
+ }
+ }
+
+ ///
+ /// Close the pool and free any resources associated with it.
+ ///
+ public void Close()
+ {
+ lock (this)
+ {
+ for (IEnumerator e = busy.GetEnumerator();
+ e.MoveNext();
+ e = busy.GetEnumerator())
+ {
+ ReturnObject(e.Current);
+ }
+ foreach (object o in free)
+ {
+ factory.DestroyObject(o);
+ }
+ MakeNotUsable();
+ }
+ }
+
+ ///
+ /// Clear objects sitting idle in the pool, releasing any
+ /// associated resources.
+ ///
+ ///
+ ///
+ /// This implementation always throws a
+ /// .
+ ///
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ public void Clear()
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Change the state of the pool to unusable.
+ ///
+ private void MakeNotUsable()
+ {
+ free = busy = new ArrayList();
+ closed = true;
+ }
+
+ ///
+ /// Gets the number of instances currently borrowed from the pool.
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ ///
+ public int NumActive
+ {
+ get { return this.busy.Count; }
+ }
+
+ ///
+ /// Gets the number of instances currently idle in the pool.
+ ///
+ ///
+ /// If the implementation does not support the operation.
+ ///
+ ///
+ public int NumIdle
+ {
+ get { return this.free.Count; }
+ }
+
+ ///
+ /// Set the factory used to create new instances.
+ ///
+ ///
+ ///
+ /// This implementation always throws a
+ /// .
+ ///
objects isolate waiting and notification for particular logical
- /// states, resource availability, events, and the like that are shared
- /// across multiple threads.
- ///
- ///
Use of s sometimes (but by no means always) adds
- /// flexibility and efficiency compared to the use of plain
- /// .Net monitor methods and locking, and are sometimes (but by no means
- /// always) simpler to program with.
- ///
- ///
Used for implementation of a
- ///
- ///
- /// Doug Lea
- /// Federico Spinazzi (.Net)
- /// $Id: ISync.cs,v 1.6 2006/09/15 19:06:08 markpollack Exp $
- public interface ISync
- {
- /// Wait (possibly forever) until successful passage.
- /// Fail only upon interuption. Interruptions always result in
- /// `clean' failures. On failure, you can be sure that it has not
- /// been acquired, and that no
- /// corresponding release should be performed. Conversely,
- /// a normal return guarantees that the acquire was successful.
- ///
- ///
- void Acquire();
-
- /// Potentially enable others to pass.
- ///
- /// Because release does not raise exceptions,
- /// it can be used in `finally' clauses without requiring extra
- /// embedded try/catch blocks. But keep in mind that
- /// as with any java method, implementations may
- /// still throw unchecked exceptions such as Error or NullPointerException
- /// when faced with uncontinuable errors. However, these should normally
- /// only be caught by higher-level error handlers.
- ///
- ///
- void Release ();
-
- ///
- /// Wait at most msecs to pass; report whether passed.
- ///
- /// The method has best-effort semantics:
- /// The msecs bound cannot
- /// be guaranteed to be a precise upper bound on wait time in Java.
- /// Implementations generally can only attempt to return as soon as possible
- /// after the specified bound. Also, timers in Java do not stop during garbage
- /// collection, so timeouts can occur just because a GC intervened.
- /// So, msecs arguments should be used in
- /// a coarse-grained manner. Further,
- /// implementations cannot always guarantee that this method
- /// will return at all without blocking indefinitely when used in
- /// unintended ways. For example, deadlocks may be encountered
- /// when called in an unintended context.
- ///
objects isolate waiting and notification for particular logical
+ /// states, resource availability, events, and the like that are shared
+ /// across multiple threads.
+ ///
+ ///
Use of s sometimes (but by no means always) adds
+ /// flexibility and efficiency compared to the use of plain
+ /// .Net monitor methods and locking, and are sometimes (but by no means
+ /// always) simpler to program with.
+ ///
+ ///
Used for implementation of a
+ ///
+ ///
+ /// Doug Lea
+ /// Federico Spinazzi (.Net)
+ public interface ISync
+ {
+ /// Wait (possibly forever) until successful passage.
+ /// Fail only upon interuption. Interruptions always result in
+ /// `clean' failures. On failure, you can be sure that it has not
+ /// been acquired, and that no
+ /// corresponding release should be performed. Conversely,
+ /// a normal return guarantees that the acquire was successful.
+ ///
+ ///
+ void Acquire();
+
+ /// Potentially enable others to pass.
+ ///
+ /// Because release does not raise exceptions,
+ /// it can be used in `finally' clauses without requiring extra
+ /// embedded try/catch blocks. But keep in mind that
+ /// as with any java method, implementations may
+ /// still throw unchecked exceptions such as Error or NullPointerException
+ /// when faced with uncontinuable errors. However, these should normally
+ /// only be caught by higher-level error handlers.
+ ///
+ ///
+ void Release ();
+
+ ///
+ /// Wait at most msecs to pass; report whether passed.
+ ///
+ /// The method has best-effort semantics:
+ /// The msecs bound cannot
+ /// be guaranteed to be a precise upper bound on wait time in Java.
+ /// Implementations generally can only attempt to return as soon as possible
+ /// after the specified bound. Also, timers in Java do not stop during garbage
+ /// collection, so timeouts can occur just because a GC intervened.
+ /// So, msecs arguments should be used in
+ /// a coarse-grained manner. Further,
+ /// implementations cannot always guarantee that this method
+ /// will return at all without blocking indefinitely when used in
+ /// unintended ways. For example, deadlocks may be encountered
+ /// when called in an unintended context.
+ ///
- /// Sample usage. Here are a set of classes that use
- /// a latch as a start signal for a group of worker threads that
- /// are created and started beforehand, and then later enabled.
- ///
+ /// Sample usage. Here are a set of classes that use
+ /// a latch as a start signal for a group of worker threads that
+ /// are created and started beforehand, and then later enabled.
+ ///
Base class for counting semaphores based on Semaphore implementation
- /// from Doug Lea.
- ///
- ///
- ///
- ///
Conceptually, a semaphore
- /// maintains a set of permits. Each acquire() blocks if
- /// necessary until a permit is available, and then takes it.
- ///
- ///
Each release adds a permit. However, no actual permit objects are used;
- /// the Semaphore just keeps a count of the number available
- /// and acts accordingly.
- ///
- ///
A semaphore initialized to 1 can serve as a mutual exclusion lock.
- ///
- /// Used for implementation of a
- ///
- /// Doug Lea
- /// Federico Spinazzi (.Net)
- /// $Id: Semaphore.cs,v 1.10 2006/09/15 21:30:09 markpollack Exp $
- public class Semaphore : ISync
- {
- ///
- /// current number of available permits
- ///
- protected long nPermits;
-
- ///
- ///
Create a Semaphore with the given initial number of permits.
- ///
Using a seed of 1 makes the semaphore act as a mutual
- /// exclusion lock.
- ///
- ///
Negative seeds are also allowed,
- /// in which case no acquires will proceed until the number of
- /// releases has pushed the number of permits past 0.
Base class for counting semaphores based on Semaphore implementation
+ /// from Doug Lea.
+ ///
+ ///
+ ///
+ ///
Conceptually, a semaphore
+ /// maintains a set of permits. Each acquire() blocks if
+ /// necessary until a permit is available, and then takes it.
+ ///
+ ///
Each release adds a permit. However, no actual permit objects are used;
+ /// the Semaphore just keeps a count of the number available
+ /// and acts accordingly.
+ ///
+ ///
A semaphore initialized to 1 can serve as a mutual exclusion lock.
+ ///
+ /// Used for implementation of a
+ ///
+ /// Doug Lea
+ /// Federico Spinazzi (.Net)
+ public class Semaphore : ISync
+ {
+ ///
+ /// current number of available permits
+ ///
+ protected long nPermits;
+
+ ///
+ ///
Create a Semaphore with the given initial number of permits.
+ ///
Using a seed of 1 makes the semaphore act as a mutual
+ /// exclusion lock.
+ ///
+ ///
Negative seeds are also allowed,
+ /// in which case no acquires will proceed until the number of
+ /// releases has pushed the number of permits past 0.
- ///
- public class Utils
- {
- private Utils()
- {
- }
-
- ///
- /// .NET threads have not a method to check if they have been interrupted.
- /// Moreover, differently from java threads, when entering locked
- /// blocks, Monitor, Sleep, SpinWait and so on, a
- /// will be raised by the runtime.
- /// Spring.Threading classes usually call this method before entering a lock block, to mirror java code
- ///
Usually this is non issue because the same exception will be raised entering the monitor
- /// associated with the lock ()
- ///
+ ///
+ public class Utils
+ {
+ private Utils()
+ {
+ }
+
+ ///
+ /// .NET threads have not a method to check if they have been interrupted.
+ /// Moreover, differently from java threads, when entering locked
+ /// blocks, Monitor, Sleep, SpinWait and so on, a
+ /// will be raised by the runtime.
+ /// Spring.Threading classes usually call this method before entering a lock block, to mirror java code
+ ///
Usually this is non issue because the same exception will be raised entering the monitor
+ /// associated with the lock ()
+ ///
- /// Not intended to be used directly by applications.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: AssertUtils.cs,v 1.13 2008/03/14 10:45:08 bbaia Exp $
- public sealed class AssertUtils
- {
- ///
- /// Checks the value of the supplied and throws an
- /// if it is .
- ///
- /// The object to check.
- /// The argument name.
- ///
- /// If the supplied is .
- ///
- public static void ArgumentNotNull(object argument, string name)
- {
- if (argument == null)
- {
- throw new ArgumentNullException (
- name,
- string.Format (
- CultureInfo.InvariantCulture,
- "Argument '{0}' cannot be null.", name));
- }
- }
-
- ///
- /// Checks the value of the supplied and throws an
- /// if it is .
- ///
- /// The object to check.
- /// The argument name.
- ///
- /// An arbitrary message that will be passed to any thrown
- /// .
- ///
- ///
- /// If the supplied is .
- ///
- public static void ArgumentNotNull(object argument, string name, string message)
- {
- if (argument == null)
- {
- throw new ArgumentNullException(name, message);
- }
- }
-
- ///
- /// Checks the value of the supplied string and throws an
- /// if it is or
- /// contains only whitespace character(s).
- ///
- /// The string to check.
- /// The argument name.
- ///
- /// If the supplied is or
- /// contains only whitespace character(s).
- ///
- public static void ArgumentHasText(string argument, string name)
- {
- if (StringUtils.IsNullOrEmpty(argument))
- {
- throw new ArgumentNullException (
- name,
- string.Format (
- CultureInfo.InvariantCulture,
- "Argument '{0}' cannot be null or resolve to an empty string : '{1}'.", name, argument));
- }
- }
-
- ///
- /// Checks the value of the supplied string and throws an
- /// if it is or
- /// contains only whitespace character(s).
- ///
- /// The string to check.
- /// The argument name.
- ///
- /// An arbitrary message that will be passed to any thrown
- /// .
- ///
- ///
- /// If the supplied is or
- /// contains only whitespace character(s).
- ///
- public static void ArgumentHasText(string argument, string name, string message)
- {
- if (StringUtils.IsNullOrEmpty(argument))
- {
- throw new ArgumentNullException(name, message);
- }
- }
-
- ///
- /// Checks the value of the supplied and throws
- /// an if it is or contains no elements.
- ///
- /// The array or collection to check.
- /// The argument name.
- ///
- /// If the supplied is or
- /// contains no elements.
- ///
- public static void ArgumentHasLength(ICollection argument, string name)
- {
- if (!ArrayUtils.HasLength(argument))
- {
- throw new ArgumentNullException(
- name,
- string.Format(
- CultureInfo.InvariantCulture,
- "Argument '{0}' cannot be null or resolve to an empty array", name));
- }
- }
-
- ///
- /// Checks the value of the supplied and throws
- /// an if it is or contains no elements.
- ///
- /// The array or collection to check.
- /// The argument name.
- /// An arbitrary message that will be passed to any thrown .
- ///
- /// If the supplied is or
- /// contains no elements.
- ///
- public static void ArgumentHasLength(ICollection argument, string name, string message)
- {
- if(!ArrayUtils.HasLength(argument))
- {
- throw new ArgumentNullException(name, message);
- }
- }
-
- ///
- /// Checks whether the specified can be cast
- /// into the .
- ///
- ///
- /// The argument to check.
- ///
- ///
- /// The name of the argument to check.
- ///
- ///
- /// The required type for the argument.
- ///
- ///
- /// An arbitrary message that will be passed to any thrown
- /// .
- ///
- public static void AssertArgumentType(object argument, string argumentName, Type requiredType, string message)
- {
- if (argument != null && requiredType != null && !requiredType.IsAssignableFrom(argument.GetType()))
- {
- throw new ArgumentException(message, argumentName);
- }
- }
-
- ///
- /// Assert a bool expression, throwing InvalidOperationException
- /// if the expression is false.
- ///
- /// a boolean expression.
- /// The exception message to use if the assertion fails
- /// if expression is false
- public static void State(bool expression, string message)
- {
- if (!expression)
- {
- throw new InvalidOperationException(message);
- }
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
+ /// Not intended to be used directly by applications.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public sealed class AssertUtils
+ {
+ ///
+ /// Checks the value of the supplied and throws an
+ /// if it is .
+ ///
+ /// The object to check.
+ /// The argument name.
+ ///
+ /// If the supplied is .
+ ///
+ public static void ArgumentNotNull(object argument, string name)
+ {
+ if (argument == null)
+ {
+ throw new ArgumentNullException (
+ name,
+ string.Format (
+ CultureInfo.InvariantCulture,
+ "Argument '{0}' cannot be null.", name));
+ }
+ }
+
+ ///
+ /// Checks the value of the supplied and throws an
+ /// if it is .
+ ///
+ /// The object to check.
+ /// The argument name.
+ ///
+ /// An arbitrary message that will be passed to any thrown
+ /// .
+ ///
+ ///
+ /// If the supplied is .
+ ///
+ public static void ArgumentNotNull(object argument, string name, string message)
+ {
+ if (argument == null)
+ {
+ throw new ArgumentNullException(name, message);
+ }
+ }
+
+ ///
+ /// Checks the value of the supplied string and throws an
+ /// if it is or
+ /// contains only whitespace character(s).
+ ///
+ /// The string to check.
+ /// The argument name.
+ ///
+ /// If the supplied is or
+ /// contains only whitespace character(s).
+ ///
+ public static void ArgumentHasText(string argument, string name)
+ {
+ if (StringUtils.IsNullOrEmpty(argument))
+ {
+ throw new ArgumentNullException (
+ name,
+ string.Format (
+ CultureInfo.InvariantCulture,
+ "Argument '{0}' cannot be null or resolve to an empty string : '{1}'.", name, argument));
+ }
+ }
+
+ ///
+ /// Checks the value of the supplied string and throws an
+ /// if it is or
+ /// contains only whitespace character(s).
+ ///
+ /// The string to check.
+ /// The argument name.
+ ///
+ /// An arbitrary message that will be passed to any thrown
+ /// .
+ ///
+ ///
+ /// If the supplied is or
+ /// contains only whitespace character(s).
+ ///
+ public static void ArgumentHasText(string argument, string name, string message)
+ {
+ if (StringUtils.IsNullOrEmpty(argument))
+ {
+ throw new ArgumentNullException(name, message);
+ }
+ }
+
+ ///
+ /// Checks the value of the supplied and throws
+ /// an if it is or contains no elements.
+ ///
+ /// The array or collection to check.
+ /// The argument name.
+ ///
+ /// If the supplied is or
+ /// contains no elements.
+ ///
+ public static void ArgumentHasLength(ICollection argument, string name)
+ {
+ if (!ArrayUtils.HasLength(argument))
+ {
+ throw new ArgumentNullException(
+ name,
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Argument '{0}' cannot be null or resolve to an empty array", name));
+ }
+ }
+
+ ///
+ /// Checks the value of the supplied and throws
+ /// an if it is or contains no elements.
+ ///
+ /// The array or collection to check.
+ /// The argument name.
+ /// An arbitrary message that will be passed to any thrown .
+ ///
+ /// If the supplied is or
+ /// contains no elements.
+ ///
+ public static void ArgumentHasLength(ICollection argument, string name, string message)
+ {
+ if(!ArrayUtils.HasLength(argument))
+ {
+ throw new ArgumentNullException(name, message);
+ }
+ }
+
+ ///
+ /// Checks whether the specified can be cast
+ /// into the .
+ ///
+ ///
+ /// The argument to check.
+ ///
+ ///
+ /// The name of the argument to check.
+ ///
+ ///
+ /// The required type for the argument.
+ ///
+ ///
+ /// An arbitrary message that will be passed to any thrown
+ /// .
+ ///
+ public static void AssertArgumentType(object argument, string argumentName, Type requiredType, string message)
+ {
+ if (argument != null && requiredType != null && !requiredType.IsAssignableFrom(argument.GetType()))
+ {
+ throw new ArgumentException(message, argumentName);
+ }
+ }
+
+ ///
+ /// Assert a bool expression, throwing InvalidOperationException
+ /// if the expression is false.
+ ///
+ /// a boolean expression.
+ /// The exception message to use if the assertion fails
+ /// if expression is false
+ public static void State(bool expression, string message)
+ {
+ if (!expression)
+ {
+ throw new InvalidOperationException(message);
+ }
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
- /// Primary purpose of this method is to allow us to parse and
- /// load configuration sections using the same API regardless
- /// of the .NET framework version.
- ///
- ///
- /// If Microsoft paid a bit more attention to preserving backwards
- /// compatibility we would not even need it, but... :(
- ///
- ///
- /// Name of the configuration section.
- /// Object created by a corresponding .
- public static object GetSection(string sectionName)
- {
-#if !NET_2_0
- return ConfigurationSettings.GetConfig(sectionName.TrimEnd('/'));
-#else
- return ConfigurationManager.GetSection(sectionName.TrimEnd('/'));
-#endif
- }
-
- ///
- /// Refresh the configuration section.
- ///
- ///
- ///
- /// Primary purpose of this method is to allow us to parse and
- /// load configuration sections using the same API regardless
- /// of the .NET framework version.
- ///
- ///
- /// If Microsoft paid a bit more attention to preserving backwards
- /// compatibility we would not even need it, but... :(
- ///
- ///
- /// Name of the configuration section.
- public static void RefreshSection(string sectionName)
- {
-#if !NET_2_0
- // TODO : Add support for .NET 1.x
-#else
- ConfigurationManager.RefreshSection(sectionName);
-#endif
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// The inner exception.
- /// Name of the configuration file.
- /// The line where exception occured.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message, Exception inner, string fileName, int line)
- {
-#if !NET_2_0
- return new ConfigurationException(message, inner, fileName, line);
-#else
- return new ConfigurationErrorsException(message, inner, fileName, line);
-#endif
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// Name of the configuration file.
- /// The line where exception occured.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message, string fileName, int line)
- {
- return CreateConfigurationException(message, null, fileName, line);
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// The inner exception.
- /// XML node where exception occured.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message, Exception inner, XmlNode node)
- {
-#if !NET_2_0
- return new ConfigurationException(message, inner, node);
-#else
- return new ConfigurationErrorsException(message, inner, node);
-#endif
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// XML node where exception occured.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message, XmlNode node)
- {
- return CreateConfigurationException(message, null, node);
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// The inner exception.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message, Exception inner)
- {
-#if !NET_2_0
- return new ConfigurationException(message, inner);
-#else
- return new ConfigurationErrorsException(message, inner);
-#endif
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// The message to display to the client when the exception is thrown.
- /// Configuration exception.
- public static Exception CreateConfigurationException(string message)
- {
- return CreateConfigurationException(message, (Exception) null);
- }
-
- ///
- /// Creates the configuration exception.
- ///
- /// Configuration exception.
- public static Exception CreateConfigurationException()
- {
- return CreateConfigurationException(null, (Exception) null);
- }
-
- ///
- /// Determines whether the specified exception is configuration exception.
- ///
- /// The exception to check.
- ///
- /// true if the specified exception is configuration exception; otherwise, false.
- ///
- public static bool IsConfigurationException(Exception exception)
- {
-#if !NET_2_0
- return exception is ConfigurationException;
-#else
- return exception is ConfigurationErrorsException;
-#endif
- }
-
- ///
- /// Returns the line number of the specified node.
- ///
- /// Node to get the line number for.
- /// The line number of the specified node.
- public static int GetLineNumber(XmlNode node)
- {
-#if !NET_2_0
- return ConfigurationException.GetXmlNodeLineNumber(node);
-#else
- return ConfigurationErrorsException.GetLineNumber(node);
-#endif
- }
-
- ///
- /// Returns the name of the file specified node is defined in.
- ///
- /// Node to get the file name for.
- /// The name of the file specified node is defined in.
- public static string GetFileName(XmlNode node)
- {
-#if !NET_2_0
- return ConfigurationException.GetXmlNodeFilename(node);
-#else
- return ConfigurationErrorsException.GetFilename(node);
-#endif
- }
-
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Configuration;
+using System.Xml;
+
+#endregion
+
+namespace Spring.Util
+{
+ ///
+ /// Utility class for .NET configuration files management.
+ ///
+ /// Aleksandar Seovic
+ public class ConfigurationUtils
+ {
+ ///
+ /// Parses the configuration section.
+ ///
+ ///
+ ///
+ /// Primary purpose of this method is to allow us to parse and
+ /// load configuration sections using the same API regardless
+ /// of the .NET framework version.
+ ///
+ ///
+ /// If Microsoft paid a bit more attention to preserving backwards
+ /// compatibility we would not even need it, but... :(
+ ///
+ ///
+ /// Name of the configuration section.
+ /// Object created by a corresponding .
+ public static object GetSection(string sectionName)
+ {
+#if !NET_2_0
+ return ConfigurationSettings.GetConfig(sectionName.TrimEnd('/'));
+#else
+ return ConfigurationManager.GetSection(sectionName.TrimEnd('/'));
+#endif
+ }
+
+ ///
+ /// Refresh the configuration section.
+ ///
+ ///
+ ///
+ /// Primary purpose of this method is to allow us to parse and
+ /// load configuration sections using the same API regardless
+ /// of the .NET framework version.
+ ///
+ ///
+ /// If Microsoft paid a bit more attention to preserving backwards
+ /// compatibility we would not even need it, but... :(
+ ///
- /// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies.
- ///
- ///
- /// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used.
- ///
- ///
- ///
- ///
+ /// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies.
+ ///
+ ///
+ /// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used.
+ ///
+ ///
+ ///
+ ///
- /// Raising events defensively means that as the raised event is passed to each handler,
- /// any thrown by a handler will be caught and silently
- /// ignored.
- ///
+ /// Raising events defensively means that as the raised event is passed to each handler,
+ /// any thrown by a handler will be caught and silently
+ /// ignored.
+ ///
- /// Mainly for internal use within the framework.
- ///
- ///
- /// Aleksandar Seovic
- /// $Id: NumberUtils.cs,v 1.6 2008/03/20 23:58:16 oakinger Exp $
- public sealed class NumberUtils
- {
- ///
- /// Determines whether the supplied is an integer.
- ///
- /// The object to check.
- ///
- /// if the supplied is an integer.
- ///
- public static bool IsInteger(object number)
- {
- return (number is Int32 || number is Int16 || number is Int64 || number is UInt32
- || number is UInt16 || number is UInt64 || number is Byte || number is SByte);
- }
-
- ///
- /// Determines whether the supplied is a decimal number.
- ///
- /// The object to check.
- ///
- /// if the supplied is a decimal number.
- ///
- public static bool IsDecimal(object number)
- {
-
- return (number is Single || number is Double || number is Decimal);
- }
-
- ///
- /// Determines whether the supplied is of numeric type.
- ///
- /// The object to check.
- ///
- /// true if the specified object is of numeric type; otherwise, false.
- ///
- public static bool IsNumber(object number)
- {
- return (IsInteger(number) || IsDecimal(number));
- }
-
- ///
- /// Determines whether the supplied can be converted to an integer.
- ///
- /// The object to check.
- ///
- /// if the supplied can be converted to an integer.
- ///
- public static bool CanConvertToInteger(object number)
- {
- TypeConverter converter = TypeDescriptor.GetConverter(number);
- return (converter.CanConvertTo(typeof(Int32))
- || converter.CanConvertTo(typeof(Int16))
- || converter.CanConvertTo(typeof(Int64))
- || converter.CanConvertTo(typeof(UInt16))
- || converter.CanConvertTo(typeof(UInt64))
- || converter.CanConvertTo(typeof(Byte))
- || converter.CanConvertTo(typeof(SByte))
- );
- }
-
- ///
- /// Determines whether the supplied can be converted to an integer.
- ///
- /// The object to check.
- ///
- /// if the supplied can be converted to an integer.
- ///
- public static bool CanConvertToDecimal(object number)
- {
- TypeConverter converter = TypeDescriptor.GetConverter(number);
- return (converter.CanConvertTo(typeof(Single))
- || converter.CanConvertTo(typeof(Double))
- || converter.CanConvertTo(typeof(Decimal))
- );
- }
-
- ///
- /// Determines whether the supplied can be converted to a number.
- ///
- /// The object to check.
- ///
- /// true if the specified object is decimal number; otherwise, false.
- ///
- public static bool CanConvertToNumber(object number)
- {
- return (CanConvertToInteger(number) || CanConvertToDecimal(number));
- }
-
- ///
- /// Is the supplied equal to zero (0)?
- ///
- /// The number to check.
- ///
- /// id the supplied is equal to zero (0).
- ///
- public static bool IsZero(object number)
- {
- if (number is Int32) return ((Int32) number) == 0;
- else if (number is Int16) return ((Int16) number) == 0;
- else if (number is Int64) return ((Int64) number) == 0;
- else if (number is UInt16) return ((Int32) number) == 0;
- else if (number is UInt32) return ((Int64) number) == 0;
- else if (number is UInt64) return (Convert.ToDecimal(number) == 0);
- else if (number is Byte) return ((Int16) number) == 0;
- else if (number is SByte) return ((Int16) number) == 0;
- else if (number is Single) return ((Single) number) == 0f;
- else if (number is Double) return ((Double) number) == 0d;
- else if (number is Decimal) return ((Decimal) number) == 0m;
- return false;
- }
-
- ///
- /// Negates the supplied .
- ///
- /// The number to negate.
- /// The supplied negated.
- ///
- /// If the supplied is not a supported numeric type.
- ///
- public static object Negate(object number)
- {
- if (number is Int32) return -((Int32) number);
- else if (number is Int16) return -((Int16) number);
- else if (number is Int64) return -((Int64) number);
- else if (number is UInt16) return -((Int32) number);
- else if (number is UInt32) return -((Int64) number);
- else if (number is UInt64) return -(Convert.ToDecimal(number));
- else if (number is Byte) return -((Int16) number);
- else if (number is SByte) return -((Int16) number);
- else if (number is Single) return -((Single) number);
- else if (number is Double) return -((Double) number);
- else if (number is Decimal) return -((Decimal) number);
- else
- {
- throw new ArgumentException(string.Format("'{0}' is not one of the supported numeric types.", number));
- }
- }
-
- ///
- /// Adds the specified numbers.
- ///
- /// The first number.
- /// The second number.
- public static object Add(object m, object n)
- {
- CoerceTypes(ref m, ref n);
-
- if (n is Int32) return (Int32) m + (Int32) n;
- else if (n is Int16) return (Int16) m + (Int16) n;
- else if (n is Int64) return (Int64) m + (Int64) n;
- else if (n is UInt16) return (UInt16) m + (UInt16) n;
- else if (n is UInt32) return (UInt32) m + (UInt32) n;
- else if (n is UInt64) return (UInt64) m + (UInt64) n;
- else if (n is Byte) return (Byte) m + (Byte) n;
- else if (n is SByte) return (SByte) m + (SByte) n;
- else if (n is Single) return (Single) m + (Single) n;
- else if (n is Double) return (Double) m + (Double) n;
- else if (n is Decimal) return (Decimal) m + (Decimal) n;
-
- return null;
- }
-
- ///
- /// Subtracts the specified numbers.
- ///
- /// The first number.
- /// The second number.
- public static object Subtract(object m, object n)
- {
- CoerceTypes(ref m, ref n);
-
- if (n is Int32) return (Int32) m - (Int32) n;
- else if (n is Int16) return (Int16) m - (Int16) n;
- else if (n is Int64) return (Int64) m - (Int64) n;
- else if (n is UInt16) return (UInt16) m - (UInt16) n;
- else if (n is UInt32) return (UInt32) m - (UInt32) n;
- else if (n is UInt64) return (UInt64) m - (UInt64) n;
- else if (n is Byte) return (Byte) m - (Byte) n;
- else if (n is SByte) return (SByte) m - (SByte) n;
- else if (n is Single) return (Single) m - (Single) n;
- else if (n is Double) return (Double) m - (Double) n;
- else if (n is Decimal) return (Decimal) m - (Decimal) n;
-
- return null;
- }
-
- ///
- /// Multiplies the specified numbers.
- ///
- /// The first number.
- /// The second number.
- public static object Multiply(object m, object n)
- {
- CoerceTypes(ref m, ref n);
-
- if (n is Int32) return (Int32) m*(Int32) n;
- else if (n is Int16) return (Int16) m*(Int16) n;
- else if (n is Int64) return (Int64) m*(Int64) n;
- else if (n is UInt16) return (UInt16) m*(UInt16) n;
- else if (n is UInt32) return (UInt32) m*(UInt32) n;
- else if (n is UInt64) return (UInt64) m*(UInt64) n;
- else if (n is Byte) return (Byte) m*(Byte) n;
- else if (n is SByte) return (SByte) m*(SByte) n;
- else if (n is Single) return (Single) m*(Single) n;
- else if (n is Double) return (Double) m*(Double) n;
- else if (n is Decimal) return (Decimal) m*(Decimal) n;
-
- return null;
- }
-
- ///
- /// Divides the specified numbers.
- ///
- /// The first number.
- /// The second number.
- public static object Divide(object m, object n)
- {
- CoerceTypes(ref m, ref n);
-
- if (n is Int32) return (Int32) m/(Int32) n;
- else if (n is Int16) return (Int16) m/(Int16) n;
- else if (n is Int64) return (Int64) m/(Int64) n;
- else if (n is UInt16) return (UInt16) m/(UInt16) n;
- else if (n is UInt32) return (UInt32) m/(UInt32) n;
- else if (n is UInt64) return (UInt64) m/(UInt64) n;
- else if (n is Byte) return (Byte) m/(Byte) n;
- else if (n is SByte) return (SByte) m/(SByte) n;
- else if (n is Single) return (Single) m/(Single) n;
- else if (n is Double) return (Double) m/(Double) n;
- else if (n is Decimal) return (Decimal) m/(Decimal) n;
-
- return null;
- }
-
- ///
- /// Calculates remainder for the specified numbers.
- ///
- /// The first number (dividend).
- /// The second number (divisor).
- public static object Modulus(object m, object n)
- {
- CoerceTypes(ref m, ref n);
-
- if (n is Int32) return (Int32) m%(Int32) n;
- else if (n is Int16) return (Int16) m%(Int16) n;
- else if (n is Int64) return (Int64) m%(Int64) n;
- else if (n is UInt16) return (UInt16) m%(UInt16) n;
- else if (n is UInt32) return (UInt32) m%(UInt32) n;
- else if (n is UInt64) return (UInt64) m%(UInt64) n;
- else if (n is Byte) return (Byte) m%(Byte) n;
- else if (n is SByte) return (SByte) m%(SByte) n;
- else if (n is Single) return (Single) m%(Single) n;
- else if (n is Double) return (Double) m%(Double) n;
- else if (n is Decimal) return (Decimal) m%(Decimal) n;
-
- return null;
- }
-
- ///
- /// Raises first number to the power of the second one.
- ///
- /// The first number.
- /// The second number.
- public static object Power(object m, object n)
- {
- return Math.Pow(Convert.ToDouble(m), Convert.ToDouble(n));
- }
-
- ///
- /// Coerces the types so they can be compared.
- ///
- /// The right.
- /// The left.
- public static void CoerceTypes(ref object m, ref object n)
- {
- TypeCode leftTypeCode = Convert.GetTypeCode(m);
- TypeCode rightTypeCode = Convert.GetTypeCode(n);
-
- if (leftTypeCode > rightTypeCode)
- {
- n = Convert.ChangeType(n, leftTypeCode);
- }
- else
- {
- m = Convert.ChangeType(m, rightTypeCode);
- }
- }
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
+ /// Mainly for internal use within the framework.
+ ///
+ ///
+ /// Aleksandar Seovic
+ public sealed class NumberUtils
+ {
+ ///
+ /// Determines whether the supplied is an integer.
+ ///
+ /// The object to check.
+ ///
+ /// if the supplied is an integer.
+ ///
+ public static bool IsInteger(object number)
+ {
+ return (number is Int32 || number is Int16 || number is Int64 || number is UInt32
+ || number is UInt16 || number is UInt64 || number is Byte || number is SByte);
+ }
+
+ ///
+ /// Determines whether the supplied is a decimal number.
+ ///
+ /// The object to check.
+ ///
+ /// if the supplied is a decimal number.
+ ///
+ public static bool IsDecimal(object number)
+ {
+
+ return (number is Single || number is Double || number is Decimal);
+ }
+
+ ///
+ /// Determines whether the supplied is of numeric type.
+ ///
+ /// The object to check.
+ ///
+ /// true if the specified object is of numeric type; otherwise, false.
+ ///
+ public static bool IsNumber(object number)
+ {
+ return (IsInteger(number) || IsDecimal(number));
+ }
+
+ ///
+ /// Determines whether the supplied can be converted to an integer.
+ ///
+ /// The object to check.
+ ///
+ /// if the supplied can be converted to an integer.
+ ///
+ public static bool CanConvertToInteger(object number)
+ {
+ TypeConverter converter = TypeDescriptor.GetConverter(number);
+ return (converter.CanConvertTo(typeof(Int32))
+ || converter.CanConvertTo(typeof(Int16))
+ || converter.CanConvertTo(typeof(Int64))
+ || converter.CanConvertTo(typeof(UInt16))
+ || converter.CanConvertTo(typeof(UInt64))
+ || converter.CanConvertTo(typeof(Byte))
+ || converter.CanConvertTo(typeof(SByte))
+ );
+ }
+
+ ///
+ /// Determines whether the supplied can be converted to an integer.
+ ///
+ /// The object to check.
+ ///
+ /// if the supplied can be converted to an integer.
+ ///
+ public static bool CanConvertToDecimal(object number)
+ {
+ TypeConverter converter = TypeDescriptor.GetConverter(number);
+ return (converter.CanConvertTo(typeof(Single))
+ || converter.CanConvertTo(typeof(Double))
+ || converter.CanConvertTo(typeof(Decimal))
+ );
+ }
+
+ ///
+ /// Determines whether the supplied can be converted to a number.
+ ///
+ /// The object to check.
+ ///
+ /// true if the specified object is decimal number; otherwise, false.
+ ///
+ public static bool CanConvertToNumber(object number)
+ {
+ return (CanConvertToInteger(number) || CanConvertToDecimal(number));
+ }
+
+ ///
+ /// Is the supplied equal to zero (0)?
+ ///
+ /// The number to check.
+ ///
+ /// id the supplied is equal to zero (0).
+ ///
+ public static bool IsZero(object number)
+ {
+ if (number is Int32) return ((Int32) number) == 0;
+ else if (number is Int16) return ((Int16) number) == 0;
+ else if (number is Int64) return ((Int64) number) == 0;
+ else if (number is UInt16) return ((Int32) number) == 0;
+ else if (number is UInt32) return ((Int64) number) == 0;
+ else if (number is UInt64) return (Convert.ToDecimal(number) == 0);
+ else if (number is Byte) return ((Int16) number) == 0;
+ else if (number is SByte) return ((Int16) number) == 0;
+ else if (number is Single) return ((Single) number) == 0f;
+ else if (number is Double) return ((Double) number) == 0d;
+ else if (number is Decimal) return ((Decimal) number) == 0m;
+ return false;
+ }
+
+ ///
+ /// Negates the supplied .
+ ///
+ /// The number to negate.
+ /// The supplied negated.
+ ///
+ /// If the supplied is not a supported numeric type.
+ ///
+ public static object Negate(object number)
+ {
+ if (number is Int32) return -((Int32) number);
+ else if (number is Int16) return -((Int16) number);
+ else if (number is Int64) return -((Int64) number);
+ else if (number is UInt16) return -((Int32) number);
+ else if (number is UInt32) return -((Int64) number);
+ else if (number is UInt64) return -(Convert.ToDecimal(number));
+ else if (number is Byte) return -((Int16) number);
+ else if (number is SByte) return -((Int16) number);
+ else if (number is Single) return -((Single) number);
+ else if (number is Double) return -((Double) number);
+ else if (number is Decimal) return -((Decimal) number);
+ else
+ {
+ throw new ArgumentException(string.Format("'{0}' is not one of the supported numeric types.", number));
+ }
+ }
+
+ ///
+ /// Adds the specified numbers.
+ ///
+ /// The first number.
+ /// The second number.
+ public static object Add(object m, object n)
+ {
+ CoerceTypes(ref m, ref n);
+
+ if (n is Int32) return (Int32) m + (Int32) n;
+ else if (n is Int16) return (Int16) m + (Int16) n;
+ else if (n is Int64) return (Int64) m + (Int64) n;
+ else if (n is UInt16) return (UInt16) m + (UInt16) n;
+ else if (n is UInt32) return (UInt32) m + (UInt32) n;
+ else if (n is UInt64) return (UInt64) m + (UInt64) n;
+ else if (n is Byte) return (Byte) m + (Byte) n;
+ else if (n is SByte) return (SByte) m + (SByte) n;
+ else if (n is Single) return (Single) m + (Single) n;
+ else if (n is Double) return (Double) m + (Double) n;
+ else if (n is Decimal) return (Decimal) m + (Decimal) n;
+
+ return null;
+ }
+
+ ///
+ /// Subtracts the specified numbers.
+ ///
+ /// The first number.
+ /// The second number.
+ public static object Subtract(object m, object n)
+ {
+ CoerceTypes(ref m, ref n);
+
+ if (n is Int32) return (Int32) m - (Int32) n;
+ else if (n is Int16) return (Int16) m - (Int16) n;
+ else if (n is Int64) return (Int64) m - (Int64) n;
+ else if (n is UInt16) return (UInt16) m - (UInt16) n;
+ else if (n is UInt32) return (UInt32) m - (UInt32) n;
+ else if (n is UInt64) return (UInt64) m - (UInt64) n;
+ else if (n is Byte) return (Byte) m - (Byte) n;
+ else if (n is SByte) return (SByte) m - (SByte) n;
+ else if (n is Single) return (Single) m - (Single) n;
+ else if (n is Double) return (Double) m - (Double) n;
+ else if (n is Decimal) return (Decimal) m - (Decimal) n;
+
+ return null;
+ }
+
+ ///
+ /// Multiplies the specified numbers.
+ ///
+ /// The first number.
+ /// The second number.
+ public static object Multiply(object m, object n)
+ {
+ CoerceTypes(ref m, ref n);
+
+ if (n is Int32) return (Int32) m*(Int32) n;
+ else if (n is Int16) return (Int16) m*(Int16) n;
+ else if (n is Int64) return (Int64) m*(Int64) n;
+ else if (n is UInt16) return (UInt16) m*(UInt16) n;
+ else if (n is UInt32) return (UInt32) m*(UInt32) n;
+ else if (n is UInt64) return (UInt64) m*(UInt64) n;
+ else if (n is Byte) return (Byte) m*(Byte) n;
+ else if (n is SByte) return (SByte) m*(SByte) n;
+ else if (n is Single) return (Single) m*(Single) n;
+ else if (n is Double) return (Double) m*(Double) n;
+ else if (n is Decimal) return (Decimal) m*(Decimal) n;
+
+ return null;
+ }
+
+ ///
+ /// Divides the specified numbers.
+ ///
+ /// The first number.
+ /// The second number.
+ public static object Divide(object m, object n)
+ {
+ CoerceTypes(ref m, ref n);
+
+ if (n is Int32) return (Int32) m/(Int32) n;
+ else if (n is Int16) return (Int16) m/(Int16) n;
+ else if (n is Int64) return (Int64) m/(Int64) n;
+ else if (n is UInt16) return (UInt16) m/(UInt16) n;
+ else if (n is UInt32) return (UInt32) m/(UInt32) n;
+ else if (n is UInt64) return (UInt64) m/(UInt64) n;
+ else if (n is Byte) return (Byte) m/(Byte) n;
+ else if (n is SByte) return (SByte) m/(SByte) n;
+ else if (n is Single) return (Single) m/(Single) n;
+ else if (n is Double) return (Double) m/(Double) n;
+ else if (n is Decimal) return (Decimal) m/(Decimal) n;
+
+ return null;
+ }
+
+ ///
+ /// Calculates remainder for the specified numbers.
+ ///
+ /// The first number (dividend).
+ /// The second number (divisor).
+ public static object Modulus(object m, object n)
+ {
+ CoerceTypes(ref m, ref n);
+
+ if (n is Int32) return (Int32) m%(Int32) n;
+ else if (n is Int16) return (Int16) m%(Int16) n;
+ else if (n is Int64) return (Int64) m%(Int64) n;
+ else if (n is UInt16) return (UInt16) m%(UInt16) n;
+ else if (n is UInt32) return (UInt32) m%(UInt32) n;
+ else if (n is UInt64) return (UInt64) m%(UInt64) n;
+ else if (n is Byte) return (Byte) m%(Byte) n;
+ else if (n is SByte) return (SByte) m%(SByte) n;
+ else if (n is Single) return (Single) m%(Single) n;
+ else if (n is Double) return (Double) m%(Double) n;
+ else if (n is Decimal) return (Decimal) m%(Decimal) n;
+
+ return null;
+ }
+
+ ///
+ /// Raises first number to the power of the second one.
+ ///
+ /// The first number.
+ /// The second number.
+ public static object Power(object m, object n)
+ {
+ return Math.Pow(Convert.ToDouble(m), Convert.ToDouble(n));
+ }
+
+ ///
+ /// Coerces the types so they can be compared.
+ ///
+ /// The right.
+ /// The left.
+ public static void CoerceTypes(ref object m, ref object n)
+ {
+ TypeCode leftTypeCode = Convert.GetTypeCode(m);
+ TypeCode rightTypeCode = Convert.GetTypeCode(n);
+
+ if (leftTypeCode > rightTypeCode)
+ {
+ n = Convert.ChangeType(n, leftTypeCode);
+ }
+ else
+ {
+ m = Convert.ChangeType(m, rightTypeCode);
+ }
+ }
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
- /// Not intended to be used directly by applications.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Rick Evans (.NET)
- /// $Id: ObjectUtils.cs,v 1.9 2007/12/29 00:31:00 markpollack Exp $
- public sealed class ObjectUtils
- {
- #region Constants
-
- ///
- /// An empty object array.
- ///
- public static readonly object[] EmptyObjects = new object[] {};
-
- #endregion
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
- ///
- private ObjectUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- #region Methods
-
- ///
- /// Instantiates the type using the assembly specified to load the type.
- ///
- /// This is a convenience in the case of needing to instantiate a type but not
- /// wanting to specify in the string the version, culture and public key token.
- /// The assembly.
- /// Name of the type.
- ///
- ///
- /// If the or is
- ///
- ///
- /// If cannot load the type from the assembly or the call to InstantiateType(Type) fails.
- ///
- public static object InstantiateType(Assembly assembly, string typeName)
- {
- AssertUtils.ArgumentNotNull(assembly, "assembly");
- AssertUtils.ArgumentNotNull(typeName, "typeName");
- Type resolvedType = assembly.GetType(typeName, false, false);
- if (resolvedType == null)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot load type named [{0}] from assembly [{1}].", typeName, assembly));
- }
- return InstantiateType(resolvedType);
- }
- ///
- /// Convenience method to instantiate a using
- /// its no-arg constructor.
- ///
- ///
- ///
- /// As this method doesn't try to instantiate s
- /// by name, it should avoid loading issues.
- ///
- ///
- ///
- /// The to instantiate*
- ///
- /// A new instance of the .
- ///
- /// If the is
- ///
- ///
- /// If the is an abstract class, an interface,
- /// an open generic type or does not have a public no-argument constructor.
- ///
- public static object InstantiateType(Type type)
- {
- AssertUtils.ArgumentNotNull(type, "type");
-
- ConstructorInfo constructor = GetZeroArgConstructorInfo(type);
- return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects);
- }
-
- ///
- /// Gets the zero arg ConstructorInfo object, if the type offers such functionality.
- ///
- /// The type.
- /// Zero argument ConstructorInfo
- ///
- /// If the type is an interface, abstract, open generic type, or does not have a zero-arg constructor.
- ///
- public static ConstructorInfo GetZeroArgConstructorInfo(Type type)
- {
- IsInstantiable(type);
- ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
- if (constructor == null)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a public no-argument constructor [{0}].", type));
- }
- return constructor;
- }
-
- ///
- /// Determines whether the specified type is instantiable, i.e. not an interface, abstract class or contains
- /// open generic type parameters.
- ///
- /// The type.
- public static void IsInstantiable(Type type)
- {
- if (type.IsInterface)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", type));
- }
- if (type.IsAbstract)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", type));
- }
-#if NET_2_0
- if (type.ContainsGenericParameters)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", type));
- }
-#endif
- }
-
- ///
- /// Convenience method to instantiate a using
- /// the given constructor.
- ///
- ///
- ///
- /// As this method doesn't try to instantiate s
- /// by name, it should avoid loading issues.
- ///
- ///
- ///
- /// The constructor to use for the instantiation.
- ///
- ///
- /// The arguments to be passed to the constructor.
- ///
- /// A new instance.
- ///
- /// If the is
- ///
- ///
- /// If the 's declaring type is an abstract class,
- /// an interface, an open generic type or does not have a public no-argument constructor.
- ///
- public static object InstantiateType(ConstructorInfo constructor, object[] arguments)
- {
- AssertUtils.ArgumentNotNull(constructor, "constructor");
-
- if (constructor.DeclaringType.IsInterface)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", constructor.DeclaringType));
- }
- if (constructor.DeclaringType.IsAbstract)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", constructor.DeclaringType));
- }
-#if NET_2_0
- if (constructor.DeclaringType.ContainsGenericParameters)
- {
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", constructor.DeclaringType));
- }
-#endif
- try
- {
- return constructor.Invoke(arguments);
- }
- catch (Exception ex)
- {
- Type ctorType = constructor.DeclaringType;
- throw new FatalReflectionException(
- string.Format(
- CultureInfo.InvariantCulture,
- "Cannot instantiate Type [{0}] using ctor [{1}] : '{2}'",
- constructor.DeclaringType, constructor, ex.Message),
- ex);
- }
- }
-
- ///
- /// Checks whether the supplied is not a transparent proxy and is
- /// assignable to the supplied .
- ///
- ///
- ///
- /// Neccessary when dealing with server-activated remote objects, because the
- /// object is of the type TransparentProxy and regular is testing for assignable
- /// types does not work.
- ///
- ///
- /// Transparent proxy instances always return when tested
- /// with the 'is' operator (C#). This method only checks if the object
- /// is assignable to the type if it is not a transparent proxy.
- ///
- ///
- /// The target to be checked.
- /// The value that should be assigned to the type.
- ///
- /// if the supplied is not a
- /// transparent proxy and is assignable to the supplied .
- ///
- public static bool IsAssignableAndNotTransparentProxy(Type type, object instance)
- {
- if (!RemotingServices.IsTransparentProxy(instance))
- {
- return IsAssignable(type, instance);
- }
- return false;
- }
-
- ///
- /// Determine if the given is assignable from the
- /// given value, assuming setting by reflection.
- ///
- ///
- ///
- /// Considers primitive wrapper classes as assignable to the
- /// corresponding primitive types.
- ///
- ///
- /// For example used in an object factory's constructor resolution.
- ///
- ///
- /// The target .
- /// The value that should be assigned to the type.
- /// True if the type is assignable from the value.
- public static bool IsAssignable(Type type, object obj)
- {
- return (type.IsInstanceOfType(obj) ||
- (!type.IsPrimitive && obj == null) ||
- (type.Equals(typeof (bool)) && obj is Boolean) ||
- (type.Equals(typeof (byte)) && obj is Byte) ||
- (type.Equals(typeof (char)) && obj is Char) ||
- (type.Equals(typeof (sbyte)) && obj is SByte) ||
- (type.Equals(typeof (int)) && obj is Int32) ||
- (type.Equals(typeof (short)) && obj is Int16) ||
- (type.Equals(typeof (long)) && obj is Int64) ||
- (type.Equals(typeof (float)) && obj is Single) ||
- (type.Equals(typeof (double)) && obj is Double));
- }
-
- ///
- /// Check if the given represents a
- /// "simple" property,
- /// i.e. a primitive, a , a
- /// , or a corresponding array.
- ///
- ///
- ///
- /// Used to determine properties to check for a "simple" dependency-check.
- ///
+ /// Not intended to be used directly by applications.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans (.NET)
+ public sealed class ObjectUtils
+ {
+ #region Constants
+
+ ///
+ /// An empty object array.
+ ///
+ public static readonly object[] EmptyObjects = new object[] {};
+
+ #endregion
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
+ ///
+ private ObjectUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Instantiates the type using the assembly specified to load the type.
+ ///
+ /// This is a convenience in the case of needing to instantiate a type but not
+ /// wanting to specify in the string the version, culture and public key token.
+ /// The assembly.
+ /// Name of the type.
+ ///
+ ///
+ /// If the or is
+ ///
+ ///
+ /// If cannot load the type from the assembly or the call to InstantiateType(Type) fails.
+ ///
+ public static object InstantiateType(Assembly assembly, string typeName)
+ {
+ AssertUtils.ArgumentNotNull(assembly, "assembly");
+ AssertUtils.ArgumentNotNull(typeName, "typeName");
+ Type resolvedType = assembly.GetType(typeName, false, false);
+ if (resolvedType == null)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot load type named [{0}] from assembly [{1}].", typeName, assembly));
+ }
+ return InstantiateType(resolvedType);
+ }
+ ///
+ /// Convenience method to instantiate a using
+ /// its no-arg constructor.
+ ///
+ ///
+ ///
+ /// As this method doesn't try to instantiate s
+ /// by name, it should avoid loading issues.
+ ///
+ ///
+ ///
+ /// The to instantiate*
+ ///
+ /// A new instance of the .
+ ///
+ /// If the is
+ ///
+ ///
+ /// If the is an abstract class, an interface,
+ /// an open generic type or does not have a public no-argument constructor.
+ ///
+ public static object InstantiateType(Type type)
+ {
+ AssertUtils.ArgumentNotNull(type, "type");
+
+ ConstructorInfo constructor = GetZeroArgConstructorInfo(type);
+ return ObjectUtils.InstantiateType(constructor, ObjectUtils.EmptyObjects);
+ }
+
+ ///
+ /// Gets the zero arg ConstructorInfo object, if the type offers such functionality.
+ ///
+ /// The type.
+ /// Zero argument ConstructorInfo
+ ///
+ /// If the type is an interface, abstract, open generic type, or does not have a zero-arg constructor.
+ ///
+ public static ConstructorInfo GetZeroArgConstructorInfo(Type type)
+ {
+ IsInstantiable(type);
+ ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
+ if (constructor == null)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate a class that does not have a public no-argument constructor [{0}].", type));
+ }
+ return constructor;
+ }
+
+ ///
+ /// Determines whether the specified type is instantiable, i.e. not an interface, abstract class or contains
+ /// open generic type parameters.
+ ///
+ /// The type.
+ public static void IsInstantiable(Type type)
+ {
+ if (type.IsInterface)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", type));
+ }
+ if (type.IsAbstract)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", type));
+ }
+#if NET_2_0
+ if (type.ContainsGenericParameters)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", type));
+ }
+#endif
+ }
+
+ ///
+ /// Convenience method to instantiate a using
+ /// the given constructor.
+ ///
+ ///
+ ///
+ /// As this method doesn't try to instantiate s
+ /// by name, it should avoid loading issues.
+ ///
+ ///
+ ///
+ /// The constructor to use for the instantiation.
+ ///
+ ///
+ /// The arguments to be passed to the constructor.
+ ///
+ /// A new instance.
+ ///
+ /// If the is
+ ///
+ ///
+ /// If the 's declaring type is an abstract class,
+ /// an interface, an open generic type or does not have a public no-argument constructor.
+ ///
+ public static object InstantiateType(ConstructorInfo constructor, object[] arguments)
+ {
+ AssertUtils.ArgumentNotNull(constructor, "constructor");
+
+ if (constructor.DeclaringType.IsInterface)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an interface [{0}].", constructor.DeclaringType));
+ }
+ if (constructor.DeclaringType.IsAbstract)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an abstract class [{0}].", constructor.DeclaringType));
+ }
+#if NET_2_0
+ if (constructor.DeclaringType.ContainsGenericParameters)
+ {
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture, "Cannot instantiate an open generic type [{0}].", constructor.DeclaringType));
+ }
+#endif
+ try
+ {
+ return constructor.Invoke(arguments);
+ }
+ catch (Exception ex)
+ {
+ Type ctorType = constructor.DeclaringType;
+ throw new FatalReflectionException(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "Cannot instantiate Type [{0}] using ctor [{1}] : '{2}'",
+ constructor.DeclaringType, constructor, ex.Message),
+ ex);
+ }
+ }
+
+ ///
+ /// Checks whether the supplied is not a transparent proxy and is
+ /// assignable to the supplied .
+ ///
+ ///
+ ///
+ /// Neccessary when dealing with server-activated remote objects, because the
+ /// object is of the type TransparentProxy and regular is testing for assignable
+ /// types does not work.
+ ///
+ ///
+ /// Transparent proxy instances always return when tested
+ /// with the 'is' operator (C#). This method only checks if the object
+ /// is assignable to the type if it is not a transparent proxy.
+ ///
+ ///
+ /// The target to be checked.
+ /// The value that should be assigned to the type.
+ ///
+ /// if the supplied is not a
+ /// transparent proxy and is assignable to the supplied .
+ ///
+ public static bool IsAssignableAndNotTransparentProxy(Type type, object instance)
+ {
+ if (!RemotingServices.IsTransparentProxy(instance))
+ {
+ return IsAssignable(type, instance);
+ }
+ return false;
+ }
+
+ ///
+ /// Determine if the given is assignable from the
+ /// given value, assuming setting by reflection.
+ ///
+ ///
+ ///
+ /// Considers primitive wrapper classes as assignable to the
+ /// corresponding primitive types.
+ ///
+ ///
+ /// For example used in an object factory's constructor resolution.
+ ///
+ ///
+ /// The target .
+ /// The value that should be assigned to the type.
+ /// True if the type is assignable from the value.
+ public static bool IsAssignable(Type type, object obj)
+ {
+ return (type.IsInstanceOfType(obj) ||
+ (!type.IsPrimitive && obj == null) ||
+ (type.Equals(typeof (bool)) && obj is Boolean) ||
+ (type.Equals(typeof (byte)) && obj is Byte) ||
+ (type.Equals(typeof (char)) && obj is Char) ||
+ (type.Equals(typeof (sbyte)) && obj is SByte) ||
+ (type.Equals(typeof (int)) && obj is Int32) ||
+ (type.Equals(typeof (short)) && obj is Int16) ||
+ (type.Equals(typeof (long)) && obj is Int64) ||
+ (type.Equals(typeof (float)) && obj is Single) ||
+ (type.Equals(typeof (double)) && obj is Double));
+ }
+
+ ///
+ /// Check if the given represents a
+ /// "simple" property,
+ /// i.e. a primitive, a , a
+ /// , or a corresponding array.
+ ///
+ ///
+ ///
+ /// Used to determine properties to check for a "simple" dependency-check.
+ ///
- /// Follows the standard .NET conventions for default values where
- /// relevant; for example, all numeric types default to the value
- /// 0.
- ///
- ///
- ///
- /// The to return default value for.
- ///
- ///
- /// The default value for the specified .
- ///
- ///
- /// If the supplied is an enumerated type that
- /// has no values.
- ///
- public static object GetDefaultValue(Type type)
- {
- if (!type.IsValueType)
- {
- return null;
- }
- if (type == typeof(Boolean))
- {
- return false;
- }
- if (type == typeof(DateTime))
- {
- return DateTime.MinValue;
- }
- if (type == typeof(Char))
- {
- return Char.MinValue;
- }
- if (type.IsEnum)
- {
- Array values = Enum.GetValues(type);
- if (values == null || values.Length == 0)
- {
- throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values.");
- }
- return values.GetValue(0);
- }
- return 0;
- }
-
- ///
- /// Returns an array consisting of the default values for the supplied
- /// .
- ///
- ///
- /// The array of s to return default values for.
- ///
- ///
- /// An array consisting of the default values for the supplied
- /// .
- ///
- ///
- /// If any of the elements in the supplied
- /// array is an enumerated type that has no values.
- ///
- ///
- public static object[] GetDefaultValues(Type[] types)
- {
- object[] defaults = new object[types.Length];
- for (int i = 0; i < types.Length; ++i)
- {
- defaults[i] = GetDefaultValue(types[i]);
- }
- return defaults;
- }
-
- ///
- /// Checks that the parameter s of the
- /// supplied match the parameter
- /// s of the supplied
- /// .
- ///
- /// The method to be checked.
- ///
- /// The array of parameter s to check against.
- ///
- ///
- /// if the parameter s
- /// match.
- ///
- public static bool ParameterTypesMatch(
- MethodInfo candidate, Type[] parameterTypes)
- {
- #region Sanity Checks
-
- AssertUtils.ArgumentNotNull(candidate, "candidate");
- AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes");
-
- #endregion
-
- Type[] candidatesParameterTypes
- = ReflectionUtils.GetParameterTypes(candidate);
- if (candidatesParameterTypes.Length != parameterTypes.Length)
- {
- return false;
- }
- for (int i = 0; i < candidatesParameterTypes.Length; ++i)
- {
- if (!candidatesParameterTypes[i].Equals(parameterTypes[i]))
- {
- return false;
- }
- }
- return true;
- }
-
- ///
- /// Returns an array containing the s of the
- /// objects in the supplied array.
- ///
- ///
- /// The objects array for which the corresponding s
- /// are needed.
- ///
- ///
- /// An array containing the s of the objects
- /// in the supplied array; this array will be empty (but not
- /// if the supplied
- /// is null or has no elements.
- ///
- ///
- ///
- /// [C#]
- /// Given an array containing the following objects,
- /// [83, "Foo", new object ()], the
- /// array returned from this method call would consist of the following
- /// elements...
- /// [Int32, String, Object].
- ///
- ///
- public static Type[] GetTypes(object[] args)
- {
- if (args == null || args.Length == 0)
- {
- return Type.EmptyTypes;
- }
- Type[] paramsType = new Type[args.Length];
- for (int i = 0; i < args.Length; ++i)
- {
- object arg = args[i];
- paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object);
- }
- return paramsType;
- }
-
- ///
- /// Does the given and/or it's superclasses
- /// have at least one or more methods with the given name (with any
- /// argument types)?
- ///
- ///
- ///
- /// Includes non-public methods in the methods searched.
- ///
- ///
- ///
- /// The to be checked.
- ///
- ///
- /// The name of the method to be searched for. Case inSenSItivE.
- ///
- ///
- /// if the given or / and it's
- /// superclasses have at least one or more methods (with any argument types);
- /// if not, or either of the parameters is .
- ///
- public static bool HasAtLeastOneMethodWithName(Type type, string name)
- {
- if (type == null || StringUtils.IsNullOrEmpty(name))
- {
- return false;
- }
- return MethodCountForName(type, name) > 0;
- }
-
- ///
- /// Within , counts the number of overloads for the method with the given (case-insensitive!)
- ///
- /// The type to be searched
- /// the name of the method for which overloads shall be counted
- /// The number of overloads for method within type
- public static int MethodCountForName(Type type, string name)
- {
- AssertUtils.ArgumentNotNull(type, "type", "Type must not be null");
- AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null");
- MemberInfo[] methods = type.FindMembers(
- MemberTypes.Method,
- ReflectionUtils.AllMembersCaseInsensitiveFlags,
- new MemberFilter(ReflectionUtils.MethodNameFilter),
- name);
- return methods.Length;
- }
-
- private static bool MethodNameFilter(MemberInfo member, object criteria)
- {
- MethodInfo method = member as MethodInfo;
- string name = criteria as string;
- return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0;
- }
-
- ///
- /// Creates a .
- ///
- ///
- ///
- /// Note that if a non-
- /// is supplied, any read write properties exposed by the
- /// will be used to overwrite values that may have been passed in via the
- /// . That is, the will be used
- /// to initialize the custom attribute, and then any read-write properties on the
- /// will be plugged in.
- ///
- ///
- ///
- /// The desired .
- ///
- ///
- /// Any constructor arguments for the attribute (may be
- /// in the case of no arguments).
- ///
- ///
- /// Source attribute to copy properties from (may be ).
- ///
- /// A custom attribute builder.
- ///
- /// If the parameter is .
- ///
- ///
- /// If the parameter is not a
- /// that derives from the class.
- ///
- ///
- public static CustomAttributeBuilder CreateCustomAttribute(
- Type type, object[] ctorArgs, Attribute sourceAttribute)
- {
- #region Sanity Checks
-
- AssertUtils.ArgumentNotNull(type, "type");
- if (!typeof(Attribute).IsAssignableFrom(type))
- {
- throw new ArgumentException(
- string.Format("[{0}] does not derive from the [System.Attribute] class.",
- type.FullName));
- }
-
- #endregion
-
- ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs));
- if (ci == null && ctorArgs.Length == 0)
- {
- ci = type.GetConstructors()[0];
- ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters()));
- }
-
- if (sourceAttribute != null)
- {
- object defaultAttribute = null;
- try
- {
- defaultAttribute = ci.Invoke(ctorArgs);
- }
- catch
- {
- }
-
- IList getSetProps = new ArrayList();
- IList getSetValues = new ArrayList();
- IList readOnlyProps = new ArrayList();
- IList readOnlyValues = new ArrayList();
- foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
- {
- if (pi.DeclaringType == typeof(Attribute))
- continue;
-
- if (pi.CanRead)
- {
- if (pi.CanWrite)
- {
- object propValue = pi.GetValue(sourceAttribute, null);
- if (defaultAttribute != null)
- {
- object defaultValue = pi.GetValue(defaultAttribute, null);
- if ((propValue == null && defaultValue == null) ||
- (propValue != null && propValue.Equals(defaultValue)))
- continue;
- }
- getSetProps.Add(pi);
- getSetValues.Add(propValue);
- }
- else
- {
- readOnlyProps.Add(pi);
- readOnlyValues.Add(pi.GetValue(sourceAttribute, null));
- }
- }
- }
-
- if (readOnlyProps.Count == 1)
- {
- PropertyInfo pi = readOnlyProps[0] as PropertyInfo;
- ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType });
- if (ciTemp != null)
- {
- ci = ciTemp;
- ctorArgs = new object[1] { readOnlyValues[0] };
- }
- else
- {
- ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() });
- if (ciTemp != null)
- {
- ci = ciTemp;
- ctorArgs = new object[1] { readOnlyValues[0] };
- }
- }
- }
-
- PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count];
- getSetProps.CopyTo(propertyInfos, 0);
-
- object[] propertyValues = new object[getSetValues.Count];
- getSetValues.CopyTo(propertyValues, 0);
-
- return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues);
- }
- else
- {
- return new CustomAttributeBuilder(ci, ctorArgs);
- }
- }
-
- ///
- /// Creates a .
- ///
- ///
- /// The desired .
- ///
- ///
- /// Source attribute to copy properties from (may be ).
- ///
- /// A custom attribute builder.
- public static CustomAttributeBuilder CreateCustomAttribute(
- Type type, Attribute sourceAttribute)
- {
- return CreateCustomAttribute(type, new object[] { }, sourceAttribute);
- }
-
- ///
- /// Creates a .
- ///
- ///
- /// The source attribute to copy properties from.
- ///
- /// A custom attribute builder.
- ///
- /// If the supplied is
- /// .
- ///
- public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute)
- {
- return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute);
- }
-
- ///
- /// Creates a .
- ///
- ///
- /// The desired .
- ///
- /// A custom attribute builder.
- public static CustomAttributeBuilder CreateCustomAttribute(Type type)
- {
- return CreateCustomAttribute(type, new object[] { }, null);
- }
-
- ///
- /// Creates a .
- ///
- ///
- /// The desired .
- ///
- ///
- /// Any constructor arguments for the attribute (may be
- /// in the case of no arguments).
- ///
- /// A custom attribute builder.
- public static CustomAttributeBuilder CreateCustomAttribute(
- Type type, params object[] ctorArgs)
- {
- return CreateCustomAttribute(type, ctorArgs, null);
- }
-
-#if NET_2_0
- ///
- /// Creates a .
- ///
- ///
- /// The to create
- /// the custom attribute builder from.
- ///
- /// A custom attribute builder.
- public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData)
- {
- object[] parameterValues = new object[attributeData.ConstructorArguments.Count];
- Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count];
-
- IList namedParameterValues = new ArrayList();
- IList namedFieldValues = new ArrayList();
-
- // Fill arrays of the constructor parameters
- for (int i = 0; i < attributeData.ConstructorArguments.Count; i++)
- {
- parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType;
- parameterValues[i] = ConvertValueIfNecessary(attributeData.ConstructorArguments[i].Value);
- }
-
- Type attributeType = attributeData.Constructor.DeclaringType;
- PropertyInfo[] attributeProperties = attributeType.GetProperties(
- BindingFlags.Instance | BindingFlags.Public);
- FieldInfo[] attributeFields = attributeType.GetFields(
- BindingFlags.Instance | BindingFlags.Public);
-
- // Not using generics bellow as probably Spring.NET tries to keep
- // it on .NET1 compatibility level right now I believe (SD)
- // In case of using List the above note makes
- // no sense (SD:)
- IList propertiesToSet = new ArrayList();
- int k = 0;
-
- IList fieldsToSet = new ArrayList();
- int n = 0;
-
-
- // Fills arrays of the constructor named parameters
- foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments)
- {
- bool noMatchingProperty = false;
-
- // Now iterate through all of the PropertyInfo, find the
- // one with the corresponding to the NamedProperty name
- // and add it to the array of properties to set.
- for (int j = 0; j < attributeProperties.Length; j++)
- {
- if (attributeProperties[j].Name == namedArgument.MemberInfo.Name)
- {
- propertiesToSet.Add(attributeProperties[j]);
- namedParameterValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value));
- break;
- }
- else
- {
- if (j == attributeProperties.Length - 1)
- {
- // In case of no match, throw
- noMatchingProperty = true;
- /*
- throw new InvalidOperationException(
- String.Format(CultureInfo.InvariantCulture,
- "The property with name {0} can't be found in the " +
- "type {1}, but is present as a named property " +
- "on the attributeData {2}", namedArgument.MemberInfo.Name,
- attributeType.FullName, attributeData));
- */
- }
- }
- }
- if (noMatchingProperty)
- {
- for (int j = 0; j < attributeFields.Length; j++)
- {
- if (attributeFields[j].Name == namedArgument.MemberInfo.Name)
- {
- fieldsToSet.Add(attributeFields[j]);
- namedFieldValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value));
- break;
- }
- else
- {
- if (j == attributeFields.Length - 1)
- {
- throw new InvalidOperationException(
- String.Format(CultureInfo.InvariantCulture,
- "A property or public field with name {0} can't be found in the " +
- "type {1}, but is present as a named property " +
- "on the attributeData {2}", namedArgument.MemberInfo.Name,
- attributeType.FullName, attributeData));
- }
- }
- }
- }
- }
- // Get constructor corresponding to the parameters and their types
- ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes);
-
- PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count];
- propertiesToSet.CopyTo(namedProperties, 0);
-
- object[] propertyValues = new object[namedParameterValues.Count];
- namedParameterValues.CopyTo(propertyValues, 0);
-
- if (fieldsToSet.Count == 0)
- {
- return new CustomAttributeBuilder(
- constructor, parameterValues, namedProperties, propertyValues);
- }
- else
- {
- FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count];
- fieldsToSet.CopyTo(namedFields, 0);
-
- object[] fieldValues = new object[namedFieldValues.Count];
- namedFieldValues.CopyTo(fieldValues, 0);
-
- return new CustomAttributeBuilder(
- constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues);
- }
-
-
-
- }
-
- private static object ConvertValueIfNecessary(object value)
- {
- if (value == null) return value;
-
- // We are only hunting for the case of the ReadOnlyCollection here.
- ReadOnlyCollection sourceArray =
- value as ReadOnlyCollection;
-
- if (sourceArray == null) return value;
-
- Type underlyingType = null; // type to be used for arguments
- Array returnArray = null;
- for (int i = 0; i < sourceArray.Count; i++)
- {
- if (underlyingType == null)
- {
- underlyingType = sourceArray[i].ArgumentType;
- returnArray = Array.CreateInstance(underlyingType, sourceArray.Count);
- }
- if (!underlyingType.Equals(sourceArray[i].ArgumentType))
- {
- throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
- "Types for the same named parameter of array type are expected to be same"));
- }
-
- returnArray.SetValue(sourceArray[i].Value, i);
- }
-
- return returnArray;
-
- }
-#endif
-
- ///
- /// Tries to find matching methods in the specified
- /// for each method in the supplied list.
- ///
- ///
- /// The to look for matching methods in.
- ///
- /// The methods to match.
- ///
- /// A flag that specifies whether to throw an exception if a matching
- /// method is not found.
- ///
- /// A list of the matched methods.
- ///
- /// If either of the or
- /// parameters are .
- ///
- public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict)
- {
- AssertUtils.ArgumentNotNull(type, "type");
- AssertUtils.ArgumentNotNull(methods, "methods");
-
- BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
-
- MethodInfo[] matched = new MethodInfo[methods.Length];
- for (int i = 0; i < methods.Length; i++)
- {
- MethodInfo method = methods[i];
- MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null);
- if ((match == null || match.ReturnType != method.ReturnType) && strict)
- {
- throw new Exception(
- string.Format("Method '{0}' could not be matched in the target class [{1}].",
- method.Name, type.FullName));
- }
- matched[i] = match;
- }
- return matched;
- }
-
- ///
- /// Returns the of the supplied
- /// .
- ///
- ///
- ///
- /// If the is a
- /// instance, the return value of this method call with be the
- /// parameter cast to a
- /// . If the is
- /// anything other than a , the return value
- /// will be the result of invoking the 's
- /// method.
- ///
+ /// Follows the standard .NET conventions for default values where
+ /// relevant; for example, all numeric types default to the value
+ /// 0.
+ ///
+ ///
+ ///
+ /// The to return default value for.
+ ///
+ ///
+ /// The default value for the specified .
+ ///
+ ///
+ /// If the supplied is an enumerated type that
+ /// has no values.
+ ///
+ public static object GetDefaultValue(Type type)
+ {
+ if (!type.IsValueType)
+ {
+ return null;
+ }
+ if (type == typeof(Boolean))
+ {
+ return false;
+ }
+ if (type == typeof(DateTime))
+ {
+ return DateTime.MinValue;
+ }
+ if (type == typeof(Char))
+ {
+ return Char.MinValue;
+ }
+ if (type.IsEnum)
+ {
+ Array values = Enum.GetValues(type);
+ if (values == null || values.Length == 0)
+ {
+ throw new ArgumentException("Bad 'enum' Type : cannot get default value because 'enum' has no values.");
+ }
+ return values.GetValue(0);
+ }
+ return 0;
+ }
+
+ ///
+ /// Returns an array consisting of the default values for the supplied
+ /// .
+ ///
+ ///
+ /// The array of s to return default values for.
+ ///
+ ///
+ /// An array consisting of the default values for the supplied
+ /// .
+ ///
+ ///
+ /// If any of the elements in the supplied
+ /// array is an enumerated type that has no values.
+ ///
+ ///
+ public static object[] GetDefaultValues(Type[] types)
+ {
+ object[] defaults = new object[types.Length];
+ for (int i = 0; i < types.Length; ++i)
+ {
+ defaults[i] = GetDefaultValue(types[i]);
+ }
+ return defaults;
+ }
+
+ ///
+ /// Checks that the parameter s of the
+ /// supplied match the parameter
+ /// s of the supplied
+ /// .
+ ///
+ /// The method to be checked.
+ ///
+ /// The array of parameter s to check against.
+ ///
+ ///
+ /// if the parameter s
+ /// match.
+ ///
+ public static bool ParameterTypesMatch(
+ MethodInfo candidate, Type[] parameterTypes)
+ {
+ #region Sanity Checks
+
+ AssertUtils.ArgumentNotNull(candidate, "candidate");
+ AssertUtils.ArgumentNotNull(parameterTypes, "parameterTypes");
+
+ #endregion
+
+ Type[] candidatesParameterTypes
+ = ReflectionUtils.GetParameterTypes(candidate);
+ if (candidatesParameterTypes.Length != parameterTypes.Length)
+ {
+ return false;
+ }
+ for (int i = 0; i < candidatesParameterTypes.Length; ++i)
+ {
+ if (!candidatesParameterTypes[i].Equals(parameterTypes[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Returns an array containing the s of the
+ /// objects in the supplied array.
+ ///
+ ///
+ /// The objects array for which the corresponding s
+ /// are needed.
+ ///
+ ///
+ /// An array containing the s of the objects
+ /// in the supplied array; this array will be empty (but not
+ /// if the supplied
+ /// is null or has no elements.
+ ///
+ ///
+ ///
+ /// [C#]
+ /// Given an array containing the following objects,
+ /// [83, "Foo", new object ()], the
+ /// array returned from this method call would consist of the following
+ /// elements...
+ /// [Int32, String, Object].
+ ///
+ ///
+ public static Type[] GetTypes(object[] args)
+ {
+ if (args == null || args.Length == 0)
+ {
+ return Type.EmptyTypes;
+ }
+ Type[] paramsType = new Type[args.Length];
+ for (int i = 0; i < args.Length; ++i)
+ {
+ object arg = args[i];
+ paramsType[i] = (arg != null) ? args[i].GetType() : typeof(object);
+ }
+ return paramsType;
+ }
+
+ ///
+ /// Does the given and/or it's superclasses
+ /// have at least one or more methods with the given name (with any
+ /// argument types)?
+ ///
+ ///
+ ///
+ /// Includes non-public methods in the methods searched.
+ ///
+ ///
+ ///
+ /// The to be checked.
+ ///
+ ///
+ /// The name of the method to be searched for. Case inSenSItivE.
+ ///
+ ///
+ /// if the given or / and it's
+ /// superclasses have at least one or more methods (with any argument types);
+ /// if not, or either of the parameters is .
+ ///
+ public static bool HasAtLeastOneMethodWithName(Type type, string name)
+ {
+ if (type == null || StringUtils.IsNullOrEmpty(name))
+ {
+ return false;
+ }
+ return MethodCountForName(type, name) > 0;
+ }
+
+ ///
+ /// Within , counts the number of overloads for the method with the given (case-insensitive!)
+ ///
+ /// The type to be searched
+ /// the name of the method for which overloads shall be counted
+ /// The number of overloads for method within type
+ public static int MethodCountForName(Type type, string name)
+ {
+ AssertUtils.ArgumentNotNull(type, "type", "Type must not be null");
+ AssertUtils.ArgumentNotNull(name, "name", "Method name must not be null");
+ MemberInfo[] methods = type.FindMembers(
+ MemberTypes.Method,
+ ReflectionUtils.AllMembersCaseInsensitiveFlags,
+ new MemberFilter(ReflectionUtils.MethodNameFilter),
+ name);
+ return methods.Length;
+ }
+
+ private static bool MethodNameFilter(MemberInfo member, object criteria)
+ {
+ MethodInfo method = member as MethodInfo;
+ string name = criteria as string;
+ return String.Compare(method.Name, name, true, CultureInfo.InvariantCulture) == 0;
+ }
+
+ ///
+ /// Creates a .
+ ///
+ ///
+ ///
+ /// Note that if a non-
+ /// is supplied, any read write properties exposed by the
+ /// will be used to overwrite values that may have been passed in via the
+ /// . That is, the will be used
+ /// to initialize the custom attribute, and then any read-write properties on the
+ /// will be plugged in.
+ ///
+ ///
+ ///
+ /// The desired .
+ ///
+ ///
+ /// Any constructor arguments for the attribute (may be
+ /// in the case of no arguments).
+ ///
+ ///
+ /// Source attribute to copy properties from (may be ).
+ ///
+ /// A custom attribute builder.
+ ///
+ /// If the parameter is .
+ ///
+ ///
+ /// If the parameter is not a
+ /// that derives from the class.
+ ///
+ ///
+ public static CustomAttributeBuilder CreateCustomAttribute(
+ Type type, object[] ctorArgs, Attribute sourceAttribute)
+ {
+ #region Sanity Checks
+
+ AssertUtils.ArgumentNotNull(type, "type");
+ if (!typeof(Attribute).IsAssignableFrom(type))
+ {
+ throw new ArgumentException(
+ string.Format("[{0}] does not derive from the [System.Attribute] class.",
+ type.FullName));
+ }
+
+ #endregion
+
+ ConstructorInfo ci = type.GetConstructor(ReflectionUtils.GetTypes(ctorArgs));
+ if (ci == null && ctorArgs.Length == 0)
+ {
+ ci = type.GetConstructors()[0];
+ ctorArgs = GetDefaultValues(GetParameterTypes(ci.GetParameters()));
+ }
+
+ if (sourceAttribute != null)
+ {
+ object defaultAttribute = null;
+ try
+ {
+ defaultAttribute = ci.Invoke(ctorArgs);
+ }
+ catch
+ {
+ }
+
+ IList getSetProps = new ArrayList();
+ IList getSetValues = new ArrayList();
+ IList readOnlyProps = new ArrayList();
+ IList readOnlyValues = new ArrayList();
+ foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
+ {
+ if (pi.DeclaringType == typeof(Attribute))
+ continue;
+
+ if (pi.CanRead)
+ {
+ if (pi.CanWrite)
+ {
+ object propValue = pi.GetValue(sourceAttribute, null);
+ if (defaultAttribute != null)
+ {
+ object defaultValue = pi.GetValue(defaultAttribute, null);
+ if ((propValue == null && defaultValue == null) ||
+ (propValue != null && propValue.Equals(defaultValue)))
+ continue;
+ }
+ getSetProps.Add(pi);
+ getSetValues.Add(propValue);
+ }
+ else
+ {
+ readOnlyProps.Add(pi);
+ readOnlyValues.Add(pi.GetValue(sourceAttribute, null));
+ }
+ }
+ }
+
+ if (readOnlyProps.Count == 1)
+ {
+ PropertyInfo pi = readOnlyProps[0] as PropertyInfo;
+ ConstructorInfo ciTemp = type.GetConstructor(new Type[1] { pi.PropertyType });
+ if (ciTemp != null)
+ {
+ ci = ciTemp;
+ ctorArgs = new object[1] { readOnlyValues[0] };
+ }
+ else
+ {
+ ciTemp = type.GetConstructor(new Type[1] { readOnlyValues[0].GetType() });
+ if (ciTemp != null)
+ {
+ ci = ciTemp;
+ ctorArgs = new object[1] { readOnlyValues[0] };
+ }
+ }
+ }
+
+ PropertyInfo[] propertyInfos = new PropertyInfo[getSetProps.Count];
+ getSetProps.CopyTo(propertyInfos, 0);
+
+ object[] propertyValues = new object[getSetValues.Count];
+ getSetValues.CopyTo(propertyValues, 0);
+
+ return new CustomAttributeBuilder(ci, ctorArgs, propertyInfos, propertyValues);
+ }
+ else
+ {
+ return new CustomAttributeBuilder(ci, ctorArgs);
+ }
+ }
+
+ ///
+ /// Creates a .
+ ///
+ ///
+ /// The desired .
+ ///
+ ///
+ /// Source attribute to copy properties from (may be ).
+ ///
+ /// A custom attribute builder.
+ public static CustomAttributeBuilder CreateCustomAttribute(
+ Type type, Attribute sourceAttribute)
+ {
+ return CreateCustomAttribute(type, new object[] { }, sourceAttribute);
+ }
+
+ ///
+ /// Creates a .
+ ///
+ ///
+ /// The source attribute to copy properties from.
+ ///
+ /// A custom attribute builder.
+ ///
+ /// If the supplied is
+ /// .
+ ///
+ public static CustomAttributeBuilder CreateCustomAttribute(Attribute sourceAttribute)
+ {
+ return CreateCustomAttribute(sourceAttribute.GetType(), sourceAttribute);
+ }
+
+ ///
+ /// Creates a .
+ ///
+ ///
+ /// The desired .
+ ///
+ /// A custom attribute builder.
+ public static CustomAttributeBuilder CreateCustomAttribute(Type type)
+ {
+ return CreateCustomAttribute(type, new object[] { }, null);
+ }
+
+ ///
+ /// Creates a .
+ ///
+ ///
+ /// The desired .
+ ///
+ ///
+ /// Any constructor arguments for the attribute (may be
+ /// in the case of no arguments).
+ ///
+ /// A custom attribute builder.
+ public static CustomAttributeBuilder CreateCustomAttribute(
+ Type type, params object[] ctorArgs)
+ {
+ return CreateCustomAttribute(type, ctorArgs, null);
+ }
+
+#if NET_2_0
+ ///
+ /// Creates a .
+ ///
+ ///
+ /// The to create
+ /// the custom attribute builder from.
+ ///
+ /// A custom attribute builder.
+ public static CustomAttributeBuilder CreateCustomAttribute(CustomAttributeData attributeData)
+ {
+ object[] parameterValues = new object[attributeData.ConstructorArguments.Count];
+ Type[] parameterTypes = new Type[attributeData.ConstructorArguments.Count];
+
+ IList namedParameterValues = new ArrayList();
+ IList namedFieldValues = new ArrayList();
+
+ // Fill arrays of the constructor parameters
+ for (int i = 0; i < attributeData.ConstructorArguments.Count; i++)
+ {
+ parameterTypes[i] = attributeData.ConstructorArguments[i].ArgumentType;
+ parameterValues[i] = ConvertValueIfNecessary(attributeData.ConstructorArguments[i].Value);
+ }
+
+ Type attributeType = attributeData.Constructor.DeclaringType;
+ PropertyInfo[] attributeProperties = attributeType.GetProperties(
+ BindingFlags.Instance | BindingFlags.Public);
+ FieldInfo[] attributeFields = attributeType.GetFields(
+ BindingFlags.Instance | BindingFlags.Public);
+
+ // Not using generics bellow as probably Spring.NET tries to keep
+ // it on .NET1 compatibility level right now I believe (SD)
+ // In case of using List the above note makes
+ // no sense (SD:)
+ IList propertiesToSet = new ArrayList();
+ int k = 0;
+
+ IList fieldsToSet = new ArrayList();
+ int n = 0;
+
+
+ // Fills arrays of the constructor named parameters
+ foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments)
+ {
+ bool noMatchingProperty = false;
+
+ // Now iterate through all of the PropertyInfo, find the
+ // one with the corresponding to the NamedProperty name
+ // and add it to the array of properties to set.
+ for (int j = 0; j < attributeProperties.Length; j++)
+ {
+ if (attributeProperties[j].Name == namedArgument.MemberInfo.Name)
+ {
+ propertiesToSet.Add(attributeProperties[j]);
+ namedParameterValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value));
+ break;
+ }
+ else
+ {
+ if (j == attributeProperties.Length - 1)
+ {
+ // In case of no match, throw
+ noMatchingProperty = true;
+ /*
+ throw new InvalidOperationException(
+ String.Format(CultureInfo.InvariantCulture,
+ "The property with name {0} can't be found in the " +
+ "type {1}, but is present as a named property " +
+ "on the attributeData {2}", namedArgument.MemberInfo.Name,
+ attributeType.FullName, attributeData));
+ */
+ }
+ }
+ }
+ if (noMatchingProperty)
+ {
+ for (int j = 0; j < attributeFields.Length; j++)
+ {
+ if (attributeFields[j].Name == namedArgument.MemberInfo.Name)
+ {
+ fieldsToSet.Add(attributeFields[j]);
+ namedFieldValues.Add(ConvertValueIfNecessary(namedArgument.TypedValue.Value));
+ break;
+ }
+ else
+ {
+ if (j == attributeFields.Length - 1)
+ {
+ throw new InvalidOperationException(
+ String.Format(CultureInfo.InvariantCulture,
+ "A property or public field with name {0} can't be found in the " +
+ "type {1}, but is present as a named property " +
+ "on the attributeData {2}", namedArgument.MemberInfo.Name,
+ attributeType.FullName, attributeData));
+ }
+ }
+ }
+ }
+ }
+ // Get constructor corresponding to the parameters and their types
+ ConstructorInfo constructor = attributeType.GetConstructor(parameterTypes);
+
+ PropertyInfo[] namedProperties = new PropertyInfo[propertiesToSet.Count];
+ propertiesToSet.CopyTo(namedProperties, 0);
+
+ object[] propertyValues = new object[namedParameterValues.Count];
+ namedParameterValues.CopyTo(propertyValues, 0);
+
+ if (fieldsToSet.Count == 0)
+ {
+ return new CustomAttributeBuilder(
+ constructor, parameterValues, namedProperties, propertyValues);
+ }
+ else
+ {
+ FieldInfo[] namedFields = new FieldInfo[fieldsToSet.Count];
+ fieldsToSet.CopyTo(namedFields, 0);
+
+ object[] fieldValues = new object[namedFieldValues.Count];
+ namedFieldValues.CopyTo(fieldValues, 0);
+
+ return new CustomAttributeBuilder(
+ constructor, parameterValues, namedProperties, propertyValues, namedFields, fieldValues);
+ }
+
+
+
+ }
+
+ private static object ConvertValueIfNecessary(object value)
+ {
+ if (value == null) return value;
+
+ // We are only hunting for the case of the ReadOnlyCollection here.
+ ReadOnlyCollection sourceArray =
+ value as ReadOnlyCollection;
+
+ if (sourceArray == null) return value;
+
+ Type underlyingType = null; // type to be used for arguments
+ Array returnArray = null;
+ for (int i = 0; i < sourceArray.Count; i++)
+ {
+ if (underlyingType == null)
+ {
+ underlyingType = sourceArray[i].ArgumentType;
+ returnArray = Array.CreateInstance(underlyingType, sourceArray.Count);
+ }
+ if (!underlyingType.Equals(sourceArray[i].ArgumentType))
+ {
+ throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
+ "Types for the same named parameter of array type are expected to be same"));
+ }
+
+ returnArray.SetValue(sourceArray[i].Value, i);
+ }
+
+ return returnArray;
+
+ }
+#endif
+
+ ///
+ /// Tries to find matching methods in the specified
+ /// for each method in the supplied list.
+ ///
+ ///
+ /// The to look for matching methods in.
+ ///
+ /// The methods to match.
+ ///
+ /// A flag that specifies whether to throw an exception if a matching
+ /// method is not found.
+ ///
+ /// A list of the matched methods.
+ ///
+ /// If either of the or
+ /// parameters are .
+ ///
+ public static MethodInfo[] GetMatchingMethods(Type type, MethodInfo[] methods, bool strict)
+ {
+ AssertUtils.ArgumentNotNull(type, "type");
+ AssertUtils.ArgumentNotNull(methods, "methods");
+
+ BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
+
+ MethodInfo[] matched = new MethodInfo[methods.Length];
+ for (int i = 0; i < methods.Length; i++)
+ {
+ MethodInfo method = methods[i];
+ MethodInfo match = type.GetMethod(method.Name, flags, null, ReflectionUtils.GetParameterTypes(method), null);
+ if ((match == null || match.ReturnType != method.ReturnType) && strict)
+ {
+ throw new Exception(
+ string.Format("Method '{0}' could not be matched in the target class [{1}].",
+ method.Name, type.FullName));
+ }
+ matched[i] = match;
+ }
+ return matched;
+ }
+
+ ///
+ /// Returns the of the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// If the is a
+ /// instance, the return value of this method call with be the
+ /// parameter cast to a
+ /// . If the is
+ /// anything other than a , the return value
+ /// will be the result of invoking the 's
+ /// method.
+ ///
- /// Mainly for internal use within the framework.
- ///
- ///
- /// Rod Johnson
- /// Juergen Hoeller
- /// Keith Donald
- /// Aleksandar Seovic (.NET)
- /// Mark Pollack (.NET)
- /// Rick Evans (.NET)
- /// $Id: StringUtils.cs,v 1.29 2006/04/09 07:19:00 markpollack Exp $
- public sealed class StringUtils
- {
- ///
- /// An empty array of instances.
- ///
- public static readonly string[] EmptyStrings = new string[] {};
-
- ///
- /// The string that signals the start of an Ant-style expression.
- ///
- private const string AntExpressionPrefix = "${";
-
- ///
- /// The string that signals the end of an Ant-style expression.
- ///
- private const string AntExpressionSuffix = "}";
-
- #region Constructor (s) / Destructor
-
- // CLOVER:OFF
-
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- /// This is a utility class, and as such exposes no public constructors.
- ///
- ///
- private StringUtils()
- {
- }
-
- // CLOVER:ON
-
- #endregion
-
- ///
- /// Tokenize the given into a
- /// array.
- ///
- ///
- ///
- /// If is , returns an empty
- /// array.
- ///
- ///
- /// If is or the empty
- /// , returns a array with one
- /// element: itself.
- ///
- ///
- /// The to tokenize.
- ///
- /// The delimiter characters, assembled as a .
- ///
- ///
- /// Trim the tokens via .
- ///
- ///
- /// Omit empty tokens from the result array.
- /// An array of the tokens.
- public static string[] Split(
- string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens)
- {
- if (s == null)
- {
- return new string[0];
- }
- if (StringUtils.IsNullOrEmpty(delimiters))
- {
- return new string[] {s};
- }
- string[] tmp = s.Split(delimiters.ToCharArray());
- // short circuit if String.Split default behavior is ok
- if (!trimTokens && !ignoreEmptyTokens)
- {
- return tmp;
- }
- else
- {
- ArrayList tokens = new ArrayList(tmp.Length);
- for (int i = 0; i < tmp.Length; ++i)
- {
- string token = (trimTokens ? tmp[i].Trim() : tmp[i]);
- if (!(ignoreEmptyTokens && token.Length == 0))
- {
- tokens.Add(token);
- }
- }
- return (string[]) tokens.ToArray(typeof (string));
- }
- }
-
- ///
- /// Convert a CSV list into an array of s.
- ///
- /// A CSV list.
- ///
- /// An array of s, or the empty array
- /// if is .
- ///
- public static string[] CommaDelimitedListToStringArray(string s)
- {
- return DelimitedListToStringArray(s, ",");
- }
-
- ///
- /// Take a which is a delimited list
- /// and convert it to a array.
- ///
- ///
- ///
- /// If the supplied is a
- /// or zero-length string, then a single element
- /// array composed of the supplied
- /// will be
- /// eturned. If the supplied
- /// is , then an empty,
- /// zero-length array will be returned.
- ///
- ///
- ///
- /// The to be parsed.
- ///
- ///
- /// The delimeter (this will not be returned). Note that only the first
- /// character of the supplied is used.
- ///
- ///
- /// An array of the tokens in the list.
- ///
- public static string[] DelimitedListToStringArray(string input, string delimiter)
- {
- if (input == null)
- {
- return new string[0];
- }
- if (!HasLength(delimiter))
- {
- return new string[] {input};
- }
- return input.Split(delimiter[0]);
- }
-
- ///
- /// Convenience method to return an
- /// as a delimited
- /// (e.g. CSV) .
- ///
- ///
- /// The to parse.
- ///
- ///
- /// The delimiter to use (probably a ',').
- ///
- /// The delimited string representation.
- public static string CollectionToDelimitedString(
- ICollection c, string delimiter)
- {
- if (c == null)
- {
- return "null";
- }
- StringBuilder sb = new StringBuilder();
- int i = 0;
- foreach (object obj in c)
- {
- if (i++ > 0)
- {
- sb.Append(delimiter);
- }
- sb.Append(obj);
- }
- return sb.ToString();
- }
-
- ///
- /// Convenience method to return an
- /// as a CSV
- /// .
- ///
- ///
- /// The to display.
- ///
- /// The delimited string representation.
- public static string CollectionToCommaDelimitedString(
- ICollection collection)
- {
- return CollectionToDelimitedString(collection, ",");
- }
-
- ///
- /// Convenience method to return an array as a CSV
- /// .
- ///
- ///
- /// The array to parse. Elements may be of any type (
- /// will be called on each
- /// element).
- ///
- public static string ArrayToCommaDelimitedString(object[] source)
- {
- return ArrayToDelimitedString(source, ",");
- }
-
- ///
- /// Convenience method to return a
- /// array as a delimited (e.g. CSV) .
- ///
- ///
- /// The array to parse. Elements may be of any type (
- /// will be called on each
- /// element).
- ///
- ///
- /// The delimiter to use (probably a ',').
- ///
- public static string ArrayToDelimitedString(
- object[] source, string delimiter)
- {
- if (source == null)
- {
- return "null";
- }
- else
- {
- return StringUtils.CollectionToDelimitedString(source, delimiter);
- }
- }
-
- /// Checks if a string has length.
- ///
- /// The string to check, may be .
- ///
- ///
- /// if the string has length and is not
- /// .
- ///
- ///
- ///
- /// StringUtils.HasLength(null) = false
- /// StringUtils.HasLength("") = false
- /// StringUtils.HasLength(" ") = true
- /// StringUtils.HasLength("Hello") = true
- ///
- ///
- public static bool HasLength(string target)
- {
- return (target != null && target.Length > 0);
- }
-
- ///
- /// Checks if a has text.
- ///
- ///
- ///
- /// More specifically, returns if the string is
- /// not , it's is >
- /// zero (0), and it has at least one non-whitespace character.
- ///
- ///
- ///
- /// The string to check, may be .
- ///
- ///
- /// if the is not
- /// ,
- /// > zero (0), and does not consist
- /// solely of whitespace.
- ///
- ///
- ///
- /// StringUtils.HasText(null) = false
- /// StringUtils.HasText("") = false
- /// StringUtils.HasText(" ") = false
- /// StringUtils.HasText("12345") = true
- /// StringUtils.HasText(" 12345 ") = true
- ///
- ///
- public static bool HasText(string target)
- {
- if (target == null)
- {
- return false;
- }
- else
- {
- return HasLength(target.Trim());
- }
- }
-
- ///
- /// Checks if a is
- /// or an empty string.
- ///
- ///
- ///
- /// More specifically, returns if the string is
- /// , it's is equal
- /// to zero (0), or it is composed entirely of whitespace
- /// characters.
- ///
- ///
- ///
- /// The string to check, may (obviously) be .
- ///
- ///
- /// if the is
- /// , has a length equal to zero (0), or
- /// is composed entirely of whitespace characters.
- ///
- ///
- ///
- /// StringUtils.IsNullOrEmpty(null) = true
- /// StringUtils.IsNullOrEmpty("") = true
- /// StringUtils.IsNullOrEmpty(" ") = true
- /// StringUtils.IsNullOrEmpty("12345") = false
- /// StringUtils.IsNullOrEmpty(" 12345 ") = false
- ///
- ///
- public static bool IsNullOrEmpty(string target)
- {
- return !HasText(target);
- }
-
- ///
- /// Strips first and last character off the string.
- ///
- /// The string to strip.
- /// The stripped string.
- public static string StripFirstAndLastCharacter(string text)
- {
- if (text != null
- && text.Length > 2)
- {
- return text.Substring(1, text.Length - 2);
- }
- else
- {
- return String.Empty;
- }
- }
-
- ///
- /// Returns a list of Ant-style expressions from the specified text.
- ///
- /// The text to inspect.
- ///
- /// A list of expressions that exist in the specified text.
- ///
- ///
- /// If any of the expressions in the supplied
- /// is empty (${}).
- ///
- public static IList GetAntExpressions(string text)
- {
- IList expressions = new ArrayList();
- if (StringUtils.HasText(text))
- {
- int start = text.IndexOf(AntExpressionPrefix);
- while (start >= 0)
- {
- int end = text.IndexOf(AntExpressionSuffix, start + 2);
- if (end == -1)
- {
- // terminator character not found, so let's quit...
- start = -1;
- }
- else
- {
- string exp = text.Substring(start + 2, end - start - 2);
- if(StringUtils.IsNullOrEmpty(exp))
- {
- throw new FormatException(
- string.Format("Empty {0}{1} value found in text : '{2}'.",
- AntExpressionPrefix,
- AntExpressionSuffix,
- text));
- }
- if (expressions.IndexOf(exp) < 0)
- {
- expressions.Add(exp);
- }
- start = text.IndexOf(AntExpressionPrefix, end);
- }
- }
- }
- return expressions;
- }
-
- ///
- /// Replaces Ant-style expression placeholder with expression value.
- ///
- ///
- ///
- ///
- ///
- ///
- /// The string to set the value in.
- /// The name of the expression to set.
- /// The expression value.
- ///
- /// A new string with the expression value set; the
- /// value if the supplied
- /// is , has a length
- /// equal to zero (0), or is composed entirely of whitespace
- /// characters.
- ///
- public static string SetAntExpression(string text, string expression, object expValue)
- {
- if (StringUtils.IsNullOrEmpty(text))
- {
- return String.Empty;
- }
- if (expValue == null)
- {
- expValue = String.Empty;
- }
- return text.Replace(
- StringUtils.Surround(AntExpressionPrefix, expression, AntExpressionSuffix), expValue.ToString());
- }
-
- ///
- /// Surrounds (prepends and appends) the string value of the supplied
- /// to the supplied .
- ///
- ///
- ///
- /// The return value of this method call is always guaranteed to be non
- /// . If every value passed as a parameter to this method is
- /// , the string will be returned.
- ///
- ///
- ///
- /// The prefix and suffix that respectively will be prepended and
- /// appended to the target . If this value
- /// is not a value, it's attendant
- /// value will be used.
- ///
- ///
- /// The target that is to be surrounded. If this value is not a
- /// value, it's attendant
- /// value will be used.
- ///
- /// The surrounded string.
- public static string Surround(object fix, object target)
- {
- return StringUtils.Surround(fix, target, fix);
- }
-
- ///
- /// Surrounds (prepends and appends) the string values of the supplied
- /// and to the supplied
- /// .
- ///
- ///
- ///
- /// The return value of this method call is always guaranteed to be non
- /// . If every value passed as a parameter to this method is
- /// , the string will be returned.
- ///
+ /// Mainly for internal use within the framework.
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Keith Donald
+ /// Aleksandar Seovic (.NET)
+ /// Mark Pollack (.NET)
+ /// Rick Evans (.NET)
+ public sealed class StringUtils
+ {
+ ///
+ /// An empty array of instances.
+ ///
+ public static readonly string[] EmptyStrings = new string[] {};
+
+ ///
+ /// The string that signals the start of an Ant-style expression.
+ ///
+ private const string AntExpressionPrefix = "${";
+
+ ///
+ /// The string that signals the end of an Ant-style expression.
+ ///
+ private const string AntExpressionSuffix = "}";
+
+ #region Constructor (s) / Destructor
+
+ // CLOVER:OFF
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ ///
+ ///
+ /// This is a utility class, and as such exposes no public constructors.
+ ///
+ ///
+ private StringUtils()
+ {
+ }
+
+ // CLOVER:ON
+
+ #endregion
+
+ ///
+ /// Tokenize the given into a
+ /// array.
+ ///
+ ///
+ ///
+ /// If is , returns an empty
+ /// array.
+ ///
+ ///
+ /// If is or the empty
+ /// , returns a array with one
+ /// element: itself.
+ ///
+ ///
+ /// The to tokenize.
+ ///
+ /// The delimiter characters, assembled as a .
+ ///
+ ///
+ /// Trim the tokens via .
+ ///
+ ///
+ /// Omit empty tokens from the result array.
+ /// An array of the tokens.
+ public static string[] Split(
+ string s, string delimiters, bool trimTokens, bool ignoreEmptyTokens)
+ {
+ if (s == null)
+ {
+ return new string[0];
+ }
+ if (StringUtils.IsNullOrEmpty(delimiters))
+ {
+ return new string[] {s};
+ }
+ string[] tmp = s.Split(delimiters.ToCharArray());
+ // short circuit if String.Split default behavior is ok
+ if (!trimTokens && !ignoreEmptyTokens)
+ {
+ return tmp;
+ }
+ else
+ {
+ ArrayList tokens = new ArrayList(tmp.Length);
+ for (int i = 0; i < tmp.Length; ++i)
+ {
+ string token = (trimTokens ? tmp[i].Trim() : tmp[i]);
+ if (!(ignoreEmptyTokens && token.Length == 0))
+ {
+ tokens.Add(token);
+ }
+ }
+ return (string[]) tokens.ToArray(typeof (string));
+ }
+ }
+
+ ///
+ /// Convert a CSV list into an array of s.
+ ///
+ /// A CSV list.
+ ///
+ /// An array of s, or the empty array
+ /// if is .
+ ///
+ public static string[] CommaDelimitedListToStringArray(string s)
+ {
+ return DelimitedListToStringArray(s, ",");
+ }
+
+ ///
+ /// Take a which is a delimited list
+ /// and convert it to a array.
+ ///
+ ///
+ ///
+ /// If the supplied is a
+ /// or zero-length string, then a single element
+ /// array composed of the supplied
+ /// will be
+ /// eturned. If the supplied
+ /// is , then an empty,
+ /// zero-length array will be returned.
+ ///
+ ///
+ ///
+ /// The to be parsed.
+ ///
+ ///
+ /// The delimeter (this will not be returned). Note that only the first
+ /// character of the supplied is used.
+ ///
+ ///
+ /// An array of the tokens in the list.
+ ///
+ public static string[] DelimitedListToStringArray(string input, string delimiter)
+ {
+ if (input == null)
+ {
+ return new string[0];
+ }
+ if (!HasLength(delimiter))
+ {
+ return new string[] {input};
+ }
+ return input.Split(delimiter[0]);
+ }
+
+ ///
+ /// Convenience method to return an
+ /// as a delimited
+ /// (e.g. CSV) .
+ ///
+ ///
+ /// The to parse.
+ ///
+ ///
+ /// The delimiter to use (probably a ',').
+ ///
+ /// The delimited string representation.
+ public static string CollectionToDelimitedString(
+ ICollection c, string delimiter)
+ {
+ if (c == null)
+ {
+ return "null";
+ }
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ foreach (object obj in c)
+ {
+ if (i++ > 0)
+ {
+ sb.Append(delimiter);
+ }
+ sb.Append(obj);
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// Convenience method to return an
+ /// as a CSV
+ /// .
+ ///
+ ///
+ /// The to display.
+ ///
+ /// The delimited string representation.
+ public static string CollectionToCommaDelimitedString(
+ ICollection collection)
+ {
+ return CollectionToDelimitedString(collection, ",");
+ }
+
+ ///
+ /// Convenience method to return an array as a CSV
+ /// .
+ ///
+ ///
+ /// The array to parse. Elements may be of any type (
+ /// will be called on each
+ /// element).
+ ///
+ public static string ArrayToCommaDelimitedString(object[] source)
+ {
+ return ArrayToDelimitedString(source, ",");
+ }
+
+ ///
+ /// Convenience method to return a
+ /// array as a delimited (e.g. CSV) .
+ ///
+ ///
+ /// The array to parse. Elements may be of any type (
+ /// will be called on each
+ /// element).
+ ///
+ ///
+ /// The delimiter to use (probably a ',').
+ ///
+ public static string ArrayToDelimitedString(
+ object[] source, string delimiter)
+ {
+ if (source == null)
+ {
+ return "null";
+ }
+ else
+ {
+ return StringUtils.CollectionToDelimitedString(source, delimiter);
+ }
+ }
+
+ /// Checks if a string has length.
+ ///
+ /// The string to check, may be .
+ ///
+ ///
+ /// if the string has length and is not
+ /// .
+ ///
+ ///
+ ///
+ /// StringUtils.HasLength(null) = false
+ /// StringUtils.HasLength("") = false
+ /// StringUtils.HasLength(" ") = true
+ /// StringUtils.HasLength("Hello") = true
+ ///
+ ///
+ public static bool HasLength(string target)
+ {
+ return (target != null && target.Length > 0);
+ }
+
+ ///
+ /// Checks if a has text.
+ ///
+ ///
+ ///
+ /// More specifically, returns if the string is
+ /// not , it's is >
+ /// zero (0), and it has at least one non-whitespace character.
+ ///
+ ///
+ ///
+ /// The string to check, may be .
+ ///
+ ///
+ /// if the is not
+ /// ,
+ /// > zero (0), and does not consist
+ /// solely of whitespace.
+ ///
+ ///
+ ///
+ /// StringUtils.HasText(null) = false
+ /// StringUtils.HasText("") = false
+ /// StringUtils.HasText(" ") = false
+ /// StringUtils.HasText("12345") = true
+ /// StringUtils.HasText(" 12345 ") = true
+ ///
+ ///
+ public static bool HasText(string target)
+ {
+ if (target == null)
+ {
+ return false;
+ }
+ else
+ {
+ return HasLength(target.Trim());
+ }
+ }
+
+ ///
+ /// Checks if a is
+ /// or an empty string.
+ ///
+ ///
+ ///
+ /// More specifically, returns if the string is
+ /// , it's is equal
+ /// to zero (0), or it is composed entirely of whitespace
+ /// characters.
+ ///
+ ///
+ ///
+ /// The string to check, may (obviously) be .
+ ///
+ ///
+ /// if the is
+ /// , has a length equal to zero (0), or
+ /// is composed entirely of whitespace characters.
+ ///
+ ///
+ ///
+ /// StringUtils.IsNullOrEmpty(null) = true
+ /// StringUtils.IsNullOrEmpty("") = true
+ /// StringUtils.IsNullOrEmpty(" ") = true
+ /// StringUtils.IsNullOrEmpty("12345") = false
+ /// StringUtils.IsNullOrEmpty(" 12345 ") = false
+ ///
+ ///
+ public static bool IsNullOrEmpty(string target)
+ {
+ return !HasText(target);
+ }
+
+ ///
+ /// Strips first and last character off the string.
+ ///
+ /// The string to strip.
+ /// The stripped string.
+ public static string StripFirstAndLastCharacter(string text)
+ {
+ if (text != null
+ && text.Length > 2)
+ {
+ return text.Substring(1, text.Length - 2);
+ }
+ else
+ {
+ return String.Empty;
+ }
+ }
+
+ ///
+ /// Returns a list of Ant-style expressions from the specified text.
+ ///
+ /// The text to inspect.
+ ///
+ /// A list of expressions that exist in the specified text.
+ ///
+ ///
+ /// If any of the expressions in the supplied
+ /// is empty (${}).
+ ///
+ public static IList GetAntExpressions(string text)
+ {
+ IList expressions = new ArrayList();
+ if (StringUtils.HasText(text))
+ {
+ int start = text.IndexOf(AntExpressionPrefix);
+ while (start >= 0)
+ {
+ int end = text.IndexOf(AntExpressionSuffix, start + 2);
+ if (end == -1)
+ {
+ // terminator character not found, so let's quit...
+ start = -1;
+ }
+ else
+ {
+ string exp = text.Substring(start + 2, end - start - 2);
+ if(StringUtils.IsNullOrEmpty(exp))
+ {
+ throw new FormatException(
+ string.Format("Empty {0}{1} value found in text : '{2}'.",
+ AntExpressionPrefix,
+ AntExpressionSuffix,
+ text));
+ }
+ if (expressions.IndexOf(exp) < 0)
+ {
+ expressions.Add(exp);
+ }
+ start = text.IndexOf(AntExpressionPrefix, end);
+ }
+ }
+ }
+ return expressions;
+ }
+
+ ///
+ /// Replaces Ant-style expression placeholder with expression value.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The string to set the value in.
+ /// The name of the expression to set.
+ /// The expression value.
+ ///
+ /// A new string with the expression value set; the
+ /// value if the supplied
+ /// is , has a length
+ /// equal to zero (0), or is composed entirely of whitespace
+ /// characters.
+ ///
+ public static string SetAntExpression(string text, string expression, object expValue)
+ {
+ if (StringUtils.IsNullOrEmpty(text))
+ {
+ return String.Empty;
+ }
+ if (expValue == null)
+ {
+ expValue = String.Empty;
+ }
+ return text.Replace(
+ StringUtils.Surround(AntExpressionPrefix, expression, AntExpressionSuffix), expValue.ToString());
+ }
+
+ ///
+ /// Surrounds (prepends and appends) the string value of the supplied
+ /// to the supplied .
+ ///
+ ///
+ ///
+ /// The return value of this method call is always guaranteed to be non
+ /// . If every value passed as a parameter to this method is
+ /// , the string will be returned.
+ ///
+ ///
+ ///
+ /// The prefix and suffix that respectively will be prepended and
+ /// appended to the target . If this value
+ /// is not a value, it's attendant
+ /// value will be used.
+ ///
+ ///
+ /// The target that is to be surrounded. If this value is not a
+ /// value, it's attendant
+ /// value will be used.
+ ///
+ /// The surrounded string.
+ public static string Surround(object fix, object target)
+ {
+ return StringUtils.Surround(fix, target, fix);
+ }
+
+ ///
+ /// Surrounds (prepends and appends) the string values of the supplied
+ /// and to the supplied
+ /// .
+ ///
+ ///
+ ///
+ /// The return value of this method call is always guaranteed to be non
+ /// . If every value passed as a parameter to this method is
+ /// , the string will be returned.
+ ///
- /// Test can be any logical expression that is supported by the Spring.NET logical
- /// expression evaluation engine, and can use any variables that can be resolved
- /// by the variable resolver used by the validation engine.
- ///
+ /// Test can be any logical expression that is supported by the Spring.NET logical
+ /// expression evaluation engine, and can use any variables that can be resolved
+ /// by the variable resolver used by the validation engine.
+ ///
Not intended to be used directly. See HibernateTemplate.
- ///
- ///
- /// Mark Pollack (.NET)
- /// $Id: HibernateAccessor.cs,v 1.6 2008/01/25 15:04:39 markpollack Exp $
- public abstract class HibernateAccessor : IInitializingObject, IObjectFactoryAware
- {
-
- private Type criteriaType;
-
- #region Constants
-
- ///
- /// The instance for this class.
- ///
- private readonly ILog log = LogManager.GetLogger(typeof (HibernateAccessor));
-
- #endregion
-
- #region Constructor (s)
-
- ///
- /// Initializes a new instance of the class.
- ///
- public HibernateAccessor()
- {
-
- }
-
- #endregion
-
-
- #region Properties
-
- ///
- /// Gets or sets if a new Session should be created when no transactional Session
- /// can be found for the current thread.
- ///
- ///
- /// true if allowed to create non-transaction session;
- /// otherwise, false.
- ///
- ///
- ///
HibernateTemplate is aware of a corresponding Session bound to the
- /// current thread, for example when using HibernateTransactionManager.
- /// If allowCreate is true, a new non-transactional Session will be created
- /// if none found, which needs to be closed at the end of the operation.
- /// If false, an InvalidOperationException will get thrown in this case.
- ///
- ///
- public abstract bool AllowCreate
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets a value indicating whether to always
- /// use a new Hibernate Session for this template.
- ///
- /// true if always use new session; otherwise, false.
- ///
- ///
- /// Default is "false"; if activated, all operations on this template will
- /// work on a new NHibernate ISession even in case of a pre-bound ISession
- /// (for example, within a transaction).
- ///
- ///
Within a transaction, a new NHibernate ISession used by this template
- /// will participate in the transaction through using the same ADO.NET
- /// Connection. In such a scenario, multiple Sessions will participate
- /// in the same database transaction.
- ///
- ///
Turn this on for operations that are supposed to always execute
- /// independently, without side effects caused by a shared NHibernate ISession.
- ///
- ///
- public abstract bool AlwaysUseNewSession
- {
- get;
- set;
- }
-
- ///
- /// Set whether to expose the native Hibernate Session to IHibernateCallback
- /// code. Default is "false": a Session proxy will be returned,
- /// suppressing close calls and automatically applying
- /// query cache settings and transaction timeouts.
- ///
- /// true if expose native session; otherwise, false.
- public abstract bool ExposeNativeSession
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets the template flush mode.
- ///
- ///
- /// Default is Auto. Will get applied to any new ISession
- /// created by the template.
- ///
- /// The template flush mode.
- public abstract TemplateFlushMode TemplateFlushMode
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets the entity interceptor that allows to inspect and change
- /// property values before writing to and reading from the database.
- ///
- ///
- /// Will get applied to any new ISession created by this object.
- ///
Such an interceptor can either be set at the ISessionFactory level,
- /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on
- /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
- /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager
- /// to avoid repeated configuration and guarantee consistent behavior in transactions.
- ///
- ///
- /// The interceptor.
- public abstract IInterceptor EntityInterceptor
- {
- get;
- set;
- }
-
- ///
- /// Set the object name of a Hibernate entity interceptor that allows to inspect
- /// and change property values before writing to and reading from the database.
- ///
- ///
- /// Will get applied to any new Session created by this transaction manager.
- ///
Requires the object factory to be known, to be able to resolve the object
- /// name to an interceptor instance on session creation. Typically used for
- /// prototype interceptors, i.e. a new interceptor instance per session.
- ///
- ///
Can also be used for shared interceptor instances, but it is recommended
- /// to set the interceptor reference directly in such a scenario.
- ///
- ///
- public abstract string EntityInterceptorObjectName
- {
- set;
- }
-
- ///
- /// Gets or sets the session factory that should be used to create
- /// NHibernate ISessions.
- ///
- /// The session factory.
- public abstract ISessionFactory SessionFactory
- {
- get;
- set;
- }
-
- ///
- /// Set the object factory instance.
- ///
- public abstract IObjectFactory ObjectFactory
- {
- set;
- }
-
- ///
- /// Gets or sets a value indicating whether to
- /// cache all queries executed by this template.
- ///
- ///
- /// If this is true, all IQuery and ICriteria objects created by
- /// this template will be marked as cacheable (including all
- /// queries through find methods).
- ///
To specify the query region to be used for queries cached
- /// by this template, set the QueryCacheRegion property.
- ///
- ///
- /// true if cache queries; otherwise, false.
- public abstract bool CacheQueries
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets the name of the cache region for queries executed by this template.
- ///
- ///
- /// If this is specified, it will be applied to all IQuery and ICriteria objects
- /// created by this template (including all queries through find methods).
- ///
The cache region will not take effect unless queries created by this
- /// template are configured to be cached via the CacheQueries property.
- ///
- ///
- /// The query cache region.
- public abstract string QueryCacheRegion
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets the fetch size for this HibernateTemplate.
- ///
- /// The size of the fetch.
- /// This is important for processing
- /// large result sets: Setting this higher than the default value will increase
- /// processing speed at the cost of memory consumption; setting this lower can
- /// avoid transferring row data that will never be read by the application.
- ///
Default is 0, indicating to use the driver's default.
- ///
- public abstract int FetchSize
- {
- get;
- set;
- }
-
- ///
- /// Gets or sets the maximum number of rows for this HibernateTemplate.
- ///
- /// The max results.
- ///
- /// This is important
- /// for processing subsets of large result sets, avoiding to read and hold
- /// the entire result set in the database or in the ADO.NET driver if we're
- /// never interested in the entire result in the first place (for example,
- /// when performing searches that might return a large number of matches).
- ///
Default is 0, indicating to use the driver's default.
- ///
- public abstract int MaxResults
- {
- get;
- set;
- }
-
- ///
- /// Set the ADO.NET exception translator for this instance.
- /// Applied to System.Data.Common.DbException (or provider specific exception type
- /// in .NET 1.1) thrown by callback code, be it direct
- /// DbException or wrapped Hibernate ADOExceptions.
- ///
The default exception translator is either a ErrorCodeExceptionTranslator
- /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise
- ///
Not intended to be used directly. See HibernateTemplate.
+ ///
+ ///
+ /// Mark Pollack (.NET)
+ public abstract class HibernateAccessor : IInitializingObject, IObjectFactoryAware
+ {
+
+ private Type criteriaType;
+
+ #region Constants
+
+ ///
+ /// The instance for this class.
+ ///
+ private readonly ILog log = LogManager.GetLogger(typeof (HibernateAccessor));
+
+ #endregion
+
+ #region Constructor (s)
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HibernateAccessor()
+ {
+
+ }
+
+ #endregion
+
+
+ #region Properties
+
+ ///
+ /// Gets or sets if a new Session should be created when no transactional Session
+ /// can be found for the current thread.
+ ///
+ ///
+ /// true if allowed to create non-transaction session;
+ /// otherwise, false.
+ ///
+ ///
+ ///
HibernateTemplate is aware of a corresponding Session bound to the
+ /// current thread, for example when using HibernateTransactionManager.
+ /// If allowCreate is true, a new non-transactional Session will be created
+ /// if none found, which needs to be closed at the end of the operation.
+ /// If false, an InvalidOperationException will get thrown in this case.
+ ///
+ ///
+ public abstract bool AllowCreate
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to always
+ /// use a new Hibernate Session for this template.
+ ///
+ /// true if always use new session; otherwise, false.
+ ///
+ ///
+ /// Default is "false"; if activated, all operations on this template will
+ /// work on a new NHibernate ISession even in case of a pre-bound ISession
+ /// (for example, within a transaction).
+ ///
+ ///
Within a transaction, a new NHibernate ISession used by this template
+ /// will participate in the transaction through using the same ADO.NET
+ /// Connection. In such a scenario, multiple Sessions will participate
+ /// in the same database transaction.
+ ///
+ ///
Turn this on for operations that are supposed to always execute
+ /// independently, without side effects caused by a shared NHibernate ISession.
+ ///
+ ///
+ public abstract bool AlwaysUseNewSession
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Set whether to expose the native Hibernate Session to IHibernateCallback
+ /// code. Default is "false": a Session proxy will be returned,
+ /// suppressing close calls and automatically applying
+ /// query cache settings and transaction timeouts.
+ ///
+ /// true if expose native session; otherwise, false.
+ public abstract bool ExposeNativeSession
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the template flush mode.
+ ///
+ ///
+ /// Default is Auto. Will get applied to any new ISession
+ /// created by the template.
+ ///
+ /// The template flush mode.
+ public abstract TemplateFlushMode TemplateFlushMode
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the entity interceptor that allows to inspect and change
+ /// property values before writing to and reading from the database.
+ ///
+ ///
+ /// Will get applied to any new ISession created by this object.
+ ///
Such an interceptor can either be set at the ISessionFactory level,
+ /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on
+ /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
+ /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager
+ /// to avoid repeated configuration and guarantee consistent behavior in transactions.
+ ///
+ ///
+ /// The interceptor.
+ public abstract IInterceptor EntityInterceptor
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Set the object name of a Hibernate entity interceptor that allows to inspect
+ /// and change property values before writing to and reading from the database.
+ ///
+ ///
+ /// Will get applied to any new Session created by this transaction manager.
+ ///
Requires the object factory to be known, to be able to resolve the object
+ /// name to an interceptor instance on session creation. Typically used for
+ /// prototype interceptors, i.e. a new interceptor instance per session.
+ ///
+ ///
Can also be used for shared interceptor instances, but it is recommended
+ /// to set the interceptor reference directly in such a scenario.
+ ///
+ ///
+ public abstract string EntityInterceptorObjectName
+ {
+ set;
+ }
+
+ ///
+ /// Gets or sets the session factory that should be used to create
+ /// NHibernate ISessions.
+ ///
+ /// The session factory.
+ public abstract ISessionFactory SessionFactory
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Set the object factory instance.
+ ///
+ public abstract IObjectFactory ObjectFactory
+ {
+ set;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to
+ /// cache all queries executed by this template.
+ ///
+ ///
+ /// If this is true, all IQuery and ICriteria objects created by
+ /// this template will be marked as cacheable (including all
+ /// queries through find methods).
+ ///
To specify the query region to be used for queries cached
+ /// by this template, set the QueryCacheRegion property.
+ ///
+ ///
+ /// true if cache queries; otherwise, false.
+ public abstract bool CacheQueries
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the name of the cache region for queries executed by this template.
+ ///
+ ///
+ /// If this is specified, it will be applied to all IQuery and ICriteria objects
+ /// created by this template (including all queries through find methods).
+ ///
The cache region will not take effect unless queries created by this
+ /// template are configured to be cached via the CacheQueries property.
+ ///
+ ///
+ /// The query cache region.
+ public abstract string QueryCacheRegion
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the fetch size for this HibernateTemplate.
+ ///
+ /// The size of the fetch.
+ /// This is important for processing
+ /// large result sets: Setting this higher than the default value will increase
+ /// processing speed at the cost of memory consumption; setting this lower can
+ /// avoid transferring row data that will never be read by the application.
+ ///
Default is 0, indicating to use the driver's default.
+ ///
+ public abstract int FetchSize
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the maximum number of rows for this HibernateTemplate.
+ ///
+ /// The max results.
+ ///
+ /// This is important
+ /// for processing subsets of large result sets, avoiding to read and hold
+ /// the entire result set in the database or in the ADO.NET driver if we're
+ /// never interested in the entire result in the first place (for example,
+ /// when performing searches that might return a large number of matches).
+ ///
Default is 0, indicating to use the driver's default.
+ ///
+ public abstract int MaxResults
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Set the ADO.NET exception translator for this instance.
+ /// Applied to System.Data.Common.DbException (or provider specific exception type
+ /// in .NET 1.1) thrown by callback code, be it direct
+ /// DbException or wrapped Hibernate ADOExceptions.
+ ///
The default exception translator is either a ErrorCodeExceptionTranslator
+ /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise
+ ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
Typically used to implement data access or business logic services that
- /// use NHibernate within their implementation but are Hibernate-agnostic in their
- /// interface. The latter or code calling the latter only have to deal with
- /// domain objects.
- ///
- ///
The central method is Execute supporting Hibernate access code
- /// implementing the HibernateCallback interface. It provides NHibernate Session
- /// handling such that neither the IHibernateCallback implementation nor the calling
- /// code needs to explicitly care about retrieving/closing NHibernate Sessions,
- /// or handling Session lifecycle exceptions. For typical single step actions,
- /// there are various convenience methods (Find, Load, SaveOrUpdate, Delete).
- ///
- ///
- ///
Can be used within a service implementation via direct instantiation
- /// with a ISessionFactory reference, or get prepared in an application context
- /// and given to services as an object reference. Note: The ISessionFactory should
- /// always be configured as an object in the application context, in the first case
- /// given to the service directly, in the second case to the prepared template.
- ///
- ///
- ///
This class can be considered as direct alternative to working with the raw
- /// Hibernate Session API (through SessionFactoryUtils.Session).
- ///
- ///
- ///
LocalSessionFactoryObject is the preferred way of obtaining a reference
- /// to a specific NHibernate ISessionFactory.
- ///
- ///
- /// Mark Pollack (.NET)
- /// $Id: HibernateTemplate.cs,v 1.3 2008/01/24 17:29:16 markpollack Exp $
- public class HibernateTemplate : HibernateAccessor, IHibernateOperations
- {
- #region Fields
-
- ///
- /// The instance for this class.
- ///
- private readonly ILog log = LogManager.GetLogger(typeof(HibernateTemplate));
-
- private bool checkWriteOperations = true;
-
-
- private bool exposeNativeSession = false;
-
- private bool alwaysUseNewSession = false;
- private int maxResults = 0;
- private TemplateFlushMode templateFlushMode = TemplateFlushMode.Auto;
- private bool allowCreate = true;
- private ISessionFactory sessionFactory;
- private object entityInterceptor;
- private IObjectFactory objectFactory;
- private bool cacheQueries = false;
- private string queryCacheRegion;
- private int fetchSize = 0;
-
- private IAdoExceptionTranslator adoExceptionTranslator;
-
- private readonly object syncRoot = new object();
- private ProxyFactory sessionProxyFactory;
-
- #endregion
-
- #region Constructor (s)
- ///
- /// Initializes a new instance of the class.
- ///
- public HibernateTemplate()
- {
-
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The default for creating a new non-transactional
- /// session when no transactional Session can be found for the current thread
- /// is set to true.
- /// The session factory to create sessions.
- public HibernateTemplate(ISessionFactory sessionFactory)
- {
- SessionFactory = sessionFactory;
- AfterPropertiesSet();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The session factory to create sessions.
- /// if set to true allow creation
- /// of a new non-transactional when no transactional Session can be found
- /// for the current thread.
- public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate)
- {
- SessionFactory = sessionFactory;
- AllowCreate = allowCreate;
- AfterPropertiesSet();
- }
- #endregion
-
- #region Properties
-
- ///
- /// Gets or sets if a new Session should be created when no transactional Session
- /// can be found for the current thread.
- ///
- ///
- /// true if allowed to create non-transaction session;
- /// otherwise, false.
- ///
- ///
- ///
HibernateTemplate is aware of a corresponding Session bound to the
- /// current thread, for example when using HibernateTransactionManager.
- /// If allowCreate is true, a new non-transactional Session will be created
- /// if none found, which needs to be closed at the end of the operation.
- /// If false, an InvalidOperationException will get thrown in this case.
- ///
- ///
- public override bool AllowCreate
- {
- get
- {
-
- return allowCreate;
- }
- set { allowCreate = value; }
- }
-
- ///
- /// Gets or sets a value indicating whether to always
- /// use a new Hibernate Session for this template.
- ///
- /// true if always use new session; otherwise, false.
- ///
- ///
- /// Default is "false"; if activated, all operations on this template will
- /// work on a new NHibernate ISession even in case of a pre-bound ISession
- /// (for example, within a transaction).
- ///
- ///
Within a transaction, a new NHibernate ISession used by this template
- /// will participate in the transaction through using the same ADO.NET
- /// Connection. In such a scenario, multiple Sessions will participate
- /// in the same database transaction.
- ///
- ///
Turn this on for operations that are supposed to always execute
- /// independently, without side effects caused by a shared NHibernate ISession.
- ///
- ///
- public override bool AlwaysUseNewSession
- {
- get { return alwaysUseNewSession; }
- set { alwaysUseNewSession = value; }
- }
-
-
- ///
- /// Gets or sets the template flush mode.
- ///
- ///
- /// Default is Auto. Will get applied to any new ISession
- /// created by the template.
- ///
- /// The template flush mode.
- public override TemplateFlushMode TemplateFlushMode
- {
- get { return templateFlushMode; }
- set { templateFlushMode = value; }
- }
-
- ///
- /// Gets or sets the entity interceptor that allows to inspect and change
- /// property values before writing to and reading from the database.
- ///
- ///
- /// Will get applied to any new ISession created by this object.
- ///
Such an interceptor can either be set at the ISessionFactory level,
- /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on
- /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
- /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager
- /// to avoid repeated configuration and guarantee consistent behavior in transactions.
- ///
- ///
- /// The interceptor.
- /// If object factory is not set and need to retrieve entity interceptor by name.
- public override IInterceptor EntityInterceptor
- {
- get
- {
- if (this.entityInterceptor is string)
- {
- if (this.objectFactory == null)
- {
- throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set");
- }
- return (IInterceptor)this.objectFactory.GetObject((String)this.entityInterceptor, typeof(IInterceptor));
- }
-
- return (IInterceptor)entityInterceptor;
- }
- set
- {
- entityInterceptor = value;
- }
- }
- ///
- /// Gets or sets the name of the cache region for queries executed by this template.
- ///
- ///
- /// If this is specified, it will be applied to all IQuery and ICriteria objects
- /// created by this template (including all queries through find methods).
- ///
The cache region will not take effect unless queries created by this
- /// template are configured to be cached via the CacheQueries property.
- ///
- ///
- /// The query cache region.
- public override string QueryCacheRegion
- {
- get { return queryCacheRegion; }
- set { queryCacheRegion = value; }
- }
-
-
- ///
- /// Gets or sets a value indicating whether to
- /// cache all queries executed by this template.
- ///
- ///
- /// If this is true, all IQuery and ICriteria objects created by
- /// this template will be marked as cacheable (including all
- /// queries through find methods).
- ///
To specify the query region to be used for queries cached
- /// by this template, set the QueryCacheRegion property.
- ///
- ///
- /// true if cache queries; otherwise, false.
- public override bool CacheQueries
- {
- get { return cacheQueries; }
- set { cacheQueries = value; }
- }
-
- ///
- /// Gets or sets the maximum number of rows for this HibernateTemplate.
- ///
- /// The max results.
- ///
- /// This is important
- /// for processing subsets of large result sets, avoiding to read and hold
- /// the entire result set in the database or in the ADO.NET driver if we're
- /// never interested in the entire result in the first place (for example,
- /// when performing searches that might return a large number of matches).
- ///
Default is 0, indicating to use the driver's default.
- ///
- public override int MaxResults
- {
- get { return maxResults; }
- set { maxResults = value; }
- }
-
- ///
- /// Set whether to expose the native Hibernate Session to IHibernateCallback
- /// code. Default is "false": a Session proxy will be returned,
- /// suppressing close calls and automatically applying
- /// query cache settings and transaction timeouts.
- ///
- /// true if expose native session; otherwise, false.
- public override bool ExposeNativeSession
- {
- get { return exposeNativeSession; }
- set { exposeNativeSession = value; }
- }
- ///
- /// Gets or sets whether to check that the Hibernate Session is not in read-only mode
- /// in case of write operations (save/update/delete).
- ///
- ///
- /// true if check that the Hibernate Session is not in read-only mode
- /// in case of write operations; otherwise, false.
- ///
- ///
- /// Default is "true", for fail-fast behavior when attempting write operations
- /// within a read-only transaction. Turn this off to allow save/update/delete
- /// on a Session with flush mode NEVER.
- ///
- public virtual bool CheckWriteOperations
- {
- get { return checkWriteOperations; }
- set { checkWriteOperations = value; }
- }
-
- ///
- /// Set the object name of a Hibernate entity interceptor that allows to inspect
- /// and change property values before writing to and reading from the database.
- ///
- ///
- /// Will get applied to any new Session created by this transaction manager.
- ///
Requires the object factory to be known, to be able to resolve the object
- /// name to an interceptor instance on session creation. Typically used for
- /// prototype interceptors, i.e. a new interceptor instance per session.
- ///
- ///
Can also be used for shared interceptor instances, but it is recommended
- /// to set the interceptor reference directly in such a scenario.
- ///
- ///
- /// The name of the entity interceptor in the object factory/application context.
- public override string EntityInterceptorObjectName
- {
- set
- {
- this.entityInterceptor = value;
- }
- }
-
- ///
- /// Set the object factory instance.
- ///
- /// The object factory instance
- public override IObjectFactory ObjectFactory
- {
- set
- {
- objectFactory = value;
- }
- }
-
- ///
- /// Gets or sets the session factory that should be used to create
- /// NHibernate ISessions.
- ///
- /// The session factory.
- public override ISessionFactory SessionFactory
- {
- get { return sessionFactory; }
- set
- {
- sessionFactory = value;
- }
- }
-
- ///
- /// Gets or sets the fetch size for this HibernateTemplate.
- ///
- /// The size of the fetch.
- /// This is important for processing
- /// large result sets: Setting this higher than the default value will increase
- /// processing speed at the cost of memory consumption; setting this lower can
- /// avoid transferring row data that will never be read by the application.
- ///
Default is 0, indicating to use the driver's default.
- ///
- public override int FetchSize
- {
- get { return fetchSize; }
- set { fetchSize = value; }
- }
-
-
- ///
- /// Gets or sets the proxy factory.
- ///
- /// This may be useful to set if you create many instances of
- /// HibernateTemplate and/or HibernateDaoSupport. This allows the same
- /// ProxyFactory implementation to be used thereby limiting the
- /// number of dynamic proxy types created in the temporary assembly, which
- /// are never garbage collected due to .NET runtime semantics.
- ///
- /// The proxy factory.
- public virtual ProxyFactory ProxyFactory
- {
- get { return sessionProxyFactory; }
- set { sessionProxyFactory = value; }
- }
-
- #endregion
-
- #region IHibernateOperations Members
-
- ///
- /// Set the ADO.NET exception translator for this instance.
- /// Applied to System.Data.Common.DbException (or provider specific exception type
- /// in .NET 1.1) thrown by callback code, be it direct
- /// DbException or wrapped Hibernate ADOExceptions.
- ///
The default exception translator is either a ErrorCodeExceptionTranslator
- /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise
- ///
- ///
- /// The ADO exception translator.
- public override IAdoExceptionTranslator AdoExceptionTranslator
- {
- set { adoExceptionTranslator = value; }
- get
- {
- if (adoExceptionTranslator == null)
- {
- adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory);
- }
- return adoExceptionTranslator;
- }
- }
-
-
- ///
- /// Delegate function that clears the session.
- ///
- /// The hibernate session.
- /// null
- protected object ClearAction(ISession session)
- {
- session.Clear();
- return null;
- }
-
- ///
- /// Flush all pending saves, updates and deletes to the database.
- ///
- ///
- /// Only invoke this for selective eager flushing, for example when ADO.NET code
- /// needs to see certain changes within the same transaction. Else, it's preferable
- /// to rely on auto-flushing at transaction completion.
- ///
- /// In case of Hibernate errors
- public void Flush()
- {
- Execute(new HibernateDelegate(FlushAction), true);
- }
-
- private object FlushAction(ISession session)
- {
- session.Flush();
- return null;
- }
-
- ///
- /// Return the persistent instance of the given entity type
- /// with the given identifier, or null if not found.
- ///
- /// The type.
- /// An identifier of the persistent instance.
- /// The persistent instance, or null if not found
- /// In case of Hibernate errors
- public object Get(Type entityType, object id)
- {
- return Get(entityType, id, null);
- }
-
- ///
- /// Return the persistent instance of the given entity type
- /// with the given identifier, or null if not found.
- /// Obtains the specified lock mode if the instance exists.
- ///
- /// The type.
- /// The lock mode to obtain.
- /// The lock mode.
- /// the persistent instance, or null if not found
- /// the persistent instance, or null if not found
- /// In case of Hibernate errors
- public object Get(Type type, object id, LockMode lockMode)
- {
- return Execute(new GetByTypeHibernateCallback(type, id, lockMode),true);
-
- }
-
- ///
- /// Return the persistent instance of the given entity class
- /// with the given identifier, throwing an exception if not found.
- ///
- /// Type of the entity.
- /// An identifier of the persistent instance.
- /// The persistent instance
- /// If not found
- /// In case of Hibernate errors
- public object Load(Type entityType, object id)
- {
- return Load(entityType, id, null);
- }
-
- ///
- /// Return the persistent instance of the given entity class
- /// with the given identifier, throwing an exception if not found.
- /// Obtains the specified lock mode if the instance exists.
- ///
- /// Type of the entity.
- /// An identifier of the persistent instance.
- /// The lock mode.
- /// The persistent instance
- /// If not found
- /// In case of Hibernate errors
- public object Load(Type entityType, object id, LockMode lockMode)
- {
- return Execute(new LoadByTypeHibernateCallback(entityType, id, lockMode),true);
-
- }
-
- ///
- /// Load the persistent instance with the given identifier
- /// into the given object, throwing an exception if not found.
- ///
- /// Entity the object (of the target class) to load into.
- /// An identifier of the persistent instance.
- /// If object not found.
- /// In case of Hibernate errors
- public void Load(object entity, object id)
- {
- Execute(new LoadByEntityHibernateCallback(entity, id),true);
- }
-
- ///
- /// Return all persistent instances of the given entity class.
- /// Note: Use queries or criteria for retrieving a specific subset.
- ///
- /// Type of the entity.
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList LoadAll(Type entityType)
- {
- return (IList)Execute(new LoadAllByTypeHibernateCallback(this, entityType),true);
- }
-
- ///
- /// Re-read the state of the given persistent instance.
- ///
- /// The persistent instance to re-read.
- /// In case of Hibernate errors
- public void Refresh(object entity)
- {
- Refresh(entity, null);
- }
-
- ///
- /// Re-read the state of the given persistent instance.
- /// Obtains the specified lock mode for the instance.
- ///
- /// The persistent instance to re-read.
- /// The lock mode to obtain.
- /// In case of Hibernate errors
- public void Refresh(object entity, LockMode lockMode)
- {
- Execute(new RefreshHibernateCallback(entity, lockMode),true);
- }
-
- ///
- /// Obtain the specified lock level upon the given object, implicitly
- /// checking whether the corresponding database entry still exists
- /// (throwing an OptimisticLockingFailureException if not found).
- ///
- /// The he persistent instance to lock.
- /// The lock mode to obtain.
- /// If not found
- /// In case of Hibernate errors
- public void Lock(object entity, LockMode lockMode)
- {
- Execute(new LockHibernateCallback(entity, lockMode),true);
- }
-
- ///
- /// Persist the given transient instance.
- ///
- /// The transient instance to persist.
- /// The generated identifier.
- /// In case of Hibernate errors
- public object Save(object entity)
- {
- return Execute(new SaveObjectHibernateCallback(this, entity),true);
- }
-
- ///
- /// Persist the given transient instance with the given identifier.
- ///
- /// The transient instance to persist.
- /// The identifier to assign.
- /// In case of Hibernate errors
- public void Save(object entity, object id)
- {
- Execute(new SaveObjectWithIdHibernateCallback(this, entity, id),true);
- }
-
- ///
- /// Update the given persistent instance.
- ///
- /// The persistent instance to update.
- /// In case of Hibernate errors
- public void Update(object entity)
- {
- Update(entity, null);
- }
-
- ///
- /// Update the given persistent instance.
- /// Obtains the specified lock mode if the instance exists, implicitly
- /// checking whether the corresponding database entry still exists
- /// (throwing an OptimisticLockingFailureException if not found).
- ///
- /// The persistent instance to update.
- /// The lock mode to obtain.
- /// In case of Hibernate errors
- public void Update(object entity, LockMode lockMode)
- {
- Execute(new UpdateObjectHibernateCallback(this, entity, lockMode),true);
- }
-
- ///
- /// Save or update the given persistent instance,
- /// according to its id (matching the configured "unsaved-value"?).
- ///
- /// Tthe persistent instance to save or update
- /// (to be associated with the Hibernate Session).
- /// In case of Hibernate errors
- public void SaveOrUpdate(object entity)
- {
- Execute(new SaveOrUpdateObjectHibernateCallback(this, entity),true);
- }
-
- ///
- /// Save or update all given persistent instances,
- /// according to its id (matching the configured "unsaved-value"?).
- ///
- /// Tthe persistent instances to save or update
- /// (to be associated with the Hibernate Session)he entities.
- /// In case of Hibernate errors
- public void SaveOrUpdateAll(ICollection entities)
- {
- Execute(new SaveOrUpdateAllHibernateCallback(this, entities), true);
- }
-
- ///
- /// Save or update the contents of given persistent object,
- /// according to its id (matching the configured "unsaved-value"?).
- /// Will copy the contained fields to an already loaded instance
- /// with the same id, if appropriate.
- ///
- /// The persistent object to save or update.
- /// (not necessarily to be associated with the Hibernate Session)
- ///
- /// The actually associated persistent object.
- /// (either an already loaded instance with the same id, or the given object)
- /// In case of Hibernate errors
- public object SaveOrUpdateCopy(object entity)
- {
- return Execute(new SaveOrUpdateCopyHibernateCallback(this, entity),true);
- }
-
-
- ///
- /// Remove all objects from the Session cache, and cancel all pending saves,
- /// updates and deletes.
- ///
- public void Clear()
- {
- Execute(new HibernateDelegate(ClearAction), true);
- }
-
-
-
- ///
- /// Determines whether the given object is in the Session cache.
- ///
- /// the persistence instance to check.
- ///
- /// true if session cache contains the specified entity; otherwise, false.
- ///
- /// In case of Hibernate errors
- public bool Contains(object entity)
- {
- return (bool)Execute(new ContainsHibernateCallback(entity));
- }
-
- ///
- /// Remove the given object from the Session cache.
- ///
- /// The persistent instance to evict.
- /// In case of Hibernate errors
- public void Evict(object entity)
- {
- Execute(new EvictHibernateCallback(entity), true);
-
- }
-
-
-
- ///
- /// Delete the given persistent instance.
- ///
- /// The persistent instance to delete.
- /// In case of Hibernate errors
- public void Delete(object entity)
- {
- Delete(entity, null);
- }
-
-
- ///
- /// Delete the given persistent instance.
- ///
- /// Tthe persistent instance to delete.
- /// The lock mode to obtain.
- ///
- /// Obtains the specified lock mode if the instance exists, implicitly
- /// checking whether the corresponding database entry still exists
- /// (throwing an OptimisticLockingFailureException if not found).
- ///
- /// In case of Hibernate errors
- public void Delete(object entity, LockMode lockMode)
- {
- Execute(new DeleteLockModeHibernateCallback(this, entity, lockMode), true);
- }
-
- ///
- /// Delete all objects returned by the query.
- ///
- /// a query expressed in Hibernate's query language.
- /// The number of entity instances deleted.
- /// In case of Hibernate errors
- public int Delete(string queryString)
- {
- return Delete(queryString, (Object[]) null, (IType[]) null);
- }
-
- ///
- /// Delete all objects returned by the query.
- ///
- /// a query expressed in Hibernate's query language.
- /// The value of the parameter.
- /// The Hibernate type of the parameter (or null).
- /// The number of entity instances deleted.
- /// In case of Hibernate errors
- public int Delete(string queryString, object value, IType type)
- {
- return Delete(queryString, new Object[] {value}, new IType[] {type});
- }
-
- ///
- /// Delete all objects returned by the query.
- ///
- /// a query expressed in Hibernate's query language.
- /// The values of the parameters.
- /// Hibernate types of the parameters (or null)
- /// The number of entity instances deleted.
- /// In case of Hibernate errors
- /// If length for argument values and types are not equal.
- public int Delete(String queryString, Object[] values, IType[] types)
- {
- if (values != null && types != null && values.Length != types.Length)
- {
- throw new ArgumentOutOfRangeException("values", "Length of values array must match length of types array");
- }
- return (int)Execute(new DeletebyQueryHibernateCallback(this, queryString, values, types),true);
-
- }
-
-
- ///
- /// Delete all given persistent instances.
- ///
- /// The persistent instances to delete.
- ///
- /// This can be combined with any of the find methods to delete by query
- /// in two lines of code, similar to Session's delete by query methods.
- ///
- /// In case of Hibernate errors
- public void DeleteAll(ICollection entities)
- {
- Execute(new DeleteAllHibernateCallback(this, entities),true);
- }
-
-
- ///
- /// Execute the action specified by the given action object within a Session.
- ///
- ///
- /// Application exceptions thrown by the action object get propagated to the
- /// caller (can only be unchecked). Hibernate exceptions are transformed into
- /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
- /// object or a collection of domain objects.
- ///
Note: Callback code is not supposed to handle transactions itself!
- /// Use an appropriate transaction manager like HibernateTransactionManager.
- /// Generally, callback code must not touch any Session lifecycle methods,
- /// like close, disconnect, or reconnect, to let the template do its work.
- ///
- ///
- /// The delegate callback object that specifies the Hibernate action.
- /// a result object returned by the action, or null
- ///
- /// In case of Hibernate errors
- public object Execute(HibernateDelegate del)
- {
- return Execute(new ExecuteHibernateCallbackUsingDelegate(del));
- }
-
- ///
- /// Execute the action specified by the delegate within a Session.
- ///
- /// The HibernateDelegate that specifies the action
- /// to perform.
- /// if set to true expose the native hibernate session to
- /// callback code.
- /// a result object returned by the action, or null
- ///
- public object Execute(HibernateDelegate del, bool exposeNativeSession)
- {
- return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true);
- }
-
- ///
- /// Execute the action specified by the given action object within a Session.
- ///
- /// The callback object that specifies the Hibernate action.
- ///
- /// a result object returned by the action, or null
- ///
- ///
- /// Application exceptions thrown by the action object get propagated to the
- /// caller (can only be unchecked). Hibernate exceptions are transformed into
- /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
- /// object or a collection of domain objects.
- ///
Note: Callback code is not supposed to handle transactions itself!
- /// Use an appropriate transaction manager like HibernateTransactionManager.
- /// Generally, callback code must not touch any Session lifecycle methods,
- /// like close, disconnect, or reconnect, to let the template do its work.
- ///
- ///
- /// In case of Hibernate errors
- public object Execute(IHibernateCallback action)
- {
- return Execute(action, ExposeNativeSession);
- }
-
- ///
- /// Execute the specified action assuming that the result object is a List.
- ///
- ///
- /// This is a convenience method for executing Hibernate find calls or
- /// queries within an action.
- ///
- /// The calback object that specifies the Hibernate action.
- /// A IList returned by the action, or null
- ///
- /// In case of Hibernate errors
- public IList ExecuteFind(IHibernateCallback action)
- {
- Object result = Execute(action, ExposeNativeSession);
- if (result != null && !(result is IList)) {
- throw new InvalidDataAccessApiUsageException(
- "Result object returned from HibernateCallback isn't a List: [" + result + "]");
- }
- return (IList) result;
- }
-
- ///
- /// Execute the action specified by the given action object within a Session.
- ///
- /// callback object that specifies the Hibernate action.
- /// if set to true expose the native hibernate session to
- /// callback code.
- ///
- /// a result object returned by the action, or null
- ///
- public object Execute(IHibernateCallback action, bool exposeNativeSession)
- {
- ISession session = Session;
-
- bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory);
- if (existingTransaction)
- {
- if(log.IsDebugEnabled) log.Debug("Found thread-bound Session for HibernateTemplate");
- }
-
- FlushModeHolder previousFlushModeHolder = new FlushModeHolder();
- try
- {
- previousFlushModeHolder = ApplyFlushMode(session, existingTransaction);
- ISession sessionToExpose = (exposeNativeSession ? session : CreateSessionProxy(session));
- Object result = action.DoInHibernate(sessionToExpose);
- FlushIfNecessary(session, existingTransaction);
- return result;
- }
- catch (ADOException ex)
- {
- IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
- if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException))
- {
- throw ConvertAdoAccessException(ex);
- }
- else
- {
- throw new HibernateSystemException(ex);
- }
- }
- catch (HibernateException ex)
- {
- throw ConvertHibernateAccessException(ex);
- }
- catch (Exception ex)
- {
- IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
- if (dbProvider != null && dbProvider.IsDataAccessException(ex))
- {
- throw ConvertAdoAccessException(ex);
- }
- else
- {
- // Callback code throw application exception or other non DB related exception.
- throw;
- }
- }
- finally
- {
- if (existingTransaction)
- {
- if (log.IsDebugEnabled) log.Debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
- if (previousFlushModeHolder.ModeWasSet)
- {
- session.FlushMode = previousFlushModeHolder.Mode;
- }
- }
- else
- {
- // Never use deferred close for an explicitly new Session.
- if (AlwaysUseNewSession)
- {
- SessionFactoryUtils.CloseSession(session);
- }
- else
- {
- SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
- }
- }
- }
- }
-
- ///
- /// Execute a query for persistent instances.
- ///
- /// a query expressed in Hibernate's query language
- ///
- /// a List containing 0 or more persistent instances
- ///
- /// In case of Hibernate errors
- public IList Find(string queryString)
- {
- return Find(queryString, (object[])null, (IType[])null );
- }
-
- ///
- /// Execute a query for persistent instances, binding
- /// one value to a "?" parameter in the query string.
- ///
- /// a query expressed in Hibernate's query language
- /// the value of the parameter
- ///
- /// a List containing 0 or more persistent instances
- ///
- /// In case of Hibernate errors
- public IList Find(string queryString, object value)
- {
- return Find(queryString, new object[] {value}, (IType[]) null);
- }
-
- ///
- /// Execute a query for persistent instances, binding one value
- /// to a "?" parameter of the given type in the query string.
- ///
- /// a query expressed in Hibernate's query language
- /// The value of the parameter.
- /// Hibernate type of the parameter (or null)
- ///
- /// a List containing 0 or more persistent instances
- ///
- /// In case of Hibernate errors
- public IList Find(string queryString, object value, IType type)
- {
- return Find(queryString, new object[] {value}, new IType[] {type});
- }
-
- ///
- /// Execute a query for persistent instances, binding a
- /// number of values to "?" parameters in the query string.
- ///
- /// a query expressed in Hibernate's query language
- /// the values of the parameters
- /// a List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList Find(string queryString, object[] values)
- {
- return Find(queryString, values, (IType[]) null);
- }
-
- ///
- /// Execute a query for persistent instances, binding a number of
- /// values to "?" parameters of the given types in the query string.
- ///
- /// A query expressed in Hibernate's query language
- /// The values of the parameters
- /// Hibernate types of the parameters (or null)
- ///
- /// a List containing 0 or more persistent instances
- ///
- /// In case of Hibernate errors
- /// If values and types are not null and their lengths are not equal
- public IList Find(string queryString, object[] values, IType[] types)
- {
- if (values != null && types != null && values.Length != types.Length)
- {
- throw new ArgumentException("Length of values array must match length of types array");
- }
- return (IList)Execute(new FindHibernateCallback(this, queryString, values, types),true);
- }
-
- ///
- /// Execute a query for persistent instances, binding
- /// one value to a named parameter in the query string.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The name of the parameter
- /// The value of the parameter
- /// a List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedParam(string queryName, string paramName, object value)
- {
- return FindByNamedParam(queryName, paramName, value, null);
- }
-
- ///
- /// Execute a query for persistent instances, binding
- /// one value to a named parameter in the query string.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The name of the parameter
- /// The value of the parameter
- /// Hibernate type of the parameter (or null)
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedParam(string queryName, string paramName, object value, IType type)
- {
- return FindByNamedParam(queryName, new string[] {paramName}, new object[] {value}, new IType[] {type});
- }
-
- ///
- /// Execute a query for persistent instances, binding a
- /// number of values to named parameters in the query string.
- ///
- /// A query expressed in Hibernate's query language
- /// The names of the parameters
- /// The values of the parameters
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedParam(string queryString, string[] paramNames, object[] values)
- {
- return FindByNamedParam(queryString, paramNames, values, null);
- }
-
- ///
- /// Execute a query for persistent instances, binding a
- /// number of values to named parameters in the query string.
- ///
- /// A query expressed in Hibernate's query language
- /// The names of the parameters
- /// The values of the parameters
- /// Hibernate types of the parameters (or null)
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- /// If paramNames length is not equal to values length or
- /// if paramNames length is not equal to types length (when types is not null)
- public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types)
- {
- if (paramNames.Length != values.Length)
- {
- throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of values array");
- }
- if (types != null && paramNames.Length != types.Length)
- {
- throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of types array");
- }
-
- return (IList)Execute(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types),true);
-
- }
-
- ///
- /// Execute a named query for persistent instances.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQuery(string queryName)
- {
- return FindByNamedQuery(queryName, (object[]) null, (IType[]) null);
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// one value to a "?" parameter in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The value of the parameter
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQuery(string queryName, object value)
- {
- return FindByNamedQuery(queryName, new object[] {value}, (IType[]) null);
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// one value to a "?" parameter in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The value of the parameter
- /// Hibernate type of the parameter (or null)
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQuery(string queryName, object value, IType type)
- {
- return FindByNamedQuery(queryName, new object[] { value }, new IType[] { type });
- }
-
- ///
- /// Execute a named query for persistent instances, binding a
- /// number of values to "?" parameters in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The values of the parameters
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQuery(string queryName, object[] values)
- {
- return FindByNamedQuery(queryName, values, (IType[]) null);
- }
-
- ///
- /// Execute a named query for persistent instances, binding a
- /// number of values to "?" parameters in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The values of the parameters
- /// Hibernate types of the parameters (or null)
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- /// If values and types are not null and their lengths differ.
- public IList FindByNamedQuery(string queryName, object[] values, IType[] types)
- {
- if (values != null && types != null && values.Length != types.Length)
- {
- throw new ArgumentOutOfRangeException("Length of values array must match length of types array");
- }
- return (IList)Execute(new FindByNamedQueryHibernateCallback(this, queryName, values, types),true);
-
-
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// one value to a named parameter in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// Name of the parameter
- /// The value of the parameter
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value)
- {
- return FindByNamedQueryAndNamedParam(queryName, paramName, value, null);
-
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// one value to a named parameter in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// Name of the parameter
- /// The value of the parameter
- /// The Hibernate type of the parameter (or null)
- /// A List containing 0 or more persistent instances
- public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type)
- {
- return FindByNamedQueryAndNamedParam(
- queryName, new string[] {paramName}, new object[] {value}, new IType[] {type});
-
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// number of values to named parameters in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The names of the parameters
- /// The values of the parameters.
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values)
- {
- return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null);
-
- }
-
- ///
- /// Execute a named query for persistent instances, binding
- /// number of values to named parameters in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The names of the parameters
- /// The values of the parameters.
- /// Hibernate types of the parameters (or null)
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- /// If paramNames length is not equal to values length or
- /// if paramNames length is not equal to types length (when types is not null)
- public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types)
- {
- if (paramNames != null && values != null && paramNames.Length != values.Length)
- {
- throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of values array");
- }
- if (paramNames != null && types != null && paramNames.Length != types.Length)
- {
- throw new ArgumentOutOfRangeException("paramNams","Length of paramNames array must match length of types array");
- }
- return (IList)Execute(new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types),true);
-
- }
-
- ///
- /// Execute a named query for persistent instances, binding the properties
- /// of the given object to named parameters in the query string.
- /// A named query is defined in a Hibernate mapping file.
- ///
- /// The name of a Hibernate query in a mapping file
- /// The values of the parameters
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByNamedQueryAndValueObject(string queryName, object valueObject)
- {
- return (IList)Execute(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject),true);
-
- }
-
- ///
- /// Execute a query for persistent instances, binding the properties
- /// of the given object to named parameters in the query string.
- ///
- /// A query expressed in Hibernate's query language
- /// The values of the parameters
- /// A List containing 0 or more persistent instances
- /// In case of Hibernate errors
- public IList FindByValueObject(string queryString, object valueObject)
- {
- return (IList)Execute(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true);
- }
-
- #endregion
-
- #region Methods
-
-
- ///
- /// Create a close-suppressing proxy for the given Hibernate Session.
- /// The proxy also prepares returned Query and Criteria objects.
- ///
- /// The session.
- /// The session proxy.
- public virtual ISession CreateSessionProxy(ISession session)
- {
- //TODO can move to HibernateAccessor and make protected
- // if issue reported with AOP+Multiple Threads resolve.
- // have not been able to reproduce so added lock as a precaution.
- //
- lock (syncRoot)
- {
- if (sessionProxyFactory == null)
- {
- sessionProxyFactory = new ProxyFactory();
- sessionProxyFactory.AddAdvice(new CloseSuppressingMethodInterceptor(this));
- }
-
- sessionProxyFactory.Target = session;
-
- return (ISession)sessionProxyFactory.GetProxy();
- }
- }
-
- ///
- /// Check whether write operations are allowed on the given Session.
- ///
- ///
- /// Default implementation throws an InvalidDataAccessApiUsageException
- /// in case of FlushMode.Never. Can be overridden in subclasses.
- ///
- /// The current Hibernate session.
- /// If write operation is attempted in read-only mode
- ///
- public virtual void CheckWriteOperationAllowed(ISession session)
- {
- if (CheckWriteOperations && TemplateFlushMode != TemplateFlushMode.Eager &&
- AreEqualFlushMode(TemplateFlushMode.Never, session.FlushMode))
- {
- throw new InvalidDataAccessApiUsageException(
- "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " +
- "into FlushMode.AUTO or remove 'readOnly' marker from transaction definition");
- }
- }
-
-
-
- ///
- /// Compares if the flush mode enumerations, Spring's
- /// TemplateFlushMode and NHibernates FlushMode have equal
- /// settings.
- ///
- /// The template flush mode.
- /// The NHibernate flush mode.
- ///
- /// Returns true if both are Never, Auto, or Commit, false
- /// otherwise.
- ///
- protected bool AreEqualFlushMode(TemplateFlushMode tfm, FlushMode fm)
- {
- if ( (tfm ==TemplateFlushMode.Never && fm == FlushMode.Never) ||
- (tfm ==TemplateFlushMode.Auto && fm == FlushMode.Auto) ||
- (tfm ==TemplateFlushMode.Commit && fm == FlushMode.Commit) )
- {
- return true;
- }
- else
- {
- return false;
- }
- //TODO other combinations.
- }
-
- #endregion
- }
-
- #region Internal Supporting Callback Classes
-
- //TODO see if can create common base class for some callbacks.
-
- internal class ContainsHibernateCallback : IHibernateCallback
- {
- private object entity;
- public ContainsHibernateCallback(object entity)
- {
- this.entity = entity;
- }
-
- public object DoInHibernate(ISession session)
- {
- return session.Contains(entity);
- }
- }
-
-
- internal class DeleteLockModeHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
- private LockMode lockMode;
- public DeleteLockModeHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode)
- {
- this.outer = template;
- this.entity = entity;
- this.lockMode = lockMode;
- }
-
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- if (lockMode != null)
- {
- session.Lock(entity, lockMode);
- }
- session.Delete(entity);
- return null;
- }
- }
-
-
- internal class DeletebyQueryHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private string queryString;
- private object[] values;
- private IType[] types;
-
- public DeletebyQueryHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types)
- {
- this.outer = template;
- this.queryString = queryString;
- this.values = values;
- this.types = types;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- if (values != null)
- {
- return session.Delete(queryString, values, types);
- }
- else
- {
- return session.Delete(queryString);
- }
- }
- }
-
-
-
- internal class DeleteAllHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private ICollection entities;
-
- public DeleteAllHibernateCallback(HibernateTemplate template, ICollection entities)
- {
- this.outer = template;
- this.entities = entities;
-
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- foreach (object entity in entities)
- {
- session.Delete(entity);
- }
- return null;
- }
-
-
-
- }
-
-
- internal class EvictHibernateCallback : IHibernateCallback
- {
- private object entity;
-
- public EvictHibernateCallback(object entity)
- {
- this.entity = entity;
-
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- session.Evict(entity);
- return null;
- }
-
-
-
- }
-
-
- internal class FindHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private string queryString;
- private object[] values;
- private IType[] types;
-
- public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types)
- {
- this.outer = template;
- this.queryString = queryString;
- this.values = values;
- this.types = types;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.CreateQuery(queryString);
- outer.PrepareQuery(queryObject);
- if (values != null)
- {
- for (int i = 0; i < values.Length; i++)
- {
- if (types != null && types[i] != null)
- {
- queryObject.SetParameter(i, values[i], types[i]);
- }
- else
- {
- queryObject.SetParameter(i, values[i]);
- }
- }
- }
-
- return queryObject.List();
- }
- }
-
-
- internal class FindByNamedParamHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private string queryString;
- private string[] paramNames;
- private object[] values;
- private IType[] types;
-
- public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, object[] values, IType[] types)
- {
- this.outer = template;
- this.queryString = queryString;
- this.paramNames = paramNames;
- this.values = values;
- this.types = types;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.CreateQuery(queryString);
- outer.PrepareQuery(queryObject);
- if (values != null)
- {
- for (int i = 0; i < values.Length; i++)
- {
- outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
- }
- }
- return queryObject.List();
-
- }
- }
-
-
- internal class FindByNamedQueryHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private string queryName;
- private object[] values;
- private IType[] types;
-
- public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, IType[] types)
- {
- this.outer = template;
- this.queryName = queryName;
- this.values = values;
- this.types = types;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.GetNamedQuery(queryName);
- outer.PrepareQuery(queryObject);
- if (values != null)
- {
- for (int i = 0; i < values.Length; i++)
- {
- if (types != null && types[i] != null)
- {
- queryObject.SetParameter(i, values[i], types[i]);
- }
- else
- {
- queryObject.SetParameter(i, values[i]);
- }
- }
- }
- return queryObject.List();
-
- }
- }
-
-
- internal class FindByNamedQueryAndNamedParamHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private string queryName;
- private string[] paramNames;
- private object[] values;
- private IType[] types;
-
- public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, string[] paramNames, object[] values, IType[] types)
- {
- this.outer = template;
- this.queryName = queryName;
- this.paramNames = paramNames;
- this.values = values;
- this.types = types;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.GetNamedQuery(queryName);
- outer.PrepareQuery(queryObject);
- if (values != null)
- {
- for (int i = 0; i < values.Length; i++)
- {
- outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
- }
- }
- return queryObject.List();
-
- }
- }
-
-
- internal class FindByNamedQueryAndValueObjectHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private string queryName;
- private object valueObject;
-
- public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, object valueObject)
- {
- this.outer = template;
- this.queryName = queryName;
- this.valueObject = valueObject;
-
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.GetNamedQuery(queryName);
- outer.PrepareQuery(queryObject);
- queryObject.SetProperties(valueObject);
- return queryObject.List();
-
- }
-
-
-
- }
-
- internal class FindByValueObjectHibernateCallback : IHibernateCallback
- {
- HibernateTemplate outer;
- private string queryString;
- private object valueObject;
-
- public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject)
- {
- this.outer = template;
- this.queryString = queryString;
- this.valueObject = valueObject;
-
- }
-
- public object DoInHibernate(ISession session)
- {
- IQuery queryObject = session.CreateQuery(queryString);
- outer.PrepareQuery(queryObject);
- queryObject.SetProperties(valueObject);
- return queryObject.List();
-
- }
-
- }
-
- internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback
- {
- private HibernateDelegate del;
-
- public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d)
- {
- del = d;
- }
-
- public object DoInHibernate(ISession session)
- {
- return del(session);
- }
- }
-
-
- internal class GetByTypeHibernateCallback : IHibernateCallback
- {
- private Type entityType;
- private object id;
- private LockMode lockMode;
-
- public GetByTypeHibernateCallback(Type entityType, object id, LockMode lockMode)
- {
- this.entityType = entityType;
- this.id = id;
- this.lockMode = lockMode;
-
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- if (lockMode != null)
- {
- return session.Get(entityType, id, lockMode);
- }
- else
- {
- return session.Get(entityType, id);
- }
- }
-
-
-
- }
-
-
- internal class LoadByTypeHibernateCallback : IHibernateCallback
- {
- private Type entityType;
- private object id;
- private LockMode lockMode;
-
- public LoadByTypeHibernateCallback(Type entityType, object id, LockMode lockMode)
- {
- this.entityType = entityType;
- this.id = id;
- this.lockMode = lockMode;
-
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- if (lockMode != null)
- {
- return session.Load(entityType, id, lockMode);
- }
- else
- {
- return session.Load(entityType, id);
- }
- }
-
-
-
- }
-
-
- internal class LoadByEntityHibernateCallback : IHibernateCallback
- {
- private object entity;
- private object id;
-
- public LoadByEntityHibernateCallback(object entity, object id)
- {
- this.entity = entity;
- this.id = id;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- session.Load(entity, id);
- return null;
- }
-
-
-
- }
-
-
- internal class LoadAllByTypeHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private Type entityType;
-
- public LoadAllByTypeHibernateCallback(HibernateTemplate template, Type entityType)
- {
- outer = template;
- this.entityType = entityType;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- ICriteria criteria = session.CreateCriteria(entityType);
- outer.PrepareCriteria(criteria);
- return criteria.List();
- }
- }
-
-
- internal class LockHibernateCallback : IHibernateCallback
- {
- private object entity;
- private LockMode lockMode;
-
- public LockHibernateCallback(object entity, LockMode lockMode)
- {
- this.entity = entity;
- this.lockMode = lockMode;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- session.Lock(entity, lockMode);
- return null;
- }
- }
-
-
- internal class RefreshHibernateCallback : IHibernateCallback
- {
- private object entity;
- private LockMode lockMode;
-
- public RefreshHibernateCallback(object entity, LockMode lockMode)
- {
- this.entity = entity;
- this.lockMode = lockMode;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- if (lockMode != null)
- {
- session.Refresh(entity, lockMode);
- }
- else
- {
- session.Refresh(entity);
- }
- return null;
- }
- }
-
-
- internal class SaveObjectHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
-
- public SaveObjectHibernateCallback(HibernateTemplate template, object entity)
- {
- this.outer = template;
- this.entity = entity;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- return session.Save(entity);
- }
- }
-
-
- internal class SaveObjectWithIdHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
- private object id;
-
- public SaveObjectWithIdHibernateCallback(HibernateTemplate template, object entity, object id)
- {
- this.outer = template;
- this.entity = entity;
- this.id = id;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- session.Save(entity, id);
- return null;
- }
- }
-
-
- internal class UpdateObjectHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
- private LockMode lockMode;
-
- public UpdateObjectHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode)
- {
- this.outer = template;
- this.entity = entity;
- this.lockMode = lockMode;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- session.Update(entity);
- if (lockMode != null)
- {
- session.Lock(entity, lockMode);
- }
- return null;
- }
- }
-
-
- internal class SaveOrUpdateObjectHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
-
- public SaveOrUpdateObjectHibernateCallback(HibernateTemplate template, object entity)
- {
- this.outer = template;
- this.entity = entity;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- session.SaveOrUpdate(entity);
- return null;
- }
- }
-
- internal class SaveOrUpdateAllHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private ICollection entities;
-
- public SaveOrUpdateAllHibernateCallback(HibernateTemplate template, ICollection entities)
- {
- this.outer = template;
- this.entities = entities;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
- ///
- public object DoInHibernate(ISession session)
- {
- outer.CheckWriteOperationAllowed(session);
- foreach (object entity in entities)
- {
- session.SaveOrUpdate(entity);
- }
- return null;
- }
- }
- internal class SaveOrUpdateCopyHibernateCallback : IHibernateCallback
- {
- private HibernateTemplate outer;
- private object entity;
-
- public SaveOrUpdateCopyHibernateCallback(HibernateTemplate template, object entity)
- {
- this.outer = template;
- this.entity = entity;
- }
-
- ///
- /// Gets called by HibernateTemplate with an active
- /// Hibernate Session. Does not need to care about activating or closing
- /// the Session, or handling transactions.
- ///
- ///
- ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
Typically used to implement data access or business logic services that
+ /// use NHibernate within their implementation but are Hibernate-agnostic in their
+ /// interface. The latter or code calling the latter only have to deal with
+ /// domain objects.
+ ///
+ ///
The central method is Execute supporting Hibernate access code
+ /// implementing the HibernateCallback interface. It provides NHibernate Session
+ /// handling such that neither the IHibernateCallback implementation nor the calling
+ /// code needs to explicitly care about retrieving/closing NHibernate Sessions,
+ /// or handling Session lifecycle exceptions. For typical single step actions,
+ /// there are various convenience methods (Find, Load, SaveOrUpdate, Delete).
+ ///
+ ///
+ ///
Can be used within a service implementation via direct instantiation
+ /// with a ISessionFactory reference, or get prepared in an application context
+ /// and given to services as an object reference. Note: The ISessionFactory should
+ /// always be configured as an object in the application context, in the first case
+ /// given to the service directly, in the second case to the prepared template.
+ ///
+ ///
+ ///
This class can be considered as direct alternative to working with the raw
+ /// Hibernate Session API (through SessionFactoryUtils.Session).
+ ///
+ ///
+ ///
LocalSessionFactoryObject is the preferred way of obtaining a reference
+ /// to a specific NHibernate ISessionFactory.
+ ///
+ ///
+ /// Mark Pollack (.NET)
+ public class HibernateTemplate : HibernateAccessor, IHibernateOperations
+ {
+ #region Fields
+
+ ///
+ /// The instance for this class.
+ ///
+ private readonly ILog log = LogManager.GetLogger(typeof(HibernateTemplate));
+
+ private bool checkWriteOperations = true;
+
+
+ private bool exposeNativeSession = false;
+
+ private bool alwaysUseNewSession = false;
+ private int maxResults = 0;
+ private TemplateFlushMode templateFlushMode = TemplateFlushMode.Auto;
+ private bool allowCreate = true;
+ private ISessionFactory sessionFactory;
+ private object entityInterceptor;
+ private IObjectFactory objectFactory;
+ private bool cacheQueries = false;
+ private string queryCacheRegion;
+ private int fetchSize = 0;
+
+ private IAdoExceptionTranslator adoExceptionTranslator;
+
+ private readonly object syncRoot = new object();
+ private ProxyFactory sessionProxyFactory;
+
+ #endregion
+
+ #region Constructor (s)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HibernateTemplate()
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The default for creating a new non-transactional
+ /// session when no transactional Session can be found for the current thread
+ /// is set to true.
+ /// The session factory to create sessions.
+ public HibernateTemplate(ISessionFactory sessionFactory)
+ {
+ SessionFactory = sessionFactory;
+ AfterPropertiesSet();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The session factory to create sessions.
+ /// if set to true allow creation
+ /// of a new non-transactional when no transactional Session can be found
+ /// for the current thread.
+ public HibernateTemplate(ISessionFactory sessionFactory, bool allowCreate)
+ {
+ SessionFactory = sessionFactory;
+ AllowCreate = allowCreate;
+ AfterPropertiesSet();
+ }
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets if a new Session should be created when no transactional Session
+ /// can be found for the current thread.
+ ///
+ ///
+ /// true if allowed to create non-transaction session;
+ /// otherwise, false.
+ ///
+ ///
+ ///
HibernateTemplate is aware of a corresponding Session bound to the
+ /// current thread, for example when using HibernateTransactionManager.
+ /// If allowCreate is true, a new non-transactional Session will be created
+ /// if none found, which needs to be closed at the end of the operation.
+ /// If false, an InvalidOperationException will get thrown in this case.
+ ///
+ ///
+ public override bool AllowCreate
+ {
+ get
+ {
+
+ return allowCreate;
+ }
+ set { allowCreate = value; }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to always
+ /// use a new Hibernate Session for this template.
+ ///
+ /// true if always use new session; otherwise, false.
+ ///
+ ///
+ /// Default is "false"; if activated, all operations on this template will
+ /// work on a new NHibernate ISession even in case of a pre-bound ISession
+ /// (for example, within a transaction).
+ ///
+ ///
Within a transaction, a new NHibernate ISession used by this template
+ /// will participate in the transaction through using the same ADO.NET
+ /// Connection. In such a scenario, multiple Sessions will participate
+ /// in the same database transaction.
+ ///
+ ///
Turn this on for operations that are supposed to always execute
+ /// independently, without side effects caused by a shared NHibernate ISession.
+ ///
+ ///
+ public override bool AlwaysUseNewSession
+ {
+ get { return alwaysUseNewSession; }
+ set { alwaysUseNewSession = value; }
+ }
+
+
+ ///
+ /// Gets or sets the template flush mode.
+ ///
+ ///
+ /// Default is Auto. Will get applied to any new ISession
+ /// created by the template.
+ ///
+ /// The template flush mode.
+ public override TemplateFlushMode TemplateFlushMode
+ {
+ get { return templateFlushMode; }
+ set { templateFlushMode = value; }
+ }
+
+ ///
+ /// Gets or sets the entity interceptor that allows to inspect and change
+ /// property values before writing to and reading from the database.
+ ///
+ ///
+ /// Will get applied to any new ISession created by this object.
+ ///
Such an interceptor can either be set at the ISessionFactory level,
+ /// i.e. on LocalSessionFactoryObject, or at the ISession level, i.e. on
+ /// HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
+ /// It's preferable to set it on LocalSessionFactoryObject or HibernateTransactionManager
+ /// to avoid repeated configuration and guarantee consistent behavior in transactions.
+ ///
+ ///
+ /// The interceptor.
+ /// If object factory is not set and need to retrieve entity interceptor by name.
+ public override IInterceptor EntityInterceptor
+ {
+ get
+ {
+ if (this.entityInterceptor is string)
+ {
+ if (this.objectFactory == null)
+ {
+ throw new InvalidOperationException("Cannot get entity interceptor via object name if no object factory set");
+ }
+ return (IInterceptor)this.objectFactory.GetObject((String)this.entityInterceptor, typeof(IInterceptor));
+ }
+
+ return (IInterceptor)entityInterceptor;
+ }
+ set
+ {
+ entityInterceptor = value;
+ }
+ }
+ ///
+ /// Gets or sets the name of the cache region for queries executed by this template.
+ ///
+ ///
+ /// If this is specified, it will be applied to all IQuery and ICriteria objects
+ /// created by this template (including all queries through find methods).
+ ///
The cache region will not take effect unless queries created by this
+ /// template are configured to be cached via the CacheQueries property.
+ ///
+ ///
+ /// The query cache region.
+ public override string QueryCacheRegion
+ {
+ get { return queryCacheRegion; }
+ set { queryCacheRegion = value; }
+ }
+
+
+ ///
+ /// Gets or sets a value indicating whether to
+ /// cache all queries executed by this template.
+ ///
+ ///
+ /// If this is true, all IQuery and ICriteria objects created by
+ /// this template will be marked as cacheable (including all
+ /// queries through find methods).
+ ///
To specify the query region to be used for queries cached
+ /// by this template, set the QueryCacheRegion property.
+ ///
+ ///
+ /// true if cache queries; otherwise, false.
+ public override bool CacheQueries
+ {
+ get { return cacheQueries; }
+ set { cacheQueries = value; }
+ }
+
+ ///
+ /// Gets or sets the maximum number of rows for this HibernateTemplate.
+ ///
+ /// The max results.
+ ///
+ /// This is important
+ /// for processing subsets of large result sets, avoiding to read and hold
+ /// the entire result set in the database or in the ADO.NET driver if we're
+ /// never interested in the entire result in the first place (for example,
+ /// when performing searches that might return a large number of matches).
+ ///
Default is 0, indicating to use the driver's default.
+ ///
+ public override int MaxResults
+ {
+ get { return maxResults; }
+ set { maxResults = value; }
+ }
+
+ ///
+ /// Set whether to expose the native Hibernate Session to IHibernateCallback
+ /// code. Default is "false": a Session proxy will be returned,
+ /// suppressing close calls and automatically applying
+ /// query cache settings and transaction timeouts.
+ ///
+ /// true if expose native session; otherwise, false.
+ public override bool ExposeNativeSession
+ {
+ get { return exposeNativeSession; }
+ set { exposeNativeSession = value; }
+ }
+ ///
+ /// Gets or sets whether to check that the Hibernate Session is not in read-only mode
+ /// in case of write operations (save/update/delete).
+ ///
+ ///
+ /// true if check that the Hibernate Session is not in read-only mode
+ /// in case of write operations; otherwise, false.
+ ///
+ ///
+ /// Default is "true", for fail-fast behavior when attempting write operations
+ /// within a read-only transaction. Turn this off to allow save/update/delete
+ /// on a Session with flush mode NEVER.
+ ///
+ public virtual bool CheckWriteOperations
+ {
+ get { return checkWriteOperations; }
+ set { checkWriteOperations = value; }
+ }
+
+ ///
+ /// Set the object name of a Hibernate entity interceptor that allows to inspect
+ /// and change property values before writing to and reading from the database.
+ ///
+ ///
+ /// Will get applied to any new Session created by this transaction manager.
+ ///
Requires the object factory to be known, to be able to resolve the object
+ /// name to an interceptor instance on session creation. Typically used for
+ /// prototype interceptors, i.e. a new interceptor instance per session.
+ ///
+ ///
Can also be used for shared interceptor instances, but it is recommended
+ /// to set the interceptor reference directly in such a scenario.
+ ///
+ ///
+ /// The name of the entity interceptor in the object factory/application context.
+ public override string EntityInterceptorObjectName
+ {
+ set
+ {
+ this.entityInterceptor = value;
+ }
+ }
+
+ ///
+ /// Set the object factory instance.
+ ///
+ /// The object factory instance
+ public override IObjectFactory ObjectFactory
+ {
+ set
+ {
+ objectFactory = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the session factory that should be used to create
+ /// NHibernate ISessions.
+ ///
+ /// The session factory.
+ public override ISessionFactory SessionFactory
+ {
+ get { return sessionFactory; }
+ set
+ {
+ sessionFactory = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the fetch size for this HibernateTemplate.
+ ///
+ /// The size of the fetch.
+ /// This is important for processing
+ /// large result sets: Setting this higher than the default value will increase
+ /// processing speed at the cost of memory consumption; setting this lower can
+ /// avoid transferring row data that will never be read by the application.
+ ///
Default is 0, indicating to use the driver's default.
+ ///
+ public override int FetchSize
+ {
+ get { return fetchSize; }
+ set { fetchSize = value; }
+ }
+
+
+ ///
+ /// Gets or sets the proxy factory.
+ ///
+ /// This may be useful to set if you create many instances of
+ /// HibernateTemplate and/or HibernateDaoSupport. This allows the same
+ /// ProxyFactory implementation to be used thereby limiting the
+ /// number of dynamic proxy types created in the temporary assembly, which
+ /// are never garbage collected due to .NET runtime semantics.
+ ///
+ /// The proxy factory.
+ public virtual ProxyFactory ProxyFactory
+ {
+ get { return sessionProxyFactory; }
+ set { sessionProxyFactory = value; }
+ }
+
+ #endregion
+
+ #region IHibernateOperations Members
+
+ ///
+ /// Set the ADO.NET exception translator for this instance.
+ /// Applied to System.Data.Common.DbException (or provider specific exception type
+ /// in .NET 1.1) thrown by callback code, be it direct
+ /// DbException or wrapped Hibernate ADOExceptions.
+ ///
The default exception translator is either a ErrorCodeExceptionTranslator
+ /// if a DbProvider is available, or a FalbackExceptionTranslator otherwise
+ ///
+ ///
+ /// The ADO exception translator.
+ public override IAdoExceptionTranslator AdoExceptionTranslator
+ {
+ set { adoExceptionTranslator = value; }
+ get
+ {
+ if (adoExceptionTranslator == null)
+ {
+ adoExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory);
+ }
+ return adoExceptionTranslator;
+ }
+ }
+
+
+ ///
+ /// Delegate function that clears the session.
+ ///
+ /// The hibernate session.
+ /// null
+ protected object ClearAction(ISession session)
+ {
+ session.Clear();
+ return null;
+ }
+
+ ///
+ /// Flush all pending saves, updates and deletes to the database.
+ ///
+ ///
+ /// Only invoke this for selective eager flushing, for example when ADO.NET code
+ /// needs to see certain changes within the same transaction. Else, it's preferable
+ /// to rely on auto-flushing at transaction completion.
+ ///
+ /// In case of Hibernate errors
+ public void Flush()
+ {
+ Execute(new HibernateDelegate(FlushAction), true);
+ }
+
+ private object FlushAction(ISession session)
+ {
+ session.Flush();
+ return null;
+ }
+
+ ///
+ /// Return the persistent instance of the given entity type
+ /// with the given identifier, or null if not found.
+ ///
+ /// The type.
+ /// An identifier of the persistent instance.
+ /// The persistent instance, or null if not found
+ /// In case of Hibernate errors
+ public object Get(Type entityType, object id)
+ {
+ return Get(entityType, id, null);
+ }
+
+ ///
+ /// Return the persistent instance of the given entity type
+ /// with the given identifier, or null if not found.
+ /// Obtains the specified lock mode if the instance exists.
+ ///
+ /// The type.
+ /// The lock mode to obtain.
+ /// The lock mode.
+ /// the persistent instance, or null if not found
+ /// the persistent instance, or null if not found
+ /// In case of Hibernate errors
+ public object Get(Type type, object id, LockMode lockMode)
+ {
+ return Execute(new GetByTypeHibernateCallback(type, id, lockMode),true);
+
+ }
+
+ ///
+ /// Return the persistent instance of the given entity class
+ /// with the given identifier, throwing an exception if not found.
+ ///
+ /// Type of the entity.
+ /// An identifier of the persistent instance.
+ /// The persistent instance
+ /// If not found
+ /// In case of Hibernate errors
+ public object Load(Type entityType, object id)
+ {
+ return Load(entityType, id, null);
+ }
+
+ ///
+ /// Return the persistent instance of the given entity class
+ /// with the given identifier, throwing an exception if not found.
+ /// Obtains the specified lock mode if the instance exists.
+ ///
+ /// Type of the entity.
+ /// An identifier of the persistent instance.
+ /// The lock mode.
+ /// The persistent instance
+ /// If not found
+ /// In case of Hibernate errors
+ public object Load(Type entityType, object id, LockMode lockMode)
+ {
+ return Execute(new LoadByTypeHibernateCallback(entityType, id, lockMode),true);
+
+ }
+
+ ///
+ /// Load the persistent instance with the given identifier
+ /// into the given object, throwing an exception if not found.
+ ///
+ /// Entity the object (of the target class) to load into.
+ /// An identifier of the persistent instance.
+ /// If object not found.
+ /// In case of Hibernate errors
+ public void Load(object entity, object id)
+ {
+ Execute(new LoadByEntityHibernateCallback(entity, id),true);
+ }
+
+ ///
+ /// Return all persistent instances of the given entity class.
+ /// Note: Use queries or criteria for retrieving a specific subset.
+ ///
+ /// Type of the entity.
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList LoadAll(Type entityType)
+ {
+ return (IList)Execute(new LoadAllByTypeHibernateCallback(this, entityType),true);
+ }
+
+ ///
+ /// Re-read the state of the given persistent instance.
+ ///
+ /// The persistent instance to re-read.
+ /// In case of Hibernate errors
+ public void Refresh(object entity)
+ {
+ Refresh(entity, null);
+ }
+
+ ///
+ /// Re-read the state of the given persistent instance.
+ /// Obtains the specified lock mode for the instance.
+ ///
+ /// The persistent instance to re-read.
+ /// The lock mode to obtain.
+ /// In case of Hibernate errors
+ public void Refresh(object entity, LockMode lockMode)
+ {
+ Execute(new RefreshHibernateCallback(entity, lockMode),true);
+ }
+
+ ///
+ /// Obtain the specified lock level upon the given object, implicitly
+ /// checking whether the corresponding database entry still exists
+ /// (throwing an OptimisticLockingFailureException if not found).
+ ///
+ /// The he persistent instance to lock.
+ /// The lock mode to obtain.
+ /// If not found
+ /// In case of Hibernate errors
+ public void Lock(object entity, LockMode lockMode)
+ {
+ Execute(new LockHibernateCallback(entity, lockMode),true);
+ }
+
+ ///
+ /// Persist the given transient instance.
+ ///
+ /// The transient instance to persist.
+ /// The generated identifier.
+ /// In case of Hibernate errors
+ public object Save(object entity)
+ {
+ return Execute(new SaveObjectHibernateCallback(this, entity),true);
+ }
+
+ ///
+ /// Persist the given transient instance with the given identifier.
+ ///
+ /// The transient instance to persist.
+ /// The identifier to assign.
+ /// In case of Hibernate errors
+ public void Save(object entity, object id)
+ {
+ Execute(new SaveObjectWithIdHibernateCallback(this, entity, id),true);
+ }
+
+ ///
+ /// Update the given persistent instance.
+ ///
+ /// The persistent instance to update.
+ /// In case of Hibernate errors
+ public void Update(object entity)
+ {
+ Update(entity, null);
+ }
+
+ ///
+ /// Update the given persistent instance.
+ /// Obtains the specified lock mode if the instance exists, implicitly
+ /// checking whether the corresponding database entry still exists
+ /// (throwing an OptimisticLockingFailureException if not found).
+ ///
+ /// The persistent instance to update.
+ /// The lock mode to obtain.
+ /// In case of Hibernate errors
+ public void Update(object entity, LockMode lockMode)
+ {
+ Execute(new UpdateObjectHibernateCallback(this, entity, lockMode),true);
+ }
+
+ ///
+ /// Save or update the given persistent instance,
+ /// according to its id (matching the configured "unsaved-value"?).
+ ///
+ /// Tthe persistent instance to save or update
+ /// (to be associated with the Hibernate Session).
+ /// In case of Hibernate errors
+ public void SaveOrUpdate(object entity)
+ {
+ Execute(new SaveOrUpdateObjectHibernateCallback(this, entity),true);
+ }
+
+ ///
+ /// Save or update all given persistent instances,
+ /// according to its id (matching the configured "unsaved-value"?).
+ ///
+ /// Tthe persistent instances to save or update
+ /// (to be associated with the Hibernate Session)he entities.
+ /// In case of Hibernate errors
+ public void SaveOrUpdateAll(ICollection entities)
+ {
+ Execute(new SaveOrUpdateAllHibernateCallback(this, entities), true);
+ }
+
+ ///
+ /// Save or update the contents of given persistent object,
+ /// according to its id (matching the configured "unsaved-value"?).
+ /// Will copy the contained fields to an already loaded instance
+ /// with the same id, if appropriate.
+ ///
+ /// The persistent object to save or update.
+ /// (not necessarily to be associated with the Hibernate Session)
+ ///
+ /// The actually associated persistent object.
+ /// (either an already loaded instance with the same id, or the given object)
+ /// In case of Hibernate errors
+ public object SaveOrUpdateCopy(object entity)
+ {
+ return Execute(new SaveOrUpdateCopyHibernateCallback(this, entity),true);
+ }
+
+
+ ///
+ /// Remove all objects from the Session cache, and cancel all pending saves,
+ /// updates and deletes.
+ ///
+ public void Clear()
+ {
+ Execute(new HibernateDelegate(ClearAction), true);
+ }
+
+
+
+ ///
+ /// Determines whether the given object is in the Session cache.
+ ///
+ /// the persistence instance to check.
+ ///
+ /// true if session cache contains the specified entity; otherwise, false.
+ ///
+ /// In case of Hibernate errors
+ public bool Contains(object entity)
+ {
+ return (bool)Execute(new ContainsHibernateCallback(entity));
+ }
+
+ ///
+ /// Remove the given object from the Session cache.
+ ///
+ /// The persistent instance to evict.
+ /// In case of Hibernate errors
+ public void Evict(object entity)
+ {
+ Execute(new EvictHibernateCallback(entity), true);
+
+ }
+
+
+
+ ///
+ /// Delete the given persistent instance.
+ ///
+ /// The persistent instance to delete.
+ /// In case of Hibernate errors
+ public void Delete(object entity)
+ {
+ Delete(entity, null);
+ }
+
+
+ ///
+ /// Delete the given persistent instance.
+ ///
+ /// Tthe persistent instance to delete.
+ /// The lock mode to obtain.
+ ///
+ /// Obtains the specified lock mode if the instance exists, implicitly
+ /// checking whether the corresponding database entry still exists
+ /// (throwing an OptimisticLockingFailureException if not found).
+ ///
+ /// In case of Hibernate errors
+ public void Delete(object entity, LockMode lockMode)
+ {
+ Execute(new DeleteLockModeHibernateCallback(this, entity, lockMode), true);
+ }
+
+ ///
+ /// Delete all objects returned by the query.
+ ///
+ /// a query expressed in Hibernate's query language.
+ /// The number of entity instances deleted.
+ /// In case of Hibernate errors
+ public int Delete(string queryString)
+ {
+ return Delete(queryString, (Object[]) null, (IType[]) null);
+ }
+
+ ///
+ /// Delete all objects returned by the query.
+ ///
+ /// a query expressed in Hibernate's query language.
+ /// The value of the parameter.
+ /// The Hibernate type of the parameter (or null).
+ /// The number of entity instances deleted.
+ /// In case of Hibernate errors
+ public int Delete(string queryString, object value, IType type)
+ {
+ return Delete(queryString, new Object[] {value}, new IType[] {type});
+ }
+
+ ///
+ /// Delete all objects returned by the query.
+ ///
+ /// a query expressed in Hibernate's query language.
+ /// The values of the parameters.
+ /// Hibernate types of the parameters (or null)
+ /// The number of entity instances deleted.
+ /// In case of Hibernate errors
+ /// If length for argument values and types are not equal.
+ public int Delete(String queryString, Object[] values, IType[] types)
+ {
+ if (values != null && types != null && values.Length != types.Length)
+ {
+ throw new ArgumentOutOfRangeException("values", "Length of values array must match length of types array");
+ }
+ return (int)Execute(new DeletebyQueryHibernateCallback(this, queryString, values, types),true);
+
+ }
+
+
+ ///
+ /// Delete all given persistent instances.
+ ///
+ /// The persistent instances to delete.
+ ///
+ /// This can be combined with any of the find methods to delete by query
+ /// in two lines of code, similar to Session's delete by query methods.
+ ///
+ /// In case of Hibernate errors
+ public void DeleteAll(ICollection entities)
+ {
+ Execute(new DeleteAllHibernateCallback(this, entities),true);
+ }
+
+
+ ///
+ /// Execute the action specified by the given action object within a Session.
+ ///
+ ///
+ /// Application exceptions thrown by the action object get propagated to the
+ /// caller (can only be unchecked). Hibernate exceptions are transformed into
+ /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
+ /// object or a collection of domain objects.
+ ///
Note: Callback code is not supposed to handle transactions itself!
+ /// Use an appropriate transaction manager like HibernateTransactionManager.
+ /// Generally, callback code must not touch any Session lifecycle methods,
+ /// like close, disconnect, or reconnect, to let the template do its work.
+ ///
+ ///
+ /// The delegate callback object that specifies the Hibernate action.
+ /// a result object returned by the action, or null
+ ///
+ /// In case of Hibernate errors
+ public object Execute(HibernateDelegate del)
+ {
+ return Execute(new ExecuteHibernateCallbackUsingDelegate(del));
+ }
+
+ ///
+ /// Execute the action specified by the delegate within a Session.
+ ///
+ /// The HibernateDelegate that specifies the action
+ /// to perform.
+ /// if set to true expose the native hibernate session to
+ /// callback code.
+ /// a result object returned by the action, or null
+ ///
+ public object Execute(HibernateDelegate del, bool exposeNativeSession)
+ {
+ return Execute(new ExecuteHibernateCallbackUsingDelegate(del), true);
+ }
+
+ ///
+ /// Execute the action specified by the given action object within a Session.
+ ///
+ /// The callback object that specifies the Hibernate action.
+ ///
+ /// a result object returned by the action, or null
+ ///
+ ///
+ /// Application exceptions thrown by the action object get propagated to the
+ /// caller (can only be unchecked). Hibernate exceptions are transformed into
+ /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
+ /// object or a collection of domain objects.
+ ///
Note: Callback code is not supposed to handle transactions itself!
+ /// Use an appropriate transaction manager like HibernateTransactionManager.
+ /// Generally, callback code must not touch any Session lifecycle methods,
+ /// like close, disconnect, or reconnect, to let the template do its work.
+ ///
+ ///
+ /// In case of Hibernate errors
+ public object Execute(IHibernateCallback action)
+ {
+ return Execute(action, ExposeNativeSession);
+ }
+
+ ///
+ /// Execute the specified action assuming that the result object is a List.
+ ///
+ ///
+ /// This is a convenience method for executing Hibernate find calls or
+ /// queries within an action.
+ ///
+ /// The calback object that specifies the Hibernate action.
+ /// A IList returned by the action, or null
+ ///
+ /// In case of Hibernate errors
+ public IList ExecuteFind(IHibernateCallback action)
+ {
+ Object result = Execute(action, ExposeNativeSession);
+ if (result != null && !(result is IList)) {
+ throw new InvalidDataAccessApiUsageException(
+ "Result object returned from HibernateCallback isn't a List: [" + result + "]");
+ }
+ return (IList) result;
+ }
+
+ ///
+ /// Execute the action specified by the given action object within a Session.
+ ///
+ /// callback object that specifies the Hibernate action.
+ /// if set to true expose the native hibernate session to
+ /// callback code.
+ ///
+ /// a result object returned by the action, or null
+ ///
+ public object Execute(IHibernateCallback action, bool exposeNativeSession)
+ {
+ ISession session = Session;
+
+ bool existingTransaction = SessionFactoryUtils.IsSessionTransactional(session, SessionFactory);
+ if (existingTransaction)
+ {
+ if(log.IsDebugEnabled) log.Debug("Found thread-bound Session for HibernateTemplate");
+ }
+
+ FlushModeHolder previousFlushModeHolder = new FlushModeHolder();
+ try
+ {
+ previousFlushModeHolder = ApplyFlushMode(session, existingTransaction);
+ ISession sessionToExpose = (exposeNativeSession ? session : CreateSessionProxy(session));
+ Object result = action.DoInHibernate(sessionToExpose);
+ FlushIfNecessary(session, existingTransaction);
+ return result;
+ }
+ catch (ADOException ex)
+ {
+ IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
+ if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException))
+ {
+ throw ConvertAdoAccessException(ex);
+ }
+ else
+ {
+ throw new HibernateSystemException(ex);
+ }
+ }
+ catch (HibernateException ex)
+ {
+ throw ConvertHibernateAccessException(ex);
+ }
+ catch (Exception ex)
+ {
+ IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
+ if (dbProvider != null && dbProvider.IsDataAccessException(ex))
+ {
+ throw ConvertAdoAccessException(ex);
+ }
+ else
+ {
+ // Callback code throw application exception or other non DB related exception.
+ throw;
+ }
+ }
+ finally
+ {
+ if (existingTransaction)
+ {
+ if (log.IsDebugEnabled) log.Debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
+ if (previousFlushModeHolder.ModeWasSet)
+ {
+ session.FlushMode = previousFlushModeHolder.Mode;
+ }
+ }
+ else
+ {
+ // Never use deferred close for an explicitly new Session.
+ if (AlwaysUseNewSession)
+ {
+ SessionFactoryUtils.CloseSession(session);
+ }
+ else
+ {
+ SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Execute a query for persistent instances.
+ ///
+ /// a query expressed in Hibernate's query language
+ ///
+ /// a List containing 0 or more persistent instances
+ ///
+ /// In case of Hibernate errors
+ public IList Find(string queryString)
+ {
+ return Find(queryString, (object[])null, (IType[])null );
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding
+ /// one value to a "?" parameter in the query string.
+ ///
+ /// a query expressed in Hibernate's query language
+ /// the value of the parameter
+ ///
+ /// a List containing 0 or more persistent instances
+ ///
+ /// In case of Hibernate errors
+ public IList Find(string queryString, object value)
+ {
+ return Find(queryString, new object[] {value}, (IType[]) null);
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding one value
+ /// to a "?" parameter of the given type in the query string.
+ ///
+ /// a query expressed in Hibernate's query language
+ /// The value of the parameter.
+ /// Hibernate type of the parameter (or null)
+ ///
+ /// a List containing 0 or more persistent instances
+ ///
+ /// In case of Hibernate errors
+ public IList Find(string queryString, object value, IType type)
+ {
+ return Find(queryString, new object[] {value}, new IType[] {type});
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding a
+ /// number of values to "?" parameters in the query string.
+ ///
+ /// a query expressed in Hibernate's query language
+ /// the values of the parameters
+ /// a List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList Find(string queryString, object[] values)
+ {
+ return Find(queryString, values, (IType[]) null);
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding a number of
+ /// values to "?" parameters of the given types in the query string.
+ ///
+ /// A query expressed in Hibernate's query language
+ /// The values of the parameters
+ /// Hibernate types of the parameters (or null)
+ ///
+ /// a List containing 0 or more persistent instances
+ ///
+ /// In case of Hibernate errors
+ /// If values and types are not null and their lengths are not equal
+ public IList Find(string queryString, object[] values, IType[] types)
+ {
+ if (values != null && types != null && values.Length != types.Length)
+ {
+ throw new ArgumentException("Length of values array must match length of types array");
+ }
+ return (IList)Execute(new FindHibernateCallback(this, queryString, values, types),true);
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding
+ /// one value to a named parameter in the query string.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The name of the parameter
+ /// The value of the parameter
+ /// a List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedParam(string queryName, string paramName, object value)
+ {
+ return FindByNamedParam(queryName, paramName, value, null);
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding
+ /// one value to a named parameter in the query string.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The name of the parameter
+ /// The value of the parameter
+ /// Hibernate type of the parameter (or null)
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedParam(string queryName, string paramName, object value, IType type)
+ {
+ return FindByNamedParam(queryName, new string[] {paramName}, new object[] {value}, new IType[] {type});
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding a
+ /// number of values to named parameters in the query string.
+ ///
+ /// A query expressed in Hibernate's query language
+ /// The names of the parameters
+ /// The values of the parameters
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedParam(string queryString, string[] paramNames, object[] values)
+ {
+ return FindByNamedParam(queryString, paramNames, values, null);
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding a
+ /// number of values to named parameters in the query string.
+ ///
+ /// A query expressed in Hibernate's query language
+ /// The names of the parameters
+ /// The values of the parameters
+ /// Hibernate types of the parameters (or null)
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ /// If paramNames length is not equal to values length or
+ /// if paramNames length is not equal to types length (when types is not null)
+ public IList FindByNamedParam(string queryString, string[] paramNames, object[] values, IType[] types)
+ {
+ if (paramNames.Length != values.Length)
+ {
+ throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of values array");
+ }
+ if (types != null && paramNames.Length != types.Length)
+ {
+ throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of types array");
+ }
+
+ return (IList)Execute(new FindByNamedParamHibernateCallback(this, queryString, paramNames, values, types),true);
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQuery(string queryName)
+ {
+ return FindByNamedQuery(queryName, (object[]) null, (IType[]) null);
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// one value to a "?" parameter in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The value of the parameter
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQuery(string queryName, object value)
+ {
+ return FindByNamedQuery(queryName, new object[] {value}, (IType[]) null);
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// one value to a "?" parameter in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The value of the parameter
+ /// Hibernate type of the parameter (or null)
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQuery(string queryName, object value, IType type)
+ {
+ return FindByNamedQuery(queryName, new object[] { value }, new IType[] { type });
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding a
+ /// number of values to "?" parameters in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The values of the parameters
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQuery(string queryName, object[] values)
+ {
+ return FindByNamedQuery(queryName, values, (IType[]) null);
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding a
+ /// number of values to "?" parameters in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The values of the parameters
+ /// Hibernate types of the parameters (or null)
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ /// If values and types are not null and their lengths differ.
+ public IList FindByNamedQuery(string queryName, object[] values, IType[] types)
+ {
+ if (values != null && types != null && values.Length != types.Length)
+ {
+ throw new ArgumentOutOfRangeException("Length of values array must match length of types array");
+ }
+ return (IList)Execute(new FindByNamedQueryHibernateCallback(this, queryName, values, types),true);
+
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// one value to a named parameter in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// Name of the parameter
+ /// The value of the parameter
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value)
+ {
+ return FindByNamedQueryAndNamedParam(queryName, paramName, value, null);
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// one value to a named parameter in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// Name of the parameter
+ /// The value of the parameter
+ /// The Hibernate type of the parameter (or null)
+ /// A List containing 0 or more persistent instances
+ public IList FindByNamedQueryAndNamedParam(string queryName, string paramName, object value, IType type)
+ {
+ return FindByNamedQueryAndNamedParam(
+ queryName, new string[] {paramName}, new object[] {value}, new IType[] {type});
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// number of values to named parameters in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The names of the parameters
+ /// The values of the parameters.
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values)
+ {
+ return FindByNamedQueryAndNamedParam(queryName, paramNames, values, null);
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding
+ /// number of values to named parameters in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The names of the parameters
+ /// The values of the parameters.
+ /// Hibernate types of the parameters (or null)
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ /// If paramNames length is not equal to values length or
+ /// if paramNames length is not equal to types length (when types is not null)
+ public IList FindByNamedQueryAndNamedParam(string queryName, string[] paramNames, object[] values, IType[] types)
+ {
+ if (paramNames != null && values != null && paramNames.Length != values.Length)
+ {
+ throw new ArgumentOutOfRangeException("paramNames","Length of paramNames array must match length of values array");
+ }
+ if (paramNames != null && types != null && paramNames.Length != types.Length)
+ {
+ throw new ArgumentOutOfRangeException("paramNams","Length of paramNames array must match length of types array");
+ }
+ return (IList)Execute(new FindByNamedQueryAndNamedParamHibernateCallback(this, queryName, paramNames, values, types),true);
+
+ }
+
+ ///
+ /// Execute a named query for persistent instances, binding the properties
+ /// of the given object to named parameters in the query string.
+ /// A named query is defined in a Hibernate mapping file.
+ ///
+ /// The name of a Hibernate query in a mapping file
+ /// The values of the parameters
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByNamedQueryAndValueObject(string queryName, object valueObject)
+ {
+ return (IList)Execute(new FindByNamedQueryAndValueObjectHibernateCallback(this, queryName, valueObject),true);
+
+ }
+
+ ///
+ /// Execute a query for persistent instances, binding the properties
+ /// of the given object to named parameters in the query string.
+ ///
+ /// A query expressed in Hibernate's query language
+ /// The values of the parameters
+ /// A List containing 0 or more persistent instances
+ /// In case of Hibernate errors
+ public IList FindByValueObject(string queryString, object valueObject)
+ {
+ return (IList)Execute(new FindByValueObjectHibernateCallback(this, queryString, valueObject), true);
+ }
+
+ #endregion
+
+ #region Methods
+
+
+ ///
+ /// Create a close-suppressing proxy for the given Hibernate Session.
+ /// The proxy also prepares returned Query and Criteria objects.
+ ///
+ /// The session.
+ /// The session proxy.
+ public virtual ISession CreateSessionProxy(ISession session)
+ {
+ //TODO can move to HibernateAccessor and make protected
+ // if issue reported with AOP+Multiple Threads resolve.
+ // have not been able to reproduce so added lock as a precaution.
+ //
+ lock (syncRoot)
+ {
+ if (sessionProxyFactory == null)
+ {
+ sessionProxyFactory = new ProxyFactory();
+ sessionProxyFactory.AddAdvice(new CloseSuppressingMethodInterceptor(this));
+ }
+
+ sessionProxyFactory.Target = session;
+
+ return (ISession)sessionProxyFactory.GetProxy();
+ }
+ }
+
+ ///
+ /// Check whether write operations are allowed on the given Session.
+ ///
+ ///
+ /// Default implementation throws an InvalidDataAccessApiUsageException
+ /// in case of FlushMode.Never. Can be overridden in subclasses.
+ ///
+ /// The current Hibernate session.
+ /// If write operation is attempted in read-only mode
+ ///
+ public virtual void CheckWriteOperationAllowed(ISession session)
+ {
+ if (CheckWriteOperations && TemplateFlushMode != TemplateFlushMode.Eager &&
+ AreEqualFlushMode(TemplateFlushMode.Never, session.FlushMode))
+ {
+ throw new InvalidDataAccessApiUsageException(
+ "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " +
+ "into FlushMode.AUTO or remove 'readOnly' marker from transaction definition");
+ }
+ }
+
+
+
+ ///
+ /// Compares if the flush mode enumerations, Spring's
+ /// TemplateFlushMode and NHibernates FlushMode have equal
+ /// settings.
+ ///
+ /// The template flush mode.
+ /// The NHibernate flush mode.
+ ///
+ /// Returns true if both are Never, Auto, or Commit, false
+ /// otherwise.
+ ///
+ protected bool AreEqualFlushMode(TemplateFlushMode tfm, FlushMode fm)
+ {
+ if ( (tfm ==TemplateFlushMode.Never && fm == FlushMode.Never) ||
+ (tfm ==TemplateFlushMode.Auto && fm == FlushMode.Auto) ||
+ (tfm ==TemplateFlushMode.Commit && fm == FlushMode.Commit) )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ //TODO other combinations.
+ }
+
+ #endregion
+ }
+
+ #region Internal Supporting Callback Classes
+
+ //TODO see if can create common base class for some callbacks.
+
+ internal class ContainsHibernateCallback : IHibernateCallback
+ {
+ private object entity;
+ public ContainsHibernateCallback(object entity)
+ {
+ this.entity = entity;
+ }
+
+ public object DoInHibernate(ISession session)
+ {
+ return session.Contains(entity);
+ }
+ }
+
+
+ internal class DeleteLockModeHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+ private LockMode lockMode;
+ public DeleteLockModeHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode)
+ {
+ this.outer = template;
+ this.entity = entity;
+ this.lockMode = lockMode;
+ }
+
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ if (lockMode != null)
+ {
+ session.Lock(entity, lockMode);
+ }
+ session.Delete(entity);
+ return null;
+ }
+ }
+
+
+ internal class DeletebyQueryHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private string queryString;
+ private object[] values;
+ private IType[] types;
+
+ public DeletebyQueryHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types)
+ {
+ this.outer = template;
+ this.queryString = queryString;
+ this.values = values;
+ this.types = types;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ if (values != null)
+ {
+ return session.Delete(queryString, values, types);
+ }
+ else
+ {
+ return session.Delete(queryString);
+ }
+ }
+ }
+
+
+
+ internal class DeleteAllHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private ICollection entities;
+
+ public DeleteAllHibernateCallback(HibernateTemplate template, ICollection entities)
+ {
+ this.outer = template;
+ this.entities = entities;
+
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ foreach (object entity in entities)
+ {
+ session.Delete(entity);
+ }
+ return null;
+ }
+
+
+
+ }
+
+
+ internal class EvictHibernateCallback : IHibernateCallback
+ {
+ private object entity;
+
+ public EvictHibernateCallback(object entity)
+ {
+ this.entity = entity;
+
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ session.Evict(entity);
+ return null;
+ }
+
+
+
+ }
+
+
+ internal class FindHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private string queryString;
+ private object[] values;
+ private IType[] types;
+
+ public FindHibernateCallback(HibernateTemplate template, string queryString, object[] values, IType[] types)
+ {
+ this.outer = template;
+ this.queryString = queryString;
+ this.values = values;
+ this.types = types;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.CreateQuery(queryString);
+ outer.PrepareQuery(queryObject);
+ if (values != null)
+ {
+ for (int i = 0; i < values.Length; i++)
+ {
+ if (types != null && types[i] != null)
+ {
+ queryObject.SetParameter(i, values[i], types[i]);
+ }
+ else
+ {
+ queryObject.SetParameter(i, values[i]);
+ }
+ }
+ }
+
+ return queryObject.List();
+ }
+ }
+
+
+ internal class FindByNamedParamHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private string queryString;
+ private string[] paramNames;
+ private object[] values;
+ private IType[] types;
+
+ public FindByNamedParamHibernateCallback(HibernateTemplate template, string queryString, string[] paramNames, object[] values, IType[] types)
+ {
+ this.outer = template;
+ this.queryString = queryString;
+ this.paramNames = paramNames;
+ this.values = values;
+ this.types = types;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.CreateQuery(queryString);
+ outer.PrepareQuery(queryObject);
+ if (values != null)
+ {
+ for (int i = 0; i < values.Length; i++)
+ {
+ outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
+ }
+ }
+ return queryObject.List();
+
+ }
+ }
+
+
+ internal class FindByNamedQueryHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private string queryName;
+ private object[] values;
+ private IType[] types;
+
+ public FindByNamedQueryHibernateCallback(HibernateTemplate template, string queryName, object[] values, IType[] types)
+ {
+ this.outer = template;
+ this.queryName = queryName;
+ this.values = values;
+ this.types = types;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.GetNamedQuery(queryName);
+ outer.PrepareQuery(queryObject);
+ if (values != null)
+ {
+ for (int i = 0; i < values.Length; i++)
+ {
+ if (types != null && types[i] != null)
+ {
+ queryObject.SetParameter(i, values[i], types[i]);
+ }
+ else
+ {
+ queryObject.SetParameter(i, values[i]);
+ }
+ }
+ }
+ return queryObject.List();
+
+ }
+ }
+
+
+ internal class FindByNamedQueryAndNamedParamHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private string queryName;
+ private string[] paramNames;
+ private object[] values;
+ private IType[] types;
+
+ public FindByNamedQueryAndNamedParamHibernateCallback(HibernateTemplate template, string queryName, string[] paramNames, object[] values, IType[] types)
+ {
+ this.outer = template;
+ this.queryName = queryName;
+ this.paramNames = paramNames;
+ this.values = values;
+ this.types = types;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.GetNamedQuery(queryName);
+ outer.PrepareQuery(queryObject);
+ if (values != null)
+ {
+ for (int i = 0; i < values.Length; i++)
+ {
+ outer.ApplyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
+ }
+ }
+ return queryObject.List();
+
+ }
+ }
+
+
+ internal class FindByNamedQueryAndValueObjectHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private string queryName;
+ private object valueObject;
+
+ public FindByNamedQueryAndValueObjectHibernateCallback(HibernateTemplate template, string queryName, object valueObject)
+ {
+ this.outer = template;
+ this.queryName = queryName;
+ this.valueObject = valueObject;
+
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.GetNamedQuery(queryName);
+ outer.PrepareQuery(queryObject);
+ queryObject.SetProperties(valueObject);
+ return queryObject.List();
+
+ }
+
+
+
+ }
+
+ internal class FindByValueObjectHibernateCallback : IHibernateCallback
+ {
+ HibernateTemplate outer;
+ private string queryString;
+ private object valueObject;
+
+ public FindByValueObjectHibernateCallback(HibernateTemplate template, string queryString, object valueObject)
+ {
+ this.outer = template;
+ this.queryString = queryString;
+ this.valueObject = valueObject;
+
+ }
+
+ public object DoInHibernate(ISession session)
+ {
+ IQuery queryObject = session.CreateQuery(queryString);
+ outer.PrepareQuery(queryObject);
+ queryObject.SetProperties(valueObject);
+ return queryObject.List();
+
+ }
+
+ }
+
+ internal class ExecuteHibernateCallbackUsingDelegate : IHibernateCallback
+ {
+ private HibernateDelegate del;
+
+ public ExecuteHibernateCallbackUsingDelegate(HibernateDelegate d)
+ {
+ del = d;
+ }
+
+ public object DoInHibernate(ISession session)
+ {
+ return del(session);
+ }
+ }
+
+
+ internal class GetByTypeHibernateCallback : IHibernateCallback
+ {
+ private Type entityType;
+ private object id;
+ private LockMode lockMode;
+
+ public GetByTypeHibernateCallback(Type entityType, object id, LockMode lockMode)
+ {
+ this.entityType = entityType;
+ this.id = id;
+ this.lockMode = lockMode;
+
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ if (lockMode != null)
+ {
+ return session.Get(entityType, id, lockMode);
+ }
+ else
+ {
+ return session.Get(entityType, id);
+ }
+ }
+
+
+
+ }
+
+
+ internal class LoadByTypeHibernateCallback : IHibernateCallback
+ {
+ private Type entityType;
+ private object id;
+ private LockMode lockMode;
+
+ public LoadByTypeHibernateCallback(Type entityType, object id, LockMode lockMode)
+ {
+ this.entityType = entityType;
+ this.id = id;
+ this.lockMode = lockMode;
+
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ if (lockMode != null)
+ {
+ return session.Load(entityType, id, lockMode);
+ }
+ else
+ {
+ return session.Load(entityType, id);
+ }
+ }
+
+
+
+ }
+
+
+ internal class LoadByEntityHibernateCallback : IHibernateCallback
+ {
+ private object entity;
+ private object id;
+
+ public LoadByEntityHibernateCallback(object entity, object id)
+ {
+ this.entity = entity;
+ this.id = id;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ session.Load(entity, id);
+ return null;
+ }
+
+
+
+ }
+
+
+ internal class LoadAllByTypeHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private Type entityType;
+
+ public LoadAllByTypeHibernateCallback(HibernateTemplate template, Type entityType)
+ {
+ outer = template;
+ this.entityType = entityType;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ ICriteria criteria = session.CreateCriteria(entityType);
+ outer.PrepareCriteria(criteria);
+ return criteria.List();
+ }
+ }
+
+
+ internal class LockHibernateCallback : IHibernateCallback
+ {
+ private object entity;
+ private LockMode lockMode;
+
+ public LockHibernateCallback(object entity, LockMode lockMode)
+ {
+ this.entity = entity;
+ this.lockMode = lockMode;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ session.Lock(entity, lockMode);
+ return null;
+ }
+ }
+
+
+ internal class RefreshHibernateCallback : IHibernateCallback
+ {
+ private object entity;
+ private LockMode lockMode;
+
+ public RefreshHibernateCallback(object entity, LockMode lockMode)
+ {
+ this.entity = entity;
+ this.lockMode = lockMode;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ if (lockMode != null)
+ {
+ session.Refresh(entity, lockMode);
+ }
+ else
+ {
+ session.Refresh(entity);
+ }
+ return null;
+ }
+ }
+
+
+ internal class SaveObjectHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+
+ public SaveObjectHibernateCallback(HibernateTemplate template, object entity)
+ {
+ this.outer = template;
+ this.entity = entity;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ return session.Save(entity);
+ }
+ }
+
+
+ internal class SaveObjectWithIdHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+ private object id;
+
+ public SaveObjectWithIdHibernateCallback(HibernateTemplate template, object entity, object id)
+ {
+ this.outer = template;
+ this.entity = entity;
+ this.id = id;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ session.Save(entity, id);
+ return null;
+ }
+ }
+
+
+ internal class UpdateObjectHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+ private LockMode lockMode;
+
+ public UpdateObjectHibernateCallback(HibernateTemplate template, object entity, LockMode lockMode)
+ {
+ this.outer = template;
+ this.entity = entity;
+ this.lockMode = lockMode;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ session.Update(entity);
+ if (lockMode != null)
+ {
+ session.Lock(entity, lockMode);
+ }
+ return null;
+ }
+ }
+
+
+ internal class SaveOrUpdateObjectHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+
+ public SaveOrUpdateObjectHibernateCallback(HibernateTemplate template, object entity)
+ {
+ this.outer = template;
+ this.entity = entity;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ session.SaveOrUpdate(entity);
+ return null;
+ }
+ }
+
+ internal class SaveOrUpdateAllHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private ICollection entities;
+
+ public SaveOrUpdateAllHibernateCallback(HibernateTemplate template, ICollection entities)
+ {
+ this.outer = template;
+ this.entities = entities;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
+ ///
+ public object DoInHibernate(ISession session)
+ {
+ outer.CheckWriteOperationAllowed(session);
+ foreach (object entity in entities)
+ {
+ session.SaveOrUpdate(entity);
+ }
+ return null;
+ }
+ }
+ internal class SaveOrUpdateCopyHibernateCallback : IHibernateCallback
+ {
+ private HibernateTemplate outer;
+ private object entity;
+
+ public SaveOrUpdateCopyHibernateCallback(HibernateTemplate template, object entity)
+ {
+ this.outer = template;
+ this.entity = entity;
+ }
+
+ ///
+ /// Gets called by HibernateTemplate with an active
+ /// Hibernate Session. Does not need to care about activating or closing
+ /// the Session, or handling transactions.
+ ///
+ ///
+ ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
Requires the object factory to be known, to be able to resolve the object
- /// name to an interceptor instance on session creation. Typically used for
- /// prototype interceptors, i.e. a new interceptor instance per session.
- ///
- ///
Can also be used for shared interceptor instances, but it is recommended
- /// to set the interceptor reference directly in such a scenario.
- ///
- ///
- public string EntityInterceptorObjectName
- {
- set
- {
- entityInterceptor = value;
- }
- }
-
- ///
- /// Gets or sets the ADO.NET exception translator for this transaction manager.
- ///
- ///
- /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException)
- ///
- /// The ADO exception translator.
- public IAdoExceptionTranslator AdoExceptionTranslator
- {
- get { return adoExceptionTranslator; }
- set { adoExceptionTranslator = value; }
- }
-
- ///
- /// Gets the default IAdoException translator, lazily creating it if nece
- ///
- /// The default IAdoException translator.
- public IAdoExceptionTranslator DefaultAdoExceptionTranslator
- {
- get
- { lock(this)
- {
- if (defaultExceptionTranslator == null)
- {
- if (dbProvider != null)
- {
- defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider);
- }
- else
- {
- defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory);
- }
- }
- return defaultExceptionTranslator;
- }
- }
- }
-
- ///
- /// Gets or sets the SessionFactory that this instance should manage transactions for.
- ///
- /// The session factory.
- public ISessionFactory SessionFactory
- {
- get { return sessionFactory; }
- set { sessionFactory = value; }
- }
-
- ///
- /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory,
- /// if set via LocalSessionFactoryObject's DbProvider. Default is "true".
- ///
- ///
- /// true if [autodetect data source]; otherwise, false.
- ///
- ///
- ///
Can be turned off to deliberately ignore an available IDbProvider,
- /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider.
- ///
- ///
- public bool AutodetectDbProvider
- {
- set { autodetectDbProvider = value; }
- }
-
- #endregion
-
- #region Methods
-
- #endregion
-
-
- ///
- /// The object factory just needs to be known for resolving entity interceptor
- /// It does not need to be set for any other mode of operation.
- ///
- ///
- /// Owning
- /// (may not be ). The object can immediately
- /// call methods on the factory.
- ///
- public IObjectFactory ObjectFactory
- {
- set
- {
- objectFactory = value;
- }
- }
-
- ///
- /// Return the current transaction object.
- ///
- /// The current transaction object.
- ///
- /// If transaction support is not available.
- ///
- ///
- /// In the case of lookup or system errors.
- ///
- protected override object DoGetTransaction()
- {
- HibernateTransactionObject txObject = new HibernateTransactionObject();
- txObject.SavepointAllowed = NestedTransactionsAllowed;
- if (TransactionSynchronizationManager.HasResource(SessionFactory))
- {
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.GetResource(SessionFactory);
- if (log.IsDebugEnabled)
- {
- log.Debug("Found thread-bound Session [" + sessionHolder.Session +
- "] for Hibernate transaction");
- }
- txObject.SetSessionHolder(sessionHolder, false);
- if (DbProvider != null)
- {
- ConnectionHolder conHolder = (ConnectionHolder)
- TransactionSynchronizationManager.GetResource(DbProvider);
- txObject.ConnectionHolder = conHolder;
- }
- }
- return txObject;
- }
-
- ///
- /// Check if the given transaction object indicates an existing,
- /// i.e. already begun, transaction.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- /// True if there is an existing transaction.
- ///
- /// In the case of system errors.
- ///
- protected override bool IsExistingTransaction(object transaction)
- {
- return ((HibernateTransactionObject) transaction).HasTransaction();
- }
-
- ///
- /// Begin a new transaction with the given transaction definition.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- ///
- /// instance, describing
- /// propagation behavior, isolation level, timeout etc.
- ///
- ///
- /// Does not have to care about applying the propagation behavior,
- /// as this has already been handled by this abstract manager.
- ///
- ///
- /// In the case of creation or system errors.
- ///
- protected override void DoBegin(object transaction, ITransactionDefinition definition)
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
-
- if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider)
- && !txObject.ConnectionHolder.SynchronizedWithTransaction)
- {
- throw new IllegalTransactionStateException(
- "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " +
- "running within AdoTransactionManager if told to manage the DbProvider itself. " +
- "It is recommended to use a single HibernateTransactionManager for all transactions " +
- "on a single DbProvider, no matter whether Hibernate or ADO.NET access.");
- }
- ISession session = null;
- try
- {
-
- if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction)
- {
- IInterceptor interceptor = EntityInterceptor;
- ISession newSession = (interceptor != null ?
- SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession());
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Opened new Session [" + newSession + "] for Hibernate transaction");
- }
- txObject.SetSessionHolder(new SessionHolder(newSession), true);
-
- }
- txObject.SessionHolder.SynchronizedWithTransaction = true;
- session = txObject.SessionHolder.Session;
-
- IDbConnection con = session.Connection;
- //TODO isolation level mgmt
- //IsolationLevel previousIsolationLevel =
-
- if (definition.ReadOnly && txObject.NewSessionHolder)
- {
- // Just set to NEVER in case of a new Session for this transaction.
- session.FlushMode = FlushMode.Never;
- }
-
- if (!definition.ReadOnly && !txObject.NewSessionHolder)
- {
- // We need AUTO or COMMIT for a non-read-only transaction.
- FlushMode flushMode = session.FlushMode;
- if (FlushMode.Never == flushMode)
- {
- session.FlushMode = FlushMode.Auto;
- txObject.SessionHolder.PreviousFlushMode = flushMode;
- }
- }
-
- // Add the Hibernate transaction to the session holder.
- // for now pass in tx options isolation level.
- ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel);
- IDbTransaction adoTx = GetIDbTransaction(hibernateTx);
-
- // Add the Hibernate transaction to the session holder.
- txObject.SessionHolder.Transaction = hibernateTx;
-
- // Register transaction timeout.
- int timeout = DetermineTimeout(definition);
- if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
- {
- txObject.SessionHolder.TimeoutInSeconds = timeout;
- }
-
- // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set.
- if (DbProvider != null)
- {
- //investigate passing null for tx.
- ConnectionHolder conHolder = new ConnectionHolder(con, adoTx);
- if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
- {
- conHolder.TimeoutInMillis = definition.TransactionTimeout;
- }
- if (log.IsDebugEnabled)
- {
- log.Debug("Exposing Hibernate transaction as ADO transaction [" + con + "]");
- }
- TransactionSynchronizationManager.BindResource(DbProvider, conHolder);
- txObject.ConnectionHolder = conHolder;
- }
-
- // Bind the session holder to the thread.
- if (txObject.NewSessionHolder)
- {
- TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder);
- }
-
- } catch (Exception ex)
- {
- SessionFactoryUtils.CloseSession(session);
- throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
- }
-
-
- }
-
-
-
-
- ///
- /// Suspend the resources of the current transaction.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- ///
- /// An object that holds suspended resources (will be kept unexamined for passing it into
- /// .)
- ///
- ///
- /// Transaction synchronization will already have been suspended.
- ///
- ///
- /// If suspending is not supported by the transaction manager implementation.
- ///
- ///
- /// in case of system errors.
- ///
- protected override object DoSuspend(object transaction)
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
- txObject.SetSessionHolder(null, false);
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.UnbindResource(SessionFactory);
- ConnectionHolder connectionHolder = null;
- if (DbProvider != null)
- {
- connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider);
- }
- return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
-
- }
-
- ///
- /// Resume the resources of the current transaction.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- ///
- /// The object that holds suspended resources as returned by
- /// .
- ///
- ///
- /// Transaction synchronization will be resumed afterwards.
- ///
- ///
- /// If suspending is not supported by the transaction manager implementation.
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoResume(object transaction, object suspendedResources)
- {
- SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
- if (TransactionSynchronizationManager.HasResource(SessionFactory))
- {
- // From non-transactional code running in active transaction synchronization
- // -> can be safely removed, will be closed on transaction completion.
- TransactionSynchronizationManager.UnbindResource(SessionFactory);
- }
- TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder);
- if (DbProvider != null)
- {
- TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder);
- }
- }
-
- ///
- /// Perform an actual commit on the given transaction.
- ///
- /// The status representation of the transaction.
- ///
- ///
- /// An implementation does not need to check the rollback-only flag.
- ///
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoCommit(DefaultTransactionStatus status)
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
- if (status.Debug)
- {
- log.Debug("Committing Hibernate transaction on Session [" +
- txObject.SessionHolder.Session + "]");
- }
- try
- {
- txObject.SessionHolder.Transaction.Commit();
- }
- // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException
- // and Spring.Data.NHibernate requires this wierd construct.
- catch (Exception ex)
- {
- Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate");
- if (ex.GetType().Equals(nhibTxExceptiontype))
- {
- // assumably from commit call to the underlying ADO.NET connection
- throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
- }
- HibernateException hibEx = ex as HibernateException;
- if (hibEx != null)
- {
- // assumably failed to flush changes to database
- throw ConvertHibernateAccessException(hibEx);
- }
- throw;
- }
- }
-
- ///
- /// Perform an actual rollback on the given transaction.
- ///
- /// The status representation of the transaction.
- ///
- /// An implementation does not need to check the new transaction flag.
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoRollback(DefaultTransactionStatus status)
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
- if (status.Debug)
- {
- log.Debug("Rolling back Hibernate transaction on Session [" +
- txObject.SessionHolder.Session + "]");
- }
- try
- {
- txObject.SessionHolder.Transaction.Rollback();
- }
- catch (HibernateTransactionException ex)
- {
- throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
- }
- catch (HibernateException ex)
- {
- // Shouldn't really happen, as a rollback doesn't cause a flush.
- throw ConvertHibernateAccessException(ex);
- }
- finally
- {
- if (!txObject.NewSessionHolder)
- {
- // Clear all pending inserts/updates/deletes in the Session.
- // Necessary for pre-bound Sessions, to avoid inconsistent state.
- txObject.SessionHolder.Session.Clear();
- }
- }
-
-
-
- }
-
-
- ///
- /// Set the given transaction rollback-only. Only called on rollback
- /// if the current transaction takes part in an existing one.
- ///
- /// The status representation of the transaction.
- ///
- /// In the case of system errors.
- ///
- protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
- if (status.Debug)
- {
- log.Debug("Setting Hibernate transaction on Session [" +
- txObject.SessionHolder.Session + "] rollback-only");
- }
- txObject.SetRollbackOnly();
- }
-
-
- ///
- /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object.
- ///
- /// The hibernate transaction.
- /// The ADO.NET transaction. Null if could not get the transaction. Warning
- /// messages will be logged in that case.
- protected IDbTransaction GetIDbTransaction(ITransaction hibernateTx)
- {
- AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction;
-
- IDbTransaction adoTransaction = null;
- if (hibernateAdoTx != null)
- {
- try
- {
- FieldInfo fi = hibernateAdoTx.GetType().GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic);
- adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction;
- }
- catch (Exception e)
- {
- log.Warn("Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans.", e);
- }
- }
- else
- {
- log.Warn("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction.");
- }
- return adoTransaction;
- }
-
- ///
- /// Convert the given HibernateException to an appropriate exception from
- /// the Spring.Dao hierarchy. Can be overridden in subclasses.
- ///
- /// The HibernateException that occured.
- /// The corresponding DataAccessException instance
- protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex)
- {
- if (AdoExceptionTranslator != null && ex is ADOException)
- {
- return ConvertAdoAccessException((ADOException) ex, AdoExceptionTranslator);
- }
- else if (ex is ADOException)
- {
- return ConvertAdoAccessException((ADOException)ex, DefaultAdoExceptionTranslator);
- }
- return SessionFactoryUtils.ConvertHibernateAccessException(ex);
- }
-
- ///
- /// Convert the given ADOException to an appropriate exception from the
- /// the Spring.Dao hierarchy. Can be overridden in subclasses.
- ///
- /// The ADOException that occured, wrapping the underlying
- /// ADO.NET thrown exception.
- /// The translator to convert hibernate ADOExceptions.
- ///
- /// The corresponding DataAccessException instance
- ///
- protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator)
- {
- return translator.Translate("Hibernate flusing: " + ex.Message, null, ex.InnerException);
- }
-
- ///
- /// Cleanup resources after transaction completion.
- ///
- /// Transaction object returned by
- /// .
- ///
- ///
- /// This implemenation unbinds the SessionFactory and
- /// DbProvider from thread local storage and closes the
- /// ISession.
- ///
- ///
- /// Called after
- /// and
- ///
- /// execution on any outcome.
- ///
- ///
- /// Should not throw any exceptions but just issue warnings on errors.
- ///
- ///
- protected override void DoCleanupAfterCompletion( object transaction )
- {
- HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
-
- // Remove the session holder from the thread.
- if (txObject.NewSessionHolder)
- {
- TransactionSynchronizationManager.UnbindResource(SessionFactory);
- }
- // Remove the ADO.NET connection holder from the thread, if exposed.
- if (DbProvider != null)
- {
- TransactionSynchronizationManager.UnbindResource(DbProvider);
- }
- /*
- try
- {
- //TODO investigate isolation level settings...
- //IDbConnection con = txObject.SessionHolder.Session.Connection;
- //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel);
- }
- catch (HibernateException ex)
- {
- log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex);
- }
- */
- ISession session = txObject.SessionHolder.Session;
- if (txObject.NewSessionHolder)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("Closing Hibernate Session [" + session + "] after transaction");
- }
- SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
- }
- else
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
- }
- if (txObject.SessionHolder.AssignedPreviousFlushMode)
- {
- session.FlushMode = txObject.SessionHolder.PreviousFlushMode;
- }
- }
- txObject.SessionHolder.Clear();
-
-
- }
-
- private class HibernateTransactionObject : AdoTransactionObjectSupport
- {
-
- private SessionHolder sessionHolder;
-
- private bool newSessionHolder;
-
-
- public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder)
- {
- this.sessionHolder = sessionHolder;
- this.newSessionHolder = newSessionHolder;
- }
-
-
- public SessionHolder SessionHolder
- {
- get
- {
- return sessionHolder;
- }
- }
-
- public bool NewSessionHolder
- {
- get
- {
- return newSessionHolder;
- }
- }
-
- public bool HasTransaction()
- {
- return (this.sessionHolder != null && this.sessionHolder.Transaction != null);
- }
-
- public void SetRollbackOnly()
- {
- SessionHolder.RollbackOnly = true;
- if (ConnectionHolder != null)
- {
- ConnectionHolder.RollbackOnly = true;
- }
- }
-
- ///
- /// Return whether the transaction is internally marked as rollback-only.
- ///
- ///
- /// True of the transaction is marked as rollback-only.
- public override bool RollbackOnly
- {
- get
- {
- return SessionHolder.RollbackOnly ||
- (ConnectionHolder != null && ConnectionHolder.RollbackOnly);
- }
- }
- }
-
- private class SuspendedResourcesHolder
- {
-
- private readonly SessionHolder sessionHolder;
-
- private readonly ConnectionHolder connectionHolder;
-
- public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder)
- {
- this.sessionHolder = sessionHolder;
- this.connectionHolder = conHolder;
- }
-
- public SessionHolder SessionHolder
- {
- get
- {
- return sessionHolder;
- }
-
- }
-
- public ConnectionHolder ConnectionHolder
- {
- get
- {
- return connectionHolder;
- }
-
- }
- }
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
Requires the object factory to be known, to be able to resolve the object
+ /// name to an interceptor instance on session creation. Typically used for
+ /// prototype interceptors, i.e. a new interceptor instance per session.
+ ///
+ ///
Can also be used for shared interceptor instances, but it is recommended
+ /// to set the interceptor reference directly in such a scenario.
+ ///
+ ///
+ public string EntityInterceptorObjectName
+ {
+ set
+ {
+ entityInterceptor = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the ADO.NET exception translator for this transaction manager.
+ ///
+ ///
+ /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException)
+ ///
+ /// The ADO exception translator.
+ public IAdoExceptionTranslator AdoExceptionTranslator
+ {
+ get { return adoExceptionTranslator; }
+ set { adoExceptionTranslator = value; }
+ }
+
+ ///
+ /// Gets the default IAdoException translator, lazily creating it if nece
+ ///
+ /// The default IAdoException translator.
+ public IAdoExceptionTranslator DefaultAdoExceptionTranslator
+ {
+ get
+ { lock(this)
+ {
+ if (defaultExceptionTranslator == null)
+ {
+ if (dbProvider != null)
+ {
+ defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider);
+ }
+ else
+ {
+ defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory);
+ }
+ }
+ return defaultExceptionTranslator;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the SessionFactory that this instance should manage transactions for.
+ ///
+ /// The session factory.
+ public ISessionFactory SessionFactory
+ {
+ get { return sessionFactory; }
+ set { sessionFactory = value; }
+ }
+
+ ///
+ /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory,
+ /// if set via LocalSessionFactoryObject's DbProvider. Default is "true".
+ ///
+ ///
+ /// true if [autodetect data source]; otherwise, false.
+ ///
+ ///
+ ///
Can be turned off to deliberately ignore an available IDbProvider,
+ /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider.
+ ///
+ ///
+ public bool AutodetectDbProvider
+ {
+ set { autodetectDbProvider = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ #endregion
+
+
+ ///
+ /// The object factory just needs to be known for resolving entity interceptor
+ /// It does not need to be set for any other mode of operation.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ public IObjectFactory ObjectFactory
+ {
+ set
+ {
+ objectFactory = value;
+ }
+ }
+
+ ///
+ /// Return the current transaction object.
+ ///
+ /// The current transaction object.
+ ///
+ /// If transaction support is not available.
+ ///
+ ///
+ /// In the case of lookup or system errors.
+ ///
+ protected override object DoGetTransaction()
+ {
+ HibernateTransactionObject txObject = new HibernateTransactionObject();
+ txObject.SavepointAllowed = NestedTransactionsAllowed;
+ if (TransactionSynchronizationManager.HasResource(SessionFactory))
+ {
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.GetResource(SessionFactory);
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Found thread-bound Session [" + sessionHolder.Session +
+ "] for Hibernate transaction");
+ }
+ txObject.SetSessionHolder(sessionHolder, false);
+ if (DbProvider != null)
+ {
+ ConnectionHolder conHolder = (ConnectionHolder)
+ TransactionSynchronizationManager.GetResource(DbProvider);
+ txObject.ConnectionHolder = conHolder;
+ }
+ }
+ return txObject;
+ }
+
+ ///
+ /// Check if the given transaction object indicates an existing,
+ /// i.e. already begun, transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ /// True if there is an existing transaction.
+ ///
+ /// In the case of system errors.
+ ///
+ protected override bool IsExistingTransaction(object transaction)
+ {
+ return ((HibernateTransactionObject) transaction).HasTransaction();
+ }
+
+ ///
+ /// Begin a new transaction with the given transaction definition.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// instance, describing
+ /// propagation behavior, isolation level, timeout etc.
+ ///
+ ///
+ /// Does not have to care about applying the propagation behavior,
+ /// as this has already been handled by this abstract manager.
+ ///
+ ///
+ /// In the case of creation or system errors.
+ ///
+ protected override void DoBegin(object transaction, ITransactionDefinition definition)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+
+ if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider)
+ && !txObject.ConnectionHolder.SynchronizedWithTransaction)
+ {
+ throw new IllegalTransactionStateException(
+ "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " +
+ "running within AdoTransactionManager if told to manage the DbProvider itself. " +
+ "It is recommended to use a single HibernateTransactionManager for all transactions " +
+ "on a single DbProvider, no matter whether Hibernate or ADO.NET access.");
+ }
+ ISession session = null;
+ try
+ {
+
+ if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction)
+ {
+ IInterceptor interceptor = EntityInterceptor;
+ ISession newSession = (interceptor != null ?
+ SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession());
+
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Opened new Session [" + newSession + "] for Hibernate transaction");
+ }
+ txObject.SetSessionHolder(new SessionHolder(newSession), true);
+
+ }
+ txObject.SessionHolder.SynchronizedWithTransaction = true;
+ session = txObject.SessionHolder.Session;
+
+ IDbConnection con = session.Connection;
+ //TODO isolation level mgmt
+ //IsolationLevel previousIsolationLevel =
+
+ if (definition.ReadOnly && txObject.NewSessionHolder)
+ {
+ // Just set to NEVER in case of a new Session for this transaction.
+ session.FlushMode = FlushMode.Never;
+ }
+
+ if (!definition.ReadOnly && !txObject.NewSessionHolder)
+ {
+ // We need AUTO or COMMIT for a non-read-only transaction.
+ FlushMode flushMode = session.FlushMode;
+ if (FlushMode.Never == flushMode)
+ {
+ session.FlushMode = FlushMode.Auto;
+ txObject.SessionHolder.PreviousFlushMode = flushMode;
+ }
+ }
+
+ // Add the Hibernate transaction to the session holder.
+ // for now pass in tx options isolation level.
+ ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel);
+ IDbTransaction adoTx = GetIDbTransaction(hibernateTx);
+
+ // Add the Hibernate transaction to the session holder.
+ txObject.SessionHolder.Transaction = hibernateTx;
+
+ // Register transaction timeout.
+ int timeout = DetermineTimeout(definition);
+ if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
+ {
+ txObject.SessionHolder.TimeoutInSeconds = timeout;
+ }
+
+ // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set.
+ if (DbProvider != null)
+ {
+ //investigate passing null for tx.
+ ConnectionHolder conHolder = new ConnectionHolder(con, adoTx);
+ if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
+ {
+ conHolder.TimeoutInMillis = definition.TransactionTimeout;
+ }
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Exposing Hibernate transaction as ADO transaction [" + con + "]");
+ }
+ TransactionSynchronizationManager.BindResource(DbProvider, conHolder);
+ txObject.ConnectionHolder = conHolder;
+ }
+
+ // Bind the session holder to the thread.
+ if (txObject.NewSessionHolder)
+ {
+ TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder);
+ }
+
+ } catch (Exception ex)
+ {
+ SessionFactoryUtils.CloseSession(session);
+ throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
+ }
+
+
+ }
+
+
+
+
+ ///
+ /// Suspend the resources of the current transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// An object that holds suspended resources (will be kept unexamined for passing it into
+ /// .)
+ ///
+ ///
+ /// Transaction synchronization will already have been suspended.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// in case of system errors.
+ ///
+ protected override object DoSuspend(object transaction)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+ txObject.SetSessionHolder(null, false);
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.UnbindResource(SessionFactory);
+ ConnectionHolder connectionHolder = null;
+ if (DbProvider != null)
+ {
+ connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider);
+ }
+ return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
+
+ }
+
+ ///
+ /// Resume the resources of the current transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// The object that holds suspended resources as returned by
+ /// .
+ ///
+ ///
+ /// Transaction synchronization will be resumed afterwards.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoResume(object transaction, object suspendedResources)
+ {
+ SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
+ if (TransactionSynchronizationManager.HasResource(SessionFactory))
+ {
+ // From non-transactional code running in active transaction synchronization
+ // -> can be safely removed, will be closed on transaction completion.
+ TransactionSynchronizationManager.UnbindResource(SessionFactory);
+ }
+ TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder);
+ if (DbProvider != null)
+ {
+ TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder);
+ }
+ }
+
+ ///
+ /// Perform an actual commit on the given transaction.
+ ///
+ /// The status representation of the transaction.
+ ///
+ ///
+ /// An implementation does not need to check the rollback-only flag.
+ ///
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoCommit(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Committing Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "]");
+ }
+ try
+ {
+ txObject.SessionHolder.Transaction.Commit();
+ }
+ // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException
+ // and Spring.Data.NHibernate requires this wierd construct.
+ catch (Exception ex)
+ {
+ Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate");
+ if (ex.GetType().Equals(nhibTxExceptiontype))
+ {
+ // assumably from commit call to the underlying ADO.NET connection
+ throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
+ }
+ HibernateException hibEx = ex as HibernateException;
+ if (hibEx != null)
+ {
+ // assumably failed to flush changes to database
+ throw ConvertHibernateAccessException(hibEx);
+ }
+ throw;
+ }
+ }
+
+ ///
+ /// Perform an actual rollback on the given transaction.
+ ///
+ /// The status representation of the transaction.
+ ///
+ /// An implementation does not need to check the new transaction flag.
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoRollback(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Rolling back Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "]");
+ }
+ try
+ {
+ txObject.SessionHolder.Transaction.Rollback();
+ }
+ catch (HibernateTransactionException ex)
+ {
+ throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
+ }
+ catch (HibernateException ex)
+ {
+ // Shouldn't really happen, as a rollback doesn't cause a flush.
+ throw ConvertHibernateAccessException(ex);
+ }
+ finally
+ {
+ if (!txObject.NewSessionHolder)
+ {
+ // Clear all pending inserts/updates/deletes in the Session.
+ // Necessary for pre-bound Sessions, to avoid inconsistent state.
+ txObject.SessionHolder.Session.Clear();
+ }
+ }
+
+
+
+ }
+
+
+ ///
+ /// Set the given transaction rollback-only. Only called on rollback
+ /// if the current transaction takes part in an existing one.
+ ///
+ /// The status representation of the transaction.
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Setting Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "] rollback-only");
+ }
+ txObject.SetRollbackOnly();
+ }
+
+
+ ///
+ /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object.
+ ///
+ /// The hibernate transaction.
+ /// The ADO.NET transaction. Null if could not get the transaction. Warning
+ /// messages will be logged in that case.
+ protected IDbTransaction GetIDbTransaction(ITransaction hibernateTx)
+ {
+ AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction;
+
+ IDbTransaction adoTransaction = null;
+ if (hibernateAdoTx != null)
+ {
+ try
+ {
+ FieldInfo fi = hibernateAdoTx.GetType().GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic);
+ adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction;
+ }
+ catch (Exception e)
+ {
+ log.Warn("Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans.", e);
+ }
+ }
+ else
+ {
+ log.Warn("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction.");
+ }
+ return adoTransaction;
+ }
+
+ ///
+ /// Convert the given HibernateException to an appropriate exception from
+ /// the Spring.Dao hierarchy. Can be overridden in subclasses.
+ ///
+ /// The HibernateException that occured.
+ /// The corresponding DataAccessException instance
+ protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex)
+ {
+ if (AdoExceptionTranslator != null && ex is ADOException)
+ {
+ return ConvertAdoAccessException((ADOException) ex, AdoExceptionTranslator);
+ }
+ else if (ex is ADOException)
+ {
+ return ConvertAdoAccessException((ADOException)ex, DefaultAdoExceptionTranslator);
+ }
+ return SessionFactoryUtils.ConvertHibernateAccessException(ex);
+ }
+
+ ///
+ /// Convert the given ADOException to an appropriate exception from the
+ /// the Spring.Dao hierarchy. Can be overridden in subclasses.
+ ///
+ /// The ADOException that occured, wrapping the underlying
+ /// ADO.NET thrown exception.
+ /// The translator to convert hibernate ADOExceptions.
+ ///
+ /// The corresponding DataAccessException instance
+ ///
+ protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator)
+ {
+ return translator.Translate("Hibernate flusing: " + ex.Message, null, ex.InnerException);
+ }
+
+ ///
+ /// Cleanup resources after transaction completion.
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// This implemenation unbinds the SessionFactory and
+ /// DbProvider from thread local storage and closes the
+ /// ISession.
+ ///
+ ///
+ /// Called after
+ /// and
+ ///
+ /// execution on any outcome.
+ ///
+ ///
+ /// Should not throw any exceptions but just issue warnings on errors.
+ ///
+ ///
+ protected override void DoCleanupAfterCompletion( object transaction )
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+
+ // Remove the session holder from the thread.
+ if (txObject.NewSessionHolder)
+ {
+ TransactionSynchronizationManager.UnbindResource(SessionFactory);
+ }
+ // Remove the ADO.NET connection holder from the thread, if exposed.
+ if (DbProvider != null)
+ {
+ TransactionSynchronizationManager.UnbindResource(DbProvider);
+ }
+ /*
+ try
+ {
+ //TODO investigate isolation level settings...
+ //IDbConnection con = txObject.SessionHolder.Session.Connection;
+ //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel);
+ }
+ catch (HibernateException ex)
+ {
+ log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex);
+ }
+ */
+ ISession session = txObject.SessionHolder.Session;
+ if (txObject.NewSessionHolder)
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Closing Hibernate Session [" + session + "] after transaction");
+ }
+ SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
+ }
+ else
+ {
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
+ }
+ if (txObject.SessionHolder.AssignedPreviousFlushMode)
+ {
+ session.FlushMode = txObject.SessionHolder.PreviousFlushMode;
+ }
+ }
+ txObject.SessionHolder.Clear();
+
+
+ }
+
+ private class HibernateTransactionObject : AdoTransactionObjectSupport
+ {
+
+ private SessionHolder sessionHolder;
+
+ private bool newSessionHolder;
+
+
+ public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder)
+ {
+ this.sessionHolder = sessionHolder;
+ this.newSessionHolder = newSessionHolder;
+ }
+
+
+ public SessionHolder SessionHolder
+ {
+ get
+ {
+ return sessionHolder;
+ }
+ }
+
+ public bool NewSessionHolder
+ {
+ get
+ {
+ return newSessionHolder;
+ }
+ }
+
+ public bool HasTransaction()
+ {
+ return (this.sessionHolder != null && this.sessionHolder.Transaction != null);
+ }
+
+ public void SetRollbackOnly()
+ {
+ SessionHolder.RollbackOnly = true;
+ if (ConnectionHolder != null)
+ {
+ ConnectionHolder.RollbackOnly = true;
+ }
+ }
+
+ ///
+ /// Return whether the transaction is internally marked as rollback-only.
+ ///
+ ///
+ /// True of the transaction is marked as rollback-only.
+ public override bool RollbackOnly
+ {
+ get
+ {
+ return SessionHolder.RollbackOnly ||
+ (ConnectionHolder != null && ConnectionHolder.RollbackOnly);
+ }
+ }
+ }
+
+ private class SuspendedResourcesHolder
+ {
+
+ private readonly SessionHolder sessionHolder;
+
+ private readonly ConnectionHolder connectionHolder;
+
+ public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder)
+ {
+ this.sessionHolder = sessionHolder;
+ this.connectionHolder = conHolder;
+ }
+
+ public SessionHolder SessionHolder
+ {
+ get
+ {
+ return sessionHolder;
+ }
+
+ }
+
+ public ConnectionHolder ConnectionHolder
+ {
+ get
+ {
+ return connectionHolder;
+ }
+
+ }
+ }
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
Provides HibernateTemplate's data access methods that mirror
- /// various Session methods. See the NHibernate ISession documentation
- /// for details on those methods.
- ///
Provides HibernateTemplate's data access methods that mirror
+ /// various Session methods. See the NHibernate ISession documentation
+ /// for details on those methods.
+ ///
- /// Allows for returning a result object created within the callback, i.e.
- /// a domain object or a collection of domain objects. Note that there's
- /// special support for single step actions: see HibernateTemplate.find etc.
- ///
+ /// Allows for returning a result object created within the callback, i.e.
+ /// a domain object or a collection of domain objects. Note that there's
+ /// special support for single step actions: see HibernateTemplate.find etc.
+ ///
Provides HibernateTemplate's data access methods that mirror
- /// various Session methods. See the NHibernate ISession documentation
- /// for details on those methods.
- ///
- ///
- ///
- /// Mark Pollack (.NET)
- /// $Id: IHibernateOperations.cs,v 1.2 2007/09/19 22:58:22 markpollack Exp $
- public interface IHibernateOperations : ICommonHibernateOperations
- {
-
- ///
- /// Delete all given persistent instances.
- ///
- /// The persistent instances to delete.
- ///
- /// This can be combined with any of the find methods to delete by query
- /// in two lines of code, similar to Session's delete by query methods.
- ///
- /// In case of Hibernate errors
- void DeleteAll(ICollection entities);
-
- ///
- /// Execute the action specified by the given action object within a Session.
- ///
- ///
- /// Application exceptions thrown by the action object get propagated to the
- /// caller (can only be unchecked). Hibernate exceptions are transformed into
- /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
- /// object or a collection of domain objects.
- ///
Note: Callback code is not supposed to handle transactions itself!
- /// Use an appropriate transaction manager like HibernateTransactionManager.
- /// Generally, callback code must not touch any Session lifecycle methods,
- /// like close, disconnect, or reconnect, to let the template do its work.
- ///
- ///
- /// The delegate callback object that specifies the Hibernate action.
- /// a result object returned by the action, or null
- ///
- /// In case of Hibernate errors
- object Execute(HibernateDelegate del);
-
- ///
- /// Execute the action specified by the given action object within a Session.
- ///
- ///
- /// Application exceptions thrown by the action object get propagated to the
- /// caller (can only be unchecked). Hibernate exceptions are transformed into
- /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
- /// object or a collection of domain objects.
- ///
Note: Callback code is not supposed to handle transactions itself!
- /// Use an appropriate transaction manager like HibernateTransactionManager.
- /// Generally, callback code must not touch any Session lifecycle methods,
- /// like close, disconnect, or reconnect, to let the template do its work.
- ///
Provides HibernateTemplate's data access methods that mirror
+ /// various Session methods. See the NHibernate ISession documentation
+ /// for details on those methods.
+ ///
+ ///
+ ///
+ /// Mark Pollack (.NET)
+ public interface IHibernateOperations : ICommonHibernateOperations
+ {
+
+ ///
+ /// Delete all given persistent instances.
+ ///
+ /// The persistent instances to delete.
+ ///
+ /// This can be combined with any of the find methods to delete by query
+ /// in two lines of code, similar to Session's delete by query methods.
+ ///
+ /// In case of Hibernate errors
+ void DeleteAll(ICollection entities);
+
+ ///
+ /// Execute the action specified by the given action object within a Session.
+ ///
+ ///
+ /// Application exceptions thrown by the action object get propagated to the
+ /// caller (can only be unchecked). Hibernate exceptions are transformed into
+ /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
+ /// object or a collection of domain objects.
+ ///
Note: Callback code is not supposed to handle transactions itself!
+ /// Use an appropriate transaction manager like HibernateTransactionManager.
+ /// Generally, callback code must not touch any Session lifecycle methods,
+ /// like close, disconnect, or reconnect, to let the template do its work.
+ ///
+ ///
+ /// The delegate callback object that specifies the Hibernate action.
+ /// a result object returned by the action, or null
+ ///
+ /// In case of Hibernate errors
+ object Execute(HibernateDelegate del);
+
+ ///
+ /// Execute the action specified by the given action object within a Session.
+ ///
+ ///
+ /// Application exceptions thrown by the action object get propagated to the
+ /// caller (can only be unchecked). Hibernate exceptions are transformed into
+ /// appropriate DAO ones. Allows for returning a result object, i.e. a domain
+ /// object or a collection of domain objects.
+ ///
Note: Callback code is not supposed to handle transactions itself!
+ /// Use an appropriate transaction manager like HibernateTransactionManager.
+ /// Generally, callback code must not touch any Session lifecycle methods,
+ /// like close, disconnect, or reconnect, to let the template do its work.
+ ///
Can be used to override values in a NHibernate XML config file,
- /// or to specify all necessary properties locally.
- ///
- ///
Note: Do not specify a transaction provider here when using
- /// Spring-driven transactions. It is also advisable to omit connection
- /// provider settings and use a Spring-set IDbProvider instead.
- ///
- ///
- public IDictionary HibernateProperties
- {
- get
- {
- if (hibernateProperties == null)
- {
- hibernateProperties = new Hashtable();
- }
- return hibernateProperties;
- }
- set
- {
- hibernateProperties = value;
- }
- }
-
- ///
- /// Get or set the DataSource to be used by the SessionFactory.
- ///
- /// The db provider.
- ///
- /// If set, this will override corresponding settings in Hibernate properties.
- /// Note: If this is set, the Hibernate settings should not define
- /// a connection string
- /// (hibernate.connection.connection_string) to avoid meaningless double configuration.
- ///
- ///
- public IDbProvider DbProvider
- {
- set { dbProvider = value; }
- get { return dbProvider; }
- }
-
-
- #endregion
-
- #region Methods
-
- #endregion
-
- ///
- /// Return the singleon session factory.
- ///
- public object GetObject()
- {
- return sessionFactory;
- }
-
- ///
- /// Return the type or subclass.
- ///
- /// The type created by this factory
- public System.Type ObjectType
- {
- get
- {
- return (sessionFactory != null) ? sessionFactory.GetType() : typeof(ISessionFactory);
- }
- }
-
- ///
- /// Returns true
- ///
- /// true
- public bool IsSingleton
- {
- get
- {
- return true;
- }
- }
-
- ///
- /// Initialize the SessionFactory for the given or the
- /// default location.
- ///
- public void AfterPropertiesSet()
- {
- // Create Configuration instance.
- Configuration config = NewConfiguration();
-
-
- if (this.dbProvider != null)
- {
- config.SetProperty(Environment.ConnectionString, dbProvider.ConnectionString);
- config.SetProperty(Environment.ConnectionProvider, typeof(DbProviderWrapper).AssemblyQualifiedName);
- }
-
- if (this.hibernateProperties != null)
- {
- if (config.GetProperty(Environment.ConnectionProvider) != null &&
- hibernateProperties.Contains(Environment.ConnectionProvider))
- {
- #region Logging
- if (log.IsWarnEnabled)
- {
- log.Warn("Overriding use of Spring's Hibernate Connection Provider with [" +
- hibernateProperties[Environment.ConnectionProvider] + "]");
- }
- #endregion
- config.Properties.Remove(Environment.ConnectionProvider);
- }
- config.AddProperties(hibernateProperties);
- }
- if (this.mappingAssemblies != null)
- {
- foreach (string assemblyName in mappingAssemblies)
- {
- config.AddAssembly(assemblyName);
- }
- }
-
- IResourceLoader resourceLoader = new ConfigurableResourceLoader();
-
- if (this.mappingResources != null)
- {
- foreach (string resourceName in mappingResources)
- {
- config.AddInputStream(resourceLoader.GetResource(resourceName).InputStream);
- }
- }
-
- if (configFilenames != null)
- {
- foreach (string configFilename in configFilenames)
- {
- config.Configure(configFilename);
- }
- }
-
- // Perform custom post-processing in subclasses.
- PostProcessConfiguration(config);
-
- // Build SessionFactory instance.
- log.Info("Building new Hibernate SessionFactory");
- this.configuration = config;
- this.sessionFactory = NewSessionFactory(config);
-
-
- }
-
- ///
- /// Close the SessionFactory on application context shutdown.
- ///
- public void Dispose()
- {
- if (sessionFactory != null)
- {
- #region Instrumentation
- if (log.IsInfoEnabled)
- {
- log.Info("Closing Hibernate SessionFactory");
- }
- #endregion
- sessionFactory.Close();
- }
- }
-
- ///
- /// Subclasses can override this method to perform custom initialization
- /// of the Configuration instance used for ISessionFactory creation.
- ///
- ///
- /// The properties of this LocalSessionFactoryObject will be applied to
- /// the Configuration object that gets returned here.
- ///
The default implementation creates a new Configuration instance.
- /// A custom implementation could prepare the instance in a specific way,
- /// or use a custom Configuration subclass.
- ///
- ///
- protected virtual Configuration NewConfiguration()
- {
- return new Configuration();
- }
-
- ///
- /// To be implemented by subclasses that want to to perform custom
- /// post-processing of the Configuration object after this FactoryObject
- /// performed its default initialization.
- ///
- /// The current configuration object.
- protected virtual void PostProcessConfiguration(Configuration config)
- {
- }
-
- ///
- /// Subclasses can override this method to perform custom initialization
- /// of the SessionFactory instance, creating it via the given Configuration
- /// object that got prepared by this LocalSessionFactoryObject.
- ///
- ///
- ///
The default implementation invokes Configuration's BuildSessionFactory.
- /// A custom implementation could prepare the instance in a specific way,
- /// or use a custom ISessionFactory subclass.
- ///
Can be used to override values in a NHibernate XML config file,
+ /// or to specify all necessary properties locally.
+ ///
+ ///
Note: Do not specify a transaction provider here when using
+ /// Spring-driven transactions. It is also advisable to omit connection
+ /// provider settings and use a Spring-set IDbProvider instead.
+ ///
+ ///
+ public IDictionary HibernateProperties
+ {
+ get
+ {
+ if (hibernateProperties == null)
+ {
+ hibernateProperties = new Hashtable();
+ }
+ return hibernateProperties;
+ }
+ set
+ {
+ hibernateProperties = value;
+ }
+ }
+
+ ///
+ /// Get or set the DataSource to be used by the SessionFactory.
+ ///
+ /// The db provider.
+ ///
+ /// If set, this will override corresponding settings in Hibernate properties.
+ /// Note: If this is set, the Hibernate settings should not define
+ /// a connection string
+ /// (hibernate.connection.connection_string) to avoid meaningless double configuration.
+ ///
+ ///
+ public IDbProvider DbProvider
+ {
+ set { dbProvider = value; }
+ get { return dbProvider; }
+ }
+
+
+ #endregion
+
+ #region Methods
+
+ #endregion
+
+ ///
+ /// Return the singleon session factory.
+ ///
+ public object GetObject()
+ {
+ return sessionFactory;
+ }
+
+ ///
+ /// Return the type or subclass.
+ ///
+ /// The type created by this factory
+ public System.Type ObjectType
+ {
+ get
+ {
+ return (sessionFactory != null) ? sessionFactory.GetType() : typeof(ISessionFactory);
+ }
+ }
+
+ ///
+ /// Returns true
+ ///
+ /// true
+ public bool IsSingleton
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ ///
+ /// Initialize the SessionFactory for the given or the
+ /// default location.
+ ///
+ public void AfterPropertiesSet()
+ {
+ // Create Configuration instance.
+ Configuration config = NewConfiguration();
+
+
+ if (this.dbProvider != null)
+ {
+ config.SetProperty(Environment.ConnectionString, dbProvider.ConnectionString);
+ config.SetProperty(Environment.ConnectionProvider, typeof(DbProviderWrapper).AssemblyQualifiedName);
+ }
+
+ if (this.hibernateProperties != null)
+ {
+ if (config.GetProperty(Environment.ConnectionProvider) != null &&
+ hibernateProperties.Contains(Environment.ConnectionProvider))
+ {
+ #region Logging
+ if (log.IsWarnEnabled)
+ {
+ log.Warn("Overriding use of Spring's Hibernate Connection Provider with [" +
+ hibernateProperties[Environment.ConnectionProvider] + "]");
+ }
+ #endregion
+ config.Properties.Remove(Environment.ConnectionProvider);
+ }
+ config.AddProperties(hibernateProperties);
+ }
+ if (this.mappingAssemblies != null)
+ {
+ foreach (string assemblyName in mappingAssemblies)
+ {
+ config.AddAssembly(assemblyName);
+ }
+ }
+
+ IResourceLoader resourceLoader = new ConfigurableResourceLoader();
+
+ if (this.mappingResources != null)
+ {
+ foreach (string resourceName in mappingResources)
+ {
+ config.AddInputStream(resourceLoader.GetResource(resourceName).InputStream);
+ }
+ }
+
+ if (configFilenames != null)
+ {
+ foreach (string configFilename in configFilenames)
+ {
+ config.Configure(configFilename);
+ }
+ }
+
+ // Perform custom post-processing in subclasses.
+ PostProcessConfiguration(config);
+
+ // Build SessionFactory instance.
+ log.Info("Building new Hibernate SessionFactory");
+ this.configuration = config;
+ this.sessionFactory = NewSessionFactory(config);
+
+
+ }
+
+ ///
+ /// Close the SessionFactory on application context shutdown.
+ ///
+ public void Dispose()
+ {
+ if (sessionFactory != null)
+ {
+ #region Instrumentation
+ if (log.IsInfoEnabled)
+ {
+ log.Info("Closing Hibernate SessionFactory");
+ }
+ #endregion
+ sessionFactory.Close();
+ }
+ }
+
+ ///
+ /// Subclasses can override this method to perform custom initialization
+ /// of the Configuration instance used for ISessionFactory creation.
+ ///
+ ///
+ /// The properties of this LocalSessionFactoryObject will be applied to
+ /// the Configuration object that gets returned here.
+ ///
The default implementation creates a new Configuration instance.
+ /// A custom implementation could prepare the instance in a specific way,
+ /// or use a custom Configuration subclass.
+ ///
+ ///
+ protected virtual Configuration NewConfiguration()
+ {
+ return new Configuration();
+ }
+
+ ///
+ /// To be implemented by subclasses that want to to perform custom
+ /// post-processing of the Configuration object after this FactoryObject
+ /// performed its default initialization.
+ ///
+ /// The current configuration object.
+ protected virtual void PostProcessConfiguration(Configuration config)
+ {
+ }
+
+ ///
+ /// Subclasses can override this method to perform custom initialization
+ /// of the SessionFactory instance, creating it via the given Configuration
+ /// object that got prepared by this LocalSessionFactoryObject.
+ ///
+ ///
+ ///
The default implementation invokes Configuration's BuildSessionFactory.
+ /// A custom implementation could prepare the instance in a specific way,
+ /// or use a custom ISessionFactory subclass.
+ ///
- /// Normally starting with 0 or 1, with indicating
- /// greatest. Same order values will result in arbitrary positions for the affected
- /// objects.
- ///
- ///
- /// Higher value can be interpreted as lower priority, consequently the first object
- /// has highest priority.
- ///
- ///
- /// The order value.
- public int Order
- {
- get
- {
- return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
- }
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Suspend this synchronization.
- ///
- ///
- ///
- /// Unbind Hibernate resources (SessionHolder) from
- ///
- /// if managing any.
- ///
- /// Rebind Hibernate resources from
- ///
- /// if managing any.
- ///
- ///
- public override void Resume()
- {
- if (this.holderActive)
- {
- TransactionSynchronizationManager.BindResource(this.sessionFactory, this.sessionHolder);
- }
- }
-
- ///
- /// Invoked before transaction commit (before
- /// )
- ///
- ///
- /// If the transaction is defined as a read-only transaction.
- ///
- ///
- ///
- /// Can flush transactional sessions to the database.
- ///
- ///
- /// Note that exceptions will get propagated to the commit caller and
- /// cause a rollback of the transaction.
- ///
- ///
- public override void BeforeCommit(bool readOnly)
- {
- if (!readOnly)
- {
- // read-write transaction -> flush the Hibernate Session
- log.Debug("Flushing Hibernate Session on transaction synchronization");
- ISession session = this.sessionHolder.Session;
- //Further check: only flush when not FlushMode.NEVER
- if (session.FlushMode != FlushMode.Never)
- {
- try
- {
- session.Flush();
- //TODO can throw System.ObjectDisposedException...
- }
- catch (ADOException ex)
- {
- if (this.adoExceptionTranslator != null)
- {
- //TODO investigate how ADOException wraps inner exception.
- throw this.adoExceptionTranslator.Translate(
- "Hibernate transaction synchronization: " + ex.Message, null, ex.InnerException);
- }
- else
- {
- throw new HibernateAdoException("ADO.NET Exception", ex);
- }
- }
- catch (HibernateException ex)
- {
- throw SessionFactoryUtils.ConvertHibernateAccessException(ex);
- }
- }
-
- }
- }
-
- ///
- /// Invoked before transaction commit (before
- /// )
- /// Can e.g. flush transactional O/R Mapping sessions to the database
- ///
- ///
- ///
- /// This callback does not mean that the transaction will actually be
- /// commited. A rollback decision can still occur after this method
- /// has been called. This callback is rather meant to perform work
- /// that's only relevant if a commit still has a chance
- /// to happen, such as flushing SQL statements to the database.
- ///
- ///
- /// Note that exceptions will get propagated to the commit caller and cause a
- /// rollback of the transaction.
- ///
- /// (note: do not throw TransactionException subclasses here!)
- ///
- ///
- public override void BeforeCompletion()
- {
- if (this.newSession)
- {
- // Default behavior: unbind and close the thread-bound Hibernate Session.
- TransactionSynchronizationManager.UnbindResource(this.sessionFactory);
- this.holderActive = false;
- }
- else if (this.sessionHolder.AssignedPreviousFlushMode == true)
- {
- // In case of pre-bound Session, restore previous flush mode.
- this.sessionHolder.Session.FlushMode = (this.sessionHolder.PreviousFlushMode);
- }
- }
-
- ///
- /// Invoked after transaction commit/rollback.
- ///
- ///
- /// Status according to
- ///
- ///
- /// Can e.g. perform resource cleanup, in this case after transaction completion.
- ///
- /// Note that exceptions will get propagated to the commit or rollback
- /// caller, although they will not influence the outcome of the transaction.
- ///
+ /// Normally starting with 0 or 1, with indicating
+ /// greatest. Same order values will result in arbitrary positions for the affected
+ /// objects.
+ ///
+ ///
+ /// Higher value can be interpreted as lower priority, consequently the first object
+ /// has highest priority.
+ ///
+ ///
+ /// The order value.
+ public int Order
+ {
+ get
+ {
+ return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Suspend this synchronization.
+ ///
+ ///
+ ///
+ /// Unbind Hibernate resources (SessionHolder) from
+ ///
+ /// if managing any.
+ ///
+ /// Rebind Hibernate resources from
+ ///
+ /// if managing any.
+ ///
+ ///
+ public override void Resume()
+ {
+ if (this.holderActive)
+ {
+ TransactionSynchronizationManager.BindResource(this.sessionFactory, this.sessionHolder);
+ }
+ }
+
+ ///
+ /// Invoked before transaction commit (before
+ /// )
+ ///
+ ///
+ /// If the transaction is defined as a read-only transaction.
+ ///
+ ///
+ ///
+ /// Can flush transactional sessions to the database.
+ ///
+ ///
+ /// Note that exceptions will get propagated to the commit caller and
+ /// cause a rollback of the transaction.
+ ///
+ ///
+ public override void BeforeCommit(bool readOnly)
+ {
+ if (!readOnly)
+ {
+ // read-write transaction -> flush the Hibernate Session
+ log.Debug("Flushing Hibernate Session on transaction synchronization");
+ ISession session = this.sessionHolder.Session;
+ //Further check: only flush when not FlushMode.NEVER
+ if (session.FlushMode != FlushMode.Never)
+ {
+ try
+ {
+ session.Flush();
+ //TODO can throw System.ObjectDisposedException...
+ }
+ catch (ADOException ex)
+ {
+ if (this.adoExceptionTranslator != null)
+ {
+ //TODO investigate how ADOException wraps inner exception.
+ throw this.adoExceptionTranslator.Translate(
+ "Hibernate transaction synchronization: " + ex.Message, null, ex.InnerException);
+ }
+ else
+ {
+ throw new HibernateAdoException("ADO.NET Exception", ex);
+ }
+ }
+ catch (HibernateException ex)
+ {
+ throw SessionFactoryUtils.ConvertHibernateAccessException(ex);
+ }
+ }
+
+ }
+ }
+
+ ///
+ /// Invoked before transaction commit (before
+ /// )
+ /// Can e.g. flush transactional O/R Mapping sessions to the database
+ ///
+ ///
+ ///
+ /// This callback does not mean that the transaction will actually be
+ /// commited. A rollback decision can still occur after this method
+ /// has been called. This callback is rather meant to perform work
+ /// that's only relevant if a commit still has a chance
+ /// to happen, such as flushing SQL statements to the database.
+ ///
+ ///
+ /// Note that exceptions will get propagated to the commit caller and cause a
+ /// rollback of the transaction.
+ ///
+ /// (note: do not throw TransactionException subclasses here!)
+ ///
+ ///
+ public override void BeforeCompletion()
+ {
+ if (this.newSession)
+ {
+ // Default behavior: unbind and close the thread-bound Hibernate Session.
+ TransactionSynchronizationManager.UnbindResource(this.sessionFactory);
+ this.holderActive = false;
+ }
+ else if (this.sessionHolder.AssignedPreviousFlushMode == true)
+ {
+ // In case of pre-bound Session, restore previous flush mode.
+ this.sessionHolder.Session.FlushMode = (this.sessionHolder.PreviousFlushMode);
+ }
+ }
+
+ ///
+ /// Invoked after transaction commit/rollback.
+ ///
+ ///
+ /// Status according to
+ ///
+ ///
+ /// Can e.g. perform resource cleanup, in this case after transaction completion.
+ ///
+ /// Note that exceptions will get propagated to the commit or rollback
+ /// caller, although they will not influence the outcome of the transaction.
+ ///
In case of an existing ISession, TemplateFlushMode.Never will turn
- /// the hibenrate flush mode
- /// to FlushMode.Never for the scope of the current operation, resetting the previous
- /// flush mode afterwards.
- ///
- ///
- Never,
-
- /// Automatic flushing is the default mode for a Hibernate Session.
- ///
- ///
- /// A session will get flushed on transaction commit, and on certain find
- /// operations that might involve already modified instances, but not
- /// after each unit of work like with eager flushing.
- ///
In case of an existing Session, TemplateFlushMode.Auto
- /// will participate in the existing flush mode, not modifying
- /// it for the current operation.
- /// This in particular means that this setting will not modify an existing
- /// hibernate flush mode FlushMode.Never, in contrast to TemplateFlushMode.Eager.
- ///
- ///
- Auto,
-
- ///
- /// Eager flushing leads to immediate synchronization with the database,
- /// even if in a transaction.
- ///
- ///
- /// This causes inconsistencies to show up and throw
- /// a respective exception immediately, and ADO access code that participates
- /// in the same transaction will see the changes as the database is already
- /// aware of them then. But the drawbacks are:
- ///
- ///
additional communication roundtrips with the database, instead of a
- /// single batch at transaction commit;
- ///
the fact that an actual database rollback is needed if the Hibernate
- /// transaction rolls back (due to already submitted SQL statements).
- ///
- ///
In case of an existing Session, TemplateFlushMode.Eager
- /// will turn the NHibernate flush mode
- /// to FlushMode.Auto for the scope of the current operation and issue a flush at the
- /// end, resetting the previous flush mode afterwards.
- ///
- ///
- Eager,
-
- ///
- /// Flushing at commit only is intended for units of work where no
- /// intermediate flushing is desired, not even for find operations
- /// that might involve already modified instances.
- ///
- ///
- ///
In case of an existing Session, TemplateFlushMode.Commit
- /// will turn the NHibernate flush mode
- /// to FlushMode.Commit for the scope of the current operation, resetting the previous
- /// flush mode afterwards. The only exception is an existing flush mode
- /// FlushMode.Never, which will not be modified through this setting.
- ///
In case of an existing ISession, TemplateFlushMode.Never will turn
+ /// the hibenrate flush mode
+ /// to FlushMode.Never for the scope of the current operation, resetting the previous
+ /// flush mode afterwards.
+ ///
+ ///
+ Never,
+
+ /// Automatic flushing is the default mode for a Hibernate Session.
+ ///
+ ///
+ /// A session will get flushed on transaction commit, and on certain find
+ /// operations that might involve already modified instances, but not
+ /// after each unit of work like with eager flushing.
+ ///
In case of an existing Session, TemplateFlushMode.Auto
+ /// will participate in the existing flush mode, not modifying
+ /// it for the current operation.
+ /// This in particular means that this setting will not modify an existing
+ /// hibernate flush mode FlushMode.Never, in contrast to TemplateFlushMode.Eager.
+ ///
+ ///
+ Auto,
+
+ ///
+ /// Eager flushing leads to immediate synchronization with the database,
+ /// even if in a transaction.
+ ///
+ ///
+ /// This causes inconsistencies to show up and throw
+ /// a respective exception immediately, and ADO access code that participates
+ /// in the same transaction will see the changes as the database is already
+ /// aware of them then. But the drawbacks are:
+ ///
+ ///
additional communication roundtrips with the database, instead of a
+ /// single batch at transaction commit;
+ ///
the fact that an actual database rollback is needed if the Hibernate
+ /// transaction rolls back (due to already submitted SQL statements).
+ ///
+ ///
In case of an existing Session, TemplateFlushMode.Eager
+ /// will turn the NHibernate flush mode
+ /// to FlushMode.Auto for the scope of the current operation and issue a flush at the
+ /// end, resetting the previous flush mode afterwards.
+ ///
+ ///
+ Eager,
+
+ ///
+ /// Flushing at commit only is intended for units of work where no
+ /// intermediate flushing is desired, not even for find operations
+ /// that might involve already modified instances.
+ ///
+ ///
+ ///
In case of an existing Session, TemplateFlushMode.Commit
+ /// will turn the NHibernate flush mode
+ /// to FlushMode.Commit for the scope of the current operation, resetting the previous
+ /// flush mode afterwards. The only exception is an existing flush mode
+ /// FlushMode.Never, which will not be modified through this setting.
+ ///
+ ///
+ Commit
+
+ }
+}
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/FindHibernateDelegate.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/FindHibernateDelegate.cs
index bc229e6a..ec4c683c 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/FindHibernateDelegate.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/FindHibernateDelegate.cs
@@ -41,6 +41,5 @@ namespace Spring.Data.NHibernate.Generic
///
/// The type of result object
/// Sree Nivask (.NET)
- /// $Id: FindHibernateDelegate.cs,v 1.2 2007/09/19 22:58:10 markpollack Exp $
public delegate IList FindHibernateDelegate(ISession session);
}
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDaoSupport.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDaoSupport.cs
index 3d210f3b..769d1c8b 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDaoSupport.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDaoSupport.cs
@@ -48,7 +48,6 @@ namespace Spring.Data.NHibernate.Generic.Support
///
/// Sree Nivask (.NET)
/// Mark Pollack (.NET)
- /// $Id: HibernateDaoSupport.cs,v 1.3 2007/09/19 22:58:10 markpollack Exp $
public abstract class HibernateDaoSupport : DaoSupport
{
#region Fields
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDelegate.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDelegate.cs
index fb8b49c0..57a762f8 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDelegate.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateDelegate.cs
@@ -40,6 +40,5 @@ namespace Spring.Data.NHibernate.Generic
///
/// The type of result object
/// Sree Nivask (.NET)
- /// $Id: HibernateDelegate.cs,v 1.2 2007/09/19 22:58:10 markpollack Exp $
public delegate T HibernateDelegate(ISession session);
}
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateTemplate.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateTemplate.cs
index 5b994ab8..1638ee69 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateTemplate.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/HibernateTemplate.cs
@@ -68,7 +68,6 @@ namespace Spring.Data.NHibernate.Generic
///
/// Sree Nivask (.NET)
/// Mark Pollack (.NET)
- /// $Id: HibernateTemplate.cs,v 1.3 2008/01/24 17:29:09 markpollack Exp $
public class HibernateTemplate : HibernateAccessor, IHibernateOperations
{
#region Fields
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IFindHibernateCallback.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IFindHibernateCallback.cs
index b84c65f4..113fd5c2 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IFindHibernateCallback.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IFindHibernateCallback.cs
@@ -35,7 +35,6 @@ namespace Spring.Data.NHibernate.Generic
///
/// Sree Nivask (.NET)
/// Mark Pollack (.NET)
- /// $Id: IFindHibernateCallback.cs,v 1.2 2007/09/19 22:58:10 markpollack Exp $
public interface IFindHibernateCallback
{
///
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateCallback.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateCallback.cs
index 6fd97f3f..4bb7c560 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateCallback.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateCallback.cs
@@ -37,7 +37,6 @@ namespace Spring.Data.NHibernate.Generic
///
///
/// Sree Nivask (.NET)
- /// $Id: IHibernateCallback.cs,v 1.2 2007/09/19 22:58:10 markpollack Exp $
public interface IHibernateCallback
{
///
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateOperations.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateOperations.cs
index 899c88bc..26925613 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateOperations.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/Generic/IHibernateOperations.cs
@@ -40,7 +40,6 @@ namespace Spring.Data.NHibernate.Generic
///
/// Sree Nivask (.NET)
/// Mark Pollack (.NET)
- /// $Id: IHibernateOperations.cs,v 1.2 2007/09/19 22:58:10 markpollack Exp $
public interface IHibernateOperations : ICommonHibernateOperations
{
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateAccessor.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateAccessor.cs
index eb2f24c0..b7e0b6ee 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateAccessor.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateAccessor.cs
@@ -48,7 +48,6 @@ namespace Spring.Data.NHibernate
///
///
/// Mark Pollack (.NET)
- /// $Id: HibernateAccessor.cs,v 1.7 2008/01/25 15:04:28 markpollack Exp $
public abstract class HibernateAccessor : IInitializingObject, IObjectFactoryAware
{
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateOptimisticLockingFailureException.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateOptimisticLockingFailureException.cs
index a196d416..2478d50d 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateOptimisticLockingFailureException.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/HibernateOptimisticLockingFailureException.cs
@@ -37,7 +37,6 @@ namespace Spring.Data.NHibernate
///
/// Juergen Hoeller
/// Mark Pollack (.NET)
- /// $Id: HibernateOptimisticLockingFailureException.cs,v 1.1 2008/04/08 20:26:30 markpollack Exp $
[Serializable]
public class HibernateOptimisticLockingFailureException : ObjectOptimisticLockingFailureException
{
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/LocalSessionFactoryObject.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/LocalSessionFactoryObject.cs
index e3232651..647c8aac 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/LocalSessionFactoryObject.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/LocalSessionFactoryObject.cs
@@ -50,7 +50,6 @@ namespace Spring.Data.NHibernate
///
///
/// Mark Pollack (.NET)
- /// $Id: LocalSessionFactoryObject.cs,v 1.11 2008/03/21 14:12:08 markpollack Exp $
public class LocalSessionFactoryObject : IFactoryObject, IInitializingObject, System.IDisposable
{
#region Fields
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SessionFactoryUtils.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SessionFactoryUtils.cs
index 9361bbb4..0e13824b 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SessionFactoryUtils.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SessionFactoryUtils.cs
@@ -47,7 +47,6 @@ namespace Spring.Data.NHibernate
/// Also provides support for exception translation.
///
/// Mark Pollack (.NET)
- /// $Id: SessionFactoryUtils.cs,v 1.1 2008/04/08 20:26:30 markpollack Exp $
public abstract class SessionFactoryUtils
{
#region Fields
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionContext.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionContext.cs
index c0ab893e..d45d948a 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionContext.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionContext.cs
@@ -38,7 +38,6 @@ namespace Spring.Data.NHibernate
/// qualified name of this class as value.
/// Juergen Hoeller
/// Mark Pollack (.NET)
- /// $Id: SpringSessionContext.cs,v 1.2 2007/09/19 22:58:11 markpollack Exp $
///
public class SpringSessionContext : ICurrentSessionContext
{
diff --git a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionSynchronization.cs b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionSynchronization.cs
index 78ca458b..1dac6449 100644
--- a/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionSynchronization.cs
+++ b/src/Spring/Spring.Data.NHibernate12/Data/NHibernate/SpringSessionSynchronization.cs
@@ -35,7 +35,6 @@ namespace Spring.Data.NHibernate
/// NHibnerations actions taken during the transaction lifecycle.
///
/// Mark Pollack (.NET)
- /// $Id: SpringSessionSynchronization.cs,v 1.1 2007/06/01 02:34:12 markpollack Exp $
public class SpringSessionSynchronization : TransactionSynchronizationAdapter, IOrdered
{
#region Fields
diff --git a/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs b/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs
index a73c4ef4..73d247bc 100644
--- a/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs
+++ b/src/Spring/Spring.Data/Dao/CannotAcquireLockException.cs
@@ -1,89 +1,88 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown on failure to aquire a lock during an update i.e a select for
- /// update statement.
- ///
- ///
- ///
- /// This exception will be thrown either by O/R mapping tools or by custom DAO
- /// implementations.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: CannotAcquireLockException.cs,v 1.6 2008/04/08 20:26:43 markpollack Exp $
- [Serializable]
- public class CannotAcquireLockException : PessimisticLockingFailureException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public CannotAcquireLockException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public CannotAcquireLockException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public CannotAcquireLockException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected CannotAcquireLockException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown on failure to aquire a lock during an update i.e a select for
+ /// update statement.
+ ///
+ ///
+ ///
+ /// This exception will be thrown either by O/R mapping tools or by custom DAO
+ /// implementations.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class CannotAcquireLockException : PessimisticLockingFailureException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public CannotAcquireLockException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public CannotAcquireLockException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public CannotAcquireLockException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected CannotAcquireLockException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs b/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs
index bdfcf15e..776975b4 100644
--- a/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs
+++ b/src/Spring/Spring.Data/Dao/CannotSerializeTransactionException.cs
@@ -1,89 +1,88 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown on failure to complete a transaction in serialized mode due to
- /// update conflicts.
- ///
- ///
- ///
- /// This exception will be thrown either by O/R mapping tools or by custom DAO
- /// implementations.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: CannotSerializeTransactionException.cs,v 1.6 2008/04/08 20:26:43 markpollack Exp $
- [Serializable]
- public class CannotSerializeTransactionException : PessimisticLockingFailureException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public CannotSerializeTransactionException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public CannotSerializeTransactionException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public CannotSerializeTransactionException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected CannotSerializeTransactionException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown on failure to complete a transaction in serialized mode due to
+ /// update conflicts.
+ ///
+ ///
+ ///
+ /// This exception will be thrown either by O/R mapping tools or by custom DAO
+ /// implementations.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class CannotSerializeTransactionException : PessimisticLockingFailureException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public CannotSerializeTransactionException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public CannotSerializeTransactionException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public CannotSerializeTransactionException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected CannotSerializeTransactionException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs b/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs
index 5c344dab..de9ea026 100644
--- a/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs
+++ b/src/Spring/Spring.Data/Dao/CleanupFailureDataAccessException.cs
@@ -1,94 +1,93 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown when we couldn't cleanup after a data access operation,
- /// but the actual operation went OK.
- ///
- ///
- ///
- /// For example, this exception or a subclass might be thrown if an ADO.NET
- /// connection couldn't be closed after it had been used successfully.
- ///
- ///
- /// Note that data access code might perform resource cleanup in a
- /// finally block and therefore log cleanup failure rather than rethrow it,
- /// to keep the original data access exception, if any.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: CleanupFailureDataAccessException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class CleanupFailureDataAccessException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public CleanupFailureDataAccessException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public CleanupFailureDataAccessException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public CleanupFailureDataAccessException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected CleanupFailureDataAccessException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown when we couldn't cleanup after a data access operation,
+ /// but the actual operation went OK.
+ ///
+ ///
+ ///
+ /// For example, this exception or a subclass might be thrown if an ADO.NET
+ /// connection couldn't be closed after it had been used successfully.
+ ///
+ ///
+ /// Note that data access code might perform resource cleanup in a
+ /// finally block and therefore log cleanup failure rather than rethrow it,
+ /// to keep the original data access exception, if any.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class CleanupFailureDataAccessException : DataAccessException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public CleanupFailureDataAccessException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public CleanupFailureDataAccessException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public CleanupFailureDataAccessException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected CleanupFailureDataAccessException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs b/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs
index 2c6ffc71..e499fc80 100644
--- a/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs
+++ b/src/Spring/Spring.Data/Dao/ConcurrencyFailureException.cs
@@ -1,90 +1,89 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown on concurrency failure. This exception should be
- /// sublassed to indicate the type of failure - optimistic locking,
- /// failure to acquire lock, etc.
- ///
- ///
- ///
- /// This exception will be thrown either by O/R mapping tools or by custom DAO
- /// implementations.
- ///
- ///
- /// Thomas Risberg
- /// Griffin Caprio (.NET)
- /// $Id: ConcurrencyFailureException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class ConcurrencyFailureException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public ConcurrencyFailureException() : base("No Exception Message") {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public ConcurrencyFailureException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public ConcurrencyFailureException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected ConcurrencyFailureException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown on concurrency failure. This exception should be
+ /// sublassed to indicate the type of failure - optimistic locking,
+ /// failure to acquire lock, etc.
+ ///
+ ///
+ ///
+ /// This exception will be thrown either by O/R mapping tools or by custom DAO
+ /// implementations.
+ ///
+ ///
+ /// Thomas Risberg
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class ConcurrencyFailureException : DataAccessException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public ConcurrencyFailureException() : base("No Exception Message") {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public ConcurrencyFailureException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public ConcurrencyFailureException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected ConcurrencyFailureException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/DataAccessException.cs b/src/Spring/Spring.Data/Dao/DataAccessException.cs
index 66b84c64..0b4769e1 100644
--- a/src/Spring/Spring.Data/Dao/DataAccessException.cs
+++ b/src/Spring/Spring.Data/Dao/DataAccessException.cs
@@ -1,81 +1,81 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Root of the hierarchy of data access exceptions
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- [Serializable]
- public abstract class DataAccessException : Exception
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- protected DataAccessException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- protected DataAccessException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- protected DataAccessException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected DataAccessException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
-}
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Root of the hierarchy of data access exceptions
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public abstract class DataAccessException : Exception
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ protected DataAccessException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ protected DataAccessException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ protected DataAccessException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected DataAccessException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
+}
diff --git a/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs b/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs
index e762cbdd..95144925 100644
--- a/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs
+++ b/src/Spring/Spring.Data/Dao/DataAccessResourceFailureException.cs
@@ -1,83 +1,82 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Data access exception thrown when a resource fails completely:
- /// for example, if we can't connect to a database using ADO.NET.
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: DataAccessResourceFailureException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class DataAccessResourceFailureException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public DataAccessResourceFailureException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public DataAccessResourceFailureException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public DataAccessResourceFailureException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected DataAccessResourceFailureException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Data access exception thrown when a resource fails completely:
+ /// for example, if we can't connect to a database using ADO.NET.
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class DataAccessResourceFailureException : DataAccessException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public DataAccessResourceFailureException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public DataAccessResourceFailureException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public DataAccessResourceFailureException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected DataAccessResourceFailureException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs b/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs
index 86c77d3c..7a1f3d2d 100644
--- a/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs
+++ b/src/Spring/Spring.Data/Dao/DataIntegrityViolationException.cs
@@ -1,89 +1,88 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown when an attempt to insert or update data
- /// results in violation of an integrity constraint.
- ///
- ///
- ///
- /// Note that this is not purely a relational concept; unique primary keys are
- /// required by most database types.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: DataIntegrityViolationException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class DataIntegrityViolationException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public DataIntegrityViolationException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public DataIntegrityViolationException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public DataIntegrityViolationException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected DataIntegrityViolationException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown when an attempt to insert or update data
+ /// results in violation of an integrity constraint.
+ ///
+ ///
+ ///
+ /// Note that this is not purely a relational concept; unique primary keys are
+ /// required by most database types.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class DataIntegrityViolationException : DataAccessException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public DataIntegrityViolationException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public DataIntegrityViolationException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public DataIntegrityViolationException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected DataIntegrityViolationException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs b/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs
index 0c5c8238..e84ea780 100644
--- a/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs
+++ b/src/Spring/Spring.Data/Dao/DataRetrievalFailureException.cs
@@ -1,89 +1,88 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown if certain expected data could not be retrieved, e.g.
- /// when looking up specific data via a known identifier.
- ///
- ///
- ///
- /// This exception will be thrown either by O/R mapping tools or by custom DAO
- /// implementations.
- ///
- ///
- /// Juergen Hoeller
- /// Griffin Caprio (.NET)
- /// $Id: DataRetrievalFailureException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class DataRetrievalFailureException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public DataRetrievalFailureException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public DataRetrievalFailureException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public DataRetrievalFailureException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected DataRetrievalFailureException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown if certain expected data could not be retrieved, e.g.
+ /// when looking up specific data via a known identifier.
+ ///
+ ///
+ ///
+ /// This exception will be thrown either by O/R mapping tools or by custom DAO
+ /// implementations.
+ ///
- /// Thrown, for example, when we wanted to update 1 row in an RDBMS but actually
- /// updated 3.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: IncorrectUpdateSemanticsDataAccessException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public abstract class IncorrectUpdateSemanticsDataAccessException
- : InvalidDataAccessResourceUsageException
- {
- /// Return whether or not data was updated.
- ///
- /// True if data was updated (as opposed to being incorrectly
- /// updated). If this property returns false, there's nothing to roll back.
- ///
- public abstract bool DataWasUpdated { get; }
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- protected IncorrectUpdateSemanticsDataAccessException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- protected IncorrectUpdateSemanticsDataAccessException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- protected IncorrectUpdateSemanticsDataAccessException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected IncorrectUpdateSemanticsDataAccessException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Data access exception thrown when something unintended appears to have
+ /// happened with an update, but the transaction hasn't already been rolled back.
+ ///
+ ///
+ ///
+ /// Thrown, for example, when we wanted to update 1 row in an RDBMS but actually
+ /// updated 3.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public abstract class IncorrectUpdateSemanticsDataAccessException
+ : InvalidDataAccessResourceUsageException
+ {
+ /// Return whether or not data was updated.
+ ///
+ /// True if data was updated (as opposed to being incorrectly
+ /// updated). If this property returns false, there's nothing to roll back.
+ ///
+ public abstract bool DataWasUpdated { get; }
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ protected IncorrectUpdateSemanticsDataAccessException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ protected IncorrectUpdateSemanticsDataAccessException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ protected IncorrectUpdateSemanticsDataAccessException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected IncorrectUpdateSemanticsDataAccessException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs b/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs
index f7f27c01..eb4c1714 100644
--- a/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs
+++ b/src/Spring/Spring.Data/Dao/InvalidDataAccessApiUsageException.cs
@@ -1,89 +1,88 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Exception thrown on incorrect usage of the API, such as failing to "compile" a query
- /// object that needed compilation before execution.
- ///
- ///
- ///
- /// This represents a problem in our data access framework, not the underlying data access
- /// infrastructure.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: InvalidDataAccessApiUsageException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class InvalidDataAccessApiUsageException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public InvalidDataAccessApiUsageException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public InvalidDataAccessApiUsageException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public InvalidDataAccessApiUsageException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected InvalidDataAccessApiUsageException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown on incorrect usage of the API, such as failing to "compile" a query
+ /// object that needed compilation before execution.
+ ///
+ ///
+ ///
+ /// This represents a problem in our data access framework, not the underlying data access
+ /// infrastructure.
+ ///
+ ///
+ /// Rod Johnson
+ /// Griffin Caprio (.NET)
+ [Serializable]
+ public class InvalidDataAccessApiUsageException : DataAccessException
+ {
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ public InvalidDataAccessApiUsageException() {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ public InvalidDataAccessApiUsageException( string message ) : base( message ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// A message about the exception.
+ ///
+ ///
+ /// The root exception (from the underlying data access API, such as ADO.NET).
+ ///
+ public InvalidDataAccessApiUsageException( string message, Exception rootCause)
+ : base( message , rootCause ) {}
+
+ ///
+ /// Creates a new instance of the
+ /// class.
+ ///
+ ///
+ /// The
+ /// that holds the serialized object data about the exception being thrown.
+ ///
+ ///
+ /// The
+ /// that contains contextual information about the source or destination.
+ ///
+ protected InvalidDataAccessApiUsageException(
+ SerializationInfo info, StreamingContext context ) : base( info, context ) {}
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs b/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs
index 65cec5ef..3d8958c1 100644
--- a/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs
+++ b/src/Spring/Spring.Data/Dao/InvalidDataAccessResourceUsageException.cs
@@ -1,88 +1,87 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Runtime.Serialization;
-
-#endregion
-
-namespace Spring.Dao
-{
- ///
- /// Root for exceptions thrown when we use a data access resource incorrectly.
- ///
- ///
- ///
- /// Thrown for example on specifying bad SQL when using a RDBMS.
- /// Resource-specific subclasses will probably be supplied by data access packages.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: InvalidDataAccessResourceUsageException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class InvalidDataAccessResourceUsageException : DataAccessException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public InvalidDataAccessResourceUsageException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public InvalidDataAccessResourceUsageException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public InvalidDataAccessResourceUsageException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected InvalidDataAccessResourceUsageException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Root for exceptions thrown when we use a data access resource incorrectly.
+ ///
+ ///
+ ///
+ /// Thrown for example on specifying bad SQL when using a RDBMS.
+ /// Resource-specific subclasses will probably be supplied by data access packages.
+ ///
- /// This exception will be thrown either by O/R mapping tools or by custom DAO
- /// implementations.
- ///
- ///
- /// Rod Johnson
- /// Griffin Caprio (.NET)
- /// $Id: OptimisticLockingFailureException.cs,v 1.5 2006/05/18 21:37:50 markpollack Exp $
- [Serializable]
- public class OptimisticLockingFailureException : ConcurrencyFailureException
- {
- ///
- /// Creates a new instance of the
- /// class.
- ///
- public OptimisticLockingFailureException() {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- public OptimisticLockingFailureException( string message ) : base( message ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// A message about the exception.
- ///
- ///
- /// The root exception (from the underlying data access API, such as ADO.NET).
- ///
- public OptimisticLockingFailureException( string message, Exception rootCause)
- : base( message , rootCause ) {}
-
- ///
- /// Creates a new instance of the
- /// class.
- ///
- ///
- /// The
- /// that holds the serialized object data about the exception being thrown.
- ///
- ///
- /// The
- /// that contains contextual information about the source or destination.
- ///
- protected OptimisticLockingFailureException(
- SerializationInfo info, StreamingContext context ) : base( info, context ) {}
- }
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Runtime.Serialization;
+
+#endregion
+
+namespace Spring.Dao
+{
+ ///
+ /// Exception thrown on an optimistic locking violation.
+ ///
+ ///
+ ///
+ /// This exception will be thrown either by O/R mapping tools or by custom DAO
+ /// implementations.
+ ///
Implementors should be marked as sealed, to make it clear that
- /// concrete subclasses are not supposed to override this template method themselves.
- ///
Implementors should be marked as sealed, to make it clear that
+ /// concrete subclasses are not supposed to override this template method themselves.
+ ///
Allows you to execute any number of operations
- /// on a single IDbCommand, for example a single ExecuteScalar
- /// call or repeated execute calls with varying parameters.
- ///
- ///
Used internally by AdoTemplate, but also useful for
- /// application code. Note that the passed in IDbCommand
- /// has been created by the framework and will have its
- /// Connection property set and the Transaction property
- /// set based on the transaction context.
Allows you to execute any number of operations
+ /// on a single IDbCommand, for example a single ExecuteScalar
+ /// call or repeated execute calls with varying parameters.
+ ///
+ ///
Used internally by AdoTemplate, but also useful for
+ /// application code. Note that the passed in IDbCommand
+ /// has been created by the framework and will have its
+ /// Connection property set and the Transaction property
+ /// set based on the transaction context.
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
- /// This method allows the object instance to perform the kind of
- /// initialization only possible when all of it's dependencies have
- /// been injected (set), and to throw an appropriate exception in the
- /// event of misconfiguration.
- ///
- ///
- /// Please do consult the class level documentation for the
- /// interface for a
- /// description of exactly when this method is invoked. In
- /// particular, it is worth noting that the
- ///
- /// and
- /// callbacks will have been invoked prior to this method being
- /// called.
- ///
+ /// This method allows the object instance to perform the kind of
+ /// initialization only possible when all of it's dependencies have
+ /// been injected (set), and to throw an appropriate exception in the
+ /// event of misconfiguration.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///
+ ///
+ ///
+ /// In the event of misconfiguration (such as the failure to set a
+ /// required property) or if initialization fails.
+ ///
+ public abstract void AfterPropertiesSet();
+
+ ///
+ /// Creates the data reader wrapper for use in AdoTemplate callback methods.
+ ///
+ /// The reader to wrap.
+ /// The data reader used in AdoTemplate callbacks
+ public abstract IDataReader CreateDataReaderWrapper(IDataReader readerToWrap);
+
+ ///
+ /// Creates the a db parameters collection, adding to the collection a parameter created from
+ /// the method parameters.
+ ///
+ /// The name of the parameter
+ /// The type of the parameter.
+ /// The size of the parameter, for use in defining lengths of string values. Use
+ /// 0 if not applicable.
+ /// The parameter value.
+ /// A collection of db parameters with a single parameter in the collection based
+ /// on the method parameters
+ protected IDbParameters CreateDbParameters(string name, Enum dbType, int size, object parameterValue)
+ {
+ IDbParameters parameters = new DbParameters(DbProvider);
+ parameters.Add(name, dbType, size).Value = parameterValue;
+ return parameters;
+ }
+
+
+ #region Parameter Creation Helper Methods
+
+ ///
+ /// Creates a new instance of
+ ///
+ /// a new instance of
+ public virtual IDbParameters CreateDbParameters()
+ {
+ return new DbParameters(DbProvider);
+ }
+
+ ///
+ /// Derives the parameters of a stored procedure, not including the return parameter.
+ ///
+ /// Name of the procedure.
+ /// The stored procedure parameters.
+ public virtual IDataParameter[] DeriveParameters(string procedureName)
+ {
+ return DeriveParameters(procedureName, false);
+ }
+
+ ///
+ /// Derives the parameters of a stored procedure including the return parameter
+ ///
+ /// Name of the procedure.
+ /// if set to true to include return parameter.
+ /// The stored procedure parameters
+ public abstract IDataParameter[] DeriveParameters(string procedureName, bool includeReturnParameter);
+
+ #endregion
+ }
+}
diff --git a/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs b/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs
index 2b8aae91..138f7287 100644
--- a/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs
+++ b/src/Spring/Spring.Data/Data/Core/AdoDaoSupport.cs
@@ -1,142 +1,142 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-using System;
-using System.Data;
-using Spring.Dao.Support;
-using Spring.Data.Common;
-using Spring.Data.Support;
-
-namespace Spring.Data.Core
-{
- ///
- /// Convenient super class for ADO.NET data access objects.
- ///
- ///
- /// Requires a IDBProvider to be set, providing a
- /// AdoTemplate based on it to subclasses.
- /// This base class is mainly intended for AdoTemplate usage.
- ///
- public class AdoDaoSupport : DaoSupport
- {
- private AdoTemplate adoTemplate;
-
- ///
- /// The DbProvider instance used by this DAO
- ///
- public IDbProvider DbProvider
- {
- set
- {
- adoTemplate = CreateAdoTemplate(value);
- }
- get
- {
- if (adoTemplate != null)
- {
- return adoTemplate.DbProvider;
- }
- else
- {
- return null;
- }
- }
-
- }
-
- ///
- /// Set the AdoTemplate for this DAO explicity, as
- /// an alternative to specifying a IDbProvider
- ///
- public AdoTemplate AdoTemplate
- {
- set
- {
- adoTemplate = value;
- }
- get
- {
- return adoTemplate;
- }
-
- }
-
- protected override void CheckDaoConfig()
- {
- if (adoTemplate == null)
- {
- throw new ArgumentException("DbProvider or AdoTemplate is required");
- }
- }
-
- protected IDbConnection Connection
- {
- get
- {
- return ConnectionUtils.GetConnection(DbProvider);
- }
- }
-
- protected IAdoExceptionTranslator ExceptionTranslator
- {
- get
- {
- return null; //Investigate AdoExceptionTranslator on AdoAccessor
- }
- }
-
- protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider)
- {
- ConnectionUtils.DisposeConnection(conn, dbProvider);
- }
-
-
- ///
- /// Create a AdoTemplate for a given DbProvider
- /// Only invoked if populating the DAO with a DbProvider reference.
- ///
- ///
- /// Can be overriden in subclasses to provide AdoTemplate instances
- /// with a different configuration, or a cusotm AdoTemplate subclass.
- ///
- /// The DbProvider to create a AdoTemplate for
- protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider)
- {
- return new AdoTemplate(dbProvider);
- }
-
- ///
- /// Convenience method to create a parameters builder.
- ///
- /// Virtual for sublcasses to override with custom
- /// implementation.
- /// A new DbParameterBuilder
- protected virtual IDbParametersBuilder CreateDbParametersBuilder()
- {
- return new DbParametersBuilder(DbProvider);
- }
-
- protected virtual IDbParameters CreateDbParameters()
- {
- return AdoTemplate.CreateDbParameters();
- }
-
- }
-}
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Data;
+using Spring.Dao.Support;
+using Spring.Data.Common;
+using Spring.Data.Support;
+
+namespace Spring.Data.Core
+{
+ ///
+ /// Convenient super class for ADO.NET data access objects.
+ ///
+ ///
+ /// Requires a IDBProvider to be set, providing a
+ /// AdoTemplate based on it to subclasses.
+ /// This base class is mainly intended for AdoTemplate usage.
+ ///
+ public class AdoDaoSupport : DaoSupport
+ {
+ private AdoTemplate adoTemplate;
+
+ ///
+ /// The DbProvider instance used by this DAO
+ ///
+ public IDbProvider DbProvider
+ {
+ set
+ {
+ adoTemplate = CreateAdoTemplate(value);
+ }
+ get
+ {
+ if (adoTemplate != null)
+ {
+ return adoTemplate.DbProvider;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ }
+
+ ///
+ /// Set the AdoTemplate for this DAO explicity, as
+ /// an alternative to specifying a IDbProvider
+ ///
+ public AdoTemplate AdoTemplate
+ {
+ set
+ {
+ adoTemplate = value;
+ }
+ get
+ {
+ return adoTemplate;
+ }
+
+ }
+
+ protected override void CheckDaoConfig()
+ {
+ if (adoTemplate == null)
+ {
+ throw new ArgumentException("DbProvider or AdoTemplate is required");
+ }
+ }
+
+ protected IDbConnection Connection
+ {
+ get
+ {
+ return ConnectionUtils.GetConnection(DbProvider);
+ }
+ }
+
+ protected IAdoExceptionTranslator ExceptionTranslator
+ {
+ get
+ {
+ return null; //Investigate AdoExceptionTranslator on AdoAccessor
+ }
+ }
+
+ protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider)
+ {
+ ConnectionUtils.DisposeConnection(conn, dbProvider);
+ }
+
+
+ ///
+ /// Create a AdoTemplate for a given DbProvider
+ /// Only invoked if populating the DAO with a DbProvider reference.
+ ///
+ ///
+ /// Can be overriden in subclasses to provide AdoTemplate instances
+ /// with a different configuration, or a cusotm AdoTemplate subclass.
+ ///
+ /// The DbProvider to create a AdoTemplate for
+ protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider)
+ {
+ return new AdoTemplate(dbProvider);
+ }
+
+ ///
+ /// Convenience method to create a parameters builder.
+ ///
+ /// Virtual for sublcasses to override with custom
+ /// implementation.
+ /// A new DbParameterBuilder
+ protected virtual IDbParametersBuilder CreateDbParametersBuilder()
+ {
+ return new DbParametersBuilder(DbProvider);
+ }
+
+ protected virtual IDbParameters CreateDbParameters()
+ {
+ return AdoTemplate.CreateDbParameters();
+ }
+
+ }
+}
diff --git a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
index 612aafa9..388290e7 100644
--- a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
+++ b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
@@ -1,431 +1,430 @@
-#region License
-
-/*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#endregion
-
-#region Imports
-
-using System;
-using System.Data;
-using Common.Logging;
-using Spring.Data.Common;
-using Spring.Data.Support;
-using Spring.Objects.Factory;
-using Spring.Transaction;
-using Spring.Transaction.Support;
-
-#endregion
-namespace Spring.Data.Core
-{
- ///
- /// ADO.NET based implementation of the
- /// interface.
- ///
- /// Mark Pollack (.NET)
- /// $Id: AdoPlatformTransactionManager.cs,v 1.7 2007/11/30 18:42:11 markpollack Exp $
- public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IInitializingObject
- {
-
- private IDbProvider dbProvider;
-
- #region Logging Definition
-
- private static readonly ILog LOG = LogManager.GetLogger(typeof (AdoPlatformTransactionManager));
-
- #endregion
-
- public AdoPlatformTransactionManager()
- {
- NestedTransactionsAllowed = true;
- }
-
- public AdoPlatformTransactionManager(IDbProvider dbProvider) : this()
- {
- DbProvider = dbProvider;
-
- }
-
- #region Propeties
-
- public IDbProvider DbProvider
- {
- get { return dbProvider; }
- set { dbProvider = value; }
- }
-
- #endregion
-
- ///
- /// Return the current transaction object.
- ///
- /// The current transaction object.
- ///
- /// If transaction support is not available.
- ///
- ///
- /// In the case of lookup or system errors.
- ///
- protected override object DoGetTransaction()
- {
- DbProviderTransactionObject txMgrStateObject =
- new DbProviderTransactionObject();
- txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed;
- ConnectionHolder conHolder =
- (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider);
- txMgrStateObject.SetConnectionHolder(conHolder, false);
- return txMgrStateObject;
- }
-
- ///
- /// Check if the given transaction object indicates an existing,
- /// i.e. already begun, transaction.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- /// True if there is an existing transaction.
- ///
- /// In the case of system errors.
- ///
- protected override bool IsExistingTransaction(object transaction)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)transaction;
- return (txMgrStateObject.ConnectionHolder != null
- &&
- txMgrStateObject.ConnectionHolder.TransactionActive);
-
- }
-
- ///
- /// Begin a new transaction with the given transaction definition.
- ///
- ///
- /// Transaction object returned by
- /// .
- ///
- ///
- /// instance, describing
- /// propagation behavior, isolation level, timeout etc.
- ///
- ///
- /// Does not have to care about applying the propagation behavior,
- /// as this has already been handled by this abstract manager.
- ///
- ///
- /// In the case of creation or system errors.
- ///
- protected override void DoBegin(object transaction, ITransactionDefinition definition)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)transaction;
- IDbConnection con = null;
-
- if (dbProvider == null)
- {
- throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager");
- }
-
- try
- {
- if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction)
- {
- IDbConnection newCon = DbProvider.CreateConnection();
- if (log.IsDebugEnabled)
- {
- log.Debug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction");
- }
- newCon.Open();
-
- //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData
- //MSDN docs...
- //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation
-
-
- //IsolationLevel previousIsolationLevel =
-
- IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel);
-
- txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true);
-
- }
- txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true;
- con = txMgrStateObject.ConnectionHolder.Connection;
-
-
- txMgrStateObject.ConnectionHolder.TransactionActive = true;
-
- int timeout = DetermineTimeout(definition);
- if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
- {
- txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout;
- }
-
-
- //Bind transactional resources to thread
- if (txMgrStateObject.NewConnectionHolder)
- {
- TransactionSynchronizationManager.BindResource(DbProvider,
- txMgrStateObject.ConnectionHolder);
- }
-
- }
- //TODO catch specific exception
- catch (Exception e)
- {
- ConnectionUtils.DisposeConnection(con, DbProvider);
- throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e);
- }
-
- }
-
-
- ///
- /// Suspend the resources of the current transaction.
- ///
- /// Transaction object returned by
- /// .
- ///
- /// An object that holds suspended resources (will be kept unexamined for passing it into
- /// .)
- ///
- ///
- /// Transaction synchronization will already have been suspended.
- ///
- ///
- /// If suspending is not supported by the transaction manager implementation.
- ///
- ///
- /// in case of system errors.
- ///
- protected override object DoSuspend(object transaction)
- {
- DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction;
- txMgrStateObject.ConnectionHolder = null;
- ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider);
- return conHolder;
- }
-
-
- ///
- /// Resume the resources of the current transaction.
- ///
- /// Transaction object returned by
- /// .
- /// The object that holds suspended resources as returned by
- /// .
- ///
- /// Transaction synchronization will be resumed afterwards.
- ///
- ///
- /// If suspending is not supported by the transaction manager implementation.
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoResume(object transaction, object suspendedResources)
- {
- ConnectionHolder conHolder = (ConnectionHolder)suspendedResources;
- TransactionSynchronizationManager.BindResource(DbProvider, conHolder);
- }
-
-
- ///
- /// Perform an actual commit on the given transaction.
- ///
- /// The status representation of the transaction.
- ///
- ///
- /// An implementation does not need to check the rollback-only flag.
- ///
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoCommit(DefaultTransactionStatus status)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)status.Transaction;
- IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction;
- if (status.Debug)
- {
- IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection;
- log.Debug("Committing ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]");
- }
- try
- {
- trans.Commit();
- }
- catch (Exception e)
- {
- throw new TransactionSystemException("Could not commit ADO.NET transaction", e);
- }
-
- }
-
- ///
- /// Perform an actual rollback on the given transaction.
- ///
- /// The status representation of the transaction.
- ///
- /// An implementation does not need to check the new transaction flag.
- ///
- ///
- /// In the case of system errors.
- ///
- protected override void DoRollback(DefaultTransactionStatus status)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)status.Transaction;
- IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection;
- IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction;
- if (status.Debug)
- {
- log.Debug("Rolling back ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]" );
- }
- try
- {
- trans.Rollback();
- }
- catch (Exception e)
- {
- throw new TransactionSystemException("Could not rollback ADO.NET transaction", e);
- }
- }
-
- ///
- /// Set the given transaction rollback-only. Only called on rollback
- /// if the current transaction takes part in an existing one.
- ///
- /// The status representation of the transaction.
- ///
- /// In the case of system errors.
- ///
- protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)status.Transaction;
- if (status.Debug)
- {
- IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection;
- log.Debug("Setting ADO.NET transaction [" + conn + ", " + conn.ConnectionString + "] rollback-only.");
- }
- txMgrStateObject.SetRollbackOnly();
-
- }
-
- protected override void DoCleanupAfterCompletion(object transaction)
- {
- DbProviderTransactionObject txMgrStateObject =
- (DbProviderTransactionObject)transaction;
- if (txMgrStateObject.NewConnectionHolder)
- {
- TransactionSynchronizationManager.UnbindResource(DbProvider);
- }
- IDbConnection con = txMgrStateObject.ConnectionHolder.Connection;
-
- if (log.IsDebugEnabled)
- {
- log.Debug("Releasing ADO.NET Connection [" + con + ", " + con.ConnectionString + "] after transaction");
- }
-
- ConnectionUtils.DisposeConnection(con, DbProvider);
- //TODO clear out IDbTransaction object?
-
- txMgrStateObject.ConnectionHolder.Clear();
-
-
- }
-
-
-
- ///
- /// DbProvider transaction (state) object, representing a ConnectionHolder.
- /// Used as a transaction object by AdoPlatformTransactionManager
- ///
- /// Derives from AdoTransactionObjectSupport to inherit the capability
- /// to manage Savepoints.
- ///
- ///
- private class DbProviderTransactionObject : AdoTransactionObjectSupport
- {
- private bool newConnectionHolder;
-
- public void SetConnectionHolder(ConnectionHolder connectionHolder,
- bool newConnection)
- {
- ConnectionHolder = connectionHolder;
- newConnectionHolder = newConnection;
- }
-
- public bool NewConnectionHolder
- {
- get
- {
- return newConnectionHolder;
- }
- }
-
- public bool HasTransaction
- {
- get
- {
- return (ConnectionHolder != null && ConnectionHolder.TransactionActive);
- }
- }
-
- ///
- /// Sets the rollback only.
- ///
- public void SetRollbackOnly()
- {
- ConnectionHolder.RollbackOnly = true;
- }
-
- ///
- /// Return whether the transaction is internally marked as rollback-only.
- ///
- ///
- /// True of the transaction is marked as rollback-only.
- public override bool RollbackOnly
- {
- get
- {
- return ConnectionHolder.RollbackOnly;
- }
- }
-
- }
-
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- /// If DbProvider is null.
- ///
- public void AfterPropertiesSet()
- {
- if (dbProvider == null)
- {
- throw new ArgumentException("DbProvider is required");
- }
- }
- }
-}
+#region License
+
+/*
+ * Copyright 2002-2004 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Data;
+using Common.Logging;
+using Spring.Data.Common;
+using Spring.Data.Support;
+using Spring.Objects.Factory;
+using Spring.Transaction;
+using Spring.Transaction.Support;
+
+#endregion
+namespace Spring.Data.Core
+{
+ ///
+ /// ADO.NET based implementation of the
+ /// interface.
+ ///
+ /// Mark Pollack (.NET)
+ public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IInitializingObject
+ {
+
+ private IDbProvider dbProvider;
+
+ #region Logging Definition
+
+ private static readonly ILog LOG = LogManager.GetLogger(typeof (AdoPlatformTransactionManager));
+
+ #endregion
+
+ public AdoPlatformTransactionManager()
+ {
+ NestedTransactionsAllowed = true;
+ }
+
+ public AdoPlatformTransactionManager(IDbProvider dbProvider) : this()
+ {
+ DbProvider = dbProvider;
+
+ }
+
+ #region Propeties
+
+ public IDbProvider DbProvider
+ {
+ get { return dbProvider; }
+ set { dbProvider = value; }
+ }
+
+ #endregion
+
+ ///
+ /// Return the current transaction object.
+ ///
+ /// The current transaction object.
+ ///
+ /// If transaction support is not available.
+ ///
+ ///
+ /// In the case of lookup or system errors.
+ ///
+ protected override object DoGetTransaction()
+ {
+ DbProviderTransactionObject txMgrStateObject =
+ new DbProviderTransactionObject();
+ txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed;
+ ConnectionHolder conHolder =
+ (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider);
+ txMgrStateObject.SetConnectionHolder(conHolder, false);
+ return txMgrStateObject;
+ }
+
+ ///
+ /// Check if the given transaction object indicates an existing,
+ /// i.e. already begun, transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ /// True if there is an existing transaction.
+ ///
+ /// In the case of system errors.
+ ///
+ protected override bool IsExistingTransaction(object transaction)
+ {
+ DbProviderTransactionObject txMgrStateObject =
+ (DbProviderTransactionObject)transaction;
+ return (txMgrStateObject.ConnectionHolder != null
+ &&
+ txMgrStateObject.ConnectionHolder.TransactionActive);
+
+ }
+
+ ///
+ /// Begin a new transaction with the given transaction definition.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// instance, describing
+ /// propagation behavior, isolation level, timeout etc.
+ ///
+ ///
+ /// Does not have to care about applying the propagation behavior,
+ /// as this has already been handled by this abstract manager.
+ ///
+ ///
+ /// In the case of creation or system errors.
+ ///
+ protected override void DoBegin(object transaction, ITransactionDefinition definition)
+ {
+ DbProviderTransactionObject txMgrStateObject =
+ (DbProviderTransactionObject)transaction;
+ IDbConnection con = null;
+
+ if (dbProvider == null)
+ {
+ throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager");
+ }
+
+ try
+ {
+ if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction)
+ {
+ IDbConnection newCon = DbProvider.CreateConnection();
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction");
+ }
+ newCon.Open();
+
+ //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData
+ //MSDN docs...
+ //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation
+
+
+ //IsolationLevel previousIsolationLevel =
+
+ IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel);
+
+ txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true);
+
+ }
+ txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true;
+ con = txMgrStateObject.ConnectionHolder.Connection;
+
+
+ txMgrStateObject.ConnectionHolder.TransactionActive = true;
+
+ int timeout = DetermineTimeout(definition);
+ if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
+ {
+ txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout;
+ }
+
+
+ //Bind transactional resources to thread
+ if (txMgrStateObject.NewConnectionHolder)
+ {
+ TransactionSynchronizationManager.BindResource(DbProvider,
+ txMgrStateObject.ConnectionHolder);
+ }
+
+ }
+ //TODO catch specific exception
+ catch (Exception e)
+ {
+ ConnectionUtils.DisposeConnection(con, DbProvider);
+ throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e);
+ }
+
+ }
+
+
+ ///
+ /// Suspend the resources of the current transaction.
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ /// An object that holds suspended resources (will be kept unexamined for passing it into
+ /// .)
+ ///
+ ///
+ /// Transaction synchronization will already have been suspended.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// in case of system errors.
+ ///
+ protected override object DoSuspend(object transaction)
+ {
+ DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction;
+ txMgrStateObject.ConnectionHolder = null;
+ ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.UnbindResource(DbProvider);
+ return conHolder;
+ }
+
+
+ ///
+ /// Resume the resources of the current transaction.
+ ///
+ /// Transaction object returned by
+ /// .
+ /// The object that holds suspended resources as returned by
+ /// .
+ ///
+ /// Transaction synchronization will be resumed afterwards.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoResume(object transaction, object suspendedResources)
+ {
+ ConnectionHolder conHolder = (ConnectionHolder)suspendedResources;
+ TransactionSynchronizationManager.BindResource(DbProvider, conHolder);
+ }
+
+
+ ///
+ /// Perform an actual commit on the given transaction.
+ ///
+ /// The status representation of the transaction.
+ ///
+ ///
+ /// An implementation does not need to check the rollback-only flag.
+ ///
- /// Note that a RowMapper object is typically stateless and thus reusable;
- /// just the RowMapperResultSetExtractor adapter is stateful.
- ///
- ///
- /// As an alternative consider subclassing MappingAdoQuery from the
- /// Spring.Data.Objects namespace: Instead of working with separate
- /// AdoTemplate and IRowMapper objects you can have executable
- /// query objects (containing row-mapping logic) there.
- ///
+ /// Note that a RowMapper object is typically stateless and thus reusable;
+ /// just the RowMapperResultSetExtractor adapter is stateful.
+ ///
+ ///
+ /// As an alternative consider subclassing MappingAdoQuery from the
+ /// Spring.Data.Objects namespace: Instead of working with separate
+ /// AdoTemplate and IRowMapper objects you can have executable
+ /// query objects (containing row-mapping logic) there.
+ ///