Monday, February 01, 2016

50% off on all Packt eBooks & Videos

Packt Publishing has a great promotion going on right now. They are offering 50% off on all Packt eBooks and Videos until March 2nd.

It is a great opportunity to grab all those Drools books as well as any others you might be interested in.

Click on the image bellow to be redirected to their online store:



Share/Bookmark

Thursday, December 03, 2015

Drools: A detailed description of internal code cleanups for fireAllRules, fireUntilHalt and Timers.

In June we blogged about a new internal state machine to manage the interaction of User, Timer and Engine threads. We've now done another big internal clean up of this code, to make it easier to read and easier to understand.

As previous mentioned all actions (insert, update, delete etc) are now placed into a thread safe propagation queue. The user thread, when executing those actions, never touches the engine any more, not even the alpha network. This gives improved thread safety. Instead when the engine starts it first drains and evaluates this queue, which can result in alpha network evaluations, before doing rule evaluation and firings.

As well as User and Engine thread separation the other aim of the state machine was to co-ordinate the Timer thread. When a timer kicks off the engine may be INACTIVE or it may be running. If the engine is active the Timer should just submit an entry into the propagation queue and let the current executing thread handle the job. If the engine is not active and the timer rule is async the timer thread should take care of the evaluating and firing, via the executeTask method. The state machine is designed to minimise sync's and locks to keep contention minimal.

The engine now has 5 possible states it can be in.  INACTIVE is the starting state.


Engine  evaluation and rule firing has three potential entry points fireAllRules, fireUntilHalt and async timer rules - the later is done through the executeTask part. We have unified fireAllRules and fireUntilHalt into a single fireLoop method, that uses a strategy class, passed as an argument, to handle the potential rest state of the loop.  The engine is considered at rest when there are no rules firing, when there are no more agenda group to evaluate and when the queue is empty.

FireAllRules all rules will then set the engine to INACTIVE and the loop will exit. FireUntilHalt will make the current thread wait, until more work comes into the queue for processing. Work has been done here to make sure there are no gaps, and loss of executions, during those state transitions.

When a thread wants to transition to FIRE_ALL_RULES or FIRE_UNTIL_HALT or EXECUTE_TASK, it must go through waitAndEnterExecutionState. If the engine is INACTIVE it can transition straight away, if not it'll go into a wait state until the current executing thread has finished and returned the engine back to INACTIVE:
private void waitAndEnterExecutionState( ExecutionState newState ) {
    if (currentState != ExecutionState.INACTIVE) {
        try {
            stateMachineLock.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException( e );
        }
    }
    setCurrentState( newState );
}

Let's look at how fireAllRules() uses this. Note firstly that if the engine is already running, because fireAllRules or fireUntilHalt have been previous called and still running, it will simply exit. Second note it only holds the sync point long enough to either exit or make the desired transition. Once the engine is in FIRE_ALL_RULES state it can let go of the sync block and the state machine will stop anything from interfering with it.
public int fireAllRules(AgendaFilter agendaFilter,
                        int fireLimit) {
    synchronized (stateMachineLock) {
        if (currentState.isFiring()) {
            return 0;
        }
        waitAndEnterExecutionState( ExecutionState.FIRING_ALL_RULES );
    }


   int fireCount = fireLoop(agendaFilter, fireLimit, RestHandler.FIRE_ALL_RULES);

   return fireCount;
}

