/ Development  

Revealed; The hidden custom call in xPath you've been missing out on (part 2)

Hi there AppWorks fans,

Welcome to a new installment of AppWorks tips.

It’s been a while ago, but this post in 2021 saved my ass during a critical implementation in 2024! That’s the power of writing blogs. I’m not only doing it for you…Also for myself!


Let get right into it…

What is the use-case? Well, we have a ‘Long text’ type of property as a description for an entity instance, but we want to replace “variables” in the text with something else when we hit an action button (or move to the next phase of a lifecycle). That’s a nice use-case to work on…right!? “Smells” like document templating! Indeed, you are correct! Do we want it in our solution? Well, that’s a different discussion, but can we do it with AppWorks? Hell yeah!!

Let’s assume we have this piece of text available in runtime for a ‘Contract’ type of entity instance:

1
2
3
4
5
6
This Contract Agreement ("Agreement") is made and entered into on 
this {{effective_date}} by and between {{company_name}}, a company
incorporated under the laws of {{company_state}}, having its principal
place of business at {{company_address}} (hereinafter referred to
as "Company"), and {{client_name}}, located at {{client_address}}
(hereinafter referred to as "Client").

The ‘Contract’ entity will have these fields configured (incl. the default BBs) and as an “extra”, the ‘Web Service’ BB…I leave the implementation up to you.

Property Label Type length
cont_input Input Long text n/a
cont_output Output Long text n/a
cont_effective_date Effective date Date n/a
cont_company_name Company name Text 64
cont_company_state Company state Text 64
cont_company_address Company address Text 128
cont_client_name Client name Text 64
cont_client_address Client address Text 128

This is my first view of the entity overview:

xpath_001

Notes:

  • Update the length for the ‘Text’ properties as described in the above table.
  • Set the display name of the entity behind the red-arrow in the top bar.
  • Provide a proper label for the lst_contracts
  • Make the ‘Create’ form look a little nicer.


To support the ‘Web Service’ BB, you need a new service container of type ‘Application Server’. You can create one in the ‘System Resource Manager’ artifact. I assume you know the drill by now.

In runtime (after publication) there is now a view available like this to create a new instance of ‘Contract:

xpath_002

Comment me below if you don’t have a clue how to start with something like this (incl. that service container)!?

On action-button “Approval” of the entity we want to output the final text to the cont_output field with a smart BPM expression…Keep on reading!

As next step, create a new rule of type ‘Action’ with name a_approval that will start a BPM bpm_approval with a first implementation like this:

xpath_003

The rule is as simple as this:

xpath_004

In the BPM, you can insert (from the context menu of the activity!) two service calls Readcontract and Updatecontract. The first one is easy; it maps the rootEntityInstanceId with the ItemId of the “Read” operation:

xpath_005

The second one does a magic xPath expression like this (#WTF…Don’t panic! 🤯):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
org.apache.commons.lang3.StringUtils.replace(
org.apache.commons.lang3.StringUtils.replace(
org.apache.commons.lang3.StringUtils.replace(
org.apache.commons.lang3.StringUtils.replace(
org.apache.commons.lang3.StringUtils.replace(
org.apache.commons.lang3.StringUtils.replace(
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_input/text()),
'{{effective_date}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_effective_date)
),
'{{company_name}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_company_name)
),
'{{company_state}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_company_state)
),
'{{company_address}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_company_address)
),
'{{client_name}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_client_name)
),
'{{client_address}}',
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_client_address)
)

This magic thing simply replaces each variable in the text with the corresponding field of the form. Read between the lines, and you’ll see it’s a nested call for each ‘replace’ where the previous result is the input for the next result.

xpath_006


Also, don’t forget to set the execution mode of the BPM to short-lived in its properties (go back to the overview of the BPM template)! This mode makes it a synchronized call with direct feedback in runtime.

Notes:

  • Read more about org.apache.commons.lang3.StringUtils.replace here
  • Watch the extra string(...) function to match the Java method-signature of “StringUtils.replace”.
  • This replacement can also be handy in weird XML encoded characters like &lt; replacing <, &gt; replacing >. Or how about &quot; replacing ', &nbsp; replacing <space>, or &amp; replacing &! At least that’s what we saw following this current post in combination with this transformation post. Do your research…It’s powerful stuff to understand!
  • You can also work with $-variables in the input text like this for example: $(effective_date).

After a publication and hitting our action button in runtime:

xpath_007

It’s a party! 🥳

WAIT…I see a glitch! Do you see it too? Watch the “effective date” output! It’s 2024-09-24Z! Can we fix this? Yes, please!

1
2
3
4
5
org.apache.commons.lang3.StringUtils.replace(
string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_input/text()),
'{{effective_date}}',
substring-before(string(ns2:ReadcontractOutput/ns2:ReadcontractResponse/ns3:contract/ns3:cont_effective_date), 'Z')
)

Next level would be formatting the date with a custom Java function! Again, read about it here.

Now I see you asking: How on earth does this person know all this stuff? Well, that’s experience, the connections, and hitting the wall a thousand times before (with endless debugging sessions)! Why? that’s simple; to learn, to grow, to teach, and to keep yourself off the street with a purpose in life. See it all as one big puzzle and life is so much easier to conquer. I’m preaching again; Time to finish. 😉


A great technical masterpiece “DONE” where we learned to think out of the box. This thinking brings you into unknown territory and exposes new creativity processes for you to consume from. Again, for me a problem solved. I remove it from the backlog while you communicate these details further into the world. Have the best of all weekends and I see you next week with another topic about “AppWorks Tips”.

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”?