Spring Framework
  1. Spring Framework
  2. SPR-982

Spring RMI does not support passing of remote objects as parameters

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.2 RC2
    • Fix Version/s: None
    • Component/s: Remoting
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      In order to pass a remote object as a parameter to a remote method, RmiProxyFactoryBean (or more precisely RemoteAccessor perhaps) needs to be made serializable. The scenerio where a remote object is required to be passed in a parameter to a remote method is discussed in http://forum.springframework.org/viewtopic.php?t=5290

        Activity

        Hide
        Juergen Hoeller added a comment -

        This is simply not supported yet, hence I'll classify this as improvement. I'll schedule this for Spring 1.2.2, although it will probably take till Spring 1.3 if the necessary changes and their potential side effects are non-trivial.

        Juergen

        Show
        Juergen Hoeller added a comment - This is simply not supported yet, hence I'll classify this as improvement. I'll schedule this for Spring 1.2.2, although it will probably take till Spring 1.3 if the necessary changes and their potential side effects are non-trivial. Juergen
        Hide
        Barry Kaplan added a comment -

        Lingo (jms spring remoting) supports this. Maybe something can be leverage from there.

        Show
        Barry Kaplan added a comment - Lingo (jms spring remoting) supports this. Maybe something can be leverage from there.
        Hide
        Sanjiv Jivan added a comment -

        I too need to use remote callbacks and support for this by Spring would be very useful.

        Thanks,
        Sanjiv

        Show
        Sanjiv Jivan added a comment - I too need to use remote callbacks and support for this by Spring would be very useful. Thanks, Sanjiv
        Hide
        Sanjiv Jivan added a comment -

        fyi the link that the reporter mentions is no longer working. Here's the url for this topic in the new forums : http://forum.springframework.org/showthread.php?t=14684

        Show
        Sanjiv Jivan added a comment - fyi the link that the reporter mentions is no longer working. Here's the url for this topic in the new forums : http://forum.springframework.org/showthread.php?t=14684
        Hide
        Mark Vickers added a comment -

        I've actually implemented this for our application.
        Our client code required server callbacks, but we could not bind our client's objects to an RMI registry.

        I created an interface INonBindingRemoter
        with method: public Object remote(Object target, Class targetInterface) throws RemotingException;

        The returned Object is a serializable instance of targetInteface which contains a reference to a Remote object. The Remote object is resident on the client, but is not bound to a RMI Registry. targetInterface invocations are delegated to the Remote object which in turn delegates calls to the target object residing on the client. The returned object is suitable for as a callback argument when passed to a remote method on a remoted server object.

        My implementation of INonBindingRemoter is not particularly clean, but is functional.
        It involved the creation of a NonBindingRMIServiceExporter, a perversion of Spring's RmiServiceExporter.
        NonBindingRMIServiceExporter calls to UnicastRemoteObject.exportObject(...), but does not bind the object to a RMI registry.

        I also had to use a custom class 'LookupFreeRmiProxyFactoryBean' in place of Spring's RmiProxyFactoryBean, to subvert the typical stub lookup process. Some of the messiness in my implementation surrounds that fact that setServiceUrl on LookupFreeRmiProxyFactoryBean must be given a garbage value, because a RMI lookup is not actually performed.

        I don't really plan on supplying code here - though if developers in spring core want to see what i've done to poach any ideas, I can arrange it.

        Typical usage is as follows:

        My POJI: ICallback
        My POJO: Callback implements ICallback

        ICallback c1 = new Callback();
        INonBindingRemoter test = new NonBindingRemoter();
        ICallback proxy = (ICallback)test.remoteProperty(c1, ICallback.class);
        IService1 s1... //get handle to remoted server service
        s1.addCallback(c1);

        Show
        Mark Vickers added a comment - I've actually implemented this for our application. Our client code required server callbacks, but we could not bind our client's objects to an RMI registry. I created an interface INonBindingRemoter with method: public Object remote(Object target, Class targetInterface) throws RemotingException; The returned Object is a serializable instance of targetInteface which contains a reference to a Remote object. The Remote object is resident on the client, but is not bound to a RMI Registry. targetInterface invocations are delegated to the Remote object which in turn delegates calls to the target object residing on the client. The returned object is suitable for as a callback argument when passed to a remote method on a remoted server object. My implementation of INonBindingRemoter is not particularly clean, but is functional. It involved the creation of a NonBindingRMIServiceExporter, a perversion of Spring's RmiServiceExporter. NonBindingRMIServiceExporter calls to UnicastRemoteObject.exportObject(...), but does not bind the object to a RMI registry. I also had to use a custom class 'LookupFreeRmiProxyFactoryBean' in place of Spring's RmiProxyFactoryBean, to subvert the typical stub lookup process. Some of the messiness in my implementation surrounds that fact that setServiceUrl on LookupFreeRmiProxyFactoryBean must be given a garbage value, because a RMI lookup is not actually performed. I don't really plan on supplying code here - though if developers in spring core want to see what i've done to poach any ideas, I can arrange it. Typical usage is as follows: My POJI: ICallback My POJO: Callback implements ICallback ICallback c1 = new Callback(); INonBindingRemoter test = new NonBindingRemoter(); ICallback proxy = (ICallback)test.remoteProperty(c1, ICallback.class); IService1 s1... //get handle to remoted server service s1.addCallback(c1);
        Hide
        Jose Luis Martin added a comment -

        Test passing remote objects as parameters.

        Show
        Jose Luis Martin added a comment - Test passing remote objects as parameters.
        Hide
        Jose Luis Martin added a comment -

        I need it and I try to solve it adding a method to expose the remote object as Service on RmiServiceExporter to pass them as parameter to remote invocations.

        
        	/**
        	 * Get remote object as service for passing it via RMI as argument. 
        	 * @return remote service
        	 */
        	public Remote getRemoteService() {
        		if (getService() instanceof Remote && (
        				getServiceInterface() == null || exportedObject.getClass().isAssignableFrom(getServiceInterface()))) {
        			// conventional RMI service
        			return exportedObject;
        		}
        		// RMI invoker
        		RmiInvocationHandler wrapper = (RmiInvocationHandler) exportedObject;
        		ProxyFactory factory = new ProxyFactory(new Class[] { getServiceInterface(), Remote.class });
        		factory.addAdvice(new RmiExporterServiceInterceptor(wrapper));
        
        		return (Remote) factory.getProxy();
        	}
        
        public class RmiExporterServiceInterceptor extends RemoteInvocationBasedAccessor 
        	implements MethodInterceptor, Serializable  {
        	
        	RmiInvocationHandler invocationHandler; 
        	
        	public RmiExporterServiceInterceptor(RmiInvocationHandler invocationHandler) {
        		this.invocationHandler = invocationHandler;
        	}
        
        	public Object invoke(MethodInvocation invocation) throws Throwable {
        		return invocationHandler.invoke(createRemoteInvocation(invocation));
        	}
        }
        

        Now, we can pass the service to a remote proxy:

        remoteProxy.method(localServiceExporter.getRemoteService());
        

        The getRemoteService() method can be added by extending RmiServiceExporter

        public class ExposeServiceRmiServiceExporter extends RmiServiceExporter {
        
        	private Remote remoteService;
        
        	@Override
        	protected Remote getObjectToExport() {
        		Remote exportedObject = super.getObjectToExport();
        
        		if (getService() instanceof Remote && (
        				getServiceInterface() == null || exportedObject.getClass().isAssignableFrom(getServiceInterface()))) {
        			this.remoteService = exportedObject;
        		}
        		else {
        			// RMI Invokers. 
        			RmiInvocationHandler wrapper = (RmiInvocationHandler) exportedObject;
        			ProxyFactory factory = new ProxyFactory(new Class[] { getServiceInterface(), Remote.class });
        			factory.addAdvice(new RmiExporterServiceInterceptor(wrapper));
        
        			this.remoteService = (Remote) factory.getProxy();
        		}
        
        		return exportedObject;
        
        	}
        
        	public Remote getRemoteService()  {
        		return remoteService;
        	}
        }
        

        I attatched a use case for testing.

        Show
        Jose Luis Martin added a comment - I need it and I try to solve it adding a method to expose the remote object as Service on RmiServiceExporter to pass them as parameter to remote invocations. /** * Get remote object as service for passing it via RMI as argument. * @ return remote service */ public Remote getRemoteService() { if (getService() instanceof Remote && ( getServiceInterface() == null || exportedObject.getClass().isAssignableFrom(getServiceInterface()))) { // conventional RMI service return exportedObject; } // RMI invoker RmiInvocationHandler wrapper = (RmiInvocationHandler) exportedObject; ProxyFactory factory = new ProxyFactory( new Class [] { getServiceInterface(), Remote.class }); factory.addAdvice( new RmiExporterServiceInterceptor(wrapper)); return (Remote) factory.getProxy(); } public class RmiExporterServiceInterceptor extends RemoteInvocationBasedAccessor implements MethodInterceptor, Serializable { RmiInvocationHandler invocationHandler; public RmiExporterServiceInterceptor(RmiInvocationHandler invocationHandler) { this .invocationHandler = invocationHandler; } public Object invoke(MethodInvocation invocation) throws Throwable { return invocationHandler.invoke(createRemoteInvocation(invocation)); } } Now, we can pass the service to a remote proxy: remoteProxy.method(localServiceExporter.getRemoteService()); The getRemoteService() method can be added by extending RmiServiceExporter public class ExposeServiceRmiServiceExporter extends RmiServiceExporter { private Remote remoteService; @Override protected Remote getObjectToExport() { Remote exportedObject = super .getObjectToExport(); if (getService() instanceof Remote && ( getServiceInterface() == null || exportedObject.getClass().isAssignableFrom(getServiceInterface()))) { this .remoteService = exportedObject; } else { // RMI Invokers. RmiInvocationHandler wrapper = (RmiInvocationHandler) exportedObject; ProxyFactory factory = new ProxyFactory( new Class [] { getServiceInterface(), Remote.class }); factory.addAdvice( new RmiExporterServiceInterceptor(wrapper)); this .remoteService = (Remote) factory.getProxy(); } return exportedObject; } public Remote getRemoteService() { return remoteService; } } I attatched a use case for testing.

          People

          • Assignee:
            Juergen Hoeller
            Reporter:
            Jeff Moszuti
            Last updater:
            Jose Luis Martin
          • Votes:
            8 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Days since last comment:
              1 year, 26 weeks, 3 days ago