The fireLoop is now generic and used by both fireAllRules and fireUntilHalt, with the use of the RestHandler strategy to handle the logic for when the engine comes to a rest point.
private int fireLoop(AgendaFilter agendaFilter,
                     int fireLimit,
                     RestHandler restHandler) {
        // The engine comes to potential rest (inside the loop) when there are no propagations and no rule firings.        // It's potentially at rest, because we cannot guarantee it is at rest.        // This is because external async actions (timer rules) can populate the queue that must be executed immediately.        // A final takeAll within the sync point determines if it can safely come to rest.        // if takeAll returns null, the engine is now safely at rest. If it returns something        // the engine is not at rest and the loop continues.        //        // When FireUntilHalt comes to a safe rest, the thread is put into a wait state,        // when the queue is populated the thread is notified and the loop begins again.        //        // When FireAllRules comes to a safe rest it will put the engine into an INACTIVE state        // and the loop can exit.        //        // When a halt() command is added to the propagation queue and that queue is flushed        // the engine is put into a HALTING state. At this point isFiring returns false and        // no more rules can fire and the loop exits.

int fireCount = 0; try { PropagationEntry head = workingMemory.takeAllPropagations(); int returnedFireCount = 0; boolean limitReached = fireLimit == 0; // -1 or > 0 will return false. No reason for user to give 0, just handled for completeness. boolean loop = true; while ( isFiring() ) { if ( head != null ) { // it is possible that there are no action propagations, but there are rules to fire. this.workingMemory.flushPropagations(head); head = null; } // a halt may have occurred during the flushPropagations, // which changes the isFiring state. So a second isFiring guard is needed if (!isFiring()) { break; } evaluateEagerList(); InternalAgendaGroup group = getNextFocus(); if ( group != null && !limitReached ) { // only fire rules while the limit has not reached. returnedFireCount = fireNextItem( agendaFilter, fireCount, fireLimit, group ); fireCount += returnedFireCount; limitReached = ( fireLimit > 0 && fireCount >= fireLimit ); head = workingMemory.takeAllPropagations(); } else { returnedFireCount = 0; // no rules fired this iteration, so we know this is 0 group = null; // set the group to null in case the fire limit has been reached } if ( returnedFireCount == 0 && head == null && ( group == null || !group.isAutoDeactivate() ) ) { // if true, the engine is now considered potentially at rest head = restHandler.handleRest( workingMemory, this ); } } if ( this.focusStack.size() == 1 && getMainAgendaGroup().isEmpty() ) { // the root MAIN agenda group is empty, reset active to false, so it can receive more activations. getMainAgendaGroup().setActive( false ); } } finally { // makes sure the engine is inactive, if an exception is thrown. // if it safely returns, then the engine should already be inactive
        // it also notifies the state machine, so that another thread can take over        immediateHalt();
    }
    return fireCount;
}

The fire loop goes through a single sync point when it does a takeAll() which is simple operation to return the current head instance, while also nulling member head field so that the queue is empty.  During this takeAll() it means that any user or timer operations will be waiting on the sync to release, before they can add into the queue. After that the rest of method, evaluating the returned list of items and evaluating the network and firing rules can happen without ever needing to go through another sync or lock.

The rest handlers are both two very simple pieces of code:
interface RestHandler {
    RestHandler FIRE_ALL_RULES = new FireAllRulesRestHandler();
    RestHandler FIRE_UNTIL_HALT = new FireUntilHaltRestHandler();

    PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda);

    class FireAllRulesRestHandler implements RestHandler {
        @Override        public PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda) {
            synchronized (agenda.stateMachineLock) {
                PropagationEntry head = wm.takeAllPropagations();
                if (head == null) {
                    agenda.halt();
                }
                return head;
            }
        }
    }

    class FireUntilHaltRestHandler  implements RestHandler {
        @Override        public PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda) {
            return wm.handleRestOnFireUntilHalt( agenda.currentState );
        }
    }
}

@Override
public PropagationEntry handleRestOnFireUntilHalt(DefaultAgenda.ExecutionState currentState) {
    // this must use the same sync target as takeAllPropagations, to ensure this entire block is atomic, up to the point of wait    synchronized (propagationList) {
        PropagationEntry head = takeAllPropagations();

        // if halt() has called, the thread should not be put into a wait state        // instead this is just a safe way to make sure the queue is flushed before exiting the loop        if (head == null && currentState == DefaultAgenda.ExecutionState.FIRING_UNTIL_HALT) {
            propagationList.waitOnRest();
            head = takeAllPropagations();
        }
        return head;
    }
}


Notice that the FireAllRulesRestHandler must get the stateMachineLock while it does final takeAll, before it can know it's truly safe to return. This is due to timers which may be placed onto the queue, that need immediate firing. If engine was to return, the timer would not fire straight away - this is what we refer to as a "gap" in behaviour, that is now avoided.

The FireUntilHalt gets a lock on the propagation queue, because as well as doing a takeAll it must perform the null check and the wait operation, all atomically. Again if the null check was not within the sync point, we'd end up with another potential gap in behaviour, that is now avoided.

The final part of the puzzle is executeTask. This allows async operations to happen, typically a timer task, in an optimal way. If the engine is already running, due to FireAllRules or FireUntilHalt, then simply submit the task to the queue and let the current running thread handle it. If not then enter the EXECUTING_TASK state and execute it within the current thread.
@Overridepublic void executeTask( ExecutableEntry executable ) {
    synchronized (stateMachineLock) {
        // state is never changed outside of a sync block, so this is safe.        if (isFiring()) {
            executable.enqueue();
            return;
        } else if (currentState != ExecutionState.EXECUTING_TASK) {
            waitAndEnterExecutionState( ExecutionState.EXECUTING_TASK );
        }
    }

    try {
        executable.execute();
    } finally {
        immediateHalt();
    }
}

I should add that halt() is now submitted as a command, and evaluated as part of the standard queue drain. When executing, it will changing the engine into a HALTING, inside of a sync block. This will allow the outer loop to exit:
public void halt() {
    synchronized (stateMachineLock) {
        if (currentState.isFiring()) {
            setCurrentState( ExecutionState.HALTING );
        }
    }
}

So we now have really robust code for handling User, Timer and Engine thread interactions, in a way which has understandable behaviour. We've put a lot of effort into the cleanup, so that the code and behaviour can hopefully be understood by everyone.

There is one final part of the engine that would still be considered unsafe. This is where a user invokes a setter of an inserted fact on one thread, while the engine is running. This can obviously end in tears. What we plan to allow is for users to submit tasks to this queue, so they can be executed with the same thread as the running engine. This will allow users to submit pojo updates from another thread outside of engine, as tasks, to execute safely.

Share/Bookmark

Wednesday, November 18, 2015

Using a rective stream as a data source for Drools

A few months ago we started redesigning the Drools lowest level executable model and making it accessible to end user with a Java 8 API. To demonstrate the flexibility of this approach I tried to integrate it with a reactive stream and in particular to use this stream as a data source for Drools.

To show how this works I created a simple temperature server that provides a RxJava Observable emitting every second the temperature for a given town and terminates after 5 seconds. There is also a second factory method that allows to merge more of these Observables in order to have a single Observable that emits the temperature for more than one town at the same time.

public class TempServer {
    public static Observable<TempInfo> getFeed(String town) {
        return Observable.create(subscriber ->
                                         Observable.interval(1, TimeUnit.SECONDS)
                                                   .subscribe(i -> {
                                                       if (i > 5) subscriber.onCompleted();
                                                       try {
                                                           subscriber.onNext(TempInfo.fetch(town));
                                                       } catch (Exception e) {
                                                           subscriber.onError(e);
                                                       }
                                                   }));
    }

    public static Observable<TempInfo> getFeeds(String... towns) {
        return Observable.merge(Arrays.stream(towns)
                                      .map(TempServer::getFeed)
                                      .collect(toList()));
    }
}

where the TempInfo.fetch method just returns a random temperature between -20 and 50 degrees

public TempInfo(String town, int temp) {
    this.town = town;
    this.temp = temp;
}

public static TempInfo fetch(String town) {
    return new TempInfo(town, random.nextInt(70) - 20);
}

Using an improved version of the Java 8 DSL presented in the former article I defined the following 2 rules:

Variable<TempInfo> temp = any( TempInfo.class );
Variable<Person> person = any( Person.class );

Rule r1 = rule("low temp")
        .view(
                subscribe(temp, "tempFeed"),
                expr(temp, t -> t.getTemp() < 0),
                input(person, "persons"),
                expr(person, temp, (p, t) -> p.getTown().equals(t.getTown()))
             )
        .then(on(person, temp)
                      .execute((p, t) -> System.out.println(p.getName() + " is freezing in " + p.getTown() + " - temp is " + t.getTemp())));

Rule r2 = rule("high temp")
        .view(
                subscribe(temp, "tempFeed"),
                expr(temp, t -> t.getTemp() > 30),
                input(person, "persons"),
                expr(person, temp, (p, t) -> p.getTown().equals(t.getTown()))
             )
        .then(on(person, temp)
                      .execute((p, t) -> System.out.println(p.getName() + " is sweating in " + p.getTown() + " - temp is " + t.getTemp())));

Here I'm using 2 different kinds of data sources: a passive one that can be considered a mere store of facts:


DataStore persons = storeOf(new Person("Mark", 37, "London"),
                            new Person("Edson", 35, "Toronto"),
                            new Person("Mario", 40, "Milano"));

that can be bound to a specific Drools KieSession with

bindDataSource(ksession, "persons", persons);

and a reactive one taken from the TempServer implemented above

Observable<TempInfo> tempFeed = TempServer.getFeeds( "Milano", "London", "Toronto" );

that can also be bound to the same KieSession in a similar way

bindRxObservable( ksession, "tempFeed", tempFeed );

Having done this you can fire those 2 rules and obtain an output like the following:

Mark is freezing in London - temp is -9
Edson is sweating in Toronto - temp is 42
Mario is sweating in Milano - temp is 42
Mario is sweating in Milano - temp is 49
Mark is freezing in London - temp is -17
Edson is sweating in Toronto - temp is 40
Edson is sweating in Toronto - temp is 47
Mario is freezing in Milano - temp is -14
Mark is freezing in London - temp is -8
Mark is freezing in London - temp is -17

The complete test case to run this example is available here.


Share/Bookmark

Tuesday, October 20, 2015

Installing KIE Server and Workbench on same server

syndicated from http://mswiderski.blogspot.co.uk/2015/10/installing-kie-server-and-workbench-on.html
----
A common requirement for installation on development machine is to run both KIE Workbench and KIE Server on same server to simplify execution environment and avoid any port offset configuration.

This article will explain all installation steps needed to make this happen on two most frequently used containers:

  • Wildfly 8.2.0.Final
  • Apache Tomcat 8

Download binaries

So let's get our hands dirty and play around with some installation steps. First make sure you download correct versions of workbench and KIE Server for the container you target.

Wildfly

Tomcat

Wildfly

Deploy applications

Copy downloaded files into WILDFLY_HOME/standalone/deployments, while copying rename them to simplify the context paths that will be used on application server:
  • rename kie-wb-distribution-wars-6.3.0.Final-wildfly8.war to kie-wb.war
  • rename kie-server-6.3.0.Final-ee7.war to kie-server.war

Configure your server

With Wildfly there is not much to setup as both transaction manager and persistence (including data source) is already preconfigured.

Configure users

  • create user in application realm 
    • name: kieserver 
    • password: kieserver1!
    • roles: kie-server
  • create user in application realm to logon to workbench
    • name: workbench 
    • password: workbench!
    • roles: admin, kie-server

Configure system properties

Following list of properties needs to be given to work smoothly for both workbench and KIE Server:
  • -Dorg.kie.server.id=wildfly-kieserver 
  • -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server 
  • -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller

Launching the server

best way is to add system properties into startup command when launching Wildfly server. Go to WILDFLY_HOME/bin and issue following command:

./standalone.sh --server-config=standalone-full.xml -Dorg.kie.server.id=wildfly-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller

Tomcat


Deploy applications

Copy downloaded files into TOMCAT_HOME/webapps, while copying rename them to simplify the context paths that will be used on application server:
  • rename kie-wb-distribution-wars-6.3.0.Final-tomcat7.war to kie-wb.war
  • rename kie-server-6.3.0.Final-webc.war to kie-server.war

Configure your server

  1. Copy following libraries into TOMCAT_HOME/lib
    1. btm-2.1.4
    2. btm-tomcat55-lifecycle-2.1.4
    3. h2-1.3.161
    4. jacc-1.0
    5. jta-1.1
    6. kie-tomcat-integration-6.3.0.Final
    7. slf4j-api-1.7.2
    8. slf4j-api-1.7.2
  2. Create Bitronix configuration files to enable JTA transaction manager
  • Create file 'btm-config.properties' under TOMCAT_HOME/conf with following content
bitronix.tm.serverId=tomcat-btm-node0
bitronix.tm.journal.disk.logPart1Filename=${btm.root}/work/btm1.tlog
bitronix.tm.journal.disk.logPart2Filename=${btm.root}/work/btm2.tlog
bitronix.tm.resource.configuration=${btm.root}/conf/resources.properties
  • Create file 'resources.properties' under TOMCAT_HOME/conf with following content
