/ Development  

Reuse a BPM for different entity actions

Hi there AppWorks fans,

Welcome to a new installment of AppWorks tips.

An interesting pattern passed my daily job. The pattern comes from a typical usage of a BPM. Let’s say you have a great reusable BPM created, and you would like to trigger it from different entity actions! From what we all know (at this moment in time) is that the value of the rootEntityInstanceId in these situations will be different from the particular entity action. If you don’t know what I’m talking about? Continue reading for some examples below! This post will show you a pattern to keep your BPM reusable in context of the entity which triggers the BPM.

⚠ Spoiler alert ⚠
It’s all about an interesting xPath expression!


Let get right into it…

The post slices into several sections where we step-by-step show you how to build a pattern for BPM reusability in context of a different entity instance. Sounds hard…right? Well, if I can do it, you for sure can do it too! 😉

Building same use-case examples

Time to create an entity in the ‘entities’ folder of the project! Name it project and add a property prj_name (with label Name). Generate all the rest for fast prototyping! Update all the fancy stuff you would normally update to make it all nice in runtime. Like this:

reuse_001

For this entity we also add a simple lifecycle…Just with two states; let’s say Draft, and Final:

reuse_002

Publish it all, create an instance in runtime and see those tasks landing in your own inbox (as we know, the lifecycle starts on instance creation!)

First use-case (start via an action type of ‘Rule’ BB)

Create a new BPM…Simple and efficient with one activity. I just name it bpm_dummy (saved in the ‘bpms’ folder of the project) and publish it. Like this:

reuse_003

We make sure the BPM executes via the ‘Rule’ BB on the entity. Name it a_start_bpm of type ‘Action’ with a label Start BPM. Like this:

reuse_004

Do a publication (of the entity plus the BPM) and execute the action rule in runtime on the already created entity. Now have a look in the ‘Process Instance Manager’ artifact and open the message map of the BPM instance:

reuse_005

You get a modal popup with the available message nodes, but have a look at the bottom tab called ‘All View’ where we see a (cleaned) XML like this passing by:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<messagemap>
<faults />
<instanceProperties>
<processName>nl-bos/bpms/bpm_dummy</processName>
<rootInstance>0800270e-e5c1-a1ec-a4bc-6bd388042225</rootInstance>
<rootInstanceType>PROCESS</rootInstanceType>
<currentOwner>cn=awdev@awp,cn=organizational users,o=appworks_tips,cn=cordys,cn=defaultInst,o=mydomain.com</currentOwner>
<rootEntityInstanceId>0800270ee5c1a1eca26359f13d9e1388.1</rootEntityInstanceId>
</instanceProperties>
<project-id>
<Id>1</Id>
<ItemId>0800270ee5c1a1eca26359f13d9e1388.327681</ItemId>
<EntityType>0800270ee5c1a1eca26359f13d9e1388</EntityType>
</project-id>
</messagemap>

Notes on this XML:

  • The rootEntityInstanceId equals the ‘ItemId’ of the current entity instance from where the BPM started (our ‘project’ entity instance!)
  • We also see another interesting element passing by! The project-id element is the ‘input’ message for our BPM (which we didn’t define on the BPM itself!)
  • Keep in mind the value of rootInstanceType…’PROCESS’

FYI on xPath background! If you would like to grab the values of those elements we can do it with these xPath expressions:

  • instance:instanceProperties/instance:rootEntityInstanceId/text()
  • bpm:project-id/bpm:ItemId/text()

Time for another use-case (call the BPM from a lifecycle instance)

For this use-case we open the ‘Lifecycle’ BB of our ‘project’ entity. Here we’ll update the ‘Draft’ state with an extra BPM-activity which triggers the bpm_dummy BPM. Just like this:

reuse_006

Save the entity and publish it. In runtime, you need to create a new entity instance of ‘project’. After this, you can double-check the full message map in PIM like we did in the previous use-case. You will see a messagemap passing by like this (cleaned) version:

1
2
3
4
5
6
7
8
9
10
<messagemap>
<faults />
<instanceProperties>
<processName>nl-bos/bpms/bpm_dummy</processName>
<rootInstance>0800270e-e5c1-a1ec-a4bd-dfc7e7159d35</rootInstance>
<rootInstanceType>CASE</rootInstanceType>
<currentOwner>cn=awdev@awp,cn=organizational users,o=appworks_tips,cn=cordys,cn=defaultInst,o=mydomain.com</currentOwner>
<rootEntityInstanceId>0800270ee5c1a1eca26359f13d9e1388.327682</rootEntityInstanceId>
</instanceProperties>
</messagemap>

Notes on this XML:

  • The rootEntityInstanceId equals the ‘ItemId’ of the current entity instance from where the BPM as started (through the lifecycle!)
  • The rootInstanceType is our ‘Lifecycle’ (aka ‘CASE’…or in other terms “Case Model Management”)…You get it? correct?
  • We indeed miss the ‘input’ message like in the previous use-case!

The third use-case (call the BPM from the related task-entity “creation” event)

To implements this use-case, we open the related ‘LifecycleTask’ entity which we retrieved for free when we applied the ‘Lifecycle’ BB to the ‘project’ entity.

reuse_007

Once opened, you see it’s a full building blocks enriched entity. For our use-case implementation, we create a new event type of ‘Rule’ BB. Name it e_on_create_start_bpm, and configure it like this:

reuse_008

It looks the same as the already created action type of ‘Rule’ BB on the parent ‘project’ entity. The difference? This one starts after lifecycle task creation! When will this happen? Well, the lifecycle starts on creation of our ‘project’ entity. In the ‘Draft’ state we configured an automatic started activity named Create draft which lands in the inbox of the current ‘owner’ of the lifecycle / case; which is in my case the awdev account.

Have a try after a publication of the project into runtime. Create (again) a new instance to trigger the lifecycle! The PIM will provide you with a messagemap like this one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<messagemap>
<faults />
<instanceProperties>
<processName>nl-bos/bpms/bpm_dummy</processName>
<rootInstance>0800270e-e5c1-a1ec-a4be-526e73e79c0f</rootInstance>
<rootInstanceType>PROCESS</rootInstanceType>
<currentOwner>cn=awdev@awp,cn=organizational users,o=appworks_tips,cn=cordys,cn=defaultInst,o=mydomain.com</currentOwner>
<rootEntityInstanceId>0800270ee5c1a1eca26380748340046c.327683.327683</rootEntityInstanceId>
</instanceProperties>
<LifecycleTask-id xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.cordys.com/default">
<Id>327682</Id>
<ItemId>0800270ee5c1a1eca26359f13d9e1388.327683</ItemId>
<EntityType>0800270ee5c1a1eca26359f13d9e1388</EntityType>
</LifecycleTask-id>
</messagemap>

Notes on this XML:

  • The rootEntityInstanceId equals the ‘ItemId’ of the related ‘LifecycleTask’ of the current entity instance from where the lifecycle triggered (our ‘project’ entity instance!)
  • The LifecycleTask-id element is also an interesting one. It’s the ‘input’ message for our BPM (which we didn’t define on the BPM itself!) and contains the ‘ItemId’ of the parent entity instance (our project!)

The final use-case is triggering the BPM manually

For this one we don’t create anything extra. Just right-click the crafted BPM and run it from the context menu:

reuse_009

The PIM will show us a message map like this; Nice and clean as expected:

1
2
3
4
5
6
7
8
9
10
<messagemap>
<faults />
<instanceProperties>
<processName>nl-bos/bpms/bpm_dummy</processName>
<rootInstance>0800270e-e5c1-a1ec-a4be-ab5a8d6d36d7</rootInstance>
<rootInstanceType value="1">PROCESS</rootInstanceType>
<rootModelRevisionID>0800270e-e5c1-a1ec-a4bd-dd96274d3417</rootModelRevisionID>
<currentOwner>cn=awdev@awp,cn=organizational users,o=appworks_tips,cn=cordys,cn=defaultInst,o=mydomain.com</currentOwner>
</instanceProperties>
</messagemap>

