Skip to content

Commit ebcdde9

Browse files
authored
Merge pull request #343 from sartography/feature/event-payloads
Feature/event payloads
2 parents 9bd018e + 8763647 commit ebcdde9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+4659
-1159
lines changed

SpiffWorkflow/bpmn/event.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class BpmnEvent:
2+
def __init__(self, event_definition, payload=None, correlations=None, target=None):
3+
self.event_definition = event_definition
4+
self.payload = payload
5+
self.correlations = correlations or {}
6+
self.target = target
7+
8+
9+
class PendingBpmnEvent:
10+
def __init__(self, name, event_type, value=None):
11+
self.name = name
12+
self.event_type = event_type
13+
self.value = value

SpiffWorkflow/bpmn/parser/BpmnParser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
BoundaryEvent,
4646
EventBasedGateway
4747
)
48-
from SpiffWorkflow.bpmn.specs.event_definitions import NoneEventDefinition, TimerEventDefinition
48+
from SpiffWorkflow.bpmn.specs.event_definitions.simple import NoneEventDefinition
49+
from SpiffWorkflow.bpmn.specs.event_definitions.timer import TimerEventDefinition
4950
from SpiffWorkflow.bpmn.specs.mixins.subworkflow_task import SubWorkflowTask as SubWorkflowTaskMixin
5051
from SpiffWorkflow.bpmn.specs.mixins.events.start_event import StartEvent as StartEventMixin
5152

SpiffWorkflow/bpmn/parser/TaskParser.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
SequentialMultiInstanceTask,
2626
ParallelMultiInstanceTask
2727
)
28-
from SpiffWorkflow.bpmn.specs.control import _BoundaryEventParent
29-
from SpiffWorkflow.bpmn.specs.event_definitions import CancelEventDefinition
28+
from SpiffWorkflow.bpmn.specs.control import BoundaryEventSplit, BoundaryEventJoin
29+
from SpiffWorkflow.bpmn.specs.event_definitions.simple import CancelEventDefinition
3030
from SpiffWorkflow.bpmn.specs.data_spec import TaskDataReference
3131

3232
from .util import one
@@ -160,18 +160,23 @@ def _add_multiinstance_task(self, loop_characteristics):
160160

161161
def _add_boundary_event(self, children):
162162

163-
parent = _BoundaryEventParent(
164-
self.spec, '%s.BoundaryEventParent' % self.bpmn_id,
165-
self.task, lane=self.task.lane)
166-
self.process_parser.parsed_nodes[self.node.get('id')] = parent
167-
parent.connect(self.task)
163+
split_task = BoundaryEventSplit(self.spec, f'{self.bpmn_id}.BoundaryEventSplit', lane=self.task.lane)
164+
join_task = BoundaryEventJoin(
165+
self.spec,
166+
f'{self.bpmn_id}.BoundaryEventJoin',
167+
lane=self.task.lane,
168+
split_task=split_task.name,
169+
cancel=True
170+
)
171+
split_task.connect(self.task)
172+
self.task.connect(join_task)
168173
for event in children:
169174
child = self.process_parser.parse_node(event)
170-
if isinstance(child.event_definition, CancelEventDefinition) \
171-
and not isinstance(self.task, TransactionSubprocess):
175+
if isinstance(child.event_definition, CancelEventDefinition) and not isinstance(self.task, TransactionSubprocess):
172176
self.raise_validation_exception('Cancel Events may only be used with transactions')
173-
parent.connect(child)
174-
return parent
177+
split_task.connect(child)
178+
child.connect(join_task)
179+
return split_task
175180

176181
def parse_node(self):
177182
"""
@@ -198,8 +203,7 @@ def parse_node(self):
198203
boundary_event_nodes = self.doc_xpath('.//bpmn:boundaryEvent[@attachedToRef="%s"]' % self.bpmn_id)
199204
if boundary_event_nodes:
200205
parent = self._add_boundary_event(boundary_event_nodes)
201-
else:
202-
self.process_parser.parsed_nodes[self.node.get('id')] = self.task
206+
self.process_parser.parsed_nodes[self.node.get('id')] = self.task
203207

204208
children = []
205209
outgoing = self.doc_xpath('.//bpmn:sequenceFlow[@sourceRef="%s"]' % self.bpmn_id)

SpiffWorkflow/bpmn/parser/event_parsers.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,28 @@
2222
from .ValidationException import ValidationException
2323
from .TaskParser import TaskParser
2424
from .util import first, one
25-
from ..specs.event_definitions import (
26-
MultipleEventDefinition,
25+
26+
from SpiffWorkflow.bpmn.specs.event_definitions.simple import (
27+
NoneEventDefinition,
28+
CancelEventDefinition,
29+
TerminateEventDefinition
30+
)
31+
from SpiffWorkflow.bpmn.specs.event_definitions.timer import (
2732
TimeDateEventDefinition,
2833
DurationTimerEventDefinition,
29-
CycleTimerEventDefinition,
30-
MessageEventDefinition,
31-
ErrorEventDefinition,
32-
EscalationEventDefinition,
34+
CycleTimerEventDefinition
35+
)
36+
from SpiffWorkflow.bpmn.specs.event_definitions.item_aware_event import (
3337
SignalEventDefinition,
34-
CancelEventDefinition,
35-
TerminateEventDefinition,
36-
NoneEventDefinition,
38+
ErrorEventDefinition,
39+
EscalationEventDefinition
40+
)
41+
from SpiffWorkflow.bpmn.specs.event_definitions.message import (
42+
MessageEventDefinition,
3743
CorrelationProperty
3844
)
45+
from SpiffWorkflow.bpmn.specs.event_definitions.multiple import MultipleEventDefinition
46+
3947

4048
CANCEL_EVENT_XPATH = './/bpmn:cancelEventDefinition'
4149
ERROR_EVENT_XPATH = './/bpmn:errorEventDefinition'

SpiffWorkflow/bpmn/serializer/event_definition.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,24 @@
1717
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1818
# 02110-1301 USA
1919

20-
from SpiffWorkflow.bpmn.specs.event_definitions import (
20+
from SpiffWorkflow.bpmn.specs.event_definitions.simple import (
21+
NoneEventDefinition,
2122
CancelEventDefinition,
23+
TerminateEventDefinition,
24+
)
25+
from SpiffWorkflow.bpmn.specs.event_definitions.item_aware_event import (
26+
SignalEventDefinition,
2227
ErrorEventDefinition,
2328
EscalationEventDefinition,
24-
MessageEventDefinition,
25-
NoneEventDefinition,
26-
SignalEventDefinition,
27-
TerminateEventDefinition,
29+
)
30+
from SpiffWorkflow.bpmn.specs.event_definitions.timer import (
2831
TimeDateEventDefinition,
2932
DurationTimerEventDefinition,
3033
CycleTimerEventDefinition,
31-
MultipleEventDefinition,
3234
)
35+
from SpiffWorkflow.bpmn.specs.event_definitions.message import MessageEventDefinition
36+
from SpiffWorkflow.bpmn.specs.event_definitions.multiple import MultipleEventDefinition
37+
3338
from .helpers.spec import EventDefinitionConverter
3439

3540
class CancelEventDefinitionConverter(EventDefinitionConverter):
@@ -44,7 +49,7 @@ def __init__(self, registry):
4449

4550
def to_dict(self, event_definition):
4651
dct = super().to_dict(event_definition)
47-
dct['error_code'] = event_definition.error_code
52+
dct['code'] = event_definition.code
4853
return dct
4954

5055

@@ -55,7 +60,7 @@ def __init__(self, registry):
5560

5661
def to_dict(self, event_definition):
5762
dct = super().to_dict(event_definition)
58-
dct['escalation_code'] = event_definition.escalation_code
63+
dct['code'] = event_definition.code
5964
return dct
6065

6166

SpiffWorkflow/bpmn/serializer/helpers/spec.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@
2222
from SpiffWorkflow.operators import Attrib, PathAttrib
2323

2424
from SpiffWorkflow.bpmn.specs.mixins.bpmn_spec_mixin import BpmnSpecMixin
25-
from SpiffWorkflow.bpmn.specs.event_definitions import (
26-
NamedEventDefinition,
27-
TimerEventDefinition,
28-
CorrelationProperty
29-
)
25+
from SpiffWorkflow.bpmn.specs.event_definitions.message import CorrelationProperty
3026

3127

3228
class BpmnSpecConverter:
@@ -96,19 +92,13 @@ class EventDefinitionConverter(BpmnSpecConverter):
9692

9793
def to_dict(self, event_definition):
9894
dct = {
99-
'internal': event_definition.internal,
100-
'external': event_definition.external,
10195
'description': event_definition.description,
96+
'name': event_definition.name
10297
}
103-
if isinstance(event_definition, (NamedEventDefinition, TimerEventDefinition)):
104-
dct['name'] = event_definition.name
10598
return dct
10699

107100
def from_dict(self, dct):
108-
internal, external = dct.pop('internal'), dct.pop('external')
109101
event_definition = self.spec_class(**dct)
110-
event_definition.internal = internal
111-
event_definition.external = external
112102
return event_definition
113103

114104
def correlation_properties_to_dict(self, props):

SpiffWorkflow/bpmn/serializer/migration/version_1_2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from datetime import datetime, timedelta
2121

2222
from SpiffWorkflow.task import TaskState
23-
from SpiffWorkflow.bpmn.specs.event_definitions import LOCALTZ
23+
from SpiffWorkflow.bpmn.specs.event_definitions.timer import LOCALTZ
2424

2525
from .exceptions import VersionMigrationError
2626

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
from uuid import uuid4
2+
3+
def update_event_definition_attributes(dct):
4+
5+
def update_specs(wf_spec):
6+
for spec in wf_spec['task_specs'].values():
7+
if 'event_definition' in spec:
8+
spec['event_definition'].pop('internal', None)
9+
spec['event_definition'].pop('external', None)
10+
if 'escalation_code' in spec['event_definition']:
11+
spec['event_definition']['code'] = spec['event_definition'].pop('escalation_code')
12+
if 'error_code' in spec['event_definition']:
13+
spec['event_definition']['code'] = spec['event_definition'].pop('error_code')
14+
15+
update_specs(dct['spec'])
16+
for sp_spec in dct['subprocess_specs'].values():
17+
update_specs(sp_spec)
18+
19+
def remove_boundary_event_parent(dct):
20+
21+
def update_specs(wf_spec):
22+
new_specs, delete_specs = {}, []
23+
for spec in wf_spec['task_specs'].values():
24+
if spec['typename'] == '_BoundaryEventParent':
25+
delete_specs.append(spec['name'])
26+
spec.pop('main_child_task_spec')
27+
spec['typename'] = 'BoundaryEventSplit'
28+
spec['name'] = spec['name'].replace('BoundaryEventParent', 'BoundaryEventSplit')
29+
new_specs[spec['name']] = spec
30+
join = {
31+
"name": spec['name'].replace('BoundaryEventSplit', 'BoundaryEventJoin'),
32+
"manual": False,
33+
"bpmn_id": None,
34+
"lookahead": 2,
35+
"inputs": spec['outputs'],
36+
"outputs": [],
37+
"split_task": spec['name'],
38+
"threshold": None,
39+
"cancel": True,
40+
"typename": "BoundaryEventJoin"
41+
}
42+
new_specs[join['name']] = join
43+
44+
for parent in spec['inputs']:
45+
parent_spec = wf_spec['task_specs'][parent]
46+
parent_spec['outputs'] = [name.replace('BoundaryEventParent', 'BoundaryEventSplit') for name in parent_spec['outputs']]
47+
48+
for child in spec['outputs']:
49+
child_spec = wf_spec['task_specs'][child]
50+
child_spec['outputs'].append(join['name'])
51+
child_spec['inputs'] = [name.replace('BoundaryEventParent', 'BoundaryEventSplit') for name in child_spec['inputs']]
52+
53+
wf_spec['task_specs'].update(new_specs)
54+
for name in delete_specs:
55+
del wf_spec['task_specs'][name]
56+
57+
def update_tasks(wf):
58+
new_tasks = {}
59+
for task in wf['tasks'].values():
60+
if task['task_spec'].endswith('BoundaryEventParent'):
61+
task['task_spec'] = task['task_spec'].replace('BoundaryEventParent', 'BoundaryEventSplit')
62+
completed = all([ wf['tasks'][child]['state'] in [64, 256] for child in task['children'] ])
63+
for child in task['children']:
64+
child_task = wf['tasks'][child]
65+
if child_task['state'] < 8:
66+
# MAYBE, LIKELY, FUTURE: use parent state
67+
state = child_task['state']
68+
elif child_task['state'] < 64:
69+
# WAITING, READY, STARTED (definite): join is FUTURE
70+
state = 4
71+
elif child_task['state'] == 64:
72+
# COMPLETED: if the join is not finished, WAITING, otherwise COMPLETED
73+
state = 64 if completed else 8
74+
elif child_task['state'] == 128:
75+
# ERROR: we don't know what the original state was, but we can't proceed through the gateway
76+
state = 8
77+
else:
78+
# Cancelled tasks don't have children
79+
continue
80+
new_task = {
81+
'id': str(uuid4()),
82+
'parent': child_task['id'],
83+
'children': [],
84+
'state': state,
85+
'task_spec': task['task_spec'].replace('BoundaryEventSplit', 'BoundaryEventJoin'),
86+
'last_state_change': None,
87+
'triggered': False,
88+
'internal_data': {},
89+
'data': {},
90+
}
91+
child_task['children'].append(new_task['id'])
92+
new_tasks[new_task['id']] = new_task
93+
94+
wf['tasks'].update(new_tasks)
95+
pass
96+
97+
update_specs(dct['spec'])
98+
for sp_spec in dct['subprocess_specs'].values():
99+
update_specs(sp_spec)
100+
101+
update_tasks(dct)
102+
for sp in dct['subprocesses'].values():
103+
update_tasks(sp)

SpiffWorkflow/bpmn/serializer/migration/version_migration.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
convert_simple_tasks,
3131
update_bpmn_attributes,
3232
)
33+
from .version_1_3 import update_event_definition_attributes, remove_boundary_event_parent
34+
35+
def from_version_1_2(old):
36+
new = deepcopy(old)
37+
update_event_definition_attributes(new)
38+
remove_boundary_event_parent(new)
39+
new['VERSION'] = "1.3"
40+
return new
3341

3442
def from_version_1_1(old):
3543
"""
@@ -62,7 +70,7 @@ def from_version_1_1(old):
6270
convert_simple_tasks(new)
6371
update_bpmn_attributes(new)
6472
new['VERSION'] = "1.2"
65-
return new
73+
return from_version_1_2(new)
6674

