:source-highlighter: highlights :data-uri: :toc:
== Video How To Run
image:documentation/images/fuse-brms-video.png[Video,link="http://vimeo.com/106557607"]
== JBoss BRMS & JBoss Fuse examples for OSGi platforms (JBoss Fuse, Karaf, Fabric8)
toc::[]
This project contains JBoss BRMS & JBoss Fuse OSGi examples that you can deploy.
== Download and compile the project
Clone project or https://github.com/jbossdemocentral/brms-fuse-osgi-examples/archive/master.zip[download and unzip.]
Compile it using maven
$ cd brms-fuse-osgi-examples
$ mvn clean install
== Download and deploy on RedHat JBoss Fuse
Open a browser at the following address : https://www.jboss.org/products/fuse.html
Download JBoss Fuse 6.2
Unzip it under your local temp directory ~/temp
Change to the JBoss Fuse bin directory
cd ~/temp/jboss-fuse-6.2.0.redhat-133/bin
Start Fuse console
./fuse
== Download and deploy on Apache Karaf/Fabric8
Procedure is exactly the same excepted that you should download Apache Karaf or Fabric8 releases
== Add Repositories of the modules
In the JBoss Fuse/Karaf console, add the url pointing to the file containing the description of the BRMS/BPM OSGI modules
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features
Now you are ready to start to play with different examples described hereafter !
See the tagged releases for the following versions of the product:
== JBoss BRMS OSGi Example
=== Simple Rule Example
To test the simple rule example which is a BRMS example using a rule DRL
rule "CanDrink" when p : Person( age >= 21 ) then p.setCanDrink(true); end
where we will check if a person can drink, we will deploy the module simple-rule
. This module
which is a feature will install the code of the bundle simple-rule
but also drools core & compiler
like kie
project (api & internal)
features:install simple-rule
After a few moment, you will see that the bundle
has been installed and started as the Activator class will report the following message
KieSession created.
corresponding to the KieSession created by Kie & BRMS after discovering the META-INF/kmodule.xml file containing the location of the resources to be loaded by BRMS (Rule, ...). This session is created as the start method of the bundle activator class contains the code to create a KieContainer, KieBaseConfiguration & KieBase
KieServices ks = KieServices.Factory.get(); KieBaseConfiguration kbaseConfig = ks.newKieBaseConfiguration(null, this.getClass().getClassLoader()); KieBase kbase = ks.newKieClasspathContainer().newKieBase(kbaseConfig);
Next, 20 persons will be generated randomly by a function which, added to a KieSession and rule fired to verify if they can Drink according to their age.
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Old Person aged of 21 , can go to the Bar
Person Young Person aged of 18, can't go to the Bar
Remark : When you stop the bundle 'simple-rule', the Kie Session is stopped and this message appears in the console of Karaf
KieSession disposed
=== Externalise the rules assets
One of the benefit of an OSGI platform is that the bundles (= jar file + META DATA defined in the MANIFEST.mf file) are isolated form each other as they run within their own classloader. That means that we can split a BRMS & Kie project into a collection of bundles: one containing the logic and the Kie classes to build the container hosting the KieBase (= assets), KieSessions (= in cache memory of the facts/objects) while the assets can be packaged in a separate bundle. This approach allows the business user to produce the jar containing the rules, decision tables, ... according to a procedure (= release management) which is independent from the one followed by developer team to design/develop the project. As the assets will be deployed in a separate bundle, they can be updated without changing the code of the project.
This demo which uses the same code as the example "Simple Rule Example" but it has been packaged into 2 bundles.
The assets
image:documentation/images/assets.png[]
and the Kie
image:documentation/images/kie-bundle.png[]
The project can be deployed using this feature command
features:install simple-import-rule
=== Simple XLS Decision Table with a Rule Example
As JBoss BRMS supports to externalize rules in a XLS Decision Table, this example will demonstrate how such a project can be packaged as an OSGi bundle. Compared to the previous example, the rule is not defined in a file where the extension ends with .drl but in a XLS file
image:documentation/images/decision-table.png[]
The XLS Table contains a rule to checks Type of the Cheese. This file is located under this directory resources/org.drools.example.cheese
and
the `resources/META-INF/kmodules.xml file contains the definition about the project to be scanned before to create the KieBase, KieSession
<?xml version="1.0" encoding="UTF-8"?>
The code of the OSGI Bundle Activator used when the OSGI Container starts the bundle and calls the events start
or stop
are similar to what has been created
for the simple-rule
project
public void start(final BundleContext bc) throws Exception {
KieServices ks = KieServices.Factory.get();
KieBaseConfiguration kbaseConfig = ks.newKieBaseConfiguration(null, this.getClass().getClassLoader());
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
KieBase kbase = ks.newKieClasspathContainer().newKieBase(kbaseConfig);
this.ksession = kbase.newKieSession();
System.out.println("KieSession created.");
for (int i = 0; i < 10; i++) {
// Create a Cheese
Cheese aCheese = EntityHelper.createCheese();
ksession.insert(aCheese);
// Fire the rules
ksession.fireAllRules();
// Check Cheese Price
EntityHelper.cheesePrice(aCheese);
}
System.out.println("Cheese added and rules fired.");
To deploy this module on the container, use this Karaf command which will install decision-table
module and the example.
When the bundle will be started, this information will appear in the Karaf Console
karaf@root> features:install simple-decisiontable-rule
KieSession created.
Cheese Stilton costs 10 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Stilton costs 10 EUR.
Cheese Stilton costs 10 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Stilton costs 10 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Stilton costs 10 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Stilton costs 10 EUR.
=== External XLS Decision Table
As Rules will be designed by business analysts in a company, they will prefer to use a XLS Spreadsheet document that they will provide to the project (developer, ...) as artefact to be used by the application to calculate decision. In the previous example, the decision table was embedded, packaged into the jar file generated during the build of the application. While this approach is fine, it implies that the project must rebuild (regenerate a jar/zip file) every time we have a new update the decision table. This example allows you to externalize the location of the decision table. The only thing to be done is to change this variable in the code
to point to your XLS file on the file system, before to build the project and deploy on it Karaf, JBoss Fuse.
Project can be deployed using the following Karaf command :
features:install fetch-external-resource
And after rules calculation, the following result will be displayed
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Stilton costs 10 EUR.
Cheese Stilton costs 10 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese Cheddar costs 50 EUR.
Cheese added and rules fired.
For later update of the XLS file, the bundle used for this example must be restarted to create new Session and load new Rules definition
osgi:restart ID_OF_THE_BUNDLE
=== Simple rule using Declarative Service
Instead of implementing the BundleActivator interface in our code, the service required to call the events (start/stop) of the bundle (managed by the OSGI container) can be managed using http://wiki.osgi.org/wiki/Declarative_Services[OSGI Declarative Service]. The DS will take care to retrieve from the OSGI Registry the interface exposed with this name ("org.osgi.framework.BundleActivator"). By adding the following annotations to the class, the service will be retrieved when the bundle will be started and the methods (start/deactivate) called by the DS container when the proxy object will be created with the classloader of the bundle.
@Component(name = "org.osgi.framework.BundleActivator")
public class CanDrinkRuleOsgiDeclarativeService {
private KieSession ksession;
@Activate
public void start(final BundleContext bc) throws Exception { ...}
@Deactivate
public void stop(final BundleContext bc) throws Exception { ... }
}
Like the simple rule example the project can be deployed with the help of the features provisioning mechanism.
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features
features:install simple-rule-inject-ds
=== Simple rule using CDI & Weld
BundleActivator like also Spring Dynamic Module, Blueprint and Declarative Service are great and interesting technologies to start/stop your bundle, inject the services or design your bundle as a component but they use http://en.wikipedia.org/wiki/OSGi[OSGI] that maybe your are not familiar with as a Java or JavaEE developer. In this case, you can also turn on your project into a CDI Beans project and use http://weld.cdi-spec.org/[Context & Dependency Injection] to manage the lifecycle of your bundle and inject the KieSession created based on your Kmodule.xml using annotations.
To use Weld 2.x and CDI 1.1, it is required to add this https://ops4j1.jira.com/wiki/display/PAXCDI/Requirements+and+Capabilities[OSGI requirement capability] to your bundle as this property will be used by the OSGI Container to register your bundle to the CDI Service managed by https://ops4j1.jira.com/wiki/display/PAXCDI/Pax+CDI[OPS4J Pax CDI] which implement the specification http://blog.osgi.org/2012/05/osgicdi-integration-rfp-available-for.html[OSGI CDI].
The java class looks like any CDI Bean class where a scope has been defined (@ApplicationScope) and dependencies injected @Inject @Kession to retrieve from the CDI Context, the object KSession created based on Kmodule.xml definition. The trick to link the lifecycle of the bundle (start/stop events) with the OSGI CDI Service is to use the @Observes http://docs.jboss.org/cdi/spec/1.0/html/events.html#observermethods[annotation] and the ContainerInitialized event.
import org.kie.api.cdi.KSession; import org.ops4j.pax.cdi.api.ContainerInitialized;
import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject;
@ApplicationScoped public class CanDrinkRuleOsgiCdiWeld {
@Inject
@KSession("sampleKSession")
private KieSession ksession;
public void onStartup(@Observes ContainerInitialized event) {
KieServices ks = KieServices.Factory.get();
KieContainer kcont = ks.newKieClasspathContainer(getClass().getClassLoader());
KieBase kbase = kcont.getKieBase("sampleKBase");
this.ksession = kbase.newKieSession();
System.out.println("KieSession created.");
for (int i = 0; i < 20; i++) {
// Create a Person
Person aPerson = PersonHelper.createPerson();
ksession.insert(aPerson);
// Fire the rules
ksession.fireAllRules();
// Check if it can drink
PersonHelper.canDrink(aPerson);
}
}
@PreDestroy
public void onClose() {
if (this.ksession != null) {
this.ksession.dispose();
System.out.println("KieSession disposed.");
}
}
To deploy this project on JBoss Fuse, use this feature command which will deploy your JBoss BRMS cdi bundle but also the Weld CDI 1.1 container , the OSGI CDI service managing the lifecyle of the CDI Container when the bundle start/stop
features:install simple-cdi
== jBPM OSGi Example
=== Simple Process
jbpmn process is also supported and can be deployed too on Karaf, JBoss Fuse container. Like the JBoss BRMS Simple Rule Example, you should install a feature which will install the bundles required (jbpm, Human-task, ...) and finally the example
features:install simple-process
The process is simple and start by logging information that process has been initiated before to diverge, register a request and finally converge at the end
image:documentation/images/evaluation-process.png[]
To configure the runtime manage with the bpmn process file, you should add assets using a ResourceFactory.newClassPathResource
with the package name containing it
RuntimeEnvironment environment = RuntimeEnvironmentBuilder.getEmpty() .addAsset(ResourceFactory.newClassPathResource(process,getClass().getClassLoader()), ResourceType.BPMN2) .get(); return RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(environment);
The parameters used by the business process like also the tasks are configured like that
runtimeEngine = runtimeManager.getRuntimeEngine(EmptyContext.get()); ksession = runtimeEngine.getKieSession();
LOG.info("Register tasks"); ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new SystemOutWorkItemHandler()); ksession.getWorkItemManager().registerWorkItemHandler("Register Request", new SystemOutWorkItemHandler());
Map<String, Object> params = new HashMap<String, Object>(); params.put("employee", "UserId-12345");
=== jBPM Process with JPA persistence
One of the key benefit of a BPM engine is that when a process will be started we can persist the state changes when the steps/nodes defined in a BPMN process are reached. The purpose of this example is to design the project using the jBPM Persistence JPA module and to manage such changes using http://hibernate.org/[Hibernate ORM Technology] with a Database http://www.h2database.com/html/main.html[H2]. Spring will be used to manage the creation of the JPA Container and load from the Hibernate mapping ORM files the classes used by the JPA layer to insert/update records in the database.
To configure the jBPM runtime manager to use the persistent layer, the Kbase configuration must include the bean jpa-persistence with the references to the TransactionManager JpaTransactionManager and the JPA Container LocalContainerEntityManagerFactoryBean. The LocalContainerEntityManager is configured with a Datasource and the persistent Unit Name containing the information about the Transaction Management (LOCAL_RESOURCE or JTA), mapping classes / tables ...
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:kie="http://drools.org/schema/kie-spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd">
<kie:kmodule id="kModule">
<kie:kbase name="kPersistence">
<kie:ksession name="kSession" type="stateful">
<kie:processEventListener ref="audit-listener"/>
<kie:processEventListener ref="log-listener"/>
<kie:configuration>
<kie:jpa-persistence>
<kie:transaction-manager ref="txManager"/>
<kie:entity-manager-factory ref="myEmf"/>
</kie:jpa-persistence>
</kie:configuration>
</kie:ksession>
</kie:kbase>
</kie:kmodule>
<bean id="jbpm-ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:tcp://localhost/jbpmprocess"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="jbpm-ds"/>
<property name="persistenceUnitName" value="org.jbpm.persistence.jpa.local"/>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
The KieRuntime will use the following bean definition to register the TxManager and the JPA Container
<kie:environment id="env">
<kie:entity-manager-factory ref="myEmf"/>
<kie:transaction-manager ref="txManager"/>
</kie:environment>
To enable the logging / audit of the processes started and nodes triggered we have added some Process listeners to the config
<kie:kmodule id="kModule">
<kie:kbase name="kPersistence">
<kie:ksession name="kSession" type="stateful">
<kie:processEventListener ref="audit-listener"/>
<kie:processEventListener ref="log-listener"/>
...
<bean id="log-listener" class="org.jbpm.osgi.persistent.example.LoggingProcessEventListener"/>
<bean id="audit-listener" class="org.jbpm.process.audit.AuditLoggerFactory"
factory-method="newJPAInstance">
<constructor-arg ref="env"/>
</bean>
Next the project can be deployed in Boss Fuse using these instructions
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install jbpm-spring-persistent
When the process will be triggered, the logging process listener will collect the information and log them on the console
Similarly, info can retrieved using the H2 web console (http://localhost:8082/) when you will be connected using the following parameters :
Driver Class : org.h2.Driver
JDBC Url : jdbc:h2:tcp://localhost/jbpmprocess
User name : sa
Password :
Click on the table nodesintancelog and run the SQL query generated (SELECT * FROM NODEINSTANCELOG) to consult info audited by the runtime manager
image:documentation/images/nodes_log.png[]
== Integration with Camel Example
The JBoss BRMS has developed different kie modules that you can use to integrate this technology with Apache Camel to collect the information needed to prepare the facts/objects that we will next inserted into the KieSessions.
=== Kie Spring with Camel & JBoss BRMS
This example combines the http://camel.apache.org[Camel Java Integration framework] with JBoss BRMS and Spring (IoC framework) to insert the facts/objects into a KieSession created and managed by camel. The objects created (= Person) whenever they are inserted in the KieSession will be
To run the project on JBoss Fuse, simply run this features:install command to deploy the bundles. After being deployed the bundle containing the camel routes definition will be started and the camel timer component will fire events every 10s to request to create a Person object or Cheese object as we have 2 camel routes.
One camel route is used by JBoss BRMS and the other by JBoss BRMS DecisionTable.
The object created (= fact) is inserted into the KieSession used by JBoss BRMS and when this is done the rules will be fired automatically. To play with the project, use the following features:install command to deploy the bundles on JBoss Fuse.
features:install drools-decisiontable-kie-spring-camel
=== Kie Blueprint with Camel & JBoss BRMS
Same example as described before but instead of Spring Dynamic Module project, we will setup the project using the http://www.ibm.com/developerworks/library/os-osgiblueprint/[OSGI Blueprint container] to instantiate the beans required to start the CamelContext containing the camel routes like also the beans handling the business logic (PersonHelper, CheeseHelper, ...).
features:install drools-decisiontable-kie-blueprint-camel
Enjoy it !
== Shortcut to play with the different scenario
To play with the different examples and redeploy the bundles in JBoss Fuse every time, follow these steps
Start Karaf with clean option to remove previously installed bundles and start the server with the features defined by default under the file etc/org.apache.karaf.features.cfg (see feeturesBoot variable)
./karaf clean
Install the features repo and the corresponding features
JBoss BRMS (kie + rules) started using BundleActivator
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-rule
JBoss BRMS (kie + rules) started using OSGI Declarative Service
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-rule-inject-ds
JBoss BRMS (kie + rules) started using CDI and Weld
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-cdi
Idem as scenario 1. but rules are packaged in a separate jar/bundle
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-import-rule
JBoss BRMS Decision Table (kie + rules defined in a spreadsheet) started using BundleActivator
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-decisiontable-rule
JBoss BRMS Decision Table (kie + rules defined in a spreadsheet ) started using BundleActivator
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install fetch-external-resource
BPM process
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install simple-process
BPM process using persistence & JPA
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install jbpm-spring-persistent
Spring project (Kie Spring) starting Camel Routes firing JBoss BRMS rules
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install drools-decisiontable-kie-spring-camel
Aries Blueprint project (Kie Aries Blueprint) starting Camel Routes firing JBoss BRMS rules
features:addurl mvn:org.drools.example/features/1.0.0-SNAPSHOT/xml/features features:install drools-decisiontable-kie-blueprint-camel