oo

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 the Groovy action logic directly in a workflow definition <script> element, you can execute Java logic by implementing the ActionExecutor interface.

  1. Write the Java implementation.
  2. 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:

  1. 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
    
  2. From the module root, build and deploy.

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
    Tip

    This command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.

  3. Confirm the deployment in the Liferay Docker container console.

    STARTED com.acme.e5c9.impl_1.0.0
    
Note

For convenience, the activate method of the ActionExecutor autoloaded a E5C9 Single Approver workflow definition. 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.

  1. In the Applications tab of the Global Menu, go to Workflow → Process Builder.

  2. In the Configuration tab, assign the E5C9 Single Approver definition to the Blogs Entry Asset Type.

  3. Click Save.

  4. Using the default administrative User Test Test, open the Site menu → Content & Data → Blogs.

  5. Click the Add button (Add).

  6. Enter something into the Title and Content fields, then click Submit for Workflow.

  7. 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.

  8. Approve the Blogs Entry in the workflow.

    This approval or rejection is accomplished by the E5C9 Action Executor.

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 autoloads 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.

WorkflowStatusManagerUtil.updateStatus(
	WorkflowConstants.STATUS_DENIED, 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 a component property.

@Component(
	property = "com.liferay.portal.workflow.kaleo.runtime.action.executor.language=java",
	service = ActionExecutor.class
)
public class E5C9ActionExecutor implements ActionExecutor {

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 auto-loaded by the Acme E5C9 Implementation project is nearly identical to the Single Approver definition that ships with Liferay. The differences are entirely in the script elements of the state and task nodes, which are greatly simplified in the E5C9 Single Approver definition because all logic is outsourced to the action executor class. Both of the definition’s actions (reject and approve) have identical script tags:

<script>
	<![CDATA[com.acme.e5c9.internal.kaleo.runtime.action.executor.E5C9ActionExecutor]]>
</script>
<script-language>java</script-language>

The script tags are still necessary, but now they 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.

Capability:
Feature: