package org.jbpm.simulation.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import bpsim.*;
import org.eclipse.bpmn2.BoundaryEvent;
import org.eclipse.bpmn2.BusinessRuleTask;
import org.eclipse.bpmn2.CancelEventDefinition;
import org.eclipse.bpmn2.CompensateEventDefinition;
import org.eclipse.bpmn2.ConditionalEventDefinition;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.EndEvent;
import org.eclipse.bpmn2.ErrorEventDefinition;
import org.eclipse.bpmn2.EventDefinition;
import org.eclipse.bpmn2.ExclusiveGateway;
import org.eclipse.bpmn2.ExtensionAttributeValue;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.FlowElementsContainer;
import org.eclipse.bpmn2.InclusiveGateway;
import org.eclipse.bpmn2.IntermediateCatchEvent;
import org.eclipse.bpmn2.IntermediateThrowEvent;
import org.eclipse.bpmn2.LinkEventDefinition;
import org.eclipse.bpmn2.ManualTask;
import org.eclipse.bpmn2.MessageEventDefinition;
import org.eclipse.bpmn2.ParallelGateway;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.ReceiveTask;
import org.eclipse.bpmn2.Relationship;
import org.eclipse.bpmn2.RootElement;
import org.eclipse.bpmn2.ScriptTask;
import org.eclipse.bpmn2.SendTask;
import org.eclipse.bpmn2.ServiceTask;
import org.eclipse.bpmn2.SignalEventDefinition;
import org.eclipse.bpmn2.StartEvent;
import org.eclipse.bpmn2.TimerEventDefinition;
import org.eclipse.bpmn2.UserTask;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.jbpm.simulation.SimulationDataProvider;
import org.jbpm.simulation.util.BPMN2Utils;
import org.jbpm.simulation.util.SimulationConstants;
import org.kie.api.definition.process.Node;
public class BPMN2SimulationDataProvider implements SimulationDataProvider {
private Definitions def;
public BPMN2SimulationDataProvider(Definitions def) {
this.def = def;
}
public BPMN2SimulationDataProvider(String bpmn2xml) {
this.def = BPMN2Utils.getDefinitions(new ByteArrayInputStream(getBytes(bpmn2xml)));
}
public BPMN2SimulationDataProvider(InputStream bpmn2Stream) {
this.def = BPMN2Utils.getDefinitions(bpmn2Stream);
}
public Map<String, Object> getSimulationDataForNode(Node node) {
String nodeId = (String) node.getMetaData().get("UniqueId");
return getSimulationDataForNode(nodeId);
}
public Map<String, Object> getSimulationDataForNode(
String nodeId) {
Map<String, Object> properties = new HashMap<String, Object>();
Scenario scenario = getDefaultScenario(def);
if(scenario != null) {
String baseTimeUnitValue = "";
String baseCurrencyUnitValue = "";
if(scenario.getScenarioParameters() != null) {
baseCurrencyUnitValue = scenario.getScenarioParameters().getBaseCurrencyUnit();
baseTimeUnitValue = scenario.getScenarioParameters().getBaseTimeUnit().getName();
}
if(scenario.getElementParameters() != null) {
for(ElementParameters eleType : scenario.getElementParameters()) {
if(eleType.getElementRef().equals(nodeId)) {
if(eleType.getControlParameters() != null && eleType.getControlParameters().getProbability() != null) {
FloatingParameterType valType = (FloatingParameterType) eleType.getControlParameters().getProbability().getParameterValue().get(0);
properties.put("probability", valType.getValue());
}
if(eleType.getTimeParameters() != null) {
if(eleType.getTimeParameters().getProcessingTime() != null) {
Parameter processingTime = eleType.getTimeParameters().getProcessingTime();
ParameterValue paramValue = processingTime.getParameterValue().get(0);
if(paramValue instanceof NormalDistributionType) {
NormalDistributionType ndt = (NormalDistributionType) paramValue;
properties.put("mean", ndt.getMean());
properties.put("standarddeviation", ndt.getStandardDeviation());
properties.put("distributiontype", "normal");
} else if(paramValue instanceof UniformDistributionType) {
UniformDistributionType udt = (UniformDistributionType) paramValue;
properties.put("max", udt.getMax());
properties.put("min", udt.getMin());
properties.put("distributiontype", "uniform");
// random distribution not supported in bpsim 1.0
// } else if(paramValue instanceof RandomDistributionType) {
// RandomDistributionType rdt = (RandomDistributionType) paramValue;
// properties.put("max", rdt.getMax());
// properties.put("min", rdt.getMin());
// properties.put("distributiontype", "random");
} else if(paramValue instanceof PoissonDistributionType) {
PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
properties.put("mean", pdt.getMean());
properties.put("distributiontype", "poisson");
}
properties.put("timeunit", baseTimeUnitValue);
if(eleType.getTimeParameters().getWaitTime() != null) {
FloatingParameterType waittimeType = (FloatingParameterType) eleType.getTimeParameters().getWaitTime().getParameterValue().get(0);
properties.put("waittime", waittimeType.getValue());
}
}
}
if(eleType.getCostParameters() != null) {
CostParameters costParams = eleType.getCostParameters();
if(costParams.getUnitCost() != null) {
FloatingParameterType unitCostVal = (FloatingParameterType) costParams.getUnitCost().getParameterValue().get(0);
properties.put("unitcost", unitCostVal.getValue());
}
properties.put("currency", baseCurrencyUnitValue);
}
if(eleType.getResourceParameters() != null) {
ResourceParameters resourceParams = eleType.getResourceParameters();
if(resourceParams.getQuantity() != null) {
FloatingParameterType quantityVal = (FloatingParameterType) resourceParams.getQuantity().getParameterValue().get(0);
properties.put("quantity", quantityVal.getValue());
}
if(resourceParams.getAvailability() != null) {
FloatingParameterType workingHoursVal = (FloatingParameterType) resourceParams.getAvailability().getParameterValue().get(0);
properties.put("workinghours", workingHoursVal.getValue());
}
}
}
}
}
}
return properties;
}
protected FlowElement findElementInContainer(FlowElementsContainer container, String id) {
List<FlowElement> currentContainerElems = container.getFlowElements();
for (FlowElement fElement : currentContainerElems) {
if (fElement.getId().equals(id) ) {
return fElement;
} else if (fElement instanceof FlowElementsContainer) {
FlowElement fe = findElementInContainer((FlowElementsContainer) fElement, id);
if (fe != null) {
return fe;
}
}
}
return null;
}
public double calculatePathProbability(SimulationPath path) {
double probability = 100;
for (String sequenceFlowId : path.getSequenceFlowsIds()) {
double transitionProbability = (Double) getSimulationDataForNode(sequenceFlowId).get(SimulationConstants.PROBABILITY);
if (transitionProbability > 0) {
probability = probability * (transitionProbability / 100);
}
}
// calculate probability based on boundary events
for (String sequenceFlowId : path.getBoundaryEventIds()) {
double transitionProbability = (Double) getSimulationDataForNode(sequenceFlowId).get(SimulationConstants.PROBABILITY);
if (transitionProbability > 0) {
probability = probability * (transitionProbability / 100);
}
}
double result = probability / 100;
path.setProbability(result);
return result;
}
public Map<String, Object> getProcessDataForNode(Node node) {
Map<String, Object> nodeProperties = new HashMap<String, Object>();
FlowElement flowElement = null;
List<RootElement> rootElements = def.getRootElements();
for (RootElement root : rootElements) {
if (root instanceof Process) {
flowElement = findElementInContainer((FlowElementsContainer) root, (String) node.getMetaData().get("UniqueId"));
break;
}
}
if (flowElement != null) {
if (flowElement instanceof ScriptTask) {
nodeProperties.put("node.type", "ScriptTask");
} else if (flowElement instanceof BusinessRuleTask) {
nodeProperties.put("node.type", "BusinessRuleTask");
} else if (flowElement instanceof UserTask) {
nodeProperties.put("node.type", "UserTask");
} else if (flowElement instanceof SendTask) {
nodeProperties.put("node.type", "SendTask");
} else if (flowElement instanceof ServiceTask) {
nodeProperties.put("node.type", "ServiceTask");
} else if (flowElement instanceof ReceiveTask) {
nodeProperties.put("node.type", "ReceiveTask");
} else if (flowElement instanceof ManualTask) {
nodeProperties.put("node.type", "ManualTask");
} else if (flowElement instanceof InclusiveGateway) {
nodeProperties.put("node.type", "InclusiveGateway");
} else if (flowElement instanceof ExclusiveGateway) {
nodeProperties.put("node.type", "ExclusiveGateway");
} else if (flowElement instanceof ParallelGateway) {
nodeProperties.put("node.type", "ParallelGateway");
} else if (flowElement instanceof BoundaryEvent) {
BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
List<EventDefinition> defs = boundaryEvent.getEventDefinitions();
String eventDef = "";
if (defs != null && defs.size() > 0) {
eventDef = getEventDefinitionAsString(defs.get(0));
}
nodeProperties.put("node.type", "BoundaryEvent:"+eventDef);
} else if (flowElement instanceof IntermediateCatchEvent) {
IntermediateCatchEvent boundaryEvent = (IntermediateCatchEvent) flowElement;
List<EventDefinition> defs = boundaryEvent.getEventDefinitions();
String eventDef = "";
if (defs != null && defs.size() > 0) {
eventDef = getEventDefinitionAsString(defs.get(0));
}
nodeProperties.put("node.type", "IntermediateCatchEvent:"+eventDef);
} else if (flowElement instanceof IntermediateThrowEvent) {
IntermediateThrowEvent boundaryEvent = (IntermediateThrowEvent) flowElement;
List<EventDefinition> defs = boundaryEvent.getEventDefinitions();
String eventDef = "";
if (defs != null && defs.size() > 0) {
eventDef = getEventDefinitionAsString(defs.get(0));
}
nodeProperties.put("node.type", "IntermediateThrowEvent:"+eventDef);
} else if (flowElement instanceof StartEvent) {
StartEvent boundaryEvent = (StartEvent) flowElement;
List<EventDefinition> defs = boundaryEvent.getEventDefinitions();
String eventDef = "";
if (defs != null && defs.size() > 0) {
eventDef = getEventDefinitionAsString(defs.get(0));
}
nodeProperties.put("node.type", "StartEvent:"+eventDef);
} else if (flowElement instanceof EndEvent) {
EndEvent boundaryEvent = (EndEvent) flowElement;
List<EventDefinition> defs = boundaryEvent.getEventDefinitions();
String eventDef = "";
if (defs != null && defs.size() > 0) {
eventDef = getEventDefinitionAsString(defs.get(0));
}
nodeProperties.put("node.type", "EndEvent:"+eventDef);
}
} else {
nodeProperties.put("node.type", "unknown");
}
return nodeProperties;
}
private static byte[] getBytes(String string) {
try {
return string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
private Scenario getDefaultScenario(Definitions def) {
if(def.getRelationships() != null && def.getRelationships().size() > 0) {
// current support for single relationship
Relationship relationship = def.getRelationships().get(0);
for(ExtensionAttributeValue extattrval : relationship.getExtensionValues()) {
FeatureMap extensionElements = extattrval.getValue();
@SuppressWarnings("unchecked")
List<BPSimDataType> bpsimExtension = (List<BPSimDataType>) extensionElements.get(BpsimPackage.Literals.DOCUMENT_ROOT__BP_SIM_DATA, true);
if(bpsimExtension != null && bpsimExtension.size() > 0) {
BPSimDataType bpmsim = bpsimExtension.get(0);
if(bpmsim.getScenario() != null && bpmsim.getScenario().size() > 0) {
return bpmsim.getScenario().get(0);
}
}
}
}
return null;
}
protected String getEventDefinitionAsString(EventDefinition eventDefinition) {
if (eventDefinition instanceof SignalEventDefinition) {
return "signalEventDefinition";
} else if (eventDefinition instanceof MessageEventDefinition) {
return "messageEventDefinition";
} else if (eventDefinition instanceof LinkEventDefinition) {
return "linkEventDefinition";
} else if (eventDefinition instanceof CompensateEventDefinition) {
return "compensateEventDefinition";
} else if (eventDefinition instanceof ErrorEventDefinition) {
return "errorEventDefinition";
} else if (eventDefinition instanceof TimerEventDefinition) {
return "timerEventDefinition";
} else if (eventDefinition instanceof ConditionalEventDefinition) {
return "conditionalEventDefinition";
} else if (eventDefinition instanceof CancelEventDefinition) {
return "cancelEventDefinition";
}
return "unknown";
}
}