JBoss.orgCommunity Documentation

Chapter 5. OSGi Integration

OSGi is a dynamic module system for declarative services. So what does that mean? Each jar in OSGi is called a bundle and has it's own ClassLoader. Each bundle specifies the packages it exports (makes publicly available) and which packages it imports (external dependencies). OSGi will use this information to wire the ClassLoaders of different bundles together; the key distinction is you don't specify what bundle you depend on, or have a single monolithic classpath, instead you specify your package import and version and OSGi attempts to satisfy this from available bundles.

It also supports side by side versioning, so you can have multiple versions of a bundle installed and it'll wire up the correct one. Further to this Bundles can register services for other bundles to use. These services need initialisation, which can cause ordering problems - how do you make sure you don't consume a service before its registered? OSGi has a number of features to help with service composition and ordering. The two main ones are the programmatic ServiceTracker and the xml based Declarative Services. There are also other projects that help with this; Spring DM, iPOJO, Gravity.

Each of the Drools factories is now also available as a FactoryService interface. You can either have OSGi inject those into a pojo, or retrieve them yourself from OSGi.

The following modules should work with OSGi;

The following Services can be located as OSGi Bundles

I'll cover injection here. The below example injects the KnowledgeBuilderFactoryService, KnowledgeBaseFactoryService and ResourceFactoryService into the TestComponent pojo.

Example 5.1. OSGi Declarative Services


<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
<implementation class="testosgi.TestComponent"/>

<reference bind="setKnowledgeBaseFactoryService"
           unbind="unsetKnowledgeBaseFactoryService"
           interface="org.drools.KnowledgeBaseFactoryService"
           />

<reference bind="setResourceFactoryService"
           unbind="unsetResourceFactoryService"
           interface="org.drools.core.io.ResourceFactoryService"
           />

<reference bind="setKnowledgeBuilderFactoryService"
           unbind="unsetKnowledgeBuilderFactoryService"
           interface="org.drools.core.builder.KnowledgeBuilderFactoryService"
           target="(org.drools.compiler.compiler.DecisionTableProvider=true)"  />
</scr:component>

The TestComponent will only be activated when all of the referenced services are available and injected into the pojo. You'll also notice the "target" attribute for the KnowledgeBuilderFactoryService. The reason for this is that OSGi DS has no built in way to declaratively say which optional services must be present to satisfy your component. As a work around I made any Drools service that has optional services set a property if/when the optional service is available. Filters can then be applied, via the target attribute, to make sure the Service is in a desired state before consuming it. And that is pretty much it :)

Example 5.2. Basic Rule Compilation

ServiceReference serviceRef = bundleContext.getServiceReference( ServiceRegistry.class.getName() );
ServiceRegistry registry = (ServiceRegistry) bundleContext.getService( serviceRef );

KnowledgeBuilderFactoryService knowledgeBuilderFactoryService = registry.get( KnowledgeBuilderFactoryService.class );
        
KnowledgeBaseFactoryService knowledgeBaseFactoryService = registry.get( KnowledgeBaseFactoryService.class );
ResourceFactoryService resourceFactoryService = registry.get( ResourceFactoryService.class );

KnowledgeBuilderConfiguration kbConf = knowledgeBuilderFactoryService.newKnowledgeBuilderConfiguration( null,
                                                                                                        getClass().getClassLoader() );

KnowledgeBuilder kbuilder = knowledgeBuilderFactoryService.newKnowledgeBuilder( kbConf );
ResourceFactoryService resource = resourceFactoryService;
kbuilder.add( resource.newByteArrayResource( string.getBytes() ),
              ResourceType.DRL );

if ( kbuilder.hasErrors() ) {
     System.out.println( kbuilder.getErrors() );
     throw new RuntimeException( kbuilder.getErrors().toString() );
}

KnowledgeBaseConfiguration kbaseConf = knowledgeBaseFactoryService.newKnowledgeBaseConfiguration( null,
                                                                                                  getClass().getClassLoader() );

KnowledgeBase kbase = knowledgeBaseFactoryService.newKnowledgeBase( kbaseConf );
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

Example 5.3. Decision Table Example

ServiceReference serviceRef = bundleContext.getServiceReference( ServiceRegistry.class.getName() );
ServiceRegistry registry = (ServiceRegistry) bundleContext.getService( serviceRef );

KnowledgeBuilderFactoryService knowledgeBuilderFactoryService = registry.get( KnowledgeBuilderFactoryService.class );
KnowledgeBaseFactoryService knowledgeBaseFactoryService = registry.get( KnowledgeBaseFactoryService.class );
ResourceFactoryService resourceFactoryService = registry.get( ResourceFactoryService.class );

KnowledgeBaseConfiguration kbaseConf = knowledgeBaseFactoryService.newKnowledgeBaseConfiguration( null,
                                                                                                  getClass().getClassLoader() );

KnowledgeBuilderConfiguration kbConf = knowledgeBuilderFactoryService.newKnowledgeBuilderConfiguration( null,
                                                                                                        getClass().getClassLoader() );
KnowledgeBuilder kbuilder = knowledgeBuilderFactoryService.newKnowledgeBuilder( kbConf );
kbuilder.add( resourceFactoryService.newClassPathResource( "changeset1Test.xml",
                                                           Dummy.class ),
              ResourceType.CHANGE_SET );

kbaseConf = knowledgeBaseFactoryService.newKnowledgeBaseConfiguration( null,
                                                                       getClass().getClassLoader() );
KnowledgeBase kbase = knowledgeBaseFactoryService.newKnowledgeBase( kbaseConf );
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();