Skip to content

ifu-lobuntu/jbpm-cmmn

Repository files navigation

1. Overview

This project provides an extension of jBPM that enables CMMN runtime semantics. For more information about CMMN, see this short introduction. This document assumes a basic knowledge of CMMN and of jBPM.

This project only provides the runtime, back-end logic implementing the execution semantics of CMMN. It does not provide any user interface functionality, which is next on our list. It also does not provide any development tooling. For more information on our implementation plan, please read our implmementation notes. The rest of this document will give a quick overview of the CMMN semantics supported by this project.

2. CaseFileItem events

CMMN expects events to be generated by the persistence engine used to store data in the CaseFile. There are currently three supported persistence engines: JPA on top of Hibernate, and Jackrabbit's OCM on top of JCR, and pure JCR alone. The CaseFile is a hierarchical structure, with CaseFileItems that recursively contain child CaseFileItems. In order to follow this hierarchical structure, all three persistence approaches required their structures to follow the naming named in a specific way to in order for the events to reflect the correct CaseFileItem. These naming requirements will be discussed subsequently:

2.1.JPA/Hibernate

The domain model hierarchy implemented by developers in Java needs to reflect the CaseFileItem hierarchy defined in the CaseFile. This means that the property used to represent a child has to have the same name as the CaseFileItem in the CaseFile. The example domain that we used in our tests was defined in UML and both the CaseFile, the Java domain model as well as the JPA annotations were generated from a UML model using our Uml2Code facility. They are therefore guaranteed to be in sync with the CaseFile. However, this is not a requirement, it just eliminated the possibility of typos and made testing much easier. Events are delivered after the EntityManager is flushed. Currently this is done synchronously but it will be done asynchronously in the future. For the JPA integration to work correctly, users need to setup new JpaPlaceHolderStrategy and JpaCollectionPlaceHolderResolverStrategy in the jBPM Environment object, along with the JpaCasePersistence object. For an example on how to do this, see the AbstractCmmnTestCase.

2.2. Jackrabbit ObjectContentManager (OCM) on JCR

Since Case Management is often used in conjunction with content management, it made sense to support JCR, and since jBPM is written in Java we decided to support Jackrabbit's JCR-to-Java object mapping facility, OCM. As is the case with JPA, the OCM classes' Java properties need to reflect the referenced CaseFileItem's name. The current implementation also requires a very specific mapping of the Java domain model to the JCR content repository. The OCM best practice is to define a 'holder' node for properties whose content represents a collection. Once again, the example content repository structure we used was generated, along with the mapped OCM classes and CaseFile structure, from the same UML model as the JPA code, but again this is not a requirement. As with JPA, this implementation requires the OcmPlaceHolderStrategy and OcmCollectionPlaceHolderResolverStrategy in the jBPM Environment object, along with the OcmFactory object. For an example on how to do this, see the AbstractCmmnTestCase.

2.3. Pure JCR

There are some performance concerns regarding OCM, since it does not have a session based cache. For this reason, this implementation also provides pure JCR support for those that wish to bypass the OCM layer altogether. When using pure JCR, this implementation still requires a 'holder' node for one-to-many associations. As with OCM and JPA, this feature requires the JcrPlaceHolderStrategy and JcrCollectionPlaceHolderResolverStrategy along with the JcrObjectPersistenceFactory in the jBPM environment. Please note that this feature is currently still under development.

3. Subscribing to events generated by the persistence engines

There are two supported mechanisms for subscribing to events, and both are supported for JCR, JCR/OCM as well as JPA/Hibernate. Both have advantages and disadvantages.

3.1. Demarcated subscription

This mechanism requires developers to programmatically 'punctuate' when the persistence engine (JPA/JCR) should deliver events to subscriptions from a CaseInstance, and when it should stop doing this. Developers would typically activate the subscriptions before execution of of Task (Human, Case or Process) transitions (claim, close, cancel, resume, etc.), and then deactivate them afterwards. However, developers are free to demarcate subscription this way whenever logic is executed that could potentially generate events to the CMMN engine. The only requirement is that the developer would need to know which CaseInstances could be affected by the logic that is being executed.

This demarcation is done using the static methods on the DemarcatedSubscriptionContent class. Subscriptions are activated and stored temporarily in ThreadLocal variables, and need to be cleaned up afterwards. This mechanism has less performance overheads on the persistence engines, and allows subscriptions to be more fine-grained. However, events occurring outside of the demarcated subscription context will not be delivered to any CaseInstance.

3.2. Persistent subscription

This mechanism stores subscriptions to domain entities or JCR nodes as they become are activated during the execution of the case instance. Remember that the CaseFileItem bindings on Task output parameters imply that the CaseInstance is subscribing to the CaseFile, and these subscriptions are added when the Task becomes active, and are removed again when the tasks become inactive (completed/terminated). The subscriptions to caseFileItem transitions are stored against the object generating them. The only exceptions are CREATE and DELETE which are stored against the object representing the parent object of the created or deleted object in the domain model. This mechanism is very powerful, as it supports delivery of events from practically any context. However, it does introduce performance overheads, which can become particularly problematic when many case instances subscribe to the same object.