6775
def from_version_1_0(old):
6876
"""
@@ -85,4 +93,5 @@ def from_version_1_0(old):
8593
MIGRATIONS = {
8694
'1.0': from_version_1_0,
8795
'1.1': from_version_1_1,
96+
'1.2': from_version_1_2,
8897
}

SpiffWorkflow/bpmn/serializer/process_spec.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
# 02110-1301 USA
1919

2020
from SpiffWorkflow.bpmn.specs.bpmn_process_spec import BpmnProcessSpec
21-
from SpiffWorkflow.bpmn.specs.control import _BoundaryEventParent
2221

2322
from .helpers.spec import WorkflowSpecConverter
2423

@@ -89,8 +88,6 @@ def from_dict(self, dct):
8988

9089
# Now we have to go back and fix all the circular references to everything
9190
for task_spec in spec.task_specs.values():
92-
if isinstance(task_spec, _BoundaryEventParent):
93-
task_spec.main_child_task_spec = spec.get_task_spec_from_name(task_spec.main_child_task_spec)
9491
task_spec.inputs = [ spec.get_task_spec_from_name(name) for name in task_spec.inputs ]
9592
task_spec.outputs = [ spec.get_task_spec_from_name(name) for name in task_spec.outputs ]
9693

0 commit comments

Comments
 (0)