cpee 1.3.136 → 1.3.137
Sign up to get free protection for your applications and to get access to all the features.
- 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
|