4. Expressions.

In CMMN, expressions are used to define PlanItem rules (e.g. automatic activation of tasks, completion requirement rules, repeat rules) and read/write of caseFileItems (parameter transformations, bindingRefinements). As with jBPM, this CMMN implementation supports expressions in CMMN defined in either Java or MVEL. In a concurrent project, we have also implemented support for OCL (Object Constraint Language), but this requires a UML model representing the Java domain model. The Java domain model can be generated from the UML model, but we are also working on the possibility of dynamically reversing the Java domain code to UML. This would obviate the need for the UML model altogether. As part of our support for pure JCR, we are also implementing XPath as an expression language, but the use of pure JCR, in other words no OCM, is a prerequisite for using XPath.

As is generally the case with existing jBPM functionality, expressions in all the various expression languages are dynamically compiled at runtime. Even the OCL and Xpath implementations generate the equivalent Java code which is then compiled at runtime using jBPM's built-in support for Java.

5. Tasks and Stages

CMMN defines several operations that a user, specifically the planning user, can perform on Tasks and Stages. All CMMN Tasks (HumanTask, CaseTask, ProcessTask) and Stages, even the CaseInstance itself therefore have Tasks in the jBPM service associated with them. These tasks are related to each other using jBPM's parentTask association, reflecting their relationship to each other in the Case itself. jBPM's standard TaskService is based on the WS Human Task specification. There is a lot of overlap between WS Human Tasks and CMMN, and users can expect operations such as for instance 'suspend' and 'resume' to map directly to their CMMN counterparts. However, there are certain transitions/operations that are required by the CMMN specification that do not map directly to equivalent WS Human Task transitions. For these we have implement custom TaskCommands that can be performed on the InternalTaskService, such as the ReenableTaskCommand, the ReactivateTaskCommand. For an example to use these new commands, have a look at the AbstractControllableLifecycleTest class. As with the other standard WS Human Task transitions, we have also implement associated BeforeXXX and AfterXXX eventss, which developers can subscribe to.

More significant though is the fact that all of these transitions generate events that are passed to the CaseInstance, and modelers can subscribe to these events. This is one of the most powerful features of CMMN, and it allows Case elements to react to each other as status changes occur. The following table presents the mapping of WS Human Task transitions to CMMN Task/Stage transitions. If there is a demand for it, we may implement thin wrapper around the standard jBPM task service to better reflect the terminology used in CMMN

WS Human Task transition CMMN Task/Stage transition
Activate Enable
Suspend Suspend
Resume Resume
Skip Disable
Start Manual Start
Exit Terminate
Fault Fault
Complete Complete
N/A Exit (Exit criteria become true)
N/A ParentSuspend
N/A ParentResume
N/A Start (automatically)
N/A Reenable
Forward Stop(Human Tasks only,not in spec)
Delegate Stop(Human Tasks only,not in spec)
Claim N/A
Release Stop(Human Tasks only,not in spec)

5.1. Roles in a Case.

Case Roles are assumed to be represented as Groups in the jBPM TaskIdentityService. Roles come into play in various places in the CMMN specification such as Roles:

  • authorized to do Planning in a Case
  • authorized to signal a UserEvent
  • assigned to HumanTasks

This implementation provides two built-in Roles in a Case, namely the Initiator and the CaseOwner. These can be passed to a new Case instance as parameters. At least one of these two needs to be provided, as it is used to do assignment of jBPM Tasks representing non HumanTasks (CaseTasks, Stages, ProcessTask and the CaseInstance itself). They are also used to determine businessAdministrators for HumanTasks. This principle enforces the paradigm of seeing work as having someone whose needs are fulfilled by a task, and someone who has an obligation to perform the task.

The mapping of Case Roles to groups is not entirely correct. A Case Role is more about the Role a user plays within the context of a specific case. However, the CMMN specification is deliberately very open-ended about how Roles map to humans. We plan to provide some interesting extensions to determine the best user to fulfill a specific Role in the Case.

5.2 Human Tasks

CMMN Human Tasks are implemented using the standard jBPM TaskService. Input parameters to Human Tasks are assigned using BindingRefinement expressions in one of the supported expression languages. These input parameters are automatically marshalled to the TaskService using the PlaceHolderStrategies associated with the chosen persistence engine. Assignment of Tasks to organizational entities is done by means of the performer Role specified on the task. The performer Role is assumed to be a group in the jBPM TaskIdentityService, and this group is added to the jBPM Task's potential owners. If a HumanTask has a ManualActivationRule that evaluates to false, this implies that the Task should be automatically assigned to a user and activated. The CaseInstance does its best to try to do this, such as finding the user who previously fulfilled the required Role in the Case.

