fixed SPRNET-1204
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user