[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
| 
Re: [riena-dev] Interface not visible from class loader!
 | 
Hi Olaf and Rieners,
Also, you should see the OSGi manifest entry:
Dynamic-ImportPackage: *
What this does is tell the classloader for the bundle that contains this 
markup (e.g. the Riena Hessian bundle I expect) that it should look for 
a class in every exported package within the current runtime.  As long 
as the proxy interface class is exported, the hessian proxy factory code 
would then find it.  You can scope it by package if you wish.
Scott
Olaf Fricke wrote:
Hi Yau, hi Christian,
 
I found another solution for the classloading issue, the does neither 
need the buddy definition nor the dependency  to 
org.eclipse.riena.communication.core.
 
To find such a solution, I had to dig into the code that throws the 
java.lang.IllegalArgumentException. The reason for that exception is 
that the HessianProxyFactory tries to construct a new 
java.lang.reflect.Proxy instance. Because Hessian does not know 
better, it gives the current context classloader to to javas 
reflection classes. That classloader is the ContextFinder of Equinox. 
When loading classes, the ContextFinder searches for the first class 
of an non-internal bundle on the callstack and delegates the 
classloading to that bundle. This bundle is the com.caucho.hessian 
bundle and that bundle does indeed know nothing about any concrete 
service interfaces.
 
My first try for a solution was to give the classloader of the 
interface class to the rienaHessianProxyFactory (by calling 
endpoint.getServiceInterfaceClass().getClassLoader(). This appoach 
failed too, because Hessian tries to bind the Proxy instance to 
another interface, too (com.caucho.hessian.io.HessianRemoteObject). 
Too make this interface visible to the bundle that contains the 
service interface, you can add a dependency to com.cauche.hessian. I 
tried this and it worked. But that appoach would require that each api 
bundle is dependend of hessian, which is no good idea.
 
Instead, I looked for another solution and detected that the bundle 
that creates the service proxy (for example 
org.eclipse.riena.communication.sample.pingpong.client.config) knows 
both interfaces, because is has indeed dependencies to 
com.cauche.hessian and to the service interface. The remaining task 
was to find a way to give the classloader of that bundle to the 
rienaHessianProxyFactory.
 
Therefore I added the following code to the class 
org.eclipse.riena.internal.communication.factory.hessian.RemoteServiceFactoryHessian, 
to be able to get the current execution stack:
 
    // copied from org.eclipse.osgi.internal.loader.BundleLoader
    static final class ClassContext extends SecurityManager {
        // need to make this method public
        public Class<?>[] getClassContext() {
            return super.getClassContext();
        }
    }
 
    @SuppressWarnings("unchecked")
    public final static ClassContext CLASS_CONTEXT = (ClassContext) 
AccessController.doPrivileged(new PrivilegedAction() {
        public Object run() {
            return new ClassContext();
        }
    });
 
In the method 
RemoteServiceFactoryHessian.createProxy(RemoteServiceDescription 
endpoint) I replaced the line
            Object proxy = 
rienaHessianProxyFactory.create(endpoint.getServiceInterfaceClass(), 
uri, classLoader);
with the following code:
      // determine the classloader for the class that called the factory
      Class<?>[] classContext = CLASS_CONTEXT.getClassContext();
      ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
      for (int i = 1; i < classContext.length; i++) { // starting at 1 
is required due to the inner class
          Class<?> clazz = classContext[i];
          if (clazz != null && clazz != this.getClass() && clazz != 
RemoteServiceFactory.class && clazz != ProxyFactory.class) {
                    classLoader = clazz.getClassLoader();
              break;
          }
      }
 
            Object proxy = 
rienaHessianProxyFactory.create(endpoint.getServiceInterfaceClass(), 
uri, classLoader);
The main idea is to lookup the first class from the callstack that 
does not belong to the proxy creation and give the classlaoder of that 
class to Hessian.
 
I tried my solution on the PingPong sample and it worked without the 
buddy definition and without a dependency from the pingpong.common 
bundle to the org.eclipse.riena.communication.core bundle.
 
Best regards,
Olaf
 
 
------------------------------------------------------------------------
_______________________________________________
riena-dev mailing list
riena-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/riena-dev