resource.ds1.className=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
resource.ds1.uniqueName=jdbc/jbpm
resource.ds1.minPoolSize=10
resource.ds1.maxPoolSize=20
resource.ds1.driverProperties.driverClassName=org.h2.Driver
resource.ds1.driverProperties.url=jdbc:h2:mem:jbpm
resource.ds1.driverProperties.user=sa
resource.ds1.driverProperties.password=
resource.ds1.allowLocalTransactions=true

Configure users

Create following users in tomcat-users.xml under TOMCAT_HOME/conf
  • create user
    • name: kieserver 
    • password: kieserver1!
    • roles: kie-server
  • create user to logon to workbench
    • name: workbench 
    • password: workbench!
    • roles: admin, kid-server
?
1
2
3
4
5
6
7
8
9
  "admin"/>
  "analyst"/>
  "user"/>
  "kie-server"/>
 
  "workbench" password="workbench1!" roles="admin,kie-server"/>
  "kieserver" password="kieserver1!" roles="kie-server"/> 

Configure system properties

Configure following system properties in file setenv.sh under TOMCAT_HOME/bin
-Dbtm.root=$CATALINA_HOME 
-Dorg.jbpm.cdi.bm=java:comp/env/BeanManager 
-Dbitronix.tm.configuration=$CATALINA_HOME/conf/btm-config.properties 
-Djbpm.tsr.jndi.lookup=java:comp/env/TransactionSynchronizationRegistry 
-Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-wb/WEB-INF/classes/login.config 
-Dorg.kie.server.persistence.ds=java:comp/env/jdbc/jbpm 
-Dorg.kie.server.persistence.tm=org.hibernate.service.jta.platform.internal.BitronixJtaPlatform 
-Dorg.kie.server.id=tomcat-kieserver 
-Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server 
-Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller

NOTE: Simple copy this into setenv.sh files to properly setup KIE Server and Workbench on Tomcat:
CATALINA_OPTS="-Xmx512M -XX:MaxPermSize=512m -Dbtm.root=$CATALINA_HOME -Dorg.jbpm.cdi.bm=java:comp/env/BeanManager -Dbitronix.tm.configuration=$CATALINA_HOME/conf/btm-config.properties -Djbpm.tsr.jndi.lookup=java:comp/env/TransactionSynchronizationRegistry -Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-wb/WEB-INF/classes/login.config -Dorg.kie.server.persistence.ds=java:comp/env/jdbc/jbpm -Dorg.kie.server.persistence.tm=org.hibernate.service.jta.platform.internal.BitronixJtaPlatform -Dorg.kie.server.id=tomcat-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller"

Launching the server

Go to TOMCAT_HOME/bin and issue following command:
./startup.sh

Going beyond default setup

Disabling KIE Server extensions

And that's all to do to setup both KIE Server and Workbench on single server instance (either Wildfly or Tomcat). This article focused on fully featured KIE server installation meaning both BRM (rules) and BPM (processes, tasks) capabilities. Although KIE Server can be configured to serve only subset of the capabilities - e.g. only BRM or only BPM.

To do so one can configure KIE Server with system properties to disable extensions (BRM or BPM)

Wildfly:
add following system property to startup command:
  • disable BRM: -Dorg.drools.server.ext.disabled=true
  • disable BPM: -Dorg.jbpm.server.ext.disabled=true
So the startup command would look like this:
./standalone.sh --server-config=standalone-full.xml -Dorg.kie.server.id=wildfly-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller -Dorg.jbpm.server.ext.disabled=true

Tomcat
add following system property to setenv.sh script (must be still part of CATALINA_OPTS configuration):
  • disable BRM: -Dorg.drools.server.ext.disabled=true
  • disable BPM: -Dorg.jbpm.server.ext.disabled=true
Complete content of setenv.sh is as follows:
CATALINA_OPTS="-Xmx512M -XX:MaxPermSize=512m -Dbtm.root=$CATALINA_HOME -Dorg.jbpm.cdi.bm=java:comp/env/BeanManager -Dbitronix.tm.configuration=$CATALINA_HOME/conf/btm-config.properties -Djbpm.tsr.jndi.lookup=java:comp/env/TransactionSynchronizationRegistry -Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-wb/WEB-INF/classes/login.config -Dorg.kie.server.persistence.ds=java:comp/env/jdbc/jbpm -Dorg.kie.server.persistence.tm=org.hibernate.service.jta.platform.internal.BitronixJtaPlatform -Dorg.kie.server.id=tomcat-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller -Dorg.jbpm.server.ext.disabled=true"

Changing data base and persistence settings

Since by default persistence uses just in memory data base (H2) it is good enough for first tryouts or demos but not for real usage. So to be able to change persistence settings following needs to be done:

KIE Workbench on Wildfly
Modify data source configuration in Wildfly - either via manual editing of standalone-full.xml file or using tools such as Wildfly CLI. See Wildfly documentation on how to define data sources.

  • Next modify persistence.xml that resides inside workbench war file. Extract the kie-wb.war file into directory with same name and in same location (WILDFLY_HOME/standalone/deployments). 
  • Then navigate to kie-wb.war/WEB-INF/classes/META-INF
  • Edit persistence.xml file and change following elements
    • jta-data-source to point to the newly created data source (JNDI name) for your data base
    • hibernate.dialect to hibernate supported dialect name for you data base
KIE Server on Wildfly
there is no need to do any changes to the application (the war file) as the persistence can be reconfigured via system properties. Set following system properties at the end of server startup command

  • -Dorg.kie.server.persistence.ds=java:jboss/datasources/jbpmDS
  • -Dorg.kie.server.persistence.dialect=org.hibernate.dialect.MySQL5Dialect
Full command to start server will be:
./standalone.sh --server-config=standalone-full.xml -Dorg.kie.server.id=wildfly-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller -Dorg.kie.server.persistence.ds=java:jboss/datasources/jbpmDS 
-Dorg.kie.server.persistence.dialect=org.hibernate.dialect.MySQL5Dialect

KIE Workbench on Tomcat
To modify data source configuration in Tomcat you need to alter resources.properties (inside TOMCAT_HOME/conf) file that defines data base connection. For MySQL it could look like this:

resource.ds1.className=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
resource.ds1.uniqueName=jdbc/jbpmDS
resource.ds1.minPoolSize=0
resource.ds1.maxPoolSize=10
resource.ds1.driverProperties.user=guest
resource.ds1.driverProperties.password=guest
resource.ds1.driverProperties.URL=jdbc:mysql://localhost:3306/jbpm
resource.ds1.allowLocalTransactions=true

Make sure you're copy mysql JDBC driver into TOMCAT_HOME/lib otherwise it won't provide proper connection handling.
  • Next modify persistence.xml that resides inside workbench war file. Extract the kie-wb.war file into directory with same name and in same location (TOMCAT_HOME/webapps). 
  • Then navigate to kie-wb.war/WEB-INF/classes/META-INF
  • Edit persistence.xml file and change following elements
    • jta-data-source to point to the newly created data source (JNDI name) for your data base
    • hibernate.dialect to hibernate supported dialect name for you data base
KIE Server on Tomcat
there is no need to do any changes to the application (the war file) as the persistence can be reconfigured via system properties. Set or modify (as data source is already defined there) following system properties in setenv.sh script inside TOMCAT_HOME/bin

  • -Dorg.kie.server.persistence.ds=java:comp/env/jdbc//jbpmDS
  • -Dorg.kie.server.persistence.dialect=org.hibernate.dialect.MySQL5Dialect
Complete content of the setenv.sh script is as follows:
CATALINA_OPTS="-Xmx512M -XX:MaxPermSize=512m -Dbtm.root=$CATALINA_HOME -Dorg.jbpm.cdi.bm=java:comp/env/BeanManager -Dbitronix.tm.configuration=$CATALINA_HOME/conf/btm-config.properties -Djbpm.tsr.jndi.lookup=java:comp/env/TransactionSynchronizationRegistry -Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-wb/WEB-INF/classes/login.config -Dorg.kie.server.persistence.ds=java:comp/env/jdbc/jbpmDS -Dorg.kie.server.persistence.tm=org.hibernate.service.jta.platform.internal.BitronixJtaPlatform 
-Dorg.kie.server.persistence.dialect=org.hibernate.dialect.MySQL5Dialect
-Dorg.kie.server.id=tomcat-kieserver -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/kie-wb/rest/controller"

Note that KIE Server persistence is required only for BPM capability so if you disable it you can skip any KIE server related persistence changes.

And that would be it. Hopefully this article will help with installation of KIE Workbench and Server on single application server. 

Have fun and comments more than welcome.

Share/Bookmark