Hi there AppWorks fans,
Welcome to a new installment of AppWorks tips.
This time a very nice feature (inspired by this forum topic) that makes it possible to call some custom Java code from the XPath editor! XPath?…Yes, also known as the expression editor that we use in the message mapping for our activities in a BPM. We know it is possible to add all kinds of nice expressions OOTB, but wouldn’t it be nice to call some function we’ve created ourselves?…Well…
Let get right into it…
First…Start your VM and login to you most favorite platform…Our “AppWorks”. We start with a clean workspace and project which looks like this:
In the ‘bpms’ folder we create a new ‘test’ bpm with just a ‘’(Green) Init’’ -> “Activity” -> “(Red) End” flow. From this BPM we jump into the message map where we have the possibility to drag & drop a process property into the ‘Assignments’ panel in the middle. We only do this action, so we are able to open the ‘Advanced’ XPath editor.
In this editor we can call all kind of advanced functions like these examples:
1 | boolean(instance:instanceProperties/instance:processName/text() != '') //returns TRUE |
All those functions and operators are available for consumption in the left bottom panel, but that’s not what I would like to dive further into for now.
What we do want to dive into is a call like this one:
com.eibus.util.Base64.encode("Hello world!")
which results into SGVsbG8gd29ybGQh
The opposite call looks like this: com.eibus.util.Base64.decode("SGVsbG8gd29ybGQh")
and reverts it back to Hello world!
Hmmm…interesting!? as this function is not directly available from the UI!…So, where does it retrieve that value from?
The search for our magic call
A search on the server brings me to this JAR file /opt/opentext/AppWorksPlatform/defaultInst/components/basicutil/basicutil.jar
The search command was:
sudo find /opt/opentext/AppWorksPlatform/defaultInst/ -type f -name '*.jar' -print0 | xargs -0 -I '{}' sh -c 'jar tf {} | grep Base64.class && echo {}'
With a view on this file with JD-GUI I see more interesting “public static” methods available to consume from…Here a set of examples:
1 | com.eibus.util.UserProfile.encryptAndEncode("awdev", "admin") //returns encoded string |
Hmmm…nice stuff, but what else?
Let’s pick another JAR: /opt/opentext/AppWorksPlatform/defaultInst/components/esbserver/esbserver.jar
We came to these examples to call in our XPath editor:
1 | com.eibus.license.Monitor.getLicenseStatus() //returns the number of days left before license expiration |
What else?
Another one: /opt/opentext/AppWorksPlatform/defaultInst/components/bpmengine/bpmengine.jar
1 | com.cordys.bpm.utils.Utilities.writeToConsole("Hello world...") //tail -f /opt/tomee/latest/logs/catalina.out |
Nice!…The final one in the ‘components’ folder: /opt/opentext/AppWorksPlatform/defaultInst/components/entityruntime/utilities.jar
1 | com.opentext.utilities.StringHelper.stringsEqualIgnoreCase("Hello world", "Hello") //returns FALSE |
Great….What about a JAR outside the ‘components’ folder…Like the ‘ext’ folder: /opt/opentext/AppWorksPlatform/defaultInst/ext/commons-lang3.jar
1 | org.apache.commons.lang3.text.WordUtils.capitalizeFully("i aM.fine") //returns I Am.fine |
Ohw yeah!!….Now we’re getting somewhere…If this is possible…How about calling some custom method?
Check the next section…
Create some Java code
Maybe you already noticed…Maybe not, but all calls above have one thing in common!
What might that be?
The method should be public, and it should be static!
The ‘public’ keyword is an access modifier used for classes, attributes, methods, and constructors making them accessible by any other class.
A ‘static’ method can be accessed without creating an object of the class first
So, with those requirements in mind we can create a Java class looking like this:
1 | package nl.bos.bpm; |
You can use a fancy IDE, but for this demo we just use Notepad++ as we will compile this source into a JAR file with the platform features in next section.
The power of JAD
To have our Java class compiled, generated into a JAR, and deployed on the server in a specific location we will use a ‘Java Archive Definition’ document in our project.
Make sure you have a folder structure like this in the ‘java’ folder of our project:
In the ‘crosscontext’ folder we create a new ‘Java Archive Definition’ with the sample same ‘bpm_jad’. We give the ‘JAR File Name’ a logical name like for example ‘BPMMethods’, and we make sure to point to the ‘src’ directory where we will upload our just crafted Java source file. This is how it should look like:
To upload our Java source we create a new ‘Java Source’ document in the ‘src/nl/bos/bpm’ folder where we copy & paste our crafted Java code from the previous section!
The end-results:
Finally, we need to set the ‘java’ folder as ‘Set start point of qualified name’ which makes our ‘relative’ path on the server to this location:
/opt/opentext/AppWorksPlatform/defaultInst/
. As we all know this is the location where the ‘crosscontext’ folder lives…So, that’s a wisely chosen folder name!
Now, let’s publish our ‘bpm_jad’, and you will start to see a nicely generated JAR uploaded to the server in this location:
/opt/opentext/AppWorksPlatform/defaultInst/crosscontext/BPMMethods.jar
Now we need to do a restart of TomEE with systemctl restart tomee
and after a refresh of the designer we will be able to call our own custom function:
1 | nl.bos.bpm.HelpMethods.toUpperCase("test") //returns TEST |
Ohhhh YEAH…That’s nice! 💪
With that final call we can also give this post a “DONE” where we learned how to call a custom method from the XPath editor. Nice to know how this works, and it will probably solve some well-though features from our analyst-guy in the future! Leaves me with one last thing…Cheers, have a great week-end, and I see you in a new installment; next week…
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”?