Article summary

Summary

Discusses how to create a custom workflow step that has a Touch UI dialog that lets workflow authors enter parameter values used in the workflow. This article also discusses how to use Java code to retrieve those values at run-time.  This article uses DS Annotations to create the custom workflow step as opposed to Felix SRC annotations. 

A special thank you to Ratna Kumar Kotla, a member of the AEM community, for testing this article and ensuring it works. 

Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (intermediate)
Required Skills
Java, OSGi, Maven
Tested On  Adobe Experience Manager 6.4

Note:

You can download an AEM package that contains the custom workflow component with the dialog and the OSGi service. Download the package and deploy using package manager. The purpose of this code is to show the community these concepts in action. That is, it's to illustrate how to write a custom workflow component with a dialog. This community code is for teaching purposes only and not meant to go into production as is. After you deploy this package, you still have to create the DeleteContentPart workflow as discussed in this article. However - the Logger custom step will be available from the sidekick.

Download

Introduction

You can develop a custom Adobe Experience Manager workflow step that reads data from a workflow dialog. An author enters data into a dialog during design time; typically when the workflow model is developed. The Java logic that belongs to the custom step reads the values and uses the vaules in the AEM workflow during run-time. In this example, the values are written to the Experiene Manager log file. 

The following illustration shows the workflow step Touch UI dialog that is created in this development article. 

dialogA
A Touch UI dialog used in a custom workflow step

As shown in the above illustration, two Touch UI fields are added to this workflow step dialog: 

  • granite/ui/components/coral/foundation/form/textfield
  • granite/ui/components/coral/foundation/form/datepicker

The following illustration shows the project files created  in this development artilce. 

DailogB1
AEM JCR nodes that create a dialog for a custom workflow step

The following describes the files in the previous illustration. 

Section Description
A Touch UI dialog
B Configuration files for the dialog. For example, a property under this node branch maps the dialog to the OSGi service that contains application logic for the custom workflow step. This is how a custom dialog is mapped to a custom OSGi service (this is discussed in more detail later in this development article).
C Classic UI dialog

Create an Experience Manager 13 archetype project

You can create an Experience Manager archetype project by using the Maven archetype plugin. In this example, assume that the working directory is C:\AdobeCQ. 

ProjectA
An Experience Manager Maven Archetype 13 project

To create an Experience Manager archetype project, perform these steps:

1. Open the command prompt and go to your working directory (for example, C:\AdobeCQ).

2. Run the following Maven command:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype -DarchetypeVersion=13 -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/

3. When prompted, specify the following information:

  • groupId - wfdialogTouch
  • artifactId - wfdialogTouch
  • version - 1.0-SNAPSHOT
  • package - com.adobe.aem
  • appsFolderName - wfdialogTouch
  • artifactName - wfdialogTouch
  • componentGroupName - wfdialogTouch
  • contentFolderName - wfdialogTouch
  • cssId - wfdialogTouch
  • packageGroup - wfdialogTouch
  • siteName -wfdialogTouch

4. WHen prompted, specify Y.

5. Once done, you will see a message like:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:42 min
[INFO] Finished at: 2016-04-25T14:34:19-04:00
[INFO] Final Memory: 16M/463M
[INFO] ------------------------------------------------------------------------

6. Change the working directory to AEMMaven13 and then enter the following command.

mvn eclipse:eclipse

After you run this command, you can import the project into Eclipse as discussed in the next section.

Note:

If you have not setup Maven, see this article Creating an Adobe Experience Manager 6.4 Project using Adobe Maven Archetype 13.

Add Java files to the Maven project using Eclipse 

To make it easier to work with the Maven generated project, import it into the Eclipse development environment, as shown in the following illustration.

Project
Eclipse Import Project Dialog

Note:

Do not worry about the errors reported in Eclipse. It does not read the POM file where the APIs are resolved. You build the bundle with Maven. Eclipse is used to edit the Java files and the POM file.

The next step is to add Java files to the com.adobe.aem.core package. The Java class that you create in this section impements the com.adobe.granite.workflow.exec.WorkflowProcess interface. For information, see Interface WorkflowProcess.

Create a Java class named LoggerProcess in the com.adobe.aem.core package that implements the WorkflowProcess interface. Specify the following DS annotation:

  • @Component - defines the class as a component


Because the LoggerProcess class extends WorkflowProccess, you have to create a method named excute. The Java application logic in this method is invoked when the custom workflow step is executed. The execute method has the following signature:

public void execute(WorkItem item, WorkflowSession wfsession,MetaDataMap args) throws WorkflowException

In this use case, the values that a workflow author enters into the workflow step's dialog can be retrieved by using the args parameter. The following Java code represents the LoggerProcess Java class.

package com.adobe.aem.core;

import org.osgi.service.component.annotations.Component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
   
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Arrays;


import com.adobe.granite.workflow.WorkflowException;
import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.WorkItem;
import com.adobe.granite.workflow.exec.WorkflowData;
import com.adobe.granite.workflow.exec.WorkflowProcess;
import com.adobe.granite.workflow.metadata.MetaDataMap;


@Component(service=WorkflowProcess.class, property = {"process.label=Logger Process"})
public class LoggerProcess implements WorkflowProcess {
	   
	   private static final Logger log = LoggerFactory.getLogger(LoggerProcess.class);
	   
	    public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException {
	        String singleValue = args.get("argSingle", "not set");
	        String date = args.get("startdate","not set");
	        String[] multiValue = args.get("argMulti", new String[]{"not set"});
	   
	        log.info("---> Single Value: {}", singleValue);
	        log.info("---> DATE: {}", date);
	     }
	}

Note:

The values argSingle and startdate correspond to the names defined in the Touch UI dialog.

Modify the Maven POM file

Add the following POM dependency to the POM file located at C:\AdobeCQ\wfdialogTouch.

<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>
    <version>6.4.0</version>
    <classifier>apis</classifier>
    <scope>provided</scope>
</dependency>
               
  <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-atinject_1.0_spec</artifactId>
       <version>1.0</version>
       <scope>provided</scope>
   </dependency>

When you add new Java classes under core, you need to modify a POM file to successfully build the OSGi bundle. You modify the POM file located at C:\AdobeCQ\wfdialogTouch\core. The following code represents this POM file.

<?xml version="1.0" encoding="UTF-8"?>
<!--
 |  Copyright 2017 Adobe Systems Incorporated
 |
 |  Licensed under the Apache License, Version 2.0 (the "License");
 |  you may not use this file except in compliance with the License.
 |  You may obtain a copy of the License at
 |
 |      http://www.apache.org/licenses/LICENSE-2.0
 |
 |  Unless required by applicable law or agreed to in writing, software
 |  distributed under the License is distributed on an "AS IS" BASIS,
 |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 |  See the License for the specific language governing permissions and
 |  limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>wfdialogTouch</groupId>
        <artifactId>wfdialogTouch</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>wfdialogTouch.core</artifactId>
    <packaging>bundle</packaging>
    <name>wfdialogTouch - Core</name>
    <description>Core bundle for wfdialogTouch</description>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.sling</groupId>
                <artifactId>maven-sling-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <!-- Import any version of javax.inject, to allow running on multiple versions of AEM -->
                        <Import-Package>javax.inject;version=0.0.0,*</Import-Package>
                        <Sling-Model-Packages>
                            com.adobe.aem.core
                        </Sling-Model-Packages>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- OSGi Dependencies -->
         <dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>
    <version>6.4.0</version>
    <classifier>apis</classifier>
    <scope>provided</scope>
</dependency>
                
  <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-atinject_1.0_spec</artifactId>
       <version>1.0</version>
       <scope>provided</scope>
   </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.cmpn</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.annotation</artifactId>
        </dependency>
        <!-- Other Dependencies -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.jcr</groupId>
            <artifactId>jcr</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>apis</classifier>
        </dependency>
        <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.models.api</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
        </dependency>
        <dependency>
            <groupId>junit-addons</groupId>
            <artifactId>junit-addons</artifactId>
        </dependency>
    </dependencies>
</project>

Build the OSGi bundle using Maven

