How to consume services registered by bundles in the host application

If we want to manage felix container from Java code, we will usually first start the felix framework, install the bundles and than start those bundles. Code will be something like this :

Felix m_framework = new Felix(configMap);

		try {
			m_framework.init();
			m_framework.start();

			final BundleContext context = m_framework.getBundleContext();

			Bundle provider = context.installBundle(
					"file:C:\\Users\\uogra\\eclipse-workspace\\simpleBundleTest\\target\\Bundle1-0.0.1-SNAPSHOT.jar");
			System.out.println("Starting.......");
			provider.start();
........................................

Lets the code of Bundle which is exposing a service. Here is the activator class of bundle

public class Activator implements BundleActivator {
	private ServiceRegistration serviceReg;

	public void start(BundleContext context) {
		System.out.println("Starting Bundlsasae1 ......");
		serviceReg = context.registerService(CronService.class.getName(), new CronServiceImpl(), null);
		//CronService.class
	}

	public void stop(BundleContext context) {
		System.out.println("Stopping Bundle1 ");
	}

}

It is registering a CronService service. This interface has been written in separate maven jar but its implementation CronServiceImpl is written in this module. Here is the POM of the jar which contains CronService interface

  <groupId>coldfusion.server</groupId>
  <artifactId>coldfusionservices</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>coldfusionservices</name>

The POM of the bundle which is importing the CronService is like this :

<dependency>
			<groupId>coldfusion.server</groupId>
			<artifactId>coldfusionservices</artifactId>
			<version>0.0.1-SNAPSHOT</version>
			<scope>provided</scope>
		</dependency>
		

Now the host application(first code) wants to access this service. Obviously we first need to add the jar containing CronService to the classpath of the host.

Here is the code to fetch the service :

ServiceReference<?> serviceReg = context
					.getServiceReference(CronService.class.getName());
			
			CronService ms = (CronService) context.getService(serviceReg);

But unfortunately this code will fail and you will get classcast exception. In the host application CronService will be loaded by a launcher classloader. But the CronService which was registered by previous bundle has been loaded by the bundle’s own classloader. Hence ‘CronService ‘ written in this host application and ‘CronService ‘ returned by context.getService(serviceReg) are not the same as they both have been loaded by different classloaders.

How to solve this problem?

We can force Felix container to load CronService by the single classloader(laucher classloader). So within the bundle also it will not use bundle’s own classloader to load the class but the launcher classloader.

Map configMap = new StringMap();
		configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "coldfusion.server");
		Felix m_framework = new Felix(configMap);

In the above config we have specified that coldfusion.server package(which contains CronService) should be loaded at the startup by launcher classloader and provided to all the bundles whosoever needs it without them loading the class via their own classloader. This package would be treated like a system package

Uday Ogra

Connect with me at http://facebook.com/tendulkarogra and lets have some healthy discussion :)

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *