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 CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cpee"
3
- s.version = "1.3.136"
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.136
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