You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@tuscany.apache.org by "Millies, Sebastian" <Se...@softwareag.com> on 2012/01/10 18:08:16 UTC

RMIBinding does not work with ContributionClassLoader

Hello there,

it seems that service invocation over an RMI binding in Tuscany 1.6 does not go
with the best practice of loading contributions through a dedicated ClassLoader,
and not putting them on the local application classpath.

This is a severe problem that I am afraid could make the RMI binding almost useless.

Here’s the background. The symptom of the problem is a stack trace like this when
calling a remote service method over an RMI binding:

org.apache.tuscany.sca.host.rmi.RMIHostRuntimeException: error unmarshalling return; nested exception is:
      java.lang.ClassNotFoundException: com.softwareag.ps.platform.dascomponent.api.DASService (no security manager: RMI class loader disabled)
      at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source) ~[na:1.6.0_29]
      at org.apache.tuscany.sca.host.rmi.DefaultRMIHost.findService(DefaultRMIHost.java:113) ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]
      at org.apache.tuscany.sca.host.rmi.ExtensibleRMIHost.findService(ExtensibleRMIHost.java:49) ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]
      at org.apache.tuscany.sca.binding.rmi.provider.RMIReferenceInvoker.invokeTarget(RMIReferenceInvoker.java:80) ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]

The cause of this error is that the stub class must be an instance of a Service interface that is part of a contribution.
However, classes loaded as part of a contribution (loaded by the ContributionClassLoader) are by definition not
not on the local application classpath and therefore not available to the built-in Java implementation of the

RMI sun.rmi.registry.RegistryImpl.

I have tried remedying the situation using the Java remote class loading mechanism, with partial success.
I store the contribution with the service interface (DASService in above example) in a jar file that is accessible
to the client. I have the remote component set the java.rmi.server.codebase property to the URL of that
jar (which couples the launcher code to the binding in the composite, but so be it.) On the client side I load the
contribution from the same jar. In addition, I set an RMISecurityManager and a user policy that grants all permissions.


So far so good – I now have a remote proxy. However, the attempt does not quite work, because methods that have

parameter types which are not on the application classpath cannot be invoked on that proxy:

When Tuscany instantiates the stub from the RMI registry it reloads the method parameter types NOT using the

ContributionClassLoader for the contribution that contains the remote service. So they do not match the parameter types

that are stored in the RMIReferenceInvoker (in the member variable “remoteMethod”).

Thus,  RMIReferenceInvoker# invokeTarget() will throw a NoSuchMethodException!



As discussed in another thread, the aforementioned best practice is necessary to make contribution exports/imports

work. The problem presented in this post may imply that one is severely limited in the method signatures that can be

used over the RMI Binding, to the extent to render the RMI binding almost useless.



I guess a way to make this work correctly would be for Tuscany to use its own RMI registry implementation, instead of

sun.rmi.registry.RegistryImpl. But that seems pretty radical. Another approach might be to change the RMIReferenceInvoker

so that it does not use Class.getMethod() directly but implements a modified sort of reflection where the

parameter types are compared by name and not by identity.



Any comments or ideas?



n  Sebastian

IDS Scheer Consulting GmbH
Geschäftsführer/Managing Directors: Kamyar Niroumand, Ivo Totev
Sitz/Registered office: Altenkesseler Straße 17, 66115 Saarbrücken, Germany - Registergericht/Commercial register: Saarbrücken HRB 19681
http://www.softwareag.com


Re: RMIBinding does not work with ContributionClassLoader

