#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using Spring.Objects.Support;
#endregion
namespace Spring.Objects.Factory.Config{
/// <summary>
/// An <see cref="Spring.Objects.Factory.IFactoryObject"/> that returns a value
/// that is the result of a <see langword="static"/> or instance method invocation.
/// </summary>
/// <remarks>
/// <p>
/// 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
/// <see cref="Spring.Objects.Factory.Config.MethodInvokingFactoryObject.GetObject()"/>
/// by the owning object factory will cause a method invocation, the return
/// value of which will be cached for all subsequent requests. The
/// <see cref="MethodInvokingFactoryObject.IsSingleton"/> property may be set to
/// <see langword="false"/>, to cause this factory to invoke the target method each
/// time it is asked for an object.
/// </p>
/// <p>
/// A <see langword="static"/> target method may be specified by setting the
/// <see cref="Spring.Objects.Support.MethodInvoker.TargetMethod"/> property to a string representing
/// the <see langword="static"/> method name, with <see cref="Spring.Objects.Support.MethodInvoker.TargetType"/> specifying
/// the <see cref="System.Type"/> that the <see langword="static"/> method is defined on.
/// Alternatively, a target instance method may be specified, by setting the
/// <see cref="Spring.Objects.Support.MethodInvoker.TargetObject"/> property as the target object, and
/// the <see cref="Spring.Objects.Support.MethodInvoker.TargetMethod"/> property as the name of the
/// method to call on that target object. Arguments for the method invocation may be
/// specified by setting the <see cref="Spring.Objects.Support.MethodInvoker.Arguments"/> property.
/// </p>
/// <p>
/// 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 <see langword="static"/> 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.
/// </p>
/// <p>
/// <note>
/// This class depends on the
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet()"/>
/// method being called after all properties have been set, as per the
/// <see cref="Spring.Objects.Factory.IInitializingObject"/> contract. If you are
/// using this class outside of a Spring.NET IoC container, you must call one of either
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet()"/> or
/// <see cref="Spring.Objects.Support.MethodInvoker.Prepare()"/> yourself to ready the object's internal
/// state, or you will get a nasty <see cref="System.NullReferenceException"/>.
/// </note>
/// </p>
/// </remarks>
/// <example>
/// <p>
/// The following example uses an instance of this class to call a <see langword="static"/>
/// factory method...
/// </p>
/// <code escaped="true">
/// <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
/// <property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/>
/// <property name="TargetMethod" value="Instance"/>
/// <!-- the ordering of arguments is significant -->
/// <property name="Arguments">
/// <list>
/// <value>1st</value>
/// <value>2nd</value>
/// <value>and 3rd arguments</value>
/// </list>
/// </property>
/// </object>
/// </code>
/// <p>
/// 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...
/// </p>
/// <code language="C#">
/// </code>
/// <code escaped="true">
/// <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
/// <property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/>
/// <property name="TargetMethod" value="Instance"/>
/// <!-- the ordering of arguments is significant -->
/// <property name="Arguments">
/// <list>
/// <!-- a primitive type (a string) -->
/// <value>1st</value>
/// <!-- an inner object definition is passed as the second argument -->
/// <object type="Whatever.SomeClass, MyAssembly"/>
/// <!-- a reference to another objects is passed as the third argument -->
/// <ref object="someOtherObject"/>
/// <!-- another list is passed as the fourth argument -->
/// <list>
/// <value>http://www.springframework.net/</value>
/// </list>
/// </list>
/// </property>
/// </object>
/// </code>
/// <p>
/// Named parameters are also supported... this next example yields the same results as
/// the preceding example (that did not use named arguments).
/// </p>
/// <code escaped="true">
/// <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
/// <property name="TargetObject">
/// <object type="Whatever.MyClassFactory, MyAssembly"/>
/// </property>
/// <property name="TargetMethod" value="Execute"/>
/// <!-- the ordering of named arguments is not significant -->
/// <property name="NamedArguments">
/// <dictionary>
/// <entry key="argumentName"><value>1st</value></entry>
/// <entry key="finalArgumentName"><value>and 3rd arguments</value></entry>
/// <entry key="anotherArgumentName"><value>2nd</value></entry>
/// </dictionary>
/// </property>
/// </object>
/// </code>
/// <p>
/// Similarly, the following example uses an instance of this class to call an instance method...
/// </p>
/// <code escaped="true">
/// <object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
/// <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
/// <property name="TargetObject">
/// <ref local="myMethodObject"/>
/// </property>
/// <property name="TargetMethod" value="Execute"/>
/// </object>
/// </code>
/// <p>
/// 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.
/// </p>
/// <code escaped="true">
/// <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
/// <property name="TargetObject">
/// <object type="Whatever.MyClassFactory, MyAssembly"/>
/// </property>
/// <property name="TargetMethod" value="Execute"/>
/// </object>
/// </code>
/// </example>
/// <author>Colin Sampaleanu</author>
/// <author>Juergen Hoeller</author>
/// <author>Rick Evans (.NET)</author>
/// <author>Simon White (.NET)</author>
/// <seealso cref="Spring.Objects.Support.MethodInvoker"/>
/// <seealso cref="Spring.Objects.Support.ArgumentConvertingMethodInvoker"/>
[Serializable]
public class MethodInvokingFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IInitializingObject
{
private bool singleton = true;
private object singletonObject;
/// <summary>
/// If a singleton should be created, or a new object on each request.
/// Defaults to <see langword="true"/>.
/// </summary>
public bool IsSingleton
{
get { return singleton; }
set { singleton = value; }
}
/// <summary>
/// Return the return value <see cref="System.Type"/> of the method
/// that this factory invokes, or <see langword="null"/> if not
/// known in advance.
/// </summary>
/// <remarks>
/// <p>
/// If the return value of the method that this factory is to invoke is
/// <see langword="void"/>, then the <see cref="System.Reflection.Missing"/>
/// <see cref="System.Type"/> will be returned (in accordance with the
/// <see cref="Spring.Objects.Factory.IFactoryObject"/> contract that
/// treats a <see langword="null"/> value as a configuration error).
/// </p>
/// </remarks>
/// <seealso cref="Spring.Objects.Factory.IFactoryObject.ObjectType"/>
public Type ObjectType
{
get
{
Type objectType = null;
if (GetPreparedMethod() != null)
{
objectType = GetPreparedMethod().ReturnType;
if (objectType.Equals(typeof (void)))
{
objectType = Void.GetType();
}
}
return objectType;
}
}
/// <summary>
/// Return an instance (possibly shared or independent) of the object
/// managed by this factory.
/// </summary>
/// <remarks>
/// <p>
/// Returns the return value of the method that is to be invoked.
/// </p>
/// <p>
/// Will return the same value each time if the
/// <see cref="Spring.Objects.Factory.IFactoryObject.IsSingleton"/>
/// property value is <see langword="true"/>.
/// </p>
/// </remarks>
/// <returns>
/// An instance (possibly shared or independent) of the object managed by
/// this factory.
/// </returns>
/// <seealso cref="Spring.Objects.Factory.IFactoryObject.GetObject"/>
public object GetObject()
{
if (singleton)
{
if (singletonObject == null)
{
singletonObject = Invoke();
}
return singletonObject;
}
return Invoke();
}
/// <summary>
/// Prepares this method invoker.
/// </summary>
/// <exception cref="System.ArgumentException">
/// If all required properties are not set.
/// </exception>
/// <exception cref="System.MissingMethodException">
/// If the specified method could not be found.
/// </exception>
/// <seealso cref="Spring.Objects.Support.ArgumentConvertingMethodInvoker.Prepare()"/>
public void AfterPropertiesSet()
{
Prepare();
}
}
}
|