Notes on this XML:

  • The rootEntityInstanceId is missing in action here! Totally correct as we didn’t start the BPM with any entity related context.

Creating a pattern

All right…We’ve just explored the use-cases by triggering one particular BPM in separate ways. Our BPM is (for now) just a one-step activity; your solution is more advanced, but the principle will be the same. What we mostly see in these types of BPMs is the so-called ‘Read’ operation of (in this case) the ‘project’ entity via an applied ‘Web service’ BB! Yes, now we’re talking! 🤓 This ‘Read’ operation in the BPM requires a message map input of an entity ‘ItemId’…Only, (from what we’ve just experienced!) this is not always brought onto the BPM-table for correct processing. We exactly solve this ‘problem’ via an interesting pattern.

Let’s first create pseudocode to explain what we’re trying to solve here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
switch(useCase) {
case "actionRule" ->
if(rootInstanceType="PROCESS" && hasProjectIdElements) {
startSubBPM( `bpm:project-id/bpm:ItemId/text()` );
};
case "lifecycle" ->
if(rootInstanceType="CASE") {
startSubBPM( `instance:instanceProperties/instance:rootEntityInstanceId/text()` );
};
case "relatedTask" ->
if(rootInstanceType="PROCESS" && hasLifecycleTaskIdElements) {
startSubBPM( `bpm:LifecycleTask-id/bpm:ItemId/text()` );
}
case "manual" ->
if(if(rootInstanceType="PROCESS" && !hasRootEntityInstanceIdElements)) {
startSubBPM( `bpm:input/bpm:ItemId/text()` );
}
default -> "Unknown use-case!";
}

Comments:

  • Looks like we need some kind of wrapper / parent BPM which calls eventually our sub-BPM bpm_dummy
  • We would expect our ‘Wrapper’ BPM to have an input-message with values like ‘useCase’ and ‘itemId’, but that’s not possible! Why? well, from experience I know the indirect calls (like the action rule and lifecycle call) will fail when you apply any input message yourself. We don’t need it on the other hand as we have already other data available in the message map to detect the correct action. Check the pseudocode again on the if-statements!
  • The current bpm_dummy BPM requires an input value. This will just be a pass-through value from the ‘Wrapper’ BPM retrieved from different input elements of the messagemap (like we saw in the use-case examples)

Time to put our skills at work with this todo-list in mind:

  1. Add Read webservice operation to ‘project’ entity and add the application connector service container to manage the calls
  2. Update current bpm_dummy BPM with a triggered input message (and element itemId) and apply the ‘Read’ webservice operation
  3. Create a wrapper BPM bpm_wrapper with a ‘smart’ xPath expression activity to grab the itemId per use-case and trigger the bpm_dummy as subprocess with the itemId as input.
  4. Update actionRule, lifecycle and related task to call the wrapper BPM

Read webservice

An image tells a thousand words:

reuse_010

With this webservice applied we also require the creation of a service container of type ‘Application Server Connector’. We can create this from within the ‘System Resource Manager’ artifact where we follow the ‘New Service Group’ wizard with these inputs:

  • Connector type: Application Server Connector
  • Group name: appserver_service_group
  • Web Service Interfaces: Select only the one from our just created ‘Read’ operation (it’s called ‘Method Set Entity project’)
  • Service name: appserver_service_container
    • Mark ‘Assign OS process’
    • Set to auto-startup

Once the service container is up and running with a green flag, we should be able to evaluate our ‘Read’ operation via the artifact ‘Web Service Interface Explorer’. Try it out on yourself…It’s not hard to do! Comment me otherwise…

Update bpm_dummy BPM

Back to our one-activity BPM. Right-click that one activity and insert a ‘Web Service Operation’ from the context menu. Find the webservice Readproject and click to apply. You see the activity will get a ‘service’ icon and a new name. You can apply your own naming conversion, but it’s fine like this.

reuse_011