5.3. Stages

Stages are similar to embedded subprocesses in jBPM - they represent containers for other elements. However, unlike embedded subprocesses in jBPM, Stages in CMMN require human intervention almost like a normal Human Tasks. This is quite a novel concept which may catch developers off guard. Once again, the ManualActivationRule could come into play. If a Stage requires manual activation, it will not automatically start when it is instantiated. It will require a user to manually start the jBPM task representing the Stage in the TaskService. The user would also be using this task to suspend, resume, and terminate a Stage. Keep in mind that all these operations will cascade down from the Stage instance being operated upon to its contained Tasks and Stages. CMMN does not specify which user should be allowed to interact with the stage in this way. In fact, there is other functionality that this Task also gives to the assigned user that are involved in the Planning actvity. During planning, this task will be used to perform operations such as explicit role and/or parameter assignment for specific tasks, or enabling/disabling Discretionary items applicable for that Stage. For this reason, this implementation first checks to see if the Stage has a PlanningTable associated with it, and it uses the Roles authorized to do this planning to determine who to assign the Stage's corresponding task to. If these are absent, it assigns the task to the CaseOwner.

5.4. CaseTasks/ProcessTasks

This implementation implements CaseTasks and ProcessTask using the same classes. These CMMN elements' corresponding jBPM Tasks are similarly assigned to the nearest authorized planning role. If ManualActivation is true, this task gets instantiated, but it does not call the specified process or task. Once again, this may surprise developers/users. However, it does give the user the opportunity to perform planning activities against this task, potentially even overriding the input parameters if necessary. These tasks also give the user the ability to suspend and resume the Case or process being called. This implementation is not interested in how the called process is implemented (BPMN/XPDL, BPEL), as long as it is available in the jBPM KieBase.

6. Milestones and Events

CMMN, like BPMN, also supports the concepts of Events and Milestones. In CMMN, these are relatively simple concepts. This implementation does not provide access to the TaskService to manipulate the state of these element directly, but it does allow the containing Stage or Case instance to be suspended/resumed/terminated, which in turn propagates the operation down to contained Milestones and Events.

6.1. Milestones.

Milestones represent significant points in a Case. Their occurrence can trigger reactions in other PlanItems

6.2. UserEvents

These are custom events, and they can be triggered in a Case using the standard ProcessRuntime.signalEvent(eventName, anyObject) method.

6.3. TimerEvents

Timer events are a bit more refined in CMMN than the UserEvents. When modelled on its own, a TimerEvent starts 'timing' the moment its parent Stage or Case instance becomes active. However, a TimerEvent could also have triggers associated with it, which delays its 'timing' until the trigger occurs. In this implementation, a TimerEvent's time expression can be expressed using either Java or MVEL. If the result is a Date, the timer is scheduled for that date. However, if the expression just evaluates to a string, the string is assumed to comply to the ISO-8601 date/duration/interval format.

7. Planning

Planning is the user activity in CMMN during which end users can decide which DiscretionaryItems to include in the Case. Once again, the CMMN specification is pretty open-ended with regard to exactly what else the user can do during the Planning activity. This implementation provides a PlanningService which defines the operations a user can perform during planning. The PlanningTest class give a broad overview of what can be done during planning. When commencing planning, the user can optionally indicate whether the Stage/Case Instance against which the planning is to be done should be suspended or not. Suspending the Stage is not a requirement per se, but it could reduce the risk of other user activity potentially interfering with the current state of the Stage. This implementation supports the follow actions during planning

  • Creation of DiscretionaryItem instances that do not have entry criteria
  • 'Activating' the entry criteria of DiscretionaryItems that do have entry criteria
  • Overriding the actualOwner of a Task
  • Overriding the input parameters of a Task.

In a concurrent project, we are implementing a couple of interesting extensions to the Planning process. For instance, the planning process can be extended to await confirmation from the performer of a Task whether the changed state of the task is acceptable. During planning, a task can also be instantiated based on an input that is offered by a potential participant, but which the participant still has to commit to. The Pavanecce platform will use these extensions to facilitate business collaborations that extend beyond organizational boundaries.

8. Future directions.

Firstly, we are hoping to get more collaborators on board for this CMMN implementation. If you are interested, please contact Ampie at ampie.private@gmail.com. This is open source software, we do not have any branding or ownership concerns. We are open to any form of collaboration, even if it entails absorbing this implementation, or a part of it in another open source project. We feel strongly about the future of CMMN, and would contribute to it as long as is possible for us.

Our next steps are to:

  1. Implement a task management user interface,and we are currently looking at either extending the Kie Workbench, or potentially integrate this implementation into the Jahia CMS product and extend its task management user interface.
  2. Implement a web based diagramming tool for CMMN. CMMN has a relatively simple notation, but we specifically want to support collaborative modeling in our planned diagramming tool, which complicates matters for us.

About

Proposed CMMN support for jBPM

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages