Back to the blog

Easy steps to create a custom workflow model in Adobe experience Manager (AEM) (PDF Watermarking)

author image

Viraj Rane

Technology | April 15, 2021

hero image

Workflows are very important in any organization to channelize several given steps/tasks sequentially.

"Workflow is a set of independent or dependent tasks which are distinct and performed by a person or a group of people"

In Adobe Experience Manager (AEM) many operations and activities are automated using workflows. Workflows allow authors and business teams to perform tasks independently. This helps them to track, organize and control different processes without getting dependent on the technical team. Adobe Experience Manager (AEM) has many OOTB workflows to automate day-to-day tasks like publishing a page or an asset, creating a language copy, deleting videos or images, etc.

You might also like: See how Adobe Experience Manager can revolutionize your customer experience

Workflows can access assets (e.g. images, videos, documents), content pages, services, and resources in the AEM JCR repository. This makes workflows a perfect choice to perform complex tasks which involve interaction between different users and resources. AEM has a very strong framework to build and extend these workflows. This allows developers to quickly develop workflows specific to project requirements.

Let’s see how to create a custom workflow in AEM to “add watermark on PDF document".

We will cover the following topics to create the workflow:

  1. What is a workflow model?
  2. Create a custom workflow model
  3. What is a workflow process/step?
  4. Create a custom workflow process
  5. Add the process in a workflow model

What is a Workflow Model?

  1. A workflow model is a skeleton or a blueprint of the workflow consisting of sequential steps.
  2. Process steps are defined either by a Java class or an ECMAScript.

    • For the Java class processes, the fully qualified class name is provided.
    • For the ECMAScript processes, the path to the script is provided.
  3. Every model has a start and end step.
  4. To initiate a workflow from the model, we need to select a payload which could be an asset or page which gets passed to each step as a string that is either a JCR path or a JCR identifier (UUID).
  5. Individual process steps that do act on the payload will usually expect a payload of a certain type, or act differently depending on the payload type.

Create a Custom Workflow Model

We will create a workflow to add a watermark to a PDF document.

Steps to create a workflow:

  1. Navigate to the Workflow Models console in AEM: AEM Start Page > Tools > Workflow > Models

Step 1.1: Create Model

Step 1.2: Create Model

So, here we will land on the Workflow Models console:

Step 1.3: Create Model

  1. Now to create the model, click on the “Create” button.

Step 2: Create Model

  1. Add the title for the workflow, in our case “Add PDF Watermark” and click on the “Done” button.

Step 3: Create Model

  1. You will get a workflow model created with the given title. To edit the steps, hover over the model and select it.

Step 4: Create Model

  1. Then click on the “Edit” button.

Step 5: Create Model

  1. It will take you to the Workflow Model editor. This is the default workflow model structure with a start and an end node also, with a default participant step. As we don’t require user participation for this workflow, we will delete it.

Step 6: Create Model

  1. Now we need to create a first step which will take a PDF document as a payload and the process adds the watermark based on the arguments configured in the model.

Step 7: Create Model

You might also like: How to implement OAuth SSO in Angular & Flask Application?

What is a Workflow Process/Step?

A workflow step component defines the appearance and behavior of the step when creating workflow models:

  1. The category and step name in the workflow sidekick
  2. The appearance of the step in the workflow models
  3. The edit dialog for configuring component properties
  4. The service or script that is executed at runtime

As with all components, workflow step components inherit from the component that is specified for the sling:resourceSuperType property. The following diagram shows the hierarchy of cq:component nodes that form the basis of all workflow step components. The diagram also includes the Process Step, Participant Step, and Dynamic Participant Step components, as these are the most common (and basic) starting points for developing custom step components.

Workflow Process Inheritance

Create a Custom Workflow Process

To create a workflow process/step we need to create the following structure:

  1. Workflow process component under /apps/<project-name>/components/workflow
  2. JAVA class or ECMAScript to implement the process logic

First, we will create a Maven project with AEM archetype to add this structure.

Execute the following command to create a Maven AEM project with archetype version 19:

mvn -B archetype:generate -D archetypeGroupId=com.adobe.granite.archetypes -D archetypeArtifactId=aem-project-archetype -D archetypeVersion=19 -D groupId="com.hashout" -DartifactId="custom-workflow-step" -D artifactName="Custom Workflow Step" -D appsFolderName="custom-workflow-step" -D componentGroupName="Custom.Workflow.Step" -D siteName="Custom Workflow Step" -D optionAemVersion="6.4.4" -D optionIncludeErrorHandler="n" -D optionIncludeExamples="n"

Now we can create the required structure manually one by one but, we have a tool called YEOMAN. Yeoman is an open-source client-side scaffolding tool for web applications. Yeoman helps you to kickstart new projects, prescribing best practices and tools to help you stay productive.

With YEOMAN, we need to use a sub-generator to create the workflow process structure. One of the best sub-generators is generator-aem-application.

It supports the generation of the following modules:

  1. AEM components
  2. Clientlibs
  3. Custom Workflow Step
  4. Galen submodule

Note: Currently, it only supports JAVA class workflow process implementation.

Refer following steps to install YEOMAN and generator-aem-application:

  1. Download Node.js
  2. Run following commands:

    • npm install -g yo
    • npm install -g generator-aem-application

To generate workflow process script and component structure, execute the following command and answer the questions as shown below:

C:\Custom Workflow Steps in AEM>yo aem-application:workflow

     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the gnarly  │
    |--(o)--|    │ generator-aem-applicatio │
   `---------´   │   n:workflow generator!  │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

? What's the name for the Workflow Process Step PDF Watermark
? What's the name for the component's maven module ui.apps
? What's the path for the component custom-workflow-step/components/workflow
? What's the name for the component's node pdf-watermark
? What's the name for the bundle's maven module core
? What's the name for the root package for the application com.hashout.core
? What's the relative name for the package for the workflow (without the root package) workflows
? What's the name for the Workflow process class PDFWatermarkProcess

It will create following files and copy these to the respective folders in your Maven project:

  1. ui.apps\src\main\content\jcrroot\apps\custom-workflow-step\components\workflow\pdf-watermark\cq_editConfig.xml
  2. ui.apps\src\main\content\jcrroot\apps\custom-workflow-step\components\workflow\pdf-watermark\cq_dialog.content.xml
  3. ui.apps\src\main\content\jcr_root\apps\custom-workflow-step\components\workflow\pdf-watermark.content.xml
  4. core\src\main\java\com\hashout\core\workflows\PDFWatermarkProcess.java

Each file has its role while rendering and processing the workflow process:

  1. .content.xml: Creates a cq:Component node with sling:resourceSuperType as "cq/workflow/components/model/process"
  2. cqeditConfig.xml: A node mentioning the process JAVA class and other options like PROCESS_AUTO_ADVANCE
  3. cqdialog/.content.xml: Defines the process Touch UI dialog for workflow editor
  4. PDFWatermarkProcess.java: JAVA class entry point for processing of the payload passed in the workflow

From the above files, we need to edit the _cq_dialog/.content.xml and add more fields as per the requirement.

Workflow Process Dialog

You can download the cq:dialog file from here.

Now, we need to implement the JAVA class for the workflow process:

The execute method of the WorkflowProcess implementation is passed with the WorkItem object. Use this object to obtain the WorkflowData object for the current workflow instance. From this WorkflowData object we will get the path of the PDF asset.

To get the asset binary, we need a Resource resolver object which we can adapt from the WorkflowSession object.

The session passed to the WorkflowProcess is backed by the service user for the workflow process service, which has the following permissions at the root of the repository:

jcr:read

rep:write

jcr:versionManagement

jcr:lockManagement

crx:replicate

Also, to get arguments for the watermark, we need to use MetaDataMap object.

@Override
    public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) {

        final WorkflowData workflowData = workItem.getWorkflowData();
        final String type = workflowData.getPayloadType();
        final String payloadPath = workflowData.getPayload().toString();
        final ResourceResolver resolver = workflowSession.adaptTo(ResourceResolver.class);
        final Resource assetResource = resolver != null ? resolver.getResource(payloadPath) : null;
        final AssetManager assetManager = resolver != null ? resolver.adaptTo(AssetManager.class) : null;

        // Check if the payload is under the DAM folder
        if (StringUtils.equals(type, TYPE_JCR_PATH)
                && StringUtils.startsWith(payloadPath, DAM_ROOT_PATH)
                && assetResource != null
                && assetManager != null) {
            //Adapt payload to asset
            final Asset asset = assetResource.adaptTo(Asset.class);
            if (asset != null && StringUtils.equals(asset.getMimeType(), PDF_MIMETYPE)) {
                ByteArrayInputStream watermarkedPDFStream = applyWatermark(asset, args);
                if (watermarkedPDFStream != null) {
                    assetManager.createAsset(payloadPath, watermarkedPDFStream, PDF_MIMETYPE, true);
                }
            }
        }

    }

To parse PDF documents and to add a watermark layer for each page, we will use the Apache PDFBox library. It is an open-source Java tool for working with PDF documents. It has the following features:

  1. Extract Unicode text from PDF files.
  2. Split a single PDF into many files or merge multiple PDF files.
  3. Extract data from PDF forms or fill a PDF form.
  4. Validate PDF files against the PDF/A-1b standard.
  5. Print a PDF file using the standard Java printing API.
  6. Save PDFs as image files, such as PNG or JPEG.
  7. Create a PDF from scratch, with embedded fonts and images.
  8. Digitally sign PDF files.

As the OSGi bundle for PDFBox is not available, we need to embed it with its dependencies in our project bundle. We can check the dependencies here.

Add PDFBox and its dependencies in the root POM:

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.23</version>
</dependency><dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>fontbox</artifactId>
    <version>2.0.23</version>
</dependency><dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency><dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

Embed these dependencies in the project bundle by adding an embed configuration for bundle POM, core/pom.xml.

Edit bundle build configuration and add the following configuration:

<Embed-Dependency>
    pdfbox,
    fontbox,
    bcprov-jdk15on,
    bcpkix-jdk15on
</Embed-Dependency>

Now, Add the code to process the PDF from PDFWatermarkProcess.java. Build the project and deploy it on AEM.

We have completed the development of the PDF Watermarking step and now we need to include it in the workflow model.

You might also like: Creating a Tool in Adobe Experience Manager

Using custom process with a workflow model

  1. To include the watermark process in the model, go to Workflow Editor again and search for the “PDF Watermark” process

Step 1: Add Process

  1. Add the process and click on the edit dialog button

Step 2: Add Process

  1. Add the watermark text and other configuration as shown below

Step 3: Add Process

  1. Click on the “Sync” button to store the changes

Step 4: Add Process

  1. We also need to add the “Process Thumbnails” step to update the PDF thumbnail after adding the watermark. For that copy this step from the “DAM Update Asset” model as is shown below:

    I. Open the “DAM Update Asset” in the editor

    Step 5.1: Add Process

    II. Click on the “Edit” button

    Step 5.2: Add Process

    III. Select the “Process Thumbnails” step and click on the copy button

    Step 5.3: Add Process

    IV. Open “Add PDF Watermark” in the editor and paste it in the parsys

    Step 5.3: Add Process

    V. Click on the “Sync” button

    Step 5.4: Add Process

  2. Congratulations, “Add PDF Watermark” workflow is ready to use!
  3. We can initiate this workflow from Assets or directly from the Workflow Models console

Step 7: Add Process

  1. We will get the following processed PDF:

Step 8: Add Process

Source Code

custom-workflow-step

Download AEM Package

custom-workflow-step.ui.apps-1.0.zip

Conclusion

Adobe Experience Manager (AEM) workflows are very powerful to automate different tasks. Also, AEM’s workflow framework is extensive and easy to implement. We can create independent processes and use them across many workflows. This increases the reusability and efficiency.

References

PDFBox: https://pdfbox.apache.org/

Browse all categories