To build the OSGi bundle by using Maven, perform these steps:

  1. Open the command prompt and go to the C:\AdobeCQ\wfdialogTouch.
  2. Run the following maven command: mvn -PautoInstallPackage install.
  3. The OSGi component can be found in the following folder: C:\AdobeCQ\wfdialogTouch\core\target. The file name of the OSGi component is wfdialogTouch.core-1.0-SNAPSHOT.jar.

The command -PautoInstallPackage automatically deploys the OSGi bundle to AEM.

View the Active OSGi bundle

After you deploy the OSGi bundle, you can see it in the Apache Felix Web Console.

OSGi
OSGi bundle

View your OSGi bundle by performing these steps:

  1. Login to Adobe Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).
  2. Click the Bundles tab, sort the bundle list by Id, and note the Id of the last bundle.

Create the Workflow Step Component

1. Create a folder named workflow under /apps/wfdialogTouch/components.

2. Right click on /apps/wfdialogTouch/components/workflow and then select New, Component. Name the component loggerprocess.

2. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter Loggerprocess.
  • Title: The title that is assigned to the component. Enter Logger.
  • Description: The description that is assigned to the component. Enter Writes workflow information to the log file.
  • Super Resource Type: Enter cq/workflow/components/model/process.
  • Group: The group in the side rail where the component appears. Enter Workflow

3. Click Ok.

cq:editConfig JCR nodes

The cq:editConfig node defines configuration values for the custom workflow step, including the OSGi Java class that defines the steps functionality.  

Perform these tasks:

1. Click on /apps/wfdialogTouch/components/workflow/loggerprocess

2. Right click and select Create, Create Node.

3. Enter the following values:

  • Name: cq:editConfig
  • Type: cq:EditConfig

4. Add the following properties to the cq:editConfig node.

  • cq:dialogMode(String) - floating
  • cq:inherit(Boolean) - true
5. Click on /apps/wfdialogTouch/components/workflow/loggerprocess/cq:editConfig.
6. Right click and select Create, Create Node.
7. Enter the following values:
  • Name: cq:formParameters
  • Type: nt:unstructured

8. Add the following properties to the cq:formParameters node.

  • PROCESS(String) - com.adobe.aem.core.LoggerProcess (this is the Java class in the OSGi service that defines the custom step logic)
  • PROCESS_AUTO_ADVANCE(String) - true
  • jcr:description(String) - Logs workflow values to the log.
  • jcr:title - Logger Process

Loggerprocess Touch UI Dialog

Build a Touch UI dialog for the custom workflow step and ensure that the nodes resemble the following illustration. 

Dialog
The custom workflow step Touch UI dialog

To build the dialog, perform these tasks:

1. Select /apps/wfdialogTouch/components/workflow/loggerprocess.

2. Right click and select Create, Create Node.

3. Enter the following values:

  • Name: cq:dialog
  • Type: nt:unstructured

4. Add the following properties to the cq:dialog node.

  • helppath (String) - en/cq/current/wcm/default_components.html#Carousel
  • jcr:title (String) - Hero Text
  • sling:resourceType (String) - cq/gui/components/authoring/dialog

5. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog.

6. Right click and select Create, Create Node. Enter the following values:

  • Name: content
  • Type: nt:unstructured

7. Add the following property to the content node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/container

8. Click on the following node:  /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content.

9. Right click and select Create, Create Node. Enter the following values:

  • Name: layout
  • Type: nt:unstructured

10. Add the following properties to the layout node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/tabs
  • type (String) -nav

11. Click on the following node:  /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content.

12. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

13. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items.

14. Right click and select Create, Create Node. Enter the following values:

  • Name: herotext
  • Type: nt:unstructured

15. Add the following properties to the herotext node (this node represents the tab).

  • jcr:title (String) - Hero Text Properties
  • sling:resourceType (String) - granite/ui/components/foundation/section

16. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/content/items/herotext.

17. Right click and select Create, Create Node. Enter the following values:

  • Name: layout
  • Type: nt:unstructured

18. Add the following property to the layout node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/fixedcolumns

19. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext.

20. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

21. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items.

