Showing posts with label jbpm-runtime_manager. Show all posts
Showing posts with label jbpm-runtime_manager. Show all posts

2014/11/21

Cross framework services in jBPM 6.2

jBPM version 6 comes with quite a few improvements that allow developers build their own systems with BPM and BRM capabilities just to name few:
  • jar based deployment units - kjar
  • deployment descriptors for kjars
  • runtime manager with predefined runtime strategies
  • runtime engine with configured components
    • KieSession
    • TaskService
    • AuditService (whenever persistence is used)
While these are certainly bringing lots of improvements in embedability of jBPM into custom application they do come with some challenges in terms of how they can be consumed. Several pieces need to come along to have it properly supported and reliably running:
  • favor use of RuntimeManager and RuntimeEngine whenever performing work instead of using cached ksession and task service instance
  • Cache only RuntimeManager not RuntimeEngine or runtime engine's components
  • Creating runtime manger requires configuration of various components via runtime environment - way more simplified compared to version 5 but still...
  • On request basis always get new RuntimeEngine with valid context, work with ksession, task service and then dispose runtime engine
All these (and more) were sometimes forgotten or assumed will be done automatically while they weren't. And even more issues could arise when working with different frameworks - CDI, ejb, spring, etc.

Rise of jBPM services (redesigned in version 6.2)

Those who are familiar with jBPM console (aka kie workbench) code base might already be aware of some services that were present from version 6.0 and through 6.1. Module that encapsulated these services is jbpm-kie-services. This module was purely written with CDI in mind and all services within it were CDI based. There was additional code to ease consumption of them without CDI but that did not work well - mainly because as soon as the code was running in CDI container (JEE6 application servers) CDI got into the way and usually caused issues due to unsatisfied dependencies.

So that (obviously not only that :)) brought us to a highly motivated decision - to revisit the design of these services to allow more developer friendly implementation that can be consumed regardless of what framework one is using.

So with the design we came up with following structure:
  • jbpm-services-api - contains only api classes and interfaces
  • jbpm-kie-services - rewritten code implementation of services api - pure java, no framework dependencies
  • jbpm-services-cdi - CDI wrapper on top of core services implementation
  • jbpm-services-ejb-api - extension to services api for ejb needs
  • jbpm-services-ejb-impl - EJB wrappers on top of core services implementation
  • jbpm-services-ejb-client - EJB remote client implementation - currently only for JBoss
Service modules are grouped with its framework dependencies, so developers are free to choose which one is suitable for them and use only that. No more issues with CDI if I don't want to use CDI :)

Let's now move into the services world and see what we have there and how they can be used. First of all they are grouped by their capabilities:

DeploymentService

As the name suggest, its primary responsibility is to deploy (and undeploy) units. Deployment unit is kjar that brings in business assets (like processes, rules, forms, data model) for execution. Deployment services allow to query it to get hold of available deployment units and even their RuntimeManager instances.

NOTE: there are some restrictions on EJB remote client to do not expose RuntimeManager as it won't make any sense on client side (after it was serialized).

So typical use case for this service is to provide dynamic behavior into your system so multiple kjars can be active at the same time and be executed simultaneously.
// create deployment unit by giving GAV
DeploymentUnit deploymentUnit = new KModuleDeploymentUnit(GROUP_ID, ARTIFACT_ID, VERSION);
// deploy        
deploymentService.deploy(deploymentUnit);
// retrieve deployed unit        
DeployedUnit deployed = deploymentService.getDeployedUnit(deploymentUnit.getIdentifier());
// get runtime manager
RuntimeManager manager = deployed.getRuntimeManager();

Deployment service interface and its methods can be found here.

DefinitionService

Upon deployment, every process definition is scanned using definition service that parses the process and extracts valuable information out of it. These information can provide valuable input to the system to inform users about what is expected. Definition service provides information about:
  • process definition - id, name, description
  • process variables - name and type
  • reusable subprocesses used in the process (if any)
  • service tasks (domain specific activities)
  • user tasks including assignment information
  • task data input and output information
So definition service can be seen as sort of supporting service that provides quite a few information about process definition that are extracted directly from BPMN2.

String processId = "org.jbpm.writedocument";
        
Collection<UserTaskDefinition> processTasks = 
bpmn2Service.getTasksDefinitions(deploymentUnit.getIdentifier(), processId);
        
Map<String, String> processData = 
bpmn2Service.getProcessVariables(deploymentUnit.getIdentifier(), processId);
        
Map<String, String> taskInputMappings = 
bpmn2Service.getTaskInputMappings(deploymentUnit.getIdentifier(), processId, "Write a Document" );

While it usually is used with combination of other services (like deployment service) it can be used standalone as well to get details about process definition that do not come from kjar. This can be achieved by using  buildProcessDefinition method of definition service.

Definition service interface can be found here.

ProcessService

Process service is the one that usually is of the most interest. Once the deployment and definition service was already used to feed the system with something that can be executed. Process service provides access to execution environment that allows:

  • start new process instance
  • work with existing one - signal, get details of it, get variables, etc
  • work with work items
At the same time process service is a command executor so it allows to execute commands (essentially on ksession) to extend its capabilities.
Important to note is that process service is focused on runtime operations so use it whenever there is a need to alter (signal, change variables, etc) process instance and not for read operations like show available process instances by looping though given list and invoking getProcessInstance method. For that there is dedicated runtime data service that is described below.

An example on how to deploy and run process can be done as follows:
KModuleDeploymentUnit deploymentUnit = new KModuleDeploymentUnit(GROUP_ID, ARTIFACT_ID, VERSION);
        
deploymentService.deploy(deploymentUnit);

long processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "customtask");
     
ProcessInstance pi = processService.getProcessInstance(processInstanceId);     

As you can see start process expects deploymentId as first argument. This is extremely powerful to enable service to easily work with various deployments, even with same processes but coming from different versions - kjar versions.

Process service interface can be found here.

RuntimeDataService

Runtime data service as name suggests, deals with all that refers to runtime information:

  • started process instances
  • executed node instances
  • available user tasks 
  • and more
Use this service as main source of information whenever building list based UI - to show process definitions, process instances, tasks for given user, etc. This service was designed to be as efficient as possible and still provide all required information.

Some examples:
1. get all process definitions
Collection definitions = runtimeDataService.getProcesses(new QueryContext());


2. get active process instances

Collection instances = runtimeDataService.getProcessInstances(new QueryContext());
3. get active nodes for given process instance

Collection instances = runtimeDataService.getProcessInstanceHistoryActive(processInstanceId, new QueryContext());
4. get tasks assigned to john

List taskSummaries = runtimeDataService.getTasksAssignedAsPotentialOwner("john", new QueryFilter(0, 10));

There are two important arguments that the runtime data service operations supports:

  • QueryContext
  • QueryFilter - extension of QueryContext
These provide capabilities for efficient management result set like pagination, sorting and ordering (QueryContext). Moreover additional filtering can be applied to task queries to provide more advanced capabilities when searching for user tasks.

Runtime data service interface can be found here.

UserTaskService

User task service covers complete life cycle of individual task so it can be managed from start to end. It explicitly eliminates queries from it to provide scoped execution and moves all query operations into runtime data service.
Besides lifecycle operations user task service allows:
  • modification of selected properties
  • access to task variables
  • access to task attachments
  • access to task comments
On top of that user task service is a command executor as well that allows to execute custom task commands.

Complete example with start process and complete user task done by services:
  
long processInstanceId = 
processService.startProcess(deployUnit.getIdentifier(), "org.jbpm.writedocument");

List<Long> taskIds = 
runtimeDataService.getTasksByProcessInstanceId(processInstanceId);

Long taskId = taskIds.get(0);
     
userTaskService.start(taskId, "john");
UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId);
     
Map<String, Object> results = new HashMap<String, Object>();
results.put("Result", "some document data");
userTaskService.complete(taskId, "john", results);

That concludes quick run through services that jBPM 6.2 will provide. Although there is one important information left to be mentioned. Article name says it's cross framework services ... so let's see various in action:

  • CDI - services with CDI wrappers are heavily used (and by that tested) in jbpm console - kie-wb. Entire execution server that comes in jbpm console is utilizing jbpm services over its CDI wrapper.
  • Ejb - jBPM provides a sample ejb based execution server (currently without UI) that can be downloaded and deployed to JBoss - it was tested with JBoss but might work on other containers too - it's built with jbpm-services-ejb-impl module
  • Spring - a sample application has been developed to illustrate how to use jbpm services in spring based application

The most important thing when working with services is that there is no more need to create your own implementations of Process service that simply wraps runtime manager, runtime engine, ksession usage. That is already there. It can be nicely seen in the sample spring application that can be found here. And actually you can try to use that as well on OpenShift Online instance here.
Go to application on Openshift Online
 Just logon with:

  • john/john1
  • mary/mary1
If there is no deployments available deploy one by specifying following string:
org.jbpm:HR:1.0
this is the only jar available on that instance.

And you'll be able to see it running. If you would like to play around with it on you own, just clone the github repo build it and deploy it. It runs out of the box on JBoss EAP 6. For tomcat and wildfly deployments see readme file in github.

That concludes this article and as usual comments and ideas for improvements are more than welcome.

As a side note, all these various framework applications built on top of jBPM services can simply work together without additional configuration just by configuring to be backed by the same data base. That means:
  • deployments performed on any of the application will be available to all applications automatically
  • all process instances and tasks can be seen and worked on via every application
that provides us with truly cross framework integration with guarantee that they all work in the same way - consistency is the most important when dealing with BPM :)


2014/01/20

jBPM 6 with spring

As some of you might noticed jBPM got quite few improvements for version 6.0, to just name few:

  • RuntimeManager
  • enhanced timer service
  • new deployment model - based on kjar and maven
  • brand new tooling 
  • see release notes for more
there is (as always) still room for improvements. After 6.0 went out, we started to look at how we could ease the usage of jBPM in Spring based applications on top of the new API. Lots of the API is now based on the concept of fluent API which is not really Spring friendly.
Before we dive into details of the API and how it can be used in Spring let's look at possible usage scenarios that users might be interested in:

  • Self managed process engine
This is the standard (and the simplest) way to get up and running with jBPM in your application. You only configure it once and run as part of the application. With the RuntimeManager usage, both process engine and task service will be managed in complete synchronization, meaning there is no need from end user to deal with "plumbing" code to make these two work together. 
  • Shared task service
There could be a need in certain situations, that a single instance of a TaskService is used. This approach give more flexibility in configuring the task service instance as it's not behind RuntimeManager. Once configured it's then used by the RuntimeManager when requested. RuntimeManager in such situation will not create new instances of task service as it's done with self managed process engine approach.

To provide spring based way of setting up jBPM, few factory beans where added:

org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean


Factory responsible for producing instances of RuntimeEnvironment that are consumed by RuntimeManager upon creation. It allows to create following types of RuntimeEnvironment (that mainly means what is configured by default):
  • DEFAULT - default (most common) configuration for RuntimeManager
  • EMPTY - completely empty environment to be manually populated
  • DEFAULT_IN_MEMORY - same as DEFAULT but without persistence of the runtime engine
  • DEFAULT_KJAR - same as DEFAULT but knowledge asset are taken from KJAR identified by releaseid or GAV
  • DEFAULT_KJAR_CL - build directly from classpath that consists kmodule.xml descriptor
Mandatory properties depends on the selected type but knowledge information must be given for all types. That means that one of the following must be provided:
  • knowledgeBase
  • assets
  • releaseId
  • groupId, artifactId, version
Next for DEFAULT, DEFAULT_KJAR, DEFAULT_KJAR_CL persistence needs to be configured:
  • entity manager factory
  • transaction manager
Transaction Manager must be Spring transaction manager as based on its presence entire persistence and transaction support is configured.  Optionally EntityManager can be provided to be used instead of always creating new one from EntityManagerFactory - e.g. when using shared entity manager from Spring. All other properties are optional and are meant to override the default given by type of the environment selected.

org.kie.spring.factorybeans.RuntimeManagerFactoryBean

FactoryBean responsible for creation of RuntimeManager instances of given type based on provided runtimeEnvironment. Supported types:
  • SINGLETON
  • PER_REQUEST
  • PER_PROCESS_INSTANCE
where default is SINGLETON when no type is specified.  Every runtime manager must be uniquely identified thus identifier is a mandatory property. All instances created by this factory are cached to be able to properly dispose them using destroy method (close()).

org.kie.spring.factorybeans.TaskServiceFactoryBean

Creates instance of TaskService based on given properties. Following are mandatory properties that must be provided:
  • entity manager factory
  • transaction manager
Transaction Manager must be Spring transaction manager as based on its presence entire persistence and transaction support is configured. Optionally EntityManager can be provided to be used instead of always creating new one from EntityManagerFactory - e.g. when using shared entity manager from Spring. In addition to above there are optional properties that can be set on task service instance:
  • userGroupCallback - implementation of UserGroupCallback to be used, defaults to MVELUserGroupCallbackImpl
  • userInfo - implementation of UserInfo to be used, defaults to DefaultUserInfo
  • listener - list of TaskLifeCycleEventListener that will be notified upon various operations on tasks
This factory creates single instance of task service only as it's intended to be shared across all other beans in the system.


Now we know what components we are going to use, so it's time to look at how we could actually configure our spring application to take advantage on jBPM version 6. We start with the simple self managed approach where we configure single runtime manager with inline resources (processes) added.

1. First we setup entity manager factory and transaction manager:

  <bean id="jbpmEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="org.jbpm.persistence.spring.jta"/>
  </bean>

  <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
  </bean>

  <bean id="BitronixTransactionManager" factory-method="getTransactionManager"
        class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown" />
  
  <bean id="jbpmTxManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="BitronixTransactionManager" />
    <property name="userTransaction" ref="BitronixTransactionManager" />
  </bean>
with this we have ready persistence configuration that gives us:
  • JTA transaction manager (backed by bitronix - for unit tests or servlet containers)
  • entity manager factory for persistence unit named org.jbpm.persistence.spring.jta
2. Next we configure resource that we are going to use - business process

<bean id="process" factory-method="newClassPathResource" class="org.kie.internal.io.ResourceFactory">
  <constructor-arg>
    <value>jbpm/processes/sample.bpmn</value>
  </constructor-arg>
</bean>
this configures single process that will be available for execution - sample.bpmn that will be taken from class path. This is the simplest way to get your processes included when trying out jbpm.

3. Then we configure RuntimeEnvironment with our infrastructure (entity manager, transaction manager, resources)


<bean id="runtimeEnvironment" class="org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean">
  <property name="type" value="DEFAULT"/>
  <property name="entityManagerFactory" ref="jbpmEMF"/>
  <property name="transactionManager" ref="jbpmTxManager"/>
  <property name="assets">
    <map>
      <entry key-ref="process"><util:constant static-field="org.kie.api.io.ResourceType.BPMN2"/></entry>
    </map>
  </property>
</bean>
that gives us default runtime environment ready to be used to create instance of a RuntimeManager.

4. And finally we create RuntimeManager with the environment we just setup

<bean id="runtimeManager" class="org.kie.spring.factorybeans.RuntimeManagerFactoryBean" destroy-method="close">
  <property name="identifier" value="spring-rm"/>
  <property name="runtimeEnvironment" ref="runtimeEnvironment"/>
</bean>

with just four steps you are ready to execute your processes with Spring and jBPM 6, utilizing EntityManagerFactory and JTA transaction manager.

As an optional step, especially useful when testing you can create AuditLogService to get history information of your process executions.


<bean id="logService" class="org.jbpm.process.audit.JPAAuditLogService">
  <constructor-arg>
    <ref bean="jbpmEMF"/>
  </constructor-arg>
</bean>

Complete spring configuration file can be found here.

This is just one configuration setup that jBPM 6 supports - JTA transaction manager and EntityManagerFactory, others are:
  • JTA and SharedEntityManager
  • Local Persistence Unit and EntityManagerFactory
  • Local Persistence Unit and SharedEntityManager
What is important to note here is that there is no need to setup TaskService at all, some part of it like user group callback, can be configured via RuntimeEnvironment but the whole setup is done automatically by RuntimeManager. No need to worry about that.

Although if you need more control over TaskService instance you can set it up yourself and let RuntimeManager use it instead of creating its own instances.

To do so, you start the same as for self managed process engine case, follow step 1 and 2. Next we configure task service

<bean id="taskService" class="org.kie.spring.factorybeans.TaskServiceFactoryBean" destroy-method="close">
    <property name="entityManagerFactory" ref="jbpmEMF"/>
    <property name="transactionManager" ref="jbpmTxManager"/>
    <property name="listeners">
      <list>
        <bean class="org.jbpm.services.task.audit.JPATaskLifeCycleEventListener" />
      </list>
    </property>
  </bean>
with that we add an extra task life cycle listener to save all task operations as log entires.

Then, step 3 needs to be slightly enhanced to set task service instance in the runtime environment so RuntimeManager can make use of it


<bean id="runtimeEnvironment" class="org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean">
  <property name="type" value="DEFAULT"/>
  <property name="entityManagerFactory" ref="jbpmEMF"/>
  <property name="transactionManager" ref="jbpmTxManager"/>
  <property name="assets">
    <map>
      <entry key-ref="process"><util:constant static-field="org.kie.api.io.ResourceType.BPMN2"/></entry>
    </map>
   </property>
   <property name="taskService" ref="taskService"/>
 </bean>
that will disable task service creation by RuntimeManager and always use this single shared instance.
Step 4 (creating RuntimeManager) is exactly the same.

Look at the example configuration files and test cases for more details on how they are utilized.

Please also note that factory beans for spring integration are currently scheduled to be released with 6.1.0 version of jBPM but I would like to encourage you to give it a try before so in case something is not working or missing we will have time to fix it and let it out with 6.1.0.Final. So all hands on board and let's spring it :)

2013/09/02

jBPM6 samples with RuntimeManager

jBPM6 introduces new module - jbpm-runtime-manager - that aims at significantly simplify management of:

  • KnowledgeBase (KieBase)
  • KnowledgeSession (KieSession)
Moreover it allows to use predefined strategies for handling knowledge sessions and its relation to process instance. By default jBPM6 comes with three strategies:
  • Singleton - single knowledge session that will execute all process instances
  • Per Request - every request (which is in fact call to getRuntimeEngine) will get new knowledge session
  • Per Process Instance - every process instance will have its dedicated knowledge session for the entire life time
To make use of the strategy it's enough to create proper type of RuntimeManager. jBPM6 allows to obtain instance of the RuntimeManager in various ways, this article will provide hands on information on how it can be achieved. 
With jBPM6 a whole new way of building application has been provided - Context and Dependency Injection is now available for users to build application and bring the power of jBPM to next level. Obviously CDI is not the only way to make use of jBPM - the regular API based approach is still available and fully functional.

CDI integration

jBPM6 tooling (like jbpm console or kie-wb) is built on CDI and thanks to that set of services has been provided to ease the development for custom applications that are based on CDI. These services are bundled as part of jbpm-kie-services and provides compact solution to most of the required operations to put BPM into your application:
  • deployment service - deploys and undeploys units (kjars) into the process engine
  • runtime service - gives access to state of the process engine, like retrieve process definitions, process instances, history log, etc
  • bpmn2 data service - gives access to details of the process definition taken from BPMN2 xml
  • form provider service - gives access to forms for processes and tasks
So whenever custom application is built with CDI these services are recommended way to go to get most of the power of CDI and jBPM. Moreover it's the safest way too as it is used in jBPM tooling so it got fair amount of testing to secure it does what is expected.

Using jbpm-kie-services is not a mandatory to be able to use jBPM6 in CDI environment but it does have some advantages:
- allow to maintain multiple RuntimeManagers within single execution environment
- allow independent deploy and undeploy of units (kjar) without server/application restart
- allow to select different strategies for different units

See jbpm-sample-cdi-services project for details.

while these are all appealing add-ons they are not always needed, especially if application requires only single RuntimeManager instance to be included in the application. If that's the case we can let CDI container to create the RuntimeManager instance for us. That is considered second approach to CDI integration where only single instance of RuntimeManager is active and it's managed completely by the CDI container. Application needs to provide environment that RuntimeManager will be based on. 

See jbpm-sample-cdi project for details.

API approach

Last but not least is the regular API based approach to jBPM6 and RuntimeManager. It expects to be built by the application and in fact provides all configuration options. Moreover this is the simplest way to extend the functionality of RuntimeManager that comes out of the box.

See jbpm-sample project for details.

This article is just an introduction to the way jBPM6 and RuntimeManager can be used. More detailed articles will follow to provide in-depth information on every option given here (cdi with services, pure cdi, api).

If you have any aspects that you would like to see in next articles (regarding runtime manager and CDI) just drop a comment here and I'll do by best to include them.