Merge pull request #26 from thomast74/InitDestroyAttribute
SPRNET-1518 Add InitDestroyPostProcessor to allow init and destroy via attributes
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Common.Logging;
|
||||
using Spring.Objects;
|
||||
using Spring.Objects.Factory;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Core;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="InitDestroyAttributeObjectPostProcessor"/> implementation
|
||||
/// that invokes attributed init and destroy methods. Allows for an attributation
|
||||
/// alternative to Spring's <see cref="IInitializingObject"/> and
|
||||
/// <see cref="IDisposable"/> callback interfaces.
|
||||
///
|
||||
/// Invoke and destroy annotations may be applied to methods of any visibility:
|
||||
/// public, protected, or private. Multiple such methods
|
||||
/// may be annotated, but it is recommended to only annotate one single
|
||||
/// init method and destroy method, respectively.
|
||||
/// </summary>
|
||||
public class InitDestroyAttributeObjectPostProcessor : IDestructionAwareObjectPostProcessor, IObjectFactoryAware, IOrdered
|
||||
{
|
||||
private static readonly ILog Logger = LogManager.GetLogger<InitDestroyAttributeObjectPostProcessor>();
|
||||
|
||||
private IConfigurableListableObjectFactory _objectFactory;
|
||||
private readonly IDictionary<string, LifecycleLifecycleMetadata> _lifecycleMetadataCache;
|
||||
|
||||
private int _order = int.MaxValue;
|
||||
private Type _initAttributeType;
|
||||
private Type _destroyAttributeType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return the order value of this object, where a higher value means greater in
|
||||
/// terms of sorting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>Normally starting with 0 or 1, with <see cref="F:System.Int32.MaxValue"/> indicating
|
||||
/// greatest. Same order values will result in arbitrary positions for the affected
|
||||
/// objects.
|
||||
/// </p><p>Higher value can be interpreted as lower priority, consequently the first object
|
||||
/// has highest priority.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// The order value.
|
||||
/// </returns>
|
||||
public int Order { get { return _order; } private set { _order = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Specify the init attribute to check for, indicating initialization
|
||||
/// methods to call after configuration of an object.
|
||||
/// </summary>
|
||||
public Type InitAttributeType { get { return _initAttributeType; } set { _initAttributeType = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Specify the destroy attribute to check for, indicating disposal
|
||||
/// methods to call before object is destroyed
|
||||
/// </summary>
|
||||
public Type DestroyAttributeType { get { return _destroyAttributeType; } set { _destroyAttributeType = value; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IObjectFactory ObjectFactory
|
||||
{
|
||||
set { _objectFactory = value as IConfigurableListableObjectFactory; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates InitDestroy Post Processor with default attribute types of
|
||||
/// <see cref="PostConstructAttribute"/>
|
||||
/// </summary>
|
||||
public InitDestroyAttributeObjectPostProcessor()
|
||||
{
|
||||
_initAttributeType = typeof (PostConstructAttribute);
|
||||
_destroyAttributeType = typeof (PreDestroyAttribute);
|
||||
|
||||
_lifecycleMetadataCache = new Dictionary<string, LifecycleLifecycleMetadata>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies PostConstruct init method initialisation if instance is attributed
|
||||
/// </summary>
|
||||
/// <param name="instance">The new object instance.
|
||||
/// </param><param name="name">The name of the object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The object instance to use, either the original or a wrapped one.
|
||||
/// </returns>
|
||||
/// <exception cref="T:Spring.Objects.ObjectsException">In case of errors.
|
||||
/// </exception>
|
||||
public object PostProcessBeforeInitialization(object instance, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
var metadata = FindLifecycleMetadata(instance.GetType(), name);
|
||||
metadata.InvokeInitMethods(instance, name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ObjectCreationException(name, "Couldn't invoke init method", e);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No special post processing after initialization
|
||||
/// </summary>
|
||||
public object PostProcessAfterInitialization(object instance, string objectName)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executed PreDestroy methods in given order for provided instance
|
||||
/// </summary>
|
||||
/// <param name="instance">The new object instance.</param><param name="name">The name of the object.</param><exception cref="T:Spring.Objects.ObjectsException">In case of errors.
|
||||
/// </exception>
|
||||
public void PostProcessBeforeDestruction(object instance, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
var metadata = FindLifecycleMetadata(instance.GetType(), name);
|
||||
metadata.InvokeDestroyMethods(instance, name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ObjectsException("Couldn't invoke destroy method", e);
|
||||
}
|
||||
}
|
||||
|
||||
private LifecycleLifecycleMetadata FindLifecycleMetadata(Type instanceType, string name)
|
||||
{
|
||||
if (_lifecycleMetadataCache.ContainsKey(name))
|
||||
return _lifecycleMetadataCache[name];
|
||||
|
||||
lock (_lifecycleMetadataCache)
|
||||
{
|
||||
var metadata = BuildLifecycleMetadata(instanceType, name);
|
||||
_lifecycleMetadataCache.Add(name, metadata);
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
private LifecycleLifecycleMetadata BuildLifecycleMetadata(Type instanceType, string name)
|
||||
{
|
||||
var initMethods = new List<LifecycleElement>();
|
||||
var destroyMethods = new List<LifecycleElement>();
|
||||
|
||||
do
|
||||
{
|
||||
var curInitMethods = new List<LifecycleElement>();
|
||||
var curDestroyMethods = new List<LifecycleElement>();
|
||||
var methods = instanceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (var methodInfo in methods)
|
||||
{
|
||||
var initAttribute =
|
||||
Attribute.GetCustomAttribute(methodInfo, _initAttributeType) as PostConstructAttribute;
|
||||
if (initAttribute != null && methodInfo.DeclaringType == instanceType)
|
||||
{
|
||||
Logger.Debug(m => m("Found init method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
|
||||
curInitMethods.Add(new LifecycleElement(methodInfo, initAttribute.Order));
|
||||
}
|
||||
|
||||
var destroyAttribute =
|
||||
Attribute.GetCustomAttribute(methodInfo, _destroyAttributeType) as PreDestroyAttribute;
|
||||
if (destroyAttribute != null && methodInfo.DeclaringType == instanceType)
|
||||
{
|
||||
Logger.Debug(m => m("Found destroy method on class [{0}]: {1}", instanceType.Name, methodInfo.Name));
|
||||
curDestroyMethods.Add(new LifecycleElement(methodInfo, destroyAttribute.Order));
|
||||
}
|
||||
}
|
||||
|
||||
initMethods.InsertRange(0, curInitMethods.OrderBy(e => e.Order));
|
||||
destroyMethods.InsertRange(0, curDestroyMethods.OrderBy(e => e.Order));
|
||||
instanceType = instanceType.BaseType;
|
||||
}
|
||||
while (instanceType != null && instanceType != typeof(Object));
|
||||
|
||||
var objectDef = _objectFactory.GetObjectDefinition(name);
|
||||
var metadata = new LifecycleLifecycleMetadata(initMethods, destroyMethods);
|
||||
metadata.CheckConfigMembers(objectDef);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
||||
private class LifecycleLifecycleMetadata
|
||||
{
|
||||
private readonly IList<LifecycleElement> _initMethods;
|
||||
private readonly IList<LifecycleElement> _destroyMethods;
|
||||
|
||||
|
||||
public LifecycleLifecycleMetadata(IList<LifecycleElement> initMethods, IList<LifecycleElement> destroyMethods)
|
||||
{
|
||||
_initMethods = initMethods;
|
||||
_destroyMethods = destroyMethods;
|
||||
}
|
||||
|
||||
public void CheckConfigMembers(IObjectDefinition objectDef)
|
||||
{
|
||||
lock (_initMethods)
|
||||
{
|
||||
for (int i = 0; i < _initMethods.Count; i++)
|
||||
{
|
||||
if (!_initMethods[i].CheckConfig(objectDef))
|
||||
_initMethods.Remove(_initMethods[i]);
|
||||
}
|
||||
}
|
||||
lock (_destroyMethods)
|
||||
{
|
||||
for (int i = 0; i < _destroyMethods.Count; i++)
|
||||
{
|
||||
if (!_destroyMethods[i].CheckConfig(objectDef))
|
||||
_destroyMethods.Remove(_destroyMethods[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InvokeInitMethods(object instance, string objectName)
|
||||
{
|
||||
foreach (var lifecycleElement in _initMethods)
|
||||
{
|
||||
lifecycleElement.Invoke(instance, objectName);
|
||||
}
|
||||
}
|
||||
|
||||
public void InvokeDestroyMethods(object instance, string objectName)
|
||||
{
|
||||
foreach (var lifecycleElement in _destroyMethods)
|
||||
{
|
||||
lifecycleElement.Invoke(instance, objectName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class LifecycleElement
|
||||
{
|
||||
private readonly MethodInfo _method;
|
||||
private readonly int _order;
|
||||
|
||||
public int Order { get { return _order; } }
|
||||
|
||||
|
||||
public LifecycleElement(MethodInfo method, int order)
|
||||
{
|
||||
_method = method;
|
||||
_order = order;
|
||||
}
|
||||
|
||||
public bool CheckConfig(IObjectDefinition objectDef)
|
||||
{
|
||||
if (_method.Name == objectDef.InitMethodName || _method.Name == objectDef.DestroyMethodName)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Invoke(object instance, string objectName)
|
||||
{
|
||||
Logger.Debug(m => m("Invoking init method on object '" + objectName + "': " + _method.Name));
|
||||
_method.Invoke(instance, new object[] {});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a method that will be called during the intantiation of an instance
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class PostConstructAttribute : Attribute
|
||||
{
|
||||
private int _order;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PostConstruct class with order = 1
|
||||
/// </summary>
|
||||
public PostConstructAttribute()
|
||||
{
|
||||
_order = int.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PostConstruct class with defined order
|
||||
/// </summary>
|
||||
/// <param name="order">Order in which the PostContruct method is called</param>
|
||||
public PostConstructAttribute(int order)
|
||||
{
|
||||
_order = order;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defined the order in which the PostContruct methods are called
|
||||
/// </summary>
|
||||
public int Order
|
||||
{
|
||||
get { return _order; }
|
||||
set { _order = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 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.Objects.Factory.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a method that will be called prior to the destruction of the object instance
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class PreDestroyAttribute : Attribute
|
||||
{
|
||||
private int _order;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PreDestroy attribute with order = 1
|
||||
/// </summary>
|
||||
public PreDestroyAttribute()
|
||||
{
|
||||
_order = int.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PreDestroy attribute with defined order
|
||||
/// </summary>
|
||||
/// <param name="order">Order in which the PostContruct method is called</param>
|
||||
public PreDestroyAttribute(int order)
|
||||
{
|
||||
_order = order;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defined the order in which the PreDestroy methods are called
|
||||
/// </summary>
|
||||
public int Order
|
||||
{
|
||||
get { return _order; }
|
||||
set { _order = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -673,6 +673,9 @@
|
||||
<Compile Include="Globalization\Resource.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Objects\Factory\Attributes\InitDestroyAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PostConstructAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PreDestroyAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Config\AbstractConfigurer.cs" />
|
||||
|
||||
@@ -675,6 +675,9 @@
|
||||
<Compile Include="Globalization\Resource.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Objects\Factory\Attributes\InitDestroyAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PostConstructAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PreDestroyAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Config\AbstractConfigurer.cs" />
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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 NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class PostConstructAttributeTests
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof (InitDestroyAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject1));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject2));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject3));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject4));
|
||||
objDef.Scope = "prototype";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject5));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject5", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PostContructTestObject1));
|
||||
objDef.InitMethodName = "Init1";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PostContructTestObject6", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void PostContructMethodExecuted()
|
||||
{
|
||||
var testObj = (PostContructTestObject1)_applicationContext.GetObject("PostContructTestObject1");
|
||||
|
||||
Assert.That(testObj.InitCalled, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExecutedInCorrectOrder()
|
||||
{
|
||||
var testObj = (PostContructTestObject2)_applicationContext.GetObject("PostContructTestObject2");
|
||||
|
||||
Assert.That(testObj.InitCalled, Is.EqualTo(2), "Two PostContruct methods defined, need to have two method calls.");
|
||||
Assert.That(testObj.CalledAfter, Is.True, "Order of PostConstruct not followed.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NoExceptionIfMethodHasReturnValue()
|
||||
{
|
||||
var testObj = (PostContructTestObject3)_applicationContext.GetObject("PostContructTestObject3");
|
||||
|
||||
Assert.That(testObj.InitCalled, Is.EqualTo(1), "A PostContruct method with return value should run the init method.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithArgumentMustThrowException()
|
||||
{
|
||||
Assert.That(delegate { _applicationContext.GetObject("PostContructTestObject4"); }, Throws.Exception.TypeOf<ObjectCreationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AttributeOnbaseTypeMethod()
|
||||
{
|
||||
var testObj = (PostContructTestObject5)_applicationContext.GetObject("PostContructTestObject5");
|
||||
|
||||
Assert.That(testObj.InitCalled, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SameMethodDefinedInXml()
|
||||
{
|
||||
var testObj = (PostContructTestObject1)_applicationContext.GetObject("PostContructTestObject6");
|
||||
|
||||
Assert.That(testObj.InitCalled, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class PostContructTestObject1
|
||||
{
|
||||
public int InitCalled { get; set; }
|
||||
|
||||
[PostConstruct]
|
||||
public void Init1()
|
||||
{
|
||||
InitCalled++;
|
||||
}
|
||||
}
|
||||
|
||||
public class PostContructTestObject2
|
||||
{
|
||||
public int InitCalled { get; set; }
|
||||
public bool Init1Called { get; set; }
|
||||
public bool CalledAfter { get; set; }
|
||||
|
||||
[PostConstruct(Order = 1)]
|
||||
public void Init1()
|
||||
{
|
||||
InitCalled++;
|
||||
Init1Called = true;
|
||||
}
|
||||
|
||||
[PostConstruct(Order = 2)]
|
||||
public void Init2()
|
||||
{
|
||||
InitCalled++;
|
||||
if (Init1Called)
|
||||
CalledAfter = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PostContructTestObject3
|
||||
{
|
||||
public int InitCalled { get; set; }
|
||||
|
||||
[PostConstruct]
|
||||
private bool Init1()
|
||||
{
|
||||
InitCalled++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PostContructTestObject4
|
||||
{
|
||||
public int InitCalled { get; set; }
|
||||
|
||||
[PostConstruct]
|
||||
private void Init1(bool enabled)
|
||||
{
|
||||
InitCalled++;
|
||||
}
|
||||
}
|
||||
|
||||
public class PostContructTestObject5 : PostContructTestObject1
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 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 NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects.Factory.Config;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Objects.Factory.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class PreDestroyAttributeTests
|
||||
{
|
||||
private GenericApplicationContext _applicationContext;
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_applicationContext = new GenericApplicationContext();
|
||||
|
||||
var objDef = new RootObjectDefinition(typeof(InitDestroyAttributeObjectPostProcessor));
|
||||
objDef.Role = ObjectRole.ROLE_INFRASTRUCTURE;
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("InitDestroyAttributeObjectPostProcessor", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PreDestroyTestObject1));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject1", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PreDestroyTestObject2));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject2", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PreDestroyTestObject3));
|
||||
objDef.DestroyMethodName = "Destroy";
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject3", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PreDestroyTestObject4));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject4", objDef);
|
||||
|
||||
objDef = new RootObjectDefinition(typeof(PreDestroyTestObject5));
|
||||
_applicationContext.ObjectFactory.RegisterObjectDefinition("PreDestroyTestObject5", objDef);
|
||||
|
||||
_applicationContext.Refresh();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PreDestroyMethodExecution()
|
||||
{
|
||||
DestroyTester.ExecutionCount1 = 0;
|
||||
var testObj = _applicationContext.GetObject("PreDestroyTestObject1");
|
||||
_applicationContext.Dispose();
|
||||
|
||||
Assert.That(DestroyTester.ExecutionCount1, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PreDestroyInBaseType()
|
||||
{
|
||||
DestroyTester.ExecutionCount2 = 0;
|
||||
var testObj = _applicationContext.GetObject("PreDestroyTestObject2");
|
||||
_applicationContext.Dispose();
|
||||
|
||||
Assert.That(DestroyTester.ExecutionCount2, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SameMethodDefinedInXml()
|
||||
{
|
||||
DestroyTester.ExecutionCount3 = 0;
|
||||
var testObj = _applicationContext.GetObject("PreDestroyTestObject3");
|
||||
_applicationContext.Dispose();
|
||||
|
||||
Assert.That(DestroyTester.ExecutionCount3, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InCorrectOrder()
|
||||
{
|
||||
DestroyTester.ExecutionCount4 = 0;
|
||||
var testObj = (PreDestroyTestObject4)_applicationContext.GetObject("PreDestroyTestObject4");
|
||||
_applicationContext.Dispose();
|
||||
|
||||
Assert.That(DestroyTester.ExecutionCount4, Is.EqualTo(2));
|
||||
Assert.That(DestroyTester.CorrectOrder, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithArgumentMustThrowException()
|
||||
{
|
||||
Assert.That(delegate
|
||||
{
|
||||
DestroyTester.ExecutionCount5 = 0;
|
||||
var testObj = (PreDestroyTestObject5)_applicationContext.GetObject("PreDestroyTestObject5");
|
||||
_applicationContext.Dispose();
|
||||
},
|
||||
Throws.Nothing);
|
||||
}
|
||||
}
|
||||
|
||||
public class PreDestroyTestObject1
|
||||
{
|
||||
[PreDestroy]
|
||||
public void Destroy()
|
||||
{
|
||||
DestroyTester.ExecutionCount1++;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreDestroyBase
|
||||
{
|
||||
[PreDestroy]
|
||||
public void Destroy()
|
||||
{
|
||||
DestroyTester.ExecutionCount2++;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreDestroyTestObject2 : PreDestroyBase
|
||||
{
|
||||
}
|
||||
|
||||
public class PreDestroyTestObject3
|
||||
{
|
||||
[PreDestroy]
|
||||
public void Destroy()
|
||||
{
|
||||
DestroyTester.ExecutionCount3++;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreDestroyTestObject4
|
||||
{
|
||||
public PreDestroyTestObject4()
|
||||
{
|
||||
DestroyTester.Destroy1Called = false;
|
||||
DestroyTester.CorrectOrder = false;
|
||||
}
|
||||
|
||||
[PreDestroy(Order = 1)]
|
||||
public void Destroy1()
|
||||
{
|
||||
DestroyTester.ExecutionCount4++;
|
||||
DestroyTester.Destroy1Called = true;
|
||||
}
|
||||
|
||||
[PreDestroy(Order = 2)]
|
||||
public void Destroy2()
|
||||
{
|
||||
DestroyTester.ExecutionCount4++;
|
||||
if (DestroyTester.Destroy1Called)
|
||||
DestroyTester.CorrectOrder = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreDestroyTestObject5
|
||||
{
|
||||
[PreDestroy]
|
||||
public void Destroy(bool arugment)
|
||||
{
|
||||
DestroyTester.ExecutionCount5++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class DestroyTester
|
||||
{
|
||||
public static int ExecutionCount1 { get; set; }
|
||||
public static int ExecutionCount2 { get; set; }
|
||||
public static int ExecutionCount3 { get; set; }
|
||||
public static int ExecutionCount4 { get; set; }
|
||||
public static int ExecutionCount5 { get; set; }
|
||||
public static bool Destroy1Called { get; set; }
|
||||
public static bool CorrectOrder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -316,7 +316,9 @@
|
||||
</Compile>
|
||||
<Compile Include="HookableContextHandler.cs" />
|
||||
<Compile Include="Objects\ExpressionTestObject.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PostConstructAttributeTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\MyRequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PreDestroyAttributeTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessorTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredTestObject.cs" />
|
||||
<Compile Include="Objects\Factory\ConcurrentObjectFactoryTests.cs" />
|
||||
|
||||
@@ -318,7 +318,9 @@
|
||||
</Compile>
|
||||
<Compile Include="HookableContextHandler.cs" />
|
||||
<Compile Include="Objects\ExpressionTestObject.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PostConstructAttributeTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\MyRequiredAttribute.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\PreDestroyAttributeTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredAttributeObjectPostProcessorTests.cs" />
|
||||
<Compile Include="Objects\Factory\Attributes\RequiredTestObject.cs" />
|
||||
<Compile Include="Objects\Factory\ConcurrentObjectFactoryTests.cs" />
|
||||
|
||||
Reference in New Issue
Block a user