Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: Antw: Re: [riena-dev] Interface not visible from class loader!

I have doubts that this will really solve the problem. The Buddy Policy is not only necessary to instantiate the proxy on the client but it is also necessary to instantiate the parameter and return values during the deserialization of the call. There are some shortcuts that Hessian uses sometimes there like taking the class object from the signature of the method for the return values but there are a number of occasion when Hessian can not get to the class object from the method signature:
- for classes deeper in an object net (not appearing in the method signature)
- for passed on classes that are subclasses of the passed parameter or return values

The JavaDeserializer has to rely on the fact that it can see these classes. We either have to change the Hessian packagage (which we havnt done yet, and isnt covered by the current way we bring Hessian into the Eclipse IP process) so that the Java Deserializer takes the classloader from the interface and second guesses from their on the classloader that knows the parameters. That might also be true for other Deserializers in Hessian. Also all parameters and interfaces have to reside in the same bundle (which they probably are most of the time).

So this might lead to remote services that seem to work until more complicated objectnets are transported and then it fails for not so obvious reasons (if we use the proposed solution and dont change the other Deserializers).

We can talk about it next week when I am back, but currently I am a little hesitant about this solution.

christian

Am 01.04.2009 um 00:47 schrieb Stefan Liebig:

Oops, nice typo:

Stefan Liebig wrote:
@Olaf & @Christian & any other interested party
I also do not see any problems concerning multi threading issues. In fact it would not be necessary to declare the CLASSSONTEXT (which really is not the class context - it is more a class context provider - but anyway) static because the RemoteServiceFactoryHessian is only created once. I think it would be also acceptable to create an instance of the ClassContextProvider for each proxy creation, retrieve the class context and use the found class loader.
As an experiment I have implemented a fall back using the ClassContextProvider solution when the ´official´ OSGi/Eclipse mechanism have not been used properly and  that the strange IllegalArgumentException occurs. This will be logged with the hint to use the official mechanisms. The few tests that I did worked all very well.
>From a technical point of few I would say that it is feasible solution and things do not get worse.
>From a technical point of view I would say that it is feasible solution and things do not get worse.

The question is: Do we want that?

Tschüß,
Stefan

Olaf Fricke wrote:
@Christian,
 
I do not see any problems concerning the static property: the static field CLASSCONTEXT will be initialized during the classloading of RemoteServiceFactoryHessian and the only method that is exposed is the native getClassContext method of java.lang.SecurityManager.
 
I am using the call stack, because I don't want to change the api of the factories. The best solution would be, if the to Register.remoteProxy would allow a classloader as parameter. I first wrapped that call in a try-finally-block to change the context classloader temporarly, but I think that could lead to other problems.
 
As a short reminder: initially I stumbled upon the same exception Yau got: "IllegalArgumentException: Interface not visible from class loader". Because that exception did not mention anything about buddy policies, I started debugging and searched for a solution. If the RemoteServiceFactoryHessian would catch this exception and would rethrow another IllegalArgumentException with a better error message, most people would be happy with adding the buddy property.
 
Best regards,
Olaf


>>> Christian Campo <christian.campo@xxxxxxxxxxxx> 31.03.2009 05:50 >>>
Hi Olaf, Scott,

@Olaf,

I think your solution will work, but I am not a big fan of looking at 
the call stack. Also your solution confuses me because some variables 
like CLASSCONTEXT are static. Are you sure that this solution works 
even if multiple threads try to create a proxy at the same time with 
different bundles trying to do that ?

Not sure why that is any better than the buddy policy. Also the buddy 
policy thing not only deals with the interface itself but also with 
all return values or paramters. If they are not in the same package as 
the interface they need to be buddy to. Your solution would not help 
anymore.

@Scott: While that solution should work I guess, I am afraid that it 
makes the system way slower. I have already read somewhere in the 
internet that buddy policies are a timing problem. Because they mean 
that for every class the classloaded search a large list of bundles. 
If it would search all bundles, I believe the result could be even 
worse. Since they are not only consulted for the interfaces but 
possibly also for return values and parameters, I am not sure that way 
is a good idea.

but thanks for the input. I know BuddyPolicies are not ideal but they 
are currently the best way to handle this problem I know.

christian
Am 30.03.2009 um 09:40 schrieb Scott Lewis:

> 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
>>
>
> _______________________________________________
> riena-dev mailing list
> riena-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/riena-dev

_______________________________________________
riena-dev mailing list
riena-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/riena-dev


<ATT00001.c>


Back to the top