cpee 1.3.136 → 1.3.137
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.
- data/cpee.gemspec +1 -1
- data/lib/cpee/bpmn2.rb +280 -0
- data/lib/cpee/cpee.rb +129 -0
- data/lib/cpee/processtransformation/structures.rb +4 -0
- data/lib/cpee/structures.rb +437 -0
- metadata +4 -1
data/cpee.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "cpee"
|
3
|
-
s.version = "1.3.
|
3
|
+
s.version = "1.3.137"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.license = "LGPL-3"
|
6
6
|
s.summary = "Preliminary release of cloud process execution engine (cpee). If you just need workflow execution, without a rest/xmpp service exposing it, then use WEEL"
|
data/lib/cpee/bpmn2.rb
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# This file is part of CPEE.
|
4
|
+
#
|
5
|
+
# Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Copyright (c) 2013 Juergen Mangler
|
8
|
+
#
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
# you may not use this file except in compliance with the License.
|
11
|
+
# You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
# See the License for the specific language governing permissions and
|
19
|
+
# limitations under the License.
|
20
|
+
|
21
|
+
require File.expand_path(File.dirname(__FILE__) + '/structures')
|
22
|
+
require 'rubygems'
|
23
|
+
require 'xml/smart'
|
24
|
+
require 'highline'
|
25
|
+
|
26
|
+
module CPEE
|
27
|
+
|
28
|
+
module ProcessTransformation
|
29
|
+
|
30
|
+
module Source
|
31
|
+
|
32
|
+
class BPMN2
|
33
|
+
attr_reader :dataelements, :endpoints, :start, :graph
|
34
|
+
|
35
|
+
def initialize(xml) #{{{
|
36
|
+
@tree = Tree.new
|
37
|
+
@hl = HighLine.new
|
38
|
+
@start = nil
|
39
|
+
|
40
|
+
doc = XML::Smart.string(xml)
|
41
|
+
doc.register_namespace 'bm', "http://www.omg.org/spec/BPMN/20100524/MODEL"
|
42
|
+
|
43
|
+
@dataelements = {}
|
44
|
+
@endpoints = {}
|
45
|
+
@graph = Graph.new
|
46
|
+
|
47
|
+
extract_dataelements(doc)
|
48
|
+
extract_endpoints(doc)
|
49
|
+
extract_nodelink(doc)
|
50
|
+
|
51
|
+
@traces = Traces.new [[@start]]
|
52
|
+
end #}}}
|
53
|
+
|
54
|
+
def extract_dataelements(doc)
|
55
|
+
doc.find("/bm:definitions/bm:process/bm:property[bm:dataState/@name='cpee:dataelement']").each do |ref|
|
56
|
+
if ref.attributes['itemSubjectRef']
|
57
|
+
doc.find("/bm:definitions/bm:itemDefinition[@id=\"" + ref.attributes['itemSubjectRef'] + "\"]").each do |sref|
|
58
|
+
@dataelements[ref.attributes['name']] = sref.attributes['structureRef'].to_s
|
59
|
+
end
|
60
|
+
else
|
61
|
+
@dataelements[ref.attributes['name']] = ''
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_endpoints(doc)
|
67
|
+
doc.find("/bm:definitions/bm:process/bm:property[bm:dataState/@name='cpee:endpoint']/@itemSubjectRef").each do |ref|
|
68
|
+
doc.find("/bm:definitions/bm:itemDefinition[@id=\"" + ref.value + "\"]/@structureRef").each do |sref|
|
69
|
+
@endpoints[ref.value] = sref.value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def extract_nodelink(doc)
|
75
|
+
doc.find("/bm:definitions/bm:process/bm:*[@id and @name and not(@itemSubjectRef) and not(name()='sequenceFlow')]").each do |e|
|
76
|
+
n = Node.new(e.attributes['id'],e.qname.name.to_sym,e.attributes['name'].strip,e.find('count(bm:incoming)'),e.find('count(bm:outgoing)'))
|
77
|
+
|
78
|
+
if e.attributes['scriptFormat'] != ''
|
79
|
+
n.script_type = e.attributes['scriptFormat']
|
80
|
+
end
|
81
|
+
|
82
|
+
e.find("bm:property[@name='cpee:endpoint']/@itemSubjectRef").each do |ep|
|
83
|
+
n.endpoints << ep.value
|
84
|
+
end
|
85
|
+
e.find("bm:property[@name='cpee:method']/@itemSubjectRef").each do |m|
|
86
|
+
n.methods << m.value
|
87
|
+
end
|
88
|
+
e.find("bm:script").each do |s|
|
89
|
+
n.script ||= ''
|
90
|
+
n.script << s.text.strip
|
91
|
+
end
|
92
|
+
e.find("bm:ioSpecification/bm:dataInput").each do |a|
|
93
|
+
name = a.attributes['name']
|
94
|
+
value = a.attributes['itemSubjectRef']
|
95
|
+
if @dataelements.keys.include?(value)
|
96
|
+
n.parameters[name] = 'data.' + value
|
97
|
+
else
|
98
|
+
n.parameters[name] = value
|
99
|
+
end
|
100
|
+
end
|
101
|
+
e.find("bm:ioSpecification/bm:dataOutput").each do |a|
|
102
|
+
ref = a.attributes['id']
|
103
|
+
e.find("bm:dataOutputAssociation[bm:sourceRef=\"#{ref}\"]").each do |d|
|
104
|
+
n.script_var = ref
|
105
|
+
n.script_id = d.find("string(bm:targetRef)")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@graph.add_node n
|
110
|
+
@start = n if n.type == :startEvent && @start == nil
|
111
|
+
end
|
112
|
+
|
113
|
+
# extract all sequences to a links
|
114
|
+
doc.find("/bm:definitions/bm:process/bm:sequenceFlow").each do |e|
|
115
|
+
source = e.attributes['sourceRef']
|
116
|
+
target = e.attributes['targetRef']
|
117
|
+
cond = e.find('bm:conditionExpression')
|
118
|
+
@graph.add_link Link.new(source, target, cond.empty? ? nil : cond.first.text.strip)
|
119
|
+
end
|
120
|
+
|
121
|
+
@graph.clean_up do |node|
|
122
|
+
if node.type == :scriptTask && (x = @graph.find_script_id(node.id)).any?
|
123
|
+
x.each do |k,n|
|
124
|
+
n.script = node.script
|
125
|
+
n.script_type = node.script_type
|
126
|
+
end
|
127
|
+
true
|
128
|
+
else
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_traces #{{{
|
135
|
+
build_extraces @traces, @start
|
136
|
+
@traces
|
137
|
+
end #}}}
|
138
|
+
def build_tree(debug=false) #{{{
|
139
|
+
build_ttree @tree, @traces.dup, nil, debug
|
140
|
+
debug_print debug, 'Tree finished'
|
141
|
+
@tree
|
142
|
+
end #}}}
|
143
|
+
|
144
|
+
def build_extraces(traces, node) #{{{
|
145
|
+
dupt = traces.last.dup
|
146
|
+
@graph.next_nodes(node).each_with_index do |n,i|
|
147
|
+
traces << dupt.dup if i > 0
|
148
|
+
if traces.last.include?(n)
|
149
|
+
traces.last << n
|
150
|
+
else
|
151
|
+
traces.last << n
|
152
|
+
build_extraces(traces,n)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end #}}}
|
156
|
+
private :build_extraces
|
157
|
+
|
158
|
+
def map_node(node) #{{{
|
159
|
+
case node.type
|
160
|
+
when :parallelGateway
|
161
|
+
Parallel.new(node.id,node.type)
|
162
|
+
when :exclusiveGateway
|
163
|
+
Conditional.new(node.id,:exclusive,node.type)
|
164
|
+
when :eventBasedGateway
|
165
|
+
Parallel.new(node.id,node.type,1)
|
166
|
+
when :inclusiveGateway
|
167
|
+
Conditional.new(node.id,:inclusive,node.type)
|
168
|
+
when :endEvent, :startEvent, nil
|
169
|
+
nil
|
170
|
+
else
|
171
|
+
node
|
172
|
+
end
|
173
|
+
end #}}}
|
174
|
+
private :map_node
|
175
|
+
|
176
|
+
def build_ttree(branch,traces,enode=nil,debug=false)
|
177
|
+
while not traces.finished?
|
178
|
+
### if traces exist more than once, make it so they exist only once
|
179
|
+
### if somebody creates a modell with an inclusive/exclusive that
|
180
|
+
### has identical branches with different conditions, we are fucked
|
181
|
+
### but how are the odds? right? right?
|
182
|
+
traces.uniq!
|
183
|
+
debug_print debug, traces
|
184
|
+
if node = traces.same_first
|
185
|
+
if branch.condition?
|
186
|
+
li = @graph.link(branch.id,traces.first_node.id)
|
187
|
+
unless li.nil?
|
188
|
+
branch.condition << li.condition unless li.condition.nil?
|
189
|
+
branch.condition_type = "text/javascript"
|
190
|
+
li.attributes.each do |k,v|
|
191
|
+
branch.attributes[k] = v
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
if node == enode
|
196
|
+
traces.shift_all
|
197
|
+
elsif node.incoming <= 1
|
198
|
+
traces.shift_all
|
199
|
+
n = map_node(node)
|
200
|
+
if !(n.nil? || (n.container? && (node.outgoing <=1 || traces.finished?)))
|
201
|
+
(branch << n).compact!
|
202
|
+
end
|
203
|
+
else
|
204
|
+
loops = traces.loops
|
205
|
+
if node.type == :exclusiveGateway || traces.length == 1
|
206
|
+
### as the first is a decision node, just remove and continue
|
207
|
+
if node.incoming == 2
|
208
|
+
node.incoming = 1
|
209
|
+
branch << Loop.new(node.id)
|
210
|
+
### remove the gateway itself, as for a single loop it is no longer used.
|
211
|
+
### the condition will the loop condition
|
212
|
+
if traces.length == 1
|
213
|
+
loops.first.pop
|
214
|
+
else
|
215
|
+
traces.shift_all
|
216
|
+
end
|
217
|
+
loops.remove_empty
|
218
|
+
build_ttree branch.last, loops, nil, debug
|
219
|
+
else
|
220
|
+
### dont remove it, treat it as a normal conditional
|
221
|
+
### an infinite loop that can only be left by break is created
|
222
|
+
node.incoming = 1
|
223
|
+
branch << InfiniteLoop.new(node.id)
|
224
|
+
### add the blank conditional to get a break
|
225
|
+
len = loops.length
|
226
|
+
loops.add_breaks
|
227
|
+
build_ttree branch.last, loops, nil, debug
|
228
|
+
### set outgoing to number of loops (without the break) so that it can be ignored (should be 1 all the time)
|
229
|
+
node.outgoing -= len
|
230
|
+
end
|
231
|
+
else
|
232
|
+
node.incoming -= loops.length
|
233
|
+
### throw away the loop traces, remove loop traces from front of all other traces
|
234
|
+
traces.segment_by_loops loops
|
235
|
+
build_ttree branch, loops, nil, debug
|
236
|
+
end
|
237
|
+
traces.remove(loops)
|
238
|
+
traces.remove_empty
|
239
|
+
end
|
240
|
+
else
|
241
|
+
endnode = traces.find_endnode || enode
|
242
|
+
tracesgroup, endnode = traces.segment_by endnode
|
243
|
+
tracesgroup.each do |trcs|
|
244
|
+
if trcs.finished?
|
245
|
+
build_ttree branch.last.new_branch, Traces.new([[Break.new(1)]]), endnode, debug
|
246
|
+
else
|
247
|
+
build_ttree branch.last.new_branch, trcs, endnode, debug
|
248
|
+
end
|
249
|
+
endnode.incoming -= 1 unless endnode.nil?
|
250
|
+
end
|
251
|
+
### all before is reduced to one incoming arrow
|
252
|
+
### if now there is still more than one incoming we have a loop situation
|
253
|
+
### where the end of a branching statement is also the starting/endpoint
|
254
|
+
### of a loop
|
255
|
+
endnode.incoming += 1 unless endnode.nil?
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
private :build_ttree
|
260
|
+
|
261
|
+
def debug_print(debug,traces) #{{{
|
262
|
+
if debug
|
263
|
+
puts '-' * @hl.output_cols, @tree.to_s
|
264
|
+
puts traces.to_s
|
265
|
+
@hl.ask('Continue ... '){ |q| q.echo = false }
|
266
|
+
end
|
267
|
+
end #}}}
|
268
|
+
private :debug_print
|
269
|
+
|
270
|
+
def generate_model(formater) #{{{
|
271
|
+
formater.new(@tree).generate
|
272
|
+
end #}}}
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
data/lib/cpee/cpee.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# This file is part of CPEE.
|
4
|
+
#
|
5
|
+
# Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Copyright (c) 2013 Juergen Mangler
|
8
|
+
#
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
# you may not use this file except in compliance with the License.
|
11
|
+
# You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
# See the License for the specific language governing permissions and
|
19
|
+
# limitations under the License.
|
20
|
+
|
21
|
+
module CPEE
|
22
|
+
|
23
|
+
module ProcessTransformation
|
24
|
+
|
25
|
+
module Target
|
26
|
+
|
27
|
+
class CPEE
|
28
|
+
def initialize(tree)
|
29
|
+
@tree = tree
|
30
|
+
end
|
31
|
+
def generate
|
32
|
+
res = XML::Smart.string("<description xmlns='http://cpee.org/ns/description/1.0'/>")
|
33
|
+
res.register_namespace 'd', 'http://cpee.org/ns/description/1.0'
|
34
|
+
generate_for_list(@tree,res.root)
|
35
|
+
res
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_for_list(list,res)
|
39
|
+
list.each do |e|
|
40
|
+
nam = e.class.name.gsub(/\w+:+/,'')
|
41
|
+
send("print_#{nam}".to_sym,e,res)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
private :generate_for_list
|
45
|
+
|
46
|
+
def print_Break(node,res)
|
47
|
+
res.add('break')
|
48
|
+
end
|
49
|
+
|
50
|
+
def print_InfiniteLoop(node,res)
|
51
|
+
s1 = res.add('loop', 'pre_test' => 'true')
|
52
|
+
generate_for_list(node,s1)
|
53
|
+
end
|
54
|
+
def print_Loop_default(node,res)
|
55
|
+
s1 = res.add('loop', 'pre_test' => node.condition.empty? ? 'true' : node.condition.join(' && '))
|
56
|
+
s1.attributes['language'] = node.condition_type unless node.condition_type.nil?
|
57
|
+
generate_for_list(node,s1)
|
58
|
+
s1
|
59
|
+
end
|
60
|
+
private :print_Loop_default
|
61
|
+
def print_Loop(node,res); print_Loop_default(node,res); end
|
62
|
+
private :print_Loop
|
63
|
+
|
64
|
+
def print_Node(node,res)
|
65
|
+
if node.endpoints.empty? && !node.script.nil? && node.script.strip != ''
|
66
|
+
n = res.add('d:manipulate', 'id' => "a#{node.niceid}")
|
67
|
+
n.text = node.script
|
68
|
+
n.attributes['output'] = node.script_var unless node.script_var.nil?
|
69
|
+
n.attributes['language'] = node.script_type unless node.script_type.nil?
|
70
|
+
else
|
71
|
+
n = res.add('d:call', 'id' => "a#{node.niceid}", 'endpoint' => node.endpoints.join(','))
|
72
|
+
p = n.add('d:parameters')
|
73
|
+
p.add('d:label',node.label)
|
74
|
+
p.add('d:method',node.methods.join(','))
|
75
|
+
p.add('d:type',node.type)
|
76
|
+
p.add('d:mid',node.id)
|
77
|
+
par = p.add('d:parameters')
|
78
|
+
node.parameters.each do |k,v|
|
79
|
+
par.add(k,v)
|
80
|
+
end
|
81
|
+
if !node.script.nil? && node.script.strip != ''
|
82
|
+
x = n.add('manipulate',node.script)
|
83
|
+
x.attributes['output'] = node.script_var unless node.script_var.nil?
|
84
|
+
x.attributes['language'] = node.script_type unless node.script_type.nil?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
private :print_Node
|
89
|
+
|
90
|
+
def print_Parallel_default(node,res)
|
91
|
+
s1 = res.add('parallel','wait' => node.wait)
|
92
|
+
node.sub.each do |branch|
|
93
|
+
s2 = s1.add('parallel_branch')
|
94
|
+
generate_for_list(branch,s2)
|
95
|
+
end
|
96
|
+
s1
|
97
|
+
end
|
98
|
+
private :print_Parallel_default
|
99
|
+
def print_Parallel(node,res); print_Parallel_default(node,res); end
|
100
|
+
private :print_Parallel
|
101
|
+
|
102
|
+
def print_Conditional_default(node,res)
|
103
|
+
s1 = res.add('d:choose', 'mode' => node.mode)
|
104
|
+
node.sub.each do |branch|
|
105
|
+
s2 = if branch.condition.any?
|
106
|
+
a = s1.add('d:alternative','condition' => branch.condition.join(' or '))
|
107
|
+
a.attributes['language'] = branch.condition_type unless branch.condition_type.nil?
|
108
|
+
a
|
109
|
+
else
|
110
|
+
s1.add('d:otherwise')
|
111
|
+
end
|
112
|
+
generate_for_list(branch,s2)
|
113
|
+
end
|
114
|
+
if (x = s1.find('d:otherwise')).any?
|
115
|
+
s1.add x
|
116
|
+
end
|
117
|
+
s1
|
118
|
+
end
|
119
|
+
private :print_Conditional_default
|
120
|
+
def print_Conditional(node,res); print_Conditional_default(node,res); end
|
121
|
+
private :print_Conditional
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -112,6 +112,7 @@ module CPEE
|
|
112
112
|
class Loop < Array #{{{
|
113
113
|
include Container
|
114
114
|
attr_accessor :id, :type, :condition, :condition_type
|
115
|
+
attr_reader :attributes
|
115
116
|
def condition?; true; end
|
116
117
|
def initialize(id)
|
117
118
|
@container = true
|
@@ -119,6 +120,7 @@ module CPEE
|
|
119
120
|
@type = :loop
|
120
121
|
@condition = []
|
121
122
|
@condition_type = nil
|
123
|
+
@attributes = {}
|
122
124
|
end
|
123
125
|
end #}}}
|
124
126
|
|
@@ -146,6 +148,7 @@ module CPEE
|
|
146
148
|
include Enumerable
|
147
149
|
attr_reader :container
|
148
150
|
attr_reader :id, :sub, :mode
|
151
|
+
attr_reader :attributes
|
149
152
|
attr_accessor :type
|
150
153
|
def initialize(id,mode,type)
|
151
154
|
@container = true
|
@@ -153,6 +156,7 @@ module CPEE
|
|
153
156
|
@sub = []
|
154
157
|
@mode = mode
|
155
158
|
@type = type
|
159
|
+
@attributes = {}
|
156
160
|
end
|
157
161
|
def new_branch
|
158
162
|
(@sub << Alternative.new(@id)).last
|
@@ -0,0 +1,437 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# This file is part of CPEE.
|
4
|
+
#
|
5
|
+
# Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Copyright (c) 2013 Juergen Mangler
|
8
|
+
#
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
# you may not use this file except in compliance with the License.
|
11
|
+
# You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
# See the License for the specific language governing permissions and
|
19
|
+
# limitations under the License.
|
20
|
+
|
21
|
+
module CPEE
|
22
|
+
|
23
|
+
module ProcessTransformation
|
24
|
+
|
25
|
+
class Link #{{{
|
26
|
+
attr_accessor :from, :to
|
27
|
+
attr_reader :condition, :attributes
|
28
|
+
def initialize(from,to,cond=nil)
|
29
|
+
@from = from
|
30
|
+
@to = to
|
31
|
+
@condition = cond
|
32
|
+
@attributes = {}
|
33
|
+
end
|
34
|
+
end #}}}
|
35
|
+
|
36
|
+
module Container
|
37
|
+
def container?
|
38
|
+
@container || false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Node #{{{
|
43
|
+
include Container
|
44
|
+
@@niceid = -1
|
45
|
+
attr_reader :id, :label, :niceid
|
46
|
+
attr_reader :endpoints, :methods, :parameters, :attributes
|
47
|
+
attr_accessor :script, :script_id, :script_var, :script_type, :incoming, :outgoing, :type
|
48
|
+
def initialize(id,type,label,incoming,outgoing)
|
49
|
+
@id = id
|
50
|
+
@niceid = (@@niceid += 1)
|
51
|
+
@type = type
|
52
|
+
@label = label
|
53
|
+
@endpoints = []
|
54
|
+
@methods = []
|
55
|
+
@script = nil
|
56
|
+
@script_type = nil
|
57
|
+
@script_id = nil
|
58
|
+
@script_var = 'result'
|
59
|
+
@parameters = {}
|
60
|
+
@incoming = incoming
|
61
|
+
@outgoing = outgoing
|
62
|
+
@attributes = {}
|
63
|
+
end
|
64
|
+
end # }}}
|
65
|
+
|
66
|
+
module Struct #{{{
|
67
|
+
def each(&a)
|
68
|
+
@sub.each{|s| a.call(s)}
|
69
|
+
end
|
70
|
+
def length
|
71
|
+
@sub.length
|
72
|
+
end
|
73
|
+
end #}}}
|
74
|
+
|
75
|
+
class Break < Node
|
76
|
+
def initialize(incoming)
|
77
|
+
super '-1', :break, 'BREAK', incoming, []
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Alternative < Array #{{{
|
82
|
+
include Container
|
83
|
+
attr_accessor :condition, :condition_type
|
84
|
+
attr_reader :id
|
85
|
+
def condition?; true; end
|
86
|
+
def initialize(id)
|
87
|
+
@container = true
|
88
|
+
@id = id
|
89
|
+
@condition = []
|
90
|
+
@condition_type = nil
|
91
|
+
end
|
92
|
+
end #}}}
|
93
|
+
class Branch < Array #{{{
|
94
|
+
include Container
|
95
|
+
attr_reader :id
|
96
|
+
def condition?; false; end
|
97
|
+
def initialize(id)
|
98
|
+
@container = true
|
99
|
+
@id = id
|
100
|
+
end
|
101
|
+
end #}}}
|
102
|
+
class InfiniteLoop < Array #{{{
|
103
|
+
include Container
|
104
|
+
def condition?; false; end
|
105
|
+
attr_accessor :id, :type
|
106
|
+
def initialize(id)
|
107
|
+
@container = true
|
108
|
+
@id = id
|
109
|
+
@type = :loop
|
110
|
+
end
|
111
|
+
end #}}}
|
112
|
+
class Loop < Array #{{{
|
113
|
+
include Container
|
114
|
+
attr_accessor :id, :type, :condition, :condition_type
|
115
|
+
attr_reader :attributes
|
116
|
+
def condition?; true; end
|
117
|
+
def initialize(id)
|
118
|
+
@container = true
|
119
|
+
@id = id
|
120
|
+
@type = :loop
|
121
|
+
@condition = []
|
122
|
+
@condition_type = nil
|
123
|
+
@attributes = {}
|
124
|
+
end
|
125
|
+
end #}}}
|
126
|
+
|
127
|
+
class Parallel #{{{
|
128
|
+
include Container
|
129
|
+
include Struct
|
130
|
+
include Enumerable
|
131
|
+
attr_reader :id, :sub
|
132
|
+
attr_accessor :type, :wait
|
133
|
+
def initialize(id,type,wait='-1')
|
134
|
+
@container = true
|
135
|
+
@id = id
|
136
|
+
@type = type
|
137
|
+
@sub = []
|
138
|
+
@wait = wait
|
139
|
+
end
|
140
|
+
def new_branch
|
141
|
+
(@sub << Branch.new(@id)).last
|
142
|
+
end
|
143
|
+
end #}}}
|
144
|
+
|
145
|
+
class Conditional #{{{
|
146
|
+
include Container
|
147
|
+
include Struct
|
148
|
+
include Enumerable
|
149
|
+
attr_reader :container
|
150
|
+
attr_reader :id, :sub, :mode
|
151
|
+
attr_reader :attributes
|
152
|
+
attr_accessor :type
|
153
|
+
def initialize(id,mode,type)
|
154
|
+
@container = true
|
155
|
+
@id = id
|
156
|
+
@sub = []
|
157
|
+
@mode = mode
|
158
|
+
@type = type
|
159
|
+
@attributes = {}
|
160
|
+
end
|
161
|
+
def new_branch
|
162
|
+
(@sub << Alternative.new(@id)).last
|
163
|
+
end
|
164
|
+
end #}}}
|
165
|
+
|
166
|
+
class Graph #{{{
|
167
|
+
attr_reader :flow, :nodes
|
168
|
+
|
169
|
+
def initialize
|
170
|
+
@nodes = {}
|
171
|
+
@links = []
|
172
|
+
end
|
173
|
+
|
174
|
+
def clean_up(&bl)
|
175
|
+
selnodes = []
|
176
|
+
@nodes.each do |k,n|
|
177
|
+
ret = bl.call(n)
|
178
|
+
selnodes << n if ret
|
179
|
+
end
|
180
|
+
selnodes.each do |n|
|
181
|
+
if n.incoming > 1 || n.outgoing > 1
|
182
|
+
raise "#{n.inspect} - not a simple node to remove"
|
183
|
+
end
|
184
|
+
to,from = nil
|
185
|
+
@links.each do |f|
|
186
|
+
to = f if f.to == n.id
|
187
|
+
from = f if f.from == n.id
|
188
|
+
end
|
189
|
+
if to && from
|
190
|
+
to.to = from.to
|
191
|
+
@links.delete(from)
|
192
|
+
@nodes.delete(n.id)
|
193
|
+
else
|
194
|
+
raise "#{n.inspect} - could not remove flow"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def find_script_id(s)
|
200
|
+
@nodes.find_all{|k,n| n.script_id == s}
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_node(n)
|
204
|
+
@nodes[n.id] = n
|
205
|
+
end
|
206
|
+
|
207
|
+
def link(f,t)
|
208
|
+
@links.find{ |x| x.from == f && x.to == t }
|
209
|
+
end
|
210
|
+
|
211
|
+
def add_link(l)
|
212
|
+
@links << l
|
213
|
+
end
|
214
|
+
|
215
|
+
def next_nodes(from)
|
216
|
+
links = @links.find_all { |x| x.from == from.id }
|
217
|
+
links.map{|x| @nodes[x.to] }
|
218
|
+
end
|
219
|
+
|
220
|
+
def next_node(from)
|
221
|
+
if (nodes = next_nodes(from)).length == 1
|
222
|
+
nodes.first
|
223
|
+
else
|
224
|
+
raise "#{from.inspect} - multiple outgoing connections"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end #}}}
|
228
|
+
|
229
|
+
class Tree < Array #{{{
|
230
|
+
def condition?; false; end
|
231
|
+
|
232
|
+
def to_s
|
233
|
+
"TREE:\n" << print_tree(self)
|
234
|
+
end
|
235
|
+
|
236
|
+
def print_tree(ele,indent=' ')
|
237
|
+
ret = ''
|
238
|
+
ele.each_with_index do |e,i|
|
239
|
+
last = (i == ele.length - 1)
|
240
|
+
pchar = last ? '└' : '├'
|
241
|
+
if e.container?
|
242
|
+
ret << indent + pchar + ' ' + e.class.to_s.gsub(/[^:]*::/,'') + "\n"
|
243
|
+
ret << print_tree(e,indent + (last ? ' ' : '│ '))
|
244
|
+
elsif e.is_a?(Break) &&
|
245
|
+
ret << indent + pchar + ' ' + e.class.to_s.gsub(/[^:]*::/,'') + "\n"
|
246
|
+
else
|
247
|
+
ret << indent + pchar + ' ' + e.niceid.to_s + "\n"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
ret
|
251
|
+
end
|
252
|
+
private :print_tree
|
253
|
+
end #}}}
|
254
|
+
|
255
|
+
class Traces < Array #{{{
|
256
|
+
def initialize_copy(other)
|
257
|
+
super
|
258
|
+
self.map!{ |t| t.dup }
|
259
|
+
end
|
260
|
+
|
261
|
+
def remove(trcs)
|
262
|
+
trcs.each do |t|
|
263
|
+
self.delete(t)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def remove_empty
|
268
|
+
self.delete_if{|t| t.empty? }
|
269
|
+
end
|
270
|
+
|
271
|
+
def first_node
|
272
|
+
self.first.first
|
273
|
+
end
|
274
|
+
def second_nodes
|
275
|
+
self.map { |t| t[1] }
|
276
|
+
end
|
277
|
+
|
278
|
+
def shortest
|
279
|
+
self.min_by{|e|e.length}
|
280
|
+
end
|
281
|
+
|
282
|
+
def to_s
|
283
|
+
"TRACES: " + self.collect { |t| t.empty? ? '∅' : t.collect{|n| "%2d" % n.niceid }.join('→ ') }.join("\n ")
|
284
|
+
end
|
285
|
+
|
286
|
+
def shift_all
|
287
|
+
self.each{ |tr| tr.shift }
|
288
|
+
end
|
289
|
+
|
290
|
+
def finished?
|
291
|
+
self.reduce(0){|sum,t| sum += t.length} == 0
|
292
|
+
end
|
293
|
+
|
294
|
+
def same_first
|
295
|
+
(n = self.map{|t| t.first }.uniq).length == 1 ? n.first : nil
|
296
|
+
end
|
297
|
+
|
298
|
+
def include_in_all?(e)
|
299
|
+
num = 0
|
300
|
+
self.each{|n| num += 1 if n.include?(e)}
|
301
|
+
num == self.length
|
302
|
+
end
|
303
|
+
|
304
|
+
def infinite_loop_fix
|
305
|
+
self << self.first.dup
|
306
|
+
self.last.pop
|
307
|
+
end
|
308
|
+
|
309
|
+
def add_breaks
|
310
|
+
trueloops = self.find_all{ |t| t.last == t.first }.length
|
311
|
+
if trueloops == self.length
|
312
|
+
self << [self.first_node] ### the blank conditional so that we get a break
|
313
|
+
else
|
314
|
+
self.each do |t|
|
315
|
+
t << Break.new(1) unless t.last == t.first ### an explicit break
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def loops
|
321
|
+
lo = Traces.new self.find_all{ |t| t.first == t.last }
|
322
|
+
self.each do |t|
|
323
|
+
lo << t if lo.second_nodes.include?(t[1])
|
324
|
+
end
|
325
|
+
lo.uniq
|
326
|
+
end
|
327
|
+
|
328
|
+
def eliminate(loops)
|
329
|
+
### find nested loops
|
330
|
+
self.each_with_index do |t,i|
|
331
|
+
maxcut = 0
|
332
|
+
### find out which common parts the traces share with theloops
|
333
|
+
loops.each do |l|
|
334
|
+
maxcut.upto(l.length) do |i|
|
335
|
+
maxcut = i if t[0...i] == l[0...i]
|
336
|
+
end
|
337
|
+
end
|
338
|
+
### in case of nested loop (common part occurs at end of loop), include the whole
|
339
|
+
0.upto (maxcut-1) do |j|
|
340
|
+
if self[i][j] == self[i].last
|
341
|
+
loops << self[i].shift(self[i].length)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
loops.uniq!
|
346
|
+
loops.remove_empty
|
347
|
+
self.remove_empty
|
348
|
+
|
349
|
+
### cut from non-nested loops
|
350
|
+
self.each_with_index do |t,i|
|
351
|
+
maxcut = 0
|
352
|
+
### find out which common parts the traces share with theloops
|
353
|
+
loops.each do |l|
|
354
|
+
maxcut.upto(l.length) do |i|
|
355
|
+
maxcut = i if t[0...i] == l[0...i]
|
356
|
+
end
|
357
|
+
end
|
358
|
+
loops << self[i].shift(maxcut)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def extend
|
363
|
+
# find largest common
|
364
|
+
max = nil
|
365
|
+
sh = self.shortest
|
366
|
+
sh = sh[0..-2] if sh.first == sh.last
|
367
|
+
sh.each do |e,i|
|
368
|
+
if self.include_in_all?(e)
|
369
|
+
max = e
|
370
|
+
else
|
371
|
+
break
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
# if last is the largest common do nothing
|
376
|
+
# else append from last to largest common
|
377
|
+
self.each do |t|
|
378
|
+
unless t.last == max
|
379
|
+
last = t.last
|
380
|
+
t.last.incoming = 1
|
381
|
+
if t.index(last) && t.index(max)
|
382
|
+
(t.index(last) + 1).upto(t.index(max)) do |i|
|
383
|
+
t << t[i]
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
max.incoming = self.length
|
390
|
+
max
|
391
|
+
end
|
392
|
+
|
393
|
+
def segment_by_loops(loops)
|
394
|
+
# supress loops
|
395
|
+
self.delete_if { |t| loops.include?(t) }
|
396
|
+
self.eliminate(loops)
|
397
|
+
loops.extend
|
398
|
+
end
|
399
|
+
|
400
|
+
def find_endnode
|
401
|
+
# supress loops
|
402
|
+
trcs = self.dup
|
403
|
+
trcs.delete_if { |t| t.uniq.length < t.length }
|
404
|
+
|
405
|
+
# find common node (except loops)
|
406
|
+
enode = nil
|
407
|
+
trcs.first.each do |n|
|
408
|
+
if trcs.include_in_all?(n)
|
409
|
+
enode = n
|
410
|
+
break
|
411
|
+
end
|
412
|
+
end
|
413
|
+
enode
|
414
|
+
end
|
415
|
+
|
416
|
+
def segment_by(endnode)
|
417
|
+
# cut shit until common node, return the shit you cut away
|
418
|
+
tracesgroup = self.group_by{|t| t.first}.map do |k,trace|
|
419
|
+
coltrace = trace.map do |t|
|
420
|
+
# slice upto common node, collect the sliced away part
|
421
|
+
len = t.index(endnode)
|
422
|
+
if len
|
423
|
+
cut = t.slice!(0...len)
|
424
|
+
cut << t.first
|
425
|
+
else # if endnode is nil, then return the whole
|
426
|
+
t
|
427
|
+
end
|
428
|
+
end.uniq
|
429
|
+
Traces.new(coltrace)
|
430
|
+
end
|
431
|
+
[tracesgroup,endnode]
|
432
|
+
end
|
433
|
+
end #}}}
|
434
|
+
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cpee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.137
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- server/handlerwrappers/default.rb
|
111
111
|
- lib/engine.xml
|
112
112
|
- lib/cpee/callback.rb
|
113
|
+
- lib/cpee/bpmn2.rb
|
113
114
|
- lib/cpee/handler_notifications.rb
|
114
115
|
- lib/cpee/controller.rb
|
115
116
|
- lib/cpee/processtransformation/bpmn2.rb
|
@@ -124,7 +125,9 @@ files:
|
|
124
125
|
- lib/cpee/processtransformation/bpel/Repository/booking.wsdl
|
125
126
|
- lib/cpee/processtransformation/bpel/Repository/booking.bpel
|
126
127
|
- lib/cpee/processtransformation/bpel/lib/BPEL_Transform.rb
|
128
|
+
- lib/cpee/cpee.rb
|
127
129
|
- lib/cpee/handler_properties.rb
|
130
|
+
- lib/cpee/structures.rb
|
128
131
|
- lib/cpee/implementation.rb
|
129
132
|
- lib/cpee/empty_workflow.rb
|
130
133
|
- lib/engine/instance-info.rng
|