[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [equinox-dev] OSGi & RMI

Hi Patrick,

On 15/05/07, Patrick Bakker <patrick@xxxxxxxxxxxx> wrote:
Stuart,
I followed your suggestions and I got it to work by changing
BeanRegistrar.lookup to the following:

public Object lookupBean(ClassLoader classLoader, String jndiName)
{
  Object obj = null;

  ClassLoader prev = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(classLoader);

  if (jndiNameCache.containsKey(jndiName))
  {
    obj = jndiNameCache.get (jndiName);
  }
  else
  {
    try
    {
      obj = context.lookup(jndiName);
      System.out.println("BeanRegistrar lookup classloader: " +
obj.getClass().getClassLoader());
    }
    catch (NamingException e)
    {
      e.printStackTrace();
    }
  }

  Thread.currentThread().setContextClassLoader(prev);

  return obj;
}

Is this an acceptable way to do things in OSGi? It seems somehow brittle.

Yes - it can look brittle, but sometimes this is the only way to integrate an existing 'framework' library. Things are much better if the library has some sort of API that accepts a classloader argument (cf. cglib).

When no such API is available, and the library uses the TCCL internally,
then this is the simplest approach, as it doesn't require any modification
to the third-party library.

BTW, you can use a try...finally block to make things a little more robust:

 Thread currentThread = Thread.currentThread();
 ClassLoader currentLoader = currentThread.getContextClassLoader();

 try
 {
     currentThread.setContextClassLoader(clientLoader);
     obj = context.lookup(jndiName);
 }
 finally
 {
     currentThread.setContextClassLoader(currentLoader);
 }

and as Alex suggested, you should use a per-classloader cache.

You might also want to consider clearing entries from the cache(s)
over time, as holding onto class references can stop bundles from
being fully GC'd.


Patrick

On 5/14/07, Stuart McCulloch <stuart.mcculloch@xxxxxxxxxx> wrote:
>
> Hi Patrick,
>
> Looks like BeanRegistrar.lookup constructs a proxy that implements
> IExampleRemote, but probably uses a different classloader during its
> construction - this would explain why it can't be cast to the local type.
>
> If you have access to the lookup code, try to see what classloader it
> uses - ie. getClassLoader() on an existing type (from either the client
> or the provider bundle) or the thread context classloader (TCCL).
>
> If the proxy only needs access to the client types then you just need
> to use the client classloader - either by getting the lookup method to
> use getClassLoader on one the parameters passed in from the client,
> or by setting the TCCL to the right classloader before the lookup call
> (and resetting it afterwards).
>
> If the proxy needs access to both client and provider types then one
> solution is to use a custom classloader to 'bridge' the two hierarchies.
> Basically this bridge classloader would know about client and provider
> classloaders and delegates to the right one according to the package
> name (or delegate one way then delegates the other way on failure).
>
> Alternatively you could try Dynamic-ImportPackage: * in the provider
> bundle, which would allow it to find the right client type instance, but
> this forces you to expose implementation types in your client, and
> makes it harder to replace and re-wire packages.
>
> Another option is using Eclipse-BuddyPolicy to bridge across bundles
> but this is specific to Equinox and isn't supported on other frameworks.
>
> For some extra info on this see:
>
>   http://www.eclipsezone.com/articles/eclipse-vms
>
  http://www2.osgi.org/pipermail/jsr-291-eg/2006-August/000169.html
>   https://bugs.eclipse.org/bugs/show_bug.cgi?id=87775
>
> hope this helps :)
>
> ( if not, a zipfile of the code would be useful, as Edward suggested )
>
> On 12/05/07, Patrick Bakker <patrick@xxxxxxxxxxxx> wrote:
> > Hi,
> > I'm experimenting with the best way to modularize an application using
Swing
> > to communicate to stateless session beans. I'm using Java SE 5 + JBoss
> > 4.2.0.CR2 + Eclipse 3.2.2.
> > I know its some kind of classloader/isolation issue with OSGi/RMI
because I
> > can construct a simple Java application that works fine.
> >
> > Suppose I have 5 bundles (I'm using Eclipse bundles rather than OSGi but
I'm
> > using Swing not SWT) & their important classes:
> > example.app
> > example.registrar.bean
> >   BeanRegistrar (singleton)
> >   jndi.properties
> > example.client
> > example.clientserver
> >   IExample
> >   IExampleRemote
> > example.server
> >   ExampleBean
> >
> > For JBoss I use an ant script to create jar from the packages in
> > example.clientserver and example.server to create example.server.jar
which I
> > drop in the deploy directory:
> >
> > @Stateless
> > @RemoteBinding(IExampleRemote.DEFAULT_JNDI_NAME)
> > public class ExampleBean implements IExample, IExampleRemote
> > {
> >    public void doSomething()
> >   {
> >     System.out.println("hello");
> >   }
> > }
> >
> > public interface IExample
> > {
> >   public void doSomething();
> > }
> >
> > @Remote
> > public interface IExampleRemote extends IExample
> > {}
> >
> > For the client I have everything packaged as individual bundles. When
> > example.client needs a bean it starts another thread which calls
> > BeanRegistrar.lookup(String jndiName) to get a reference to a remote
bean.
> >
> > public class Task extends Thread
> > {
> >   boolean inSwing;
> >   TaskCallback callback;
> >
> >   public void Task(TaskCallback callback)
> >   {
> >     this.callback = callback;
> >     inSwing = false;
> >   }
> >
> >    public void run()
> >   {
> >     if (inSwing)
> >     {
> >       callback.taskComplete();
> >     }
> >     else
> >     {
> >       IExampleRemote example = (IExampleRemote)
> > BeanRegistrar.lookup(IExampleRemote.DEFAULT_JNDI_NAME
);
> >       example.doSomething();
> >
> >       inSwing = true;
> >       SwingUtilities.invokeLater(this);
> >     }
> >   }
> > }
> >
> > If I collapse this entire example down to a simple Java application
instead
> > of bundles it works fine.
> > If I run it as an Eclispe RCP, I get:
> >
> > java.lang.ClassCastException: $Proxy0 cannot be cast to
> > example.clientserver.IExampleRemote
> >     at example.client.Task.run(Task.java:xx) <-- stops at the line with
> > BeanRegistrar.lookup
> >
> > I've googled around extensively and OSGi/RMI issues come up in several
> > places but the closest anybody gets to answering anything is to hint
that
> > this may be problematic and the conversation ends just before anybody
says
> > anything useful. A few other documents mention the Eclipse Buddy policy
> > extension. I've experimented with it but have not had any success yet.
Also,
> > I'm not sure exactly what I'm trying to do so I'm basically just
guessing at
> > possible combinations.
> >
> > I am running the program under the default Java security manager with
the
> > following permissive policy:
> > grant
> > {
> >     permission java.security.AllPermission ;
> > };
> >
> > I do that by supplying VM arguments to the run program option in
Eclipse:
> > -Djava.security.manager
> > -Djava.security.policy="/Configuration/security.conf"
> > -Djava.security.auth.login.config=
"/Configuration/jaas.conf"
> >
> > Can anybody help me get to the bottom of this?
> >
> >
> > _______________________________________________
> > equinox-dev mailing list
> > equinox-dev@xxxxxxxxxxx
> > https://dev.eclipse.org/mailman/listinfo/equinox-dev
> >
> >
>
>
> --
> Cheers, Stuart
> _______________________________________________
> equinox-dev mailing list
> equinox-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/equinox-dev
>


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




--
Cheers, Stuart