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 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