openwferu 0.9.0

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.
Files changed (55) hide show
  1. data/README +47 -0
  2. data/lib/codec.rb +571 -0
  3. data/lib/controlclient.rb +115 -0
  4. data/lib/definitions.rb +112 -0
  5. data/lib/exception.rb +60 -0
  6. data/lib/flowexpressionid.rb +137 -0
  7. data/lib/openwferu.rb +43 -0
  8. data/lib/osocket.rb +138 -0
  9. data/lib/otime.rb +171 -0
  10. data/lib/restclient.rb +155 -0
  11. data/lib/ru/contextual.rb +63 -0
  12. data/lib/ru/dollar.rb +163 -0
  13. data/lib/ru/engine.rb +130 -0
  14. data/lib/ru/environment.rb +140 -0
  15. data/lib/ru/expressionmap.rb +120 -0
  16. data/lib/ru/expressionpool.rb +339 -0
  17. data/lib/ru/expressionstorage.rb +97 -0
  18. data/lib/ru/fe_base.rb +105 -0
  19. data/lib/ru/fe_concurrence.rb +122 -0
  20. data/lib/ru/fe_define.rb +101 -0
  21. data/lib/ru/fe_misc.rb +96 -0
  22. data/lib/ru/fe_participant.rb +75 -0
  23. data/lib/ru/fe_raw.rb +173 -0
  24. data/lib/ru/fe_subprocess.rb +84 -0
  25. data/lib/ru/fe_time.rb +135 -0
  26. data/lib/ru/fe_utils.rb +123 -0
  27. data/lib/ru/fe_value.rb +225 -0
  28. data/lib/ru/flowexpression.rb +250 -0
  29. data/lib/ru/logging.rb +85 -0
  30. data/lib/ru/participant.rb +67 -0
  31. data/lib/ru/participantmap.rb +93 -0
  32. data/lib/ru/participants.rb +74 -0
  33. data/lib/ru/rudefinitions.rb +70 -0
  34. data/lib/ru/ruutils.rb +68 -0
  35. data/lib/ru/scheduler.rb +478 -0
  36. data/lib/ru/schedulers.rb +63 -0
  37. data/lib/ru/service.rb +64 -0
  38. data/lib/test.rb +220 -0
  39. data/lib/utils.rb +94 -0
  40. data/lib/workitem.rb +250 -0
  41. data/lib/worklistclient.rb +276 -0
  42. data/test/dollartest.rb +79 -0
  43. data/test/feitest.rb +130 -0
  44. data/test/flowtestbase.rb +86 -0
  45. data/test/ft_0.rb +161 -0
  46. data/test/ft_1_unset.rb +152 -0
  47. data/test/ft_2_concurrence.rb +34 -0
  48. data/test/ft_3_equals.rb +84 -0
  49. data/test/ft_4_misc.rb +128 -0
  50. data/test/ft_5_time.rb +56 -0
  51. data/test/misctest.rb +46 -0
  52. data/test/runtest.rb +21 -0
  53. data/test/rutest_utils.rb +15 -0
  54. data/test/timetest.rb +111 -0
  55. metadata +100 -0
