feat(rules): implement compensation rules

Related to #291
This commit is contained in:
Nico Rehwaldt 2016-01-20 18:30:34 +01:00 committed by pedesen
parent d7834e9bee
commit 7190f8bef8
4 changed files with 216 additions and 18 deletions

View File

@ -144,6 +144,10 @@ function getOrganizationalParent(element) {
return bo;
}
function isForCompensation(e) {
return getBusinessObject(e).isForCompensation;
}
function isSameOrganization(a, b) {
var parentA = getOrganizationalParent(a),
parentB = getOrganizationalParent(b);
@ -152,7 +156,8 @@ function isSameOrganization(a, b) {
}
function isMessageFlowSource(element) {
return is(element, 'bpmn:InteractionNode') && (
return is(element, 'bpmn:InteractionNode') &&
!isForCompensation(element) && (
!is(element, 'bpmn:Event') || (
is(element, 'bpmn:ThrowEvent') &&
hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition')
@ -161,7 +166,8 @@ function isMessageFlowSource(element) {
}
function isMessageFlowTarget(element) {
return is(element, 'bpmn:InteractionNode') && (
return is(element, 'bpmn:InteractionNode') &&
!isForCompensation(element) && (
!is(element, 'bpmn:Event') || (
is(element, 'bpmn:CatchEvent') &&
hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition')
@ -217,8 +223,11 @@ function isSequenceFlowSource(element) {
!isEventSubProcess(element) &&
!(is(element, 'bpmn:IntermediateThrowEvent') &&
hasEventDefinition(element, 'bpmn:LinkEventDefinition')
);
) &&
!(is(element, 'bpmn:BoundaryEvent') &&
hasEventDefinition(element, 'bpmn:CompensateEventDefinition')
) &&
!isForCompensation(element);
}
function isSequenceFlowTarget(element) {
@ -228,7 +237,8 @@ function isSequenceFlowTarget(element) {
!isEventSubProcess(element) &&
!(is(element, 'bpmn:IntermediateCatchEvent') &&
hasEventDefinition(element, 'bpmn:LinkEventDefinition')
);
) &&
!isForCompensation(element);
}
@ -401,8 +411,8 @@ function canAttach(elements, target, source, position) {
return false;
}
// only allow drop on activities
if (!is(target, 'bpmn:Activity')) {
// only allow drop on non compensation activities
if (!is(target, 'bpmn:Activity') || isForCompensation(target)) {
return false;
}

View File

@ -1,38 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_tkxkICCPEeWwcL3w8i7dvw" exporter="camunda modeler" exporterVersion="2.7.0" targetNamespace="http://activiti.org/bpmn">
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="_tkxkICCPEeWwcL3w8i7dvw" targetNamespace="http://activiti.org/bpmn" exporter="camunda modeler" exporterVersion="2.7.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:subProcess id="SubProcess_1">
<bpmn2:startEvent id="StartEvent_1">
<bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1"/>
<bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1" />
<bpmn2:task id="Task_1">
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
</bpmn2:task>
</bpmn2:subProcess>
<bpmn2:boundaryEvent id="BoundaryEvent_1" name="batman" attachedToRef="SubProcess_1" />
<bpmn2:task id="Task_2" />
<bpmn2:boundaryEvent id="BoundaryEvent_2" name="superman" attachedToRef="Task_2"/>
<bpmn2:boundaryEvent id="BoundaryEvent_2" name="superman" attachedToRef="Task_2" />
<bpmn2:task id="CompensationTask" isForCompensation="true" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="275.0" y="214.0"/>
<dc:Bounds x="275" y="214" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="293.0" y="255.0"/>
<dc:Bounds x="293" y="255" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_2" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds height="289.0" width="457.0" x="204.0" y="78.0"/>
<dc:Bounds x="204" y="78" width="457" height="289" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_1">
<dc:Bounds height="80.0" width="100.0" x="431.0" y="192.0"/>
<dc:Bounds x="431" y="192" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="_BPMNShape_StartEvent_2" targetElement="_BPMNShape_Task_2">
<di:waypoint xsi:type="dc:Point" x="311.0" y="232.0"/>
<di:waypoint xsi:type="dc:Point" x="431.0" y="232.0"/>
<di:waypoint xsi:type="dc:Point" x="311" y="232" />
<di:waypoint xsi:type="dc:Point" x="431" y="232" />
<bpmndi:BPMNLabel>
<dc:Bounds height="6.0" width="6.0" x="332.0" y="236.0"/>
<dc:Bounds x="332" y="236" width="6" height="6" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BoundaryEvent_1_di" bpmnElement="BoundaryEvent_1">
@ -50,6 +51,9 @@
<dc:Bounds x="754" y="176" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="CompensationTask_di" bpmnElement="CompensationTask">
<dc:Bounds x="795" y="249" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_9X-DgL31EeWxRuodBysTLQ" exporter="camunda modeler" exporterVersion="2.6.0" targetNamespace="http://activiti.org/bpmn">
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:task id="Task"/>
<bpmn2:boundaryEvent id="CompensationBoundary" attachedToRef="Task">
<bpmn2:compensateEventDefinition id="_CompensateEventDefinition_2" waitForCompletion="false"/>
</bpmn2:boundaryEvent>
<bpmn2:task id="TaskForCompensation" isForCompensation="true"/>
<bpmn2:intermediateThrowEvent id="IntermediateThrowEvent_1">
<bpmn2:compensateEventDefinition id="_CompensateEventDefinition_3" waitForCompletion="false"/>
</bpmn2:intermediateThrowEvent>
<bpmn2:subProcess id="SubProcess_1" isForCompensation="true" triggeredByEvent="true">
<bpmn2:startEvent id="StartEvent_1">
<bpmn2:compensateEventDefinition id="_CompensateEventDefinition_4" waitForCompletion="false"/>
</bpmn2:startEvent>
</bpmn2:subProcess>
<bpmn2:endEvent id="EndEvent_1">
<bpmn2:compensateEventDefinition id="_CompensateEventDefinition_5" waitForCompletion="false"/>
</bpmn2:endEvent>
<bpmn2:exclusiveGateway id="Gateway"/>
<bpmn2:intermediateThrowEvent id="IntermediateEvent"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_TaskForCompensation" bpmnElement="Task">
<dc:Bounds height="80.0" width="100.0" x="43.0" y="99.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="CompensationBoundary">
<dc:Bounds height="36.0" width="36.0" x="87.0" y="161.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="TaskForCompensation">
<dc:Bounds height="80.0" width="100.0" x="142.0" y="240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_IntermediateThrowEvent_2" bpmnElement="IntermediateThrowEvent_1">
<dc:Bounds height="36.0" width="36.0" x="192.0" y="121.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="210.0" y="162.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_2" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds height="150.0" width="200.0" x="142.0" y="369.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="180.0" y="408.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="198.0" y="449.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_EndEvent_2" bpmnElement="EndEvent_1">
<dc:Bounds height="36.0" width="36.0" x="298.0" y="120.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_ExclusiveGateway_2" bpmnElement="Gateway" isMarkerVisible="true">
<dc:Bounds height="50.0" width="50.0" x="316.0" y="254.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="341.0" y="309.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_IntermediateThrowEvent_4" bpmnElement="IntermediateEvent">
<dc:Bounds height="36.0" width="36.0" x="432.0" y="262.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="450.0" y="303.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View File

@ -445,6 +445,86 @@ describe('features/modeling/rules - BpmnRules', function() {
});
describe('compensation', function() {
var testXML = require('./BpmnRules.compensation.bpmn');
beforeEach(bootstrapModeler(testXML, { modules: testModules }));
it('connect CompensationBoundary -> Task', inject(function() {
expectCanConnect('CompensationBoundary', 'Task', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect CompensationBoundary -> TaskForCompensation', inject(function() {
expectCanConnect('CompensationBoundary', 'TaskForCompensation', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect CompensationBoundary -> Gateway', inject(function() {
expectCanConnect('CompensationBoundary', 'Gateway', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect CompensationBoundary -> IntermediateEvent', inject(function() {
expectCanConnect('CompensationBoundary', 'IntermediateEvent', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect Task -> TaskForCompensation', inject(function() {
expectCanConnect('Task', 'TaskForCompensation', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect TaskForCompensation -> Task', inject(function() {
expectCanConnect('TaskForCompensation', 'Task', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
});
describe('on collaboration diagram', function() {
var testXML = require('./BpmnRules.collaboration.bpmn');
@ -776,7 +856,7 @@ describe('features/modeling/rules - BpmnRules', function() {
beforeEach(bootstrapModeler(testXML, { modules: testModules }));
it('attach IntermediateEvent to Task', inject(function(elementFactory, bpmnRules) {
it('attach IntermediateEvent to Task', inject(function(elementFactory) {
// given
var eventShape = elementFactory.createShape({
@ -792,6 +872,22 @@ describe('features/modeling/rules - BpmnRules', function() {
}));
it('not attach IntermediateEvent to CompensationTask', inject(function(elementFactory) {
// given
var eventShape = elementFactory.createShape({
type: 'bpmn:IntermediateThrowEvent',
x: 413, y: 254
});
// then
expectCanMove([ eventShape ], 'CompensationTask', {
attach: false,
move: false
});
}));
it('attach IntermediateEvent to SubProcess inner', inject(function(elementFactory, elementRegistry, bpmnRules) {
// given
@ -836,6 +932,28 @@ describe('features/modeling/rules - BpmnRules', function() {
}));
it('not attach IntermediateEvent to compensation activity', inject(function(elementFactory, elementRegistry, bpmnRules) {
// given
var compensationTask = elementRegistry.get('CompensationTask');
var eventShape = elementFactory.createShape({
type: 'bpmn:IntermediateThrowEvent',
x: 0, y: 0
});
var position = {
x: compensationTask.x + compensationTask.width / 2,
y: compensationTask.y + compensationTask.height
};
// when
var canAttach = bpmnRules.canAttach([ eventShape ], compensationTask, null, position);
// then
expect(canAttach).to.be.false;
}));
it('create IntermediateEvent in SubProcess body', inject(function(elementFactory, elementRegistry, bpmnRules) {
// given