fixed SPRNET-1204: added Server Component support

This commit is contained in:
eeichinger
2009-05-10 22:00:45 +00:00
parent 2228209f2e
commit ab9683d9c9
8 changed files with 117 additions and 93 deletions

View File

@@ -279,7 +279,9 @@ namespace Spring.EnterpriseServices
/// </summary>
public virtual void Export()
{
string assemblyFileName = AppDomain.CurrentDomain.DynamicDirectory.Trim('\\', '/') + "\\" + assemblyName + ".dll";
string ext = (ActivationMode == ActivationOption.Library) ? ".dll" : ".exe";
string moduleName = assemblyName + ext;
string assemblyFileName = AppDomain.CurrentDomain.DynamicDirectory.Trim('\\', '/') + "\\" + moduleName;
FileInfo assemblyFile = new FileInfo(assemblyFileName);
GenerateComponentAssembly(assemblyFile);
@@ -292,12 +294,13 @@ namespace Spring.EnterpriseServices
public Assembly GenerateComponentAssembly(FileInfo assemblyFile)
{
AssemblyName an = new AssemblyName();
an.Name = assemblyName;
an.Name = Path.GetFileNameWithoutExtension(assemblyFile.Name);
an.Version = new Version("1.0.0.0");
an.KeyPair = new StrongNameKeyPair(GetKeyPair());
AssemblyBuilder proxyAssembly = DefineProxyAssembly(an, assemblyFile);
GenerateComponentTypes(proxyAssembly, objectFactory, components, UseSpring);
ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, assemblyFile.Name, true);
GenerateComponentTypes(module, objectFactory, components, UseSpring);
// Assembly.Save() does not allow paths...
string dynamicFileName = assemblyFile.Name;
@@ -310,14 +313,12 @@ namespace Spring.EnterpriseServices
/// 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="module">the module 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)
private static void GenerateComponentTypes(ModuleBuilder module, IObjectFactory objectFactory, IList components, bool springManaged)
{
string moduleName = proxyAssembly.GetName().Name;
ModuleBuilder module = proxyAssembly.DefineDynamicModule(moduleName, moduleName + ".dll", true);
Type baseType = typeof(ServicedComponent);
if (springManaged)
{
@@ -328,7 +329,6 @@ namespace Spring.EnterpriseServices
{
definition.CreateWrapperType(module, baseType, objectFactory.GetType(definition.TargetName), springManaged);
}
return proxyAssembly;
}
private AssemblyBuilder DefineProxyAssembly(AssemblyName an, FileInfo assemblyFile)

View File

@@ -258,19 +258,6 @@ namespace Spring.EnterpriseServices
il.Emit(OpCodes.Ret);
}
// TODO:remove
// 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,

View File

@@ -62,7 +62,7 @@ namespace Spring.EnterpriseServices
if (isInitialized) return;
isInitialized = true;
// this is to ensure, that assemblies place next to the component assembly can be loaded
// this is to ensure, that assemblies placed 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(componentType.Assembly.Location);

View File

@@ -34,6 +34,7 @@ using NUnit.Framework;
using DotNetMock.Dynamic;
using Rhino.Mocks;
using Spring.Aop.Framework;
using Spring.Context;
using Spring.Context.Support;
using Spring.Objects.Factory;
using Spring.Objects;
@@ -43,13 +44,13 @@ using Spring.Objects.Factory.Support;
namespace Spring.EnterpriseServices
{
/// <summary>
/// <summary>
/// Unit tests for the ServicedComponentExporter class.
/// </summary>
/// <author>Bruno Baia</author>
[TestFixture]
/// </summary>
/// <author>Bruno Baia</author>
[TestFixture]
public class ServicedComponentExporterTests
{
{
[TearDown]
public void TearDown()
{
@@ -58,10 +59,10 @@ namespace Spring.EnterpriseServices
[Test]
[ExpectedException(typeof(ArgumentException))]
public void BailsWhenNotConfigured ()
public void BailsWhenNotConfigured()
{
ServicedComponentExporter exp = new ServicedComponentExporter();
exp.AfterPropertiesSet ();
exp.AfterPropertiesSet();
}
[Test]
@@ -76,7 +77,7 @@ namespace Spring.EnterpriseServices
Type type = CreateWrapperType(exp, typeof(TestObject), false);
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
Assert.AreEqual(1, attrs.Length);
Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value);
}
@@ -93,48 +94,30 @@ namespace Spring.EnterpriseServices
Type type = CreateWrapperType(exp, typeof(TestObject), true);
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
TransactionAttribute[] attrs = (TransactionAttribute[])type.GetCustomAttributes(typeof(TransactionAttribute), false);
Assert.AreEqual(1, attrs.Length);
Assert.AreEqual(TransactionOption.RequiresNew, attrs[0].Value);
}
[Test]
public void CanExportAopProxy()
public void CanExportAopProxyToLibrary()
{
// 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);
// NOTE: the method interceptor will return the number of method calls intercepted
FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.dll");
XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml");
EnterpriseServicesExporter exporter = new EnterpriseServicesExporter();
exporter.ActivationMode = ActivationOption.Library;
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));
Assert.AreEqual(1, testObject.CompareTo(null));
testObject = (IComparable)Activator.CreateInstance(serviceType);
methodInterceptor.NextResult = 4;
Assert.AreEqual(methodInterceptor.NextResult, testObject.CompareTo(null));
Assert.AreEqual(2, methodInterceptor.Calls);
Assert.AreEqual(2, testObject.CompareTo(null));
}
finally
{
@@ -143,41 +126,62 @@ namespace Spring.EnterpriseServices
}
}
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;
[Test]
public void CanExportAopProxyToServer()
{
FileInfo assemblyFile = new FileInfo("ServiceComponentExporterTests.TestServicedComponents.exe");
XmlApplicationContext appCtx = new XmlApplicationContext("ServiceComponentExporterTests.TestServicedComponents.Services.xml");
EnterpriseServicesExporter exporter = new EnterpriseServicesExporter();
exporter.ActivationMode = ActivationOption.Server;
Type serviceType = ExportObject(exporter, assemblyFile, appCtx, "objectTest");
try
{
// ServiceComponent will obtain its target from root context
IComparable testObject;
testObject = (IComparable)Activator.CreateInstance(serviceType);
Assert.AreEqual(1, testObject.CompareTo(null));
testObject = (IComparable)Activator.CreateInstance(serviceType);
Assert.AreEqual(2, testObject.CompareTo(null));
}
finally
{
exporter.UnregisterServicedComponents(assemblyFile);
ContextRegistry.Clear();
}
}
ServicedComponentExporter exp = new ServicedComponentExporter();
exp.TargetName = objectName;
exp.ObjectName = objectName + "Service";
exp.TypeAttributes = new ArrayList();
exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew));
exp.AfterPropertiesSet();
private Type ExportObject(EnterpriseServicesExporter exporter, FileInfo assemblyFile, IConfigurableApplicationContext appCtx, string objectName)
{
exporter.ObjectFactory = appCtx.ObjectFactory;
exporter.Assembly = Path.GetFileNameWithoutExtension(assemblyFile.Name);
exporter.ApplicationName = exporter.Assembly;
exporter.AccessControl = new ApplicationAccessControlAttribute(false);
exporter.UseSpring = true;
exporter.Components.Add(exp);
ServicedComponentExporter exp = new ServicedComponentExporter();
exp.TargetName = objectName;
exp.ObjectName = objectName + "Service";
exp.TypeAttributes = new ArrayList();
exp.TypeAttributes.Add(new TransactionAttribute(TransactionOption.RequiresNew));
exp.AfterPropertiesSet();
Assembly assembly = exporter.GenerateComponentAssembly(assemblyFile);
exporter.Components.Add(exp);
Assembly assembly = exporter.GenerateComponentAssembly(assemblyFile);
exporter.RegisterServicedComponents(assemblyFile);
return assembly.GetType(objectName + "Service");
}
}
#region Private helpers & classes
#region Private helpers & classes
private class MockMethodInterceptor : IMethodInterceptor
public class CountingMethodInterceptor : IMethodInterceptor
{
public object NextResult = null;
public int Calls = 0;
public IMethodInvocation LastInvocation;
private int Calls = 0;
public object Invoke(IMethodInvocation invocation)
{
Calls++;
LastInvocation = invocation;
return NextResult;
return Calls;
}
}
@@ -188,7 +192,7 @@ namespace Spring.EnterpriseServices
AssemblyBuilder proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module = proxyAssembly.DefineDynamicModule(an.Name, an.Name + ".dll", true);
Type baseType = typeof (ServicedComponent);
Type baseType = typeof(ServicedComponent);
if (useSpring)
{
baseType = EnterpriseServicesExporter.CreateSpringServicedComponentType(module, baseType);
@@ -202,7 +206,7 @@ namespace Spring.EnterpriseServices
}
#endregion
}
}
}
#endif // (!NET_1_0)

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object id="countingInterceptor" type="Spring.EnterpriseServices.ServicedComponentExporterTests+CountingMethodInterceptor, Spring.Services.Tests" />
<object name="objectTest" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="ProxyInterfaces">
<list>
<value>System.IComparable</value>
</list>
</property>
<property name="InterceptorNames">
<list>
<idref local="countingInterceptor"/>
</list>
</property>
</object>
</objects>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<spring>
<context>
<resource uri="ServiceComponentExporterTests.TestServicedComponents.Services.xml" />
</context>
</spring>

View File

@@ -189,6 +189,14 @@
<ItemGroup>
<EmbeddedResource Include="Data\Spring\Remoting\saoSingleton-autowired.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="ServiceComponentExporterTests.TestServicedComponents.Services.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>

View File

@@ -10,23 +10,23 @@
<if test="${net-3.0.installed and net-3.0}">
<property name="bin.dir.to.use" value="${current.bin.dir}\..\..\2.0\${project.build.config}"/>
<copy todir="${current.bin.dir}">
<fileset basedir="${bin.dir.to.use}">
<include name="*.dll"/>
<include name="*.pdb"/>
<include name="*.xml"/>
<exclude name="Spring.Services.dll"/>
<exclude name="Spring.Services.pdb"/>
<exclude name="Spring.Services.xml"/>
<fileset basedir="${bin.dir.to.use}">
<include name="*.dll"/>
<include name="*.pdb"/>
<include name="*.xml"/>
<exclude name="Spring.Services.dll"/>
<exclude name="Spring.Services.pdb"/>
<exclude name="Spring.Services.xml"/>
</fileset>
</copy>
</if>
<!-- build Spring.Services.Tests -->
<csc target="library" define="${current.build.defines.csc}"
warnaserror="true"
debug="${current.build.debug}"
output="${current.bin.dir}/${project::get-name()}.dll"
doc="${current.bin.dir}/${project::get-name()}.xml">
warnaserror="true"
debug="${current.build.debug}"
output="${current.bin.dir}/${project::get-name()}.dll"
doc="${current.bin.dir}/${project::get-name()}.xml">
<nowarn>
<warning number="${nowarn.numbers.test}" />
</nowarn>
@@ -43,7 +43,7 @@
<include name="*.dll" />
<include if="${net-3.0.installed and net-3.0}" name="${net-3.0.ReferenceInstallPath}\System.ServiceModel.dll" />-->
<exclude name="${project::get-name()}.dll" />
<exclude name="CloverRuntime.dll" />
<exclude name="CloverRuntime.dll" />
</references>
</csc>
<copy todir="${current.bin.dir}">
@@ -56,6 +56,7 @@
<copy todir="${current.bin.dir}">
<fileset basedir="${project::get-base-directory()}">
<include name="**/*.config" />
<include name="**/*.xml" />
</fileset>
</copy>
<copy file="${project::get-base-directory()}/${project::get-name()}.dll.config"
@@ -66,7 +67,7 @@
<nunit2outproc>
<formatter type="Plain" />
<formatter type="Xml" usefile="true" extension=".xml"
outputdir="${current.bin.dir}/results" />
outputdir="${current.bin.dir}/results" />
<test assemblyname="${current.bin.dir}/${project::get-name()}.dll" />
</nunit2outproc>
</target>