@@ -0,0 +1,478 @@
1
+ #
2
+ # Copyright (c) 2006, John Mettraux, OpenWFE.org
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # . Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # . Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without
17
+ # specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
32
+ #
33
+
34
+ #
35
+ # "made in Japan"
36
+ #
37
+ # John Mettraux at openwfe.org
38
+ #
39
+
40
+ require 'monitor'
41
+ require 'otime'
42
+ require 'ru/ruutils'
43
+
44
+
45
+ module OpenWFEru
46
+
47
+ class Scheduler
48
+ include MonitorMixin
49
+
50
+ attr_accessor \
51
+ :precision
52
+
53
+ def initialize
54
+
55
+ super()
56
+
57
+ @pending_jobs = []
58
+ @cron_entries = {}
59
+
60
+ @scheduler_thread = nil
61
+
62
+ @precision = 0.250
63
+ #
64
+ # every 250ms, the scheduler wakes up
65
+
66
+ @last_cron_minute = -1
67
+ end
68
+
69
+ def stop
70
+ @scheduler_thread.stop \
71
+ if @scheduler_thread and not @scheduler_thread.stop?
72
+ end
73
+
74
+ def start
75
+ if @scheduler_thread
76
+ @scheduler_thread.wakeup
77
+ return
78
+ end
79
+
80
+ @scheduler_thread = Thread.new do
81
+ while true
82
+ step
83
+ sleep(@precision)
84
+ end
85
+ end
86
+ end
87
+
88
+ def step
89
+ synchronize do
90
+ now = Time.new
91
+ minute = now.to_i / 60
92
+
93
+ #puts "step() minute is #{minute}"
94
+ #puts "step() last_cron_minute is #{@last_cron_minute}"
95
+
96
+ #
97
+ # cron entries
98
+
99
+ begin
100
+ if minute > @last_cron_minute
101
+ @last_cron_minute = minute
102
+ @cron_entries.each do |cron_id, cron_entry|
103
+ #puts "step() cron_id : #{cron_id}"
104
+ cron_entry.trigger \
105
+ if cron_entry.matches? now
106
+ end
107
+ end
108
+ rescue Exception => e
109
+ #puts \
110
+ # "step() caught exception\n" +
111
+ # OpenWFEru::exception_to_s(e)
112
+ end
113
+
114
+ #
115
+ # pending jobs
116
+
117
+ now = now.to_f
118
+ #
119
+ # that's what at jobs do understand
120
+
121
+ while true
122
+
123
+ #puts "step() job.count is #{@pending_jobs.length}"
124
+
125
+ break if @pending_jobs.length < 1
126
+
127
+ job = @pending_jobs[0]
128
+
129
+ #puts "step() job.at is #{job.at}"
130
+ #puts "step() now is #{now}"
131
+
132
+ break if job.at > now
133
+
134
+ #if job.at <= now
135
+ #
136
+ # obviously
137
+
138
+ job.trigger()
139
+ @pending_jobs.delete_at(0)
140
+ end
141
+ end
142
+ end
143
+
144
+ #
145
+ # joins on the scheduler thread
146
+ #
147
+ def join
148
+ @scheduler_thread.join
149
+ end
150
+
151
+ #
152
+ # schedules a job by specifying at which time it should trigger
153
+ #
154
+ def schedule_at (at, schedulable, params)
155
+ synchronize do
156
+
157
+ at = OpenWFE::to_ruby_time(at) \
158
+ if at.kind_of?(String)
159
+
160
+ at = at.to_f \
161
+ if at.kind_of?(Time)
162
+
163
+ job = JobEntry.new(at, schedulable, params)
164
+
165
+ if at < (Time.new.to_f + @precision)
166
+ job.trigger()
167
+ return nil
168
+ end
169
+
170
+ return push(job) \
171
+ if @pending_jobs.length < 1
172
+
173
+ # shortcut : check if the new job is posterior to
174
+ # the last job pending
175
+
176
+ return push(job) \
177
+ if at >= @pending_jobs.last.at
178
+
179
+ for i in 0...@pending_jobs.length
180
+ if at <= @pending_jobs[i].at
181
+ return push(job, i)
182
+ end
183
+ end
184
+
185
+ return push(job)
186
+
187
+ end
188
+ end
189
+
190
+ #
191
+ # schedules a job by stating in how much time it should trigger
192
+ #
193
+ def schedule_in (duration, schedulable, params)
194
+
195
+ if duration.kind_of?(String)
196
+ duration = OpenWFE::parse_time_string(duration)
197
+ elsif not duration.kind_of?(Float)
198
+ duration = Float(duration.to_s)
199
+ end
200
+
201
+ return schedule_at(Time.new.to_f + duration, schedulable, params)
202
+ end
203
+
204
+ #
205
+ # unschedules 'at' or 'cron' job
206
+ #
207
+ def unschedule (entry_id)
208
+ synchronize do
209
+
210
+ for i in 0...@pending_jobs.length
211
+ if @pending_jobs[i].id == at_id
212
+ @pending_jobs.delete_at(i)
213
+ return true
214
+ end
215
+ end
216
+
217
+ if @cron_entries.has_key?(entry_id)
218
+ @cron_entries.delete(entry_id)
219
+ return true
220
+ end
221
+
222
+ return false
223
+ end
224
+ end
225
+
226
+ #
227
+ # schedules a cron job
228
+ #
229
+ def schedule (cron_line, schedulable, params)
230
+ synchronize do
231
+ entry = CronEntry.new(cron_line, schedulable, params)
232
+ @cron_entries[entry.eid] = entry
233
+ return entry.eid
234
+ end
235
+ end
236
+
237
+ protected
238
+
239
+ def push (job, index=-1)
240
+
241
+ if index == -1
242
+ #
243
+ # push job at the end
244
+ #
245
+ @pending_jobs << job
246
+ else
247
+ #
248
+ # insert job at given index
249
+ #
250
+ @pending_jobs[index, 0] = job
251
+ end
252
+
253
+ #puts "push() at '#{Time.at(job.at)}'"
254
+
255
+ return job.eid
256
+ end
257
+ end
258
+
259
+ #
260
+ # This module adds a trigger method to any class that includes it.
261
+ # The default implementation feature here triggers an exception.
262
+ #
263
+ module Schedulable
264
+
265
+ def trigger (params)
266
+ raise "trigger() implementation is missing"
267
+ end
268
+ end
269
+
270
+ #
271
+ # a 'cron line' is a line in the sense of a crontab (man 5 cron) file
272
+ #
273
+ class CronLine
274
+
275
+ def initialize (line)
276
+
277
+ super()
278
+
279
+ items = line.split
280
+
281
+ if items.length != 5
282
+ raise \
283
+ "cron '#{line}' string should hold 5 items, " +
284
+ "not #{items.length}" \
285
+ end
286
+
287
+ @minutes = parse_item(items[0], 0, 59)
288
+ @hours = parse_item(items[1], 0, 24)
289
+ @days = parse_item(items[2], 1, 31)
290
+ @months = parse_item(items[3], 1, 12)
291
+ @weekdays = parse_item(items[4], 1, 7)
292
+
293
+ adjust_arrays()
294
+ end
295
+
296
+ def matches? (time)
297
+
298
+ if time.kind_of?(Float) or time.kind_of?(Integer)
299
+ time = Time.at(time)
300
+ end
301
+
302
+ return false if no_match?(time.min, @minutes)
303
+ return false if no_match?(time.hour, @hours)
304
+ return false if no_match?(time.day, @days)
305
+ return false if no_match?(time.month, @months)
306
+ return false if no_match?(time.wday, @weekdays)
307
+
308
+ return true
309
+ end
310
+
311
+ private
312
+
313
+ #
314
+ # adjust values to Ruby
315
+ #
316
+ def adjust_arrays()
317
+ if @hours
318
+ @hours.each do |h|
319
+ h = 0 if h == 23
320
+ end
321
+ end
322
+ if @weekdays
323
+ @weekdays.each do |wd|
324
+ wd = wd - 1
325
+ end
326
+ end
327
+ end
328
+
329
+ def parse_item (item, min, max)
330
+
331
+ return nil \
332
+ if item == "*"
333
+ return parse_list(item, min, max) \
334
+ if item.index(",") > -1
335
+ return parse_range(item, min, max) \
336
+ if item.index("*") > -1 or item.index("-") > -1
337
+
338
+ i = Integer(item)
339
+
340
+ i = min if i < min
341
+ i = max if i > max
342
+
343
+ return [ i ]
344
+ end
345
+
346
+ def parse_list (item, min, max)
347
+ items = item.split(",")
348
+ result = []
349
+ items.each do |i|
350
+ i = Integer(i)
351
+ i = min if i < min
352
+ i = max if i > max
353
+ result << i
354
+ end
355
+ return result
356
+ end
357
+
358
+ def parse_range (item, min, max)
359
+ i = item.index("-")
360
+ j = item.index("/")
361
+
362
+ inc = 1
363
+
364
+ inc = Integer(item[j+1..-1]) if j > -1
365
+
366
+ istart = -1
367
+ iend = -1
368
+
369
+ if i > -1
370
+
371
+ istart = Integer(item[0..i])
372
+
373
+ if j > -1
374
+ iend = Integer(item[i+1..j])
375
+ else
376
+ iend = Integer(i+1..-1)
377
+ end
378
+
379
+ else # case */x
380
+ istart = min
381
+ iend = max
382
+ end
383
+
384
+ istart = min if istart < min
385
+ iend = max if iend > max
386
+
387
+ result = []
388
+
389
+ value = istart
390
+ while true
391
+ result << value
392
+ value = value + inc
393
+ break if value > iend
394
+ end
395
+
396
+ return result
397
+ end
398
+
399
+ def no_match? (value, cron_values)
400
+
401
+ return false if not cron_values
402
+
403
+ cron_values.each do |v|
404
+ return false if value == v
405
+ end
406
+
407
+ return true
408
+ end
409
+ end
410
+
411
+ protected
412
+
413
+ JOB_ID_LOCK = Monitor.new
414
+
415
+ class Entry
416
+
417
+ @@last_given_id = 0
418
+ #
419
+ # as a scheduler is fully transient, no need to
420
+ # have persistent ids, a simple counter is sufficient
421
+
422
+ attr_accessor \
423
+ :eid, :schedulable, :params
424
+
425
+ def initialize (schedulable, params)
426
+ @schedulable = schedulable
427
+ @params = params
428
+ JOB_ID_LOCK.synchronize do
429
+ @eid = @@last_given_id + 1
430
+ @@last_given_id = @eid
431
+ end
432
+ end
433
+
434
+ def trigger
435
+ @schedulable.trigger(params)
436
+ end
437
+ end
438
+
439
+ class JobEntry < Entry
440
+
441
+ attr_accessor \
442
+ :at
443
+
444
+ def initialize (at, schedulable, params)
445
+ super(schedulable, params)
446
+ @at = at
447
+ end
448
+ end
449
+
450
+ class CronEntry < Entry
451
+
452
+ attr_accessor \
453
+ :cron_line
454
+
455
+ def initialize (line, schedulable, params)
456
+
457
+ super(schedulable, params)
458
+
459
+ if line.kind_of?(String)
460
+ @cronline = CronLine.new(line)
461
+ elsif line.kind_of?(CronLine)
462
+ @cronline = line
463
+ else
464
+ raise \
465
+ "Cannot initialize a CronEntry " +
466
+ "with a param of class #{line.class}"
467
+ end
468
+
469
+ @cron_line = CronLine.new(line)
470
+ end
471
+
472
+ def matches? (time)
473
+ @cron_line.matches?(time)
474
+ end
475
+ end
476
+
477
+ end
478
+
@@ -0,0 +1,63 @@
1
+ #
2
+ # Copyright (c) 2006, John Mettraux, OpenWFE.org
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # . Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # . Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without
17
+ # specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
32
+ #
33
+
34
+ #
35
+ # "made in Japan"
36
+ #
37
+ # John Mettraux at openwfe.org
38
+ #
39
+
40
+ require 'ru/service'
41
+ require 'ru/scheduler'
42
+
43
+
44
+ module OpenWFEru
45
+
46
+ #
47
+ # The Scheduler class has been made independant of OpenWFE service
48
+ # infrastructure (so that one could easily use it without OpenWFEru)
49
+ #
50
+ class SchedulerService < Scheduler
51
+ include ServiceMixin
52
+
53
+ def initialize (service_name, application_context)
54
+ super()
55
+ @service_name = service_name
56
+ @application_context = application_context
57
+
58
+ start()
59
+ end
60
+ end
61
+
62
+ end
63
+
data/lib/ru/service.rb ADDED
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright (c) 2006, John Mettraux, OpenWFE.org
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # . Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # . Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without
17
+ # specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
32
+ #
33
+
34
+ #
35
+ # "made in Japan"
36
+ #
37
+ # John Mettraux at openwfe.org
38
+ #
39
+
40
+ require 'ru/logging'
41
+ require 'ru/contextual'
42
+
43
+
44
+ module OpenWFEru
45
+
46
+ module ServiceMixin
47
+ include Contextual, Logging
48
+
49
+ attr_accessor \
50
+ :service_name
51
+ end
52
+
53
+ class Service
54
+ include ServiceMixin
55
+
56
+ def initialize (service_name, application_context)
57
+ @service_name = service_name
58
+ @application_context = application_context
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+