openwferu-extras 0.9.15 → 0.9.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,275 @@
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
+ #
41
+ # this participant requires atom-tools from
42
+ #
43
+ # http://code.necronomicorp.com/trac/atom-tools
44
+ #
45
+ # atom-tools' license is X11/MIT
46
+ #
47
+
48
+ #require 'monitor'
49
+
50
+ require 'rubygems'
51
+
52
+ begin
53
+ require 'atom/collection'
54
+ rescue LoadError
55
+ #
56
+ # soft dependency on 'atom-tools'
57
+ #
58
+ puts
59
+ puts
60
+ puts "'atom/collection' is missing. You can install with :"
61
+ puts
62
+ puts " [sudo] gem install atom-tools"
63
+ puts
64
+ puts
65
+ exit 1
66
+ end
67
+
68
+ require 'openwfe/service'
69
+
70
+
71
+
72
+ module OpenWFE::Extras
73
+
74
+ #
75
+ # A workitem event as kept
76
+ #
77
+ class Entry
78
+
79
+ attr_accessor :id
80
+ attr_accessor :updated
81
+
82
+ attr_accessor :participant_name
83
+ attr_accessor :upon
84
+ attr_accessor :workitem
85
+
86
+ def initialize
87
+
88
+ @update = Time.now
89
+ end
90
+
91
+ def as_atom_entry
92
+
93
+ e = Atom::Entry.new
94
+
95
+ e.id = @id
96
+ e.updated = @updated
97
+
98
+ e
99
+ end
100
+ end
101
+
102
+ #
103
+ # This feed registers as an observer to the ParticipantMap.
104
+ # Each time a workitem is delivered to a participant or comes back from/for
105
+ # it, an AtomEntry is generated.
106
+ # The get_feed() method produces an atom feed of participant activity.
107
+ #
108
+ class ActivityFeedService
109
+ #include MonitorMixin
110
+ include ServiceMixin
111
+ include OwfeServiceLocator
112
+
113
+
114
+ attr_accessor :max_item_count
115
+
116
+
117
+ #
118
+ # This service is generally tied to an engine by doing :
119
+ #
120
+ # engine.init_service 'activityFeed', ActivityFeedService
121
+ #
122
+ # The init_service() will take care of calling the constructor
123
+ # implemented here.
124
+ #
125
+ def initialize (service_name, application_context)
126
+
127
+ super()
128
+
129
+ service_init service_name, application_context
130
+
131
+ @entries = []
132
+ @max_item_count = 100
133
+
134
+ get_participant_map.add_observer ".*", self
135
+ end
136
+
137
+ #
138
+ # This is the method call by the expression pool each time a
139
+ # workitem reaches a participant.
140
+ #
141
+ def call (channel, *args)
142
+
143
+ e = Entry.new
144
+
145
+ e.participant_name = channel
146
+ e.upon = args[0]
147
+ e.workitem = args[1].dup
148
+
149
+ e.id = \
150
+ "#{e.workitem.participant_name} - #{e.upon} " +
151
+ "#{e.workitem.fei.workflow_instance_id}--" +
152
+ "#{e.workitem.fei.expression_id}"
153
+
154
+ @entries << e
155
+
156
+ @entries = @entries[0, @max_item_count] \
157
+ if @entries.length > @max_item_count
158
+ end
159
+
160
+ #
161
+ # Returns an Atom feed of all the workitem activity for the
162
+ # participants whose name matches the given regular expression.
163
+ #
164
+ # Options :
165
+ #
166
+ # [:upon] can be set to either nil, :apply, :reply. :apply states
167
+ # that the returned feed should only contain entries about
168
+ # participant getting applied, :reply only about
169
+ # participant replying.
170
+ # [:feed_uri] the URI for the feed. Defaults to
171
+ # 'http://localhost/feed'
172
+ # [:feed_title] the title for the feed. Defaults to
173
+ # 'OpenWFEru engine activity feed'
174
+ # [:format] yaml|text|json
175
+ #
176
+ #
177
+ def get_feed (participant_regex, options={})
178
+
179
+ participant_regex = Regexp.compile(participant_regex) \
180
+ if participant_regex.is_a?(String)
181
+
182
+ upon = options[:upon]
183
+ feed_uri = options[:feed_uri] || "http://localhost/feed"
184
+ title = options[:feed_title] || "OpenWFEru engine activity feed"
185
+
186
+ feed = Atom::Collection.new feed_uri
187
+ feed.title = title
188
+
189
+ format = options[:format]
190
+ format = validate_format(format)
191
+
192
+ @entries.each do |e|
193
+
194
+ next unless participant_regex.match(e.participant_name)
195
+ next if upon and upon != e.upon
196
+
197
+ feed.updated = e.updated \
198
+ if feed.updated == nil or e.updated > feed.updated
199
+
200
+ feed << as_atom_entry(format, e)
201
+ end
202
+
203
+ feed
204
+ end
205
+
206
+ protected
207
+
208
+ #
209
+ # Makes sure the required 'render' is valid. Returns it
210
+ # as a Symbol.
211
+ #
212
+ def validate_format (f)
213
+
214
+ f = "as_#{f}"
215
+ return :as_yaml unless methods.include?(f)
216
+ f.to_sym
217
+ end
218
+
219
+ def as_atom_entry (render, entry)
220
+
221
+ send(
222
+ render,
223
+ entry.as_atom_entry,
224
+ entry.participant_name,
225
+ entry.upon,
226
+ entry.workitem)
227
+ end
228
+
229
+ #
230
+ # A basic rendition of a workitem as a YAML string
231
+ #
232
+ def as_yaml (atom_entry, participant_name, upon, workitem)
233
+
234
+ atom_entry.title = "#{participant_name} - #{upon}"
235
+ atom_entry.content = workitem.to_yaml
236
+ atom_entry.content['type'] = "text/plain"
237
+
238
+ atom_entry
239
+ end
240
+
241
+ #class Atom::Content
242
+ # def convert_contents e
243
+ # REXML::CData.new(@content.to_s)
244
+ # end
245
+ #end
246
+
247
+ #
248
+ # A basic rendition of a workitem as text.
249
+ #
250
+ def as_text (atom_entry, participant_name, upon, workitem)
251
+
252
+ atom_entry.title = "#{participant_name} - #{upon}"
253
+
254
+ atom_entry.content = workitem.to_s
255
+ atom_entry.content['type'] = "text/plain"
256
+
257
+ atom_entry
258
+ end
259
+
260
+ #
261
+ # Renders the workitem as a JSON string.
262
+ #
263
+ def as_json (atom_entry, participant_name, upon, workitem)
264
+
265
+ atom_entry.title = "#{participant_name} - #{upon}"
266
+
267
+ atom_entry.content = workitem.to_json
268
+ atom_entry.content['type'] = "text/plain"
269
+
270
+ atom_entry
271
+ end
272
+ end
273
+
274
+ end
275
+
@@ -68,7 +68,7 @@ module Extras
68
68
  # in the same source file. It should be quite easy for the Rails hackers
69
69
  # among you to sort that out for a Rails based usage.
70
70
  #
71
- class OwfeTables < ActiveRecord::Migration
71
+ class WorkitemTables < ActiveRecord::Migration
72
72
 
73
73
  def self.up
74
74
 
@@ -106,6 +106,14 @@ module Extras
106
106
  end
107
107
  end
108
108
 
109
+ #
110
+ # Reopening InFlowWorkItem to add a 'db_id' attribute.
111
+ #
112
+ class InFlowWorkItem
113
+
114
+ attr_accessor :db_id
115
+ end
116
+
109
117
  #
110
118
  # The ActiveRecord version of an OpenWFEru workitem (InFlowWorkItem).
111
119
  #
@@ -179,7 +187,7 @@ module Extras
179
187
  end
180
188
 
181
189
  i.save!
182
-
190
+ # making sure to throw an exception in case of trouble
183
191
  end
184
192
 
185
193
  i
@@ -191,10 +199,14 @@ module Extras
191
199
  def as_owfe_workitem
192
200
 
193
201
  wi = OpenWFE::InFlowWorkItem.new
202
+
194
203
  wi.fei = full_fei
195
204
  wi.participant_name = participant_name
196
205
  wi.attributes = fields_hash
197
206
  # don't care about dispatch_time and last_modified
207
+
208
+ wi.db_id = self.id
209
+
198
210
  wi
199
211
  end
200
212
 
@@ -230,6 +242,7 @@ module Extras
230
242
  # an old trick for backward compatibility with OpenWFEja
231
243
 
232
244
  save!
245
+ # making sure to throw an exception in case of trouble
233
246
  end
234
247
 
235
248
  #
@@ -302,6 +315,78 @@ module Extras
302
315
 
303
316
  result
304
317
  end
