fixed SPRNET-1204

This commit is contained in:
eeichinger
2009-05-10 15:44:08 +00:00
parent ca9f8689d3
commit fb0fb91c7d
8 changed files with 385 additions and 92 deletions

View File

@@ -57,6 +57,17 @@ namespace Spring.Context.Support
RegisterSingleton( MessageSourceObjectName, typeof( StaticMessageSource ), null );
}
/// <summary>
/// Creates a new, named instance of the StaticApplicationContext class.
/// </summary>
/// <param name="name">the context name</param>
/// <param name="parentContext">The parent application context.</param>
public StaticApplicationContext( string name, IApplicationContext parentContext )
: base( name, true, parentContext )
{
RegisterSingleton( MessageSourceObjectName, typeof( StaticMessageSource ), null );
}
/// <summary>
/// Do nothing: we rely on callers to update our public methods.
/// </summary>

View File

@@ -296,7 +296,10 @@ namespace Spring.Proxy
il.EmitCall(OpCodes.Callvirt, interfaceMethod, null);
}
private void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName)
/// <summary>
/// Emits code to ensure that target understands the method and throw a sensible exception otherwise.
/// </summary>
protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName)
{
// AssertArgumentType
il.Emit(OpCodes.Ldloc, targetRef);

View File

@@ -30,15 +30,15 @@ using Spring.Util;
namespace Spring.Proxy
{
/// <summary>
/// Builds a proxy type using composition.
/// </summary>
/// <remarks>
/// <note>
/// In order for this builder to work, the target <b>must</b> implement
/// one or more interfaces.
/// </note>
/// </remarks>
/// <summary>
/// Builds a proxy type using composition.
/// </summary>
/// <remarks>
/// <note>
/// In order for this builder to work, the target <b>must</b> implement
/// one or more interfaces.
/// </note>
/// </remarks>
/// <author>Aleksandar Seovic</author>
/// <author>Bruno Baia</author>
public class CompositionProxyTypeBuilder : AbstractProxyTypeBuilder
@@ -56,17 +56,17 @@ namespace Spring.Proxy
#region Properties
/// <summary>
/// <summary>
/// Gets or sets a value indicating whether interfaces should be implemented explicitly.
/// </summary>
/// <value>
/// <see langword="true"/> if they should be; otherwise, <see langword="false"/>.
/// </value>
public bool ExplicitInterfaceImplementation
{
get { return explicitInterfaceImplementation; }
set { explicitInterfaceImplementation = value; }
}
public bool ExplicitInterfaceImplementation
{
get { return explicitInterfaceImplementation; }
set { explicitInterfaceImplementation = value; }
}
#endregion
@@ -84,32 +84,32 @@ namespace Spring.Proxy
#endregion
#region IProxyTypeBuilder Members
/// <summary>
/// Creates a proxy that delegates calls to an instance of the
/// target object.
/// </summary>
/// <remarks>
/// <p>
/// Only interfaces can be proxied using composition, so the target
/// <b>must</b> implement one or more interfaces.
/// </p>
/// </remarks>
/// Creates a proxy that delegates calls to an instance of the
/// target object.
/// </summary>
/// <remarks>
/// <p>
/// Only interfaces can be proxied using composition, so the target
/// <b>must</b> implement one or more interfaces.
/// </p>
/// </remarks>
/// <returns>The generated proxy class.</returns>
/// <exception cref="System.ArgumentException">
/// If the <see cref="IProxyTypeBuilder.TargetType"/>
/// does not implement any interfaces.
/// </exception>
/// <exception cref="System.ArgumentException">
/// If the <see cref="IProxyTypeBuilder.TargetType"/>
/// does not implement any interfaces.
/// </exception>
public override Type BuildProxyType()
{
if (Interfaces == null || Interfaces.Length == 0)
{
throw new ArgumentException(
"Composition proxy target must implement at least one interface.");
"Composition proxy target must implement at least one interface.");
}
TypeBuilder typeBuilder = CreateTypeBuilder(Name, BaseType);
// apply custom attributes to the proxy type.
ApplyTypeAttributes(typeBuilder, TargetType);
@@ -123,15 +123,31 @@ namespace Spring.Proxy
foreach (Type intf in Interfaces)
{
ImplementInterface(typeBuilder,
new TargetProxyMethodBuilder(typeBuilder, this, explicitInterfaceImplementation),
CreateTargetProxyMethodBuilder(typeBuilder),
intf, TargetType);
}
ImplementCustom(typeBuilder);
return typeBuilder.CreateType();
}
/// <summary>
/// Create an <see cref="IProxyMethodBuilder"/> to create interface implementations
/// </summary>
protected virtual IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder)
{
return new TargetProxyMethodBuilder(typeBuilder, this, explicitInterfaceImplementation);
}
#endregion
/// <summary>
/// Allows subclasses to generate additional code
/// </summary>
protected virtual void ImplementCustom(TypeBuilder builder)
{ }
#region IProxyTypeGenerator Members
/// <summary>

View File

@@ -278,36 +278,96 @@ namespace Spring.EnterpriseServices
/// them with COM+ Component Services.
/// </summary>
public virtual void Export()
{
string assemblyFileName = AppDomain.CurrentDomain.DynamicDirectory.Trim('\\', '/') + "\\" + assemblyName + ".dll";
FileInfo assemblyFile = new FileInfo(assemblyFileName);
GenerateComponentAssembly(assemblyFile);
RegisterServicedComponents(assemblyFile);
}
/// <summary>
/// Generates all configured <see cref="Components"/> to the given assembly.
/// </summary>
public Assembly GenerateComponentAssembly(FileInfo assemblyFile)
{
AssemblyName an = new AssemblyName();
an.Name = assemblyName;
an.Version = new Version("1.0.0.0");
an.KeyPair = new StrongNameKeyPair(GetKeyPair());
AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module = proxyAssembly.DefineDynamicModule(assemblyName, assemblyName + ".dll", true);
ApplyAssemblyAttributes(proxyAssembly);
AssemblyBuilder proxyAssembly = DefineProxyAssembly(an, assemblyFile);
GenerateComponentTypes(proxyAssembly, objectFactory, components, UseSpring);
// Assembly.Save() does not allow paths...
string dynamicFileName = assemblyFile.Name;
proxyAssembly.Save(dynamicFileName);
Assembly resultAssembly = System.Reflection.Assembly.LoadFrom(assemblyFile.FullName);
return resultAssembly;
}
/// <summary>
/// Generates service types from the <paramref name="components"/> list of <see cref="ServicedComponentExporter"/> instances
/// into the given assembly.
/// </summary>
/// <param name="proxyAssembly">the assembly to export types to</param>
/// <param name="objectFactory">the object factory to resolve target types</param>
/// <param name="components">the list of <see cref="ServicedComponentExporter"/> instances.</param>
/// <param name="springManaged">whether to generate context lookups, <see cref="ServicedComponentExporter.CreateWrapperType"/></param>
private static AssemblyBuilder GenerateComponentTypes(AssemblyBuilder proxyAssembly, IObjectFactory objectFactory, IList components, bool springManaged)
{
string moduleName = proxyAssembly.GetName().Name;
ModuleBuilder module = proxyAssembly.DefineDynamicModule(moduleName, moduleName + ".dll", true);
Type baseType = typeof(ServicedComponent);
if (UseSpring)
if (springManaged)
{
baseType = CreateSpringServicedComponentType(module);
baseType = CreateSpringServicedComponentType(module, baseType);
}
foreach (ServicedComponentExporter definition in components)
{
definition.CreateWrapperType(module, baseType, objectFactory, UseSpring);
definition.CreateWrapperType(module, baseType, objectFactory.GetType(definition.TargetName), springManaged);
}
return proxyAssembly;
}
proxyAssembly.Save(assemblyName + ".dll");
private AssemblyBuilder DefineProxyAssembly(AssemblyName an, FileInfo assemblyFile)
{
AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyFile.DirectoryName);
ApplyAssemblyAttributes(proxyAssembly);
return proxyAssembly;
}
/// <summary>
///
/// </summary>
/// <param name="assemblyFile"></param>
public void RegisterServicedComponents(FileInfo assemblyFile)
{
RegistrationConfig config = new RegistrationConfig();
config.Application = applicationName;
config.AssemblyFile = AppDomain.CurrentDomain.DynamicDirectory + assemblyName + ".dll";
config.AssemblyFile = assemblyFile.FullName;
config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication;
RegistrationHelper regHelper = new RegistrationHelper();
regHelper.InstallAssemblyFromConfig(ref config);
}
/// <summary>
///
/// </summary>
/// <param name="assemblyFile"></param>
public void UnregisterServicedComponents(FileInfo assemblyFile)
{
RegistrationConfig config = new RegistrationConfig();
config.Application = applicationName;
config.AssemblyFile = assemblyFile.FullName;
config.InstallationFlags = InstallationFlags.ReportWarningsToConsole | InstallationFlags.FindOrCreateTargetApplication | InstallationFlags.ReconfigureExistingApplication;
RegistrationHelper regHelper = new RegistrationHelper();
regHelper.UninstallAssemblyFromConfig(ref config);
}
#endregion
#region Private Methods
@@ -406,7 +466,7 @@ namespace Spring.EnterpriseServices
/// </summary>
/// <example>
/// <code>
/// internal class SpringServicedComponent
/// internal class SpringServicedComponent: BaseType
/// {
/// protected delegate object GetObjectHandler(ServicedComponent servicedComponent, string targetName);
///
@@ -433,11 +493,16 @@ namespace Spring.EnterpriseServices
/// }
/// </code>
/// </example>
private Type CreateSpringServicedComponentType(ModuleBuilder module)
public static Type CreateSpringServicedComponentType(ModuleBuilder module, Type baseType)
{
if (!typeof(ServicedComponent).IsAssignableFrom(baseType))
{
throw new ArgumentException(string.Format("baseType must derive from {0}, was {1}", typeof(ServicedComponent).FullName, baseType), "baseType");
}
Type delegateType = DefineDelegate(module);
TypeBuilder typeBuilder = module.DefineType("SpringServicedComponent", System.Reflection.TypeAttributes.Public, typeof(ServicedComponent));
TypeBuilder typeBuilder = module.DefineType("SpringServicedComponent", System.Reflection.TypeAttributes.Public, baseType);
ILGenerator il = null;
FieldBuilder getObjectRef = typeBuilder.DefineField("getObject", delegateType, FieldAttributes.Family | FieldAttributes.Static);
@@ -448,6 +513,8 @@ namespace Spring.EnterpriseServices
Label tryBegin = il.BeginExceptionBlock();
LocalBuilder fldAssembly = il.DeclareLocal(typeof(Assembly));
LocalBuilder fldType = il.DeclareLocal(typeof(Type));
LocalBuilder fldArgs = il.DeclareLocal(typeof (object[]));
LocalBuilder fldMethod = il.DeclareLocal(typeof (MethodBase));
il.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetExecutingAssembly"));
il.Emit(OpCodes.Callvirt, typeof(Assembly).GetProperty("Location").GetGetMethod());
@@ -484,6 +551,24 @@ namespace Spring.EnterpriseServices
il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("CreateDelegate", new Type[] { typeof(Type), typeof(MethodInfo) }));
il.Emit(OpCodes.Castclass, delegateType);
il.Emit(OpCodes.Stsfld, getObjectRef);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc, fldArgs);
il.Emit(OpCodes.Ldloc, fldArgs);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldtoken, typeBuilder);
il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldloc, fldType);
il.Emit(OpCodes.Ldstr, "EnsureComponentContextRegistryInitialized");
il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) }));
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ldloc, fldArgs);
il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }));
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Leave_S, methodEnd);
il.BeginCatchBlock(typeof(Exception));
@@ -497,8 +582,14 @@ namespace Spring.EnterpriseServices
private static readonly MethodAttributes ConstructorAttributes = MethodAttributes.Public |
MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
private void InvokeBal()
{
Type type = typeof (Assembly);
object[] args = new object[] { typeof(EnterpriseServicesExporter) };
type.GetMethod("MethodName").Invoke(null, args);
}
private Type DefineDelegate(ModuleBuilder module)
private static Type DefineDelegate(ModuleBuilder module)
{
MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;

View File

@@ -164,25 +164,49 @@ namespace Spring.EnterpriseServices
/// </summary>
/// <param name="module">Dynamic module builder to use</param>
/// <param name="baseType"></param>
/// <param name="objectFactory">Object factory to get target from.</param>
/// <param name="useSpring">whether to generated ApplicationContext lookups or use static target instances</param>
public Type CreateWrapperType(ModuleBuilder module, Type baseType, IObjectFactory objectFactory, bool useSpring)
/// <param name="targetType">Type of the exported object.</param>
/// <param name="springManagedLifecycle">whether to generate lookups in ContextRegistry for each service method call or use a 'new'ed target instance</param>
/// <remarks>
/// if <paramref name="springManagedLifecycle"/> is <c>true</c>, each ServicedComponent method call will look similar to
/// <code>
/// class MyServicedComponent {
/// void MethodX() {
/// ContextRegistry.GetContext().GetObject("TargetName").MethodX();
/// }
/// }
/// </code>
/// <br/>
/// if <paramref name="springManagedLifecycle"/> is <c>false</c>, the instance will be simply created at component activation using 'new':
/// <code>
/// class MyServicedComponent {
/// TargetType target = new TargetType();
///
/// void MethodX() {
/// target.MethodX();
/// }
/// }
/// </code>
/// <br/>
/// The differences are of course that in the former case, the target lifecycle is entirely managed by Spring, thus avoiding
/// issues with ServiceComponent activation/deactivation as well as removing the need for default constructors.
/// </remarks>
public Type CreateWrapperType(ModuleBuilder module, Type baseType, Type targetType, bool springManagedLifecycle)
{
ValidateConfiguration();
// create wrapper using appropriate proxy builder
IProxyTypeBuilder proxyBuilder;
if (useSpring)
if (springManagedLifecycle)
{
proxyBuilder = new SpringManagedServicedComponentProxyTypeBuilder(module, baseType, this);
}
else
{
proxyBuilder = new SimpleServicedComponentProxyTypeBuilder(module);
proxyBuilder = new SimpleServicedComponentProxyTypeBuilder(module, baseType);
}
proxyBuilder.Name = _objectName;
proxyBuilder.TargetType = objectFactory.GetType(TargetName);
proxyBuilder.TargetType = targetType;
if (_interfaces != null && _interfaces.Length > 0)
{
proxyBuilder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(_interfaces);
@@ -201,16 +225,70 @@ namespace Spring.EnterpriseServices
#region ServicedComponentProxyTypeBuilder inner class definition
private sealed class SimpleServicedComponentProxyTypeBuilder : CompositionProxyTypeBuilder
private class ServicedComponentTargetProxyMethodBuilder : TargetProxyMethodBuilder
{
public ServicedComponentTargetProxyMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator, bool explicitImplementation) : base(typeBuilder, proxyGenerator, explicitImplementation)
{}
/// <summary>
/// Suppress output to avoid Spring.Core dependency
/// </summary>
protected override void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName)
{
// base.CallAssertUnderstands(il, method, targetRef, targetName);
}
}
private class ServicedComponentProxyTypeBuilder : CompositionProxyTypeBuilder
{
/// <summary>
/// Implements default constructor for the proxy class.
/// </summary>
protected override void ImplementConstructors(TypeBuilder builder)
{
MethodAttributes attributes = MethodAttributes.Public |
MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName;
ConstructorBuilder cb = builder.DefineConstructor(attributes,
CallingConventions.Standard, Type.EmptyTypes);
ILGenerator il = cb.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, builder.BaseType.GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ret);
ImplementFactoryMethod(builder, cb);
}
protected void ImplementFactoryMethod(TypeBuilder builder, ConstructorBuilder cb)
{
base.ImplementCustom(builder);
TypeBuilder factory = builder.DefineNestedType("Factory", System.Reflection.TypeAttributes.NestedPublic);
MethodBuilder newMethod = factory.DefineMethod("New", MethodAttributes.Public | MethodAttributes.Static|MethodAttributes.HideBySig,
CallingConventions.Standard, builder, new Type[0]);
ILGenerator il = newMethod.GetILGenerator();
il.Emit(OpCodes.Newobj, cb);
il.Emit(OpCodes.Ret);
factory.CreateType();
}
protected override IProxyMethodBuilder CreateTargetProxyMethodBuilder(TypeBuilder typeBuilder)
{
return new ServicedComponentTargetProxyMethodBuilder(typeBuilder, this,
this.ExplicitInterfaceImplementation);
}
}
private sealed class SimpleServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder
{
private readonly ModuleBuilder module;
#region Constructor(s) / Destructor
public SimpleServicedComponentProxyTypeBuilder(ModuleBuilder module)
public SimpleServicedComponentProxyTypeBuilder(ModuleBuilder module, Type baseType)
{
this.module = module;
BaseType = typeof(ServicedComponent);
BaseType = baseType;
}
#endregion
@@ -225,7 +303,7 @@ namespace Spring.EnterpriseServices
#endregion
}
private sealed class SpringManagedServicedComponentProxyTypeBuilder : CompositionProxyTypeBuilder
private sealed class SpringManagedServicedComponentProxyTypeBuilder : ServicedComponentProxyTypeBuilder
{
#region Fields
@@ -268,26 +346,6 @@ namespace Spring.EnterpriseServices
#region IProxyTypeGenerator Members
/// <summary>
/// Implements constructors for the proxy class.
/// </summary>
/// <param name="builder">
/// The <see cref="System.Reflection.Emit.TypeBuilder"/> to use.
/// </param>
protected override void ImplementConstructors( TypeBuilder builder )
{
MethodAttributes attributes = MethodAttributes.Public |
MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName;
ConstructorBuilder cb = builder.DefineConstructor( attributes,
CallingConventions.Standard, Type.EmptyTypes );
ILGenerator il = cb.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, builder.BaseType.GetConstructor(Type.EmptyTypes));
il.Emit( OpCodes.Ret );
}
/// <summary>
/// Generates the IL instructions that pushes
/// the target instance on which calls should be delegated to.
@@ -301,7 +359,6 @@ namespace Spring.EnterpriseServices
il.Emit( OpCodes.Ldstr, this.exporter.TargetName );
il.Emit( OpCodes.Callvirt, getObjectRef.FieldType.GetMethod("Invoke"));
}
#endregion
}

View File

@@ -50,10 +50,10 @@ namespace Spring.EnterpriseServices
}
///<summary>
/// Reads in the 'xxx.spring-context.xml' configuration file associated with the specified <paramref name="component"/>.
/// Reads in the 'xxx.spring-context.xml' configuration file associated with the specified <paramref name="componentType"/>.
/// See <see cref="EnterpriseServicesExporter"/> for an in-depth description on how to export and configure COM+ components.
///</summary>
private static void EnsureComponentContextRegistryInitialized(ServicedComponent component)
public static void EnsureComponentContextRegistryInitialized(Type componentType)
{
if (isInitialized) return;
@@ -65,15 +65,15 @@ namespace Spring.EnterpriseServices
// this is to ensure, that assemblies place next to the component assembly can be loaded
// even when they are not strong named.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
FileInfo componentAssemblyFile = new FileInfo(component.GetType().Assembly.Location);
FileInfo componentAssemblyFile = new FileInfo(componentType.Assembly.Location);
componentDirectory = componentAssemblyFile.Directory.FullName;
// switch to component assembly's directory (affects resolving relative paths during context instantiation!)
Environment.CurrentDirectory = componentDirectory;
// read in config file
ConfigXmlDocument configDoc = new ConfigXmlDocument();
// read in config file if any
FileInfo configFile = new FileInfo(componentAssemblyFile.FullName + ".spring-context.xml");
if (configFile.Exists)
{
ConfigXmlDocument configDoc = new ConfigXmlDocument();
configDoc.Load(configFile.FullName);
XmlNode configNode = configDoc.SelectSingleNode("//context");
ServicedComponentContextHandler handler = new ServicedComponentContextHandler();
@@ -103,7 +103,7 @@ namespace Spring.EnterpriseServices
///</summary>
public static object GetObject(ServicedComponent sender, string targetName)
{
EnsureComponentContextRegistryInitialized(sender);
EnsureComponentContextRegistryInitialized(sender.GetType());
return ContextRegistry.GetContext().GetObject(targetName);
}
}

View File

@@ -25,13 +25,19 @@
using System;
using System.Collections;
using System.EnterpriseServices;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting;
using AopAlliance.Intercept;
using NUnit.Framework;
using DotNetMock.Dynamic;
using Rhino.Mocks;
using Spring.Aop.Framework;
using Spring.Context.Support;
using Spring.Objects.Factory;
using Spring.Objects;
using Spring.Objects.Factory.Support;
#endregion
@@ -44,6 +50,12 @@ namespace Spring.EnterpriseServices
[TestFixture]
public class ServicedComponentExporterTests
{
[TearDown]
public void TearDown()
{
ContextRegistry.Clear();
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void BailsWhenNotConfigured ()
@@ -62,28 +74,127 @@ namespace Spring.EnterpriseServices
exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew));
exp.AfterPropertiesSet();
Type type = CreateWrapperType(exp, typeof(TestObject));
Type type = CreateWrapperType(exp, typeof(TestObject), false);
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
Assert.AreEqual(1, attrs.Length);
Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value);
}
#region Private helpers classes
[Test]
public void RegistersManagedObjectWithNonDefaultTransactionOption()
{
ServicedComponentExporter exp = new ServicedComponentExporter();
exp.TargetName = "objectTest";
exp.ObjectName = "objectTestProxy";
exp.TypeAttributes = new ArrayList();
exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew));
exp.AfterPropertiesSet();
// private delegate Type CreateWrapperTypeHandler(ModuleBuilder module, Type baseType, IObjectFactory objectFactory, bool useSpring);
Type type = CreateWrapperType(exp, typeof(TestObject), true);
private Type CreateWrapperType(ServicedComponentExporter exporter, Type type)
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
Assert.AreEqual(1, attrs.Length);
Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value);
}
[Test]
public void CanExportAopProxy()
{
// create an advised proxy and add to objectFactory
// note, that we need to implement a signed interface here
ProxyFactory aopProxyFactory = new ProxyFactory(new Type[] { typeof(IComparable) });
MockMethodInterceptor methodInterceptor = new MockMethodInterceptor();
aopProxyFactory.AddAdvice(methodInterceptor);
IComparable aopProxy = (IComparable) aopProxyFactory.GetProxy();
// ((AssemblyBuilder)aopProxy.GetType().Assembly).Save("Spring.Proxy.dll");
// sanity check
methodInterceptor.NextResult = 2;
Assert.AreEqual(methodInterceptor.NextResult, aopProxy.CompareTo(this));
Assert.AreEqual(1, methodInterceptor.Calls);
StaticApplicationContext appCtx = new StaticApplicationContext(AbstractApplicationContext.DefaultRootContextName, null);
appCtx.ObjectFactory.RegisterSingleton("objectTest", aopProxy);
FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.dll");
EnterpriseServicesExporter exporter = new EnterpriseServicesExporter();
Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest");
try
{
// ServiceComponent will obtain its target from root context
ContextRegistry.RegisterContext(appCtx);
methodInterceptor.Calls = 0;
IComparable testObject;
testObject = (IComparable)Activator.CreateInstance(serviceType);
methodInterceptor.NextResult = 3;
Assert.AreEqual(methodInterceptor.NextResult, testObject.CompareTo(null));
testObject = (IComparable)Activator.CreateInstance(serviceType);
methodInterceptor.NextResult = 4;
Assert.AreEqual(methodInterceptor.NextResult, testObject.CompareTo(null));
Assert.AreEqual(2, methodInterceptor.Calls);
}
finally
{
exporter.UnregisterServicedComponents(assemblyFile);
ContextRegistry.Clear();
}
}
private Type ExportObject(EnterpriseServicesExporter exporter, FileInfo assemblyFile, StaticApplicationContext appCtx, string objectName)
{
exporter.ObjectFactory = appCtx.ObjectFactory;
exporter.Assembly = Path.GetFileNameWithoutExtension(assemblyFile.Name);
exporter.ApplicationName = exporter.Assembly;
exporter.ActivationMode = ActivationOption.Library;
exporter.UseSpring = true;
ServicedComponentExporter exp = new ServicedComponentExporter();
exp.TargetName = objectName;
exp.ObjectName = objectName + "Service";
exp.TypeAttributes = new ArrayList();
exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew));
exp.AfterPropertiesSet();
exporter.Components.Add(exp);
Assembly assembly = exporter.GenerateComponentAssembly(assemblyFile);
exporter.RegisterServicedComponents(assemblyFile);
return assembly.GetType(objectName + "Service");
}
#region Private helpers & classes
private class MockMethodInterceptor : IMethodInterceptor
{
public object NextResult = null;
public int Calls = 0;
public IMethodInvocation LastInvocation;
public object Invoke(IMethodInvocation invocation)
{
Calls++;
LastInvocation = invocation;
return NextResult;
}
}
private Type CreateWrapperType(ServicedComponentExporter exporter, Type targetType, bool useSpring)
{
AssemblyName an = new AssemblyName();
an.Name = "Spring.EnterpriseServices.Tests";
an.Name = "Spring.EnterpriseServices.Tests";
AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, an.Name + ".dll", true);
IDynamicMock mockObjectFactory = new DynamicMock(typeof(IObjectFactory));
mockObjectFactory.ExpectAndReturn("GetType", type, new object[]{ exporter.TargetName });
Type baseType = typeof (ServicedComponent);
if (useSpring)
{
baseType = EnterpriseServicesExporter.CreateSpringServicedComponentType(module, baseType);
}
object result = exporter.CreateWrapperType(module, typeof(ServicedComponent), (IObjectFactory) mockObjectFactory.Object, false); //createWrapperTypeMethodInfo.Invoke(exporter, new object[] { module, mockObjectFactory.Object });
object result = exporter.CreateWrapperType(module, baseType, targetType, useSpring);
Assert.IsNotNull(result);
Assert.IsTrue(result is Type);

View File

@@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>9.0.21022</ProductVersion>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4374F018-9738-46BF-A399-4594CEE75B21}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -80,6 +80,10 @@
<Name>nunit.framework</Name>
<HintPath>..\..\..\lib\Net\2.0\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="Rhino.Mocks, Version=3.4.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Rhino.Mocks.dll</HintPath>
</Reference>
<Reference Include="System">
<Name>System</Name>
</Reference>