Tuesday

OSGI and Injection

As stated previously at ServiceMix 4.x, the new version of that ESB, uses OSGi for solving the JBI's weakest areas which is the cumbersome classloader model. OSGi solves this problem with advanced OSGi bundling and classloading mechanisms. In a nutshell, OSGi is an environment where bundles (modules) communicate through well-defined services while hiding their internals from other bundles. OSGi also specifies how components are installed and managed. Components can be started, stopped, updated and uninstalled dynamically without bringing down the entire server. This is very beneficial for high availability systems (like an ESB). OSGi bundles are versioned and only bundles that can collaborate are wired together in the same class space.

One of the architectural decision was to find which injection frameworks could be used in an OSGI environment, apart from the ESB issues. The motivation was the integration of Wicket and OSGI.

At this time several options are offered. I selected the two following frameworks:

I started with Spring DM but after few weeks I decided to look into Guice - Pearry.

What are the benefits of Guice - Peaberry?

  1. Lightweight OSGI Injection Framework – no XML configuration file,
  2. The only annotation to know is @Inject,
  3. Targeted an OSGI service instead of a fake mock class is transparent,
  4. No modifications are needed for Unit Testing. Create only a new AbtractModule

I would like to show through a simple example the power of Guice, Peaberry.

Here is the example to initialize Guice with Peaberry:

public abstract class WebAppActivator implements BundleActivator {
protected abstract WebApplication getWebAppImpl();
public Injector getInjector() {
return injector;
}

@Override
public void start(final BundleContext bundleContext) {
// Create a Guice Module
Module module = new AbstractModule() {
protected void configure() {
// Use the Guice Peaberry extension
install(Peaberry.osgiModule(bundleContext));
// Bind a Wicket Web Application
bind(WebApplication.class).toInstance(getWebAppImpl());
// Bind the OWLoginChange class
bind(LoginContext.class).to(OWLoginChange.class);
}
};
injector = createInjector(module, getCustomModule());
// Get the Web App out of the injector and register it in
// the OSGi core registry
Properties p = new Properties();
Object instance = injector.getInstance(WebApplication.class);
bundleContext.registerService(WebApplication.class.getName(), instance, p);
}
protected Module getCustomModule() {
return new AbstractModule() {
protected void configure() {
}
};
}



@Override
public void stop(BundleContext bundleContext) {
// NOTE: The core is automatically unregistered.
}
// guice injector
private Injector injector;
}

The configuration of Peaberry and Guice is done in one line during the creation of the AbstractModule class.

The framework used Wicket Swarm for the authentication and the authorisation. Each sub-class of the WebAppActivator needs to register the following interfaces:

  1. IHomePageService - the home page
  2. IAuthenticationService - the authentication service

Here is an example to register an OSGI service:

protected Module getCustomModule() {
return new AbstractModule() {

protected void configure() {
// bind the IHomePageService with an OSGI service
bind(IHomePageService.class).toProvider(service(IHomePageService.class).single());

// Bind the authentication service
bind(IAuthenticationService.class).to(DefaultLogin.class);
}
};
}

The registration of an OSGI service is done in using the static method org.ops4j.peaberry.Peaberry.service of the Peaberry framework.

Another powerfull functionality of Peaberry is to retrieve multiple occurance of a Service. Let see how to retrieve with Peaberry multiple services which define the same interface.

Here is the example to register multiple OSGI services:

@Override
protected Module getCustomModule() {
return new AbstractModule() {
@Override
protected void configure() {
// bind the IMenuItemFactory
bind(iterable(IMenuItemFactory.class)).toProvider(service(IMenuItemFactory.class).multiple());
}
};
}

How to retrieve the services:

public class MenuPanel extends Panel {

@Inject
public Iterable menuItems;
}


full window

2 comments:

Lars Heinemann said...

Really nice work!
But I would suggest reworking the code formatting because it makes my eyes bleeding :)

Dimosthenes said...

many thanks and... sorry s for your eyes... malfunction of the auto numbering feature of the blog's automations... reformatted as plain txt to be sure.