openwferu-extras 0.9.12.863

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.
@@ -0,0 +1,151 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2007, John Mettraux, OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "made in Japan"
38
+ #
39
+ # John Mettraux at openwfe.org
40
+ #
41
+
42
+ require 'yaml'
43
+ require 'base64'
44
+ require 'monitor'
45
+
46
+ require 'openwfe/service'
47
+ require 'openwfe/util/scheduler'
48
+ require 'openwfe/listeners/listener'
49
+
50
+ require 'openwfe/extras/util/sqs'
51
+
52
+
53
+ #
54
+ # some base listener implementations
55
+ #
56
+ module OpenWFE
57
+ module Extras
58
+
59
+ #
60
+ # Polls an Amazon SQS queue for workitems
61
+ #
62
+ # Workitems can be instances of InFlowWorkItem or LaunchItem.
63
+ #
64
+ # require 'openwfe/extras/listeners/sqslisteners'
65
+ #
66
+ # ql = OpenWFE::SqsListener("workqueue1", engine.application_context)
67
+ #
68
+ # engine.add_workitem_listener(ql, "2m30s")
69
+ # #
70
+ # # thus, the engine will poll our "workqueue1" SQS queue
71
+ # # every 2 minutes and 30 seconds
72
+ #
73
+ class SqsListener < Service
74
+ include MonitorMixin
75
+ include WorkItemListener
76
+ include Schedulable
77
+
78
+ #
79
+ # The name of the Amazon SQS whom this listener cares for
80
+ #
81
+ attr_reader :queue_name
82
+
83
+ def initialize (queue_name, application_context)
84
+
85
+ @queue_name = queue_name.to_s
86
+
87
+ service_name = "#{self.class}::#{@queue_name}"
88
+
89
+ super(service_name, application_context)
90
+
91
+ linfo { "new() queue is '#{@queue_name}'" }
92
+ end
93
+
94
+ #
95
+ # Will 'find' files in the work directory (by default ./work/in/),
96
+ # extract the workitem in them and feed it back to the engine.
97
+ #
98
+ def trigger (params)
99
+ synchronize do
100
+
101
+ ldebug { "trigger()" }
102
+
103
+ qs = SQS::QueueService.new
104
+
105
+ qs.create_queue(@queue_name)
106
+ # just to be sure it is there
107
+
108
+ while true
109
+
110
+ l = qs.get_messages(
111
+ @queue_name, :timeout => 0, :count => 255)
112
+
113
+ break if l.length < 1
114
+
115
+ l.each do |msg|
116
+
117
+ o = decode_object(msg)
118
+
119
+ handle_object(o)
120
+
121
+ msg.delete
122
+
123
+ ldebug do
124
+ "trigger() " +
125
+ "handled successfully msg #{msg.message_id}"
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ #
133
+ # Extracts a workitem from the message's body.
134
+ #
135
+ # By default, this listeners assumes the workitem is stored in
136
+ # its "hash form" (not directly as a Ruby InFlowWorkItem instance).
137
+ #
138
+ # LaunchItem instances (as hash as well) are also accepted.
139
+ #
140
+ def decode_object (message)
141
+
142
+ o = Base64.decode64(message.message_body)
143
+ o = YAML.load(o)
144
+ o = OpenWFE::workitem_from_h(o)
145
+ o
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+
@@ -0,0 +1,334 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2007, John Mettraux OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+
34
+ #
35
+ # "made in Japan"
36
+ #
37
+ # John Mettraux at openwfe.org
38
+ #
39
+
40
+ require 'rubygems'
41
+ require_gem 'activerecord'
42
+
43
+
44
+ require 'openwfe/workitem'
45
+ require 'openwfe/flowexpressionid'
46
+ require 'openwfe/participants/participant'
47
+
48
+
49
+ module OpenWFE
50
+ module Extras
51
+
52
+ #
53
+ # The migration for ActiveParticipant and associated classes.
54
+ #
55
+ # There are two tables 'workitems' and 'fields'. As its name implies,
56
+ # the latter table stores the fields (also called attributes in OpenWFE
57
+ # speak) of the workitems.
58
+ #
59
+ # See Workitem and Field for more details.
60
+ #
61
+ # For centralization purposes, the migration and the model are located
62
+ # in the same source file. It should be quite easy for the Rails hackers
63
+ # among you to sort that out for a Rails based usage.
64
+ #
65
+ class OwfeTables < ActiveRecord::Migration
66
+ def self.up
67
+ create_table :workitems do |t|
68
+ t.column :fei, :string
69
+ t.column :wfid, :string
70
+ t.column :wf_name, :string
71
+ t.column :wf_revision, :string
72
+ t.column :participant_name, :string
73
+ t.column :store, :string
74
+ end
75
+ create_table :fields do |t|
76
+ t.column :key, :string, :null => false
77
+ t.column :value, :text
78
+ t.column :workitem_id, :integer, :null => false
79
+ end
80
+ add_index :fields, [ :workitem_id, :key], :unique => true
81
+ end
82
+ def self.down
83
+ drop_table :workitems
84
+ drop_table :fields
85
+ end
86
+ end
87
+
88
+ #
89
+ # The ActiveRecord version of an OpenWFEru workitem (InFlowWorkItem).
90
+ #
91
+ # One can very easily build a worklist based on a participant name via :
92
+ #
93
+ # wl = OpenWFE::Extras::Workitem.find_all_by_participant_name("toto")
94
+ # puts "found #{wl.size} workitems for participant 'toto'"
95
+ #
96
+ # These workitems are not OpenWFEru workitems directly. But the conversion
97
+ # is pretty easy.
98
+ # Note that you probaly won't need to do the conversion by yourself,
99
+ # except for certain advanced scenarii.
100
+ #
101
+ # awi = OpenWFE::Extras::Workitem.find_by_participant_name("toto")
102
+ # #
103
+ # # returns the first workitem in the database whose participant
104
+ # # name is 'toto'.
105
+ #
106
+ # owi = awi.as_owfe_workitem
107
+ # #
108
+ # # Now we have a copy of the reference as a OpenWFEru
109
+ # # InFlowWorkItem instance.
110
+ #
111
+ # awi = OpenWFE::Extras::Workitem.from_owfe_workitem(owi)
112
+ # #
113
+ # # turns an OpenWFEru InFlowWorkItem instance into an
114
+ # # 'active workitem'.
115
+ #
116
+ class Workitem < ActiveRecord::Base
117
+
118
+ has_many :fields, :dependent => :destroy
119
+
120
+ #
121
+ # Returns the flow expression id of this work (its unique OpenWFEru
122
+ # identifier) as a FlowExpressionId instance.
123
+ # (within the Workitem it's just stored as a String).
124
+ #
125
+ def full_fei
126
+
127
+ OpenWFE::FlowExpressionId.from_s(fei)
128
+ end
129
+
130
+ #
131
+ # Generates a (new) Workitem from an OpenWFEru InFlowWorkItem instance.
132
+ #
133
+ # This is a 'static' method :
134
+ #
135
+ # awi = OpenWFE::Densha::Workitem.from_owfe_workitem(wi)
136
+ #
137
+ # (This method will not save the 'ActiveWorkitem').
138
+ #
139
+ def self.from_owfe_workitem (wi)
140
+
141
+ i = Workitem.new
142
+ i.fei = wi.fei.to_s
143
+ i.wfid = wi.fei.wfid
144
+ i.wf_name = wi.fei.workflow_definition_name
145
+ i.wf_revision = wi.fei.workflow_definition_revision
146
+ i.participant_name = wi.participant_name
147
+
148
+ wi.attributes.each do |k, v|
149
+ f = Field.new
150
+ f.key = k
151
+ f.value = v
152
+ i.fields << f
153
+ end
154
+ i
155
+ end
156
+
157
+ #
158
+ # Turns the densha Workitem into an OpenWFEru InFlowWorkItem.
159
+ #
160
+ def as_owfe_workitem
161
+
162
+ wi = OpenWFE::InFlowWorkItem.new
163
+ wi.fei = full_fei
164
+ wi.participant_name = participant_name
165
+ wi.attributes = fields_hash
166
+ wi
167
+ end
168
+
169
+ #
170
+ # Returns a hash version of the 'fields' of this workitem.
171
+ #
172
+ # (Each time this method is called, it returns a new hash).
173
+ #
174
+ def fields_hash
175
+
176
+ h = {}
177
+ fields.each do |f|
178
+ h[f.key] = f.value
179
+ end
180
+ h
181
+ end
182
+
183
+ #
184
+ # Returns the Field instance with the given key. This method accept
185
+ # symbols as well as strings as its parameter.
186
+ #
187
+ # wi.field("customer_name")
188
+ # wi.field :customer_name
189
+ #
190
+ def field (key)
191
+
192
+ fields.find_by_key(key.to_s)
193
+ end
194
+
195
+ #
196
+ # A shortcut method, replies to the workflow engine and removes self
197
+ # from the database.
198
+ # Handy for people who don't want to play with an ActiveParticipant
199
+ # instance when just consuming workitems (that an active participant
200
+ # pushed in the database).
201
+ #
202
+ def reply (engine)
203
+
204
+ engine.reply self.as_owfe_workitem
205
+ self.destroy
206
+ end
207
+
208
+ alias :forward :reply
209
+ alias :proceed :reply
210
+ end
211
+
212
+ #
213
+ # A Field (Attribute) of a Workitem.
214
+ #
215
+ class Field < ActiveRecord::Base
216
+
217
+ belongs_to :workitem
218
+ serialize :value
219
+
220
+ #
221
+ # A quick method for doing
222
+ #
223
+ # f = Field.new
224
+ # f.key = key
225
+ # f.value = value
226
+ #
227
+ # One can then quickly add fields to an [active] workitem via :
228
+ #
229
+ # wi.fields << Field.new_field("toto", "b")
230
+ #
231
+ def self.new_field (key, value)
232
+ f = Field.new
233
+ f.key = key
234
+ f.value = value
235
+ f
236
+ end
237
+ end
238
+
239
+
240
+ #
241
+ # A basic 'ActiveParticipant'.
242
+ # A store participant whose store is a set of ActiveRecord tables.
243
+ #
244
+ # Sample usage :
245
+ #
246
+ # class MyDefinition < OpenWFE::ProcessDefinition
247
+ # sequence do
248
+ # active0
249
+ # active1
250
+ # end
251
+ # end
252
+ #
253
+ # def play_with_the_engine
254
+ #
255
+ # engine = OpenWFE::Engine.new
256
+ #
257
+ # engine.register_participant(
258
+ # :active0, OpenWFE::Extras::ActiveParticipant)
259
+ # engine.register_participant(
260
+ # :active1, OpenWFE::Extras::ActiveParticipant)
261
+ #
262
+ # li = OpenWFE::LaunchItem.new(MyDefinition)
263
+ # li.customer_name = 'toto'
264
+ # engine.launch li
265
+ #
266
+ # sleep 0.500
267
+ # # give some slack to the engine, it's asynchronous after all
268
+ #
269
+ # wi = OpenWFE::Extras::Workitem.find_by_participant_name("active0")
270
+ #
271
+ # # ...
272
+ # end
273
+ #
274
+ class ActiveParticipant
275
+ include OpenWFE::LocalParticipant
276
+
277
+ #
278
+ # This is the method called by the OpenWFEru engine to hand a
279
+ # workitem to this participant.
280
+ #
281
+ def consume (workitem)
282
+
283
+ awi = Workitem.from_owfe_workitem(workitem)
284
+ #
285
+ # turns the workitem into an 'active' one
286
+
287
+ awi.save
288
+ #
289
+ # and saves it in the db.
290
+ end
291
+
292
+ #
293
+ # Called by the engine when the whole process instance (or just the
294
+ # segment of it that sports this participant) is cancelled.
295
+ # Will removed the workitem with the same fei as the cancelitem
296
+ # from the database.
297
+ #
298
+ # No expression will be raised if there is no corresponding workitem.
299
+ #
300
+ def cancel (cancelitem)
301
+
302
+ Workitem.delete_all([ "fei = ?", cancelitem.fei.to_s ])
303
+ end
304
+
305
+ #
306
+ # When the activity/work/operation whatever is over and the flow
307
+ # should resume, this is the method to use to hand back the [modified]
308
+ # workitem to the [local] engine.
309
+ #
310
+ def reply_to_engine (workitem)
311
+
312
+ super workitem.as_owfe_workitem
313
+ #
314
+ # replies to the workflow engine
315
+
316
+ workitem.destroy
317
+ #
318
+ # removes the workitem from the database
319
+ end
320
+ end
321
+
322
+ #
323
+ # TODO : please document me
324
+ #
325
+ class ActiveStoreParticipant < ActiveParticipant
326
+ include Enumerable
327
+
328
+ def each (&block)
329
+ end
330
+ end
331
+
332
+ end
333
+ end
334
+