bpmn-elements 6.0.1 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +341 -0
  2. package/README.md +3 -0
  3. package/dist/index.js +52 -44
  4. package/dist/src/Api.js +77 -76
  5. package/dist/src/Context.js +176 -172
  6. package/dist/src/Environment.js +110 -102
  7. package/dist/src/EventBroker.js +89 -88
  8. package/dist/src/ExtensionsMapper.js +2 -2
  9. package/dist/src/MessageFormatter.js +164 -95
  10. package/dist/src/Scripts.js +6 -2
  11. package/dist/src/activity/Activity.js +1105 -916
  12. package/dist/src/activity/ActivityExecution.js +342 -297
  13. package/dist/src/activity/Dummy.js +3 -3
  14. package/dist/src/definition/Definition.js +498 -444
  15. package/dist/src/definition/DefinitionExecution.js +710 -408
  16. package/dist/src/error/Errors.js +17 -7
  17. package/dist/src/eventDefinitions/CancelEventDefinition.js +190 -150
  18. package/dist/src/eventDefinitions/CompensateEventDefinition.js +194 -161
  19. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +197 -135
  20. package/dist/src/eventDefinitions/ErrorEventDefinition.js +207 -165
  21. package/dist/src/eventDefinitions/EscalationEventDefinition.js +175 -141
  22. package/dist/src/eventDefinitions/EventDefinitionExecution.js +157 -129
  23. package/dist/src/eventDefinitions/LinkEventDefinition.js +174 -149
  24. package/dist/src/eventDefinitions/MessageEventDefinition.js +213 -176
  25. package/dist/src/eventDefinitions/SignalEventDefinition.js +203 -161
  26. package/dist/src/eventDefinitions/TerminateEventDefinition.js +21 -23
  27. package/dist/src/eventDefinitions/TimerEventDefinition.js +243 -228
  28. package/dist/src/events/BoundaryEvent.js +180 -144
  29. package/dist/src/events/EndEvent.js +18 -23
  30. package/dist/src/events/IntermediateCatchEvent.js +44 -58
  31. package/dist/src/events/IntermediateThrowEvent.js +18 -23
  32. package/dist/src/events/StartEvent.js +109 -94
  33. package/dist/src/flows/Association.js +94 -100
  34. package/dist/src/flows/MessageFlow.js +86 -103
  35. package/dist/src/flows/SequenceFlow.js +173 -182
  36. package/dist/src/gateways/EventBasedGateway.js +88 -84
  37. package/dist/src/gateways/ExclusiveGateway.js +13 -16
  38. package/dist/src/gateways/InclusiveGateway.js +11 -14
  39. package/dist/src/gateways/ParallelGateway.js +11 -14
  40. package/dist/src/getPropertyValue.js +34 -34
  41. package/dist/src/io/BpmnIO.js +17 -14
  42. package/dist/src/io/EnvironmentDataObject.js +33 -29
  43. package/dist/src/io/EnvironmentDataStore.js +33 -29
  44. package/dist/src/io/EnvironmentDataStoreReference.js +35 -31
  45. package/dist/src/io/InputOutputSpecification.js +177 -168
  46. package/dist/src/io/Properties.js +117 -124
  47. package/dist/src/messageHelper.js +1 -1
  48. package/dist/src/process/Process.js +439 -362
  49. package/dist/src/process/ProcessExecution.js +748 -646
  50. package/dist/src/shared.js +2 -2
  51. package/dist/src/tasks/CallActivity.js +160 -0
  52. package/dist/src/tasks/LoopCharacteristics.js +309 -330
  53. package/dist/src/tasks/ReceiveTask.js +233 -182
  54. package/dist/src/tasks/ScriptTask.js +35 -41
  55. package/dist/src/tasks/ServiceImplementation.js +13 -20
  56. package/dist/src/tasks/ServiceTask.js +82 -75
  57. package/dist/src/tasks/SignalTask.js +97 -93
  58. package/dist/src/tasks/StandardLoopCharacteristics.js +1 -1
  59. package/dist/src/tasks/SubProcess.js +193 -175
  60. package/dist/src/tasks/Task.js +17 -19
  61. package/index.js +2 -0
  62. package/package.json +16 -16
  63. package/src/Api.js +65 -59
  64. package/src/Context.js +145 -140
  65. package/src/Environment.js +116 -100
  66. package/src/EventBroker.js +67 -68
  67. package/src/ExtensionsMapper.js +2 -2
  68. package/src/MessageFormatter.js +132 -74
  69. package/src/activity/Activity.js +914 -776
  70. package/src/activity/ActivityExecution.js +293 -247
  71. package/src/activity/Dummy.js +2 -2
  72. package/src/definition/Definition.js +437 -401
  73. package/src/definition/DefinitionExecution.js +598 -340
  74. package/src/error/Errors.js +11 -6
  75. package/src/eventDefinitions/CancelEventDefinition.js +164 -121
  76. package/src/eventDefinitions/CompensateEventDefinition.js +159 -124
  77. package/src/eventDefinitions/ConditionalEventDefinition.js +147 -104
  78. package/src/eventDefinitions/ErrorEventDefinition.js +190 -131
  79. package/src/eventDefinitions/EscalationEventDefinition.js +139 -101
  80. package/src/eventDefinitions/EventDefinitionExecution.js +127 -95
  81. package/src/eventDefinitions/LinkEventDefinition.js +160 -129
  82. package/src/eventDefinitions/MessageEventDefinition.js +178 -121
  83. package/src/eventDefinitions/SignalEventDefinition.js +162 -106
  84. package/src/eventDefinitions/TerminateEventDefinition.js +19 -19
  85. package/src/eventDefinitions/TimerEventDefinition.js +202 -167
  86. package/src/events/BoundaryEvent.js +156 -115
  87. package/src/events/EndEvent.js +15 -18
  88. package/src/events/IntermediateCatchEvent.js +40 -44
  89. package/src/events/IntermediateThrowEvent.js +15 -18
  90. package/src/events/StartEvent.js +84 -50
  91. package/src/flows/Association.js +98 -112
  92. package/src/flows/MessageFlow.js +81 -97
  93. package/src/flows/SequenceFlow.js +146 -160
  94. package/src/gateways/EventBasedGateway.js +75 -68
  95. package/src/gateways/ExclusiveGateway.js +8 -13
  96. package/src/gateways/InclusiveGateway.js +8 -13
  97. package/src/gateways/ParallelGateway.js +8 -13
  98. package/src/getPropertyValue.js +34 -33
  99. package/src/io/BpmnIO.js +20 -15
  100. package/src/io/EnvironmentDataObject.js +29 -18
  101. package/src/io/EnvironmentDataStore.js +29 -18
  102. package/src/io/EnvironmentDataStoreReference.js +31 -20
  103. package/src/io/InputOutputSpecification.js +154 -157
  104. package/src/io/Properties.js +95 -97
  105. package/src/process/Process.js +378 -333
  106. package/src/process/ProcessExecution.js +603 -553
  107. package/src/tasks/CallActivity.js +130 -0
  108. package/src/tasks/LoopCharacteristics.js +290 -289
  109. package/src/tasks/ReceiveTask.js +174 -107
  110. package/src/tasks/ScriptTask.js +27 -30
  111. package/src/tasks/ServiceImplementation.js +13 -18
  112. package/src/tasks/ServiceTask.js +67 -60
  113. package/src/tasks/SignalTask.js +77 -52
  114. package/src/tasks/StandardLoopCharacteristics.js +1 -1
  115. package/src/tasks/SubProcess.js +184 -157
  116. package/src/tasks/Task.js +15 -19
@@ -1,428 +1,686 @@
1
- import {DefinitionApi} from '../Api';
2
- import {cloneContent, cloneMessage, pushParent} from '../messageHelper';
3
1
  import getPropertyValue from '../getPropertyValue';
2
+ import {DefinitionApi} from '../Api';
3
+ import {brokerSafeId} from '../shared';
4
+ import {cloneContent, cloneMessage, pushParent, cloneParent} from '../messageHelper';
5
+
6
+ const kActivated = Symbol.for('activated');
7
+ const kProcessesQ = Symbol.for('processesQ');
8
+ const kCompleted = Symbol.for('completed');
9
+ const kExecuteMessage = Symbol.for('executeMessage');
10
+ const kMessageHandlers = Symbol.for('messageHandlers');
11
+ const kParent = Symbol.for('definition');
12
+ const kProcesses = Symbol.for('processes');
13
+ const kStatus = Symbol.for('status');
14
+ const kStopped = Symbol.for('stopped');
15
+
16
+ export default function DefinitionExecution(definition, context) {
17
+ const broker = definition.broker;
18
+
19
+ this[kParent] = definition;
20
+ this.id = definition.id;
21
+ this.type = definition.type;
22
+ this.broker = broker;
23
+ const environment = this.environment = definition.environment;
24
+ this.context = context;
25
+
26
+ const processes = context.getProcesses();
27
+ const ids = [];
28
+ const executable = [];
29
+ for (const bp of processes) {
30
+ bp.environment.assignVariables(environment.variables);
31
+ bp.environment.assignSettings(environment.settings);
32
+ ids.push(bp.id);
33
+ if (bp.isExecutable) executable.push(bp);
34
+ }
4
35
 
5
- export default function DefinitionExecution(definition) {
6
- const {id, type, broker, logger, environment} = definition;
7
-
8
- const processes = definition.getProcesses();
9
- const processIds = processes.map(({id: childId}) => childId);
10
- let executableProcesses = definition.getExecutableProcesses();
36
+ this[kProcesses] = {
37
+ processes,
38
+ running: [],
39
+ ids,
40
+ executable,
41
+ postponed: [],
42
+ };
11
43
 
12
- const postponed = [];
13
44
  broker.assertExchange('execution', 'topic', {autoDelete: false, durable: true});
14
45
 
15
- let activityQ, status = 'init', executionId, stopped, activated, initMessage, completed = false;
16
-
17
- const definitionExecution = {
18
- id,
19
- type,
20
- broker,
21
- get environment() {
22
- return environment;
23
- },
24
- get executionId() {
25
- return executionId;
26
- },
27
- get completed() {
28
- return completed;
29
- },
30
- get status() {
31
- return status;
32
- },
33
- get stopped() {
34
- return stopped;
35
- },
36
- get postponedCount() {
37
- return postponed.length;
38
- },
39
- get isRunning() {
40
- if (activated) return true;
41
- return false;
42
- },
43
- processes,
44
- createMessage,
45
- getApi,
46
- getState,
47
- getPostponed,
48
- execute,
49
- resume,
50
- recover,
51
- stop,
46
+ this.executionId = undefined;
47
+ this[kCompleted] = false;
48
+ this[kStopped] = false;
49
+ this[kActivated] = false;
50
+ this[kStatus] = 'init';
51
+ this[kProcessesQ] = undefined;
52
+
53
+ this[kMessageHandlers] = {
54
+ onApiMessage: this._onApiMessage.bind(this),
55
+ onCallActivity: this._onCallActivity.bind(this),
56
+ onCancelCallActivity: this._onCancelCallActivity.bind(this),
57
+ onChildEvent: this._onChildEvent.bind(this),
58
+ onDelegateMessage: this._onDelegateMessage.bind(this),
59
+ onMessageOutbound: this._onMessageOutbound.bind(this),
60
+ onProcessMessage: this._onProcessMessage.bind(this),
52
61
  };
62
+ }
63
+
64
+ const proto = DefinitionExecution.prototype;
65
+
66
+ Object.defineProperty(proto, 'stopped', {
67
+ enumerable: true,
68
+ get() {
69
+ return this[kStopped];
70
+ },
71
+ });
72
+
73
+ Object.defineProperty(proto, 'completed', {
74
+ enumerable: true,
75
+ get() {
76
+ return this[kCompleted];
77
+ },
78
+ });
79
+
80
+ Object.defineProperty(proto, 'status', {
81
+ enumerable: true,
82
+ get() {
83
+ return this[kStatus];
84
+ },
85
+ });
86
+
87
+ Object.defineProperty(proto, 'processes', {
88
+ enumerable: true,
89
+ get() {
90
+ return this[kProcesses].running;
91
+ },
92
+ });
93
+
94
+ Object.defineProperty(proto, 'postponedCount', {
95
+ get() {
96
+ return this[kProcesses].postponed.length;
97
+ },
98
+ });
99
+
100
+ Object.defineProperty(proto, 'isRunning', {
101
+ get() {
102
+ return this[kActivated];
103
+ },
104
+ });
105
+
106
+ proto.execute = function execute(executeMessage) {
107
+ if (!executeMessage) throw new Error('Definition execution requires message');
108
+ const content = executeMessage.content;
109
+ const executionId = this.executionId = content.executionId;
110
+ if (!executionId) throw new Error('Definition execution requires execution id');
111
+
112
+ this[kExecuteMessage] = cloneMessage(executeMessage, {
113
+ executionId,
114
+ state: 'start',
115
+ });
116
+
117
+ this[kStopped] = false;
118
+
119
+ this[kProcessesQ] = this.broker.assertQueue(`execute-${executionId}-q`, {durable: true, autoDelete: false});
120
+
121
+ if (executeMessage.fields.redelivered) {
122
+ return this.resume();
123
+ }
53
124
 
54
- return definitionExecution;
125
+ const {running, executable} = this[kProcesses];
55
126
 
56
- function execute(executeMessage) {
57
- if (!executeMessage) throw new Error('Definition execution requires message');
58
- const {content, fields} = executeMessage;
59
- if (!content || !content.executionId) throw new Error('Definition execution requires execution id');
127
+ if (content.processId) {
128
+ const startWithProcess = this.getProcessById(content.processId);
129
+ if (startWithProcess) {
130
+ executable.splice(0);
131
+ executable.push(startWithProcess);
132
+ }
133
+ }
60
134
 
61
- const isRedelivered = fields.redelivered;
62
- executionId = content.executionId;
135
+ this._debug('execute definition');
136
+ running.push(...executable);
137
+ this._activate(executable);
138
+ this._start();
139
+ return true;
140
+ };
63
141
 
64
- initMessage = cloneMessage(executeMessage, {executionId, state: 'start'});
142
+ proto.resume = function resume() {
143
+ this._debug(`resume ${this[kStatus]} definition execution`);
65
144
 
66
- stopped = false;
145
+ if (this[kCompleted]) return this._complete('completed');
67
146
 
68
- activityQ = broker.assertQueue(`execute-${executionId}-q`, {durable: true, autoDelete: false});
147
+ const {running, postponed} = this[kProcesses];
148
+ this._activate(running);
149
+ postponed.splice(0);
150
+ this[kProcessesQ].consume(this[kMessageHandlers].onProcessMessage, {
151
+ prefetch: 1000,
152
+ consumerTag: `_definition-activity-${this.executionId}`,
153
+ });
69
154
 
70
- if (isRedelivered) {
71
- return resume();
72
- }
155
+ if (this[kCompleted]) return;
73
156
 
74
- if (content.processId) {
75
- const startWithProcess = definition.getProcessById(content.processId);
76
- if (startWithProcess) executableProcesses = [startWithProcess];
77
- }
157
+ for (const bp of running) bp.resume();
158
+ };
78
159
 
79
- logger.debug(`<${executionId} (${id})> execute definition`);
80
- activate();
81
- start();
82
- return true;
83
- }
160
+ proto.recover = function recover(state) {
161
+ if (!state) return this;
162
+ this.executionId = state.executionId;
84
163
 
85
- function resume() {
86
- logger.debug(`<${executionId} (${id})> resume`, status, 'definition execution');
164
+ this[kStopped] = state.stopped;
165
+ this[kCompleted] = state.completed;
166
+ this[kStatus] = state.status;
87
167
 
88
- if (completed) return complete('completed');
168
+ this._debug(`recover ${this[kStatus]} definition execution`);
89
169
 
90
- activate();
91
- postponed.splice(0);
92
- activityQ.consume(onProcessMessage, {prefetch: 1000, consumerTag: `_definition-activity-${executionId}`});
170
+ const running = this[kProcesses].running;
171
+ running.splice(0);
93
172
 
94
- if (completed) return complete('completed');
95
- switch (status) {
96
- case 'init':
97
- return start();
98
- case 'executing': {
99
- if (!postponed.length) return complete('completed');
100
- break;
101
- }
173
+ const ids = [];
174
+ for (const bpState of state.processes) {
175
+ const bpid = bpState.id;
176
+ let bp;
177
+ if (ids.indexOf(bpid) > -1) {
178
+ bp = this.context.getNewProcessById(bpid);
179
+ } else {
180
+ bp = this.getProcessById(bpid);
102
181
  }
182
+ if (!bp) return;
103
183
 
104
- processes.forEach((p) => p.resume());
184
+ ids.push(bpid);
185
+ bp.recover(bpState);
186
+ running.push(bp);
105
187
  }
106
188
 
107
- function start() {
108
- if (!processes.length) {
109
- return publishCompletionMessage('completed');
110
- }
111
- if (!executableProcesses.length) {
112
- return complete('error', {error: new Error('No executable process')});
113
- }
114
-
115
- status = 'start';
189
+ return this;
190
+ };
116
191
 
117
- executableProcesses.forEach((p) => p.init());
118
- executableProcesses.forEach((p) => p.run());
192
+ proto.stop = function stop() {
193
+ this.getApi().stop();
194
+ };
119
195
 
120
- postponed.splice(0);
121
- activityQ.assertConsumer(onProcessMessage, {prefetch: 1000, consumerTag: `_definition-activity-${executionId}`});
196
+ proto.getProcesses = function getProcesses() {
197
+ const {running, processes} = this[kProcesses];
198
+ const result = running.slice();
199
+ for (const bp of processes) {
200
+ if (!result.find((runningBp) => bp.id === runningBp.id)) result.push(bp);
122
201
  }
202
+ return result;
203
+ };
204
+
205
+ proto.getProcessById = function getProcessById(processId) {
206
+ return this.getProcesses().find((bp) => bp.id === processId);
207
+ };
208
+
209
+ proto.getProcessesById = function getProcessesById(processId) {
210
+ return this.getProcesses().filter((bp) => bp.id === processId);
211
+ };
212
+
213
+ proto.getProcessByExecutionId = function getProcessByExecutionId(processExecutionId) {
214
+ const running = this[kProcesses].running;
215
+ return running.find((bp) => bp.executionId === processExecutionId);
216
+ };
217
+
218
+ proto.getRunningProcesses = function getRunningProcesses() {
219
+ const running = this[kProcesses].running;
220
+ return running.filter((bp) => bp.executionId);
221
+ };
222
+
223
+ proto.getExecutableProcesses = function getExecutableProcesses() {
224
+ return this[kProcesses].executable.slice();
225
+ };
226
+
227
+ proto.getState = function getState() {
228
+ return {
229
+ executionId: this.executionId,
230
+ stopped: this[kStopped],
231
+ completed: this[kCompleted],
232
+ status: this[kStatus],
233
+ processes: this[kProcesses].running.map((bp) => bp.getState()),
234
+ };
235
+ };
123
236
 
124
- function recover(state) {
125
- if (!state) return definitionExecution;
126
- executionId = state.executionId;
127
-
128
- stopped = state.stopped;
129
- completed = state.completed;
130
- status = state.status;
237
+ proto.getApi = function getApi(apiMessage) {
238
+ if (!apiMessage) apiMessage = this[kExecuteMessage] || {content: this._createMessage()};
131
239
 
132
- logger.debug(`<${executionId} (${id})> recover`, status, 'definition execution');
240
+ const content = apiMessage.content;
241
+ if (content.executionId !== this.executionId) {
242
+ return this._getProcessApi(apiMessage);
243
+ }
133
244
 
134
- state.processes.forEach((processState) => {
135
- const instance = definition.getProcessById(processState.id);
136
- if (!instance) return;
245
+ const api = DefinitionApi(this.broker, apiMessage);
246
+ const postponed = this[kProcesses].postponed;
247
+ const self = this;
137
248
 
138
- instance.recover(processState);
139
- });
249
+ api.getExecuting = function getExecuting() {
250
+ return postponed.reduce((result, msg) => {
251
+ const bpApi = self._getProcessApi(msg);
252
+ if (bpApi) result.push(bpApi);
253
+ return result;
254
+ }, []);
255
+ };
140
256
 
141
- return definitionExecution;
257
+ return api;
258
+ };
259
+
260
+ proto.getPostponed = function getPostponed(...args) {
261
+ const running = this[kProcesses].running;
262
+ return running.reduce((result, p) => {
263
+ result = result.concat(p.getPostponed(...args));
264
+ return result;
265
+ }, []);
266
+ };
267
+
268
+ proto._start = function start() {
269
+ const {ids, executable, postponed} = this[kProcesses];
270
+ if (!ids.length) {
271
+ return this._complete('completed');
142
272
  }
143
273
 
144
- function stop() {
145
- getApi().stop();
274
+ if (!executable.length) {
275
+ return this._complete('error', {error: new Error('No executable process')});
146
276
  }
147
277
 
148
- function activate() {
149
- broker.subscribeTmp('api', '#', onApiMessage, {noAck: true, consumerTag: '_definition-api-consumer'});
150
-
151
- processes.forEach((p) => {
152
- p.broker.subscribeTmp('message', 'message.outbound', onMessageOutbound, {noAck: true, consumerTag: '_definition-outbound-message-consumer'});
153
- p.broker.subscribeTmp('event', 'activity.signal', onDelegateMessage, {noAck: true, consumerTag: '_definition-signal-consumer', priority: 200});
154
- p.broker.subscribeTmp('event', 'activity.message', onDelegateMessage, {noAck: true, consumerTag: '_definition-message-consumer', priority: 200});
155
- p.broker.subscribeTmp('event', '#', onEvent, {noAck: true, consumerTag: '_definition-activity-consumer', priority: 100});
156
- });
157
-
158
- activated = true;
159
-
160
- function onEvent(routingKey, originalMessage) {
161
- const message = cloneMessage(originalMessage);
162
- const content = message.content;
163
- const parent = content.parent = content.parent || {};
164
-
165
- const isDirectChild = processIds.indexOf(content.id) > -1;
166
- if (isDirectChild) {
167
- parent.executionId = executionId;
168
- } else {
169
- content.parent = pushParent(parent, {id, type, executionId});
170
- }
171
-
172
- broker.publish('event', routingKey, content, {...message.properties, mandatory: false});
173
- if (!isDirectChild) return;
174
-
175
- activityQ.queueMessage(message.fields, cloneContent(content), message.properties);
176
- }
278
+ this[kStatus] = 'start';
279
+
280
+ for (const bp of executable) bp.init();
281
+ for (const bp of executable) bp.run();
282
+
283
+ postponed.splice(0);
284
+ this[kProcessesQ].assertConsumer(this[kMessageHandlers].onProcessMessage, {
285
+ prefetch: 1000,
286
+ consumerTag: `_definition-activity-${this.executionId}`,
287
+ });
288
+ };
289
+
290
+ proto._activate = function activate(processList) {
291
+ this.broker.subscribeTmp('api', '#', this[kMessageHandlers].onApiMessage, {
292
+ noAck: true,
293
+ consumerTag: '_definition-api-consumer',
294
+ });
295
+ for (const bp of processList) this._activateProcess(bp);
296
+ this[kActivated] = true;
297
+ };
298
+
299
+ proto._activateProcess = function activateProcess(bp) {
300
+ const handlers = this[kMessageHandlers];
301
+
302
+ bp.broker.subscribeTmp('message', 'message.outbound', handlers.onMessageOutbound, {
303
+ noAck: true,
304
+ consumerTag: '_definition-outbound-message-consumer',
305
+ });
306
+ bp.broker.subscribeTmp('event', 'activity.signal', handlers.onDelegateMessage, {
307
+ noAck: true,
308
+ consumerTag: '_definition-signal-consumer',
309
+ priority: 200,
310
+ });
311
+ bp.broker.subscribeTmp('event', 'activity.message', handlers.onDelegateMessage, {
312
+ noAck: true,
313
+ consumerTag: '_definition-message-consumer',
314
+ priority: 200,
315
+ });
316
+ bp.broker.subscribeTmp('event', 'activity.call', handlers.onCallActivity, {
317
+ noAck: true,
318
+ consumerTag: '_definition-call-consumer',
319
+ priority: 200,
320
+ });
321
+ bp.broker.subscribeTmp('event', 'activity.call.cancel', handlers.onCancelCallActivity, {
322
+ noAck: true,
323
+ consumerTag: '_definition-call-cancel-consumer',
324
+ priority: 200,
325
+ });
326
+ bp.broker.subscribeTmp('event', '#', handlers.onChildEvent, {
327
+ noAck: true,
328
+ consumerTag: '_definition-activity-consumer',
329
+ priority: 100,
330
+ });
331
+ };
332
+
333
+ proto._onChildEvent = function onChildEvent(routingKey, originalMessage) {
334
+ const message = cloneMessage(originalMessage);
335
+ const content = message.content;
336
+ const parent = content.parent = content.parent || {};
337
+
338
+ const isDirectChild = this[kProcesses].ids.indexOf(content.id) > -1;
339
+ if (isDirectChild) {
340
+ parent.executionId = this.executionId;
341
+ } else {
342
+ content.parent = pushParent(parent, this);
177
343
  }
178
344
 
179
- function deactivate() {
180
- broker.cancel('_definition-api-consumer');
181
- broker.cancel(`_definition-activity-${executionId}`);
182
-
183
- processes.forEach((p) => {
184
- p.broker.cancel('_definition-outbound-message-consumer');
185
- p.broker.cancel('_definition-activity-consumer');
186
- p.broker.cancel('_definition-signal-consumer');
187
- p.broker.cancel('_definition-message-consumer');
188
- });
189
-
190
- activated = false;
345
+ this.broker.publish('event', routingKey, content, {...message.properties, mandatory: false});
346
+ if (!isDirectChild) return;
347
+
348
+ this[kProcessesQ].queueMessage(message.fields, cloneContent(content), message.properties);
349
+ };
350
+
351
+ proto._deactivate = function deactivate() {
352
+ this.broker.cancel('_definition-api-consumer');
353
+ this.broker.cancel(`_definition-activity-${this.executionId}`);
354
+ for (const bp of this[kProcesses].running) this._deactivateProcess(bp);
355
+ this[kActivated] = false;
356
+ };
357
+
358
+ proto._deactivateProcess = function deactivateProcess(bp) {
359
+ bp.broker.cancel('_definition-outbound-message-consumer');
360
+ bp.broker.cancel('_definition-activity-consumer');
361
+ bp.broker.cancel('_definition-signal-consumer');
362
+ bp.broker.cancel('_definition-message-consumer');
363
+ bp.broker.cancel('_definition-call-consumer');
364
+ bp.broker.cancel('_definition-call-cancel-consumer');
365
+ };
366
+
367
+ proto._onProcessMessage = function onProcessMessage(routingKey, message) {
368
+ const content = message.content;
369
+ const isRedelivered = message.fields.redelivered;
370
+ const {id: childId, inbound} = content;
371
+
372
+ if (isRedelivered && message.properties.persistent === false) return;
373
+
374
+ switch (routingKey) {
375
+ case 'execution.stop': {
376
+ message.ack();
377
+ return this._onStopped(message);
378
+ }
379
+ case 'process.leave': {
380
+ return this._onProcessCompleted(message);
381
+ }
191
382
  }
192
383
 
193
- function onProcessMessage(routingKey, message) {
194
- const content = message.content;
195
- const isRedelivered = message.fields.redelivered;
196
- const {id: childId, type: activityType, executionId: childExecutionId} = content;
197
-
198
- if (isRedelivered && message.properties.persistent === false) return;
199
-
200
- switch (routingKey) {
201
- case 'execution.stop': {
202
- if (childExecutionId === executionId) {
203
- message.ack();
204
- return onStopped();
205
- }
206
- break;
207
- }
208
- case 'process.leave': {
209
- return onChildCompleted();
384
+ this._stateChangeMessage(message, true);
385
+
386
+ switch (routingKey) {
387
+ case 'process.enter':
388
+ this[kStatus] = 'executing';
389
+ break;
390
+ case 'process.discarded': {
391
+ if (inbound && inbound.length) {
392
+ const calledFrom = inbound[0];
393
+ this._getProcessApi({content: calledFrom}).cancel({
394
+ executionId: calledFrom.executionId,
395
+ });
210
396
  }
397
+ break;
211
398
  }
399
+ case 'process.end': {
400
+ if (inbound && inbound.length) {
401
+ const calledFrom = inbound[0];
212
402
 
213
- stateChangeMessage(true);
214
-
215
- switch (routingKey) {
216
- case 'process.discard':
217
- case 'process.enter':
218
- status = 'executing';
219
- break;
220
- case 'process.error': {
221
- processes.slice().forEach((p) => {
222
- if (p.id !== childId) p.stop();
403
+ this._getProcessApi({content: calledFrom}).signal({
404
+ executionId: calledFrom.executionId,
405
+ output: {...content.output},
223
406
  });
224
- complete('error', {error: content.error});
225
- break;
407
+ } else {
408
+ Object.assign(this.environment.output, content.output);
226
409
  }
410
+ break;
227
411
  }
412
+ case 'process.error': {
413
+ if (inbound && inbound.length) {
414
+ const calledFrom = inbound[0];
415
+
416
+ this._getProcessApi({content: calledFrom}).sendApiMessage('error', {
417
+ executionId: calledFrom.executionId,
418
+ error: content.error,
419
+ }, {mandatory: true, type: 'error'});
420
+ } else {
421
+ for (const bp of this[kProcesses].running.slice()) {
422
+ if (bp.id !== childId) bp.stop();
423
+ }
228
424
 
229
- function stateChangeMessage(postponeMessage = true) {
230
- const previousMsg = popPostponed(childId);
231
- if (previousMsg) previousMsg.ack();
232
- if (postponeMessage) postponed.push(message);
233
- }
234
-
235
- function popPostponed(postponedId) {
236
- const idx = postponed.findIndex((msg) => msg.content.id === postponedId);
237
- if (idx > -1) {
238
- return postponed.splice(idx, 1)[0];
425
+ this._complete('error', {error: content.error});
239
426
  }
427
+ break;
240
428
  }
429
+ }
430
+ };
431
+
432
+ proto._stateChangeMessage = function stateChangeMessage(message, postponeMessage) {
433
+ let previousMsg;
434
+ const postponed = this[kProcesses].postponed;
435
+ const idx = postponed.findIndex((msg) => msg.content.executionId === message.content.executionId);
436
+ if (idx > -1) {
437
+ previousMsg = postponed.splice(idx, 1)[0];
438
+ }
241
439
 
242
- function onChildCompleted() {
243
- stateChangeMessage(false);
244
- if (isRedelivered) return message.ack();
440
+ if (previousMsg) previousMsg.ack();
441
+ if (postponeMessage) postponed.push(message);
442
+ };
245
443
 
246
- logger.debug(`<${executionId} (${id})> left <${childId}> (${activityType}), pending runs ${postponed.length}`);
444
+ proto._onProcessCompleted = function onProcessCompleted(message) {
445
+ this._stateChangeMessage(message, false);
446
+ if (message.fields.redelivered) return message.ack();
247
447
 
248
- if (!postponed.length) {
249
- message.ack();
250
- complete('completed');
251
- }
252
- }
448
+ const {id, executionId, type, inbound} = message.content;
449
+ this._debug(`left <${executionId} (${id})> (${type}), pending runs ${this.postponedCount}`);
253
450
 
254
- function onStopped() {
255
- logger.debug(`<${executionId} (${id})> stop definition execution (stop process executions ${postponed.length})`);
256
- activityQ.close();
257
- deactivate();
258
- processes.slice().forEach((p) => {
259
- p.stop();
260
- });
261
- stopped = true;
262
- return broker.publish('execution', `execution.stopped.${executionId}`, {
263
- ...initMessage.content,
264
- ...content,
265
- }, {type: 'stopped', persistent: false});
266
- }
451
+ if (inbound && inbound.length) {
452
+ const bp = this._removeProcessByExecutionId(executionId);
453
+ this._deactivateProcess(bp);
267
454
  }
268
455
 
269
- function onApiMessage(routingKey, message) {
270
- const messageType = message.properties.type;
271
- const delegate = message.properties.delegate;
272
-
273
- if (delegate && id === message.content.id) {
274
- const referenceId = getPropertyValue(message, 'content.message.id');
275
- for (const bp of processes) {
276
- if (bp.isRunning) continue;
277
- if (bp.getStartActivities({referenceId, referenceType: messageType}).length) {
278
- logger.debug(`<${executionId} (${id})> start <${bp.id}>`);
279
- bp.run();
280
- }
281
- }
282
- }
283
-
284
- if (delegate) {
285
- for (const bp of processes) {
286
- bp.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
287
- }
288
- }
289
-
290
- if (executionId !== message.content.executionId) return;
456
+ if (!this.postponedCount) {
457
+ message.ack();
458
+ this._complete('completed');
459
+ }
460
+ };
461
+
462
+ proto._onStopped = function onStopped(message) {
463
+ const running = this[kProcesses].running;
464
+ this._debug(`stop definition execution (stop process executions ${running.length})`);
465
+ this[kProcessesQ].close();
466
+ for (const bp of running.slice()) bp.stop();
467
+ this._deactivate();
468
+
469
+ this[kStopped] = true;
470
+ return this.broker.publish('execution', `execution.stopped.${this.executionId}`, cloneContent(this[kExecuteMessage].content, {
471
+ ...message.content,
472
+ }), {type: 'stopped', persistent: false});
473
+ };
474
+
475
+ proto._onApiMessage = function onApiMessage(routingKey, message) {
476
+ const messageType = message.properties.type;
477
+ const delegate = message.properties.delegate;
478
+
479
+ if (delegate && this.id === message.content.id) {
480
+ const referenceId = getPropertyValue(message, 'content.message.id');
481
+ this._startProcessesByMessage({referenceId, referenceType: messageType});
482
+ }
291
483
 
292
- switch (messageType) {
293
- case 'stop':
294
- activityQ.queueMessage({routingKey: 'execution.stop'}, cloneContent(message.content), {persistent: false});
295
- break;
484
+ if (delegate) {
485
+ for (const bp of this[kProcesses].running.slice()) {
486
+ bp.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
296
487
  }
297
488
  }
298
489
 
299
- function getState() {
300
- return {
301
- executionId,
302
- stopped,
303
- completed,
304
- status,
305
- processes: processes.map((p) => p.getState()),
306
- };
307
- }
490
+ if (this.executionId !== message.content.executionId) return;
308
491
 
309
- function getPostponed(...args) {
310
- return processes.reduce((result, p) => {
311
- result = result.concat(p.getPostponed(...args));
312
- return result;
313
- }, []);
492
+ if (messageType === 'stop') {
493
+ this[kProcessesQ].queueMessage({routingKey: 'execution.stop'}, cloneContent(message.content), {persistent: false});
314
494
  }
495
+ };
496
+
497
+ proto._startProcessesByMessage = function startProcessesByMessage(reference) {
498
+ const {processes: bps, running} = this[kProcesses];
499
+ if (bps.length < 2) return;
500
+
501
+ for (const bp of bps) {
502
+ if (bp.isExecutable) continue;
503
+ if (!bp.getStartActivities(reference).length) continue;
504
+
505
+ if (!bp.executionId) {
506
+ this._debug(`start <${bp.id}> by <${reference.referenceId}> (${reference.referenceType})`);
507
+ this._activateProcess(bp);
508
+ running.push(bp);
509
+ bp.init();
510
+ bp.run();
511
+ if (reference.referenceType === 'message') return;
512
+ continue;
513
+ }
315
514
 
316
- function complete(completionType, content, options) {
317
- deactivate();
318
- logger.debug(`<${executionId} (${id})> definition execution ${completionType} in ${Date.now() - initMessage.properties.timestamp}ms`);
319
- if (!content) content = createMessage();
320
- completed = true;
321
- if (status !== 'terminated') status = completionType;
322
- broker.deleteQueue(activityQ.name);
323
-
324
- return broker.publish('execution', `execution.${completionType}.${executionId}`, {
325
- ...initMessage.content,
326
- output: environment.output,
327
- ...content,
328
- state: completionType,
329
- }, {type: completionType, mandatory: completionType === 'error', ...options});
515
+ this._debug(`start new <${bp.id}> by <${reference.referenceId}> (${reference.referenceType})`);
516
+
517
+ const targetProcess = this.context.getNewProcessById(bp.id);
518
+ this._activateProcess(targetProcess);
519
+ running.push(targetProcess);
520
+ targetProcess.init();
521
+ targetProcess.run();
522
+ if (reference.referenceType === 'message') return;
330
523
  }
524
+ };
331
525
 
332
- function onMessageOutbound(routingKey, message) {
333
- const content = message.content;
334
- const {target, source} = content;
526
+ proto._onMessageOutbound = function onMessageOutbound(routingKey, message) {
527
+ const content = message.content;
528
+ const {target, source} = content;
335
529
 
336
- logger.debug(`<${executionId} (${id})> conveying message from <${source.processId}.${source.id}> to`, target.id ? `<${target.processId}.${target.id}>` : `<${target.processId}>`);
530
+ this._debug(`conveying message from <${source.processId}.${source.id}> to`, target.id ? `<${target.processId}.${target.id}>` : `<${target.processId}>`);
337
531
 
338
- const targetProcess = getProcessById(target.processId);
532
+ const targetProcesses = this.getProcessesById(target.processId);
533
+ if (!targetProcesses.length) return;
339
534
 
340
- targetProcess.sendMessage(message);
535
+ let targetProcess, found;
536
+ for (const bp of targetProcesses) {
537
+ if (!bp.executionId) {
538
+ targetProcess = bp;
539
+ continue;
540
+ }
541
+ bp.sendMessage(message);
542
+ found = true;
341
543
  }
342
544
 
343
- function onDelegateMessage(routingKey, executeMessage) {
344
- const content = executeMessage.content;
345
- const messageType = executeMessage.properties.type;
346
- const delegateMessage = executeMessage.content.message;
545
+ if (found) return;
347
546
 
348
- const reference = definition.getElementById(delegateMessage.id);
349
- const message = reference && reference.resolve(executeMessage);
547
+ targetProcess = targetProcess || this.context.getNewProcessById(target.processId);
350
548
 
351
- logger.debug(`<${executionId} (${id})>`, reference ? `${messageType} <${delegateMessage.id}>` : `anonymous ${messageType}`, `event received from <${content.parent.id}.${content.id}>. Delegating.`);
549
+ this._activateProcess(targetProcess);
550
+ this[kProcesses].running.push(targetProcess);
551
+ targetProcess.init();
552
+ targetProcess.run();
553
+ targetProcess.sendMessage(message);
554
+ };
352
555
 
353
- getApi().sendApiMessage(messageType, {
354
- message: message,
355
- originalMessage: content.message,
356
- }, {delegate: true, type: messageType});
556
+ proto._onCallActivity = function onCallActivity(routingKey, message) {
557
+ const content = message.content;
558
+ const {calledElement, id: fromId, executionId: fromExecutionId, name: fromName, parent: fromParent} = content;
559
+ if (!calledElement) return;
357
560
 
358
- broker.publish('event', `definition.${messageType}`, createMessage({
359
- message: message && cloneContent(message),
360
- }), {type: messageType});
561
+ const bpExecutionId = `${brokerSafeId(calledElement)}_${fromExecutionId}`;
562
+ if (content.isRecovered) {
563
+ if (this.getProcessByExecutionId(bpExecutionId)) return;
361
564
  }
362
565
 
363
- function getProcessById(processId) {
364
- return processes.find((p) => p.id === processId);
365
- }
566
+ const targetProcess = this.context.getNewProcessById(calledElement, {
567
+ settings: {
568
+ calledFrom: cloneContent({
569
+ id: fromId,
570
+ name: fromName,
571
+ executionId: content.executionId,
572
+ parent: content.parent,
573
+ }),
574
+ },
575
+ });
366
576
 
367
- function publishCompletionMessage(completionType, content) {
368
- deactivate();
369
- logger.debug(`<${executionId} (${id})> ${completionType}`);
370
- if (!content) content = createMessage();
371
- return broker.publish('execution', `execution.${completionType}.${executionId}`, content, { type: completionType });
372
- }
577
+ if (!targetProcess) return;
373
578
 
374
- function createMessage(content = {}) {
375
- return {
376
- id,
377
- type,
378
- executionId,
379
- status,
380
- ...content,
381
- };
382
- }
579
+ this._debug(`call from <${fromParent.id}.${fromId}> to <${calledElement}>`);
383
580
 
384
- function getApi(apiMessage) {
385
- if (!apiMessage) apiMessage = initMessage || {content: createMessage()};
581
+ this._activateProcess(targetProcess);
582
+ this[kProcesses].running.push(targetProcess);
583
+ targetProcess.init(bpExecutionId);
584
+ targetProcess.run({inbound: [cloneContent(content)]});
585
+ };
386
586
 
387
- const content = apiMessage.content;
388
- if (content.executionId !== executionId) {
389
- return getProcessApi(apiMessage);
390
- }
587
+ proto._onCancelCallActivity = function onCancelCallActivity(routingKey, message) {
588
+ const {calledElement, id: fromId, executionId: fromExecutionId, parent: fromParent} = message.content;
589
+ if (!calledElement) return;
391
590
 
392
- const api = DefinitionApi(broker, apiMessage);
591
+ const bpExecutionId = `${brokerSafeId(calledElement)}_${fromExecutionId}`;
592
+ const targetProcess = this.getProcessByExecutionId(bpExecutionId);
593
+ if (!targetProcess) return;
393
594
 
394
- api.getExecuting = function getExecuting() {
395
- return postponed.reduce((result, msg) => {
396
- if (msg.content.executionId === content.executionId) return result;
397
- result.push(getApi(msg));
398
- return result;
399
- }, []);
400
- };
595
+ this._debug(`cancel call from <${fromParent.id}.${fromId}> to <${calledElement}>`);
401
596
 
402
- return api;
403
- }
597
+ targetProcess.getApi().discard();
598
+ };
404
599
 
405
- function getProcessApi(message) {
406
- const content = message.content;
407
- let api = getApiByProcessId(content.id);
408
- if (api) return api;
600
+ proto._onDelegateMessage = function onDelegateMessage(routingKey, executeMessage) {
601
+ const content = executeMessage.content;
602
+ const messageType = executeMessage.properties.type;
603
+ const delegateMessage = executeMessage.content.message;
409
604
 
410
- if (!content.parent) return;
605
+ const reference = this.context.getActivityById(delegateMessage.id);
606
+ const message = reference && reference.resolve(executeMessage);
411
607
 
412
- api = getApiByProcessId(content.parent.id);
413
- if (api) return api;
608
+ this._debug(`<${reference ? `${messageType} ${delegateMessage.id}>` : `anonymous ${messageType}`} event received from <${content.parent.id}.${content.id}>. Delegating.`);
609
+
610
+ this.getApi().sendApiMessage(messageType, {
611
+ source: {
612
+ id: content.id,
613
+ executionId: content.executionId,
614
+ type: content.type,
615
+ parent: cloneParent(content.parent),
616
+ },
617
+ message,
618
+ originalMessage: content.message,
619
+ }, {delegate: true, type: messageType});
620
+
621
+ this.broker.publish('event', `definition.${messageType}`, this._createMessage({
622
+ message: message && cloneContent(message),
623
+ }), {type: messageType});
624
+ };
625
+
626
+ proto._removeProcessByExecutionId = function removeProcessByExecutionId(processExecutionId) {
627
+ const running = this[kProcesses].running;
628
+ const idx = running.findIndex((p) => p.executionId === processExecutionId);
629
+ if (idx === -1) return;
630
+ return running.splice(idx, 1)[0];
631
+ };
632
+
633
+ proto._complete = function complete(completionType, content, options) {
634
+ this._deactivate();
635
+ const stateMessage = this[kExecuteMessage];
636
+ this._debug(`definition execution ${completionType} in ${Date.now() - stateMessage.properties.timestamp}ms`);
637
+ if (!content) content = this._createMessage();
638
+ this[kCompleted] = true;
639
+ this[kStatus] = completionType;
640
+ this.broker.deleteQueue(this[kProcessesQ].name);
641
+
642
+ return this.broker.publish('execution', `execution.${completionType}.${this.executionId}`, {
643
+ ...stateMessage.content,
644
+ output: {...this.environment.output},
645
+ ...content,
646
+ state: completionType,
647
+ }, {type: completionType, mandatory: completionType === 'error', ...options});
648
+ };
649
+
650
+ proto._createMessage = function createMessage(content = {}) {
651
+ return {
652
+ id: this.id,
653
+ type: this.type,
654
+ executionId: this.executionId,
655
+ status: this[kStatus],
656
+ ...content,
657
+ };
658
+ };
414
659
 
415
- if (!content.parent.path) return;
660
+ proto._getProcessApi = function getProcessApi(message) {
661
+ const content = message.content;
662
+ let api = this._getProcessApiByExecutionId(content.executionId, message);
663
+ if (api) return api;
416
664
 
417
- for (let i = 0; i < content.parent.path.length; i++) {
418
- api = getApiByProcessId(content.parent.path[i].id);
419
- if (api) return api;
420
- }
665
+ if (!content.parent) return;
421
666
 
422
- function getApiByProcessId(parentId) {
423
- const processInstance = getProcessById(parentId);
424
- if (!processInstance) return;
425
- return processInstance.getApi(message);
426
- }
667
+ api = this._getProcessApiByExecutionId(content.parent.executionId, message);
668
+ if (api) return api;
669
+
670
+ if (!content.parent.path) return;
671
+
672
+ for (const pp of content.parent.path) {
673
+ api = this._getProcessApiByExecutionId(pp.executionId, message);
674
+ if (api) return api;
427
675
  }
428
- }
676
+ };
677
+
678
+ proto._getProcessApiByExecutionId = function getProcessApiByExecutionId(parentExecutionId, message) {
679
+ const processInstance = this.getProcessByExecutionId(parentExecutionId);
680
+ if (!processInstance) return;
681
+ return processInstance.getApi(message);
682
+ };
683
+
684
+ proto._debug = function debug(logMessage) {
685
+ this[kParent].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`);
686
+ };