April 1, 2020
Estimated Post Reading Time ~

How to extend Replication Page Process for workflow in AEM

Use Case: You want to extend existing replication page process and add your own logic during workflow step. Some of common use case could be,
1) Activate Asset as soon as it is uploaded to DAM

Solution:

Here is sample code you can use for this,
What this code is doing is trying to find DAM asset path from workflow item and then activating DAM asset instead of activating just original node when OOTB activate page workflow is used.

package com.wemblog;

import com.day.cq.dam.api.Asset;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.wcm.workflow.process.ReplicatePageProcess;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import com.day.cq.workflow.model.WorkflowNode;
import org.apache.felix.scr.annotations.*;
import org.apache.felix.scr.annotations.Property;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import java.util.Date;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;

import com.day.cq.dam.commons.util.DamUtil;

/**
* Workflow used to activate the asset when the workflow item is the "original" version of the asset.
*
* It will use DAM Util to traverse upward to find the DAM Asset node and provide it as the target of the execution
*/
@Component
@Service({WorkflowProcess.class})
@Property(name="process.label", value={"Activate Original Asset"})
public class ActivateAssetFromOriginalProcess extends ReplicatePageProcess {

private static final Logger log = LoggerFactory.getLogger(ActivateAssetFromOriginalProcess.class);

@Reference
ResourceResolverFactory resourceResolverFactory;

@Property(value = "An implementation of activating assets from the original asset.")
static final String DESCRIPTION = Constants.SERVICE_DESCRIPTION;

@Override
public ReplicationActionType getReplicationType()
{
return ReplicationActionType.ACTIVATE;
}

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


/*
A typical path of the assets looks like this `/content/wemblog/yogesh.jpg/jcr:content/renditions/original`
In order to go from ..../original to .../yogesh.jpg, we need to go (3 steps) up
*/
// This is the augmented path of DAM Asset, above .../original
String path = null;
try {
WorkflowData data = workItem.getWorkflowData();
Session session = workflowSession.getSession();

String type = data.getPayloadType();
Node originalAsset = null;
if ((type.equals("JCR_PATH")) && (data.getPayload() != null)) {
String payloadData = (String)data.getPayload();
originalAsset = session.getNode(payloadData);
}
else if ((data.getPayload() != null) && (type.equals("JCR_UUID"))) {
originalAsset = session.getNodeByUUID((String)data.getPayload());
}
Map authInfo = new HashMap();
authInfo.put("user.jcr.session", session);
ResourceResolver resolver = resourceResolverFactory.getResourceResolver(authInfo);
Asset asset = DamUtil.resolveToAsset(resolver.getResource(originalAsset.getPath()));
resolver.close();
path = asset.getPath();
}
catch (RepositoryException e) {
throw new WorkflowException(e);
}
catch (LoginException e) {
throw new WorkflowException(e);
}
log.info("For the original asset replication, augmented path is: " + path);


// Utlize the replication logic in the super class, with the augmented path
super.execute(new AssetWorkItemWrapper(workItem, path), workflowSession, args);

}

//Created two inner class to alternate the behavior of WorkItem and WorkflowData
/**
* AssetWorkItemWrapper
* <br/>
* A wrapper around WorkItem, it delegate all other methods back to wrapped WorkItem instance,
* except `getWorkflowData`, which it returns the result wrapped with AssetWorkflowDataWrapper.
*/
class AssetWorkItemWrapper implements WorkItem {

WorkItem wrappedItem;
String augmentedPath;

AssetWorkItemWrapper(WorkItem wrappedItem, String augmentedPath) {
this.wrappedItem = wrappedItem;
this.augmentedPath = augmentedPath;
}

@Override
public Date getTimeStarted() {
return wrappedItem.getTimeStarted();
}

@Override
public Date getTimeEnded() {
return wrappedItem.getTimeEnded();
}

@Override
public com.day.cq.workflow.exec.Workflow getWorkflow() {
return wrappedItem.getWorkflow();
}

@Override
public WorkflowNode getNode() {
return wrappedItem.getNode();
}

@Override
public String getId() {
return wrappedItem.getId();
}

@Override
public com.day.cq.workflow.exec.WorkflowData getWorkflowData() {
return new AssetWorkflowDataWrapper(wrappedItem.getWorkflowData(), augmentedPath);

}

@Override
public String getCurrentAssignee() {
return wrappedItem.getCurrentAssignee();
}

@Override
public Dictionary<String, String> getMetaData() {
return wrappedItem.getMetaData();
}

@Override
public MetaDataMap getMetaDataMap() {
return wrappedItem.getMetaDataMap();
}
}

class AssetWorkflowDataWrapper implements WorkflowData {

WorkflowData wrappedData;
String augmentedPath;

AssetWorkflowDataWrapper(WorkflowData wrappedData, String augmentedPath) {
this.wrappedData = wrappedData;
this.augmentedPath = augmentedPath;

}

@Override
public Object getPayload() {
return augmentedPath;
}

@Override
public String getPayloadType() {
// AugmentedPath is alway of type JCR_PATH
return "JCR_PATH";
}

@Override
public Dictionary<String, String> getMetaData() {
return wrappedData.getMetaData();
}

@Override
public MetaDataMap getMetaDataMap() {
return wrappedData.getMetaDataMap();
}
}
}


Once you add your code, you can add this as a workflow step in your workflow. If you are extending model.xml for workflow then it will look something like this,

<node
jcr:primaryType="cq:WorkflowNode"
description="A process to activate a page or asset"
title="Activate Original Asset"
type="PROCESS">
<metaData
jcr:primaryType="nt:unstructured"
PROCESS="com.wemblog.ActivateAssetFromOriginalProcess"
PROCESS_AUTO_ADVANCE="true"/>
</node>


Also, you have to make sure that you have the right dependency in your pom.xml. If you are using AEM6.1 then you need to use

<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>    <version>6.1.0</version>    <classifier>apis</classifier>    <scope>provided</scope>
</dependency>


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.