/* 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.List; import org.activiti.bpmn.model.FlowElement; import org.activiti.bpmn.model.FlowNode; import org.activiti.bpmn.model.FormProperty; import org.activiti.bpmn.model.FormValue; import org.activiti.bpmn.model.Process; import org.activiti.bpmn.model.SequenceFlow; import org.activiti.workflow.simple.converter.ConversionConstants; import org.activiti.workflow.simple.converter.WorkflowDefinitionConversion; import org.activiti.workflow.simple.definition.StepDefinition; import org.activiti.workflow.simple.definition.form.BooleanPropertyDefinition; import org.activiti.workflow.simple.definition.form.DatePropertyDefinition; import org.activiti.workflow.simple.definition.form.FormDefinition; import org.activiti.workflow.simple.definition.form.FormPropertyDefinition; import org.activiti.workflow.simple.definition.form.ListPropertyDefinition; import org.activiti.workflow.simple.definition.form.ListPropertyEntry; import org.activiti.workflow.simple.definition.form.NumberPropertyDefinition; import org.apache.commons.lang3.StringUtils; /** * Base class that can be used for {@link StepDefinitionConverter}, contains utility-methods. * * All {@link StepDefinitionConverter} should extend this class and implement any BPMN 2.0 xml * generation logic in the {@link #createProcessArtifact(StepDefinition, WorkflowDefinitionConversion)} method. * * The generation of additional artifacts should be done by overriding the {@link #createAdditionalArtifacts(Object)} * method adn adding the produced artifacts to the generic map on the {@link WorkflowDefinitionConversion}. * * @author Frederik Heremans * @author Joram Barrez */ public abstract class BaseStepDefinitionConverter<U extends StepDefinition, T> implements StepDefinitionConverter<U, T> { private static final long serialVersionUID = 1L; @SuppressWarnings("unchecked") public T convertStepDefinition(StepDefinition stepDefinition, WorkflowDefinitionConversion conversion) { U typedStepDefinition = (U) stepDefinition; T processArtifact = createProcessArtifact(typedStepDefinition, conversion); createAdditionalArtifacts(conversion, typedStepDefinition, processArtifact); return processArtifact; } /** * Subclasses must implement this method and create the BPMN 2.0 process artifact(s) for the provided step. */ protected abstract T createProcessArtifact(U stepDefinition, WorkflowDefinitionConversion conversion); /** * Subclasses should override this method if they want to create additional artifacts * for this specific step. The default generated process artifact is passed as parameter. */ protected void createAdditionalArtifacts(WorkflowDefinitionConversion conversion, U stepDefinition, T defaultGeneratedArtifact) { } /** * Adds a flow element to the {@link Process}. * A sequence flow will NOT automatically be added */ protected void addFlowElement(WorkflowDefinitionConversion conversion, FlowElement flowElement) { addFlowElement(conversion, flowElement, false); } protected void addFlowElement(WorkflowDefinitionConversion conversion, FlowElement flowElement, boolean addSequenceFlowToLastActivity) { if (conversion.isSequenceflowGenerationEnabled() && addSequenceFlowToLastActivity) { addSequenceFlow(conversion, conversion.getLastActivityId(), flowElement.getId()); } conversion.getProcess().addFlowElement(flowElement); if (conversion.isUpdateLastActivityEnabled()) { conversion.setLastActivityId(flowElement.getId()); } } protected SequenceFlow addSequenceFlow(WorkflowDefinitionConversion conversion, FlowNode sourceActivity, FlowNode targetActivity) { return addSequenceFlow(conversion, sourceActivity.getId(), targetActivity.getId()); } protected SequenceFlow addSequenceFlow(WorkflowDefinitionConversion conversion, String sourceActivityId, String targetActivityId) { return addSequenceFlow(conversion, sourceActivityId, targetActivityId, null); } /** * Add a sequence-flow to the current process from source to target. * Sequence-flow name is set to a user-friendly name, containing an * incrementing number. * * @param conversion * @param sourceActivityId * @param targetActivityId * @param condition */ protected SequenceFlow addSequenceFlow(WorkflowDefinitionConversion conversion, String sourceActivityId, String targetActivityId, String condition) { SequenceFlow sequenceFlow = new SequenceFlow(); sequenceFlow.setId(conversion.getUniqueNumberedId(getSequenceFlowPrefix())); sequenceFlow.setSourceRef(sourceActivityId); sequenceFlow.setTargetRef(targetActivityId); if (StringUtils.isNotEmpty(condition)) { sequenceFlow.setConditionExpression(condition); } conversion.getProcess().addFlowElement(sequenceFlow); return sequenceFlow; } // Subclasses can overwrite this if they want a different sequence flow prefix protected String getSequenceFlowPrefix() { return ConversionConstants.DEFAULT_SEQUENCEFLOW_PREFIX; } /** * Converts form properties. Multiple step types can contain forms, * hence why it it a shared method here. */ protected List<FormProperty> convertProperties(FormDefinition formDefinition) { List<FormProperty> formProperties = new ArrayList<FormProperty>(); for (FormPropertyDefinition propertyDefinition : formDefinition.getFormPropertyDefinitions()) { FormProperty formProperty = new FormProperty(); formProperties.add(formProperty); formProperty.setId(propertyDefinition.getName()); formProperty.setName(propertyDefinition.getName()); formProperty.setRequired(propertyDefinition.isMandatory()); String type = null; if (propertyDefinition instanceof NumberPropertyDefinition) { type = "long"; } else if (propertyDefinition instanceof DatePropertyDefinition) { type = "date"; } else if (propertyDefinition instanceof BooleanPropertyDefinition) { type = "boolean"; } else if (propertyDefinition instanceof ListPropertyDefinition) { type = "enum"; ListPropertyDefinition listDefinition = (ListPropertyDefinition) propertyDefinition; if (!listDefinition.getEntries().isEmpty()) { List<FormValue> formValues = new ArrayList<FormValue>(listDefinition.getEntries().size()); for (ListPropertyEntry entry : listDefinition.getEntries()) { FormValue formValue = new FormValue(); // We're using same value for id and name for the moment formValue.setId(entry.getValue()); formValue.setName(entry.getName()); formValues.add(formValue); } formProperty.setFormValues(formValues); } } else { // Fallback to simple text type = "string"; } formProperty.setType(type); } return formProperties; } }