SPRNET-923, fixed SaoExporter - WebServiceExporter is still TBD
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#region License
|
||||
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright 2002-2004 the original author or authors.
|
||||
* Copyright 2002-2008 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.
|
||||
@@ -14,349 +14,355 @@
|
||||
* 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
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Remoting;
|
||||
|
||||
using Spring.Core;
|
||||
using Spring.Core.TypeResolution;
|
||||
using Spring.Proxy;
|
||||
using Spring.Context;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Objects;
|
||||
using Spring.Objects.Factory;
|
||||
using Spring.Objects.Factory.Support;
|
||||
using Spring.Remoting.Support;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Remoting
|
||||
{
|
||||
/// <summary>
|
||||
/// Publishes an instance of an object under
|
||||
/// a given url as a Server Activated Object (SAO).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Object can be exported either as SingleCall or Singleton.
|
||||
/// </remarks>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
/// <author>Mark Pollack</author>
|
||||
/// <author>Bruno Baia</author>
|
||||
public class SaoExporter : ConfigurableLifetime, IApplicationContextAware, IObjectFactoryAware, IInitializingObject, IDisposable
|
||||
{
|
||||
#region Logging
|
||||
|
||||
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(SaoExporter));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private string targetName;
|
||||
private string applicationName;
|
||||
private string serviceName;
|
||||
private string[] interfaces;
|
||||
|
||||
private IApplicationContext applicationContext;
|
||||
private IObjectFactory objectFactory;
|
||||
|
||||
private MarshalByRefObject remoteObject;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor(s) / Destructor
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="SaoExporter"/> class.
|
||||
/// </summary>
|
||||
public SaoExporter()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the target object definition.
|
||||
/// </summary>
|
||||
public string TargetName
|
||||
{
|
||||
get { return targetName; }
|
||||
set { targetName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the remote application.
|
||||
/// </summary>
|
||||
public string ApplicationName
|
||||
{
|
||||
get { return applicationName; }
|
||||
set { applicationName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the exported remote service.
|
||||
/// <remarks>
|
||||
/// The name that will be used in the URI to refer to this service.
|
||||
/// This will be of the form, tcp://host:port/ServiceName or
|
||||
/// tcp://host:port/ApplicationName/ServiceName
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public string ServiceName
|
||||
{
|
||||
get { return serviceName; }
|
||||
set { serviceName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of interfaces whose methods should be exported.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value of this property is all the interfaces
|
||||
/// implemented or inherited by the target type.
|
||||
/// </remarks>
|
||||
/// <value>The interfaces to export.</value>
|
||||
public string[] Interfaces
|
||||
{
|
||||
get { return interfaces; }
|
||||
set { interfaces = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IApplicationContextAware Members
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Remoting;
|
||||
using Spring.Core.TypeResolution;
|
||||
using Spring.Proxy;
|
||||
using Spring.Objects.Factory;
|
||||
using Spring.Remoting.Support;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Remoting
|
||||
{
|
||||
/// <summary>
|
||||
/// Publishes an instance of an object under
|
||||
/// a given url as a Server Activated Object (SAO).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Remoting servers exported by <see cref="SaoExporter"/> always correspond to <see cref="WellKnownObjectMode.Singleton"/>.
|
||||
/// Objects can be exported either as SingleCall or Singleton by marking the exported object identified by
|
||||
/// <see name="TargetName"/> as either singleton or prototype.
|
||||
/// </remarks>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
/// <author>Mark Pollack</author>
|
||||
/// <author>Bruno Baia</author>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class SaoExporter : ConfigurableLifetime, IObjectFactoryAware, IInitializingObject, IDisposable
|
||||
{
|
||||
#region Logging
|
||||
|
||||
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger( typeof( SaoExporter ) );
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Spring.Context.IApplicationContext"/> that this
|
||||
/// object runs in.
|
||||
/// Holds EXPORTER_ID to SaoExporter instance mappings.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
private static readonly IDictionary s_activeExporters = new Hashtable();
|
||||
|
||||
///<summary>
|
||||
/// Returns the target object instance exported by the SaoExporter identified by <see cref="EXPORTER_ID"/>.
|
||||
///</summary>
|
||||
///<param name="exporterId"></param>
|
||||
///<returns></returns>
|
||||
public static object GetTarget( string exporterId )
|
||||
{
|
||||
SaoExporter exporterInstance;
|
||||
lock (s_activeExporters.SyncRoot)
|
||||
{
|
||||
exporterInstance = (SaoExporter)s_activeExporters[exporterId];
|
||||
}
|
||||
AssertUtils.ArgumentNotNull( exporterInstance, "exporterId", "Remoting Server object is not associated with any active SaoExporter" );
|
||||
object target = exporterInstance.GetTargetInstance();
|
||||
AssertUtils.ArgumentNotNull( target, "exporterId", string.Format( "Failed retrieving target object for SaoExporter ID {0}", exporterId ) );
|
||||
return target;
|
||||
}
|
||||
|
||||
#region Fields
|
||||
|
||||
private readonly string EXPORTER_ID = Guid.NewGuid().ToString();
|
||||
private string targetName;
|
||||
private string applicationName;
|
||||
private string serviceName;
|
||||
private string[] interfaces;
|
||||
|
||||
private IObjectFactory objectFactory;
|
||||
private MarshalByRefObject remoteObject;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor(s) / Destructor
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="SaoExporter"/> class.
|
||||
/// </summary>
|
||||
public SaoExporter()
|
||||
{
|
||||
lock (s_activeExporters.SyncRoot)
|
||||
{
|
||||
s_activeExporters[EXPORTER_ID] = this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup before GC
|
||||
/// </summary>
|
||||
~SaoExporter()
|
||||
{
|
||||
Dispose( false );
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the target object definition.
|
||||
/// </summary>
|
||||
public string TargetName
|
||||
{
|
||||
get { return targetName; }
|
||||
set { targetName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the remote application.
|
||||
/// </summary>
|
||||
public string ApplicationName
|
||||
{
|
||||
get { return applicationName; }
|
||||
set { applicationName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the exported remote service.
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// Normally this call will be used to initialize the object.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// Invoked after population of normal object properties but before an
|
||||
/// init callback such as
|
||||
/// <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
|
||||
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
|
||||
/// or a custom init-method. Invoked after the setting of any
|
||||
/// <see cref="Spring.Context.IResourceLoaderAware"/>'s
|
||||
/// <see cref="Spring.Context.IResourceLoaderAware.ResourceLoader"/>
|
||||
/// property.
|
||||
/// </p>
|
||||
/// The name that will be used in the URI to refer to this service.
|
||||
/// This will be of the form, tcp://host:port/ServiceName or
|
||||
/// tcp://host:port/ApplicationName/ServiceName
|
||||
/// </remarks>
|
||||
/// <exception cref="Spring.Context.ApplicationContextException">
|
||||
/// In the case of application context initialization errors.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.ObjectsException">
|
||||
/// If thrown by any application context methods.
|
||||
/// </exception>
|
||||
/// <exception cref="Spring.Objects.Factory.ObjectInitializationException"/>
|
||||
public IApplicationContext ApplicationContext
|
||||
{
|
||||
set { applicationContext = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IObjectFactoryAware Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets object factory to use.
|
||||
/// </summary>
|
||||
public IObjectFactory ObjectFactory
|
||||
{
|
||||
set { objectFactory = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInitializingObject Members
|
||||
|
||||
/// <summary>
|
||||
/// Publish the object
|
||||
/// </summary>
|
||||
public void AfterPropertiesSet()
|
||||
{
|
||||
ValidateConfiguration();
|
||||
Export();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect the remote object from the registered remoting channels.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
RemotingServices.Disconnect(remoteObject);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (TargetName == null)
|
||||
{
|
||||
throw new ArgumentException("The TargetName property is required.");
|
||||
}
|
||||
|
||||
if (ServiceName == null)
|
||||
{
|
||||
throw new ArgumentException("The ServiceName property is required.");
|
||||
}
|
||||
}
|
||||
|
||||
private void Export()
|
||||
{
|
||||
IProxyTypeBuilder builder = new SaoRemoteObjectProxyTypeBuilder(applicationContext.Name, targetName, this);
|
||||
builder.TargetType = this.objectFactory.GetType(targetName);
|
||||
if (interfaces != null && interfaces.Length > 0)
|
||||
{
|
||||
builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray(interfaces);
|
||||
}
|
||||
|
||||
ConstructorInfo proxyConstructor =
|
||||
builder.BuildProxyType().GetConstructor(Type.EmptyTypes);
|
||||
|
||||
string objectUri = (applicationName != null ? applicationName + "/" + serviceName : serviceName);
|
||||
|
||||
remoteObject = (MarshalByRefObject) proxyConstructor.Invoke(ObjectUtils.EmptyObjects);
|
||||
|
||||
RemotingServices.Marshal(remoteObject, objectUri);
|
||||
|
||||
#region Instrumentation
|
||||
|
||||
if (LOG.IsDebugEnabled)
|
||||
{
|
||||
LOG.Debug(String.Format("Target '{0}' exported as '{1}'.", targetName, objectUri));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SaoRemoteObjectProxyTypeBuilder inner class definition
|
||||
|
||||
/// <summary>
|
||||
/// Builds a proxy type based on <see cref="BaseRemoteObject"/> to wrap a target object
|
||||
/// that is intended to be remotable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The wrapped target object is retrieved by name from the IoC container.
|
||||
/// </remarks>
|
||||
private sealed class SaoRemoteObjectProxyTypeBuilder : RemoteObjectProxyTypeBuilder
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private static readonly MethodInfo TimeSpan_FromTicks =
|
||||
typeof(TimeSpan).GetMethod("FromTicks", BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
private static readonly MethodInfo ContextRegistry_GetContext =
|
||||
typeof(ContextRegistry).GetMethod("GetContext", new Type[1] { typeof(string) });
|
||||
|
||||
private static readonly MethodInfo IObjectFactory_GetObject =
|
||||
typeof(IObjectFactory).GetMethod("GetObject", new Type[1] { typeof(string) });
|
||||
|
||||
private string contextName;
|
||||
private string targetObjectName;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor(s) / Destructor
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the
|
||||
/// <see cref="SaoRemoteObjectProxyTypeBuilder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="contextName">
|
||||
/// The name of the target object definition.
|
||||
/// </param>
|
||||
/// <param name="targetObjectName">
|
||||
/// The name of the application context that this object runs in.
|
||||
/// </param>
|
||||
/// <param name="lifetime">
|
||||
/// The lifetime properties to be applied to the target object.
|
||||
/// </param>
|
||||
public SaoRemoteObjectProxyTypeBuilder(string contextName, string targetObjectName, ILifetime lifetime)
|
||||
: base(lifetime)
|
||||
{
|
||||
this.contextName = contextName;
|
||||
this.targetObjectName = targetObjectName;
|
||||
|
||||
Name = "SaoRemoteObjectProxy";
|
||||
BaseType = typeof(BaseRemoteObject);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IProxyTypeGenerator Members
|
||||
|
||||
/// <summary>
|
||||
/// Generates the IL instructions that pushes
|
||||
/// the target instance on which calls should be delegated to.
|
||||
/// </summary>
|
||||
/// <param name="il">The IL generator to use.</param>
|
||||
public override void PushTarget(ILGenerator il)
|
||||
{
|
||||
il.Emit(OpCodes.Ldstr, this.contextName);
|
||||
il.Emit(OpCodes.Call, ContextRegistry_GetContext);
|
||||
il.Emit(OpCodes.Ldstr, this.targetObjectName);
|
||||
il.Emit(OpCodes.Callvirt, IObjectFactory_GetObject);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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();
|
||||
GenerateRemoteObjectLifetimeInitialization(il);
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deaclares a field that holds the target object instance.
|
||||
/// </summary>
|
||||
/// <param name="builder">
|
||||
/// The <see cref="System.Type"/> builder to use for code generation.
|
||||
/// </param>
|
||||
protected override void DeclareTargetInstanceField(TypeBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// </summary>
|
||||
public string ServiceName
|
||||
{
|
||||
get { return serviceName; }
|
||||
set { serviceName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of interfaces whose methods should be exported.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value of this property is all the interfaces
|
||||
/// implemented or inherited by the target type.
|
||||
/// </remarks>
|
||||
/// <value>The interfaces to export.</value>
|
||||
public string[] Interfaces
|
||||
{
|
||||
get { return interfaces; }
|
||||
set { interfaces = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IObjectFactoryAware Members
|
||||
|
||||
/// <summary>
|
||||
/// Sets object factory to use.
|
||||
/// </summary>
|
||||
public IObjectFactory ObjectFactory
|
||||
{
|
||||
set { objectFactory = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInitializingObject Members
|
||||
|
||||
/// <summary>
|
||||
/// Publish the object
|
||||
/// </summary>
|
||||
public void AfterPropertiesSet()
|
||||
{
|
||||
ValidateConfiguration();
|
||||
Export();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect the remote object from the registered remoting channels.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize( this );
|
||||
Dispose( true );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops exporting the object identified by <see cref="TargetName"/>.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose( bool disposing )
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
RemotingServices.Disconnect( remoteObject );
|
||||
lock (s_activeExporters.SyncRoot)
|
||||
{
|
||||
s_activeExporters.Remove( this.EXPORTER_ID );
|
||||
}
|
||||
remoteObject = null;
|
||||
objectFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private object GetTargetInstance()
|
||||
{
|
||||
return objectFactory.GetObject( targetName );
|
||||
}
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (TargetName == null)
|
||||
{
|
||||
throw new ArgumentException( "The TargetName property is required." );
|
||||
}
|
||||
|
||||
if (ServiceName == null)
|
||||
{
|
||||
throw new ArgumentException( "The ServiceName property is required." );
|
||||
}
|
||||
}
|
||||
|
||||
private void Export()
|
||||
{
|
||||
if (remoteObject != null)
|
||||
{
|
||||
throw new InvalidOperationException("object is already exported");
|
||||
}
|
||||
|
||||
IProxyTypeBuilder builder = new SaoRemoteObjectProxyTypeBuilder( this );
|
||||
builder.TargetType = this.objectFactory.GetType( targetName );
|
||||
if (interfaces != null && interfaces.Length > 0)
|
||||
{
|
||||
builder.Interfaces = TypeResolutionUtils.ResolveInterfaceArray( interfaces );
|
||||
}
|
||||
|
||||
Type proxyType = builder.BuildProxyType();
|
||||
string objectUri = (applicationName != null ? applicationName + "/" + serviceName : serviceName);
|
||||
|
||||
ConstructorInfo proxyConstructor = proxyType.GetConstructor( Type.EmptyTypes );
|
||||
remoteObject = (MarshalByRefObject)proxyConstructor.Invoke( ObjectUtils.EmptyObjects );
|
||||
|
||||
RemotingServices.Marshal( remoteObject, objectUri );
|
||||
|
||||
#region Instrumentation
|
||||
|
||||
if (LOG.IsDebugEnabled)
|
||||
{
|
||||
LOG.Debug( String.Format( "Target '{0}' exported as '{1}'.", targetName, objectUri ) );
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SaoRemoteObjectProxyTypeBuilder inner class definition
|
||||
|
||||
/// <summary>
|
||||
/// Builds a proxy type based on <see cref="BaseRemoteObject"/> to wrap a target object
|
||||
/// that is intended to be remotable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The wrapped target object is retrieved by name from the IoC container.
|
||||
/// </remarks>
|
||||
private sealed class SaoRemoteObjectProxyTypeBuilder : RemoteObjectProxyTypeBuilder
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private static readonly MethodInfo SaoExporter_GetTargetInstance = typeof( SaoExporter ).GetMethod( "GetTarget", new Type[] { typeof( string ) } );
|
||||
|
||||
private SaoExporter _saoExporter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor(s) / Destructor
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the
|
||||
/// <see cref="SaoRemoteObjectProxyTypeBuilder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="saoExporter">
|
||||
/// The exporter to be associated with the proxy.
|
||||
/// </param>
|
||||
public SaoRemoteObjectProxyTypeBuilder( SaoExporter saoExporter )
|
||||
: base( saoExporter )
|
||||
{
|
||||
this._saoExporter = saoExporter;
|
||||
|
||||
Name = "SaoRemoteObjectProxy";
|
||||
BaseType = typeof( BaseRemoteObject );
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IProxyTypeGenerator Members
|
||||
|
||||
/// <summary>
|
||||
/// Generates the IL instructions that pushes
|
||||
/// the target instance on which calls should be delegated to.
|
||||
/// </summary>
|
||||
/// <param name="il">The IL generator to use.</param>
|
||||
public override void PushTarget( ILGenerator il )
|
||||
{
|
||||
il.Emit( OpCodes.Ldstr, this._saoExporter.EXPORTER_ID );
|
||||
il.Emit( OpCodes.Call, SaoExporter_GetTargetInstance );
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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();
|
||||
GenerateRemoteObjectLifetimeInitialization( il );
|
||||
il.Emit( OpCodes.Ret );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deaclares a field that holds the target object instance.
|
||||
/// </summary>
|
||||
/// <param name="builder">
|
||||
/// The <see cref="System.Type"/> builder to use for code generation.
|
||||
/// </param>
|
||||
protected override void DeclareTargetInstanceField( TypeBuilder builder )
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Spring.Objects;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -42,5 +44,46 @@ namespace Spring.Remoting
|
||||
SaoExporter exp = new SaoExporter();
|
||||
exp.AfterPropertiesSet();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExportSingleton()
|
||||
{
|
||||
using(DefaultListableObjectFactory of = new DefaultListableObjectFactory())
|
||||
{
|
||||
of.RegisterSingleton("simpleCounter", new SimpleCounter());
|
||||
SaoExporter saoExporter = new SaoExporter();
|
||||
saoExporter.ObjectFactory = of;
|
||||
saoExporter.TargetName = "simpleCounter";
|
||||
saoExporter.ServiceName = "RemotedSaoSingletonCounter";
|
||||
saoExporter.AfterPropertiesSet();
|
||||
of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()!
|
||||
|
||||
ISimpleCounter client = (ISimpleCounter) Activator.GetObject(typeof(ISimpleCounter), "tcp://localhost:8005/RemotedSaoSingletonCounter" );
|
||||
client.Count();
|
||||
client.Count();
|
||||
|
||||
Assert.AreEqual(2, client.Counter);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExportSingleCall()
|
||||
{
|
||||
using(DefaultListableObjectFactory of = new DefaultListableObjectFactory())
|
||||
{
|
||||
of.RegisterObjectDefinition("simpleCounter", new RootObjectDefinition(typeof(SimpleCounter), false));
|
||||
SaoExporter saoExporter = new SaoExporter();
|
||||
saoExporter.ObjectFactory = of;
|
||||
saoExporter.TargetName = "simpleCounter";
|
||||
saoExporter.ServiceName = "RemotedSaoSingleCallCounter";
|
||||
saoExporter.AfterPropertiesSet();
|
||||
of.RegisterSingleton("simpleCounterExporter", saoExporter); // also tests SaoExporter.Dispose()!
|
||||
|
||||
ISimpleCounter client = (ISimpleCounter) Activator.GetObject(typeof(ISimpleCounter), "tcp://localhost:8005/RemotedSaoSingleCallCounter" );
|
||||
client.Count();
|
||||
client.Count();
|
||||
Assert.AreEqual(0, client.Counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user