/* 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;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.workflow.simple.converter.listener.WorkflowDefinitionConversionListener;
import org.activiti.workflow.simple.converter.step.StepDefinitionConverter;
import org.activiti.workflow.simple.definition.ListStepDefinition;
import org.activiti.workflow.simple.definition.ParallelStepsDefinition;
import org.activiti.workflow.simple.definition.StepDefinition;
import org.activiti.workflow.simple.definition.WorkflowDefinition;
import org.activiti.workflow.simple.exception.SimpleWorkflowException;
/**
* Instances of this class are created by a {@link WorkflowDefinitionConversionFactory}.
*
* An instance of this class is capabale of doing the actual conversion of a {@link WorkflowDefinition}
* and it will contain all artifacts produces by the {@link StepDefinitionConverter} objects and
* {@link WorkflowDefinitionConversionListener} which were injected into
* the {@link WorkflowDefinitionConversionFactory}.
*
* @author Frederik Heremans
* @author Joram Barrez
*/
public class WorkflowDefinitionConversion {
// Input
protected WorkflowDefinition workflowDefinition;
// Artifacts of the conversion
protected BpmnModel bpmnModel;
protected Process process;
/**
* It is assumed the conversion will always create a {@link BpmnModel} and a {@link Process}
* (altough, strictly even that is pluggable). Other artifacts that are produced
* during conversion are stored in this generic map.
*/
protected Map<String, Object> additionalArtifacts;
// Helper members
protected WorkflowDefinitionConversionFactory conversionFactory;
protected String lastActivityId;
protected HashMap<String, Integer> incrementalIdMapping;
// Properties to influence the conversion
protected boolean sequenceflowGenerationEnabled = true;
protected boolean updateLastActivityEnabled = true;
/* package */
WorkflowDefinitionConversion(WorkflowDefinitionConversionFactory factory) {
this.conversionFactory = factory;
}
public WorkflowDefinitionConversion(WorkflowDefinitionConversionFactory factory, WorkflowDefinition workflowDefinition) {
this(factory);
this.workflowDefinition = workflowDefinition;
}
/**
* Call this method to actually execute the conversion of the {@link WorkflowDefinition}
* which was provided in the constructor.
*/
public void convert() {
if (workflowDefinition == null) {
throw new SimpleWorkflowException("Cannot start conversion: need to set a WorkflowDefinition first!");
}
this.incrementalIdMapping = new HashMap<String, Integer>();
this.additionalArtifacts = new HashMap<String, Object>();
// Create new process
bpmnModel = new BpmnModel();
process = new Process();
bpmnModel.addProcess(process);
// Let conversion listeners know initialization is finished
if (conversionFactory.getAllWorkflowDefinitionConversionListeners() != null) {
for (WorkflowDefinitionConversionListener conversionListener : conversionFactory.getAllWorkflowDefinitionConversionListeners()) {
conversionListener.beforeStepsConversion(this);
}
}
// Convert each step
convertSteps(workflowDefinition.getSteps());
// Let conversion listeners know step conversion is done
if (conversionFactory.getAllWorkflowDefinitionConversionListeners() != null) {
for (WorkflowDefinitionConversionListener conversionListener : conversionFactory.getAllWorkflowDefinitionConversionListeners()) {
conversionListener.afterStepsConversion(this);
}
}
// Add DI information to bpmn model
BpmnAutoLayout bpmnAutoLayout = new BpmnAutoLayout(bpmnModel);
bpmnAutoLayout.execute();
}
public void convertSteps(List<StepDefinition> stepDefinitions) {
for (StepDefinition step : stepDefinitions) {
conversionFactory.getStepConverterFor(step).convertStepDefinition(step, this);
}
}
public void convertListParallelSteps(List<ListStepDefinition<ParallelStepsDefinition>> stepDefinitions) {
for (ListStepDefinition<ParallelStepsDefinition> step : stepDefinitions) {
conversionFactory.getStepConverterFor(step).convertStepDefinition(step, this);
}
}
/**
* @param baseName
* base name of the unique identifier
* @return a string that can be used as a unique id. Eg. if a baseName with
* value "userTask" is passed, the first time "userTask1" will be
* returned. When called agian with the same baseName, "userTask2" is
* returned. Counts are incremented for each baseName independently
* withing this context instance.
*/
public String getUniqueNumberedId(String baseName) {
Integer index = incrementalIdMapping.get(baseName);
if (index == null) {
index = 1;
incrementalIdMapping.put(baseName, index);
} else {
index = index + 1;
incrementalIdMapping.put(baseName, index);
}
return baseName + index;
}
/**
* @return id of the activity that is at the end of the current process. Used
* to add additional steps and sequence-flows to the process.
*/
public String getLastActivityId() {
return this.lastActivityId;
}
/**
* @param lastActivityId
* id of the activity that is at the end of the current process. Used
* to add additional steps and sequence-flows to the process.
*/
public void setLastActivityId(String lastActivityId) {
this.lastActivityId = lastActivityId;
}
public BpmnModel getBpmnModel() {
return bpmnModel;
}
public void setBpmnModel(BpmnModel bpmnModel) {
this.bpmnModel = bpmnModel;
}
public Process getProcess() {
return process;
}
public void setProcess(Process process) {
this.process = process;
}
public Object getArtifact(String artifactKey) {
return additionalArtifacts.get(artifactKey);
}
public Map<String, Object> getAdditionalArtifacts() {
return additionalArtifacts;
}
public void setArtifact(String artifactKey, Object artifact) {
additionalArtifacts.put(artifactKey, artifact);
}
public WorkflowDefinition getWorkflowDefinition() {
return workflowDefinition;
}
public void setWorkflowDefinition(WorkflowDefinition workflowDefinition) {
this.workflowDefinition = workflowDefinition;
}
public boolean isSequenceflowGenerationEnabled() {
return sequenceflowGenerationEnabled;
}
public void setSequenceflowGenerationEnabled(boolean sequenceflowGenerationEnabled) {
this.sequenceflowGenerationEnabled = sequenceflowGenerationEnabled;
}
public boolean isUpdateLastActivityEnabled() {
return updateLastActivityEnabled;
}
public void setUpdateLastActivityEnabled(boolean updateLastActivityEnabled) {
this.updateLastActivityEnabled = updateLastActivityEnabled;
}
public WorkflowDefinitionConversionFactory getConversionFactory() {
return conversionFactory;
}
/**
* Returns the BPMN 2.0 xml which is the converted version of the
* provided {@link WorkflowDefinition}.
*/
public String getBpmn20Xml() {
if (bpmnModel == null) {
convert();
}
BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
return new String(bpmnXMLConverter.convertToXML(bpmnModel));
}
}