318
+
319
+ #
320
+ # A kind of 'google search' among workitems
321
+ #
322
+ def Workitem.search (search_string, storename_list=nil)
323
+
324
+ storename_list = Array(storename_list) if storename_list
325
+
326
+ # participant_name
327
+
328
+ result = find(
329
+ :all,
330
+ :conditions => conditions(
331
+ "participant_name", search_string, storename_list),
332
+ :order => "participant_name")
333
+ # :limit => 10)
334
+
335
+ ids = result.collect { |wi| wi.id }
336
+
337
+ # svalue
338
+
339
+ fields = Field.find(
340
+ :all,
341
+ :conditions => conditions(
342
+ "svalue", search_string, storename_list),
343
+ :include => :workitem)
344
+
345
+ merge_search_results(ids, result, fields)
346
+
347
+ # fkey
348
+
349
+ fields = Field.find(
350
+ :all,
351
+ :conditions => conditions(
352
+ "fkey", search_string, storename_list),
353
+ :include => :workitem)
354
+
355
+ merge_search_results(ids, result, fields)
356
+
357
+ # over.
358
+
359
+ result
360
+ end
361
+
362
+ protected
363
+
364
+ #
365
+ # builds the condition (the WHERE clause) for the
366
+ # search.
367
+ #
368
+ def Workitem.conditions (keyname, search_string, storename_list)
369
+
370
+ if storename_list
371
+ [ "#{keyname} LIKE ? AND workitems.store_name IN (?)",
372
+ search_string, storename_list ]
373
+ else
374
+ [ "#{keyname} LIKE ?",
375
+ search_string ]
376
+ end
377
+ end
378
+
379
+ def Workitem.merge_search_results (ids, wis, new_wis)
380
+
381
+ return if new_wis.size < 1
382
+
383
+ new_wis.each do |wi|
384
+ wi = wi.workitem if wi.kind_of?(Field)
385
+ next if ids.include? wi.id
386
+ ids << wi.id
387
+ wis << wi
388
+ end
389
+ end
305
390
  end
306
391
 
307
392
  #
@@ -30,8 +30,6 @@
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
31
  #++
32
32
  #
33
- # $Id$
34
- #
35
33
 
36
34
  #
37
35
  # "made in Japan"
@@ -70,15 +68,14 @@ end
70
68
  require 'openwfe/participants/participant'
71
69
 
72
70
 
73
- module OpenWFE
74
- module Extras
71
+ module OpenWFE::Extras
75
72
 
76
73
  #
77
74
  # Stores the incoming workitem into an 'atom feed'
78
75
  #
79
76
  # An example :
80
77
  #
81
- # feed0 = AtomParticipant.new(
78
+ # feed0 = AtomFeedParticipant.new(
82
79
  # 20, # no more than 20 entries are kept
83
80
  # """
84
81
  # <p>
@@ -89,13 +86,13 @@ module Extras
89
86
  # The 'template' parameter may contain an instance of File instead of
90
87
  # an instance of String.
91
88
  #
92
- # feed0 = AtomParticipant.new(
89
+ # feed0 = AtomFeedParticipant.new(
93
90
  # 20, File.new("path/to/my/atom/template.txt")
94
91
  #
95
92
  # The template can be passed as the second parameter (after the max entry
96
93
  # count) or as a block :
97
94
  #
98
- # feed1 = AtomParticipant.new(20) do |flow_expression, atom_participant, workitem|
95
+ # feed1 = AtomFeedParticipant.new(20) do |flow_expression, atom_participant, workitem|
99
96
  # #
100
97
  # # usually only the workitem parameter is used
101
98
  # # but the other two allow for advanced tricks...
@@ -117,15 +114,19 @@ module Extras
117
114
  # "atom-tools" from http://code.necronomicorp.com/trac/atom-tools
118
115
  #
119
116
  #
120
- class AtomParticipant
121
- include LocalParticipant, MonitorMixin
117
+ class AtomFeedParticipant
118
+ include MonitorMixin
119
+ include LocalParticipant
120
+ include TemplateMixin
122
121
 
123
- attr_accessor \
124
- :content_type # blocks may manipulate them
122
+ #
123
+ # Made accessible so that blocks may set it.
124
+ #
125
+ attr_accessor :content_type
125
126
 
126
127
  def initialize (max_item_count, template=nil, &block)
127
128
 
128
- super()
129
+ super() # very important as this class includes MonitorMixin
129
130
 
130
131
  @template = template
131
132
  @max_item_count = max_item_count
@@ -160,24 +161,15 @@ module Extras
160
161
 
161
162
  protected
162
163
 
164
+ #
165
+ # This base implementation simply calls the eval_template()
166
+ # method of the TemplateMixin.
167
+ # Feel free to override this render() method for custom
168
+ # representations.
169
+ #
163
170
  def render (workitem)
164
171
 
165
- fe = get_flow_expression(workitem)
166
-
167
- template = if @block_template
168
- #@block_template.call(fe, self, workitem)
169
- call_block @block_template, workitem
170
- elsif @template
171
- if @template.kind_of? File
172
- @template.readlines
173
- else
174
- @template.to_s
175
- end
176
- else
177
- "(no template given)"
178
- end
179
-
180
- OpenWFE::dosub(template, fe, workitem)
172
+ eval_template workitem
181
173
  end
182
174
 
183
175
  #
@@ -194,5 +186,4 @@ module Extras
194
186
  end
195
187
 
196
188
  end
197
- end
198
189