Creating an Action Executor
Workflow nodes can contain <action>
elements that execute custom logic via Groovy scripts.
<action>
<name>approve</name>
<script>
<![CDATA[
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.WorkflowStatusManagerUtil;
WorkflowStatusManagerUtil.updateStatus(WorkflowConstants.getLabelStatus("approved"), workflowContext);
]]>
</script>
<script-language>groovy</script-language>
<execution-type>onEntry</execution-type>
</action>
Instead of writing Groovy action logic directly in a workflow definition <script>
element, you can execute Java logic by implementing the ActionExecutor
interface.
- Write the Java implementation.
- Call the Java class from the workflow definition XML file.
First deploy and observe a working ActionExecutor
.
Deploy an Action Executor
Start a new Liferay DXP instance by running
docker run -it -m 8g -p 8080:8080 liferay/dxp:2024.q1.1
Sign in to Liferay at http://localhost:8080 using the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
-
Download and unzip the Acme E5C9 Implementation project.
curl https://resources.learn.liferay.com/dxp/latest/en/process-automation/workflow/developer-guide/liferay-e5c9.zip -O
unzip liferay-e5c9.zip
-
From the module root, build and deploy.
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
TipThis command is the same as copying the deployed jars to
/opt/liferay/osgi/modules
on the Docker container. -
Confirm the deployment in the Liferay Docker container console.
STARTED com.acme.e5c9.impl_1.0.0
For convenience, the activate
method of the ActionExecutor
auto-loaded a workflow definition called E5C9 Single Approver. This code achieved the same thing as navigating to the Workflow Process Builder and uploading a workflow definition. See Uploading a New Workflow Definition.
Test the Action Executor
To use the Acme E5C9 Action Executor, set the workflow definition for use with Blogs Entries and add a new Blogs Entry with the administrative User.
-
In the Applications tab of the Global Menu, go to Workflow → Process Builder.
-
In the Configuration tab, assign the E5C9 Single Approver definition to the Blogs Entry Asset Type.
-
Click Save.
-
Using the default administrative User Test Test, open the Site menu → Content & Data → Blogs.
-
Click the Add button (
).
-
Enter something into the Title and Content fields, then click Submit for Workflow.
-
Back in the main Blogs view, confirm that the entry is visible and that the status is marked as Pending.
The workflow framework set the status as pending. From this point onward, the status updates are made using the logic in the action executor.
-
Approve the Blogs Entry in the workflow.
If you assign the Single Approver workflow to Blogs Entries, you can see it work identically to the E5C9 Single Approver.
Understanding the E5C9 Action Executor
The Acme E5C9 Implementation project extracts the status-setting logic of the Single Approver definition’s workflow scripts into its single Java class, E5C9ActionExecutor
.
In addition to the action executor, the project includes and auto-loads a workflow definition called the E5C9 Single Approver, which has the same logic as the default Single Approver but uses the action executor class’s logic instead of Groovy scripting directly in the workflow definition.
<script>
<![CDATA[com.acme.e5c9.internal.workflow.kaleo.runtime.scripting.internal.action.E5C9ActionExecutor]]>
</script>
The ActionExecutor
sets the workflow status according to each transition’s name:
if (Objects.equals(
workflowContext.get("transitionName"), "reject")) {
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_DENIED, workflowContext);
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_PENDING, workflowContext);
}
else if (Objects.equals(
workflowContext.get("transitionName"), "approve")) {
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_APPROVED, workflowContext);
}
Implementing an ActionExecutor
The action executor class implements the com.acme.e5c9.internal.workflow.kaleo.runtime.scripting.internal.action.ActionExecutor
interface, overriding its single execute
method. Set the action’s scripting language as java
in the getActionExecutorKey
method:
@Override
public String getActionExecutorKey() {
return "java";
}
The execute
method does not return anything. Instead, logic is executed arbitrarily within the method and the workflow processing continues according to the XML definition. Often times the status of the workflow is updated within the action execution.
The execute
method takes two parameters, a KaleoAction
and an ExecutionContext
. Because the workflow engine is responsible for calling the action executor in the workflow process, your code isn’t responsible for instantiating and constructing these objects. However, you can obtain useful information from them. For example, the E5C9 Action Executor retrieves the workflowContext
(of the type Map
) from the ExecutionContext
:
Map<String, Serializable> workflowContext =
executionContext.getWorkflowContext();
The workflowContext
is used to get the transition most recently executed, so that conditional logic can determine which status to set for the asset in the workflow.
if (Objects.equals(
workflowContext.get("transitionName"), "reject")) {
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_DENIED, workflowContext);
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_PENDING, workflowContext);
}
else if (Objects.equals(
workflowContext.get("transitionName"), "approve")) {
WorkflowStatusManagerUtil.updateStatus(
WorkflowConstants.STATUS_APPROVED, workflowContext);
}
Calling the ActionExecutor in the Workflow Definition
The E5C9 Single Approver workflow definition contains script elements in the state and task nodes. These script elements declare the action executor class. Both of the definition’s actions (reject and approve) have identical script tags:
<script>
<![CDATA[com.acme.e5c9.internal.workflow.kaleo.runtime.scripting.internal.action.E5C9ActionExecutor]]>
</script>
<script-language>java</script-language>
The script tags point the workflow framework to the action executor that holds the logic.
You aren’t limited to calling a single action executor in your workflow definition. For example, the E5C9ActionExecutor
has logic to determine the transition before setting the workflow status. However, if the logic was more complex each action in the workflow could be backed by a separate ActionExecutor
implementation, and these implementations can be reused in other workflow definitions.