bpmn-elements 8.0.1 → 8.2.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.
@@ -4,6 +4,7 @@ import {toSeconds, parse} from 'iso8601-duration';
4
4
  const kStopped = Symbol.for('stopped');
5
5
  const kTimerContent = Symbol.for('timerContent');
6
6
  const kTimer = Symbol.for('timer');
7
+ const repeatPattern = /^\s*R(\d+)\//;
7
8
 
8
9
  export default function TimerEventDefinition(activity, eventDefinition) {
9
10
  const type = this.type = eventDefinition.type || 'TimerEventDefinition';
@@ -63,7 +64,7 @@ proto.execute = function execute(executeMessage) {
63
64
  const resolvedTimer = this._getTimers(executeMessage);
64
65
  const timerContent = this[kTimerContent] = cloneContent(content, {
65
66
  ...resolvedTimer,
66
- ...(isResumed ? {isResumed} : undefined),
67
+ ...(isResumed && {isResumed}),
67
68
  startedAt,
68
69
  state: 'timer',
69
70
  });
@@ -112,6 +113,12 @@ proto._completed = function completed(completeContent, options) {
112
113
 
113
114
  const broker = this.broker;
114
115
  broker.publish('event', 'activity.timeout', cloneContent(timerContent, content), options);
116
+
117
+ if (timerContent.repeat > 1) {
118
+ const repeat = timerContent.repeat - 1;
119
+ broker.publish('execution', 'execute.repeat', cloneContent(timerContent, {...content, repeat}), options);
120
+ }
121
+
115
122
  broker.publish('execution', 'execute.completed', cloneContent(timerContent, content), options);
116
123
  };
117
124
 
@@ -146,7 +153,7 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
146
153
  this._stop();
147
154
  return this._completed({
148
155
  state: 'cancel',
149
- ...(message.content.message ? {message: message.content.message} : undefined),
156
+ ...(message.content.message && {message: message.content.message}),
150
157
  }, {correlationId});
151
158
  }
152
159
  case 'stop': {
@@ -175,7 +182,7 @@ proto._getTimers = function getTimers(executeMessage) {
175
182
 
176
183
  const now = Date.now();
177
184
  const result = {
178
- ...('expireAt' in content ? {expireAt: new Date(content.expireAt)} : undefined),
185
+ ...('expireAt' in content && {expireAt: new Date(content.expireAt)}),
179
186
  };
180
187
 
181
188
  for (const t of ['timeDuration', 'timeDate', 'timeCycle']) {
@@ -183,33 +190,39 @@ proto._getTimers = function getTimers(executeMessage) {
183
190
  else if (t in this) result[t] = this.environment.resolveExpression(this[t], executeMessage);
184
191
  else continue;
185
192
 
186
- let expireAtDate;
187
- if (t === 'timeDuration') {
188
- const durationStr = result[t];
189
- if (durationStr) {
190
- const delay = this._getDurationInMilliseconds(durationStr);
191
- if (delay !== undefined) expireAtDate = new Date(now + delay);
192
- } else {
193
- expireAtDate = new Date(now);
194
- }
195
- } else if (t === 'timeDate') {
196
- const dateStr = result[t];
197
- if (dateStr) {
198
- const ms = Date.parse(dateStr);
199
- if (!isNaN(ms)) {
200
- expireAtDate = new Date(ms);
201
- } else {
202
- this._warn(`invalid timeDate >${dateStr}<`);
193
+ let expireAtDate, repeat;
194
+ const timerStr = result[t];
195
+ if (timerStr) {
196
+ switch (t) {
197
+ case 'timeCycle': {
198
+ const mRepeat = timerStr.match(repeatPattern);
199
+ if (mRepeat && mRepeat.length) repeat = parseInt(mRepeat[1]);
200
+ }
201
+ case 'timeDuration': {
202
+ const delay = this._getDurationInMilliseconds(timerStr);
203
+ if (delay !== undefined) expireAtDate = new Date(now + delay);
204
+ break;
205
+ }
206
+ case 'timeDate': {
207
+ const dateStr = result[t];
208
+ const ms = Date.parse(dateStr);
209
+ if (!isNaN(ms)) {
210
+ expireAtDate = new Date(ms);
211
+ } else {
212
+ this._warn(`invalid timeDate >${dateStr}<`);
213
+ }
214
+ break;
203
215
  }
204
- } else {
205
- expireAtDate = new Date(now);
206
216
  }
217
+ } else {
218
+ expireAtDate = new Date(now);
207
219
  }
208
220
 
209
221
  if (!expireAtDate) continue;
210
222
  if (!('expireAt' in result) || result.expireAt > expireAtDate) {
211
223
  result.timerType = t;
212
224
  result.expireAt = expireAtDate;
225
+ if (repeat) result.repeat = repeat;
213
226
  }
214
227
  }
215
228
 
@@ -221,6 +234,10 @@ proto._getTimers = function getTimers(executeMessage) {
221
234
  result.timeout = 0;
222
235
  }
223
236
 
237
+ if (content.inbound && 'repeat' in content.inbound[0]) {
238
+ result.repeat = content.inbound[0].repeat;
239
+ }
240
+
224
241
  return result;
225
242
  };
226
243
 
@@ -228,7 +245,7 @@ proto._getDurationInMilliseconds = function getDurationInMilliseconds(duration)
228
245
  try {
229
246
  return toSeconds(parse(duration)) * 1000;
230
247
  } catch (err) {
231
- this._warn(`failed to parse timeDuration >${duration}<: ${err.message}`);
248
+ this._warn(`failed to parse ${this.timerType} >${duration}<: ${err.message}`);
232
249
  }
233
250
  };
234
251
 
@@ -50,13 +50,6 @@ proto.execute = function execute(executeMessage) {
50
50
  this[kExecuteMessage] = executeMessage;
51
51
 
52
52
  const broker = this.broker;
53
- if (eventDefinitionExecution && !this.environment.settings.strict) {
54
- broker.subscribeTmp('execution', 'execute.expect', this._onExpectMessage.bind(this), {
55
- noAck: true,
56
- consumerTag: '_expect-tag',
57
- });
58
- }
59
-
60
53
  const consumerTag = `_bound-listener-${executionId}`;
61
54
  this.attachedTo.broker.subscribeTmp('event', 'activity.leave', this._onAttachedLeave.bind(this), {
62
55
  noAck: true,
@@ -65,15 +58,19 @@ proto.execute = function execute(executeMessage) {
65
58
  });
66
59
  this[kAttachedTags].push(consumerTag);
67
60
 
68
- broker.subscribeOnce('execution', 'execute.detach', this._onDetachMessage.bind(this), {
69
- consumerTag: '_detach-tag',
70
- });
71
61
  broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), {
72
62
  consumerTag: `_api-${executionId}`,
73
63
  });
74
- broker.subscribeOnce('execution', 'execute.bound.completed', this._onCompleted.bind(this), {
75
- consumerTag: `_execution-completed-${executionId}`,
76
- });
64
+
65
+ const execQ = broker.assertQueue(`_bound-execution-${executionId}`, {durable: false, autoDelete: true});
66
+ broker.bindQueue(execQ.name, 'execution', 'execute.detach');
67
+ broker.bindQueue(execQ.name, 'execution', 'execute.bound.completed');
68
+ broker.bindQueue(execQ.name, 'execution', 'execute.repeat');
69
+ if (eventDefinitionExecution && !this.environment.settings.strict) {
70
+ broker.bindQueue(execQ.name, 'execution', 'execute.expect');
71
+ }
72
+
73
+ execQ.consume(this._onExecutionMessage.bind(this), {consumerTag: '_execution-tag'});
77
74
  }
78
75
 
79
76
  if (eventDefinitionExecution) {
@@ -81,15 +78,29 @@ proto.execute = function execute(executeMessage) {
81
78
  }
82
79
  };
83
80
 
81
+ proto._onExecutionMessage = function onExecutionMessage(routingKey, message) {
82
+ message.ack();
83
+ switch (routingKey) {
84
+ case 'execute.detach':
85
+ return this._onDetachMessage(routingKey, message);
86
+ case 'execute.bound.completed':
87
+ return this._onCompleted(routingKey, message);
88
+ case 'execute.repeat':
89
+ return this._onRepeatMessage(routingKey, message);
90
+ case 'execute.expect':
91
+ return this._onExpectMessage(routingKey, message);
92
+ }
93
+ };
94
+
84
95
  proto._onCompleted = function onCompleted(_, {content}) {
85
96
  if (!this.cancelActivity && !content.cancelActivity) {
86
97
  this._stop();
87
- return this.broker.publish('execution', 'execute.completed', cloneContent(content));
98
+ return this.broker.publish('execution', 'execute.completed', cloneContent(content, {cancelActivity: false}));
88
99
  }
89
100
 
90
101
  this[kCompleteContent] = content;
91
102
 
92
- const {inbound} = this[kExecuteMessage].content;
103
+ const inbound = this[kExecuteMessage].content.inbound;
93
104
  const attachedToContent = inbound && inbound[0];
94
105
  const attachedTo = this.attachedTo;
95
106
  this.activity.logger.debug(`<${this.executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
@@ -160,13 +171,19 @@ proto._onApiMessage = function onApiMessage(_, message) {
160
171
  }
161
172
  };
162
173
 
174
+ proto._onRepeatMessage = function onRepeatMessage(_, message) {
175
+ if (this.cancelActivity) return;
176
+ const executeMessage = this[kExecuteMessage];
177
+ const repeat = message.content.repeat;
178
+ this.broker.getQueue('inbound-q').queueMessage({routingKey: 'activity.restart'}, cloneContent(executeMessage.content.inbound[0], {repeat}));
179
+ };
180
+
163
181
  proto._stop = function stop(detach) {
164
182
  const attachedTo = this.attachedTo, broker = this.broker, executionId = this.executionId;
165
183
  for (const tag of this[kAttachedTags].splice(0)) attachedTo.broker.cancel(tag);
166
184
  for (const shovelName of this[kShovels].splice(0)) attachedTo.broker.closeShovel(shovelName);
167
185
 
168
- broker.cancel('_expect-tag');
169
- broker.cancel('_detach-tag');
186
+ broker.cancel('_execution-tag');
170
187
  broker.cancel(`_execution-completed-${executionId}`);
171
188
 
172
189
  if (detach) return;
package/src/io/BpmnIO.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export default function BpmnIO(activity, context) {
2
2
  this.activity = activity;
3
3
  this.context = context;
4
+ this.type = 'bpmnio';
4
5
 
5
6
  const {
6
7
  ioSpecification: ioSpecificationDef,
@@ -11,6 +12,12 @@ export default function BpmnIO(activity, context) {
11
12
  this.properties = propertiesDef && new propertiesDef.Behaviour(activity, propertiesDef, context);
12
13
  }
13
14
 
15
+ Object.defineProperty(BpmnIO.prototype, 'hasIo', {
16
+ get() {
17
+ return this.specification || this.properties;
18
+ },
19
+ });
20
+
14
21
  BpmnIO.prototype.activate = function activate(message) {
15
22
  const properties = this.properties, specification = this.specification;
16
23
  if (properties) properties.activate(message);
@@ -9,6 +9,7 @@ export default function EnvironmentDataObject(dataObjectDef, {environment}) {
9
9
  }
10
10
 
11
11
  EnvironmentDataObject.prototype.read = function read(broker, exchange, routingKeyPrefix, messageProperties) {
12
+
12
13
  const environment = this.environment;
13
14
  const value = environment.variables._data && environment.variables._data[this.id];
14
15
  const content = this._createContent(value);
@@ -15,8 +15,14 @@ export default function IoSpecification(activity, ioSpecificationDef, context) {
15
15
 
16
16
  const proto = IoSpecification.prototype;
17
17
 
18
- proto.activate = function activate() {
18
+ proto.activate = function activate(message) {
19
19
  if (this[kConsuming]) return;
20
+ if (message && message.fields.redelivered && message.fields.routingKey === 'run.start') {
21
+ this._onFormatEnter();
22
+ }
23
+ if (message && message.fields.redelivered && message.fields.routingKey === 'run.end') {
24
+ this._onFormatComplete(message);
25
+ }
20
26
  this[kConsuming] = this.broker.subscribeTmp('event', 'activity.#', this._onActivityEvent.bind(this), {noAck: true});
21
27
  };
22
28
 
@@ -107,6 +113,7 @@ proto._onFormatComplete = function formatOnComplete(message) {
107
113
  const broker = this.broker;
108
114
  const context = this.context;
109
115
 
116
+
110
117
  const {dataObjects, sources} = dataOutputs.reduce((result, ioSource, index) => {
111
118
  const {value} = messageOutputs.find((output) => output.id === ioSource.id) || {};
112
119
  const source = {
@@ -117,7 +124,6 @@ proto._onFormatComplete = function formatOnComplete(message) {
117
124
  };
118
125
  result.sources.push(source);
119
126
 
120
-
121
127
  const dataObjectId = getPropertyValue(ioSource, 'behaviour.association.target.dataObject.id');
122
128
  if (!dataObjectId) return result;
123
129
  const dataObject = context.getDataObjectById(dataObjectId);
@@ -143,8 +149,10 @@ proto._onFormatComplete = function formatOnComplete(message) {
143
149
  broker.publish('format', `${startRoutingKey}.begin`, {
144
150
  endRoutingKey,
145
151
  ioSpecification: {
146
- dataInputs: sources.map((input) => {
147
- return {...input};
152
+ ...(messageInputs && {
153
+ dataInputs: messageInputs.map((input) => {
154
+ return {...input};
155
+ }),
148
156
  }),
149
157
  dataOutputs: this._getDataOutputs(dataOutputs),
150
158
  },
@@ -155,8 +163,12 @@ proto._onFormatComplete = function formatOnComplete(message) {
155
163
 
156
164
  broker.publish('format', endRoutingKey, {
157
165
  ioSpecification: {
158
- dataInputs: sources,
159
- dataOutputs: this._getDataOutputs(dataOutputs),
166
+ ...(messageInputs && {
167
+ dataInputs: messageInputs.map((input) => {
168
+ return {...input};
169
+ }),
170
+ }),
171
+ dataOutputs: sources,
160
172
  },
161
173
  });
162
174
  });
@@ -13,7 +13,6 @@ export default function Properties(activity, propertiesDef, context) {
13
13
  dataOutputObjects: [],
14
14
  };
15
15
 
16
-
17
16
  for (const {id, ...def} of propertiesDef.values) {
18
17
  const source = {
19
18
  id,
@@ -62,6 +61,9 @@ const proto = Properties.prototype;
62
61
 
63
62
  proto.activate = function activate(message) {
64
63
  if (this[kConsuming]) return;
64
+ if (message.fields.redelivered && message.fields.routingKey === 'run.start') {
65
+ this._onActivityEvent('activity.enter', message);
66
+ }
65
67
 
66
68
  if (message.fields.redelivered && message.content.properties) {
67
69
  this._onActivityEvent('activity.extension.resume', message);
@@ -75,16 +77,12 @@ proto.deactivate = function deactivate() {
75
77
  };
76
78
 
77
79
  proto._onActivityEvent = function onActivityEvent(routingKey, message) {
78
- if (routingKey === 'activity.enter') {
79
- return this._formatOnEnter(message);
80
- }
81
-
82
- if (routingKey === 'activity.extension.resume') {
83
- return this._formatOnEnter(message);
84
- }
85
-
86
- if (routingKey === 'activity.execution.completed') {
87
- return this._formatOnComplete(message);
80
+ switch (routingKey) {
81
+ case 'activity.enter':
82
+ case 'activity.extension.resume':
83
+ return this._formatOnEnter(message);
84
+ case 'activity.execution.completed':
85
+ return this._formatOnComplete(message);
88
86
  }
89
87
  };
90
88
 
@@ -46,9 +46,7 @@ proto.execute = function execute(executeMessage) {
46
46
 
47
47
  proto.getService = function getService(message) {
48
48
  let Service = this.activity.behaviour.Service;
49
- if (!Service) {
50
- Service = this.environment.settings.enableDummyService ? DummyService : null;
51
- }
49
+ if (!Service && this.environment.settings.enableDummyService) Service = DummyService;
52
50
  return Service && new Service(this.activity, cloneMessage(message));
53
51
  };
54
52