bpmn 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/lib/{spot_flow → bpmn}/context.rb +5 -5
- data/lib/bpmn/definitions.rb +53 -0
- data/lib/bpmn/element.rb +42 -0
- data/lib/bpmn/event.rb +193 -0
- data/lib/bpmn/event_definition.rb +133 -0
- data/lib/{spot_flow → bpmn}/execution.rb +7 -7
- data/lib/bpmn/extension_elements.rb +27 -0
- data/lib/bpmn/extensions.rb +75 -0
- data/lib/bpmn/flow.rb +45 -0
- data/lib/bpmn/gateway.rb +83 -0
- data/lib/bpmn/process.rb +177 -0
- data/lib/bpmn/step.rb +56 -0
- data/lib/bpmn/task.rb +126 -0
- data/lib/bpmn/version.rb +5 -0
- data/lib/{spot_flow.rb → bpmn.rb} +19 -8
- metadata +17 -18
- data/lib/spot_flow/bpmn/definitions.rb +0 -55
- data/lib/spot_flow/bpmn/element.rb +0 -44
- data/lib/spot_flow/bpmn/event.rb +0 -195
- data/lib/spot_flow/bpmn/event_definition.rb +0 -135
- data/lib/spot_flow/bpmn/extension_elements.rb +0 -29
- data/lib/spot_flow/bpmn/extensions.rb +0 -77
- data/lib/spot_flow/bpmn/flow.rb +0 -47
- data/lib/spot_flow/bpmn/gateway.rb +0 -85
- data/lib/spot_flow/bpmn/process.rb +0 -179
- data/lib/spot_flow/bpmn/step.rb +0 -58
- data/lib/spot_flow/bpmn/task.rb +0 -128
- data/lib/spot_flow/bpmn.rb +0 -18
- data/lib/spot_flow/version.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ffd863edea8a05d607b816c4fc0464968a822db50e8389ccfd36cc68734e6ba
|
4
|
+
data.tar.gz: 624fc1a44f2b4c6c9c3dd1bd309ce6d0a2a381f74fe975a65c067616384d2af3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9581fe6232d79731cb29b5267afeced58fd5c8f817ba7e98ee77aadfb048ef8f05f0e0851010cce4f78e0de4b18beddfc812874ce0cf99e6b0ae46d6e43e6370
|
7
|
+
data.tar.gz: 338dad681a7d7ec6c67bb1a16b2cb42a0745575cb66fe23fbea2479eeee9b430248ed94a0bb6c0bbb49809eaa3c9494a3de028b381239a3ffd0d221b9d79b1d7
|
data/README.md
CHANGED
@@ -15,14 +15,14 @@ Processes are made of a series of tasks. Tasks can be manual (require `signal` t
|
|
15
15
|
- BusinessRuleTask (automated): evaluates the decision_id (expects dmn source to be included in the context).
|
16
16
|
- ScriptTask (automated): evaluates the FEEL expression in the script property.
|
17
17
|
|
18
|
-
To start the process, initialize
|
18
|
+
To start the process, initialize with the BPMN and DMN source files, then call `start`.
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
sources = [
|
22
22
|
File.read("hello_world.bpmn"),
|
23
23
|
File.read("choose_greeting.dmn")
|
24
24
|
]
|
25
|
-
execution =
|
25
|
+
execution = BPMN.new(sources).start
|
26
26
|
```
|
27
27
|
|
28
28
|
It's often useful to print the process state to the console.
|
@@ -39,7 +39,7 @@ HelloWorld started * Flow_080794y
|
|
39
39
|
2 BoundaryEvent EggTimer: waiting
|
40
40
|
```
|
41
41
|
|
42
|
-
The HelloWorld process began at the Start event and is _waiting_ at the IntroduceYourself user task. This is an important concept in the
|
42
|
+
The HelloWorld process began at the Start event and is _waiting_ at the IntroduceYourself user task. This is an important concept in the BPMN engine. It's designed to be used in a Rails application where a process might be waiting for a user to complete a form, or a background job to complete. It's common to save the state the process until a task is complete. Calling `serialize` on a process will return the execution state so it can be continued later.
|
43
43
|
|
44
44
|
```ruby
|
45
45
|
# Returns a hash of the process state.
|
@@ -49,7 +49,7 @@ execution_state = execution.serialize
|
|
49
49
|
# or a background job completes (ServiceTask)
|
50
50
|
|
51
51
|
# Restores the process from the execution state.
|
52
|
-
execution =
|
52
|
+
execution = BPMN.restore(sources, execution_state:)
|
53
53
|
|
54
54
|
# Now we can continue the process by `signaling` the waiting task.
|
55
55
|
step = execution.step_by_element_id("IntroduceYourself")
|
@@ -162,13 +162,13 @@ HelloWorld completed *
|
|
162
162
|
Execute:
|
163
163
|
|
164
164
|
```bash
|
165
|
-
$ bundle add
|
165
|
+
$ bundle add bpmn
|
166
166
|
```
|
167
167
|
|
168
168
|
Or install it directly:
|
169
169
|
|
170
170
|
```bash
|
171
|
-
$ gem install
|
171
|
+
$ gem install bpmn
|
172
172
|
```
|
173
173
|
|
174
174
|
## Development
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module BPMN
|
4
4
|
class Context
|
5
5
|
attr_reader :sources, :processes, :decisions, :services, :executions
|
6
6
|
attr_reader :bpmn_definitions, :dmn_definitions
|
@@ -11,15 +11,15 @@ module SpotFlow
|
|
11
11
|
@bpmn_definitions = []
|
12
12
|
@dmn_definitions = []
|
13
13
|
@decisions = Array.wrap(decisions)
|
14
|
-
@services = HashWithIndifferentAccess.new((
|
14
|
+
@services = HashWithIndifferentAccess.new((BPMN.config.services || {}).merge(services))
|
15
15
|
|
16
16
|
@sources.each do |source|
|
17
17
|
if source.include?("http://www.omg.org/spec/DMN/20180521/DC/")
|
18
|
-
definitions =
|
18
|
+
definitions = DMN.definitions_from_xml(source)
|
19
19
|
@dmn_definitions << definitions
|
20
20
|
@decisions += definitions.decisions
|
21
21
|
else
|
22
|
-
@processes +=
|
22
|
+
@processes += BPMN.processes_from_xml(source)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -55,7 +55,7 @@ module SpotFlow
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def notify_listener(*args)
|
58
|
-
|
58
|
+
BPMN.config.listener&.call(args)
|
59
59
|
end
|
60
60
|
|
61
61
|
def default_process
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Definitions
|
5
|
+
include ActiveModel::Model
|
6
|
+
|
7
|
+
attr_accessor :id, :name, :target_namespace, :exporter, :exporter_version, :execution_platform, :execution_platform_version
|
8
|
+
attr_reader :messages, :signals, :errors, :processes
|
9
|
+
|
10
|
+
def self.from_xml(xml)
|
11
|
+
XmlHasher.configure do |config|
|
12
|
+
config.snakecase = true
|
13
|
+
config.ignore_namespaces = true
|
14
|
+
config.string_keys = false
|
15
|
+
end
|
16
|
+
hash = XmlHasher.parse(xml)
|
17
|
+
Definitions.new(hash[:definitions].except(:bpmn_diagram)).tap do |definitions|
|
18
|
+
definitions.processes.each do |process|
|
19
|
+
process.wire_references(definitions)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(attributes={})
|
25
|
+
super(attributes.except(:message, :signal, :error, :process))
|
26
|
+
|
27
|
+
@messages = Array.wrap(attributes[:message]).map { |atts| Message.new(atts) }
|
28
|
+
@signals = Array.wrap(attributes[:signal]).map { |atts| Signal.new(atts) }
|
29
|
+
@errors = Array.wrap(attributes[:error]).map { |atts| Error.new(atts) }
|
30
|
+
@processes = Array.wrap(attributes[:process]).map { |atts| Process.new(atts) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def message_by_id(id)
|
34
|
+
messages.find { |message| message.id == id }
|
35
|
+
end
|
36
|
+
|
37
|
+
def signal_by_id(id)
|
38
|
+
signals.find { |signal| signal.id == id }
|
39
|
+
end
|
40
|
+
|
41
|
+
def error_by_id(id)
|
42
|
+
errors.find { |error| error.id == id }
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_by_id(id)
|
46
|
+
processes.find { |process| process.id == id }
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
"#<BPMN::Definitions @id=#{id.inspect} @name=#{name.inspect} @messages=#{messages.inspect} @signals=#{signals.inspect} @errors=#{errors.inspect} @processes=#{processes.inspect}>"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/bpmn/element.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Element
|
5
|
+
include ActiveModel::Model
|
6
|
+
|
7
|
+
attr_accessor :id, :name, :extension_elements
|
8
|
+
|
9
|
+
def initialize(attributes = {})
|
10
|
+
super(attributes.slice(:id, :name))
|
11
|
+
|
12
|
+
@extension_elements = ExtensionElements.new(attributes[:extension_elements]) if attributes[:extension_elements].present?
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#<#{self.class.name.gsub(/BPMN::/, "")} @id=#{id.inspect} @name=#{name.inspect}>"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Message < Element
|
21
|
+
end
|
22
|
+
|
23
|
+
class Signal < Element
|
24
|
+
end
|
25
|
+
|
26
|
+
class Error < Element
|
27
|
+
end
|
28
|
+
|
29
|
+
class Collaboration < Element
|
30
|
+
end
|
31
|
+
|
32
|
+
class LaneSet < Element
|
33
|
+
end
|
34
|
+
|
35
|
+
class Participant < Element
|
36
|
+
attr_accessor :process_ref, :process
|
37
|
+
|
38
|
+
def initialize(attributes = {})
|
39
|
+
super(attributes.except(:process_ref))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/bpmn/event.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Event < Step
|
5
|
+
attr_accessor :event_definitions
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
super(attributes.except(:message_event_definition, :signal_event_definition, :error_event_definition, :terminate_event_definition, :timer_event_definition))
|
9
|
+
|
10
|
+
@event_definitions = []
|
11
|
+
|
12
|
+
Array.wrap(attributes[:message_event_definition]).each do |med|
|
13
|
+
@event_definitions.push MessageEventDefinition.new(med)
|
14
|
+
end if attributes[:message_event_definition].present?
|
15
|
+
|
16
|
+
Array.wrap(attributes[:signal_event_definition]).each do |sed|
|
17
|
+
@event_definitions.push SignalEventDefinition.new(sed)
|
18
|
+
end if attributes[:signal_event_definition].present?
|
19
|
+
|
20
|
+
Array.wrap(attributes[:error_event_definition]).each do |eed|
|
21
|
+
@event_definitions.push ErrorEventDefinition.new(eed)
|
22
|
+
end if attributes[:error_event_definition].present?
|
23
|
+
|
24
|
+
Array.wrap(attributes[:terminate_event_definition]).each do |ted|
|
25
|
+
@event_definitions.push TerminateEventDefinition.new(ted)
|
26
|
+
end if attributes[:terminate_event_definition].present?
|
27
|
+
|
28
|
+
Array.wrap(attributes[:timer_event_definition]).each do |ted|
|
29
|
+
@event_definitions.push TimerEventDefinition.new(ted)
|
30
|
+
end if attributes[:timer_event_definition].present?
|
31
|
+
end
|
32
|
+
|
33
|
+
def event_definition_ids
|
34
|
+
event_definitions.map(&:id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_catching?
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def is_throwing?
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def is_none?
|
46
|
+
event_definitions.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_conditional?
|
50
|
+
conditional_event_definition.present?
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_escalation?
|
54
|
+
escalation_event_definition.present?
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_error?
|
58
|
+
error_event_definition.present?
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_message?
|
62
|
+
!message_event_definitions.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_signal?
|
66
|
+
!signal_event_definitions.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_terminate?
|
70
|
+
terminate_event_definition.present?
|
71
|
+
end
|
72
|
+
|
73
|
+
def is_timer?
|
74
|
+
timer_event_definition.present?
|
75
|
+
end
|
76
|
+
|
77
|
+
def conditional_event_definition
|
78
|
+
event_definitions.find { |ed| ed.is_a?(ConditionalEventDefinition) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def escalation_event_definition
|
82
|
+
event_definitions.find { |ed| ed.is_a?(EscalationEventDefinition) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def error_event_definitions
|
86
|
+
event_definitions.select { |ed| ed.is_a?(ErrorEventDefinition) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def error_event_definition
|
90
|
+
event_definitions.find { |ed| ed.is_a?(ErrorEventDefinition) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def message_event_definitions
|
94
|
+
event_definitions.select { |ed| ed.is_a?(MessageEventDefinition) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def signal_event_definitions
|
98
|
+
event_definitions.select { |ed| ed.is_a?(SignalEventDefinition) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def terminate_event_definition
|
102
|
+
event_definitions.find { |ed| ed.is_a?(TerminateEventDefinition) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def timer_event_definition
|
106
|
+
event_definitions.find { |ed| ed.is_a?(TimerEventDefinition) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def execute(execution)
|
110
|
+
event_definitions.each { |event_definition| event_definition.execute(execution) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class StartEvent < Event
|
115
|
+
|
116
|
+
def is_catching?
|
117
|
+
true
|
118
|
+
end
|
119
|
+
|
120
|
+
def execute(execution)
|
121
|
+
super
|
122
|
+
leave(execution)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class IntermediateThrowEvent < Event
|
127
|
+
|
128
|
+
def is_throwing?
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
def execute(execution)
|
133
|
+
super
|
134
|
+
leave(execution)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class IntermediateCatchEvent < Event
|
139
|
+
|
140
|
+
def is_catching?
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute(execution)
|
145
|
+
super
|
146
|
+
execution.wait
|
147
|
+
end
|
148
|
+
|
149
|
+
def signal(execution)
|
150
|
+
leave(execution)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class BoundaryEvent < Event
|
155
|
+
attr_accessor :attached_to_ref, :attached_to, :cancel_activity
|
156
|
+
|
157
|
+
def initialize(attributes = {})
|
158
|
+
super(attributes.except(:attached_to_ref, :cancel_activity))
|
159
|
+
|
160
|
+
@attached_to_ref = attributes[:attached_to_ref]
|
161
|
+
@cancel_activity = true
|
162
|
+
if attributes[:cancel_activity].present?
|
163
|
+
@cancel_activity = attributes[:cancel_activity] == "false" ? false : true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def is_catching?
|
168
|
+
true
|
169
|
+
end
|
170
|
+
|
171
|
+
def execute(execution)
|
172
|
+
super
|
173
|
+
execution.wait
|
174
|
+
end
|
175
|
+
|
176
|
+
def signal(execution)
|
177
|
+
execution.attached_to.terminate if cancel_activity
|
178
|
+
leave(execution)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class EndEvent < Event
|
183
|
+
|
184
|
+
def is_throwing?
|
185
|
+
true
|
186
|
+
end
|
187
|
+
|
188
|
+
def execute(execution)
|
189
|
+
super
|
190
|
+
execution.end(true)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class EventDefinition < Element
|
5
|
+
def execute(execution)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class ConditionalEventDefinition < EventDefinition
|
10
|
+
attr_accessor :variable_name, :variable_events, :condition
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
super(attributes.except(:variable_name, :variable_events, :condition))
|
14
|
+
|
15
|
+
@variable_name = moddle[:variable_name] # "var1"
|
16
|
+
@variable_events = moddle[:variable_events] # "create, update"
|
17
|
+
@condition = moddle[:condition] # var1 = 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class EscalationEventDefinition < EventDefinition
|
22
|
+
end
|
23
|
+
|
24
|
+
class ErrorEventDefinition < EventDefinition
|
25
|
+
attr_accessor :error_ref, :error
|
26
|
+
attr_accessor :error_code_variable, :error_message_variable
|
27
|
+
|
28
|
+
def initialize(attributes = {})
|
29
|
+
super(attributes.except(:error_ref, :error_code_variable, :error_message_variable))
|
30
|
+
|
31
|
+
@error_ref = attributes[:error_ref]
|
32
|
+
@error_code_variable = attributes[:error_code_variable]
|
33
|
+
@error_message_variable = attributes[:error_message_variable]
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute(execution)
|
37
|
+
if execution.step.is_throwing?
|
38
|
+
execution.throw_error(error_name)
|
39
|
+
else
|
40
|
+
execution.error_names.push error_name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def error_id
|
45
|
+
error&.id
|
46
|
+
end
|
47
|
+
|
48
|
+
def error_name
|
49
|
+
error&.name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class MessageEventDefinition < EventDefinition
|
54
|
+
attr_accessor :message_ref, :message
|
55
|
+
|
56
|
+
def initialize(attributes = {})
|
57
|
+
super(attributes.except(:message_ref))
|
58
|
+
|
59
|
+
@message_ref = attributes[:message_ref]
|
60
|
+
end
|
61
|
+
|
62
|
+
def execute(execution)
|
63
|
+
if execution.step.is_throwing?
|
64
|
+
execution.throw_message(message_name)
|
65
|
+
else
|
66
|
+
execution.message_names.push message_name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def message_id
|
71
|
+
message&.id
|
72
|
+
end
|
73
|
+
|
74
|
+
def message_name
|
75
|
+
message&.name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class SignalEventDefinition < EventDefinition
|
80
|
+
attr_accessor :signal_ref, :signal
|
81
|
+
|
82
|
+
def initialize(attributes = {})
|
83
|
+
super(attributes.except(:signal_ref))
|
84
|
+
|
85
|
+
@signal_ref = moddle[:signal_ref]
|
86
|
+
end
|
87
|
+
|
88
|
+
def signal_id
|
89
|
+
signal&.id
|
90
|
+
end
|
91
|
+
|
92
|
+
def signal_name
|
93
|
+
signal&.name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class TerminateEventDefinition < EventDefinition
|
98
|
+
|
99
|
+
def execute(execution)
|
100
|
+
execution.parent&.terminate
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class TimerEventDefinition < EventDefinition
|
105
|
+
attr_accessor :time_date, :time_duration_type, :time_duration, :time_cycle
|
106
|
+
|
107
|
+
def initialize(attributes = {})
|
108
|
+
super(attributes.except(:time_date, :time_duration, :time_cycle))
|
109
|
+
|
110
|
+
@time_duration_type = attributes[:time_duration_type]
|
111
|
+
@time_duration = attributes[:time_duration]
|
112
|
+
end
|
113
|
+
|
114
|
+
def execute(execution)
|
115
|
+
if execution.step.is_catching?
|
116
|
+
execution.timer_expires_at = time_due
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def time_due
|
123
|
+
# Return the next time the timer is due
|
124
|
+
if time_date
|
125
|
+
return Date.parse(time_date)
|
126
|
+
elsif time_duration
|
127
|
+
return Time.zone.now + ActiveSupport::Duration.parse(time_duration)
|
128
|
+
else
|
129
|
+
return Time.zone.now # time_cycle not yet implemented
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module BPMN
|
4
4
|
class Execution
|
5
5
|
attr_accessor :id, :status, :started_at, :ended_at, :variables, :tokens_in, :tokens_out, :start_event_id, :timer_expires_at, :message_names, :error_names, :condition
|
6
6
|
attr_accessor :step, :parent, :children, :context, :attached_to_id
|
@@ -97,7 +97,7 @@ module SpotFlow
|
|
97
97
|
@started_at = Time.zone.now
|
98
98
|
map_input_variables if step&.input_mappings&.present?
|
99
99
|
context.notify_listener(:execution_started, execution: self)
|
100
|
-
step.attachments.each { |attachment| parent.execute_step(attachment, attached_to: self) } if step.is_a?(
|
100
|
+
step.attachments.each { |attachment| parent.execute_step(attachment, attached_to: self) } if step.is_a?(BPMN::Activity)
|
101
101
|
continue
|
102
102
|
end
|
103
103
|
|
@@ -147,7 +147,7 @@ module SpotFlow
|
|
147
147
|
def throw_message(message_name, variables: {})
|
148
148
|
waiting_children.each do |child|
|
149
149
|
step = child.step
|
150
|
-
if step.is_a?(
|
150
|
+
if step.is_a?(BPMN::Event) && step.message_event_definitions.any? { |message_event_definition| message_event_definition.message_name == message_name }
|
151
151
|
child.signal(variables)
|
152
152
|
break
|
153
153
|
end
|
@@ -158,7 +158,7 @@ module SpotFlow
|
|
158
158
|
def throw_error(error_name, variables: {})
|
159
159
|
waiting_children.each do |child|
|
160
160
|
step = child.step
|
161
|
-
if step.is_a?(
|
161
|
+
if step.is_a?(BPMN::Event) && step.error_event_definitions.any? { |error_event_definition| error_event_definition.error_name == error_name }
|
162
162
|
child.signal(variables)
|
163
163
|
break
|
164
164
|
end
|
@@ -175,7 +175,7 @@ module SpotFlow
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def evaluate_expression(expression, variables: parent&.variables || {}.with_indifferent_access)
|
178
|
-
|
178
|
+
DMN.evaluate(expression.delete_prefix("="), variables:)
|
179
179
|
end
|
180
180
|
|
181
181
|
def run_automated_tasks
|
@@ -202,7 +202,7 @@ module SpotFlow
|
|
202
202
|
# Called by the child step executors when they have ended
|
203
203
|
#
|
204
204
|
def has_ended(_child)
|
205
|
-
step.leave(self) if step.is_a?(
|
205
|
+
step.leave(self) if step.is_a?(BPMN::SubProcess) || step.is_a?(BPMN::CallActivity)
|
206
206
|
self.end(true)
|
207
207
|
end
|
208
208
|
|
@@ -219,7 +219,7 @@ module SpotFlow
|
|
219
219
|
end
|
220
220
|
|
221
221
|
def waiting_tasks
|
222
|
-
waiting_children.select { |child| child.step.is_a?(
|
222
|
+
waiting_children.select { |child| child.step.is_a?(BPMN::Task) }
|
223
223
|
end
|
224
224
|
|
225
225
|
def waiting_automated_tasks
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class ExtensionElements
|
5
|
+
VALID_EXTENSION_NAMESPACES = %w[zeebe]
|
6
|
+
|
7
|
+
attr_accessor :assignment_definition, :called_element, :called_decision, :form_definition, :io_mapping, :properties, :script, :subscription, :task_definition, :task_headers, :task_schedule
|
8
|
+
|
9
|
+
def initialize(attributes = {})
|
10
|
+
if attributes[:properties].present?
|
11
|
+
@properties = HashWithIndifferentAccess.new
|
12
|
+
Array.wrap(attributes[:properties][:property]).each { |property_moddle| @properties[property_moddle[:name]] = property_moddle[:value] }
|
13
|
+
end
|
14
|
+
|
15
|
+
@assignment_definition = Zeebe::AssignmentDefinition.new(attributes[:assignment_definition]) if attributes[:assignment_definition].present?
|
16
|
+
@called_element = Zeebe::CalledElement.new(attributes[:called_element]) if attributes[:called_element].present?
|
17
|
+
@called_decision = Zeebe::CalledDecision.new(attributes[:called_decision]) if attributes[:called_decision].present?
|
18
|
+
@form_definition = Zeebe::FormDefinition.new(attributes[:form_definition]) if attributes[:form_definition].present?
|
19
|
+
@io_mapping = Zeebe::IoMapping.new(attributes[:io_mapping]) if attributes[:io_mapping].present?
|
20
|
+
@script = Zeebe::Script.new(attributes[:script]) if attributes[:script].present?
|
21
|
+
@subscription = Zeebe::Subscription.new(attributes[:subscription]) if attributes[:subscription].present?
|
22
|
+
@task_definition = Zeebe::TaskDefinition.new(attributes[:task_definition]) if attributes[:task_definition].present?
|
23
|
+
@task_headers = Zeebe::TaskHeaders.new(attributes[:task_headers]) if attributes[:task_headers].present?
|
24
|
+
@task_schedule = Zeebe::TaskSchedule.new(attributes[:task_schedule]) if attributes[:task_schedule].present?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Extension
|
5
|
+
include ActiveModel::Model
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Zeebe
|
10
|
+
class AssignmentDefinition < BPMN::Extension
|
11
|
+
attr_accessor :assignee, :candidate_groups, :candidate_users
|
12
|
+
end
|
13
|
+
|
14
|
+
class CalledElement < BPMN::Extension
|
15
|
+
attr_accessor :process_id, :propagate_all_child_variables, :propagate_all_parent_variables
|
16
|
+
|
17
|
+
def initialize(attributes = {})
|
18
|
+
super(attributes.except(:propagate_all_child_variables))
|
19
|
+
|
20
|
+
@propagate_all_parent_variables = true
|
21
|
+
@propagate_all_parent_variables = attributes[:propagate_all_parent_variables] == "true" if attributes[:propagate_all_parent_variables].present?
|
22
|
+
@propagate_all_child_variables = attributes[:propagate_all_child_variables] == "true"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class CalledDecision < BPMN::Extension
|
27
|
+
attr_accessor :decision_id, :result_variable
|
28
|
+
end
|
29
|
+
|
30
|
+
class FormDefinition < BPMN::Extension
|
31
|
+
attr_accessor :form_key
|
32
|
+
end
|
33
|
+
|
34
|
+
class IoMapping < BPMN::Extension
|
35
|
+
attr_reader :inputs, :outputs
|
36
|
+
|
37
|
+
def initialize(attributes = {})
|
38
|
+
super(attributes.except(:input, :output))
|
39
|
+
|
40
|
+
@inputs = Array.wrap(attributes[:input]).map { |atts| Parameter.new(atts) } if attributes[:input].present?
|
41
|
+
@outputs = Array.wrap(attributes[:output]).map { |atts| Parameter.new(atts) } if attributes[:output].present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Parameter < BPMN::Extension
|
46
|
+
attr_accessor :source, :target
|
47
|
+
end
|
48
|
+
|
49
|
+
class Script < BPMN::Extension
|
50
|
+
attr_accessor :expression, :result_variable
|
51
|
+
end
|
52
|
+
|
53
|
+
class Subscription < BPMN::Extension
|
54
|
+
attr_accessor :correlation_key
|
55
|
+
end
|
56
|
+
|
57
|
+
class TaskDefinition < BPMN::Extension
|
58
|
+
attr_accessor :type, :retries
|
59
|
+
end
|
60
|
+
|
61
|
+
class TaskHeaders < BPMN::Extension
|
62
|
+
attr_accessor :headers
|
63
|
+
|
64
|
+
def initialize(attributes = {})
|
65
|
+
super(attributes.except(:header))
|
66
|
+
|
67
|
+
@headers = HashWithIndifferentAccess.new
|
68
|
+
Array.wrap(attributes[:header]).each { |header| @headers[header[:key]] = header[:value] }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class TaskSchedule < BPMN::Extension
|
73
|
+
attr_accessor :due_date, :follow_up_date
|
74
|
+
end
|
75
|
+
end
|