15

I am trying to invoke a method of an OSGi bundle from a Java Web Application. Both are supposed to run on Tomcat 7.

I already wrote a normal Java application that invokes methods from the OSGi bundle, as described on this site: http://drupal.osgibook.org/node/37.

To get the context of the Equinox environment I started it from the application and installed the bundles from within. Furthermore the context was used to retrieve a service reference of the running bundle and getting its service.

The runEquinox method of the EquinoxRunner class:

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

public BundleContext runEquinox([...]) throws Exception {
    [...]

    BundleContext bundleContext = EclipseStarter.startup(new String[]{"-console"}, null);
    bundleContext.installBundle("file:C:/.../plugins/myosgiclass.interface_1.0.0.201108301327.jar");
    Bundle bundleTranslationImpl =  bundleContext.installBundle("file:C:/.../plugins/myosgiclass.impl_1.0.0.201108301327.jar");
    bundleTranslationImpl.start();

    [...]
    return bundleContext;
}

and the invokeMethod of the ServiceRunner class:

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

[...]

public Object invokeMethod(BundleContext bundleContext, Object value, [...]){
    ServiceReference serviceReference = bundleContext.getServiceReference(MyOSGiClass.class.getName());
    Object result = null;
    if (serviceReference != null) {
        MyOSGiClass myOSGiClass = (MyOSGiClass) bundleContext.getService(serviceReference);
        if (myOSGiClass != null) result = myOSGiClass.method(value);
        bundleContext.ungetService(serviceReference);
    }
    return result;
}

Now, on Tomcat using the eclipse bridge, I don't know how to retrieve the right context of the Equinox environment. When I try running it on Tomcat with Equinox I get NoClassDefFound Exceptions. I would appreciate any advice on how to solve this problem.

Thanks a lot in advance. Cheers, Nic

Nicolas
  • 472
  • 6
  • 14
  • I think the key is to stay in control of the launching of the OSgi framework. I'm not familiar with the exact workings of equinox, but I'm sure they have something similar to what's described for Felix, here: http://felix.apache.org/site/apache-felix-framework-launching-and-embedding.html – forty-two Sep 01 '11 at 21:30
  • Thanks for your comment. This was the approach I tried too. Though since I need to run my project on a Tomcat server, the above described Bridge seems to be needed - and this I cannot start manually. Or is there any way to bypass this Bridge and use a manually started OSGi framework? – Nicolas Sep 05 '11 at 08:20
  • I don't see how using Tomcat ties you to a specific servlet bridge implementation. Why don't you start with customizing the `org.eclipse.equinox.servletbridge` project? – forty-two Sep 05 '11 at 08:55
  • 4
    Do you need the OSGi framework running at all? Maybe you just need to put your bundle jar file in your WEB-INF/lib folder and use it like any other jar. A bundle is just a jar with extra information in the jar manifest. Any OSGi bundle can be used outside of OSGi as a normal Jar file. – dlaidlaw Oct 21 '11 at 16:11
  • In many cases I would agree with the comment by @dlaidlaw, but the original question mentions retrieving service references, so it's likely that the bundle in question has several runtime dependencies. Trying to set those up outside of an OSGi framework is often futile. – Chris Dolan Dec 18 '11 at 14:32
  • Just a thought: JBoss AS7 includes both an OSGi runtime and Tomcat. – Chris Dolan Dec 18 '11 at 14:33

4 Answers4

2

I have done this before using the EclipseStarter stuff with the bridge, and it was a lot of work to get the classpath stuff right which is the key. You also have to call EclipseStarter using reflection. It looks like they have standardized this since then so you don't need to use the EclipseStarter.

The key here (as briefly mentioned in the Felix article is that you have to have a shared classpath between your Tomcat environment and your OSGi environment. If you look in that article at the section starting with "Using Services Provided by Bundles", it seems to suggest what you want.

You will need to have an interface to what you are calling in your Tomcat (parent) classpath, and then you need to start the framework such that it uses your parent classpath first (which is likely not their launcher stuff works), and you need to exclude the bundle that provides the interface from the OSGi bundles. I accomplished this by making a separate OSGi bundle (the API bundle) that just had the interfaces, so when I wanted to use this setup in a context where my code was called from outside OSGi I would not provide that API bundle.

Francis Upton IV
  • 19,322
  • 3
  • 53
  • 57
2

When you embeds an OSGi framework like that and then want to access an OSGi service from the outer environment, you need to be sure that the service interface are the same inside and outside of OSGi.

So, configure your OSGi container to export the package of your service interface from Tomcat to OSGi. To achieve this, configure your OSGi framework with the 'FRAMEWORK_SYSTEMPACKAGES_EXTRA' property.

More info on http://felix.apache.org/site/apache-felix-framework-launching-and-embedding.html#ApacheFelixFrameworkLaunchingandEmbedding-hostservices (even if it's for Apache Felix, the embedding API is standardized).

Clement
  • 2,817
  • 1
  • 12
  • 11
  • An up-to-date link: http://felix.apache.org/documentation/subprojects/apache-felix-framework/apache-felix-framework-launching-and-embedding.html – FableBlaze Jan 17 '16 at 00:11
0

I overcame this challenge by overriding the JasperClass Loader what is happening each bundle as its own class loader classdeffnotfound is because the tomcat loader is being used. There are more resources online.

Duncan Krebs
  • 3,366
  • 2
  • 33
  • 53
0

I am sorry I won't answer to your question directly... From my point of view you don't take the good approach , do you have any valuable reason to use an existing Tomcat 7 instance ? I would use a more OSGi centric approach , and use the standard Http Service to publish your web application... In such context both components are on the same level as standard OSGi bundles and then as a consequence the communication between 2 components is really easy (direct method invokation or asynchronous message using EventAdmin service) HTH my 2 cents Jerome PS: this approach gives you much more flexibility, it can be used with Equinox or any other OSgi shell you want (felix, knopflerfish..)

romje
  • 650
  • 3
  • 4