22. Right click and select Create, Create Node. Enter the following values:

  • Name: column
  • Type: nt:unstructured

23. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/column.

24. Add the following property to the column node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/container

25. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/columns.

26. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

27. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/column/items.

28. Right click and select Create, Create Node. Enter the following values:

  • Name: headingText
  • Type: nt:unstructured

29. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/column/items/headingText.

30. Add the following properties to the headingText node (this node represents the Heading Text input control on the dialog. See the illustration at the start of this article.)

  • fieldLabel (String) - Heading Text
  • name (String) - ./metaData/argSingle
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/textfield

31. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/column/items.

32. Right click and select Create, Create Node. Enter the following values:

  • Name: startDate
  • Type: nt:unstructured

33. Click on the following node: /apps/wfdialogTouch/components/workflow/loggerprocess/cq:dialog/content/items/herotext/items/column/items/description.

34. Add the following property to the description node (this node represents the Description input field on the dialog. See the illustration at the start of this article.)

  • displayedFormat (String) - YYYY-MM-DD HH:mm
  • fieldLabel (String) - Start Date
  • name (String) -./metaData/startdate 
  • class (String) - field
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/datepicker
  • type (String) – datetime

Create an AEM Workflow that uses the custom workflow step

In this step, create an AEM workflow in the Touch UI environment that deletes content and uses the custom step to log messages. 

 

Workflow
An AEM Workflow that uses the Logger custom workflow step

To create a workflow that deletes content and logs a message using the custom step, perform the following tasks:

1. Click the Hammer icon in the main AEM view at http://localhost:4502. 

2. Click Workflow on the side menu. 

3. Click Models. 

4. Click the Create button then Create Model

5. Enter DeleteContentPart as the workflow title.

6. Open the DeleteContentPart workflow by selecting it and clicking Edit. 

 

WF1
Opening a workflow model

7. Add the Delete Node component from the side rail onto the workflow model. Make this the second step of the workflow.

 

secondstep
Add the delete node step

8. Add the Logger custom step to the workflow by dragging-and-dropping the Logger component from the side rail onto the workflow model. Ensure that this is the third step in the workflow model. 

thirdstep
Add the Logger custom step

9. Double click on this step.  Enter values into the fields. (These vaules are logged to the AEM log file).

 

Dialog44
Touch UI resource types in a custom workflow step dialog

10. Click the Sync button.

Invoke the DeleteContentPart Workflow

The final task to perform is to invoke the workflow from the Experience Manager Touch UI Digital Asset view located at:

http://localhost:4502/sites.html/content

Select an AEM page and from the top menu, select Create, Workflow as shown in this illustration.  

WF2
Invoke an AEM Workflow

The Workflow dialog appears. Select the workflow, as shown in this illustration.  

Wf3
Select a workflow

Click the Next button and then the Create button. This invokes the workflow. You will see a success message if the workflow is successful. 

For the site admin UI at: 

http://localhost:4502/sites.html/content/we-retail

click on the messages icon, as shown here. 

wf4
The admin message generated by the first step in the workflow

This bring you to the Workflow confirmation view. Click the Complete button and then the OK button.

wf5
Click the Complete button to complete the workflow

When the administrator clicks the Complete button, the Complete Work Item dialog is shown that specifies the Delete Node step (the second step in the workflow). The piece of content that is specified as the second argument (TestPage) is deleted. The worflow advances to the custom workflow step that logs the values entered into the dialog into the AEM log file.

14.06.2018 15:26:34.656 *INFO* [JobHandler: /var/workflow/instances/server0/2018-06-14_1/deletecontentpart_5:/content/QUeryJCR64/fr] com.adobe.aem.core.LoggerProcess ---> Single Value: TestValue1
14.06.2018 15:26:34.660 *INFO* [JobHandler: /var/workflow/instances/server0/2018-06-14_1/deletecontentpart_5:/content/QUeryJCR64/fr] com.adobe.aem.core.LoggerProcess ---> DATE: 2018-06-14T15:24:00.000-04:00



See also

Congratulations, you have just created a custom workflow step that uses a dialog. Please refer to the AEM community page for more articles that discuss how to build AEM services/applications.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy