13 Replies Latest reply: Jul 18, 2012 3:43 AM by Thomas Diesler RSS

TCCL used by EJBNamingContext is wrong when callstack passes through multiple OSGi modules

Steffen Wollscheid Newbie

Hi all,

 

we face the following problem in JBoss 7.1.0-Final (including the fix for AS7-3830):

 

We would like to be able to trigger a chain of events, say by JMX-Bean in on OSGi bundle [A].

[A] then calls up an OSGi Service/Class located in bundle [B] using an interface exported by [B].

Now [B] tries to make a remote EJB lookup into an ear [C] on an interface it imported from another OSGi Bundle [D].

 

This fails with the following stacktrace:

[Server:server-one] 15:46:32,245 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110) javax.naming.NamingException: Could not load ejb proxy class steffen.experimental.remote.ejb.RemoteCalculator [Root exception is java.lang.ClassNotFoundException: steffen.experimental.remote.ejb.RemoteCalculator from [Module "deployment.steffen.experimental.ejb-remote.twice-removed:0.0.1.SNAPSHOT" from Service Module Loader]]

[Server:server-one] 15:46:32,245 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.createEjbProxy(EjbNamingContext.java:108)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110) at org.jboss.ejb.client.naming.ejb.EjbNamingContext.lookup(EjbNamingContext.java:96)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.lookup(EjbNamingContext.java:76)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at org.jboss.as.naming.InitialContext.lookup(InitialContext.java:100)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110) at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:213)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)

[Server:server-one] 15:46:32,246 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at steffen.experimental.client.jmx.service.LookupImpl.internal_InitialContextService(LookupImpl.java:63)

[Server:server-one] 15:46:32,247 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110) at steffen.experimental.client.jmx.service.TriggerLookup.doAddition_InitialContextService(TriggerLookup.java:85)

[Server:server-one] 15:46:32,247 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at steffen.experimental.indirect.jmx.ServiceCallerWrapper.doAddition_InitialContextService(ServiceCallerWrapper.java:30)

[Server:server-one] 15:46:32,247 ERROR [stderr] (RMI TCP Connection(4)-10.0.103.110)    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

 

Where “twice-removed” is [A] and the class TriggerLookup does reside in [B].

 

(We have aries.jndi running in our jboss, but the behavior described here occurs also without aries.jndi – in fact we had hoped that aries.jndi would solve our problems)

 

It is important to note, that the same code in [B] works alright, when the initiating JMX Bean resides in [B] instead of [A], because in this case the TCCL is bundle classloader of bundle [B], whereas in the other case it is the bundle classloader of [A] which of course has not knowledge of the interface class.

 

Furthermore it is important to note that this behavior occurs even though the flow of control from [A] to [B] is done using:

 

private TriggerLookupMBean getService()

{

        ServiceReference sRef = TwiceRemovedActivator.getBundleContext().getServiceReference(TriggerLookupMBean.class.getName());

        if( sRef != null ){

           return (TriggerLookupMBean) TwiceRemovedActivator.getBundleContext().getService(sRef);

        } else {

           throw new IllegalStateException("Service TriggerLookupMBean was not found!");

        }

    }

 

public String doAddition_InitialContextService()

{

     return getService().doAddition_InitialContextService();

}

 

So that the OSGi framework would have a chance to change the TCCL using an interceptor hooked into the service which is returned by getService.

But from what I see simply an instance of the implementation class from bundle [B] is returned.

 

Am I doing something wrong here?

 

Having aries.jndi installed, I can do a successful JNDI lookup for an OSGi Service regardless of the Bundle initiating the flow of control, while the same lookup, when done with a “ejb:” prefix fails.

 

This works:

AnOSGiService otherSvc = null;

ServiceReference sRef = Activator.getBundleContext()

      .getServiceReference(JNDIContextManager.class.getName());

if (sRef != null)

{

     JNDIContextManager contextMgr = (JNDIContextManager) Activator.getBundleContext().getService(sRef);

 

     try

     {

        Properties props = new Properties();

        props.put("osgi.service.jndi.bundleContext", Activator.getBundleContext());

        Context ctx = contextMgr.newInitialContext(props);

        System.out.println("doing JNDI lookup");

        otherSvc = (AnOSGiService) ctx.lookup("osgi:service/" + AnOSGiService.class.getName());

        System.out.println("lookup succeeded, calling service");

        return "result:" + otherSvc.foo();

     }

  //...

  

This fails:

 

RemoteCalculator calc = null;

ServiceReference sRef = Activator.getBundleContext()

                .getServiceReference(JNDIContextManager.class.getName());

  if (sRef != null)

{

      JNDIContextManager contextMgr = (JNDIContextManager) Activator.getBundleContext().getService(sRef);

 

           try

      {

         Properties props = new Properties();

         props.put("osgi.service.jndi.bundleContext", Activator.getBundleContext());

         props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

         Context ctx = contextMgr.newInitialContext(props);

         System.out.println("doing lookup");

         calc = (RemoteCalculator)ctx.lookup("ejb:application-ear-0.0.1-SNAPSHOT/ejb-definition-0.0.1-SNAPSHOT//CalculatorBean!steffen.experimental.remote.ejb.RemoteCalculator");

         System.out.println("lookup succeeded, calling remote bean");

            return "result:" + calc.add(1, 1);

      }

//...


 

 

As I mentioned before when called from a JMX-Bean in the same bundle both work!

What am I missing?

 

Our current workaround is an aspect that changes the TCCL in exported public methods if required – but I believe this should not be necessary.