use of de.hpi.bpt.scylla.model.process.node.EventType in project scylla by bptlab.
the class ProcessModelParser method parseProcess.
private ProcessModel parseProcess(Element process, Namespace bpmnNamespace, boolean hasParentModel, CommonProcessElements commonProcessElements) throws ScyllaValidationException {
if (!hasParentModel && process.getChildren("startEvent", bpmnNamespace).size() == 0) {
throw new ScyllaValidationException("No start event in the top process.");
}
String processId = process.getAttributeValue("id");
String processName = process.getAttributeValue("name");
Graph<Integer> graph = new Graph<Integer>();
Map<Integer, String> identifiers = new HashMap<Integer, String>();
Map<String, Integer> identifiersToNodeIds = new HashMap<String, Integer>();
Map<Integer, String> displayNames = new HashMap<Integer, String>();
// node id must be key of any of the following
Map<Integer, ProcessModel> subProcesses = new HashMap<Integer, ProcessModel>();
Map<Integer, String> calledElementsOfCallActivities = new HashMap<Integer, String>();
Map<Integer, TaskType> tasks = new HashMap<Integer, TaskType>();
Map<Integer, GatewayType> gateways = new HashMap<Integer, GatewayType>();
Map<Integer, EventType> eventTypes = new HashMap<Integer, EventType>();
// optional
Map<Integer, Map<String, String>> nodeAttributes = new HashMap<Integer, Map<String, String>>();
Map<Integer, String> conditionExpressions = new HashMap<Integer, String>();
Map<Integer, Set<String>> resourceReferences = new HashMap<Integer, Set<String>>();
Map<Integer, Map<EventDefinitionType, Map<String, String>>> eventDefinitions = new HashMap<Integer, Map<EventDefinitionType, Map<String, String>>>();
Map<Integer, Boolean> cancelActivities = new HashMap<Integer, Boolean>();
Map<Integer, List<Integer>> referencesToBoundaryEvents = new HashMap<Integer, List<Integer>>();
Map<Integer, BatchActivity> batchActivities = new HashMap<Integer, BatchActivity>();
// TODO support more than standard data objects (i.e. support input, output)
Graph<Integer> dataObjectsGraph = new Graph<Integer>();
Map<Integer, String> dataObjectReferences = new HashMap<Integer, String>();
Map<Integer, DataObjectType> dataObjectTypes = new HashMap<Integer, DataObjectType>();
// TODO parse loop / multi instance elements
Map<Integer, Element> boundaryEvents = new HashMap<Integer, Element>();
Map<Integer, Element> sequenceFlows = new HashMap<Integer, Element>();
// not only tasks anymore, also events
Map<Integer, List<Element>> tasksWithDataInputAssociations = new HashMap<Integer, List<Element>>();
// not only tasks anymore, also events
Map<Integer, List<Element>> tasksWithDataOutputAssociations = new HashMap<Integer, List<Element>>();
int nodeId = 1;
for (Element el : process.getChildren()) {
String elementName = el.getName();
if (isKnownElement(elementName)) {
String identifier = el.getAttributeValue("id");
identifiers.put(nodeId, identifier);
identifiersToNodeIds.put(identifier, nodeId);
String displayName = el.getAttributeValue("name");
if (displayName != null && !displayName.isEmpty()) {
displayNames.put(nodeId, displayName);
}
if (elementName.equals("sequenceFlow")) {
// just store them for now, use later to build graph
sequenceFlows.put(nodeId, el);
// store expressions after gateway conditions
Element conditionExpression = el.getChild("conditionExpression", bpmnNamespace);
if (conditionExpression != null) {
conditionExpressions.put(nodeId, conditionExpression.getText());
}
} else if (elementName.equals("subProcess")) {
batchActivities = parseExtensions(el, bpmnNamespace, nodeId, batchActivities);
ProcessModel subProcessModel = parseProcess(el, bpmnNamespace, true, commonProcessElements);
subProcesses.put(nodeId, subProcessModel);
} else if (elementName.equals("callActivity")) {
String calledElement = el.getAttributeValue("calledElement");
if (calledElement != null) {
calledElementsOfCallActivities.put(nodeId, calledElement);
}
} else if (elementName.equals("task") || elementName.endsWith("Task")) {
batchActivities = parseExtensions(el, bpmnNamespace, nodeId, batchActivities);
tasks.put(nodeId, TaskType.getEnum(el.getName()));
if (elementName.equals("userTask") || elementName.equals("manualTask")) {
String[] resourceElementNames = new String[] { "resourceRole", "performer", "humanPerformer", "potentialOwner" };
for (String ren : resourceElementNames) {
Element elem = el.getChild(ren, bpmnNamespace);
if (elem != null) {
String resourceRefOrAssignmentExpression = null;
Element resourceRefElement = elem.getChild("resourceRef", bpmnNamespace);
if (resourceRefElement != null) {
resourceRefOrAssignmentExpression = resourceRefElement.getText();
}
Element resourceAssignmentExpressionElement = elem.getChild("resourceAssignmentExpression", bpmnNamespace);
if (resourceAssignmentExpressionElement != null) {
resourceRefOrAssignmentExpression = resourceAssignmentExpressionElement.getText();
}
if (resourceRefOrAssignmentExpression != null) {
if (!resourceReferences.containsKey(nodeId)) {
resourceReferences.put(nodeId, new TreeSet<String>());
}
resourceReferences.get(nodeId).add(resourceRefOrAssignmentExpression);
break;
}
}
}
}
List<Element> dataInElements = el.getChildren("dataInputAssociation", bpmnNamespace);
if (!dataInElements.isEmpty()) {
tasksWithDataInputAssociations.put(nodeId, dataInElements);
}
List<Element> dataOutElements = el.getChildren("dataOutputAssociation", bpmnNamespace);
if (!dataOutElements.isEmpty()) {
tasksWithDataOutputAssociations.put(nodeId, dataOutElements);
}
} else if (elementName.endsWith("Gateway") || elementName.equals("gateway")) {
gateways.put(nodeId, GatewayType.getEnum(el.getName()));
Map<String, String> gatewayAttributes = new HashMap<String, String>();
String defaultFlow = el.getAttributeValue("default");
if (defaultFlow != null) {
gatewayAttributes.put("default", defaultFlow);
}
String gatewayDirection = el.getAttributeValue("gatewayDirection");
if (gatewayDirection != null) {
gatewayAttributes.put("gatewayDirection", gatewayDirection);
}
nodeAttributes.put(nodeId, gatewayAttributes);
} else if (elementName.endsWith("Event") || elementName.equals("event")) {
eventTypes.put(nodeId, EventType.getEnum(el.getName()));
Map<EventDefinitionType, Map<String, String>> eventDefinitionsOfElement = new HashMap<EventDefinitionType, Map<String, String>>();
for (EventDefinitionType edt : EventDefinitionType.values()) {
Element edElem = el.getChild(edt.toString(), bpmnNamespace);
if (edElem != null) {
Map<String, String> eventAttributes = new HashMap<String, String>();
if (edt == EventDefinitionType.CANCEL) {
// TODO transaction subprocesses only
} else if (edt == EventDefinitionType.COMPENSATION) {
String activityRef = edElem.getAttributeValue("activityRef");
if (activityRef != null) {
eventAttributes.put("activityRef", activityRef);
}
String waitForCompletion = edElem.getAttributeValue("waitForCompletion");
if (waitForCompletion != null) {
eventAttributes.put("waitForCompletion", waitForCompletion);
}
} else if (edt == EventDefinitionType.CONDITIONAL) {
Element conditionElement = edElem.getChild("condition", bpmnNamespace);
if (conditionElement != null) {
eventAttributes.put("condition", conditionElement.getText());
}
} else if (edt == EventDefinitionType.ERROR) {
String errorRef = edElem.getAttributeValue("errorRef");
if (errorRef != null) {
if (!commonProcessElements.getErrors().containsKey(errorRef)) {
throw new ScyllaValidationException("Referenced object of error event " + identifier + " is unknown: " + errorRef);
}
eventAttributes.put("errorRef", errorRef);
} else {
throw new ScyllaValidationException("Error event " + identifier + " has no reference to an error.");
}
} else if (edt == EventDefinitionType.ESCALATION) {
String escalationRef = edElem.getAttributeValue("escalationRef");
if (escalationRef != null) {
if (!commonProcessElements.getEscalations().containsKey(escalationRef)) {
throw new ScyllaValidationException("Referenced object of escalation event " + identifier + " is unknown: " + escalationRef);
}
eventAttributes.put("escalationRef", escalationRef);
} else {
throw new ScyllaValidationException("Escalation event " + identifier + " has no reference to an escalation.");
}
} else if (edt == EventDefinitionType.LINK) {
String name = edElem.getAttributeValue("name");
if (name != null) {
eventAttributes.put("name", name);
}
List<Element> sourceElements = edElem.getChildren("source", bpmnNamespace);
int i = 0;
for (Element sourceElement : sourceElements) {
eventAttributes.put("source" + ++i, sourceElement.getText());
}
Element targetElement = edElem.getChild("target", bpmnNamespace);
if (targetElement != null) {
eventAttributes.put("target", targetElement.getText());
}
} else if (edt == EventDefinitionType.MESSAGE) {
String messageRef = edElem.getAttributeValue("messageRef");
if (messageRef != null) {
if (!commonProcessElements.getMessages().containsKey(messageRef)) {
throw new ScyllaValidationException("Referenced object of message event " + identifier + " is unknown: " + messageRef);
}
eventAttributes.put("messageRef", messageRef);
}
Element operationElement = edElem.getChild("operationRef", bpmnNamespace);
if (operationElement != null) {
eventAttributes.put("operationRef", operationElement.getText());
}
} else if (edt == EventDefinitionType.SIGNAL) {
String signalRef = edElem.getAttributeValue("signalRef");
if (signalRef != null) {
eventAttributes.put("signalRef", signalRef);
}
} else if (edt == EventDefinitionType.TIMER) {
Element timeDateElement = edElem.getChild("timeDate", bpmnNamespace);
// this is the reponsibility of the plug-ins
if (timeDateElement != null) {
eventAttributes.put("timeDate", timeDateElement.getText());
}
Element timeCycleElement = edElem.getChild("timeCycle", bpmnNamespace);
if (timeCycleElement != null) {
eventAttributes.put("timeCycle", timeCycleElement.getText());
}
Element timeDurationElement = edElem.getChild("timeDuration", bpmnNamespace);
if (timeDurationElement != null) {
eventAttributes.put("timeDuration", timeDurationElement.getText());
}
// time attributes are mutually exclusive
if (eventAttributes.size() > 1) {
throw new ScyllaValidationException("Timer event " + identifier + " is invalid. Time definitions are mutually exclusive.");
}
}
eventDefinitionsOfElement.put(edt, eventAttributes);
}
eventDefinitions.put(nodeId, eventDefinitionsOfElement);
if (elementName.equals("boundaryEvent")) {
// just store them for now, use later to create references to boundary events
boundaryEvents.put(nodeId, el);
}
}
List<Element> dataInElements = el.getChildren("dataInputAssociation", bpmnNamespace);
if (!dataInElements.isEmpty()) {
tasksWithDataInputAssociations.put(nodeId, dataInElements);
}
List<Element> dataOutElements = el.getChildren("dataOutputAssociation", bpmnNamespace);
if (!dataOutElements.isEmpty()) {
tasksWithDataOutputAssociations.put(nodeId, dataOutElements);
}
} else if (elementName.equals("dataObjectReference")) {
String dataObjectRef = el.getAttributeValue("dataObjectRef");
dataObjectReferences.put(nodeId, dataObjectRef);
} else if (elementName.equals("ioSpecification")) {
Element input = el.getChild("dataInput", bpmnNamespace);
if (input != null) {
// remove the ioSpecification element
identifiersToNodeIds.remove(identifier);
// override the values with the inner input element
identifier = input.getAttributeValue("id");
identifiers.put(nodeId, identifier);
identifiersToNodeIds.put(identifier, nodeId);
displayName = input.getAttributeValue("name");
if (displayName != null && !displayName.isEmpty()) {
displayNames.put(nodeId, displayName);
}
dataObjectTypes.put(nodeId, DataObjectType.INPUT);
}
} else if (elementName.equals("dataObject")) {
dataObjectTypes.put(nodeId, DataObjectType.DEFAULT);
} else {
DebugLogger.log("Element " + el.getName() + " of process model is expected to be known, but not supported.");
}
nodeId++;
} else {
DebugLogger.log("Element " + el.getName() + " of process model not supported.");
}
}
// create resource references
for (Element laneSet : process.getChildren("laneSet", bpmnNamespace)) {
for (Element lane : laneSet.getChildren("lane", bpmnNamespace)) {
String resourceName = lane.getAttributeValue("name");
for (Element flowNodeRef : lane.getChildren("flowNodeRef", bpmnNamespace)) {
String elementId = flowNodeRef.getText();
Integer nId = identifiersToNodeIds.get(elementId);
if (!resourceReferences.containsKey(nId)) {
resourceReferences.put(nId, new TreeSet<String>());
}
resourceReferences.get(nId).add(resourceName);
}
}
}
for (Integer nId : boundaryEvents.keySet()) {
Element boundaryEvent = boundaryEvents.get(nId);
// interrupting or not?
// initially true, because at least "Camunda Modeler" does not set the cancelActivity value if it is an interrupting activity
boolean cancelActivity;
if (boundaryEvent.getAttributeValue("cancelActivity") != null) {
cancelActivity = Boolean.valueOf(boundaryEvent.getAttributeValue("cancelActivity"));
} else {
cancelActivity = true;
}
cancelActivities.put(nId, cancelActivity);
// attached to?
String attachedTo = boundaryEvent.getAttributeValue("attachedToRef");
int nodeIdOfAttachedTo = identifiersToNodeIds.get(attachedTo);
if (!referencesToBoundaryEvents.containsKey(nodeIdOfAttachedTo)) {
referencesToBoundaryEvents.put(nodeIdOfAttachedTo, new ArrayList<Integer>());
}
referencesToBoundaryEvents.get(nodeIdOfAttachedTo).add(nId);
}
// System.out.println("-----------NORMALFLOW-------------");
for (Integer nId : sequenceFlows.keySet()) {
Element sequenceFlow = sequenceFlows.get(nId);
String sourceRef = sequenceFlow.getAttributeValue("sourceRef");
String targetRef = sequenceFlow.getAttributeValue("targetRef");
int sourceId = identifiersToNodeIds.get(sourceRef);
int targetId = identifiersToNodeIds.get(targetRef);
graph.addEdge(sourceId, nId);
// System.out.println(identifiers.get(sourceId)+" -> "+identifiers.get(nId)+" -> "+identifiers.get(targetId));
graph.addEdge(nId, targetId);
}
// System.out.println("-----------DATAFLOWOUT-------------");
for (Integer nId : tasksWithDataInputAssociations.keySet()) {
List<Element> dataInputAssociations = tasksWithDataInputAssociations.get(nId);
for (Element elem : dataInputAssociations) {
String sourceRef = elem.getChild("sourceRef", bpmnNamespace).getText();
if (identifiersToNodeIds.containsKey(sourceRef)) {
int dataObjectNodeId = identifiersToNodeIds.get(sourceRef);
// System.out.println(identifiers.get(dataObjectNodeId)+" -> "+identifiers.get(nId));
dataObjectsGraph.addEdge(dataObjectNodeId, nId);
/*Map<Integer, Node<Integer>> nodes = dataObjectsGraph.getNodes();
Node<Integer> currentNode = nodes.get(nId);
currentNode.setId(identifiers.get(nId));
currentNode = nodes.get(dataObjectNodeId);
currentNode.setId(identifiers.get(dataObjectNodeId));*/
}
// String targetRef = elem.getChild("targetRef", bpmnNamespace).getText();
}
}
// System.out.println("-----------DATAFLOWIN-------------");
for (Integer nId : tasksWithDataOutputAssociations.keySet()) {
List<Element> dataOutputAssociations = tasksWithDataOutputAssociations.get(nId);
for (Element elem : dataOutputAssociations) {
// String sourceRef = elem.getChild("sourceRef", bpmnNamespace).getText();
String targetRef = elem.getChild("targetRef", bpmnNamespace).getText();
if (identifiersToNodeIds.containsKey(targetRef)) {
int dataObjectNodeId = identifiersToNodeIds.get(targetRef);
// System.out.println(identifiers.get(nId)+" -> "+identifiers.get(dataObjectNodeId));
dataObjectsGraph.addEdge(nId, dataObjectNodeId);
/*Map<Integer, Node<Integer>> nodes = dataObjectsGraph.getNodes();
Node<Integer> currentNode = nodes.get(nId);
currentNode.setId(identifiers.get(nId));
currentNode = nodes.get(dataObjectNodeId);
currentNode.setId(identifiers.get(dataObjectNodeId));*/
}
}
}
ProcessModel processModel = new ProcessModel(processId, process, graph, identifiers, identifiersToNodeIds, displayNames, subProcesses, calledElementsOfCallActivities, tasks, gateways, eventTypes);
processModel.setName(processName);
processModel.setNodeAttributes(nodeAttributes);
processModel.setConditionExpressions(conditionExpressions);
processModel.setResourceReferences(resourceReferences);
processModel.setEventDefinitions(eventDefinitions);
processModel.setCancelActivities(cancelActivities);
processModel.setReferencesToBoundaryEvents(referencesToBoundaryEvents);
processModel.setDataObjectsGraph(dataObjectsGraph);
processModel.setDataObjectTypes(dataObjectTypes);
processModel.setDataObjectReferences(dataObjectReferences);
processModel.setBatchActivities(batchActivities);
batchActivities.forEach((key, value) -> value.setProcessModel(processModel));
for (Integer subProcessId : subProcesses.keySet()) {
ProcessModel subProcessModel = subProcesses.get(subProcessId);
subProcessModel.setNodeIdInParent(subProcessId);
subProcessModel.setParent(processModel);
}
// System.out.println(dataObjectsGraph);
return processModel;
}
use of de.hpi.bpt.scylla.model.process.node.EventType in project scylla by bptlab.
the class BoundaryEventPluginUtils method createTimerBoundaryEvents.
// I did not touch this for now. Hopefully could be deleted in future.
private void createTimerBoundaryEvents(SimulationModel model, BoundaryObject bo, double startOfInterval, double endOfInterval) throws ScyllaRuntimeException {
double beginTimeOfTask = bo.getBeginTimeOfTask();
ProcessSimulationComponents desmojObjects = bo.getDesmojObjects();
ProcessModel processModel = desmojObjects.getProcessModel();
Map<Integer, EventType> eventTypes = processModel.getEventTypes();
Map<Integer, Boolean> cancelActivities = processModel.getCancelActivities();
List<Integer> referenceToBoundaryEvents = bo.getReferenceToBoundaryEvents();
for (Integer nId : referenceToBoundaryEvents) {
boolean timerEventIsInterrupting = false;
EventType eventType = eventTypes.get(nId);
if (eventType == EventType.BOUNDARY) {
Map<EventDefinitionType, Map<String, String>> eventDefinitions = processModel.getEventDefinitions().get(nId);
Map<String, String> definitionAttributes = eventDefinitions.get(EventDefinitionType.TIMER);
if (definitionAttributes != null) {
// if boundary event is timer event
double timeUntilWhenTimerEventsAreCreated = bo.getTimeUntilWhenTimerEventsAreCreated();
if (definitionAttributes.get("timeDuration") != null) {
// ISO 8601 duration
String timeDuration = definitionAttributes.get("timeDuration");
if (beginTimeOfTask != timeUntilWhenTimerEventsAreCreated) {
// timer event has already been created once, skip
continue;
}
Duration javaDuration = Duration.parse(timeDuration);
double duration = javaDuration.get(ChronoUnit.SECONDS);
if (duration == 0) {
continue;
}
double timeToSchedule = beginTimeOfTask + duration;
if (timeToSchedule < endOfInterval) {
String displayName = processModel.getDisplayNames().get(nId);
if (displayName == null) {
displayName = processModel.getIdentifiers().get(nId);
}
String source = bo.getSource();
ProcessInstance processInstance = bo.getProcessInstance();
TimeInstant timeInstant = new TimeInstant(startOfInterval, TimeUnit.SECONDS);
BPMNIntermediateEvent event = new BPMNIntermediateEvent(model, source, timeInstant, desmojObjects, processInstance, nId);
bo.getBoundaryEventsToSchedule().computeIfAbsent(timeToSchedule, k -> new ArrayList<BPMNIntermediateEvent>());
bo.getBoundaryEventsToSchedule().get(timeToSchedule).add(event);
String message = "Schedule boundary timer event: " + displayName;
bo.getMessagesOfBoundaryEventsToSchedule().computeIfAbsent(timeToSchedule, k -> new ArrayList<String>());
bo.getMessagesOfBoundaryEventsToSchedule().get(timeToSchedule).add(message);
// timeUntilWhenTimerEventsAreCreated = timeToSchedule;
}
// TODO fix boundary
timeUntilWhenTimerEventsAreCreated = timeToSchedule;
} else if (definitionAttributes.get("timeCycle") != null) {
// ISO 8601 repeating time interval:
String timeCycle = definitionAttributes.get("timeCycle");
// Rn/[ISO 8601 duration] where n
// (optional) for number of
// recurrences
// ["Rn"], "[ISO 8601 duration]"]
String[] recurrencesAndDuration = timeCycle.split("/");
String recurrencesString = recurrencesAndDuration[0];
String timeDurationString = recurrencesAndDuration[1];
Integer recurrencesMax = null;
if (recurrencesString.length() > 1) {
recurrencesMax = Integer.parseInt(recurrencesString.substring(1, recurrencesString.length()));
timerEventIsInterrupting = cancelActivities.get(nId);
if (timerEventIsInterrupting) {
recurrencesMax = 1;
}
}
Duration javaDuration = Duration.parse(timeDurationString);
double duration = javaDuration.get(ChronoUnit.SECONDS);
if (duration == 0 || recurrencesMax != null && recurrencesMax == 0) {
continue;
}
double timeToSchedule = beginTimeOfTask;
int actualNumberOfOccurrences = 0;
boolean recurrencesMaxExceeded = false;
while (timeToSchedule <= timeUntilWhenTimerEventsAreCreated) {
timeToSchedule += duration;
actualNumberOfOccurrences++;
if (recurrencesMax != null && actualNumberOfOccurrences > recurrencesMax) {
recurrencesMaxExceeded = true;
break;
}
}
if (recurrencesMaxExceeded) {
continue;
}
while (timeToSchedule <= endOfInterval) {
// add as many timer events for scheduling as possible (lots of them if timer event is
// non-interrupting,
// only one if it is interrupting
String displayName = processModel.getDisplayNames().get(nId);
if (displayName == null) {
displayName = processModel.getIdentifiers().get(nId);
}
String source = bo.getSource();
ProcessInstance processInstance = bo.getProcessInstance();
TimeInstant timeInstant = new TimeInstant(startOfInterval, TimeUnit.SECONDS);
BPMNIntermediateEvent event = new BPMNIntermediateEvent(model, source, timeInstant, desmojObjects, processInstance, nId);
bo.getBoundaryEventsToSchedule().computeIfAbsent(timeToSchedule, k -> new ArrayList<BPMNIntermediateEvent>());
bo.getBoundaryEventsToSchedule().get(timeToSchedule).add(event);
String message = "Schedule boundary timer event: " + displayName;
bo.getMessagesOfBoundaryEventsToSchedule().computeIfAbsent(timeToSchedule, k -> new ArrayList<String>());
bo.getMessagesOfBoundaryEventsToSchedule().get(timeToSchedule).add(message);
actualNumberOfOccurrences++;
if (recurrencesMax != null && actualNumberOfOccurrences == recurrencesMax) {
// recurrencesMaxExceeded = true;
break;
}
timeToSchedule += duration;
}
timeUntilWhenTimerEventsAreCreated = timeToSchedule;
} else {
// TODO support timeDate attributes?
String identifier = processModel.getIdentifiers().get(nId);
DebugLogger.log("Timer event " + identifier + " has no timer definition, skip.");
continue;
}
bo.setTimeUntilWhenTimerEventsAreCreated(timeUntilWhenTimerEventsAreCreated);
}
}
}
}
use of de.hpi.bpt.scylla.model.process.node.EventType in project scylla by bptlab.
the class BoundaryEventPluginUtils method createNonTimerBoundaryEvents.
private void createNonTimerBoundaryEvents(SimulationModel model, BoundaryObject bo, double startOfInterval, double endOfInterval) throws ScyllaRuntimeException {
double timeUntilWhenNonTimerEventsAreCreated = bo.getTimeUntilWhenNonTimerEventsAreCreated();
if (!bo.isGenerateMoreNonTimerBoundaryEvents() || timeUntilWhenNonTimerEventsAreCreated >= endOfInterval) {
return;
}
ProcessSimulationComponents desmojObjects = bo.getDesmojObjects();
ProcessModel processModel = desmojObjects.getProcessModel();
Map<Integer, EventType> eventTypes = processModel.getEventTypes();
Map<Integer, Boolean> cancelActivities = processModel.getCancelActivities();
int nodeId = bo.getNodeId();
while (timeUntilWhenNonTimerEventsAreCreated < endOfInterval) {
// If the parent task has not already ended...
// simulation configuration defines probability of firing boundary events
Map<Integer, Object> branchingDistributions = desmojObjects.getExtensionDistributions().get(PLUGIN_NAME);
@SuppressWarnings("unchecked") DiscreteDistEmpirical<Integer> distribution = (DiscreteDistEmpirical<Integer>) branchingDistributions.get(nodeId);
if (distribution == null) {
// There are no non-timer boundary events at this task...
bo.setGenerateMoreNonTimerBoundaryEvents(false);
return;
}
// decide on next node
model.skipTraceNote();
Integer nodeIdOfElementToSchedule = distribution.sample();
// System.out.println("Choosed: "+processModel.getIdentifiers().get(nodeIdOfElementToSchedule)+" "+processModel.getIdentifiers().get(nodeId));
if (nodeIdOfElementToSchedule == nodeId) {
// No next boundary non-timer event, finish
bo.setGenerateMoreNonTimerBoundaryEvents(false);
return;
} else {
// There are boundary events
EventType eventType = eventTypes.get(nodeIdOfElementToSchedule);
if (eventType == EventType.BOUNDARY) {
// Determine whether the boundary event to schedule is an interrupting one.
boolean eventIsInterrupting = cancelActivities.get(nodeIdOfElementToSchedule);
// Get time relative to the start of the task when this boundary event will trigger.
double relativeTimeToTrigger = desmojObjects.getDistributionSample(nodeIdOfElementToSchedule);
if (relativeTimeToTrigger == 0) {
// If this happens something is wrong anyways...
continue;
}
// Add the relative time of this boundary event, to determine when no more events are scheduled.
TimeUnit unit = desmojObjects.getDistributionTimeUnit(nodeIdOfElementToSchedule);
TimeSpan durationAsTimeSpan = new TimeSpan(relativeTimeToTrigger, unit);
timeUntilWhenNonTimerEventsAreCreated += durationAsTimeSpan.getTimeAsDouble(TimeUnit.SECONDS);
// Took this message sending part out. It was just to complicated for boundary events, fixed to their parent task.
// Furthermore it is not needed anymore.
/*String message = null;
boolean showInTrace = model.traceIsOn();
Map<EventDefinitionType, Map<String, String>> definitions = processModel.getEventDefinitions().get(nodeIdOfElementToSchedule);
String displayName = processModel.getDisplayNames().get(nodeIdOfElementToSchedule);
if (displayName == null) {
displayName = processModel.getIdentifiers().get(nodeIdOfElementToSchedule);
}
for (EventDefinitionType definition : definitions.keySet()) {
if (definition == EventDefinitionType.MESSAGE) {
message = "Schedule boundary message event: " + displayName;
}
else if (definition == EventDefinitionType.CONDITIONAL) {
message = "Schedule boundary conditional event: " + displayName;
}
else if (definition == EventDefinitionType.SIGNAL) {
message = "Schedule boundary signal event: " + displayName;
}
else if (definition == EventDefinitionType.ESCALATION) {
message = "Schedule boundary escalation event: " + displayName;
}
else {
if (eventIsInterrupting) {
if (definition == EventDefinitionType.ERROR) {
message = "Schedule boundary error event: " + displayName;
}
else if (definition == EventDefinitionType.COMPENSATION) {
message = "Schedule boundary compensation event: " + displayName;
}
else if (definition == EventDefinitionType.CANCEL) {
message = "Schedule boundary cancel event: " + displayName;
}
}
else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName,
nodeIdOfElementToSchedule);
SimulationUtils.abort(model, processInstance, nodeId, showInTrace);
String identifier = processModel.getIdentifiers().get(nodeIdOfElementToSchedule);
throw new ScyllaRuntimeException("BPMNEvent " + identifier + " not supported.");
}
}*
bo.getMessagesOfBoundaryEventsToSchedule().computeIfAbsent(timeUntilWhenNonTimerEventsAreCreated,
k -> new ArrayList<String>());
bo.getMessagesOfBoundaryEventsToSchedule().get(timeUntilWhenNonTimerEventsAreCreated)
.add(message);
}
*/
String source = bo.getSource();
ProcessInstance processInstance = bo.getProcessInstance();
TimeInstant timeInstant = new TimeInstant(startOfInterval, TimeUnit.SECONDS);
// And create the event with the time it should trigger.
BPMNIntermediateEvent event = new BPMNIntermediateEvent(model, source, timeInstant, desmojObjects, processInstance, nodeIdOfElementToSchedule);
bo.getBoundaryEventsToSchedule().computeIfAbsent(timeUntilWhenNonTimerEventsAreCreated, k -> new ArrayList<BPMNIntermediateEvent>());
bo.getBoundaryEventsToSchedule().get(timeUntilWhenNonTimerEventsAreCreated).add(event);
if (eventIsInterrupting) {
// If the element is interrupting, finish and clean up
// boundaryObjects.values().remove(bo);
bo.setGenerateMoreNonTimerBoundaryEvents(false);
break;
}
}
}
}
bo.setTimeUntilWhenNonTimerEventsAreCreated(timeUntilWhenNonTimerEventsAreCreated);
}
use of de.hpi.bpt.scylla.model.process.node.EventType in project scylla by bptlab.
the class SimulationUtils method createEventsForNextNode.
/**
* Gets type of next node and prepare respective event.
*
* @param model
* the simulation model
* @param processModel
* the process model
* @param processInstanceId
* the identifier of the process instance
* @param nextNodeId
* the identifier of the next node
* @return the DesmoJ representing the next node plus DesmoJ events from plug-ins
* @throws ScyllaRuntimeException
* @throws NodeNotFoundException
* @throws ScyllaValidationException
*/
public static List<ScyllaEvent> createEventsForNextNode(ScyllaEvent currentEvent, ProcessSimulationComponents desmojObjects, ProcessInstance processInstance, int nextNodeId) throws ScyllaRuntimeException, NodeNotFoundException, ScyllaValidationException {
SimulationModel model = (SimulationModel) processInstance.getModel();
TimeInstant currentSimulationTime = model.presentTime();
ProcessModel processModel = processInstance.getProcessModel();
String source = currentEvent.getSource();
List<ScyllaEvent> events = new ArrayList<ScyllaEvent>();
if (processModel.getTasks().containsKey(nextNodeId) || processModel.getSubProcesses().containsKey(nextNodeId)) {
// TaskType tType = processModel.getTasks().get(nextNodeId);
ScyllaEvent event = new TaskEnableEvent(model, source, currentSimulationTime, desmojObjects, processInstance, nextNodeId);
events.add(event);
} else if (processModel.getGateways().containsKey(nextNodeId)) {
GatewayType gType = processModel.getGateways().get(nextNodeId);
Set<Integer> idsOfNodesBeforeGateway = processModel.getIdsOfPreviousNodes(nextNodeId);
if (gType == GatewayType.PARALLEL && idsOfNodesBeforeGateway.size() > 1) {
Map<Integer, Set<Integer>> referenceToEventsOnHold = processInstance.getNodesAndTriggers();
if (!referenceToEventsOnHold.containsKey(nextNodeId)) {
referenceToEventsOnHold.put(nextNodeId, new HashSet<Integer>());
}
Set<Integer> nodesTriggeredFrom = referenceToEventsOnHold.get(nextNodeId);
int currentNodeId = currentEvent.getNodeId();
nodesTriggeredFrom.add(currentNodeId);
if (idsOfNodesBeforeGateway.equals(nodesTriggeredFrom)) {
ScyllaEvent event = new GatewayEvent(model, source, currentSimulationTime, desmojObjects, processInstance, nextNodeId);
events.add(event);
// clear list of fired incoming flows
referenceToEventsOnHold.remove(nextNodeId);
}
} else {
ScyllaEvent event = new GatewayEvent(model, source, currentSimulationTime, desmojObjects, processInstance, nextNodeId);
events.add(event);
}
} else if (processModel.getEventTypes().containsKey(nextNodeId)) {
EventType eType = processModel.getEventTypes().get(nextNodeId);
if (eType == EventType.START) {
throw new ScyllaRuntimeException("Start event " + nextNodeId + " must be at the beginning of the process.");
} else if (eType == EventType.END) {
ScyllaEvent event = new BPMNEndEvent(model, source, currentSimulationTime, desmojObjects, processInstance, nextNodeId);
events.add(event);
} else {
ScyllaEvent event = new BPMNIntermediateEvent(model, source, currentSimulationTime, desmojObjects, processInstance, nextNodeId);
events.add(event);
}
} else {
throw new ScyllaRuntimeException("Next node " + nextNodeId + " not found or not supported.");
}
List<ScyllaEvent> eventsFromPlugins = EventCreationPluggable.runPlugins(currentEvent, desmojObjects, processInstance, nextNodeId);
events.addAll(eventsFromPlugins);
return events;
}
use of de.hpi.bpt.scylla.model.process.node.EventType in project scylla by bptlab.
the class BPMNIntermediateEvent method eventRoutine.
@Override
public void eventRoutine(ProcessInstance processInstance) throws SuspendExecution {
super.eventRoutine(processInstance);
SimulationModel model = (SimulationModel) getModel();
ProcessModel processModel = processInstance.getProcessModel();
try {
EventType type = processModel.getEventTypes().get(nodeId);
// Long duration = null;
// TimeUnit timeUnit = null;
Map<EventDefinitionType, Map<String, String>> definitions = processModel.getEventDefinitions().get(nodeId);
Set<String> messages = new HashSet<String>();
for (EventDefinitionType definition : definitions.keySet()) {
// TODO what about implicit throw events?
if (definition == EventDefinitionType.CANCEL) {
// TODO: cancel event only in transaction sub-process
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (type == EventType.BOUNDARY && cancelActivity) {
String message = "Boundary Cancel Event: " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.COMPENSATION) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (type == EventType.BOUNDARY && cancelActivity) {
String message = "Boundary Compensation Event: " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.CONDITIONAL) {
if (type == EventType.BOUNDARY) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (cancelActivity) {
String message = "Boundary Conditional Event (Interrupting): " + displayName;
messages.add(message);
} else {
String message = "Boundary Conditional Event (Non-Interrupting): " + displayName;
messages.add(message);
}
} else if (type == EventType.INTERMEDIATE_CATCH) {
String message = "Intermediate Conditional Event (Catching): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.ERROR) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (type == EventType.BOUNDARY && cancelActivity) {
String message = "Boundary Error Event: " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.ESCALATION) {
if (type == EventType.BOUNDARY) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (cancelActivity) {
String message = "Boundary Escalation Event (Interrupting): " + displayName;
messages.add(message);
} else {
String message = "Boundary Escalation Event (Non-Interrupting): " + displayName;
messages.add(message);
}
} else if (type == EventType.INTERMEDIATE_THROW) {
String message = "Intermediate Escalation Event (Throwing): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.LINK) {
if (type == EventType.INTERMEDIATE_CATCH) {
String message = "Intermediate Link Event (Catching): " + displayName;
messages.add(message);
} else if (type == EventType.INTERMEDIATE_THROW) {
String message = "Intermediate Link Event (Throwing): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.MESSAGE) {
if (type == EventType.BOUNDARY) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (cancelActivity) {
String message = "Boundary Message Event (Interrupting): " + displayName;
messages.add(message);
} else {
String message = "Boundary Message Event (Non-Interrupting): " + displayName;
messages.add(message);
}
} else if (type == EventType.INTERMEDIATE_CATCH) {
String message = "Intermediate Message Event (Catching): " + displayName;
messages.add(message);
} else if (type == EventType.INTERMEDIATE_THROW) {
String message = "Intermediate Message Event (Throwing): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.SIGNAL) {
if (type == EventType.BOUNDARY) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (cancelActivity) {
String message = "Boundary Signal Event (Interrupting): " + displayName;
messages.add(message);
} else {
String message = "Boundary Signal Event (Non-Interrupting): " + displayName;
messages.add(message);
}
} else if (type == EventType.INTERMEDIATE_CATCH) {
String message = "Intermediate Signal Event (Catching): " + displayName;
messages.add(message);
} else if (type == EventType.INTERMEDIATE_THROW) {
String message = "Intermediate Signal Event (Throwing): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else if (definition == EventDefinitionType.TIMER) {
if (type == EventType.BOUNDARY) {
// isInterrupting?
boolean cancelActivity = processModel.getCancelActivities().get(nodeId);
if (cancelActivity) {
String message = "Boundary Timer Event (Interrupting): " + displayName;
messages.add(message);
} else {
String message = "Boundary Timer Event (Non-Interrupting): " + displayName;
messages.add(message);
}
} else if (type == EventType.INTERMEDIATE_CATCH) {
String message = "Intermediate Timer Event (Catching): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
} else {
// None Event
if (messages.isEmpty()) {
if (type == EventType.INTERMEDIATE_THROW) {
String message = "Intermediate None Event (Throwing): " + displayName;
messages.add(message);
} else {
SimulationUtils.sendElementNotSupportedTraceNote(model, processModel, displayName, nodeId);
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
}
}
}
}
for (String message : messages) {
sendTraceNote(message);
}
// get next node(s)
Set<Integer> idsOfNextNodes = processModel.getIdsOfNextNodes(nodeId);
// BPMN intermediate event must not have more than successor
if (idsOfNextNodes.size() != 1) {
throw new ScyllaValidationException("Event " + nodeId + " does not have 1 successor, but " + idsOfNextNodes.size() + ".");
}
Integer nextNodeId = idsOfNextNodes.iterator().next();
// schedule event for next node
List<ScyllaEvent> events = SimulationUtils.createEventsForNextNode(this, pSimComponents, processInstance, nextNodeId);
// next event occurs immediately after start event
TimeSpan timeSpan = new TimeSpan(0);
for (ScyllaEvent event : events) {
int index = getNewEventIndex();
nextEventMap.put(index, event);
timeSpanToNextEventMap.put(index, timeSpan);
}
// unless current one is BPMN timer event with timerDuration
BPMNIntermediateEventPluggable.runPlugins(this, processInstance);
scheduleNextEvents();
} catch (NodeNotFoundException | ScyllaValidationException | ScyllaRuntimeException e) {
System.err.println(e.getMessage());
e.printStackTrace();
SimulationUtils.abort(model, processInstance, nodeId, traceIsOn());
return;
}
}
Aggregations