bpmn-elements 6.0.1 → 7.0.0

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