Package org.activiti.workflow.simple.converter.step

Source Code of org.activiti.workflow.simple.converter.step.FeedbackStepDefinitionConverter

/* 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 org.activiti.workflow.simple.converter.step;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.activiti.bpmn.model.ActivitiListener;
import org.activiti.bpmn.model.BaseElement;
import org.activiti.bpmn.model.BoundaryEvent;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FieldExtension;
import org.activiti.bpmn.model.FormProperty;
import org.activiti.bpmn.model.ImplementationType;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.bpmn.model.ParallelGateway;
import org.activiti.bpmn.model.Signal;
import org.activiti.bpmn.model.SignalEventDefinition;
import org.activiti.bpmn.model.ThrowEvent;
import org.activiti.bpmn.model.UserTask;
import org.activiti.workflow.simple.converter.ConversionConstants;
import org.activiti.workflow.simple.converter.WorkflowDefinitionConversion;
import org.activiti.workflow.simple.definition.FeedbackStepDefinition;
import org.activiti.workflow.simple.definition.StepDefinition;
import org.activiti.workflow.simple.util.JvmUtil;


/**
* @author Joram Barrez
*/
public class FeedbackStepDefinitionConverter extends BaseStepDefinitionConverter<FeedbackStepDefinition, Map<String, BaseElement>> {
 
  private static final long serialVersionUID = 1L;
 
  private static final String SELECT_PEOPLE_USER_TASK = "initiatorSelectPeopleTask";
  private static final String FEEDBACK_FORK = "feedbackFork";
  private static final String FEEDBACK_JOIN = "feedbackJoin";
  private static final String FEEDBACK_USER_TASK = "gatherFeedback";
 
  public static final String VARIABLE_FEEDBACK_PROVIDERS = "feedbackProviders";
  public static final String VARIABLE_FEEDBACK_PROVIDER = "feedbackProvider";

  @Override
  public Class< ? extends StepDefinition> getHandledClass() {
    return FeedbackStepDefinition.class;
  }

  @Override
  protected Map<String, BaseElement> createProcessArtifact(FeedbackStepDefinition feedbackStepDefinition, WorkflowDefinitionConversion conversion) {

    // See feedback-step.png in the resource folder to get a graphical understanding of the conversion below
   
    Map<String, BaseElement> processElements = new HashMap<String, BaseElement>();
   
    // The first user task, responsible for configuring the feedback
    UserTask selectPeopleUserTask = createSelectPeopleUserTask(feedbackStepDefinition, conversion, processElements);
   
    // Parallel gateways (forking/joining)
    ParallelGateway fork = createForkParallelGateway(conversion, processElements);
    addSequenceFlow(conversion, selectPeopleUserTask, fork);
   
    // Gather feedback user task for the initiator of the feedback step
    UserTask gatherFeedbackUserTask = createGatherFeedbackUserTask(feedbackStepDefinition, conversion, processElements);
    addSequenceFlow(conversion, fork, gatherFeedbackUserTask);
   
    // Global signal event
    Signal signal = createSignalDeclaration(conversion);
   
    // Signal throw event after the gather feedback task
    ThrowEvent signalThrowEvent = createSignalThrow(conversion, signal);
    addSequenceFlow(conversion, gatherFeedbackUserTask, signalThrowEvent);
   
    // Povide feedback step
    UserTask feedbackTask = createFeedbackUserTask(feedbackStepDefinition, conversion, processElements);
    addSequenceFlow(conversion, fork, feedbackTask);
   
    // Boundary signal catch to shut down all tasks if the 'gather feedback' task is completed
    BoundaryEvent boundarySignalCatch = createBoundarySignalCatch(conversion, signal, feedbackTask);
   
    // Exclusive gateway after the feedback task, needed to correctly merge the sequence flow
    // such that the joining parallel gateway has exactly two incoming sequence flow
    ExclusiveGateway mergingExclusiveGateway = createMergingExclusiveGateway(conversion);
    addSequenceFlow(conversion, feedbackTask, mergingExclusiveGateway);
    addSequenceFlow(conversion, boundarySignalCatch, mergingExclusiveGateway);
   
    // Parallel gateway that will join  it all together
    ParallelGateway join = createJoinParallelGateway(conversion, processElements);
    addSequenceFlow(conversion, signalThrowEvent, join);
    addSequenceFlow(conversion, mergingExclusiveGateway, join);
   
    // Set the last activity id, such that next steps can connect correctly
    conversion.setLastActivityId(join.getId());
   
    return processElements;
  }

  protected UserTask createSelectPeopleUserTask(FeedbackStepDefinition feedbackStepDefinition, WorkflowDefinitionConversion conversion,
          Map<String, BaseElement> processElements) {
    UserTask selectPeopleUserTask = new UserTask();
    selectPeopleUserTask.setId(conversion.getUniqueNumberedId(ConversionConstants.USER_TASK_ID_PREFIX));
    selectPeopleUserTask.setName(getSelectPeopleTaskName());
    selectPeopleUserTask.setAssignee(feedbackStepDefinition.getFeedbackInitiator());
    addFlowElement(conversion, selectPeopleUserTask, true);
    processElements.put(SELECT_PEOPLE_USER_TASK, selectPeopleUserTask);
   
    // TODO: work out form such that it can be used in Activiti Explorer, ie. add correct form properties
    // The following is just a a bit of a dummy form property
    FormProperty feedbackProvidersProperty = new FormProperty();
    feedbackProvidersProperty.setId(VARIABLE_FEEDBACK_PROVIDERS);
    feedbackProvidersProperty.setName("Who needs to provide feedback?");
    feedbackProvidersProperty.setRequired(true);
    feedbackProvidersProperty.setType("string"); // TODO: we need some kind of 'people' property type here
   
    selectPeopleUserTask.setFormProperties(Arrays.asList(feedbackProvidersProperty));
   
    // When the list of feedback providers is fixed up front, we need to add a script listener
    // that injects these variables into the process (instead of having it provided by the end user in a form)
    if (feedbackStepDefinition.getFeedbackProviders() != null && !feedbackStepDefinition.getFeedbackProviders()
                                                                                        .isEmpty()) {
      if (selectPeopleUserTask.getTaskListeners() == null)
      {
        selectPeopleUserTask.setTaskListeners(new ArrayList<ActivitiListener>());
      }
     
      ActivitiListener taskListener = new ActivitiListener();
      taskListener.setEvent("complete");
      taskListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS);
      taskListener.setImplementation("org.activiti.engine.impl.bpmn.listener.ScriptTaskListener");
     
      FieldExtension languageField = new FieldExtension();
      languageField.setFieldName("language");
      languageField.setStringValue("JavaScript");
     
      FieldExtension scriptField = new FieldExtension();
      scriptField.setFieldName("script");
     
      StringBuilder script = new StringBuilder();
      if (JvmUtil.isJDK8()) {
        script.append("load(\"nashorn:mozilla_compat.js\");");
      }
      script.append("importPackage (java.util); var feedbackProviders = new ArrayList();" + System.getProperty("line.separator"));
      for (String feedbackProvider : feedbackStepDefinition.getFeedbackProviders()) {
        script.append("feedbackProviders.add('" + feedbackProvider + "');" + System.getProperty("line.separator"));
      }
      script.append("task.getExecution().setVariable('" + VARIABLE_FEEDBACK_PROVIDERS + "', feedbackProviders);" + System.getProperty("line.separator"));
      scriptField.setStringValue(script.toString());

      taskListener.setFieldExtensions(Arrays.asList(languageField, scriptField));
     
      selectPeopleUserTask.getTaskListeners().add(taskListener);
    }
   
   
    return selectPeopleUserTask;
  }

  protected ParallelGateway createForkParallelGateway(WorkflowDefinitionConversion conversion, Map<String, BaseElement> processElements) {
    ParallelGateway fork = new ParallelGateway();
    fork.setId(conversion.getUniqueNumberedId(ConversionConstants.GATEWAY_ID_PREFIX));
    addFlowElement(conversion, fork);
    processElements.put(FEEDBACK_FORK, fork);
    return fork;
  }

  protected UserTask createGatherFeedbackUserTask(FeedbackStepDefinition feedbackStepDefinition, WorkflowDefinitionConversion conversion,
          Map<String, BaseElement> processElements) {
    UserTask gatherFeedbackUserTask = new UserTask();
    gatherFeedbackUserTask.setId(conversion.getUniqueNumberedId(ConversionConstants.USER_TASK_ID_PREFIX));
    gatherFeedbackUserTask.setName(getGatherFeedbackTaskName());
    gatherFeedbackUserTask.setAssignee(feedbackStepDefinition.getFeedbackInitiator());
    addFlowElement(conversion, gatherFeedbackUserTask);
    processElements.put(SELECT_PEOPLE_USER_TASK, gatherFeedbackUserTask);
    return gatherFeedbackUserTask;
  }

  protected Signal createSignalDeclaration(WorkflowDefinitionConversion conversion) {
    Signal signal = new Signal();
    String uniqueSignalId = "signal-" + UUID.randomUUID().toString();
    signal.setId(uniqueSignalId);
    signal.setName(uniqueSignalId);
    signal.setScope(Signal.SCOPE_PROCESS_INSTANCE);
   
    conversion.getBpmnModel().addSignal(signal);
   
    return signal;
  }

  protected ThrowEvent createSignalThrow(WorkflowDefinitionConversion conversion, Signal signal) {
    ThrowEvent signalThrowEvent = new ThrowEvent();
    signalThrowEvent.setId(conversion.getUniqueNumberedId(ConversionConstants.EVENT_ID_PREFIX));
   
    SignalEventDefinition signalThrowEventDefinition = new SignalEventDefinition();
    signalThrowEventDefinition.setSignalRef(signal.getId());
    signalThrowEvent.addEventDefinition(signalThrowEventDefinition);
   
    addFlowElement(conversion, signalThrowEvent);
   
    return signalThrowEvent;
  }

  protected ParallelGateway createJoinParallelGateway(WorkflowDefinitionConversion conversion, Map<String, BaseElement> processElements) {
    ParallelGateway join = new ParallelGateway();
    join.setId(conversion.getUniqueNumberedId(ConversionConstants.GATEWAY_ID_PREFIX));
    addFlowElement(conversion, join);
    processElements.put(FEEDBACK_JOIN, join);
    return join;
  }

  protected UserTask createFeedbackUserTask(FeedbackStepDefinition feedbackStepDefinition, WorkflowDefinitionConversion conversion,
          Map<String, BaseElement> processElements) {
    UserTask feedbackTask = new UserTask();
    feedbackTask.setId(conversion.getUniqueNumberedId(ConversionConstants.USER_TASK_ID_PREFIX));
    feedbackTask.setName(getProvideFeedbackTaskName());
    feedbackTask.setAssignee("${" + VARIABLE_FEEDBACK_PROVIDER + "}");
   
    MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
    multiInstanceLoopCharacteristics.setSequential(false);
    multiInstanceLoopCharacteristics.setInputDataItem(VARIABLE_FEEDBACK_PROVIDERS);
    multiInstanceLoopCharacteristics.setElementVariable(VARIABLE_FEEDBACK_PROVIDER);
    feedbackTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
   
    addFlowElement(conversion, feedbackTask);
    processElements.put(FEEDBACK_USER_TASK, feedbackTask);
    return feedbackTask;
  }

  protected BoundaryEvent createBoundarySignalCatch(WorkflowDefinitionConversion conversion, Signal signal, UserTask feedbackTask) {
    BoundaryEvent boundarySignalCatch = new BoundaryEvent();
    boundarySignalCatch.setId(conversion.getUniqueNumberedId(ConversionConstants.BOUNDARY_ID_PREFIX));
    boundarySignalCatch.setAttachedToRef(feedbackTask);
    boundarySignalCatch.setAttachedToRefId(feedbackTask.getId());
    boundarySignalCatch.setCancelActivity(true);
    addFlowElement(conversion, boundarySignalCatch);
   
    SignalEventDefinition signalCatchEventDefinition = new SignalEventDefinition();
    signalCatchEventDefinition.setSignalRef(signal.getId());
    boundarySignalCatch.addEventDefinition(signalCatchEventDefinition);
    return boundarySignalCatch;
  }

  protected ExclusiveGateway createMergingExclusiveGateway(WorkflowDefinitionConversion conversion) {
    ExclusiveGateway mergingExclusiveGateway = new ExclusiveGateway();
    mergingExclusiveGateway.setId(conversion.getUniqueNumberedId(ConversionConstants.GATEWAY_ID_PREFIX));
    addFlowElement(conversion, mergingExclusiveGateway);
    return mergingExclusiveGateway;
  }
 
 
  // The following are default task names and can be overidden by subclasses
 
  protected String getSelectPeopleTaskName() {
    return "Choose people";
  }
 
  protected String getProvideFeedbackTaskName() {
    return "Provide feedback";
  }
 
  protected String getGatherFeedbackTaskName() {
    return "Gather feedback";
  }
 
}
TOP

Related Classes of org.activiti.workflow.simple.converter.step.FeedbackStepDefinitionConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.