
com.day.cq.wcm.workflow.process.ReplicatePageProcess Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.wcm.workflow.process;
import com.adobe.granite.workflow.collection.ResourceCollection;
import com.adobe.granite.workflow.collection.ResourceCollectionManager;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationException;
import com.day.cq.replication.ReplicationOptions;
import com.day.cq.replication.Replicator;
import com.day.cq.wcm.workflow.api.WcmWorkflowService;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.HistoryItem;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import com.day.cq.workflow.model.WorkflowNode;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.AccessDeniedException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* This abstract ReplicatePageProcess
class serves as the basis for
* all replication specific JavaProcess
classes, like activate,
* deactivate...
* This Porcess starts the Replicator with the type provided by the implementing
* Classes
* {@link com.day.cq.wcm.workflow.process.ReplicatePageProcess#getReplicationType()
* getReblicationType()-method} of payloads of type path or uuid
* This Process checks permissions.
* In case the {@link com.day.cq.workflow.WorkflowSession Session} starting the
* process is lacking the Privilege to replicate, an event of this topic
* {@value com.day.cq.wcm.workflow.api.WcmWorkflowService#EVENT_TOPIC}
* is send out. Listeners to this topic, may handle this situation.
*
*
* Configuration
* This process supports the following configuration arguments:
*
* - replicateAsParticipant
* - Boolean flag indicating if the replication should be performed under the context of the latest participant, Default is
false
,
* meaning the replication is performed as workflow-session-service-user. This process supports this configuration either as a dedicated process
* arguments or as part of the generic PROCESS_ARGS argument. If set to true
the workflow model must have
* a participant or daynamic participant step modeled ahead this replication process, to determine the participant. If no
* participant can be determined, it falls back to workflow-session-service-user.
*
*
*
*/
@Component(componentAbstract = true)
public abstract class ReplicatePageProcess implements WorkflowProcess {
/**
* the logger
*/
private static final Logger log = LoggerFactory.getLogger(ReplicatePageProcess.class);
public static final String TYPE_JCR_PATH = "JCR_PATH";
public static final String TYPE_JCR_UUID = "JCR_UUID";
private static final String WCM_WORKFLOW_SERVICE = "wcm-workflow-service";
@Reference
protected Replicator replicator;
@Reference
protected EventAdmin eventAdmin;
@Reference
protected ResourceCollectionManager rcManager;
@Reference
private SlingRepository repository;
private enum Arguments {
PROCESS_ARGS("PROCESS_ARGS"), REPLICATE_AS_PARTICIPANT("replicateAsParticipant");
private String argumentName;
Arguments(String argumentName) {
this.argumentName = argumentName;
}
public String getArgumentName() {
return this.argumentName;
}
}
/**
* @see com.day.cq.workflow.exec.WorkflowProcess#execute(com.day.cq.workflow.exec.WorkItem,
* com.day.cq.workflow.WorkflowSession,
* com.day.cq.workflow.metadata.MetaDataMap)
*/
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
Session participantSession = null;
Session replicationSession = null;
try {
Session session = workflowSession.getSession();
if (replicateAsParticipant(args)) {
String approverId = resolveParticipantId(workItem, workflowSession);
if (approverId != null) {
participantSession = getParticipantSession(approverId, workflowSession);
}
}
if (participantSession != null) {
replicationSession = participantSession;
} else {
replicationSession = session;
}
WorkflowData data = workItem.getWorkflowData();
String path = null;
String type = data.getPayloadType();
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String payloadData = (String) data.getPayload();
if (session.itemExists(payloadData)) {
path = payloadData;
}
} else if (data.getPayload() != null && type.equals(TYPE_JCR_UUID)) {
Node node = session.getNodeByUUID((String) data.getPayload());
path = node.getPath();
}
MetaDataMap metaDataMap = data.getMetaDataMap();
Map versionMap = new HashMap();
if (metaDataMap.containsKey("versions")) {
JSONObject versionJs = new JSONObject(data.getMetaDataMap().get("versions", String.class));
Iterator iterator = versionJs.keys();
while (iterator.hasNext()) {
String key = (String)iterator.next();
versionMap.put(key, (String)versionJs.get(key));
}
}
if (path != null) {
// check for resource collection
List rcCollections = rcManager.getCollectionsForNode((Node) session.getItem(path));
// get list of paths to replicate (no resource collection: size
// == 1
// otherwise size >= 1
List paths = ResourceCollectionHelper.getPaths(path, rcCollections);
for (String aPath : paths) {
if (canReplicate(replicationSession, aPath)) {
ReplicationOptions opts = new ReplicationOptions();
String versionLabel = getVersionLabel(aPath, versionMap);
// if a version's label exist pass it to the replicator
if (StringUtils.isNotEmpty(versionLabel)) {
// Set the local revision label
opts.setRevision(versionLabel);
}
opts = prepareOptions(opts);
replicator.replicate(replicationSession, getReplicationType(), aPath, opts);
} else {
// request for "replication action"
log.debug(session.getUserID() + " is not allowed to replicate " + "this page/asset " + aPath
+ ". Issuing request for 'replication");
final Dictionary properties = new Hashtable();
properties.put("path", aPath);
properties.put("replicationType", getReplicationType());
properties.put("userId", session.getUserID());
Event event = new Event(WcmWorkflowService.EVENT_TOPIC, properties);
eventAdmin.sendEvent(event);
}
}
} else {
log.warn("Cannot activate page or asset because path is null for this " + "workitem: "
+ workItem.toString());
}
} catch (RepositoryException e) {
throw new WorkflowException(e);
} catch (ReplicationException e) {
throw new WorkflowException(e);
} catch (JSONException e) {
throw new WorkflowException(e);
} finally {
if (participantSession != null && participantSession.isLive()) {
participantSession.logout();
participantSession = null;
}
}
}
/**
* Returns the latest version for the given resource path
*
* @param path Path to the resource
* @param versionMap Map of available version labels
* @return
*/
private String getVersionLabel(String path, Map versionMap) {
if (StringUtils.isEmpty(path)) {
return null;
}
if (versionMap.containsKey(path)) {
return versionMap.get(path);
}
if (!path.endsWith("/" + JcrConstants.JCR_CONTENT)) {
path += "/" + JcrConstants.JCR_CONTENT;
}
return versionMap.get(path);
}
/**
* Determine the replication mode from the arguments map.
*
* @param args The process arguments
* @return Depending on the process arguments true
if the replication is supposed to take place under
* the participants context, false
otherwise.
*/
private boolean replicateAsParticipant(MetaDataMap args) {
String processArgs = args.get(Arguments.PROCESS_ARGS.getArgumentName(), String.class);
if (processArgs != null && !processArgs.equals("")) {
String[] arguments = processArgs.split(",");
for (String argument : arguments) {
String[] split = argument.split("=");
if (split.length == 2) {
String key = split[0];
String value = split[1];
if (key.equalsIgnoreCase(Arguments.REPLICATE_AS_PARTICIPANT.getArgumentName())) {
return Boolean.parseBoolean(value);
}
}
}
return false;
} else {
return args.get(Arguments.REPLICATE_AS_PARTICIPANT.getArgumentName(), Boolean.FALSE);
}
}
/**
* Get a session for the given approver.
*
* @param participantId
* @param workflowSession
* @return The approver's session or null
in case of repository exceptions.
*/
private Session getParticipantSession(String participantId, WorkflowSession workflowSession) {
try {
return this.repository.impersonateFromService(WCM_WORKFLOW_SERVICE,new SimpleCredentials(participantId,new char[0]),null);
} catch (Exception e) {
log.warn(e.getMessage());
return null;
}
}
/**
* Travael up the session's history to find the latest participant step or dynamic participant step and use it's
* current assignee as approver.
*
* @param workItem
* @param workflowSession
* @return The approver's id of the latest participant/dynamic participant step in the history. In case there is no
* participant step, null
is returned.
*/
private String resolveParticipantId(WorkItem workItem, WorkflowSession workflowSession) {
List history = new ArrayList();
try {
history = workflowSession.getHistory(workItem.getWorkflow());
for (int index = history.size() - 1; index >= 0; index--) {
HistoryItem previous = history.get(index);
String type = previous.getWorkItem().getNode().getType();
if (type != null && (type.equals(WorkflowNode.TYPE_PARTICIPANT) || type.equals(WorkflowNode.TYPE_DYNAMIC_PARTICIPANT))) {
return previous.getUserId();
}
}
return null;
} catch (Exception e) {
log.warn(e.getMessage());
return null;
}
}
/**
* Specifies the {@link ReplicationActionType}
for which this
* class is designed for.
*
* @return {@link ReplicationActionType}
*/
public abstract ReplicationActionType getReplicationType();
/**
* allows subclasses to mangle with the replication options.
*
* @return the options or null
*/
protected ReplicationOptions prepareOptions(ReplicationOptions opts) {
return opts;
}
protected boolean canReplicate(Session session, String path) throws AccessDeniedException {
try {
AccessControlManager acMgr = session.getAccessControlManager();
return acMgr.hasPrivileges(path, new Privilege[]{acMgr.privilegeFromName(Replicator.REPLICATE_PRIVILEGE)});
} catch (RepositoryException e) {
return false;
}
}
// ---------- SCR Integration ----------------------------------------------
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy