Posts Tagged ‘osgi’

Felix and Websphere 7

December 25, 2010

Recently I have ran into issues running Apache’s Felix Project in IBM Websphere 7. When you try and start an embedded Felix OSGi container you get class cast exceptions that classes are not properly matching the interfaces. Specifically I saw that the bundles implementations don’t match BundleActivator interface. Also you could see issues with the “getBundleContext” method not existing on the Bundle class. After some gnashing of teeth I have found the fix for this and its took a little digging so hopefully this will save folks time with the same issue.

The problem…

Websphere 7 (and possibly 6.1+) is including on the classpath org.osgi.core packages which include versions of the interfaces used included in the Felix jars. Also the classes get loaded into the bootstrap classloader which is prefered by Felix when when loading classes. The net result is if you have class loading set to parent first (the default setting) you will see missing methods on interfaces being called, specifically Bundle.getBundleContext. If you have parent last classloading set you will still see issues and all your bundles will not be able to initialize because of class casting issues on BundleActivator (or maybe other interfaces as well). The casting issues are from classes being loaded from different classloaders, bootstrap verses application, when that happens classes even if they have the exact same methods on them will not properly cast to each other. I believe you’ll see most of your issues in the System Bundles for class casting.

The Solution…

There is a pretty simple two part solution which can be accomplished via no code changes…

  1. Ensure your Felix and related classes are included in your war file or some other class loader ahead of the bootstrap class loader in a ‘parent last’ setting. Generally this means set your Web Application to parent last class loading. If you are loading Felix classes from somewhere else ensure the class loader you are loading them with is a parent last classloader.
  2. Update the org.osgi.framework.bundle.parent configuration to ‘framework’. The easiest way to do this just add that exact property name as a system property with value ‘framework’. By default Felix delegates class loading to the bootstrap class loader overriding the class loading strategy set on the initializing code which is what is causing the class cast exception due to multiple versions of the classes getting loaded.

For more configuration properties available for Felix visit http://felix.apache.org/site/apache-felix-framework-configuration-properties.html

OSGi Enabled War

March 25, 2010

If you have ever taken a look at OSGi and thought that it wasn’t going to fit into any of your web applications because of your application server, you may not be out of luck after all. Apache’s Felix project has made a relatively straight forward way of creating an OSGi enabled war file that fits within most applications servers. I’ll go over the basic process and point you to important examples on Felix’s site.

You’ll need to create two projects.

  1. A Bridge War project – this project will manage passing requests back to OSGi (Felix) via a ProxyServlet.
  2. OSGi bundle with Servlet registered – If you already have this skip it but we’ll hit way to register servlets with OSGi.

We’ll start with the Bridge war. You can see a working example on Felix’s site here.

Bridge Dependencies

<dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>servlet-api</artifactId>
     <version>2.5</version>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>org.osgi</groupId>
     <artifactId>org.osgi.compendium</artifactId>
     <version>4.0.0</version>
</dependency>
<dependency>
     <groupId>org.apache.felix</groupId>
     <artifactId>org.apache.felix.framework</artifactId>
     <version>1.8.1</version>
</dependency>
<dependency>
     <groupId>org.apache.felix</groupId>
     <artifactId>org.apache.felix.http.proxy</artifactId>
     <version>2.0.4</version>
</dependency>
<dependency>
     <groupId>org.apache.felix</groupId>
     <artifactId>org.apache.felix.http.bridge</artifactId>
     <version>2.0.4</version>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>org.apache.felix</groupId>
     <artifactId>org.apache.felix.webconsole</artifactId>
     <version>1.2.8</version>
     <scope>provided</scope>
</dependency>

Special Dependency Handling

Two dependencies mentioned are actually OSGi bundles and need to get copied to the place you’ll load bundles from. Those two dependencies are…

  1. org.apache.felix.webconsole
  2. org.apache.felix.http.bridge

Here an sample of how the example how in maven2 you can get those dependencies copied to a special spot

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-dependency-plugin</artifactId>
     <executions>
          <execution>
               <id>copy-bundles</id>
               <goals>
                    <goal>copy-dependencies</goal>
               </goals>
               <configuration>
                    <includeArtifactIds>
                         org.apache.felix.http.bridge,org.apache.felix.webconsole
                    </includeArtifactIds>
                    <stripVersion>true</stripVersion>
                    <outputDirectory>
                         PLACE TO PACKAGE OR LOAD BUNDLES
                    </outputDirectory>
               </configuration>
          </execution>
     </executions>
</plugin>

Ok now that we have the dependencies out of the way here is the coding that needs to be done.

Step One – Create a start up hook to initialize Felix

The simplest place for this is a ServletContextListner.contextInitialized but it just needs to be a place which is guaranteed to be executed before your webapp tries to initialize the ProxyServlet which you’ll configure in step 3. Here is example code of how to initialize Felix.

Properties props = new Properties();
//Load a framework.properties from somewhere accessible to your application server.
//We'll just use the current threads context classloader as an example. Adjust to your situation.
props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("/framework.properties"));
HashMap<String, Object> map = new HashMap<String, Object>();
for (Object key : props.keySet()) {
map.put(key.toString(), props.get(key));
}
BundleActivator activator = ...//We will talk about this in the next step.
map.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, Arrays.asList(activator));
Felix container = new Felix(map);
//You will probably want to keep a reference to keep the container around to
//be able to stop. Depends on where you binding the lifecycle of Felix to.
container.start();

Step Two – Create a class to load your OSGi Bundles for the war

Here we’ll need to create something that implements BundleActivator for the bridge war. We want to create bundle activator that finds and installs bundles for the war file. I’ll provide one that simply looks on the file system at an external location for *.jar files and assumes they are all OSGi bundles. Check out Felix’s example to see how to load bundles internal to the war packaging.

public final class WebActivator
implements BundleActivator
{
public void start(BundleContext context)
throws Exception
{
ArrayList<Bundle> installed = new ArrayList<Bundle>();
File bundleDir = new File("/path/to/bundles");
File[] bundles = bundleDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
});
for (File file : bundles) {
//Load the bundle. file.toURI().toURL()... can probably be done in an easier way not the  point here though.
Bundle bundle = context.installBundle(file.toURI().toURL().toExternalForm());
installed.add(bundle);
}
for (Bundle bundle : installed) {
bundle.start();
}
}
public void stop(BundleContext context)
throws Exception
{
//Nothing necessary
}
}

Step Three – Update your web.xml with ProxyServlet

Add the ProxyServlet mapping for the Felix bridge. Below is an example which forwards everything to the proxy servlet.

<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>org.apache.felix.http.proxy.ProxyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

Step Four – Create a bundle with a servlet in it.

Now you need to create an actual bundle project. I’ll assume you have created a bundle project before, if not check out Felix’s documentation and tutorials. I’ll just point out the basics of how to register your servlet in your new or existing BundleActivator to receive requests. Also I’ll provide the additional dependencies that are needed for you bundle.

Additional Dependencies for a bundle project

<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.http.api</artifactId>
<version>2.0.4</version>
</dependency>

Activator Example

public final class Activator
implements BundleActivator
{
private ServiceTracker tracker;
private CustonActionServlet servlet = new CustonActionServlet();
public void start(BundleContext context)
throws Exception
{
this.tracker = new ServiceTracker(context, ExtHttpService.class.getName(), null)
{
@Override
public Object addingService(ServiceReference ref)
{
Object service =  super.addingService(ref);
serviceAdded((ExtHttpService)service);
try {
//You can map the servlet to any context. This will actually map it to all requests.
((ExtHttpService)service).registerServlet("/", servlet, null, null);
} catch (Exception e) {
e.printStackTrace();
}
return service;
}
@Override
public void removedService(ServiceReference ref, Object service)
{
((ExtHttpService)service).unregisterServlet(servlet);
super.removedService(ref, service);
}
};
this.tracker.open();
}
public void stop(BundleContext context)
throws Exception
{
this.tracker.close();
}
}

If this isn’t making sense take a look Felix’s Example HTTP Servlet and Filter Bundle. This bundle shows also how Felix supports HTTP Filters as well.

Step Five: Build and Run!

Now you have everything in place you simply need to build your bundle then add it to the bundles location where your webapp will be looking for it. Then build your bridge webapp and run it with your favorite appserver.

Additional Notes and Thoughts

First off this is only useful for scenarios where using an application server that doesn’t provide some kind of OSGi integration out of the box. But if you are in a non-OSGi enabled application server you could use this pattern and start Felix in a central location available to all web applications and start integrating services across all applications which where the power in this would be. The trick to this is getting an entire legacy webapp tucked behind the servlet bridge which seems simple enough but there are lots of little issues here and there to work out. I’m working on a porting over several applications using different frameworks, I’ll put up updates if they turn out positive.