UNPKG

mida

Version:

Muiltiple Instance and Data Animator for BPMN models.

173 lines (140 loc) 4.64 kB
'use strict'; var elementHelper = require('../../util/ElementHelper'), getBusinessObject = elementHelper.getBusinessObject, is = elementHelper.is, isAncestor = elementHelper.isAncestor, isTypedEvent = elementHelper.isTypedEvent; var events = require('../../util/EventHelper'), TOGGLE_MODE_EVENT = events.TOGGLE_MODE_EVENT, CONSUME_TOKEN_EVENT = events.CONSUME_TOKEN_EVENT; var VERY_LOW_PRIORITY = 250; function SimulationState( eventBus, animation, elementRegistry, log, elementNotifications, canvas, processInstances ) { var self = this; this._animation = animation; this._elementRegistry = elementRegistry; this._log = log; this._elementNotifications = elementNotifications; this._canvas = canvas; this._processInstances = processInstances; eventBus.on(CONSUME_TOKEN_EVENT, VERY_LOW_PRIORITY, function() { // self.isDeadlock(); }); } // TODO: refactor SimulationState.prototype.isDeadlock = function() { var self = this; var hasTokens = []; this._elementRegistry.forEach(function(element) { if (element.tokenCount) { hasTokens.push(element); } }); var cannotContinue = []; var hasTerminate = []; hasTokens.forEach(function(element) { var outgoingSequenceFlows = element.outgoing.filter(function(outgoing) { return is(outgoing, 'bpmn:SequenceFlow'); }); // has tokens but no outgoing sequence flows if (!outgoingSequenceFlows.length) { cannotContinue.push(element); } // parallel gateway after exclusive gateway if (is(element, 'bpmn:ParallelGateway')) { var incomingSequenceFlows = element.incoming.filter(function(incoming) { return is(incoming, 'bpmn:SequenceFlow'); }); if (incomingSequenceFlows.length > element.tokenCount) { cannotContinue.push(element); } } var visited = []; // has terminate event function checkIfHasTerminate(element) { element.outgoing.forEach(function(outgoing) { if (visited.indexOf(outgoing.target) !== -1) { return; } visited.push(outgoing.target); var isTerminate = isTypedEvent(getBusinessObject(outgoing.target), 'bpmn:TerminateEventDefinition'); if (isTerminate) { hasTerminate.push(element); } checkIfHasTerminate(outgoing.target); }); } checkIfHasTerminate(element); }); var hasAnimations = this._animation.animations.length; if (hasTokens.length && !hasTerminate.length && cannotContinue.length && !this._animation.animations.length) { self._log.log('Deadlock', 'warning', 'fa-exclamation-triangle'); cannotContinue.forEach(function(element) { self._elementNotifications.addElementNotification(element, { type: 'warning', icon: 'fa-exclamation-triangle', text: 'Deadlock' }); }); } }; /** * Check if process instance finished. * Element is necessary to display element notification if finished. */ SimulationState.prototype.isFinished = function(element, processInstanceId) { var processInstance = this._processInstances.getProcessInstance(processInstanceId); parent = processInstance.parent; var hasTokens = false; if (!parent) { parent = this._canvas.getRootElement(); } parent.children.forEach(function(element) { if (element.tokenCount && element.tokenCount[processInstanceId] && element.tokenCount[processInstanceId].length ) { hasTokens = true; } }); var hasAnimations = false; this._animation.animations.forEach(function(animation) { if (isAncestor(animation.element, parent) && animation.processInstanceId === processInstanceId) { hasAnimations = true; } }); if (!hasTokens && !hasAnimations) { if (is(parent, 'bpmn:SubProcess')) { this._log.log('Subprocess ' + processInstanceId + ' finished', 'info', 'fa-check-circle'); } else { this._log.log('Process ' + processInstanceId + ' finished', 'success', 'fa-check-circle'); this._elementNotifications.addElementNotification(element, { type: 'success', icon: 'fa-check-circle', text: 'Instance ' +processInstanceId +' Finished', }); } return true; } }; SimulationState.$inject = [ 'eventBus', 'animation', 'elementRegistry', 'log', 'elementNotifications', 'canvas', 'processInstances' ]; module.exports = SimulationState;