Commons BPMN Library
Name | |
---|---|
Version | 1.0.0 |
Description |
|
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:
getting the ProcessHandle(s) of the instance(s) in question
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 | id: String | Returns the id of the created process |
getProcessHandle | processName: 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 | processes: Array of Process | Returns an array with process instances matching the query |
queryProcessesFiltered | processName: String | 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 | 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 | 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 | 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 | 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 | 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 | self: ProcessQuery | queries processes' "creation" attribute |
updated{OnOrAfter,OnOrBefore,Between} | onOrAfter: DateTime | 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 | 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.

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:

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

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):

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:

with the following implementation of the two mapping operations:

