bpmn-elements 5.1.3 → 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 (119) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/README.md +9 -3
  3. package/dist/index.js +71 -39
  4. package/dist/src/Api.js +77 -76
  5. package/dist/src/Context.js +169 -164
  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/Timers.js +4 -6
  12. package/dist/src/activity/Activity.js +1108 -901
  13. package/dist/src/activity/ActivityExecution.js +342 -297
  14. package/dist/src/activity/Dummy.js +3 -3
  15. package/dist/src/definition/Definition.js +498 -444
  16. package/dist/src/definition/DefinitionExecution.js +722 -409
  17. package/dist/src/error/Errors.js +17 -7
  18. package/dist/src/eventDefinitions/CancelEventDefinition.js +190 -150
  19. package/dist/src/eventDefinitions/CompensateEventDefinition.js +194 -161
  20. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +197 -135
  21. package/dist/src/eventDefinitions/ErrorEventDefinition.js +207 -165
  22. package/dist/src/eventDefinitions/EscalationEventDefinition.js +175 -141
  23. package/dist/src/eventDefinitions/EventDefinitionExecution.js +157 -129
  24. package/dist/src/eventDefinitions/LinkEventDefinition.js +174 -149
  25. package/dist/src/eventDefinitions/MessageEventDefinition.js +213 -176
  26. package/dist/src/eventDefinitions/SignalEventDefinition.js +203 -161
  27. package/dist/src/eventDefinitions/TerminateEventDefinition.js +21 -23
  28. package/dist/src/eventDefinitions/TimerEventDefinition.js +243 -228
  29. package/dist/src/events/BoundaryEvent.js +180 -144
  30. package/dist/src/events/EndEvent.js +18 -23
  31. package/dist/src/events/IntermediateCatchEvent.js +44 -58
  32. package/dist/src/events/IntermediateThrowEvent.js +18 -23
  33. package/dist/src/events/StartEvent.js +109 -94
  34. package/dist/src/flows/Association.js +94 -101
  35. package/dist/src/flows/MessageFlow.js +86 -103
  36. package/dist/src/flows/SequenceFlow.js +172 -184
  37. package/dist/src/gateways/EventBasedGateway.js +88 -84
  38. package/dist/src/gateways/ExclusiveGateway.js +13 -16
  39. package/dist/src/gateways/InclusiveGateway.js +11 -14
  40. package/dist/src/gateways/ParallelGateway.js +11 -14
  41. package/dist/src/getPropertyValue.js +34 -34
  42. package/dist/src/io/BpmnIO.js +31 -0
  43. package/dist/src/io/EnvironmentDataObject.js +33 -29
  44. package/dist/src/io/EnvironmentDataStore.js +52 -0
  45. package/dist/src/io/EnvironmentDataStoreReference.js +52 -0
  46. package/dist/src/io/InputOutputSpecification.js +177 -168
  47. package/dist/src/io/Properties.js +252 -0
  48. package/dist/src/messageHelper.js +1 -1
  49. package/dist/src/process/Process.js +433 -359
  50. package/dist/src/process/ProcessExecution.js +744 -645
  51. package/dist/src/shared.js +3 -6
  52. package/dist/src/tasks/CallActivity.js +160 -0
  53. package/dist/src/tasks/LoopCharacteristics.js +309 -330
  54. package/dist/src/tasks/ReceiveTask.js +233 -182
  55. package/dist/src/tasks/ScriptTask.js +35 -41
  56. package/dist/src/tasks/ServiceImplementation.js +13 -20
  57. package/dist/src/tasks/ServiceTask.js +82 -75
  58. package/dist/src/tasks/SignalTask.js +97 -93
  59. package/dist/src/tasks/StandardLoopCharacteristics.js +1 -1
  60. package/dist/src/tasks/SubProcess.js +195 -175
  61. package/dist/src/tasks/Task.js +17 -19
  62. package/index.js +8 -0
  63. package/package.json +16 -15
  64. package/src/Api.js +65 -59
  65. package/src/Context.js +142 -132
  66. package/src/Environment.js +88 -100
  67. package/src/EventBroker.js +67 -68
  68. package/src/ExtensionsMapper.js +2 -2
  69. package/src/MessageFormatter.js +132 -74
  70. package/src/Timers.js +4 -4
  71. package/src/activity/Activity.js +916 -757
  72. package/src/activity/ActivityExecution.js +293 -247
  73. package/src/activity/Dummy.js +2 -2
  74. package/src/definition/Definition.js +436 -401
  75. package/src/definition/DefinitionExecution.js +603 -343
  76. package/src/error/Errors.js +11 -6
  77. package/src/eventDefinitions/CancelEventDefinition.js +164 -121
  78. package/src/eventDefinitions/CompensateEventDefinition.js +158 -124
  79. package/src/eventDefinitions/ConditionalEventDefinition.js +147 -104
  80. package/src/eventDefinitions/ErrorEventDefinition.js +190 -131
  81. package/src/eventDefinitions/EscalationEventDefinition.js +139 -101
  82. package/src/eventDefinitions/EventDefinitionExecution.js +127 -95
  83. package/src/eventDefinitions/LinkEventDefinition.js +160 -129
  84. package/src/eventDefinitions/MessageEventDefinition.js +178 -121
  85. package/src/eventDefinitions/SignalEventDefinition.js +162 -106
  86. package/src/eventDefinitions/TerminateEventDefinition.js +19 -19
  87. package/src/eventDefinitions/TimerEventDefinition.js +202 -167
  88. package/src/events/BoundaryEvent.js +156 -115
  89. package/src/events/EndEvent.js +15 -18
  90. package/src/events/IntermediateCatchEvent.js +40 -44
  91. package/src/events/IntermediateThrowEvent.js +15 -18
  92. package/src/events/StartEvent.js +84 -50
  93. package/src/flows/Association.js +98 -113
  94. package/src/flows/MessageFlow.js +81 -97
  95. package/src/flows/SequenceFlow.js +145 -163
  96. package/src/gateways/EventBasedGateway.js +75 -68
  97. package/src/gateways/ExclusiveGateway.js +8 -13
  98. package/src/gateways/InclusiveGateway.js +8 -13
  99. package/src/gateways/ParallelGateway.js +8 -13
  100. package/src/getPropertyValue.js +34 -33
  101. package/src/io/BpmnIO.js +20 -0
  102. package/src/io/EnvironmentDataObject.js +29 -18
  103. package/src/io/EnvironmentDataStore.js +33 -0
  104. package/src/io/EnvironmentDataStoreReference.js +33 -0
  105. package/src/io/InputOutputSpecification.js +154 -157
  106. package/src/io/Properties.js +199 -0
  107. package/src/process/Process.js +374 -333
  108. package/src/process/ProcessExecution.js +606 -554
  109. package/src/shared.js +1 -5
  110. package/src/tasks/CallActivity.js +130 -0
  111. package/src/tasks/LoopCharacteristics.js +290 -289
  112. package/src/tasks/ReceiveTask.js +174 -107
  113. package/src/tasks/ScriptTask.js +27 -30
  114. package/src/tasks/ServiceImplementation.js +13 -18
  115. package/src/tasks/ServiceTask.js +67 -60
  116. package/src/tasks/SignalTask.js +77 -52
  117. package/src/tasks/StandardLoopCharacteristics.js +1 -1
  118. package/src/tasks/SubProcess.js +184 -157
  119. package/src/tasks/Task.js +15 -19
@@ -10,25 +10,22 @@ var _Errors = require("../error/Errors");
10
10
  var _messageHelper = require("../messageHelper");
11
11
 
12
12
  function LoopCharacteristics(activity, loopCharacteristics) {
13
- const {
14
- id,
15
- broker,
16
- environment
17
- } = activity;
18
- const {
19
- batchSize = 50
20
- } = environment.settings;
13
+ this.activity = activity;
14
+ this.loopCharacteristics = loopCharacteristics;
21
15
  const {
22
16
  type = 'LoopCharacteristics',
23
17
  behaviour = {}
24
18
  } = loopCharacteristics;
19
+ this.type = type;
25
20
  const {
26
21
  isSequential = false,
27
- collection: collectionExpression,
28
- elementVariable = 'item'
22
+ collection
29
23
  } = behaviour;
24
+ this.isSequential = isSequential;
25
+ this.collection = collection;
30
26
  let completionCondition, startCondition, loopCardinality;
31
27
  if ('loopCardinality' in behaviour) loopCardinality = behaviour.loopCardinality;else if ('loopMaximum' in behaviour) loopCardinality = behaviour.loopMaximum;
28
+ this.loopCardinality = loopCardinality;
32
29
 
33
30
  if (behaviour.loopCondition) {
34
31
  if (behaviour.testBefore) startCondition = behaviour.loopCondition;else completionCondition = behaviour.loopCondition;
@@ -38,344 +35,326 @@ function LoopCharacteristics(activity, loopCharacteristics) {
38
35
  completionCondition = behaviour.completionCondition;
39
36
  }
40
37
 
41
- const loopType = getLoopType();
42
- if (!loopType) return;
38
+ if (collection) {
39
+ this.loopType = 'collection';
40
+ this.elementVariable = behaviour.elementVariable || 'item';
41
+ } else if (completionCondition) this.loopType = 'complete condition';else if (startCondition) this.loopType = 'start condition';else if (loopCardinality) this.loopType = 'cardinality';
42
+
43
+ this.characteristics = null;
44
+ this.execution = null;
45
+ }
46
+
47
+ LoopCharacteristics.prototype.execute = function execute(executeMessage) {
48
+ if (!executeMessage) throw new TypeError('LoopCharacteristics execution requires message');
49
+ const chr = this.characteristics = this.characteristics || new Characteristics(this.activity, this.loopCharacteristics, executeMessage);
50
+ if (chr.cardinality === 0) return chr.complete();
51
+ const execution = this.isSequential ? new SequentialLoopCharacteristics(this.activity, chr) : new ParallelLoopCharacteristics(this.activity, chr);
52
+ return execution.execute(executeMessage);
53
+ };
54
+
55
+ function SequentialLoopCharacteristics(activity, characteristics) {
56
+ this.activity = activity;
57
+ this.id = activity.id;
58
+ this.characteristics = characteristics;
59
+ }
60
+
61
+ SequentialLoopCharacteristics.prototype.execute = function execute(executeMessage) {
43
62
  const {
44
- debug
45
- } = environment.Logger(type.toLowerCase());
46
- const executeConsumerTag = '_execute-q-multi-instance-tag';
47
- broker.cancel(executeConsumerTag);
48
- const apiConsumerTag = '_api-multi-instance-tag';
49
- broker.cancel(apiConsumerTag);
50
- let loopSettings;
51
- const characteristicsApi = {
52
- type,
53
- loopType,
54
- collection: collectionExpression,
55
- elementVariable,
56
- isSequential,
57
- loopCardinality,
58
- execute
59
- };
60
- return characteristicsApi;
63
+ routingKey: executeRoutingKey,
64
+ redelivered: isRedelivered
65
+ } = executeMessage.fields || {};
66
+ const chr = this.characteristics;
61
67
 
62
- function getLoopType() {
63
- if (collectionExpression) return 'collection';
64
- if (completionCondition) return 'complete condition';
65
- if (startCondition) return 'start condition';
66
- if (loopCardinality) return 'cardinality';
68
+ if (!chr.cardinality && !chr.startCondition && !chr.completionCondition) {
69
+ throw new _Errors.RunError(`<${this.id}> cardinality, collection, or condition is required in sequential loops`, executeMessage);
67
70
  }
68
71
 
69
- function execute(executeMessage) {
70
- if (!executeMessage) throw new Error('LoopCharacteristics execution requires message');
71
- const {
72
- routingKey: executeRoutingKey,
73
- redelivered: isRedelivered
74
- } = executeMessage.fields || {};
75
- const {
76
- executionId: parentExecutionId
77
- } = executeMessage.content;
78
- if (!getCharacteristics()) return;
79
-
80
- try {
81
- return isSequential ? executeSequential() : executeParallel();
82
- } catch (err) {
83
- return activity.emitFatal(new _Errors.ActivityError(err.message, executeMessage, err), executeMessage.content);
84
- }
72
+ let startIndex = 0;
85
73
 
86
- function executeSequential() {
87
- const {
88
- cardinality,
89
- getContent: getStartContent
90
- } = getCharacteristics();
91
- if (cardinality === 0) return complete();
92
- if (!cardinality && !startCondition && !completionCondition) return activity.emitFatal(new _Errors.ActivityError(`<${id}> cardinality, collection, or condition is required in sequential loops`, executeMessage), getStartContent());
93
- let startIndex = 0;
94
-
95
- if (isRedelivered && executeRoutingKey === 'execute.iteration.next') {
96
- startIndex = executeMessage.content.index;
97
- }
98
-
99
- subscribe(onCompleteMessage);
100
- return startNext(startIndex, isRedelivered);
101
-
102
- function startNext(index, ignoreIfExecuting) {
103
- const content = next(index);
104
- if (!content) return;
105
- const characteristics = getCharacteristics();
106
-
107
- if (startCondition && isConditionMet(startCondition, {
108
- content
109
- })) {
110
- debug(`<${parentExecutionId} (${id})> start condition met`);
111
- return;
112
- }
113
-
114
- debug(`<${content.executionId} (${id})>`, ignoreIfExecuting ? 'resume' : 'start', `sequential iteration index ${content.index}`);
115
- broker.publish('execution', 'execute.iteration.next', { ...content,
116
- ...characteristics.getContent(),
117
- index,
118
- preventComplete: true,
119
- output: characteristics.output.slice(),
120
- state: 'iteration.next'
121
- });
122
- broker.publish('execution', 'execute.start', { ...content,
123
- ignoreIfExecuting
124
- });
125
- return content;
126
- }
127
-
128
- function onCompleteMessage(_, message) {
129
- const {
130
- content
131
- } = message;
132
- const loopOutput = getCharacteristics().output;
133
- if (content.output !== undefined) loopOutput[content.index] = content.output;
134
- broker.publish('execution', 'execute.iteration.completed', { ...message.content,
135
- ...getCharacteristics().getContent(),
136
- preventComplete: true,
137
- output: loopOutput.slice(),
138
- state: 'iteration.completed'
139
- });
140
-
141
- if (isConditionMet(completionCondition, message, loopOutput)) {
142
- debug(`<${parentExecutionId} (${id})> complete condition met`);
143
- } else if (startNext(content.index + 1)) return;
144
-
145
- debug(`<${parentExecutionId} (${id})> sequential loop completed`);
146
- return complete(content);
147
- }
148
-
149
- function complete(content) {
150
- stop();
151
- const {
152
- getContent,
153
- output
154
- } = getCharacteristics();
155
- return broker.publish('execution', 'execute.completed', { ...content,
156
- ...getContent(),
157
- output
158
- });
159
- }
160
- }
74
+ if (isRedelivered && executeRoutingKey === 'execute.iteration.next') {
75
+ startIndex = executeMessage.content.index;
76
+ }
161
77
 
162
- function executeParallel() {
163
- const {
164
- cardinality,
165
- getContent: getStartContent
166
- } = getCharacteristics();
167
- if (cardinality === 0) return complete();
168
- if (!cardinality) return activity.emitFatal(new _Errors.ActivityError(`<${id}> cardinality or collection is required in parallel loops`, executeMessage), getStartContent());
169
- let index = 0,
170
- running = 0;
171
-
172
- if (isRedelivered) {
173
- if (!isNaN(executeMessage.content.index)) index = executeMessage.content.index;
174
- if (!isNaN(executeMessage.content.running)) running = executeMessage.content.running;
175
- }
176
-
177
- subscribe(onCompleteMessage);
178
- if (isRedelivered) return;
179
- return startBatch();
180
-
181
- function startBatch() {
182
- const {
183
- output: loopOutput,
184
- getContent
185
- } = getCharacteristics();
186
- const batch = [];
187
- let startContent = next(index);
188
-
189
- do {
190
- debug(`<${parentExecutionId} (${id})> start parallel iteration index ${index}`);
191
- batch.push(startContent);
192
- running++;
193
- index++;
194
-
195
- if (index >= cardinality || running >= batchSize) {
196
- break;
197
- }
198
- } while (startContent = next(index));
199
-
200
- broker.publish('execution', 'execute.iteration.batch', { ...getContent(),
201
- index,
202
- running,
203
- output: loopOutput,
204
- preventComplete: true
205
- });
206
-
207
- for (const content of batch) {
208
- broker.publish('execution', 'execute.start', content);
209
- }
210
- }
211
-
212
- function onCompleteMessage(_, message) {
213
- const {
214
- content
215
- } = message;
216
- const {
217
- output: loopOutput
218
- } = getCharacteristics();
219
- if (content.output !== undefined) loopOutput[content.index] = content.output;
220
- running--;
221
- broker.publish('execution', 'execute.iteration.completed', { ...content,
222
- ...getCharacteristics().getContent(),
223
- index,
224
- running,
225
- output: loopOutput,
226
- state: 'iteration.completed',
227
- preventComplete: true
228
- });
229
-
230
- if (running <= 0 && !next(index)) {
231
- return complete(content);
232
- }
233
-
234
- if (isConditionMet(completionCondition, message)) {
235
- return complete(content);
236
- }
237
-
238
- if (running <= 0) {
239
- running = 0;
240
- startBatch();
241
- }
242
- }
243
-
244
- function complete(content) {
245
- stop();
246
- const {
247
- getContent,
248
- output
249
- } = getCharacteristics();
250
- return broker.publish('execution', 'execute.completed', { ...content,
251
- ...getContent(),
252
- output
253
- });
254
- }
255
- }
78
+ chr.subscribe(this._onCompleteMessage.bind(this));
79
+ return this._startNext(startIndex, isRedelivered);
80
+ };
256
81
 
257
- function next(index) {
258
- const executionId = `${parentExecutionId}_${index}`;
259
- const {
260
- cardinality,
261
- collection,
262
- parent,
263
- getContent
264
- } = getCharacteristics();
265
- const content = { ...getContent(),
266
- isRootScope: undefined,
267
- executionId,
268
- isMultiInstance: true,
269
- index,
270
- parent
271
- };
272
- if (isComplete(content)) return;
273
-
274
- if (collection) {
275
- content[elementVariable] = collection[index];
276
- }
277
-
278
- return content;
279
-
280
- function isComplete() {
281
- if (cardinality > 0 && index >= cardinality) return true;
282
- if (collection && index >= collection.length) return true;
283
- }
284
- }
82
+ SequentialLoopCharacteristics.prototype._startNext = function startNext(index, ignoreIfExecuting) {
83
+ const chr = this.characteristics;
84
+ const content = chr.next(index);
85
+ if (!content) return;
285
86
 
286
- function getCharacteristics() {
287
- if (loopSettings) return loopSettings;
288
- const collection = getCollection();
289
- const cardinality = getCardinality(collection);
290
- const messageContent = { ...(0, _messageHelper.cloneContent)(executeMessage.content),
291
- loopCardinality: cardinality,
292
- isSequential,
293
- output: undefined
294
- };
295
-
296
- if (cardinality !== undefined && isNaN(cardinality) || cardinality < 0) {
297
- return activity.emitFatal(new _Errors.ActivityError(`<${id}> invalid loop cardinality >${cardinality}<`, executeMessage), messageContent);
298
- }
299
-
300
- const output = executeMessage.content.output || [];
301
- const parent = (0, _messageHelper.unshiftParent)(executeMessage.content.parent, executeMessage.content);
302
- loopSettings = {
303
- cardinality,
304
- collection,
305
- messageContent,
306
- output,
307
- parent,
308
-
309
- getContent() {
310
- return (0, _messageHelper.cloneContent)(messageContent);
311
- }
312
-
313
- };
314
- return loopSettings;
87
+ if (chr.isStartConditionMet({
88
+ content
89
+ })) {
90
+ chr.debug('start condition met');
91
+ return;
92
+ }
93
+
94
+ chr.debug(`${ignoreIfExecuting ? 'resume' : 'start'} sequential iteration index ${content.index}`);
95
+ const broker = this.activity.broker;
96
+ broker.publish('execution', 'execute.iteration.next', { ...content,
97
+ ...chr.getContent(),
98
+ index,
99
+ preventComplete: true,
100
+ output: chr.output.slice(),
101
+ state: 'iteration.next'
102
+ });
103
+ broker.publish('execution', 'execute.start', { ...content,
104
+ ignoreIfExecuting
105
+ });
106
+ return content;
107
+ };
108
+
109
+ SequentialLoopCharacteristics.prototype._onCompleteMessage = function onCompleteMessage(_, message) {
110
+ const {
111
+ content
112
+ } = message;
113
+ const chr = this.characteristics;
114
+ const loopOutput = chr.output;
115
+ if (content.output !== undefined) loopOutput[content.index] = content.output;
116
+ this.activity.broker.publish('execution', 'execute.iteration.completed', { ...message.content,
117
+ ...chr.getContent(),
118
+ preventComplete: true,
119
+ output: loopOutput.slice(),
120
+ state: 'iteration.completed'
121
+ });
122
+
123
+ if (chr.isCompletionConditionMet(message, loopOutput)) {
124
+ chr.debug('complete condition met');
125
+ } else if (this._startNext(content.index + 1)) return;
126
+
127
+ chr.debug('sequential loop completed');
128
+ return chr.complete(content);
129
+ };
130
+
131
+ function ParallelLoopCharacteristics(activity, characteristics) {
132
+ this.activity = activity;
133
+ this.id = activity.id;
134
+ this.characteristics = characteristics;
135
+ this.running = 0;
136
+ this.index = 0;
137
+ }
138
+
139
+ ParallelLoopCharacteristics.prototype.execute = function execute(executeMessage) {
140
+ const chr = this.characteristics;
141
+ if (!chr.cardinality) throw new _Errors.RunError(`<${this.id}> cardinality or collection is required in parallel loops`, executeMessage);
142
+ const isRedelivered = executeMessage.fields.redelivered;
143
+
144
+ if (isRedelivered) {
145
+ if (!isNaN(executeMessage.content.index)) this.index = executeMessage.content.index;
146
+ if (!isNaN(executeMessage.content.running)) this.running = executeMessage.content.running;
147
+ }
148
+
149
+ chr.subscribe(this._onCompleteMessage.bind(this));
150
+ if (isRedelivered) return;
151
+ return this._startBatch();
152
+ };
153
+
154
+ ParallelLoopCharacteristics.prototype._startBatch = function startBatch() {
155
+ const chr = this.characteristics;
156
+ const cardinality = chr.cardinality;
157
+ const batch = [];
158
+ let startContent = chr.next(this.index);
159
+
160
+ do {
161
+ chr.debug(`start parallel iteration index ${this.index}`);
162
+ batch.push(startContent);
163
+ this.running++;
164
+ this.index++;
165
+
166
+ if (this.index >= cardinality || this.running >= chr.batchSize) {
167
+ break;
315
168
  }
169
+ } while (startContent = chr.next(this.index));
170
+
171
+ const broker = this.activity.broker;
172
+ broker.publish('execution', 'execute.iteration.batch', { ...chr.getContent(),
173
+ index: this.index,
174
+ running: this.running,
175
+ output: chr.output,
176
+ preventComplete: true
177
+ });
178
+
179
+ for (const content of batch) {
180
+ broker.publish('execution', 'execute.start', content);
181
+ }
182
+ };
316
183
 
317
- function getCardinality(collection) {
318
- const collectionLen = Array.isArray(collection) ? collection.length : undefined;
184
+ ParallelLoopCharacteristics.prototype._onCompleteMessage = function onCompleteMessage(_, message) {
185
+ const chr = this.characteristics;
186
+ const {
187
+ content
188
+ } = message;
189
+ if (content.output !== undefined) chr.output[content.index] = content.output;
190
+ this.running--;
191
+ this.activity.broker.publish('execution', 'execute.iteration.completed', { ...content,
192
+ ...chr.getContent(),
193
+ index: this.index,
194
+ running: this.running,
195
+ output: chr.output,
196
+ state: 'iteration.completed',
197
+ preventComplete: true
198
+ });
199
+
200
+ if (this.running <= 0 && !chr.next(this.index)) {
201
+ return chr.complete(content);
202
+ }
319
203
 
320
- if (!loopCardinality) {
321
- return collectionLen;
322
- }
204
+ if (chr.isCompletionConditionMet(message)) {
205
+ return chr.complete(content);
206
+ }
323
207
 
324
- const value = environment.resolveExpression(loopCardinality, executeMessage);
325
- if (value === undefined) return collectionLen;
326
- return Number(value);
327
- }
208
+ if (this.running <= 0) {
209
+ this.running = 0;
328
210
 
329
- function getCollection() {
330
- if (!collectionExpression) return;
331
- debug(`<${id}> has collection`);
332
- return environment.resolveExpression(collectionExpression, executeMessage);
333
- }
211
+ this._startBatch();
212
+ }
213
+ };
214
+
215
+ function Characteristics(activity, loopCharacteristics, executeMessage) {
216
+ this.activity = activity;
217
+ const behaviour = this.behaviour = loopCharacteristics.behaviour || {};
218
+ this.message = executeMessage;
219
+ const type = this.type = loopCharacteristics.type || 'LoopCharacteristics';
220
+ this.id = activity.id;
221
+ this.broker = activity.broker;
222
+ this.parentExecutionId = executeMessage.content.executionId;
223
+ this.isSequential = behaviour.isSequential || false;
224
+ this.output = executeMessage.content.output || [];
225
+ this.parent = (0, _messageHelper.unshiftParent)(executeMessage.content.parent, executeMessage.content);
226
+ if ('loopCardinality' in behaviour) this.loopCardinality = behaviour.loopCardinality;else if ('loopMaximum' in behaviour) this.loopCardinality = behaviour.loopMaximum;
334
227
 
335
- function subscribe(onIterationCompleteMessage) {
336
- broker.subscribeTmp('api', `activity.*.${parentExecutionId}`, onApiMessage, {
337
- noAck: true,
338
- consumerTag: apiConsumerTag
339
- }, {
340
- priority: 400
341
- });
342
- broker.subscribeTmp('execution', 'execute.*', onComplete, {
343
- noAck: true,
344
- consumerTag: executeConsumerTag,
345
- priority: 300
346
- });
347
-
348
- function onComplete(routingKey, message, ...args) {
349
- if (!message.content.isMultiInstance) return;
350
-
351
- switch (routingKey) {
352
- case 'execute.cancel':
353
- case 'execute.completed':
354
- return onIterationCompleteMessage(routingKey, message, ...args);
355
- }
356
- }
357
- }
228
+ if (behaviour.loopCondition) {
229
+ if (behaviour.testBefore) this.startCondition = behaviour.loopCondition;else this.completionCondition = behaviour.loopCondition;
358
230
  }
359
231
 
360
- function onApiMessage(_, message) {
361
- switch (message.properties.type) {
362
- case 'stop':
363
- case 'discard':
364
- stop();
365
- break;
366
- }
232
+ if (behaviour.completionCondition) {
233
+ this.completionCondition = behaviour.completionCondition;
234
+ }
235
+
236
+ const collection = this.collection = this.getCollection();
237
+
238
+ if (collection) {
239
+ this.elementVariable = behaviour.elementVariable || 'item';
240
+ }
241
+
242
+ this.cardinality = this.getCardinality(collection);
243
+ this.onApiMessage = this.onApiMessage.bind(this);
244
+ const environment = activity.environment;
245
+ this.logger = environment.Logger(type.toLowerCase());
246
+ this.batchSize = environment.settings.batchSize || 50;
247
+ }
248
+
249
+ Characteristics.prototype.getContent = function getContent() {
250
+ return { ...(0, _messageHelper.cloneContent)(this.message.content),
251
+ loopCardinality: this.cardinality,
252
+ isSequential: this.isSequential,
253
+ output: undefined
254
+ };
255
+ };
256
+
257
+ Characteristics.prototype.next = function next(index) {
258
+ const cardinality = this.cardinality;
259
+ if (cardinality > 0 && index >= cardinality) return;
260
+ const collection = this.collection;
261
+ if (collection && index >= collection.length) return;
262
+ const content = { ...this.getContent(),
263
+ isRootScope: undefined,
264
+ executionId: `${this.parentExecutionId}_${index}`,
265
+ isMultiInstance: true,
266
+ parent: (0, _messageHelper.cloneParent)(this.parent),
267
+ index
268
+ };
269
+
270
+ if (collection) {
271
+ content[this.elementVariable] = collection[index];
272
+ }
273
+
274
+ return content;
275
+ };
276
+
277
+ Characteristics.prototype.getCardinality = function getCardinality(collection) {
278
+ const collectionLen = this.collection && Array.isArray(collection) ? collection.length : undefined;
279
+
280
+ if (!this.loopCardinality) {
281
+ return collectionLen;
367
282
  }
368
283
 
369
- function stop() {
370
- broker.cancel(executeConsumerTag);
371
- broker.cancel(apiConsumerTag);
284
+ const value = this.activity.environment.resolveExpression(this.loopCardinality, this.message);
285
+
286
+ if (value !== undefined && isNaN(value) || value < 0) {
287
+ throw new _Errors.RunError(`<${this.id}> invalid loop cardinality >${value}<`, this.message);
372
288
  }
373
289
 
374
- function isConditionMet(condition, message, loopOutput) {
375
- if (!condition) return false;
376
- const testContext = (0, _messageHelper.cloneMessage)(message, {
377
- loopOutput
378
- });
379
- return environment.resolveExpression(condition, testContext);
290
+ if (value === undefined) return collectionLen;
291
+ return Number(value);
292
+ };
293
+
294
+ Characteristics.prototype.getCollection = function getCollection() {
295
+ const collectionExpression = this.behaviour.collection;
296
+ if (!collectionExpression) return;
297
+ return this.activity.environment.resolveExpression(collectionExpression, this.message);
298
+ };
299
+
300
+ Characteristics.prototype.isStartConditionMet = function isStartConditionMet(message) {
301
+ if (!this.startCondition) return false;
302
+ return this.activity.environment.resolveExpression(this.startCondition, (0, _messageHelper.cloneMessage)(message));
303
+ };
304
+
305
+ Characteristics.prototype.isCompletionConditionMet = function isCompletionConditionMet(message) {
306
+ if (!this.completionCondition) return false;
307
+ return this.activity.environment.resolveExpression(this.completionCondition, (0, _messageHelper.cloneMessage)(message, {
308
+ loopOutput: this.output
309
+ }));
310
+ };
311
+
312
+ Characteristics.prototype.complete = function complete(content) {
313
+ this.stop();
314
+ return this.broker.publish('execution', 'execute.completed', { ...content,
315
+ ...this.getContent(),
316
+ output: this.output
317
+ });
318
+ };
319
+
320
+ Characteristics.prototype.subscribe = function subscribe(onIterationCompleteMessage) {
321
+ this.broker.subscribeTmp('api', `activity.*.${this.parentExecutionId}`, this.onApiMessage, {
322
+ noAck: true,
323
+ consumerTag: '_api-multi-instance-tag'
324
+ }, {
325
+ priority: 400
326
+ });
327
+ this.broker.subscribeTmp('execution', 'execute.*', onComplete, {
328
+ noAck: true,
329
+ consumerTag: '_execute-q-multi-instance-tag',
330
+ priority: 300
331
+ });
332
+
333
+ function onComplete(routingKey, message, ...args) {
334
+ if (!message.content.isMultiInstance) return;
335
+
336
+ switch (routingKey) {
337
+ case 'execute.cancel':
338
+ case 'execute.completed':
339
+ return onIterationCompleteMessage(routingKey, message, ...args);
340
+ }
341
+ }
342
+ };
343
+
344
+ Characteristics.prototype.onApiMessage = function onApiMessage(_, message) {
345
+ switch (message.properties.type) {
346
+ case 'stop':
347
+ case 'discard':
348
+ this.stop();
349
+ break;
380
350
  }
381
- }
351
+ };
352
+
353
+ Characteristics.prototype.stop = function stop() {
354
+ this.broker.cancel('_execute-q-multi-instance-tag');
355
+ this.broker.cancel('_api-multi-instance-tag');
356
+ };
357
+
358
+ Characteristics.prototype.debug = function debug(msg) {
359
+ this.logger.debug(`<${this.parentExecutionId} (${this.id})> ${msg}`);
360
+ };