#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.Serialization;
using Common.Logging;
using Spring.Collections;
using Spring.Core;
using Spring.Core.TypeConversion;
using Spring.Objects.Factory.Config;
using Spring.Threading;
using Spring.Util;
#endregion
namespace Spring.Objects.Factory.Support{
/// <summary>
/// Abstract superclass for <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// implementations.
/// </summary>
/// <remarks>
/// <p>
/// This class provides singleton / prototype determination, singleton caching,
/// object definition aliasing, <see cref="Spring.Objects.Factory.IFactoryObject"/>
/// handling, and object definition merging for child object definitions.
/// </p>
/// </remarks>
/// <author>Rod Johnson</author>
/// <author>Juergen Hoeller</author>
/// <author>Rick Evans (.NET)</author>
[Serializable]
public abstract class AbstractObjectFactory : IConfigurableObjectFactory
{
[Serializable]
private class LogicalThreadContextSetVariable : IDisposable
{
private readonly string name = Guid.NewGuid().ToString();
public ISet Value
{
get
{
ISet set = LogicalThreadContext.GetData(this.name) as ISet;
if (set == null)
{
set = CreateSet();
LogicalThreadContext.SetData(this.name, set);
}
return set;
}
}
#region Implementation of IDisposable
public void Dispose()
{
LogicalThreadContext.FreeNamedDataSlot(this.name);
}
#endregion
private ISet CreateSet()
{
return new HashedSet();
}
}
/// <summary>
/// Makes a distinction between sort order and object identity.
/// This is important when used with <see cref="ISet"/>, since most
/// implementations assume Order == Identity
/// </summary>
[Serializable]
private class ObjectOrderComparator : OrderComparator
{
/// <summary>
/// Handle the case when both objects have equal sort order priority. By default returns 0,
/// but may be overriden for handling special cases.
/// </summary>
/// <param name="o1">The first object to compare.</param>
/// <param name="o2">The second object to compare.</param>
/// <returns>
/// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal.
/// </returns>
protected override int CompareEqualOrder(object o1, object o2)
{
if (ReferenceEquals(o1, o2))
return 0;
if (o1 == null)
return 1;
if (o2 == null)
return -1;
return o1.GetHashCode().CompareTo(o2.GetHashCode());
}
}
/// <summary>
/// Marker object to be temporarily registered in the singleton cache,
/// while instantiating an object (in order to be able to detect circular references).
/// </summary>
private static readonly object CURRENTLY_IN_CREATION = new Object();
/// <summary>
/// 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.
/// </summary>
private static readonly object EMPTYOBJECT = new object();
/// <summary>
/// The <see cref="Common.Logging.ILog"/> instance for this class.
/// </summary>
private readonly ILog log;
/// <summary>
/// Cache of singleton objects created by <see cref="IFactoryObject"/>s: FactoryObject name -> product
/// </summary>
private readonly Hashtable factoryObjectProductCache = new Hashtable();
#region Constructor (s) / Destructor
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory"/> class.
/// </summary>
/// <remarks>
/// <p>
/// This constructor implicitly creates an
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory"/>
/// that treats the names of objects in this factory in a case-sensitive fashion.
/// </p>
/// <p>
/// This is an <see langword="abstract"/> class, and as such exposes no public constructors.
/// </p>
/// </remarks>
protected AbstractObjectFactory()
: this(true)
{ }
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory"/> class.
/// </summary>
/// <remarks>
/// <p>
/// This is an <see langword="abstract"/> class, and as such exposes no public constructors.
/// </p>
/// </remarks>
/// <param name="caseSensitive">
/// <see lang="true"/> if the names of objects in this factory are to be treated in a
/// case-sensitive fashion.
/// </param>
protected AbstractObjectFactory(bool caseSensitive)
{
this.log = LogManager.GetLogger(this.GetType());
this.caseSensitive = caseSensitive;
#if NET_1_0 || NET_1_1
if (caseSensitive)
{
this.aliasMap = new Hashtable();
this.singletonCache = new Hashtable();
this.singletonsInCreation = new Hashtable();
}
else
{
this.aliasMap = new CaseInsensitiveHashtable();
this.singletonCache = new CaseInsensitiveHashtable();
this.singletonsInCreation = new CaseInsensitiveHashtable();
}
#else
IEqualityComparer comparer = (caseSensitive) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
this.aliasMap = new OrderedDictionary(comparer);
this.singletonCache = new OrderedDictionary(comparer);
this.singletonsInCreation = new OrderedDictionary(comparer);
#endif
this.prototypesInCreation = new LogicalThreadContextSetVariable();
}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory"/> class.
/// </summary>
/// <remarks>
/// <p>
/// This is an <see langword="abstract"/> class, and as such exposes no public constructors.
/// </p>
/// </remarks>
/// <param name="caseSensitive">
/// <see lang="true"/> if the names of objects in this factory are to be treated in a
/// case-sensitive fashion.
/// </param>
/// <param name="parentFactory">
/// Any parent object factory; may be <see lang="null"/>.
/// </param>
protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory)
: this(caseSensitive)
{
ParentObjectFactory = parentFactory;
}
#endregion
#region Properties
/// <summary>
/// Returns, whether this factory treats object names case sensitive or not.
/// </summary>
public bool IsCaseSensitive
{
get { return caseSensitive; }
}
/// <summary>
/// Gets the <see cref="ISet"/> of
/// <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>s
/// that will be applied to objects created by this factory.
/// </summary>
public ISet ObjectPostProcessors
{
get { return objectPostProcessors; }
}
/// <summary>
/// Gets the set of classes that will be ignored for autowiring.
/// </summary>
/// <remarks>
/// <p>
/// The elements of this <see cref="Spring.Collections.ISet"/> are
/// <see cref="System.Type"/>s.
/// </p>
/// </remarks>
public ISet IgnoredDependencyTypes
{
get { return ignoreDependencyTypes; }
}
/// <summary>
/// Returns, whether this object factory instance contains <see cref="IInstantiationAwareObjectPostProcessor"/> objects.
/// </summary>
protected bool HasInstantiationAwareBeanPostProcessors
{
get { return hasInstantiationAwareBeanPostProcessors; }
}
/// <summary>
/// Returns, whether this object factory instance contains <see cref="IDestructionAwareObjectPostProcessor"/> objects.
/// </summary>
protected bool HasDestructionAwareBeanPostProcessors
{
get { return hasDestructionAwareBeanPostProcessors; }
}
#endregion
#region Methods
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name.
/// </summary>
/// <param name="name">The name of the object to return.</param>
/// <param name="requiredType">
/// The <see cref="System.Type"/> the object may match. Can be an interface or
/// superclass of the actual class. For example, if the value is the
/// <see cref="System.Object"/> class, this method will succeed whatever the
/// class of the returned instance.
/// </param>
/// <param name="arguments">
/// The arguments to use if creating a prototype using explicit arguments to
/// a <see lang="static"/> factory method. If there is no factory method and the
/// supplied <paramref name="arguments"/> array is not <see lang="null"/>, then
/// match the argument values by type and call the object's constructor.
/// </param>
/// <returns>The instance of the object.</returns>
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
/// If there's no such object definition.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// If the object could not be created.
/// </exception>
/// <exception cref="Spring.Objects.Factory.ObjectNotOfRequiredTypeException">
/// If the object is not of the required type.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="name"/> is <see langword="null"/>.
/// </exception>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string, Type)"/>
public object GetObject(string name, Type requiredType, object[] arguments)
{
return GetObjectInternal(name, requiredType, arguments, false);
}
/// <summary>
/// Apply the property values of the object definition with the supplied
/// <paramref name="name"/> to the supplied <paramref name="instance"/>.
/// </summary>
/// <remarks>
/// <p>
/// 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.
/// </p>
/// </remarks>
/// <param name="instance">
/// The existing object that the property values for the named object will
/// be applied to.
/// </param>
/// <param name="name">
/// The name of the object definition associated with the property values that are
/// to be applied.
/// </param>
/// <exception cref="Spring.Objects.ObjectsException">
/// In case of errors.
/// </exception>
public virtual void ApplyObjectPropertyValues(object instance, string name)
{
// explicit no-op...
}
/// <summary>
/// Apply the property values of the object definition with the supplied
/// <paramref name="name"/> to the supplied <paramref name="instance"/>.
/// </summary>
/// <remarks>
/// <p>
/// 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.
/// </p>
/// </remarks>
/// <param name="instance">
/// The existing object that the property values for the named object will
/// be applied to.
/// </param>
/// <param name="name">
/// The name of the object definition associated with the property values that are
/// to be applied.
/// </param>
/// <param name="definition">
/// An object definition that should be used to apply property values.
/// </param>
/// <exception cref="Spring.Objects.ObjectsException">
/// In case of errors.
/// </exception>
public virtual void ApplyObjectPropertyValues(object instance, string name, IObjectDefinition definition)
{
// explicit no-op...
}
// /// <summary>
// /// Create an object instance for the given object definition.
// /// </summary>
// /// <remarks>
// /// <p>
// /// The object definition will already have been merged with the parent
// /// definition in case of a child definition.
// /// </p>
// /// <p>
// /// 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.
// /// </p>
// /// </remarks>
// /// <param name="name">The name of the object.</param>
// /// <param name="definition">
// /// The object definition for the object that is to be instantiated.
// /// </param>
// /// <param name="arguments">
// /// The arguments to use if creating a prototype using explicit arguments to
// /// a <see lang="static"/> factory method. If there is no factory method and the
// /// supplied <paramref name="arguments"/> array is not <see lang="null"/>,
// /// then match the argument values by type and call the object's constructor.
// /// </param>
// /// <returns>
// /// A new instance of the object.
// /// </returns>
// /// <exception cref="Spring.Objects.ObjectsException">
// /// In case of errors.
// /// </exception>
// protected internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments);
/// <summary>
/// Create an object instance for the given object definition.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <param name="definition">
/// The object definition for the object that is to be instantiated.
/// </param>
/// <param name="arguments">
/// The arguments to use if creating a prototype using explicit arguments to
/// a static factory method. It is invalid to use a non-<see langword="null"/> arguments value
/// in any other case.
/// </param>
/// <param name="allowEagerCaching">
/// Whether eager caching of singletons is allowed... typically true for
/// singlton objects, but never true for inner object definitions.
/// </param>
/// <param name="suppressConfigure">
/// Create instance only - suppress injecting dependencies yet.
/// </param>
/// <returns>
/// A new instance of the object.
/// </returns>
/// <exception cref="Spring.Objects.ObjectsException">
/// In case of errors.
/// </exception>
/// <remarks>
/// <p>
/// The object definition will already have been merged with the parent
/// definition in case of a child definition.
/// </p>
/// <p>
/// 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.
/// </p>
/// </remarks>
protected internal abstract object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments,
bool allowEagerCaching, bool suppressConfigure);
/// <summary>
/// Destroy the target object.
/// </summary>
/// <remarks>
/// <p>
/// Must destroy objects that depend on the given object before the object itself,
/// nor throw an exception.
/// </p>
/// </remarks>
/// <param name="name">
/// The name of the object.
/// </param>
/// <param name="target">
/// The target object instance to destroyed.
/// </param>
protected abstract void DestroyObject(string name, object target);
/// <summary>
/// Does this object factory contain an object definition with the
/// supplied <paramref name="name"/>?
/// </summary>
/// <remarks>
/// <p>
/// Does not consider any hierarchy this factory may participate in.
/// Invoked by
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory.ContainsObject"/>
/// when no cached singleton instance is found.
/// </p>
/// </remarks>
/// <param name="name">
/// The name of the object to look for.
/// </param>
/// <returns>
/// <see lang="true"/> if this object factory contains an object
/// definition with the supplied <paramref name="name"/>.
/// </returns>
public abstract bool ContainsObjectDefinition(string name);
/// <summary>
/// Adds the supplied <paramref name="singleton"/> (object) to this factory's
/// singleton cache.
/// </summary>
/// <remarks>
/// <p>
/// To be called for eager registration of singletons, e.g. to be able to
/// resolve circular references.
/// </p>
/// <note>
/// If a singleton has already been registered under the same name as
/// the supplied <paramref name="name"/>, then the old singleton will
/// be replaced.
/// </note>
/// </remarks>
/// <param name="name">The name of the object.</param>
/// <param name="singleton">The singleton object.</param>
/// <exception cref="System.ArgumentNullException">
/// If the <paramref name="name"/> argument is <see langword="null"/>
/// or consists wholly of whitespace characters; or if the
/// <paramref name="singleton"/> is <see langword="null"/>.
/// </exception>
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;
registeredSingletons.Add(name);
}
}
/// <summary>
/// Return the object name, stripping out the factory dereference prefix if
/// necessary, and resolving aliases to canonical names.
/// </summary>
/// <param name="name">
/// The transformed name of the object.
/// </param>
protected string TransformedObjectName(string name)
{
string objectName = ObjectFactoryUtils.TransformedObjectName(name);
// handle aliasing...
lock (aliasMap)
{
string canonicalName = (string)aliasMap[objectName];
return canonicalName != null ? canonicalName : objectName;
}
}
/// <summary>
/// Ensures, that the given name is prefixed with <see cref="ObjectFactoryUtils.FactoryObjectPrefix"/>
/// if it incidentially already starts with this prefix. This avoids troubles when dereferencing
/// the object name during <see cref="ObjectFactoryUtils.TransformedObjectName"/>
/// </summary>
protected string OriginalObjectName(string name)
{
string objectName = TransformedObjectName(name);
if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix))
{
objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName;
}
return objectName;
}
/// <summary>
/// Determines whether the specified name is defined as an alias as opposed
/// to the name of an actual object definition.
/// </summary>
/// <param name="name">The object name to check.</param>
/// <returns>
/// <c>true</c> if the specified name is alias; otherwise, <c>false</c>.
/// </returns>
protected bool IsAlias(string name)
{
lock (aliasMap)
{
return aliasMap.Contains(name);
}
}
/// <summary>
/// Return a <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>,
/// even by traversing parent if the parameter is a child definition.
/// </summary>
/// <param name="name">
/// The name of the object.
/// </param>
/// <param name="includingAncestors">
/// Are ancestors to be included in the merge?
/// </param>
/// <remarks>
/// <p>
/// Will ask the parent object factory if not found in this instance.
/// </p>
/// </remarks>
/// <returns>
/// A merged <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>
/// with overridden properties.
/// </returns>
public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors)
{
return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors));
}
/// <summary>
/// Return a <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>,
/// even by traversing parent if the parameter is a child definition.
/// </summary>
/// <returns>
/// A merged <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>
/// with overridden properties.
/// </returns>
protected internal virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition od)
{
if (od == null)
{
return null;
}
RootObjectDefinition mod;
if (od.ParentName == null)
{
mod = CreateRootObjectDefinition(od);
}
else
{
// IObjectDefinition childDefinition = definition;
IObjectDefinition pod = null;
if (!name.Equals(od.ParentName))
{
pod = GetMergedObjectDefinition(TransformedObjectName(od.ParentName), true);
}
else
{
if (ParentObjectFactory is AbstractObjectFactory)
{
pod = ((AbstractObjectFactory)ParentObjectFactory).GetMergedObjectDefinition(od.ParentName, true);
}
}
if (pod == null)
{
throw new NoSuchObjectDefinitionException(od.ParentName,
string.Format(
"Parent name '{0}' is equal to object name '{1}' - "
+
"cannot be resolved without an AbstractObjectFactory parent.",
od.ParentName, name));
}
mod = CreateRootObjectDefinition(pod);
mod.OverrideFrom(od);
}
return mod;
}
/// <summary>
/// Creates the root object definition.
/// </summary>
/// <param name="templateDefinition">The template definition to base root definition on.</param>
/// <returns>Root object definition.</returns>
protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition)
{
return new RootObjectDefinition(templateDefinition);
}
/// <summary>
/// Register a new object definition with this registry.
/// </summary>
/// <param name="name">
/// The name of the object instance to register.
/// </param>
/// <param name="objectDefinition">
/// The definition of the object instance to register.
/// </param>
/// <exception cref="Spring.Objects.ObjectsException">
/// If the object definition is invalid.
/// </exception>
/// <seealso cref="Spring.Objects.Factory.Support.IObjectDefinitionRegistry.RegisterObjectDefinition(string, IObjectDefinition)"/>
public abstract void RegisterObjectDefinition(string name, IObjectDefinition objectDefinition);
/// <summary>
/// Return the registered
/// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/> for the
/// given object, allowing access to its property values and constructor
/// argument values.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <returns>
/// The registered
/// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/>.
/// </returns>
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
/// If there is no object with the given name.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// In the case of errors.
/// </exception>
public abstract IObjectDefinition GetObjectDefinition(string name);
/// <summary>
/// Return the registered
/// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/> for the
/// given object, allowing access to its property values and constructor
/// argument values.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <param name="includeAncestors">Whether to search parent object factories.</param>
/// <returns>
/// The registered
/// <see cref="Spring.Objects.Factory.Config.IObjectDefinition"/>.
/// </returns>
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
/// If there is no object with the given name.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// In the case of errors.
/// </exception>
public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors);
/// <summary>
/// Gets the type for the given FactoryObject.
/// </summary>
/// <param name="factoryObject">The factory object instance to check.</param>
/// <returns>the FactoryObject's object type</returns>
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;
}
}
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// The default implementation creates the FactoryObject via <code>GetObject</code>
/// to call its <code>ObjectType</code> property. Subclasses are encouraged to optimize
/// this, typically by just instantiating the FactoryObject but not populating it yet,
/// trying whether its <code>ObjectType</code> property already returns a type.
/// If no type found, a full FactoryObject creation as performed by this implementation
/// should be used as fallback.
/// </remarks>
/// <param name="objectName">Name of the object.</param>
/// <param name="mod">The merged object definition for the object.</param>
/// <returns>The type for the object if determinable, or <code>null</code> otherwise</returns>
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.Warn("Ignoring object creation exception on FactoryObject type check", ex);
return null;
}
}
/// <summary>
/// Predict the eventual object type (of the processed object instance) for the
/// specified object.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="objectName">Name of the object.</param>
/// <param name="mod">The merged object definition to determine the type for. May be <c>null</c></param>
/// <returns>The type of the object, or <code>null</code> if not predictable</returns>
protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod)
{
if (mod == null || StringUtils.HasText(mod.FactoryObjectName))
{
return null;
}
return ResolveObjectType(mod, objectName);
}
/// <summary>
/// Get the object for the given object instance, either the object
/// instance itself or its created object in case of an
/// <see cref="Spring.Objects.Factory.IFactoryObject"/>.
/// </summary>
/// <param name="name">
/// The name that may include the factory dereference prefix.
/// </param>
/// <param name="instance">The object instance.</param>
/// <returns>
/// The singleton instance of the object.
/// </returns>
[Obsolete("")]
protected internal virtual object GetObjectForInstance(string name, object instance)
{
return GetObjectForInstance(instance, name, TransformedObjectName(name), null);
}
/// <summary>
/// Get the object for the given object instance, either the object
/// instance itself or its created object in case of an
/// <see cref="Spring.Objects.Factory.IFactoryObject"/>.
/// </summary>
/// <param name="instance">The object instance.</param>
/// <param name="name">
/// The name that may include the factory dereference prefix (=the requested name).
/// </param>
/// <param name="canonicalName">
/// The canonical object name
/// </param>
/// <param name="rod">the merged object definition</param>
/// <returns>
/// The singleton instance of the object.
/// </returns>
protected internal virtual object GetObjectForInstance(object instance, string name, string canonicalName, RootObjectDefinition rod)
{
// don't let calling code try to dereference the
// object factory if the object isn't a factory
if (IsFactoryDereference(name) && !(ObjectUtils.IsAssignable(typeof(IFactoryObject), instance)))
{
throw new ObjectIsNotAFactoryException(canonicalName, instance);
}
// now we have the object instance, which may be a normal object
// or an IFactoryObject. If it's an IFactoryObject and the caller wants
// a reference to the factory there's nothing more to do
// it's a normal object ?
if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance))
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Calling code asked for normal instance for name '{0}'.", canonicalName));
}
#endregion
return instance;
}
// the user wants the factory itself ?
if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance) || IsFactoryDereference(name))
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(
string.Format("Calling code asked for IFactoryObject instance for name '{0}'.",
TransformedObjectName(name)));
}
#endregion
return instance;
}
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Object with name '{0}' is a factory object.", canonicalName));
}
#endregion
object resultInstance = null;
if (rod == null)
{
resultInstance = factoryObjectProductCache[canonicalName];
}
if (resultInstance == null)
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Dereferencing Object with name '{0}'", canonicalName));
}
#endregion
// return object instance from factory...
IFactoryObject factory = (IFactoryObject)instance;
if (rod == null && ContainsObjectDefinition(canonicalName))
{
rod = GetMergedObjectDefinition(canonicalName, true);
}
if (factory.IsSingleton && ContainsSingleton(canonicalName))
{
lock (factoryObjectProductCache.SyncRoot)
{
resultInstance = factoryObjectProductCache[canonicalName];
if (resultInstance == null)
{
resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod);
if (resultInstance != null)
{
factoryObjectProductCache[canonicalName] = resultInstance;
}
}
}
}
else
{
resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod);
}
if (resultInstance == null)
{
throw new FactoryObjectNotInitializedException(canonicalName,
"Factory object returned null object - "
+ "possible cause: not fully initialized due to "
+ "circular object reference.");
}
}
else
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Returning factory product from cache for Object with name '{0}'", canonicalName));
}
#endregion
}
return resultInstance;
}
/// <summary>
/// Obtain an object to expose from the given IFactoryObject.
/// </summary>
/// <param name="factory">The IFactoryObject instance.</param>
/// <param name="objectName">Name of the object.</param>
/// <param name="rod">The merged object definition.</param>
/// <returns>The object obtained from the IFactoryObject</returns>
/// <exception cref="ObjectCreationException">If IFactoryObject object creation failed.</exception>
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)
{
ApplyObjectPropertyValues(instance, 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;
}
/// <summary>
/// Post-process the given object that has been obtained from the FactoryObject.
/// The resulting object will be exposed for object references.
/// </summary>
/// <remarks>The default implementation simply returns the given object
/// as-is. Subclasses may override this, for example, to apply
/// post-processors.</remarks>
/// <param name="instance">The instance obtained from the IFactoryObject.</param>
/// <param name="objectName">Name of the object.</param>
/// <returns>The object instance to expose</returns>
/// <exception cref="ObjectsException">if any post-processing failed.</exception>
protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName)
{
return instance;
}
/// <summary>
/// Convenience method to pull an <see cref="Spring.Objects.Factory.IFactoryObject"/>
/// from this factory.
/// </summary>
/// <param name="objectName">
/// The name of the factory object to be retrieved. If this name is not a valid
/// <see cref="Spring.Objects.Factory.IFactoryObject"/> name, it will be converted
/// into one.
/// </param>
/// <returns>
/// The <see cref="Spring.Objects.Factory.IFactoryObject"/> associated with the
/// supplied <paramref name="objectName"/>.
/// </returns>
protected IFactoryObject GetFactoryObject(string objectName)
{
if (!ObjectFactoryUtils.IsFactoryDereference(objectName))
{
objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName);
}
return (IFactoryObject)GetObject(objectName);
}
/// <summary>
/// Is the supplied <paramref name="name"/> a factory object dereference?
/// </summary>
protected bool IsFactoryDereference(string name)
{
return ObjectFactoryUtils.IsFactoryDereference(name);
}
/// <summary>
/// Determines whether the type of the given object definition matches the
/// specified target type.
/// </summary>
/// <remarks>Allows for lazy load of the actual object type, provided that the
/// type match can be determined otherwise.
/// <para>The default implementation simply delegates to the standard
/// <code>ResolveObjectType</code> method. Subclasses may override this to use
/// a differnt strategy.</para>
/// </remarks>
/// <param name="objectName">Name of the object (for error handling purposes).</param>
/// <param name="rod">The merged object definition to determine the type for.</param>
/// <param name="targetType">Type to match against (never null).</param>
/// <returns>
/// <c>true</c> if object definition matches tye specified target type; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="CannotLoadObjectTypeException">if we failed to load the type.</exception>"
protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType)
{
Type objectType = ResolveObjectType(rod, objectName);
return (objectType != null && targetType.IsAssignableFrom(objectType));
}
/// <summary>
/// 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.
/// </summary>
/// <param name="rod">The merged object definition to dertermine the type for.</param>
/// <param name="objectName">Name of the object (for error handling purposes).</param>
/// <returns></returns>
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);
}
}
/// <summary>
/// Is the object (definition) with the supplied <paramref name="name"/> an
/// <see cref="Spring.Objects.Factory.IFactoryObject"/>?
/// </summary>
/// <param name="name">The name of the object to be checked.</param>
/// <returns>
/// <see lang="true"/> the object (definition) with the supplied
/// <paramref name="name"/> an <see cref="Spring.Objects.Factory.IFactoryObject"/>?
/// </returns>
protected bool IsFactoryObject(string name)
{
string objectName = TransformedObjectName(name);
object objectInstance = GetSingleton(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
+ "]");
}
}
}
}
/// <summary>
/// Remove the object identified by the supplied <paramref name="name"/>
/// from this factory's singleton cache.
/// </summary>
/// <param name="name">
/// The name of the object that is to be removed from the singleton
/// cache.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the <paramref name="name"/> argument is <see langword="null"/> or
/// consists wholly of whitespace characters.
/// </exception>
protected void RemoveSingleton(string name)
{
AssertUtils.ArgumentHasText(name, "name");
lock (singletonCache)
{
this.singletonCache.Remove(name);
}
}
/// <summary>
/// Return the names of objects in the singleton cache that match the given
/// object type (including subclasses).
/// </summary>
/// <param name="type">
/// The class or interface to match, or <see langword="null"/> for all object names.
/// </param>
/// <remarks>
/// <p>
/// Will <i>not</i> consider <see cref="Spring.Objects.Factory.IFactoryObject"/>s
/// as the type of their created objects is not known before instantiation.
/// </p>
/// <p>
/// Does not consider any hierarchy this factory may participate in.
/// </p>
/// </remarks>
/// <returns>
/// The names of objects in the singleton cache that match the given
/// object type (including subclasses), or an empty array if none.
/// </returns>
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));
}
}
/// <summary>
/// Determines whether the object with the given name matches the specified type.
/// </summary>
/// <remarks>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.
/// </remarks>
/// <param name="name">The name of the object to query.</param>
/// <param name="targetType">Type of the target to match against.</param>
/// <returns>
/// <c>true</c> if the object type matches; otherwise, <c>false</c>
/// if it doesn't match or cannot be determined yet.
/// </returns>
/// <exception cref="NoSuchObjectDefinitionException">Ff there is no object with the given name
/// </exception>
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);
}
}
}
/// <summary>
/// Determines the <see cref="System.Type"/> of the object with the
/// supplied <paramref name="name"/>.
/// </summary>
/// <remarks>
/// <p>
/// More specifically, checks the <see cref="System.Type"/> of object that
/// <see cref="Spring.Objects.Factory.IObjectFactory.GetObject(string)"/> would return.
/// For an <see cref="Spring.Objects.Factory.IFactoryObject"/>, returns the
/// <see cref="System.Type"/> of object that the
/// <see cref="Spring.Objects.Factory.IFactoryObject"/> creates.
/// </p>
/// <p>
/// Please note that (prototype) objects created via a factory method or
/// <see cref="Spring.Objects.Factory.IFactoryObject"/> objects are handled
/// slightly differently, in that we <b>don't</b> want to needlessly create
/// instances of such objects just to determine the <see cref="System.Type"/>
/// of object that they create.
/// </p>
/// </remarks>
/// <param name="name">The name of the object to query.</param>
/// <returns>
/// The <see cref="System.Type"/> of the object or <see langword="null"/>
/// if not determinable.
/// </returns>
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);
}
}
}
/// <summary>
/// Determines the <see cref="System.Type"/> of the object defined
/// by the supplied object <paramref name="definition"/>.
/// </summary>
/// <remarks>
/// <p>
/// This, the default, implementation returns <see lang="null"/>
/// to indicate that the type cannot be determined. Subclasses are
/// encouraged to try to determine the actual return
/// <see cref="System.Type"/> here, matching their strategy of resolving
/// factory methods in the
/// <code>Spring.Objects.Factory.Support.AbstractObjectFactory.CreateObject</code>
/// implementation.
/// </p>
/// </remarks>
/// <param name="objectName">
/// The name associated with the supplied object <paramref name="definition"/>.
/// </param>
/// <param name="definition">
/// The <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/>
/// that the <see cref="System.Type"/> is to be determined for.
/// </param>
/// <returns>
/// The <see cref="System.Type"/> of the object defined by the supplied
/// object <paramref name="definition"/>; or <see lang="null"/> if the
/// <see cref="System.Type"/> cannot be determined.
/// </returns>
protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition)
{
return null;
}
/// <summary>
/// Returns the names of the objects in the singleton cache.
/// </summary>
/// <remarks>
/// <p>
/// Does not consider any hierarchy this factory may participate in.
/// </p>
/// </remarks>
/// <returns>The names of the objects in the singleton cache.</returns>
public virtual string[] GetSingletonNames()
{
lock (singletonCache)
{
ICollection keys = singletonCache.Keys;
return (string[])new ArrayList(keys).ToArray(typeof(string));
}
}
/// <summary>
/// Returns the number of objects in the singleton cache.
/// </summary>
/// <remarks>
/// <p>
/// Does not consider any hierarchy this factory may participate in.
/// </p>
/// </remarks>
/// <returns>The number of objects in the singleton cache.</returns>
public virtual int GetSingletonCount()
{
lock (singletonCache)
{
return singletonCache.Count;
}
}
/// <summary>
/// Destroys the named singleton object.
/// </summary>
/// <remarks>
/// <p>
/// Delegates to
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectFactory.DestroyObject"/>
/// if a corresponding singleton instance is found.
/// </p>
/// </remarks>
/// <param name="name">
/// The name of the singleton object that is to be destroyed.
/// </param>
/// <seealso cref="Spring.Objects.Factory.Support.AbstractObjectFactory.DestroyObject"/>
protected virtual void DestroySingleton(string name)
{
lock (singletonCache)
{
object tempObject = singletonCache[name];
singletonCache.Remove(name);
registeredSingletons.Remove(name);
object singletonInstance = tempObject;
if (singletonInstance != null)
{
DestroyObject(name, singletonInstance);
}
}
}
/// <summary>
/// Check the supplied merged object definition for any possible
/// validation errors.
/// </summary>
/// <param name="mergedObjectDefinition">
/// The object definition to be checked for validation errors.
/// </param>
/// <param name="objectName">
/// The name of the object associated with the supplied object definition.
/// </param>
/// <param name="requiredType">
/// The <see cref="System.Type"/> the object may match. Can be an interface or
/// superclass of the actual class. For example, if the value is the
/// <see cref="System.Object"/> class, this method will succeed whatever the
/// class of the returned instance.
/// </param>
/// <param name="arguments">
/// The arguments to use if creating a prototype using explicit arguments to
/// a <see lang="static"/> factory method. If there is no factory method and the
/// supplied <paramref name="arguments"/> array is not <see lang="null"/>, then
/// match the argument values by type and call the object's constructor.
/// </param>
/// <exception cref="Spring.Objects.ObjectsException">
/// In the case of object validation errors.
/// </exception>
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)
{
if (mergedObjectDefinition.IsSingleton)
{
throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when "
+ "referring to a singleton object definition.");
}
if (mergedObjectDefinition.HasObjectType
&& typeof(IFactoryObject).IsAssignableFrom(mergedObjectDefinition.ObjectType))
{
throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when "
+ "referring to a factory 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.");
}
*/
}
}
/// <summary>
/// Gets the temporary object that is placed
/// into the singleton cache during object resolution.
/// </summary>
protected object TemporarySingletonPlaceHolder
{
get { return CURRENTLY_IN_CREATION; }
}
#endregion
#region Fields
/// <summary>
/// Parent object factory, for object inheritance support
/// </summary>
private IObjectFactory parentObjectFactory;
/// <summary>
/// Dependency types to ignore on dependency check and autowire, as Set of
/// Type objects: for example, string. Default is none.
/// </summary>
private ISet ignoreDependencyTypes = new HybridSet();
/// <summary>
/// ObjectPostProcessors to apply in CreateObject
/// </summary>
private ISet objectPostProcessors = new SortedSet(new ObjectOrderComparator());
/// <summary>
/// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered
/// </summary>
private bool hasInstantiationAwareBeanPostProcessors;
/// <summary>
/// Indicates whether any IDestructionAwareBeanPostProcessors have been registered
/// </summary>
private bool hasDestructionAwareBeanPostProcessors;
private bool caseSensitive;
private IDictionary aliasMap;
private IDictionary singletonCache;
/// <summary>
/// Set of registered singletons, containing the bean names in registration order
/// </summary>
private ISet registeredSingletons = new HashedSet();
private readonly IDictionary singletonsInCreation;
private readonly LogicalThreadContextSetVariable prototypesInCreation;
/// <summary>
/// Set that holds all inner objects created by this factory that implement the IDisposable
/// interface, to be destroyed on call to Dispose.
/// </summary>
private ISet disposableInnerObjects = new SynchronizedSet(new HybridSet());
#endregion
/// <summary>
/// Set that holds all inner objects created by this factory that implement the IDisposable
/// interface, to be destroyed on call to Dispose.
/// </summary>
protected internal ISet DisposableInnerObjects
{
get { return disposableInnerObjects; }
}
#region IHierarchicalObjectFactory Members
/// <summary>
/// The parent object factory, or <see langword="null"/> if there is none.
/// </summary>
/// <value>
/// The parent object factory, or <see langword="null"/> if there is none.
/// </value>
public IObjectFactory ParentObjectFactory
{
get { return parentObjectFactory; }
set { parentObjectFactory = value; }
}
/// <summary>
/// Determines whether the local object factory contains a bean of the given name,
/// ignoring object defined in ancestor contexts.
/// This is an alternative to <code>ContainsObject</code>, ignoring an object
/// of the given name from an ancestor object factory.
/// </summary>
/// <param name="name">The name of the object to query.</param>
/// <returns>
/// <c>true</c> if objects with the specified name is defined in the local factory; otherwise, <c>false</c>.
/// </returns>
public bool ContainsLocalObject(string name)
{
string objectName = TransformedObjectName(name);
return ((ContainsSingleton(objectName) || ContainsObjectDefinition(objectName)) &&
(!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(objectName)));
}
#endregion
#region IObjectFactory Members
#region New region
/// <summary>
/// Is this object a singleton?
/// </summary>
/// <see cref="Spring.Objects.Factory.IObjectFactory.IsSingleton"/>
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);
if (od == null)
{
throw new NoSuchObjectDefinitionException(objectName);
}
// 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;
}
}
}
/// <summary>
/// Determines whether the specified object name is prototype. That is, will GetObject
/// always return independent instances?
/// </summary>
/// <param name="name">The name of the object to query</param>
/// <returns>
/// <c>true</c> if the specified object name will always deliver independent instances; otherwise, <c>false</c>.
/// </returns>
/// <remarks>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.
/// <para>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.
/// </para>
/// </remarks>
/// <exception cref="NoSuchObjectDefinitionException">if there is no object with the given name.</exception>
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;
}
}
}
/// <summary>
/// Does this object factory or one of its parent factories contain an object with the given name?
/// </summary>
/// <remarks>
/// This method scans the object factory hierarchy starting with the current factory instance upwards.
/// Use <see cref="ContainsLocalObject"/> if you want to explicitely check just this object factory instance.
/// </remarks>
/// <see cref="Spring.Objects.Factory.IObjectFactory.ContainsObject"/>.
public bool ContainsObject(string name)
{
string objectName = TransformedObjectName(name);
if (ContainsSingleton(objectName) ||ContainsObjectDefinition(objectName))
{
return (!ObjectFactoryUtils.IsFactoryDereference(name) || IsFactoryObject(name));
}
IObjectFactory parent = this.ParentObjectFactory;
return (parent != null) && parent.ContainsObject(OriginalObjectName(name));
}
/// <summary>
/// Return the aliases for the given object name, if defined.
/// </summary>
/// <see cref="Spring.Objects.Factory.IObjectFactory.GetAliases"/>.
public string[] GetAliases(string name)
{
string objectName = TransformedObjectName(name);
// check if object actually exists in this object factory...
bool isInSingletonCache = ContainsSingleton(objectName);
if (isInSingletonCache || ContainsObjectDefinition(objectName))
{
// if found, gather aliases...
ArrayList matches = new ArrayList();
lock (aliasMap)
{
foreach (DictionaryEntry aliasEntry in aliasMap)
{
if (0 == string.Compare((string)aliasEntry.Value, objectName, !this.IsCaseSensitive))
{
matches.Add(aliasEntry.Key);
}
}
}
return (string[])matches.ToArray(typeof(string));
}
// not found, so check parent...
if (ParentObjectFactory != null)
{
return ParentObjectFactory.GetAliases(objectName);
}
throw new NoSuchObjectDefinitionException(objectName, ToString());
}
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name.
/// </summary>
/// <see cref="Spring.Objects.Factory.IObjectFactory.GetObject(string)"/>.
public object this[string name]
{
get { return GetObject(name); }
}
/// <summary>
/// Return an unconfigured(!) instance (possibly shared or independent) of the given object name.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.CreateObject(string, Type, object[])"/>
/// <remarks>
/// This method will only <b>instantiate</b> the requested object. It does <b>NOT</b> inject any dependencies!
/// </remarks>
public object CreateObject(string name, Type requiredType, object[] arguments)
{
return GetObjectInternal(name, requiredType, arguments, true);
}
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name.
/// </summary>
/// <see cref="Spring.Objects.Factory.IObjectFactory.GetObject(string)"/>.
public object GetObject(string name)
{
return GetObjectInternal(name, null, null, false);
}
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string, Type)"/>
public object GetObject(string name, Type requiredType)
{
return GetObjectInternal(name, requiredType, null, false);
}
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name.
/// </summary>
/// <remarks>
/// <p>
/// This method allows an object factory to be used as a replacement for the
/// Singleton or Prototype design pattern.
/// </p>
/// <p>
/// 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.
/// </p>
/// <p>
/// Will ask the parent factory if the object cannot be found in this factory
/// instance.
/// </p>
/// </remarks>
/// <param name="name">The name of the object to return.</param>
/// <param name="arguments">
/// 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.
/// </param>
/// <returns>The instance of the object.</returns>
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
/// If there's no such object definition.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// If the object could not be created.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="name"/> is <see langword="null"/>.
/// </exception>
public object GetObject(string name, object[] arguments)
{
return GetObjectInternal(name, null, arguments, false);
// string objectName = TransformedObjectName(name);
// object instance = null;
//
// // check if object definition exists
// RootObjectDefinition mergedObjectDefinition = null;
// mergedObjectDefinition = GetMergedObjectDefinition(objectName, false);
// if (mergedObjectDefinition == null)
// {
// if (ParentObjectFactory != null)
// {
// return ParentObjectFactory.GetObject(name, arguments);
// }
// throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]");
// }
//
// // Override constructor values and configure as a prototype
// RootObjectDefinition tmpObjectDefinition = new RootObjectDefinition(mergedObjectDefinition);
// tmpObjectDefinition.ConstructorArgumentValues = null;
// tmpObjectDefinition.IsSingleton = false;
//
// // create a new instance...
// instance = CreateObject(name, tmpObjectDefinition, arguments);
//
// return GetObjectForInstance(name, instance);
}
/// <summary>
/// Return an instance (possibly shared or independent) of the given object name,
/// optionally injecting dependencies.
/// </summary>
/// <param name="name">The name of the object to return.</param>
/// <param name="requiredType">
/// The <see cref="System.Type"/> the object may match. Can be an interface or
/// superclass of the actual class. For example, if the value is the
/// <see cref="System.Object"/> class, this method will succeed whatever the
/// class of the returned instance.
/// </param>
/// <param name="arguments">
/// The arguments to use if creating a prototype using explicit arguments to
/// a <see lang="static"/> factory method. If there is no factory method and the
/// supplied <paramref name="arguments"/> array is not <see lang="null"/>, then
/// match the argument values by type and call the object's constructor.
/// </param>
/// <param name="suppressConfigure">whether to inject dependencies or not.</param>
/// <returns>The instance of the object.</returns>
/// <exception cref="Spring.Objects.Factory.NoSuchObjectDefinitionException">
/// If there's no such object definition.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// If the object could not be created.
/// </exception>
/// <exception cref="Spring.Objects.Factory.ObjectNotOfRequiredTypeException">
/// If the object is not of the required type.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="name"/> is <see langword="null"/>.
/// </exception>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.CreateObject(string, Type, object[])"/>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.GetObject(string, Type, object[])"/>
protected object GetObjectInternal(string name, Type requiredType, object[] arguments, bool suppressConfigure)
{
const int INDENT = 3;
bool hasErrors = false;
try
{
string objectName = TransformedObjectName(name);
nestingCount++;
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("{2}GetObjectInternal: obtaining instance for name {0} => canonical name {1}", name, objectName, new String(' ', nestingCount * INDENT)));
}
#endregion
object instance = null;
// those are cases, where singleton cache can be used
if (arguments == null && !suppressConfigure)
{
// eagerly check singleton cache for manually registered singletons...
object sharedInstance = GetSingleton(objectName);
if (sharedInstance != null)
{
#region Instrumentation
if (log.IsDebugEnabled)
{
if (IsSingletonCurrentlyInCreation(objectName))
{
log.Debug("Returning eagerly cached instance of singleton object '" + objectName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else
{
log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName));
}
}
#endregion
instance = GetObjectForInstance(sharedInstance, name, objectName, null);
return EnsureObjectIsOfRequiredType(name, instance, requiredType);
}
}
if (IsPrototypeCurrentlyInCreation(name))
{
throw new ObjectCurrentlyInCreationException(name);
}
// 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 + "]");
}
if (arguments != null
|| suppressConfigure)
{
// Clone ObjectDefinition
mergedObjectDefinition = CreateRootObjectDefinition(mergedObjectDefinition);
mergedObjectDefinition.IsSingleton = false;
if (arguments != null)
{
// Override constructor values and configure as a prototype if arguments are specified
mergedObjectDefinition.ConstructorArgumentValues = null;
}
}
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...
object sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments);
instance = GetObjectForInstance(sharedInstance, name, objectName, mergedObjectDefinition);
}
else
{
// it's a prototype, so create a new instance...
BeforePrototypeCreation(name);
try
{
instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure);
}
finally
{
AfterPrototypeCreation(name);
}
}
return EnsureObjectIsOfRequiredType(name, instance, requiredType);
}
catch
{
nestingCount--;
hasErrors = true;
#region Instrumentation
if (log.IsErrorEnabled)
{
log.Error(string.Format("{1}GetObjectInternal: error obtaining object {0}", name, new String(' ', nestingCount * INDENT)));
}
#endregion
throw;
}
finally
{
if (!hasErrors)
{
nestingCount--;
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("{1}GetObjectInternal: returning instance for objectname {0}", name, new String(' ', nestingCount * INDENT)));
}
#endregion
}
}
}
[ThreadStatic]
private int nestingCount;
/// <summary>
/// Checks, if the passed instance is of the required type.
/// </summary>
/// <param name="name">the name of the object</param>
/// <param name="instance">the actual instance</param>
/// <param name="requiredType">the type contract the given instance must adhere.</param>
/// <returns>the object instance passed in via <paramref name="instance"/>(for more fluent usage)</returns>
/// <exception cref="ObjectNotOfRequiredTypeException">
/// if <paramref name="instance"/> is null or not assignable to <paramref name="requiredType"/>.
/// </exception>
private object EnsureObjectIsOfRequiredType(string name, object instance, Type requiredType)
{
// check that any required type matches the type of the actual object instance...
if (requiredType != null && instance!= null && !requiredType.IsAssignableFrom(instance.GetType()))
{
throw new ObjectNotOfRequiredTypeException(name, requiredType, instance);
}
return instance;
}
/// <summary>
/// Creates a singleton instance for the specified object name and definition.
/// </summary>
/// <param name="objectName">
/// The object name (will be used as the key in the singleton cache key).
/// </param>
/// <param name="objectDefinition">The object definition.</param>
/// <param name="arguments">
/// 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.
/// </param>
/// <returns>The created object instance.</returns>
protected virtual object CreateAndCacheSingletonInstance(string objectName,
RootObjectDefinition objectDefinition,
object[] arguments)
{
lock (singletonCache)
{
object sharedInstance = singletonCache[objectName];
if (sharedInstance == null)
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Creating shared instance of singleton object '{0}'", objectName));
}
#endregion
BeforeSingletonCreation(objectName);
try
{
sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false);
}
finally
{
AfterSingletonCreation(objectName);
}
AddSingleton(objectName, sharedInstance);
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Cached shared instance of singleton object '{0}'", objectName));
}
#endregion
}
return sharedInstance;
}
}
/// <summary>
/// Injects dependencies into the supplied <paramref name="target"/> instance
/// using the named object definition.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.ConfigureObject(object, string)"/>
public abstract object ConfigureObject(object target, string name);
/// <summary>
/// Injects dependencies into the supplied <paramref name="target"/> instance
/// using the supplied <paramref name="definition"/>.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.IObjectFactory.ConfigureObject(object, string)"/>
public abstract object ConfigureObject(object target, string name, IObjectDefinition definition);
#endregion
#endregion
/// <summary>
/// Destroy all cached singletons in this factory.
/// </summary>
public virtual void Dispose()
{
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Destroying singletons in factory [{0}].", this));
}
#endregion
this.prototypesInCreation.Dispose();
lock (singletonCache)
{
// copy the keys into a new set, 'cos we are going to modifying the
// original collection (_singletonCache) as we destroy each singleton.
ISet keys = new HashedSet(singletonCache.Keys);
foreach (string name in keys)
{
DestroySingleton(name);
}
}
}
/// <summary>
/// Ignore the given dependency type for autowiring
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.IConfigurableObjectFactory.IgnoreDependencyType"/>.
public void IgnoreDependencyType(Type type)
{
IgnoredDependencyTypes.Add(type);
}
/// <summary>
/// Determines whether the specified object name is currently in creation..
/// </summary>
/// <param name="objectName">Name of the object.</param>
/// <returns>
/// <c>true</c> if the specified object name is currently in creation; otherwise, <c>false</c>.
/// </returns>
public bool IsCurrentlyInCreation(string objectName)
{
return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName);
}
private void BeforePrototypeCreation(string name)
{
this.prototypesInCreation.Value.Add(name);
}
private void AfterPrototypeCreation(string name)
{
if (!IsPrototypeCurrentlyInCreation(name))
{
throw new InvalidOperationException("Singleton " + name + " isn't currently in creation.");
}
this.prototypesInCreation.Value.Remove(name);
}
private bool IsPrototypeCurrentlyInCreation(string name)
{
return this.prototypesInCreation.Value.Contains(name);
}
private void AfterSingletonCreation(string name)
{
if (!IsSingletonCurrentlyInCreation(name))
{
throw new InvalidOperationException("Singleton " + name + " isn't currently in creation.");
}
singletonsInCreation.Remove(name);
}
private void BeforeSingletonCreation(string name)
{
if (this.singletonsInCreation.Contains(name))
{
throw new ObjectCurrentlyInCreationException(name);
}
singletonsInCreation.Add(name, EMPTYOBJECT);
}
private bool IsSingletonCurrentlyInCreation(string name)
{
return this.singletonsInCreation.Contains(name);
}
/// <summary>
/// Add a new <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>
/// that will get applied to objects created by this factory.
/// </summary>
/// <param name="objectPostProcessor">
/// The <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>
/// to register.
/// </param>
/// <seealso cref="Spring.Objects.Factory.Config.IConfigurableObjectFactory.AddObjectPostProcessor"/>.
public void AddObjectPostProcessor(IObjectPostProcessor objectPostProcessor)
{
if (objectPostProcessor is IObjectFactoryAware)
{
((IObjectFactoryAware)objectPostProcessor).ObjectFactory = this;
}
// ensure the same instance doesn't get registered twice
if (!ObjectPostProcessors.Contains(objectPostProcessor))
{
ObjectPostProcessors.Add(objectPostProcessor);
}
if (typeof(IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor))
{
hasInstantiationAwareBeanPostProcessors = true;
}
if (typeof(IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor))
{
hasDestructionAwareBeanPostProcessors = true;
}
}
/// <summary>
/// Returns the current number of registered
/// <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>s.
/// </summary>
/// <value>
/// The current number of registered
/// <see cref="Spring.Objects.Factory.Config.IObjectPostProcessor"/>s.
/// </value>
/// <seealso cref="Spring.Objects.Factory.Config.IConfigurableObjectFactory.ObjectPostProcessorCount"/>.
public int ObjectPostProcessorCount
{
get { return ObjectPostProcessors.Count; }
}
/// <summary>
/// Given an object name, create an alias.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.IConfigurableObjectFactory.RegisterAlias"/>.
public void RegisterAlias(string name, string alias)
{
#region Sanity Checks
AssertUtils.ArgumentHasText(name, "The object name must not be empty.");
AssertUtils.ArgumentHasText(alias, "The alias must not be empty.");
#endregion
#region Instrumentation
if (log.IsDebugEnabled)
{
log.Debug(string.Format("Registering alias '{0}' for object with name '{1}'.", alias, name));
}
#endregion
lock (aliasMap)
{
object registeredName = aliasMap[alias];
if (registeredName != null)
{
throw new ObjectDefinitionStoreException(
string.Format(
"Cannot register alias '{0}' for object with name '{1}': it's already registered for object name '{2}'.",
alias, name, registeredName));
}
aliasMap[alias] = name;
}
}
/// <summary>
/// Register the given custom <see cref="System.ComponentModel.TypeConverter"/>
/// for all properties of the given <see cref="System.Type"/>.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.IConfigurableObjectFactory.RegisterCustomConverter"/>.
public void RegisterCustomConverter(Type requiredType, TypeConverter converter)
{
AssertUtils.ArgumentNotNull(requiredType, "requiredType");
TypeConverterRegistry.RegisterConverter(requiredType, converter);
}
#region ISingletonObjectRegistry Members
/// <summary>
/// Register the given existing object as singleton in the object factory,
/// under the given object name.
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.ISingletonObjectRegistry.RegisterSingleton"/>.
public void RegisterSingleton(string name, object singletonObject)
{
AssertUtils.ArgumentHasText(name, "name", "The singleton object cannot be registered under an empty name.");
lock (singletonCache)
{
object oldObject = singletonCache[name];
if (oldObject != null)
{
throw new ObjectDefinitionStoreException(
string.Format(
"Could not register object [{0}] under object name '{1}': there's already object [{2}] bound.",
singletonObject, name, oldObject));
}
AddSingleton(name, singletonObject);
}
}
/// <summary>
/// Does this object factory contains a singleton instance with the
/// supplied <paramref name="name"/>?
/// </summary>
/// <seealso cref="Spring.Objects.Factory.Config.ISingletonObjectRegistry.ContainsSingleton(string)"/>
public bool ContainsSingleton(string name)
{
AssertUtils.ArgumentHasText(name, "name");
lock (singletonCache)
{
return singletonCache.Contains(name);
}
}
/// <summary>
/// Gets the names of singleton objects registered in this registry.
/// </summary>
/// <value>The list of names as String array (never <code>null</code>).</value>
/// <remarks>
/// <para>
/// Only checks already instantiated singletons; does not return names
/// for singleton bean definitions which have not been instantiated yet.
/// </para>
/// <para>
/// The main purpose of this method is to check manually registered singletons
/// <see cref="RegisterSingleton"/>. Can also be used to check which
/// singletons defined by an object definition have already been created.
/// </para>
/// </remarks>
/// <see cref="RegisterSingleton"/>
/// <see cref="Spring.Objects.Factory.Support.IObjectDefinitionRegistry.GetObjectDefinitionNames"/>
/// <see cref="Spring.Objects.Factory.IListableObjectFactory.GetObjectDefinitionNames"/>
public string[] SingletonNames
{
get
{
lock (singletonCache)
{
return
StringUtils.DelimitedListToStringArray(
StringUtils.CollectionToDelimitedString(registeredSingletons, ","), ",");
}
}
}
/// <summary>
/// Gets the number of singleton beans registered in this registry.
/// </summary>
/// <value>The number of singleton objects.</value>
/// <remarks>
/// <para>
/// Only checks already instantiated singletons; does not count
/// singleton object definitions which have not been instantiated yet.
/// </para>
/// <para>
/// The main purpose of this method is to check manually registered singletons
/// <see cref="RegisterSingleton"/>. Can also be used to count the number of
/// singletons defined by an object definition that have already been created.
/// </para>
/// </remarks>
/// <see cref="RegisterSingleton"/>
/// <see cref="Spring.Objects.Factory.Support.IObjectDefinitionRegistry.ObjectDefinitionCount"/>
/// <see cref="Spring.Objects.Factory.IListableObjectFactory.ObjectDefinitionCount"/>
public int SingletonCount
{
get
{
lock (singletonCache)
{
return registeredSingletons.Count;
}
}
}
/// <summary>
/// Tries to find a cached object for the specified name.
/// </summary>
/// <param name="objectName">Teh object name to look for.</param>
/// <returns>The cached object if found, <see langword="null"/> otherwise.</returns>
public virtual object GetSingleton(string objectName)
{
lock (singletonCache)
{
return singletonCache[objectName];
}
}
#endregion
/// <summary>
/// Determines whether the given object name is already in use within this factory,
/// i.e. whether there is a local object or alias registered under this name or
/// an inner object created with this name.
/// </summary>
/// <param name="objectName">Name of the object to check.</param>
/// <returns>
/// <c>true</c> if is object name in use; otherwise, <c>false</c>.
/// </returns>
public bool IsObjectNameInUse(string objectName)
{
return IsAlias(objectName) || ContainsLocalObject(objectName);
}
}
}
|