Posted by Simon Nash <na...@apache.org>.
Millies, Sebastian wrote:
> Hello there,
> 
>  
> 
> it seems that service invocation over an RMI binding in Tuscany 1.6 does 
> not go
> 
> with the best practice of loading contributions through a dedicated 
> ClassLoader,
> 
> and not putting them on the local application classpath.
> 
>  
> 
> This is a severe problem that I am afraid could make the RMI binding 
> almost useless.
> 
>  
> 
> Here’s the background. The symptom of the problem is a stack trace like 
> this when
> 
> calling a remote service method over an RMI binding:
> 
>  
> 
> _org.apache.tuscany.sca.host.rmi.RMIHostRuntimeException_: error 
> unmarshalling return; nested exception is:
> 
>       _java.lang.ClassNotFoundException_: 
> com.softwareag.ps.platform.dascomponent.api.DASService (no security 
> manager: RMI class loader disabled)
> 
>       at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source) 
> ~[na:1.6.0_29]
> 
>       at 
> org.apache.tuscany.sca.host.rmi.DefaultRMIHost.findService(_DefaultRMIHost.java:113_) 
> ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]
> 
>       at 
> org.apache.tuscany.sca.host.rmi.ExtensibleRMIHost.findService(_ExtensibleRMIHost.java:49_) 
> ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]
> 
>       at 
> org.apache.tuscany.sca.binding.rmi.provider.RMIReferenceInvoker.invokeTarget(_RMIReferenceInvoker.java:80_) 
> ~[tuscany-sca-all-1.7-SNAPSHOT.jar:1.7-SNAPSHOT]
> 
>  
> 
> The cause of this error is that the stub class must be an instance of a 
> Service interface that is part of a contribution.
> 
> However, classes loaded as part of a contribution (loaded by the 
> ContributionClassLoader) are by definition not
> 
> not on the local application classpath and therefore not available to 
> the built-in Java implementation of the
> 
> RMI sun.rmi.registry.RegistryImpl.
> 
>  
> 
> I have tried remedying the situation using the Java remote class loading 
> mechanism, with partial success.
> 
> I store the contribution with the service interface (DASService in above 
> example) in a jar file that is accessible
> 
> to the client. I have the remote component set the 
> java.rmi.server.codebase property to the URL of that
> 
> jar (which couples the launcher code to the binding in the composite, 
> but so be it.) On the client side I load the
> 
> contribution from the same jar. In addition, I set an RMISecurityManager 
> and a user policy that grants all permissions.
> 
>  
> 
> So far so good – I now have a remote proxy. However, the attempt does not quite work, because methods that have
> 
> parameter types which are not on the application classpath cannot be invoked on that proxy:
> 
> When Tuscany instantiates the stub from the RMI registry it reloads the method parameter types NOT using the 
> 
> ContributionClassLoader for the contribution that contains the remote service. So they do not match the parameter types 
> 
> that are stored in the RMIReferenceInvoker (in the member variable “remoteMethod”). 
> 
> Thus,  RMIReferenceInvoker# invokeTarget() will throw a NoSuchMethodException!
> 
>  
> 
> As discussed in another thread, the aforementioned best practice is necessary to make contribution exports/imports
> 
> work. The problem presented in this post may imply that one is severely limited in the method signatures that can be
> 
> used over the RMI Binding, to the extent to render the RMI binding almost useless.
> 
>  
> 
> I guess a way to make this work correctly would be for Tuscany to use its own RMI registry implementation, instead of
> 
> sun.rmi.registry.RegistryImpl. But that seems pretty radical. Another approach might be to change the RMIReferenceInvoker
> 
> so that it does not use Class.getMethod() directly but implements a modified sort of reflection where the
> 
> parameter types are compared by name and not by identity.
> 
>  
> 
> Any comments or ideas? 
> 
>  
I suspect that RMI is searching the thread context class loader (TCCL)
when looking for the parameter types.  The Java launcher gives TCCL an
initial value of the application classloader.

There's an API in the Thread class to change TCCL, but doing this is
an evil hack and I'd be hesitant to recommend it.

As an experiment, you could try setting TCCL to the contribution
classloader before making the RMI invocation and resetting it to its
previous value when the invocation returns.  It would be interesting
to know whether that resolves the problem.

   Simon
> 
> n  Sebastian
> 
>  
> 
> IDS Scheer Consulting GmbH
> Geschäftsführer/Managing Directors: Kamyar Niroumand, Ivo Totev
> Sitz/Registered office: Altenkesseler Straße 17, 66115 Saarbrücken, 
> Germany - Registergericht/Commercial register: Saarbrücken HRB 19681
> *http://www.softwareag.com*
>