ProjectTaskWorkflowProcess.java 17 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.cq.projects.api.Project
 *  com.adobe.granite.taskmanagement.Task
 *  com.adobe.granite.taskmanagement.TaskAction
 *  com.adobe.granite.taskmanagement.TaskManager
 *  com.adobe.granite.taskmanagement.TaskManagerException
 *  com.adobe.granite.taskmanagement.TaskManagerFactory
 *  com.adobe.granite.workflow.WorkflowException
 *  com.adobe.granite.workflow.WorkflowSession
 *  com.adobe.granite.workflow.exec.HistoryItem
 *  com.adobe.granite.workflow.exec.WorkItem
 *  com.adobe.granite.workflow.exec.Workflow
 *  com.adobe.granite.workflow.exec.WorkflowData
 *  com.adobe.granite.workflow.exec.WorkflowProcess
 *  com.adobe.granite.workflow.metadata.MetaDataMap
 *  com.adobe.granite.workflow.model.WorkflowNode
 *  javax.jcr.Session
 *  org.apache.commons.lang3.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.ReferencePolicy
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.api.scripting.SlingBindings
 *  org.apache.sling.api.scripting.SlingScript
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.projects.impl.workflow;

import com.adobe.cq.projects.api.Project;
import com.adobe.cq.projects.impl.workflow.DynamicScriptResource;
import com.adobe.granite.taskmanagement.Task;
import com.adobe.granite.taskmanagement.TaskAction;
import com.adobe.granite.taskmanagement.TaskManager;
import com.adobe.granite.taskmanagement.TaskManagerException;
import com.adobe.granite.taskmanagement.TaskManagerFactory;
import com.adobe.granite.workflow.WorkflowException;
import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.HistoryItem;
import com.adobe.granite.workflow.exec.WorkItem;
import com.adobe.granite.workflow.exec.Workflow;
import com.adobe.granite.workflow.exec.WorkflowData;
import com.adobe.granite.workflow.exec.WorkflowProcess;
import com.adobe.granite.workflow.metadata.MetaDataMap;
import com.adobe.granite.workflow.model.WorkflowNode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.jcr.Session;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScript;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@Service
@Properties(value={@Property(name="service.description", value={"Task Manager Step implementation."}), @Property(name="service.vendor", value={"Adobe"}), @Property(name="process.label", value={"Task Manager Step"})})
public class ProjectTaskWorkflowProcess
implements WorkflowProcess {
    private static final Logger log = LoggerFactory.getLogger(ProjectTaskWorkflowProcess.class);
    static final String WORK_ITEM_ID = "workItemId";
    static final String WORKFLOW_INSTANCE_ID = "wfInstanceId";
    public static final String PARM_PUSH_PAYLOAD_CHANGES = "pushPayloadChanges";
    static final String ARG_TASK_TYPE = "argTaskType";
    static final String ARG_TASK_NAME = "argTaskName";
    static final String ARG_TASK_DUE_DELTA_DAYS = "argTaskDueDeltaDays";
    static final String ARG_TASK_DUE_DELTA_HOURS = "argTaskDueDeltaHours";
    static final String ARG_ACTIONS = "argActions";
    static final String ARG_TASK_PRIORITY = "argTaskPriority";
    static final String ARG_TASK_DESCRIPTION = "argTaskDescription";
    static final String ARGS_SEND_EMAIL_NOTIFICATION = "sendEmailNotification";
    static final String TASKPROPERTY_DUE_DATE = "taskDueDate";
    static final String TASKPROPERTY_PRIORITY = "taskPriority";
    static final String ARG_TASK_OWNER = "argTaskOwner";
    static final String WORKITEMPROPERTY_TASK_ID = "taskId";
    static final String ARG_ON_ASSIGN_SCRIPT = "onCreateScript";
    static final String ARG_ON_ASSIGN_INLINE_SCRIPT = "script";
    static final String TASKPROPERTY_COMMENT = "comment";
    static final String WORKITEM_COMMENT = "comment";
    public static final String PROJECT_PATH = "project.path";
    public static final String PROJECT_DUE_DATE = "project.dueDate";
    public static final String TASKPROPERTY_PREVIOUS_TASK_ACTION = "previousTaskAction";
    public static final String TASKPROPERTY_PREVIOUS_COMPLETED_BY = "previousCompletedBy";
    public static final String TASKPROPERTY_PREVIOUS_COMMENT = "previous_comment";
    @Reference(policy=ReferencePolicy.STATIC)
    private ResourceResolverFactory resolverFactory;

    public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException {
        log.debug("creating task for workitem {}", (Object)(item != null ? item.getId() : "<null>"));
        ResourceResolver resourceResolver = null;
        try {
            resourceResolver = (ResourceResolver)session.adaptTo(ResourceResolver.class);
            String projectPath = (String)item.getWorkflowData().getMetaDataMap().get("project.path", String.class);
            if (StringUtils.isEmpty((CharSequence)projectPath)) {
                throw new WorkflowException(String.format("Metadata must include project path property in property named: %s", "project.path"));
            }
            Resource projectResource = resourceResolver.getResource(projectPath);
            Project project = (Project)projectResource.adaptTo(Project.class);
            TaskManager taskManager = this.getTaskManager(projectResource);
            Task task = this.constructTaskInstanceFromParameters(taskManager, item, args);
            task.setProperty("project.path", (Object)projectPath);
            this.addPreviousTaskInfo(session, taskManager, task, item);
            Object dueDateProperty = task.getProperty("taskDueDate");
            if (dueDateProperty == null || StringUtils.isBlank((CharSequence)dueDateProperty.toString())) {
                ValueMap valueMap = (ValueMap)projectResource.adaptTo(ValueMap.class);
                Date dueDate = (Date)valueMap.get("project.dueDate", Date.class);
                task.setProperty("taskDueDate", (Object)dueDate);
            }
            this.runOnCreateScript(session, item, task, project, args);
            Task result = taskManager.createTask(task);
            if (result != null) {
                item.getMetaDataMap().put((Object)"taskId", (Object)result.getId());
                log.debug("task {} created", (Object)result.getId());
            }
        }
        catch (TaskManagerException e) {
            throw new WorkflowException("Failed to create task", (Throwable)e);
        }
    }

    private void addPreviousTaskInfo(WorkflowSession session, TaskManager taskManager, Task task, WorkItem workItem) {
        WorkItem previousUserWorkItem = this.findPreviousUserWorkItem(session, workItem);
        if (previousUserWorkItem != null) {
            String previousTaskId = (String)previousUserWorkItem.getMetaDataMap().get("taskId", String.class);
            try {
                Task previousTask = taskManager.getTask(previousTaskId);
                if (previousTask != null) {
                    TaskAction selectedAction = previousTask.getSelectedAction();
                    if (selectedAction != null) {
                        task.setProperty("previousTaskAction", (Object)selectedAction.getActionID());
                    }
                    task.setProperty("previous_comment", previousTask.getProperty("comment"));
                    task.setProperty("previousCompletedBy", (Object)previousTask.getCompletedBy());
                }
            }
            catch (TaskManagerException e) {
                log.warn("Failed to load task for workitem {} and task id {}", (Object)new Object[]{previousUserWorkItem.getId(), previousTaskId}, (Object)e);
            }
            return;
        }
        String workitemComment = (String)workItem.getMetaDataMap().get("comment", String.class);
        if (workitemComment != null) {
            task.setProperty("comment", (Object)workitemComment);
        }
    }

    private WorkItem findPreviousUserWorkItem(WorkflowSession session, WorkItem workItem) {
        try {
            List history = session.getHistory(workItem.getWorkflow());
            String previousHistoryEntry = (String)workItem.getMetaDataMap().get("historyEntryPath", String.class);
            previousHistoryEntry = previousHistoryEntry + "/workItem";
            for (int index = history.size() - 1; index >= 0; --index) {
                HistoryItem historyEntry = (HistoryItem)history.get(index);
                WorkItem historyWorkItem = historyEntry.getWorkItem();
                if (historyWorkItem == null || !historyWorkItem.getId().equals(previousHistoryEntry)) continue;
                if (this.isTaskOrParticipantWorkItem(historyWorkItem)) {
                    return historyWorkItem;
                }
                if (historyEntry.getPreviousHistoryItem() == null) continue;
                previousHistoryEntry = historyEntry.getPreviousHistoryItem().getWorkItem().getId();
            }
        }
        catch (WorkflowException e) {
            log.warn("Failed to load history for workitem {} and workflow {}", (Object)new Object[]{workItem.getId(), workItem.getWorkflow().getId()}, (Object)e);
        }
        return null;
    }

    private boolean isTaskOrParticipantWorkItem(WorkItem historyWorkItem) {
        String taskId = (String)historyWorkItem.getMetaDataMap().get("taskId", String.class);
        if (taskId != null) {
            return true;
        }
        return false;
    }

    private TaskManager getTaskManager(Resource projectResource) throws WorkflowException {
        Resource projectContent = projectResource.getChild("jcr:content");
        ValueMap valueMap = (ValueMap)projectContent.adaptTo(ValueMap.class);
        String tasksFolderName = (String)valueMap.get("tasks.folder", String.class);
        Resource tasksNode = null;
        if (tasksFolderName != null) {
            tasksNode = projectContent.getChild(tasksFolderName);
        }
        if (tasksNode == null) {
            throw new WorkflowException("Child resource for creating tasks: '" + tasksFolderName + "' does not exist at location: '" + projectContent.getPath() + "'");
        }
        TaskManager taskManager = (TaskManager)tasksNode.adaptTo(TaskManager.class);
        return taskManager;
    }

    private Task constructTaskInstanceFromParameters(TaskManager taskManager, WorkItem workItem, MetaDataMap args) throws TaskManagerException, WorkflowException {
        String[] actions;
        String taskOwner = (String)args.get("argTaskOwner", String.class);
        String taskType = (String)args.get("argTaskType", String.class);
        if (taskType == null) {
            taskType = "default";
        }
        Task newTask = taskManager.getTaskManagerFactory().newTask(taskType);
        newTask.setCurrentAssignee(taskOwner);
        newTask.setProperty("workItemId", (Object)workItem.getId());
        newTask.setProperty("wfInstanceId", (Object)workItem.getWorkflow().getId());
        String taskName = (String)args.get("argTaskName", String.class);
        if (taskName != null) {
            newTask.setName(taskName);
        }
        String pushPayloadChange = "false";
        Object wfPayload = workItem.getWorkflowData().getPayload();
        if (wfPayload instanceof String) {
            newTask.setContentPath((String)wfPayload);
            pushPayloadChange = "true";
        }
        newTask.setProperty("pushPayloadChanges", (Object)pushPayloadChange);
        String taskDescription = (String)args.get("argTaskDescription", String.class);
        if (taskDescription != null) {
            newTask.setDescription(taskDescription);
        }
        int deltaDays = this.getInt(args, "argTaskDueDeltaDays");
        int deltaHours = this.getInt(args, "argTaskDueDeltaHours");
        if (deltaDays != 0 || deltaHours != 0) {
            Calendar calendar = Calendar.getInstance();
            calendar.add(10, deltaHours);
            calendar.add(5, deltaDays);
            newTask.setProperty("taskDueDate", (Object)calendar.getTime());
        }
        if ((actions = (String[])args.get("argActions", String[].class)) != null && actions.length > 0) {
            ArrayList<TaskAction> actionList = new ArrayList<TaskAction>();
            for (String action : actions) {
                if (action == null || action.trim().length() <= 0) continue;
                actionList.add(taskManager.getTaskManagerFactory().newTaskAction(action));
            }
            if (actionList.size() > 0) {
                newTask.setActions(actionList);
            }
        }
        String taskPriority = (String)args.get("argTaskPriority", String.class);
        newTask.setProperty("taskPriority", (Object)taskPriority);
        String notifyUser = (String)args.get("sendEmailNotification", String.class);
        if (StringUtils.isNotBlank((CharSequence)notifyUser)) {
            newTask.setProperty("sendEmailNotification", (Object)notifyUser);
        }
        return newTask;
    }

    private int getInt(MetaDataMap args, String propertyName) {
        if (args != null && propertyName != null) {
            Integer integer = (Integer)args.get(propertyName, Integer.class);
            if (integer != null) {
                return integer;
            }
            String numberAsString = (String)args.get(propertyName, String.class);
            if (numberAsString != null) {
                try {
                    return Integer.parseInt(numberAsString);
                }
                catch (NumberFormatException nfe) {
                    log.debug("value of {} is not an integer number, instead got {}", (Object)propertyName, (Object)numberAsString);
                }
            }
        }
        return 0;
    }

    private void runOnCreateScript(WorkflowSession session, WorkItem workItem, Task task, Project project, MetaDataMap args) throws WorkflowException {
        workItem.getNode().getMetaDataMap().get("argTaskName", String.class);
        if (args.containsKey((Object)"onCreateScript")) {
            ResourceResolver resourceResolver = (ResourceResolver)session.adaptTo(ResourceResolver.class);
            String scriptPath = (String)args.get("onCreateScript", String.class);
            Resource script = resourceResolver.getResource(scriptPath);
            this.runOnCreateScript(script, workItem, task, project, session, resourceResolver);
        }
        if (args.containsKey((Object)"script")) {
            String script = (String)args.get("script", String.class);
            ResourceResolver resolver = null;
            try {
                resolver = this.resolverFactory.getResourceResolver(Collections.singletonMap("user.jcr.session", session.adaptTo(Session.class)));
            }
            catch (LoginException e) {
                throw new WorkflowException("Can't create resource resolver.", (Throwable)e);
            }
            DynamicScriptResource scriptResource = new DynamicScriptResource(resolver, script);
            this.runOnCreateScript((Resource)scriptResource, workItem, task, project, session, resolver);
        }
    }

    private void runOnCreateScript(Resource scriptResource, WorkItem workItem, Task task, Project project, WorkflowSession workflowSession, ResourceResolver resolver) {
        SlingScript script = (SlingScript)scriptResource.adaptTo(SlingScript.class);
        SlingBindings props = new SlingBindings();
        props.put((Object)"workflowData", (Object)workItem.getWorkflowData());
        props.put((Object)"workItem", (Object)workItem);
        props.put((Object)"workflowSession", (Object)workflowSession);
        props.put((Object)"jcrSession", resolver.adaptTo(Session.class));
        props.put((Object)"task", (Object)task);
        props.put((Object)"project", (Object)project);
        log.debug("Calling script {}.", (Object)script);
        Object result = script.eval(props);
        log.debug("Result from script {} is {}", (Object)script, result);
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }
}