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