com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction.java

Source

/*
 * Copyright (c) 2010-2013 Evolveum
 *
 * 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.
 */

package com.evolveum.midpoint.wf.impl.jobs;

import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.impl.lens.LensContext;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.task.api.TaskBinding;
import com.evolveum.midpoint.task.api.TaskRecurrence;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface;
import com.evolveum.midpoint.wf.impl.processes.common.ActivitiUtil;
import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames;
import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ScheduleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UriStackEntry;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.midpoint.xml.ns._public.model.model_context_3.LensContextType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
import org.apache.commons.lang.Validate;

import javax.xml.namespace.QName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A generic instruction to start a workflow process and/or a task (using umbrella term "a job").
 * May be subclassed in order to add further information.
 *
 * @author mederly
 */
public class JobCreationInstruction implements DebugDumpable {

    private ChangeProcessor changeProcessor;

    private String processDefinitionKey; // name of wf process to be started (e.g. ItemApproval)

    private Map<String, Serializable> processVariables = new HashMap<>(); // values of process variables
    private Map<QName, Item> taskVariables = new HashMap<>(); // items to be put into task extension
    private PrismObject taskObject; // object to be attached to the task; this object must have its definition available
    private PrismObject<UserType> taskOwner; // if null, owner from parent task will be taken (if there's no parent task, exception will be thrown)
    private PolyStringType taskName; // name of task to be created/updated (applies only if the task has no name already) - e.g. "Approve adding role R to U"

    private boolean executeModelOperationHandler; // should the job contain model operation to be executed?
    private boolean noProcess; // should the job provide no wf process (only direct execution of model operation)?

    private boolean simple; // is workflow task simple? (i.e. such that requires periodic watching of its state)
    private boolean sendStartConfirmation = true; // should we send explicit "process started" event when the process was started by midPoint?
                                                  // for listener-enabled processes this can be misleading, because "process started" event could come
                                                  // after "process finished" one (for immediately-finishing processes)
                                                  //
                                                  // unfortunately, it seems we have to live with this (unless we define a "process started" listener)

    private boolean createTaskAsSuspended; // should the task be created in SUSPENDED state?
    private boolean createTaskAsWaiting; // should the task be created in WAITING state?

    // what should be executed at a given occasion (in the order of being in this list)
    private List<UriStackEntry> handlersAfterModelOperation = new ArrayList<>();
    private List<UriStackEntry> handlersBeforeModelOperation = new ArrayList<>();
    private List<UriStackEntry> handlersAfterWfProcess = new ArrayList<>();

    //region Constructors
    protected JobCreationInstruction(ChangeProcessor changeProcessor) {
        Validate.notNull(changeProcessor);
        this.changeProcessor = changeProcessor;
    }

    protected JobCreationInstruction(Job parentJob) {
        this(parentJob.getChangeProcessor());
    }

    public static JobCreationInstruction createModelOperationRootJob(ChangeProcessor changeProcessor,
            ModelContext modelContext) throws SchemaException {
        JobCreationInstruction instruction = new JobCreationInstruction(changeProcessor);
        instruction.setNoProcess(true);
        instruction.addTaskModelContext(modelContext);
        instruction.setExecuteModelOperationHandler(true);
        return instruction;
    }

    public static JobCreationInstruction createNoModelOperationRootJob(ChangeProcessor changeProcessor)
            throws SchemaException {
        JobCreationInstruction instruction = new JobCreationInstruction(changeProcessor);
        instruction.setNoProcess(true);
        instruction.setExecuteModelOperationHandler(false);
        return instruction;
    }

    public static JobCreationInstruction createWfProcessChildJob(ChangeProcessor changeProcessor) {
        JobCreationInstruction jci = new JobCreationInstruction(changeProcessor);
        prepareWfProcessChildJobInternal(jci);
        return jci;
    }

    public static JobCreationInstruction createWfProcessChildJob(Job parentJob) {
        JobCreationInstruction jci = new JobCreationInstruction(parentJob);
        prepareWfProcessChildJobInternal(jci);
        return jci;
    }

    protected static void prepareWfProcessChildJobInternal(JobCreationInstruction instruction) {
        instruction.setNoProcess(false);
        instruction.initializeCommonProcessVariables();
    }

    public static JobCreationInstruction createModelOperationChildJob(Job parentJob, ModelContext modelContext)
            throws SchemaException {
        JobCreationInstruction instruction = new JobCreationInstruction(parentJob);
        instruction.setNoProcess(true);
        instruction.addTaskModelContext(modelContext);
        instruction.setExecuteModelOperationHandler(true);
        return instruction;
    }
    //endregion

    // region Simple getters and setters
    public boolean isSimple() {
        return simple;
    }

    public void setSimple(boolean simple) {
        this.simple = simple;
    }

    public boolean isSendStartConfirmation() {
        return sendStartConfirmation;
    }

    public void setSendStartConfirmation(boolean sendStartConfirmation) {
        this.sendStartConfirmation = sendStartConfirmation;
    }

    public void setProcessDefinitionKey(String name) {
        processDefinitionKey = name;
    }

    public String getProcessDefinitionKey() {
        return processDefinitionKey;
    }

    public Map<String, Object> getProcessVariables() {
        return Collections.<String, Object>unmodifiableMap(processVariables);
    }

    public void addProcessVariable(String name, Serializable value) {
        processVariables.put(name, value);
    }

    private void removeProcessVariable(String name) {
        processVariables.remove(name);
    }

    public PolyStringType getTaskName() {
        return taskName;
    }

    public void setTaskName(PolyStringType taskName) {
        this.taskName = taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = new PolyStringType(taskName);
    }

    public boolean isNoProcess() {
        return noProcess;
    }

    public boolean startsWorkflowProcess() {
        return !noProcess;
    }

    public void setNoProcess(boolean noProcess) {
        this.noProcess = noProcess;
    }

    public void setCreateTaskAsSuspended(boolean createTaskAsSuspended) {
        this.createTaskAsSuspended = createTaskAsSuspended;
    }

    public boolean isCreateTaskAsSuspended() {
        return createTaskAsSuspended;
    }

    public List<UriStackEntry> getHandlersAfterModelOperation() {
        return handlersAfterModelOperation;
    }

    public List<UriStackEntry> getHandlersBeforeModelOperation() {
        return handlersBeforeModelOperation;
    }

    public List<UriStackEntry> getHandlersAfterWfProcess() {
        return handlersAfterWfProcess;
    }

    public Map<QName, Item> getTaskVariables() {
        return taskVariables;
    }

    public void setExecuteModelOperationHandler(boolean executeModelOperationHandler) {
        this.executeModelOperationHandler = executeModelOperationHandler;
    }

    public boolean isExecuteModelOperationHandler() {
        return executeModelOperationHandler;
    }

    public void setTaskObject(PrismObject taskObject) {
        this.taskObject = taskObject;
    }

    public PrismObject getTaskObject() {
        return taskObject;
    }

    public void setCreateTaskAsWaiting(boolean createTaskAsWaiting) {
        this.createTaskAsWaiting = createTaskAsWaiting;
    }

    public boolean isCreateTaskAsWaiting() {
        return createTaskAsWaiting;
    }

    public ChangeProcessor getChangeProcessor() {
        return changeProcessor;
    }

    public PrismObject<UserType> getTaskOwner() {
        return taskOwner;
    }

    public void setTaskOwner(PrismObject<UserType> taskOwner) {
        this.taskOwner = taskOwner;
    }
    //endregion

    //region Setters for handlers
    public void setHandlersBeforeModelOperation(String... handlerUri) {
        setHandlers(handlersBeforeModelOperation, createUriStackEntries(handlerUri));
    }

    public void setHandlersAfterModelOperation(String... handlerUri) {
        setHandlers(handlersAfterModelOperation, createUriStackEntries(handlerUri));
    }

    public void setHandlersAfterWfProcess(String... handlerUri) {
        setHandlers(handlersAfterWfProcess, createUriStackEntries(handlerUri));
    }

    public void addHandlersAfterWfProcessAtEnd(String... handlerUriArray) {
        addHandlersAtEnd(handlersAfterWfProcess, createUriStackEntries(handlerUriArray));
    }

    private List<UriStackEntry> createUriStackEntries(String[] handlerUriArray) {
        List<UriStackEntry> retval = new ArrayList<UriStackEntry>();
        for (String handlerUri : handlerUriArray) {
            retval.add(createUriStackEntry(handlerUri));
        }
        return retval;
    }

    private void addAtBeginningOfExecutionList(List<UriStackEntry> list, String handlerUri,
            TaskRecurrence recurrence, ScheduleType scheduleType, TaskBinding taskBinding) {
        list.add(0, createUriStackEntry(handlerUri, recurrence, scheduleType, taskBinding));
    }

    private void addAtEndOfExecutionList(List<UriStackEntry> list, String handlerUri, TaskRecurrence recurrence,
            ScheduleType scheduleType, TaskBinding taskBinding) {
        list.add(createUriStackEntry(handlerUri, recurrence, scheduleType, taskBinding));
    }

    private UriStackEntry createUriStackEntry(String handlerUri, TaskRecurrence recurrence,
            ScheduleType scheduleType, TaskBinding taskBinding) {
        UriStackEntry uriStackEntry = new UriStackEntry();
        uriStackEntry.setHandlerUri(handlerUri);
        uriStackEntry.setRecurrence(recurrence != null ? recurrence.toTaskType() : null);
        uriStackEntry.setSchedule(scheduleType);
        uriStackEntry.setBinding(taskBinding != null ? taskBinding.toTaskType() : null);
        return uriStackEntry;
    }

    private void setHandlers(List<UriStackEntry> list, List<UriStackEntry> uriStackEntry) {
        list.clear();
        list.addAll(uriStackEntry);
    }

    private void addHandlersAtEnd(List<UriStackEntry> list, List<UriStackEntry> uriStackEntry) {
        list.addAll(uriStackEntry);
    }

    private UriStackEntry createUriStackEntry(String handlerUri) {
        return createUriStackEntry(handlerUri, TaskRecurrence.SINGLE, new ScheduleType(), null);
    }
    //endregion

    //region Setters for task variables
    public <T> void addTaskVariable(PrismPropertyDefinition<T> definition, T realValue) {
        PrismProperty property = definition.instantiate();
        property.setRealValue(realValue);
        taskVariables.put(definition.getName(), property);
    }

    public <T> void addTaskVariableValues(PrismPropertyDefinition<T> definition, Collection<T> realValues) {
        PrismProperty<T> property = definition.instantiate();
        for (T realValue : realValues) {
            property.addRealValue(realValue);
        }
        taskVariables.put(definition.getName(), property);
    }

    public void addTaskModelContext(ModelContext modelContext) throws SchemaException {
        Validate.notNull(modelContext, "model context cannot be null");
        PrismContainer<LensContextType> modelContextPrism = ((LensContext) modelContext).toPrismContainer();
        taskVariables.put(modelContextPrism.getElementName(), modelContextPrism);
    }
    //endregion

    //region Setters for process variables
    public void initializeCommonProcessVariables() {
        addProcessVariable(CommonProcessVariableNames.VARIABLE_UTIL, new ActivitiUtil());
        addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR,
                changeProcessor.getClass().getName());
        addProcessVariable(CommonProcessVariableNames.VARIABLE_START_TIME, new Date());
    }

    public void setRequesterOidInProcess(PrismObject<UserType> requester) {
        addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID, requester.getOid());
    }

    public void setObjectOidInProcess(String objectOid) {
        if (objectOid != null) {
            addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID, objectOid);
        } else {
            removeProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID);
        }
    }

    public void setProcessInstanceName(String name) {
        addProcessVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME, name);
    }

    public void setProcessInterfaceBean(ProcessMidPointInterface processInterfaceBean) {
        addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME,
                processInterfaceBean.getBeanName());
    }
    //endregion

    //region Diagnostics
    public String toString() {
        return "JobCreationInstruction: processDefinitionKey = " + processDefinitionKey + ", simple: " + simple
                + ", variables: " + processVariables;
    }

    @Override
    public String debugDump() {
        return debugDump(0);
    }

    @Override
    public String debugDump(int indent) {
        StringBuilder sb = new StringBuilder();

        DebugUtil.indentDebugDump(sb, indent);
        sb.append("JobCreationInstruction: process: " + processDefinitionKey + " (" + (simple ? "simple" : "smart")
                + ", " + (noProcess ? "no-process" : "with-process") + "), task = " + taskName + "\n");

        if (!noProcess) {
            DebugUtil.indentDebugDump(sb, indent);
            sb.append("Process variables:\n");

            for (Map.Entry<String, Serializable> entry : processVariables.entrySet()) {
                DebugUtil.indentDebugDump(sb, indent);
                sb.append(" - " + entry.getKey() + " = ");
                Object value = entry.getValue();
                if (value instanceof DebugDumpable) {
                    sb.append("\n" + ((DebugDumpable) value).debugDump(indent + 1));
                } else {
                    sb.append(value != null ? value.toString() : "null");
                }
                sb.append("\n");
            }
        }
        return sb.toString();

    }
    //endregion

}