From ab9683d9c906b247f6aa09ea09b053d9c322ec48 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Sun, 10 May 2009 22:00:45 +0000 Subject: [PATCH] fixed SPRNET-1204: added Server Component support --- .../EnterpriseServicesExporter.cs | 16 +-- .../ServicedComponentExporter.cs | 13 -- .../ServicedComponentHelper.cs | 2 +- .../ServicedComponentExporterTests.cs | 120 +++++++++--------- ...rTests.TestServicedComponents.Services.xml | 18 +++ ...tServicedComponents.exe.spring-context.xml | 6 + .../Spring.Services.Tests.2008.csproj | 8 ++ .../Spring.Services.Tests.build | 27 ++-- 8 files changed, 117 insertions(+), 93 deletions(-) create mode 100644 test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml create mode 100644 test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml diff --git a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs index d71f0b58..1bd9fa07 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs @@ -279,7 +279,9 @@ namespace Spring.EnterpriseServices /// 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 list of instances /// into the given assembly. /// - /// the assembly to export types to + /// the module to export types to /// the object factory to resolve target types /// the list of instances. /// whether to generate context lookups, - 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) diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs index f76b025c..edc4f7b6 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs @@ -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, diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs index c7d32290..ce85085a 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs @@ -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); diff --git a/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs b/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs index cb438dc9..93d93783 100644 --- a/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs +++ b/test/Spring/Spring.Services.Tests/EnterpriseServices/ServicedComponentExporterTests.cs @@ -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 { - /// + /// /// Unit tests for the ServicedComponentExporter class. - /// - /// Bruno Baia - [TestFixture] + /// + /// Bruno Baia + [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) diff --git a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml new file mode 100644 index 00000000..d0c85ace --- /dev/null +++ b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.Services.xml @@ -0,0 +1,18 @@ + + + + + + + + + System.IComparable + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml new file mode 100644 index 00000000..6262be52 --- /dev/null +++ b/test/Spring/Spring.Services.Tests/ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Services.Tests/Spring.Services.Tests.2008.csproj b/test/Spring/Spring.Services.Tests/Spring.Services.Tests.2008.csproj index 25922fd8..85ccf814 100644 --- a/test/Spring/Spring.Services.Tests/Spring.Services.Tests.2008.csproj +++ b/test/Spring/Spring.Services.Tests/Spring.Services.Tests.2008.csproj @@ -189,6 +189,14 @@ + + + Always + + + Always + + diff --git a/test/Spring/Spring.Services.Tests/Spring.Services.Tests.build b/test/Spring/Spring.Services.Tests/Spring.Services.Tests.build index f1f5d870..ae4afacd 100644 --- a/test/Spring/Spring.Services.Tests/Spring.Services.Tests.build +++ b/test/Spring/Spring.Services.Tests/Spring.Services.Tests.build @@ -10,23 +10,23 @@ - - - - - - - + + + + + + + + warnaserror="true" + debug="${current.build.debug}" + output="${current.bin.dir}/${project::get-name()}.dll" + doc="${current.bin.dir}/${project::get-name()}.xml"> @@ -43,7 +43,7 @@ --> - + @@ -56,6 +56,7 @@ + + outputdir="${current.bin.dir}/results" />