Now select the activity and jump into the messagemap tab (at the bottom). Here we see the power of BPM where we can connect elements from ‘Source’ to ‘Target’! The first thing we do is adding (right-click) a new input message in the ‘process Specific Messages’ (incl. one element):

reuse_012

After creation, we connect the source input:item_id with the target Readproject:project-id:ItemId. A trick learned from the masters!

reuse_013

The final setting on this BPM is the trigger type from our input message. We configure this on the model tab again in the properties of the green start-construct:

reuse_014

Nice and “done”, I would say…You might not see it yet, but this already fulfills our first use-case! The one where we “manual” start our BPM…For this one we don’t need any ‘Wrapper’ BPM! Right-click the bpm_dummy from your project and execute it (after save, and publication!)! Yes, my friends…You get a modal popup for the input message like we would expect! Well, where are you waiting for!? Fill-in the ‘ItemId’ of a ‘project’ instance in runtime and double-check the PIM on a ‘Completion’ status!

Great!…next step

Create the wrapper BPM

Create a new ‘Business Process Model’ type of document; nicely saved in the bpms folder of the project. Name it bpm_wrapper and just add two activities. One named grabItemId and the other one will trigger the bpm_dummy BPM as subprocess.

reuse_015

The next step is to define a kind of process variable in the messagemap of the BPM. This is the same action as we created the ‘input’ message in the bpm_dummy BPM, but now we only require the element; without any message…Like this:

reuse_016

With the “variable” in place, we can simply use it as input to our bpm_dummy call…

reuse_017

Leaves us with one last step! Making sure the item_id variable gets the correct value…And that, my friends, is a nice xPath expression learned in the field:

1
2
3
4
5
6
7
if(instance:instanceProperties/instance:rootInstanceType/text() = 'CASE')
then instance:instanceProperties/instance:rootEntityInstanceId/text()
else if(instance:instanceProperties/instance:rootInstanceType/text() = 'PROCESS' and bpm:LifecycleTask-id)
then bpm:LifecycleTask-id/bpm:ItemId/text()
else if(instance:instanceProperties/instance:rootInstanceType/text() = 'PROCESS' and bpm:project-id)
then bpm:project-id/bpm:ItemId/text()
else 'Unknown use-case!'

reuse_018

NOTE: Make sure to update the expression usage to ‘Replace Content With Expression’

Do I hear somebody? But isn’t this just the work of a ‘decision table’ type of document!?. Totally correct! Off-course I played with it upfront but struggled on the “action” part of the rules within the decision table. So, after creating my use-case, I wanted to start my BPM like we do in the above example. Only, I wasn’t able to figure out how to dynamically grab the ‘ItemId’ value like we do now in the xPath!? Comment me if you’re the decision-table-expert to have a call with!?

FYI: Here is another quick xPath example with quotes; which is always a struggle (trust me…this is a valid expression as long as you keep those multi-lines in place!!)

1
2
3
4
5
if(false()) 
then "I'm true"
else if(true())
then 'I"m false'
else ''

Update the calling non-manual end-points

Before we can start evaluating our expression, we require some updates where we move from the bpm_dummy BPM, to the bpm_wrapper BPM:

  1. The action Rule a_start_bpm on the ‘project’ entity
  2. The BPM activity on the ‘project’ Lifecycle BB!
  3. The event Rule e_on_create_start_bpm on the related LifecycleTask entity

The 4th use-case was our ‘manual’ call which we already fixed with the input parameter!

Well, time for a publication of our project and try out the different scenario’s…Keep focus on the PIM to see if the end-result is satisfied!? 😁 Believe me or not, but I only retrieve green flags with a satisfied outcome.

reuse_019


Give yourself a tap on the shoulder! Always nice to see when a plan comes together in a fine-grind “DONE” post. We learned about an interesting principle on how to reuse a BPM when triggered from difference contexts. The trick here is all in the xPath expressions where we learned about a fascinating if-else-then construction. Have your own advantage with it, and I CU in the next post; Have a great xPath-weekend! 🤗

Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?