Skip to main content
Skip table of contents

Commons BPMN Library

Name

⬇️ libCommonsBpmn

Version

1.0.0

Description

  • intra and inter BPMN communication

  • simulation of persistent state adapter functionality by using Runtime and process REST ports

While the Designer allows us to model BPMNs that are internally translated and compiled to Persistent State Classes, there is currently no such thing as the Persistent State Adapter to query process instances, get object copies, send signals, etc. This library makes use of the canonical REST ports (xUML Runtime API and Process REST API) that offer these operations and provides similar functionality.

The ProcessAdapter is the equivalent of the PStateAdapter, allowing you to create process instances, send messages, and query existing instances. The "getObjectCopy(handle)" functionality is also available, although the result will be given provided as JSON that you will have to deserialize yourself into a class that features all the attributes you defined as being "persisted".
The RemoteProcessAdapter provides equivalent functionality to interact with PStates maintained by remote service instances (practical use cases for this will be few, if any).

The library is just a convenience layer on top of the REST ports that get automatically created with every BPMN you design and deploy. These REST interfaces are generic by nature, and their structure derives from the names of the process, its states, and signals. This library makes use of this knowledge (and bears the risk of braking in case the current naming scheme used by compiler and runtime changes). Everything you find in this library can also be achieved by importing your own REST interface and call the relevant operations.

The most common use cases are the following scenarios:

  • you want to know how many process instances are currently running, maybe restricting your search to a specific BPMN task of interest

    • special case: how many of my processes are in "Error" state

  • you want to know whether there is an instance already running for a given key like orderNumber

  • you want to send signals or events to your process instances

  • you want to retrieve process instances including some or all of their persisted data

If you want to query BPMN process instances, based on their persisted attributes (e.g. orderNumber, or countryCode), be aware that this is possible but only for scalar values that you added to the instance list of your process. Adding scalar attributes to the instance list will turn them into "search keys" in the persistent state database, thereby being available for queries.

Another option is to use the operation queryProcessesFiltered(), where you can combine DB query with a scan on all matching objects. The operation calls back on a provided filter instance, feeding each retrieved instance as JSON. You will have to provide this filter and do the heavy lifting of deciding whether the JSON represents an instance you are interested in. The advantage here is that you can include external (read: complex) persisted attributes in the filter evaluation. And using JSON Path on the retrieved JSON objects can help as well.

User Tasks

The library provides no explicit operation to send user task messages (i.e. form data). That would be kind of pointless. If you want to be able to proceed from a user task without user input, you should model an additional boundary event on the user task with a (different) message type suitable for inter-process communication, and use sendBoundaryEventMessage() in these cases.

BPMN lane permissions are ignored

The operations provided herein (as well as the underlying REST ports) do not check for permissions of the executing user. I.e. if you provide a UI, which triggers sending of signals to a process that should be feasible for users with specific permissions only, these permissions won't be checked by these operations. If you want/need permissions to be checked, you have to take care of them yourself.

Overview

The ProcessAdapter provides all the operations you might be interested in. If you want to query your instances, use createInstance() on ProcessQuery and its convenience functions to build up the full query.

The library is aimed at talking to self, i.e. the processes defined in the model using the library. Hence there are two REST Aliases coming with the library:

  • RuntimeApi: for connecting to the xUML Runtime API available at runtime

  • ProcessApi: for connecting to the specific Processes' REST Service created (this is used solely to create new instances of processes, which is the one operation not available through the runtime API).

Set REST Alias ports for Bridge deployments

The library defines two RESTAlias instances, that will appear as settings on any deployed service using this library. They point to the "self" Runtime and Process APIs. If you deploy as container, the predefined ports align with generated ports for container deployments. However if you deploy onto Bridge, then you will probably not use ports 21111 and 11111 for your service, and you need to adapt these REST Aliases to point to the correct ports.

Don't confuse Process id with ProcessHandle id

  • ProcessHandle::id is an internal id that you see nowhere on any admin UI

  • Process::name is what you see as "id" in e.g. instance lists etc.

Therefore, in order to communicate with the persisted process, you have to get its handle first. Use getProcessHandle() if you have the visible id, or use getProcesses() which return an array of Process (Process inherits from ProcessHandle and can directly be used as input where a ProcessHandle is expected).

Following the legacy logic of the PState Adapter, the process of retrieving (a copy of) process instances with their persisted data consists of two steps:

  1. getting the ProcessHandle(s) of the instance(s) in question

  2. using the ProcessHandle to retrieve the ProcessCopy

The "copy" part of the naming indicates that what you can retrieve is just a read-only copy. Making changes on these copies will not affect the actual process. Process instances can be manipulated only by sending them messages (signals).

ProcessAdapter

Operation

Input

Output / Return

Comment

createProcess

processName: String
startEventName: String
startEventMessage: Any

id: String

Returns the id of the created process

getProcessHandle

processName: String
id: String

handle: ProcessHandle

Raises an exception when no such process instance can be found

getProcesses

processName: String

processes: Array of Process

Returns an array with all process instances

queryProcesses

processName: String
query: ProcessQuery

processes: Array of Process

Returns an array with process instances matching the query

queryProcessesFiltered

processName: String
query: ProcessQuery
filter: ProcessQueryFilter

processes: Array of Process

Like above, but additionally retrieves each process' copy as JSON and feeds it to the supplied filter.

This can be a powerful search feature in combination with Json Match

getProcessCopy

handle: ProcessHandle

copy: ProcessCopy

Returns a copy of the Process object with all generic attributes populated

getProcessCopyJson

handle: ProcessHandle
withExternals: Boolean

json: String

Returns the raw JSON of the Process data, with all attributes that you use in the "Persistent" parts of your model. If you define a class that inherits from ProcessCopy, and redefine those attributes on that class, you can call e.g. json.jsonToClass() to deserialize the JSON copy with all attributes you want to get.

sendBoundaryEventMessage

handle: ProcessHandle
eventName: String
message: Any

Feed the eventName as you defined it in the model, and an instance of the class you defined on that event:

In this example, eventName would be "NewValues", and message would be an instance of RandomValues class.

sendReceiveTaskMessage

handle: ProcessHandle
receiveTaskName: String
message: Any

Like above, but for sending the event signal expected by a receive task.

sendAbort

handle: ProcessHandle

Sends the "Abort" signal, telling the process to abort

sendError

handle: ProcessHandle
message: ErrorSignal

Sends the "Error" signal, telling the process to enter the error state (you have to provide the full error information)

sendRetry

handle: ProcessHandle

Sends the "Retry" signal, telling the process to retry from Error

bulkSendAbort

handles: array of ProcessHandle

bulk version of sendAbort

bulkSendRetry

handles: array of ProcessHandle

bulk version sendRetry

RemoteProcessAdapter

This class repeats (almost) all operations of the ProcessAdapter, but expecting an additional parameter of type RemoteProcessLocation, that specifies host an ports of the process to interact with. Dealing with remote processes by using this library should be an exception. The default would be to import the remote processes' REST port and use that instead. However, for closely coupled services sharing parts or all of their data model this might make sense.

ProcessQuery

Operation

Input

Output/Return

Comment

createInstance

instance: ProcessQuery

a static create() method for convenience

create{And,Or}Condition

condition: {And,Or}QueryCondition

create an instance of the desired complex query condition

createAttributeCondition

attribute: String
operator: String
value: String

condition: SimpleQueryCondition

create an instance to query search key attribute values

operator must match a QueryOperator enum value

value is always provided as String and is internally converted to the searched attributes type (Float, Integer, DateTime, Boolean)

created{OnOrAfter,OnOrBefore,Between}

onOrAfter: DateTime
onOrBefore: DateTime
sortDirection: String

self: ProcessQuery

queries processes' "creation" attribute

updated{OnOrAfter,OnOrBefore,Between}

onOrAfter: DateTime
onOrBefore: DateTime
ortDirection: String

self: ProcessQuery

queries processes' "lastUpdate" attribute

sortDirection must be one of ASC, DESC

orIn{Aborted,Error,Initialized}State

self: ProcessQuery

adds the corresponding state to the "states" query condition

orIn{Control,User,Receive}TaskState

taskName: String

self: ProcessQuery

adds the corresponding state to the "states" query condition

taskName is expected to be given exactly as it is displayed in the BPMN diagram

orInBpmnEventState

eventName: String

self: ProcessQuery

adds the corresponding state to the "states" query condition

eventName is expected to be given exactly as it is displayed in the BPMN diagram

thenSortBy

attribute: String
direction: String

self: ProcessQuery

adds a sort criterion to the "sort" condition array

attribute must be a search key

direction must be one of ASC, DESC

ProcessCopyFilter

You can provide an instance of a class that implements this interface to queryProcessesFiltered()

Operation

Input

Output/Return

Comment

isUsingExternals

true, if the filter inspects external attributes, false otherwise

if you filter implementation inspects external attributes, return true here

passes

processCopyJson: String

true, if the instance shall be included in the query result set, false otherwise

the query will call you with every processes' copy for you to decide if it shall be included in the result set

Example

The following simple example illustrates typical use cases of the library.

image-20240617-075823.png

Please note that a message event AlternateInputEvent is present on the user task, with a dedicated message type AlternateInput assigned to. This allows the process to be continued without an actual user submitting the assigned form, but send relevant input from somewhere else as well.

This already allows us to query for all instances of this process that are currently awaiting user input:

image-20240617-075653.png

Given a process retrieved this way, you can now send a message to it:

image-20240617-081701.png

All library operations that send messages expect an input of type Any, as it is unknown in advance what you are going to send. So it’s your responsibility to feed it a message of the expected type. The library will convert it to JSON internally and send it to the REST port. (This means that you won’t get an error when using the wrong message type, just that on the receiving end it might appear as an empty message, because whatever arrives there will be parsed back from JSON to a (different) model class, thereby ignoring all non-matching attributes.)

Finally, if you want to get all running processes with their data (for e.g. populating an alternative instance list), you can do this by first getting all process instances and then use these to retrieve process copies. For this we will need a structure representing our process, which can be derived from the library class ProcessCopy and that redefines all attributes that you use in any Persisted box within that process (you don’t have to define all attributes, but at least the ones you want to retrieve):

image-20240617-085250.png

Now you can proceed to fetch all instances of our InteractiveProcess, get their JSON representations (which btw is exactly what you can retrieve by hand for any persistent state instance using the admin UI when asking for Raw Data for Support), and deserialize these into that structure:

image-20240617-084501.png

with the following implementation of the two mapping operations:

image-20240617-084724.png
image-20240617-084852.png
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.