use of de.hpi.bpt.scylla.model.process.ProcessModel 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.ProcessModel 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.ProcessModel in project scylla by bptlab.
the class DataObjectTaskTerminate method eventRoutine.
@SuppressWarnings("unchecked")
@Override
public /* collect all fields of all dataobjects and simulate them with the given desmoj distribution. After that, pass them to the XES Logger */
void eventRoutine(TaskTerminateEvent desmojEvent, ProcessInstance processInstance) throws ScyllaRuntimeException {
ProcessModel processModel = processInstance.getProcessModel();
// int processInstanceId = processInstance.getId();
try {
if (processModel.getDataObjectsGraph().getNodes().containsKey(desmojEvent.getNodeId())) {
Set<Integer> refferingObjects = processModel.getDataObjectsGraph().getTargetObjects(desmojEvent.getNodeId());
Collection<Object> allFields = desmojEvent.getDesmojObjects().getExtensionDistributions().get("dataobject").values();
for (Object fields : allFields) {
Integer i = 0;
while (((Map<String, Map<Integer, DataObjectField>>) fields).values().toArray().length - i != 0) {
DataObjectField field = (DataObjectField) ((Map<String, Map<Integer, DataObjectField>>) fields).values().toArray()[i];
if (refferingObjects.contains(field.getNodeId())) {
// System.out.println(processInstance.getId() + " " + desmojEvent.getDisplayName() + " " + processModel.getDisplayNames().get(field.getNodeId()) + " " + field.getDataDistributionWrapper().getSample());
SimulationModel model = (SimulationModel) desmojEvent.getModel();
Collection<Map<Integer, java.util.List<ProcessNodeInfo>>> allProcesses = model.getProcessNodeInfos().values();
for (Map<Integer, java.util.List<ProcessNodeInfo>> process : allProcesses) {
List<ProcessNodeInfo> currentProcess = process.get(processInstance.getId());
for (ProcessNodeInfo task : currentProcess) {
// System.out.println(processModel.getDisplayNames().get(processModel.getDataObjectsGraph().getSourceObjects(field.getNodeId()).toArray()[0]) + " " + task.getTaskName());
for (Integer j = 0; j < processModel.getDataObjectsGraph().getSourceObjects(field.getNodeId()).toArray().length; j++) {
if (task.getId().equals(processModel.getDataObjectsGraph().getSourceObjects(field.getNodeId()).toArray()[j]) && task.getTransition() == ProcessNodeTransitionType.TERMINATE) {
// check all tasks and find the ones that may be looged; already logged ones will get ignored next line
if (!task.getDataObjectField().containsKey(processModel.getDisplayNames().get(field.getNodeId()) + "." + field.getFieldName())) {
// don't log if task already has this field logged
Map<String, Object> fieldSample = new HashMap<String, Object>();
Object currentSample = field.getDataDistributionWrapper().getSample();
// log Value at TaskTerminate
fieldSample.put(processModel.getDisplayNames().get(field.getNodeId()) + "." + field.getFieldName(), currentSample);
task.SetDataObjectField(fieldSample);
// set current DataObjectFieldValue
DataObjectField.addDataObjectValue(processInstance.getId(), fieldSample.keySet().toArray()[0].toString(), currentSample);
}
}
}
}
}
}
i++;
}
}
} else {
// do nothing and continue with the next task because Node has no dataobejcts
}
} catch (ScyllaRuntimeException | ScyllaValidationException | NodeNotFoundException e) {
e.printStackTrace();
}
}
use of de.hpi.bpt.scylla.model.process.ProcessModel in project scylla by bptlab.
the class EventArrivalRateSCParserPlugin method parse.
/**
* Parses all occurences of event arrival rates to be stored as extension attribute.
*/
@Override
public Map<String, Object> parse(SimulationConfiguration simulationInput, Element sim) throws ScyllaValidationException {
Map<Integer, TimeDistributionWrapper> arrivalRates = new HashMap<Integer, TimeDistributionWrapper>();
Namespace simNamespace = sim.getNamespace();
ProcessModel processModel = simulationInput.getProcessModel();
for (Element el : sim.getChildren()) {
String elementName = el.getName();
if (elementName.equals(EventArrivalRatePluginUtils.ELEMENT_NAME)) {
String identifier = el.getAttributeValue("id");
if (identifier == null) {
DebugLogger.log("Warning: Simulation configuration definition catch event element '" + elementName + "' does not have an identifier, skip.");
continue;
}
Integer nodeId = processModel.getIdentifiersToNodeIds().get(identifier);
if (nodeId == null) {
DebugLogger.log("Warning: There is no matching catch event in the process model for " + "simulation configuration definition '" + identifier + ", skip.");
continue;
}
Element elem = el.getChild("arrivalRate", simNamespace);
if (elem != null) {
TimeDistributionWrapper distribution = SimulationConfigurationParser.getTimeDistributionWrapper(elem, simNamespace);
arrivalRates.put(nodeId, distribution);
}
}
}
Map<String, Object> extensionAttributes = new HashMap<String, Object>();
extensionAttributes.put(EventArrivalRatePluginUtils.ARRIVALRATES_KEY, arrivalRates);
return extensionAttributes;
}
use of de.hpi.bpt.scylla.model.process.ProcessModel in project scylla by bptlab.
the class ExclusiveGatewayEventPlugin method eventRoutine.
@SuppressWarnings("unchecked")
@Override
public void eventRoutine(GatewayEvent desmojEvent, ProcessInstance processInstance) throws ScyllaRuntimeException {
SimulationModel model = (SimulationModel) desmojEvent.getModel();
ProcessModel processModel = processInstance.getProcessModel();
int nodeId = desmojEvent.getNodeId();
boolean showInTrace = desmojEvent.traceIsOn();
GatewayType type = processModel.getGateways().get(nodeId);
ProcessSimulationComponents desmojObjects = desmojEvent.getDesmojObjects();
try {
Set<Integer> idsOfNextNodes = processModel.getIdsOfNextNodes(nodeId);
if (idsOfNextNodes.size() > 1) {
// split
if (type == GatewayType.DEFAULT || type == GatewayType.EXCLUSIVE) {
Map<Integer, Object> branchingDistributions = desmojObjects.getExtensionDistributions().get(getName());
DiscreteDistEmpirical<Integer> distribution = (DiscreteDistEmpirical<Integer>) branchingDistributions.get(nodeId);
// decide on next node
if (distribution != null) {
// if a distribution is given take this
Integer nextFlowId = distribution.sample().intValue();
if (!processModel.getIdentifiers().keySet().contains(nextFlowId)) {
throw new ScyllaValidationException("Flow with id " + nextFlowId + " does not exist.");
}
scheduleNextEvent(desmojEvent, processInstance, processModel, nextFlowId);
} else {
// otherwise try to get information out of the describing branches and branch on the basis of this
Map<Class<?>, ArrayList<PluginWrapper>> a = PluginLoader.getDefaultPluginLoader().getExtensions();
Collection<ArrayList<PluginWrapper>> plugins = a.values();
Boolean dataObjectPluginOn = false;
for (ArrayList<PluginWrapper> plugin : plugins) {
for (PluginWrapper p : plugin) {
if (p.toString().equals("DataObjectSCParserPlugin")) {
dataObjectPluginOn = true;
}
}
}
if (dataObjectPluginOn) {
Object[] outgoingRefs = processModel.getGraph().getTargetObjects(nodeId).toArray();
Integer DefaultPath = null;
Boolean foundAWay = false;
for (Object or : outgoingRefs) {
// go through all outgoing references
if (or.equals(getKeyByValue(processModel.getIdentifiers(), processModel.getNodeAttributes().get(desmojEvent.getNodeId()).get("default")))) {
// if it's the default path jump it
DefaultPath = (Integer) or;
continue;
}
String[] conditions = processModel.getDisplayNames().get(or).split("&&");
Integer nextFlowId = (Integer) or;
List<Boolean> test = new ArrayList<>();
for (String condition : conditions) {
condition = condition.trim();
String field = null;
String value = null;
String comparison = null;
if (condition.contains("==")) {
field = condition.split("==")[0];
value = condition.split("==")[1];
// value = processModel.getDisplayNames().get(or).substring(2, processModel.getDisplayNames().get(or).length());
comparison = "equal";
} else if (condition.contains(">=")) {
field = condition.split(">=")[0];
value = condition.split(">=")[1];
comparison = "greaterOrEqual";
} else if (condition.contains("<=")) {
field = condition.split("<=")[0];
value = condition.split("<=")[1];
comparison = "lessOrEqual";
} else if (condition.contains("!=")) {
field = condition.split("!=")[0];
value = condition.split("!=")[1];
comparison = "notEqual";
} else if (condition.contains("=")) {
field = condition.split("=")[0];
value = condition.split("=")[1];
comparison = "equal";
} else if (condition.contains("<")) {
field = condition.split("<")[0];
value = condition.split("<")[1];
comparison = "less";
} else if (condition.contains(">")) {
field = condition.split(">")[0];
value = condition.split(">")[1];
comparison = "greater";
} else {
throw new ScyllaValidationException("Condition " + condition + " does not have a comparison-operator");
}
value = value.trim();
field = field.trim();
Object fieldValue = DataObjectField.getDataObjectValue(processInstance.getId(), field);
if (!isParsableAsLong(value) || !isParsableAsLong((String.valueOf(fieldValue)))) {
// try a long comparison
Integer comparisonResult = (String.valueOf(fieldValue)).trim().compareTo(String.valueOf(value));
if (comparison.equals("equal") && comparisonResult == 0) {
break;
} else if (comparison.equals("notEqual") && comparisonResult != 0) {
break;
} else {
test.add(false);
}
} else {
// otherwise do a string compare
Long LongValue = Long.valueOf(value);
Long dOValue = Long.valueOf((String.valueOf(fieldValue)));
Integer comparisonResult = (dOValue.compareTo(LongValue));
if (comparison.equals("equal") && comparisonResult == 0) {
} else if (comparison.equals("less") && comparisonResult < 0) {
} else if (comparison.equals("greater") && comparisonResult > 0) {
} else if (comparison.equals("greaterOrEqual") && comparisonResult >= 0) {
} else if (comparison.equals("lessOrEqual") && comparisonResult <= 0) {
} else {
test.add(false);
}
}
}
if (test.size() == 0) {
scheduleNextEvent(desmojEvent, processInstance, processModel, nextFlowId);
foundAWay = true;
}
}
if (!foundAWay && DefaultPath != null) {
scheduleNextEvent(desmojEvent, processInstance, processModel, DefaultPath);
} else if (!foundAWay && DefaultPath == null) {
// everything will be killed, logical error
throw new ScyllaValidationException("No Default Path for " + desmojEvent.getDisplayName() + " given and outgoing branches not complete. No branch matches, abort.");
}
} else {
Object[] outgoingRefs = processModel.getGraph().getTargetObjects(nodeId).toArray();
Integer DefaultPath = null;
for (Object or : outgoingRefs) {
// try to find default path
if (or.equals(getKeyByValue(processModel.getIdentifiers(), processModel.getNodeAttributes().get(desmojEvent.getNodeId()).get("default")))) {
DefaultPath = (Integer) or;
break;
}
}
if (DefaultPath != null) {
scheduleNextEvent(desmojEvent, processInstance, processModel, DefaultPath);
} else {
throw new ScyllaValidationException("No Distribution for " + desmojEvent.getDisplayName() + " given, no DefaultPath given and DataObject PlugIn not activated.");
}
}
}
}
}
} catch (NodeNotFoundException | ScyllaValidationException e) {
System.err.println(e.getMessage());
e.printStackTrace();
SimulationUtils.abort(model, processInstance, nodeId, showInTrace);
return;
}
}
Aggregations