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:
For this entity we also add a simple lifecycle…Just with two states; let’s say Draft
, and Final
:
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:
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:
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:
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 | <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:
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 | <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.
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:
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 | <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:
The PIM will show us a message map like this; Nice and clean as expected:
1 | <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 | switch(useCase) { |
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:
- Add Read webservice operation to ‘project’ entity and add the application connector service container to manage the calls
- Update current
bpm_dummy
BPM with a triggered input message (and elementitemId
) and apply the ‘Read’ webservice operation - Create a wrapper BPM
bpm_wrapper
with a ‘smart’ xPath expression activity to grab the itemId per use-case and trigger thebpm_dummy
as subprocess with theitemId
as input. - Update actionRule, lifecycle and related task to call the wrapper BPM
…
Read webservice
An image tells a thousand words:
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.
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):
After creation, we connect the source input:item_id
with the target Readproject:project-id:ItemId
. A trick learned from the masters!
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:
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.
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:
With the “variable” in place, we can simply use it as input to our bpm_dummy
call…
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 | if(instance:instanceProperties/instance:rootInstanceType/text() = 'CASE') |
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 | if(false()) |
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:
- The action Rule
a_start_bpm
on the ‘project’ entity - The BPM activity on the ‘project’ Lifecycle BB!
- 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.
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”?