ruote 0.9.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (291) hide show
  1. data/README.txt +24 -0
  2. data/bin/validate-workflow.rb +89 -0
  3. data/examples/about_state.rb +81 -0
  4. data/examples/bigflow.rb +19 -0
  5. data/examples/csv_weather.rb +23 -0
  6. data/examples/engine_template.rb +247 -0
  7. data/examples/flowtracing.rb +24 -0
  8. data/examples/homeworkreview.rb +68 -0
  9. data/examples/kotoba.rb +22 -0
  10. data/examples/mano_tracker.rb +172 -0
  11. data/examples/openwferu.rb +58 -0
  12. data/examples/quotereporter.rb +157 -0
  13. data/examples/scheduler_cron_usage.rb +48 -0
  14. data/examples/scheduler_usage.rb +56 -0
  15. data/lib/openwfe.rb +41 -0
  16. data/lib/openwfe/contextual.rb +111 -0
  17. data/lib/openwfe/def.rb +46 -0
  18. data/lib/openwfe/engine.rb +37 -0
  19. data/lib/openwfe/engine/engine.rb +756 -0
  20. data/lib/openwfe/engine/expool_methods.rb +172 -0
  21. data/lib/openwfe/engine/file_persisted_engine.rb +105 -0
  22. data/lib/openwfe/engine/participant_methods.rb +133 -0
  23. data/lib/openwfe/engine/status_methods.rb +353 -0
  24. data/lib/openwfe/engine/update_exp_methods.rb +112 -0
  25. data/lib/openwfe/exceptions.rb +51 -0
  26. data/lib/openwfe/expool/errorjournal.rb +476 -0
  27. data/lib/openwfe/expool/expressionpool.rb +1144 -0
  28. data/lib/openwfe/expool/expstorage.rb +403 -0
  29. data/lib/openwfe/expool/history.rb +174 -0
  30. data/lib/openwfe/expool/journal.rb +224 -0
  31. data/lib/openwfe/expool/journal_replay.rb +321 -0
  32. data/lib/openwfe/expool/parser.rb +242 -0
  33. data/lib/openwfe/expool/representation.rb +121 -0
  34. data/lib/openwfe/expool/threadedexpstorage.rb +188 -0
  35. data/lib/openwfe/expool/wfidgen.rb +388 -0
  36. data/lib/openwfe/expool/yamlexpstorage.rb +224 -0
  37. data/lib/openwfe/expressions/condition.rb +244 -0
  38. data/lib/openwfe/expressions/environment.rb +246 -0
  39. data/lib/openwfe/expressions/expressionmap.rb +258 -0
  40. data/lib/openwfe/expressions/fe_cancel.rb +109 -0
  41. data/lib/openwfe/expressions/fe_command.rb +241 -0
  42. data/lib/openwfe/expressions/fe_concurrence.rb +662 -0
  43. data/lib/openwfe/expressions/fe_cron.rb +259 -0
  44. data/lib/openwfe/expressions/fe_cursor.rb +259 -0
  45. data/lib/openwfe/expressions/fe_define.rb +192 -0
  46. data/lib/openwfe/expressions/fe_do.rb +168 -0
  47. data/lib/openwfe/expressions/fe_equals.rb +291 -0
  48. data/lib/openwfe/expressions/fe_filter.rb +129 -0
  49. data/lib/openwfe/expressions/fe_filter_definition.rb +168 -0
  50. data/lib/openwfe/expressions/fe_fqv.rb +250 -0
  51. data/lib/openwfe/expressions/fe_if.rb +303 -0
  52. data/lib/openwfe/expressions/fe_iterator.rb +145 -0
  53. data/lib/openwfe/expressions/fe_listen.rb +371 -0
  54. data/lib/openwfe/expressions/fe_losfor.rb +111 -0
  55. data/lib/openwfe/expressions/fe_misc.rb +421 -0
  56. data/lib/openwfe/expressions/fe_participant.rb +269 -0
  57. data/lib/openwfe/expressions/fe_reserve.rb +212 -0
  58. data/lib/openwfe/expressions/fe_save.rb +274 -0
  59. data/lib/openwfe/expressions/fe_sequence.rb +117 -0
  60. data/lib/openwfe/expressions/fe_set.rb +139 -0
  61. data/lib/openwfe/expressions/fe_sleep.rb +166 -0
  62. data/lib/openwfe/expressions/fe_step.rb +159 -0
  63. data/lib/openwfe/expressions/fe_subprocess.rb +168 -0
  64. data/lib/openwfe/expressions/fe_timeout.rb +127 -0
  65. data/lib/openwfe/expressions/fe_wait.rb +78 -0
  66. data/lib/openwfe/expressions/fe_when.rb +142 -0
  67. data/lib/openwfe/expressions/filter.rb +104 -0
  68. data/lib/openwfe/expressions/flowexpression.rb +847 -0
  69. data/lib/openwfe/expressions/iterator.rb +221 -0
  70. data/lib/openwfe/expressions/merge.rb +84 -0
  71. data/lib/openwfe/expressions/raw.rb +547 -0
  72. data/lib/openwfe/expressions/rprocdef.rb +375 -0
  73. data/lib/openwfe/expressions/time.rb +333 -0
  74. data/lib/openwfe/expressions/timeout.rb +178 -0
  75. data/lib/openwfe/expressions/value.rb +126 -0
  76. data/lib/openwfe/filterdef.rb +259 -0
  77. data/lib/openwfe/flowexpressionid.rb +357 -0
  78. data/lib/openwfe/listeners/listener.rb +97 -0
  79. data/lib/openwfe/listeners/listeners.rb +139 -0
  80. data/lib/openwfe/listeners/socketlisteners.rb +272 -0
  81. data/lib/openwfe/logging.rb +122 -0
  82. data/lib/openwfe/omixins.rb +95 -0
  83. data/lib/openwfe/orest/controlclient.rb +119 -0
  84. data/lib/openwfe/orest/definitions.rb +113 -0
  85. data/lib/openwfe/orest/exception.rb +60 -0
  86. data/lib/openwfe/orest/oldrestservlet.rb +279 -0
  87. data/lib/openwfe/orest/osocket.rb +148 -0
  88. data/lib/openwfe/orest/restclient.rb +176 -0
  89. data/lib/openwfe/orest/workitem.rb +206 -0
  90. data/lib/openwfe/orest/worklistclient.rb +272 -0
  91. data/lib/openwfe/orest/xmlcodec.rb +670 -0
  92. data/lib/openwfe/participants.rb +38 -0
  93. data/lib/openwfe/participants/enoparticipants.rb +230 -0
  94. data/lib/openwfe/participants/participant.rb +141 -0
  95. data/lib/openwfe/participants/participantmap.rb +249 -0
  96. data/lib/openwfe/participants/participants.rb +407 -0
  97. data/lib/openwfe/participants/soapparticipants.rb +135 -0
  98. data/lib/openwfe/participants/socketparticipants.rb +202 -0
  99. data/lib/openwfe/participants/storeparticipants.rb +254 -0
  100. data/lib/openwfe/rudefinitions.rb +130 -0
  101. data/lib/openwfe/service.rb +103 -0
  102. data/lib/openwfe/storage/yamlcustom.rb +106 -0
  103. data/lib/openwfe/storage/yamlfilestorage.rb +245 -0
  104. data/lib/openwfe/tools/flowtracer.rb +81 -0
  105. data/lib/openwfe/util/dollar.rb +217 -0
  106. data/lib/openwfe/util/irb.rb +86 -0
  107. data/lib/openwfe/util/observable.rb +144 -0
  108. data/lib/openwfe/util/ometa.rb +62 -0
  109. data/lib/openwfe/util/workqueue.rb +124 -0
  110. data/lib/openwfe/util/xml.rb +418 -0
  111. data/lib/openwfe/utils.rb +554 -0
  112. data/lib/openwfe/version.rb +37 -0
  113. data/lib/openwfe/workitem.rb +499 -0
  114. data/lib/openwfe/worklist/oldrest.rb +244 -0
  115. data/lib/openwfe/worklist/storelocks.rb +293 -0
  116. data/lib/openwfe/worklist/storeparticipant.rb +44 -0
  117. data/lib/openwfe/worklist/worklist.rb +297 -0
  118. data/test/README.txt +27 -0
  119. data/test/back_0916_test.rb +111 -0
  120. data/test/bm/bm_1_xml_vs_prog.rb +56 -0
  121. data/test/bm/bm_2_step.rb +109 -0
  122. data/test/bm/ft_0f_5ms.rb +35 -0
  123. data/test/bm/ft_26_load.rb +210 -0
  124. data/test/bm/ft_26b_load.rb +86 -0
  125. data/test/bm/ft_26c_load.rb +97 -0
  126. data/test/bm/ft_26d_load.rb +97 -0
  127. data/test/bm/ft_recu.rb +71 -0
  128. data/test/clone_test.rb +122 -0
  129. data/test/concurrence_test.rb +77 -0
  130. data/test/condition_test.rb +155 -0
  131. data/test/console_test.rb +12 -0
  132. data/test/cron_ltest.rb +15 -0
  133. data/test/description_test.rb +87 -0
  134. data/test/eno_test.rb +76 -0
  135. data/test/expmap_test.rb +54 -0
  136. data/test/expool_20031219_0916.tgz +0 -0
  137. data/test/fe_lookup_att_test.rb +62 -0
  138. data/test/fei_test.rb +181 -0
  139. data/test/file_persisted_engine_test.rb +64 -0
  140. data/test/file_persistence_test.rb +134 -0
  141. data/test/filep_cancel_test.rb +123 -0
  142. data/test/filter_test.rb +109 -0
  143. data/test/flowtestbase.rb +351 -0
  144. data/test/ft_0.rb +68 -0
  145. data/test/ft_0b_sequence.rb +36 -0
  146. data/test/ft_0c_testname.rb +33 -0
  147. data/test/ft_0d_participant.rb +30 -0
  148. data/test/ft_0e_multibody.rb +34 -0
  149. data/test/ft_10_loop.rb +134 -0
  150. data/test/ft_11_ppd.rb +415 -0
  151. data/test/ft_11b_ppd.rb +54 -0
  152. data/test/ft_12_blockparticipant.rb +97 -0
  153. data/test/ft_13_eno.rb +52 -0
  154. data/test/ft_14_subprocess.rb +88 -0
  155. data/test/ft_14b_subprocess.rb +192 -0
  156. data/test/ft_14c_subprocess.rb +68 -0
  157. data/test/ft_15_iterator.rb +216 -0
  158. data/test/ft_15b_iterator.rb +74 -0
  159. data/test/ft_16_fqv.rb +73 -0
  160. data/test/ft_17_condition.rb +84 -0
  161. data/test/ft_18_pname.rb +56 -0
  162. data/test/ft_1_unset.rb +175 -0
  163. data/test/ft_1b_unset.rb +39 -0
  164. data/test/ft_20_cron.rb +53 -0
  165. data/test/ft_21_cron.rb +87 -0
  166. data/test/ft_21b_cron_pause.rb +82 -0
  167. data/test/ft_22_history.rb +74 -0
  168. data/test/ft_23_when.rb +77 -0
  169. data/test/ft_23b_when.rb +70 -0
  170. data/test/ft_23c_wait.rb +80 -0
  171. data/test/ft_23d_cww.rb +58 -0
  172. data/test/ft_24_def.rb +44 -0
  173. data/test/ft_25_cancel.rb +89 -0
  174. data/test/ft_27_getflowpos.rb +147 -0
  175. data/test/ft_28_fileparticipant.rb +63 -0
  176. data/test/ft_29_httprb.rb +106 -0
  177. data/test/ft_2_concurrence.rb +135 -0
  178. data/test/ft_2b_concurrence.rb +188 -0
  179. data/test/ft_2c_concurrence.rb +64 -0
  180. data/test/ft_30_socketlistener.rb +203 -0
  181. data/test/ft_31_flowname.rb +40 -0
  182. data/test/ft_32_journal.rb +91 -0
  183. data/test/ft_32c_journal.rb +102 -0
  184. data/test/ft_32d_journal.rb +84 -0
  185. data/test/ft_33_description.rb +107 -0
  186. data/test/ft_34_cancelwfid.rb +80 -0
  187. data/test/ft_35_localdefs.rb +75 -0
  188. data/test/ft_36_subprocids.rb +97 -0
  189. data/test/ft_37_pnames.rb +70 -0
  190. data/test/ft_38_tag.rb +127 -0
  191. data/test/ft_38b_tag.rb +161 -0
  192. data/test/ft_38c_tag.rb +100 -0
  193. data/test/ft_39_reserve.rb +63 -0
  194. data/test/ft_39b_reserve.rb +84 -0
  195. data/test/ft_3_equals.rb +170 -0
  196. data/test/ft_3b_lookup_vf.rb +83 -0
  197. data/test/ft_40_defined.rb +61 -0
  198. data/test/ft_41_case.rb +110 -0
  199. data/test/ft_42_environments.rb +75 -0
  200. data/test/ft_43_pat10.rb +85 -0
  201. data/test/ft_44_save.rb +70 -0
  202. data/test/ft_44b_restore.rb +212 -0
  203. data/test/ft_45_citerator.rb +214 -0
  204. data/test/ft_46_pparams.rb +62 -0
  205. data/test/ft_47_filter.rb +160 -0
  206. data/test/ft_48_fe_filter.rb +88 -0
  207. data/test/ft_49_condition.rb +126 -0
  208. data/test/ft_4_misc.rb +237 -0
  209. data/test/ft_50_xml_attribute.rb +155 -0
  210. data/test/ft_51_stack.rb +55 -0
  211. data/test/ft_52_obs_participant.rb +123 -0
  212. data/test/ft_53_null_noop_participant.rb +62 -0
  213. data/test/ft_54_listen.rb +288 -0
  214. data/test/ft_54b_listen.rb +66 -0
  215. data/test/ft_54c_listen.rb +99 -0
  216. data/test/ft_55_ptimeout.rb +59 -0
  217. data/test/ft_56_timeout.rb +59 -0
  218. data/test/ft_57_a.rb +145 -0
  219. data/test/ft_58_ejournal.rb +151 -0
  220. data/test/ft_59_ps.rb +150 -0
  221. data/test/ft_59b_ps_for_pat.rb +58 -0
  222. data/test/ft_5_time.rb +118 -0
  223. data/test/ft_60_ecancel.rb +161 -0
  224. data/test/ft_61_elsub.rb +51 -0
  225. data/test/ft_62_procparticipant.rb +71 -0
  226. data/test/ft_63_pause.rb +124 -0
  227. data/test/ft_64_alias.rb +102 -0
  228. data/test/ft_64_clone.rb +69 -0
  229. data/test/ft_65_stringlaunch.rb +59 -0
  230. data/test/ft_66_subforget.rb +70 -0
  231. data/test/ft_67_schedlaunch.rb +116 -0
  232. data/test/ft_68_ifparticipant.rb +70 -0
  233. data/test/ft_69_cancelmissing.rb +51 -0
  234. data/test/ft_6_lambda.rb +64 -0
  235. data/test/ft_70_lookupvar.rb +55 -0
  236. data/test/ft_71_log.rb +60 -0
  237. data/test/ft_72_lookup_processes.rb +76 -0
  238. data/test/ft_73_cancel_sub.rb +139 -0
  239. data/test/ft_74_block_and_workitem_dup.rb +63 -0
  240. data/test/ft_75_ruby_attributes.rb +87 -0
  241. data/test/ft_76_merge_isolate.rb +88 -0
  242. data/test/ft_77_segments.rb +35 -0
  243. data/test/ft_78_eval.rb +150 -0
  244. data/test/ft_79_tticket.rb +187 -0
  245. data/test/ft_79b_tticket.rb +172 -0
  246. data/test/ft_79c_outcome.rb +56 -0
  247. data/test/ft_7_lose.rb +104 -0
  248. data/test/ft_7b_lose.rb +78 -0
  249. data/test/ft_80_spname.rb +91 -0
  250. data/test/ft_81_exp.rb +60 -0
  251. data/test/ft_82_trecu.rb +46 -0
  252. data/test/ft_83_badpause.rb +58 -0
  253. data/test/ft_84_updateexp.rb +198 -0
  254. data/test/ft_85_dolhash.rb +43 -0
  255. data/test/ft_86_dollar_fv.rb +68 -0
  256. data/test/ft_87_define.rb +74 -0
  257. data/test/ft_8_forget.rb +44 -0
  258. data/test/ft_9_cursor.rb +145 -0
  259. data/test/ft_9b_cursor.rb +105 -0
  260. data/test/ft_tests.rb +124 -0
  261. data/test/hash_test.rb +75 -0
  262. data/test/hparticipant_test.rb +164 -0
  263. data/test/lookup_att_test.rb +90 -0
  264. data/test/lookup_vf_test.rb +94 -0
  265. data/test/misc_test.rb +90 -0
  266. data/test/nut_0_irb.rb +20 -0
  267. data/test/obs_test.rb +142 -0
  268. data/test/orest_test.rb +251 -0
  269. data/test/param_test.rb +290 -0
  270. data/test/participant_test.rb +101 -0
  271. data/test/pending.rb +23 -0
  272. data/test/ps_representation.rb +133 -0
  273. data/test/rake_ltest.rb +38 -0
  274. data/test/rake_qtest.rb +68 -0
  275. data/test/raw_prog_test.rb +412 -0
  276. data/test/restart_cron_test.rb +136 -0
  277. data/test/restart_paused_test.rb +98 -0
  278. data/test/restart_sleep_test.rb +140 -0
  279. data/test/restart_tests.rb +18 -0
  280. data/test/restart_when_test.rb +112 -0
  281. data/test/ruby_procdef_test.rb +132 -0
  282. data/test/rutest_utils.rb +63 -0
  283. data/test/sec_test.rb +205 -0
  284. data/test/slock_test.rb +80 -0
  285. data/test/storage_test.rb +44 -0
  286. data/test/test.rb +3 -0
  287. data/test/timeout_test.rb +105 -0
  288. data/test/util_xml_test.rb +112 -0
  289. data/test/wfid_test.rb +175 -0
  290. data/test/wi_test.rb +75 -0
  291. metadata +433 -0
@@ -0,0 +1,48 @@
1
+
2
+ #
3
+ # showing how to use the scheduler
4
+ #
5
+
6
+ require 'rubygems'
7
+
8
+ require 'time'
9
+
10
+ require 'openwfe/util/scheduler'
11
+ include OpenWFE
12
+
13
+
14
+ def p (msg)
15
+ t = Time.new
16
+ puts "#{t.iso8601} -- #{msg}"
17
+ end
18
+ #
19
+ # a small method for displaying the time at the beginning
20
+ # of each output line
21
+
22
+
23
+ scheduler = Scheduler.new
24
+ scheduler.start
25
+ #
26
+ # create a scheduler instance and start it
27
+
28
+ p "started scheduler"
29
+
30
+ i = 0
31
+
32
+ scheduler.schedule("1-60 * * * *") do
33
+ p "minute ##{i}"
34
+ i = i + 1
35
+ end
36
+
37
+ scheduler.schedule_in("2m10s") do
38
+ p "after 2 minutes and 10 seconds stopping the scheduler and exiting..."
39
+ scheduler.stop
40
+ end
41
+ #
42
+ # using a regular "at" job to stop the scheduler after 4 minutes
43
+
44
+ scheduler.join
45
+ #
46
+ # align the thread of this program to the scheduler thread
47
+ # i.e. exit program only when scheduler terminates
48
+
@@ -0,0 +1,56 @@
1
+
2
+ #
3
+ # showing how to use the scheduler
4
+ #
5
+
6
+ require 'rubygems'
7
+
8
+ require 'time'
9
+
10
+ require 'openwfe/util/scheduler'
11
+ include OpenWFE
12
+
13
+
14
+ def p (msg)
15
+ t = Time.new
16
+ puts "#{t.iso8601} -- #{msg}"
17
+ end
18
+ #
19
+ # a small method for displaying the time at the beginning
20
+ # of each output line
21
+
22
+
23
+ scheduler = Scheduler.new
24
+ scheduler.start
25
+ #
26
+ # create a scheduler instance and start it
27
+
28
+ p "started scheduler"
29
+
30
+ scheduler.schedule_in("3s") do
31
+ p "after 3 seconds"
32
+ end
33
+
34
+ scheduler.schedule_in("2s") do
35
+ p "after 2 seconds"
36
+ end
37
+
38
+ scheduler.schedule_in("5500") do
39
+ p "after 5500 ms stopping the scheduler and exiting..."
40
+ scheduler.stop
41
+ end
42
+
43
+ #scheduler.schedule_at("x" do
44
+ #end
45
+
46
+ #scheduler.schedule_in("3M4h27m") do
47
+ # p "3 months, 4 hours and 27 minutes... A bit too much"
48
+ #end
49
+ #
50
+ # showing what the time strings are capable of
51
+
52
+ scheduler.join
53
+ #
54
+ # align the thread of this program to the scheduler thread
55
+ # i.e. exit program only when scheduler terminates
56
+
data/lib/openwfe.rb ADDED
@@ -0,0 +1,41 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2005-2007, John Mettraux and Alain Hoang, 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
+ # = openwferu -- Open Workflow Engine in Ruby
34
+ #
35
+ # This is the main file for the openwferu engine. It is normally
36
+ # referenced as a library via a require statement.
37
+ #
38
+
39
+ require 'openwfe/engine/engine'
40
+ #require 'openwfe/engine/file_persisted_engine'
41
+
@@ -0,0 +1,111 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2008, John Mettraux, Nicolas Modrzyk 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
+ # Nicolas Modrzyk at openwfe.org
39
+ #
40
+
41
+ module OpenWFE
42
+
43
+ #
44
+ # This mixin helds an application_context field and provides a
45
+ # lookup method for digging into that context.
46
+ #
47
+ module Contextual
48
+
49
+ attr_accessor :application_context
50
+
51
+ alias :ac :application_context
52
+
53
+ #
54
+ # Looks up something in the application context, if the given
55
+ # key is a class, then the first value in the context of that
56
+ # class is returned.
57
+ #
58
+ def lookup (key)
59
+
60
+ if key.kind_of? Class
61
+ @application_context.each do |k, value|
62
+ return value if value.class == key
63
+ end
64
+ return nil
65
+ end
66
+
67
+ @application_context[key]
68
+ end
69
+
70
+ #
71
+ # Use reflection to instantiate the new service,and
72
+ # add it to the application context
73
+ # The service_name can be a String or a Symbol (which will be
74
+ # turned into a String).
75
+ #
76
+ def init_service (service_name, service_class)
77
+
78
+ s = service_class.new service_name, @application_context
79
+
80
+ unless service_name
81
+ s.service_name = "#{service_class.name}::#{s.object_id}"
82
+ @application_context[s.service_name.to_s] = s
83
+ end
84
+
85
+ s
86
+ end
87
+
88
+ #
89
+ # Returns the work directory for the OpenWFE[ru] application context
90
+ # (if any).
91
+ #
92
+ def get_work_directory (context_or_dir=nil)
93
+
94
+ dir = if context_or_dir.is_a?(String)
95
+ context_or_dir
96
+ elsif context_or_dir.respond_to?(:[])
97
+ context_or_dir[:work_directory]
98
+ else
99
+ @application_context[:work_directory] if @application_context
100
+ end
101
+
102
+ dir = DEFAULT_WORK_DIRECTORY unless dir
103
+
104
+ FileUtils.makedirs(dir) unless File.exist?(dir)
105
+
106
+ dir
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,46 @@
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
+ # just a redirection
36
+ #
37
+ # require 'openwfe/def'
38
+ #
39
+ # being shorter and easier to remember than
40
+ #
41
+ # require 'openwfe/expressions/raw_prog'
42
+ #
43
+
44
+ require 'openwfe/expressions/rprocdef'
45
+ require 'openwfe/expressions/raw'
46
+
@@ -0,0 +1,37 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2008, John Mettraux, Nicolas Modrzyk 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
+ # just for nicer looking examples
35
+
36
+ require 'openwfe/engine/engine'
37
+
@@ -0,0 +1,756 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2008, John Mettraux, Nicolas Modrzyk 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
+ # Nicolas Modrzyk at openwfe.org
39
+ #
40
+
41
+ require 'logger'
42
+ require 'fileutils'
43
+
44
+ require 'rufus/scheduler' # gem 'rufus-scheduler'
45
+
46
+ require 'openwfe/omixins'
47
+ require 'openwfe/rudefinitions'
48
+ require 'openwfe/service'
49
+ require 'openwfe/workitem'
50
+ require 'openwfe/util/irb'
51
+ require 'openwfe/util/workqueue'
52
+ require 'openwfe/expool/wfidgen'
53
+ require 'openwfe/expool/expressionpool'
54
+ require 'openwfe/expool/expstorage'
55
+ require 'openwfe/expool/errorjournal'
56
+ require 'openwfe/engine/expool_methods'
57
+ require 'openwfe/engine/status_methods'
58
+ require 'openwfe/engine/participant_methods'
59
+ require 'openwfe/engine/update_exp_methods'
60
+ require 'openwfe/expressions/environment'
61
+ require 'openwfe/expressions/expressionmap'
62
+ require 'openwfe/participants/participantmap'
63
+
64
+
65
+ module OpenWFE
66
+
67
+ #
68
+ # The simplest implementation of the OpenWFE workflow engine.
69
+ # No persistence is used, everything is stored in memory.
70
+ #
71
+ class Engine < Service
72
+
73
+ include OwfeServiceLocator
74
+ include FeiMixin
75
+
76
+ include ExpoolMethods
77
+ include StatusMethods
78
+ include ParticipantMethods
79
+ include UpdateExpMethods
80
+
81
+
82
+ #
83
+ # The name of the engine, will be used to 'stamp' each expression
84
+ # active in the engine (and thus indirectrly, each workitem)
85
+ #
86
+ attr_reader :engine_name
87
+
88
+ #
89
+ # Builds an OpenWFEru engine.
90
+ #
91
+ # Accepts an optional initial application_context (containing
92
+ # initialization params for services for example).
93
+ #
94
+ # The engine itself uses one param :logger, used to define
95
+ # where all the log output for OpenWFEru should go.
96
+ # By default, this output goes to logs/openwferu.log
97
+ #
98
+ def initialize (application_context={})
99
+
100
+ super S_ENGINE, application_context
101
+
102
+ @engine_name = application_context[:engine_name] || 'engine'
103
+
104
+ $OWFE_LOG = application_context[:logger]
105
+
106
+ unless $OWFE_LOG
107
+ #puts "Creating logs in " + FileUtils.pwd
108
+ FileUtils.mkdir("logs") unless File.exist?("logs")
109
+ $OWFE_LOG = Logger.new "logs/openwferu.log", 10, 1024000
110
+ $OWFE_LOG.level = Logger::INFO
111
+ end
112
+
113
+ # build order matters.
114
+ #
115
+ # especially for the expstorage which 'observes' the expression
116
+ # pool and thus needs to be instantiated after it.
117
+
118
+ build_scheduler
119
+ #
120
+ # for delayed or repetitive executions (it's the engine's clock)
121
+ # see http://openwferu.rubyforge.org/scheduler.html
122
+
123
+ build_expression_map
124
+ #
125
+ # mapping expression names ('sequence', 'if', 'concurrence',
126
+ # 'when'...) to their implementations (SequenceExpression,
127
+ # IfExpression, ConcurrenceExpression, ...)
128
+
129
+ build_wfid_generator
130
+ #
131
+ # the workflow instance (process instance) id generator
132
+ # making sure each process instance has a unique identifier
133
+
134
+ build_workqueue
135
+ #
136
+ # where apply/reply get queued and processed asynchronously
137
+ # by a single thread
138
+
139
+ build_expression_pool
140
+ #
141
+ # the core (hairy ball) of the engine
142
+
143
+ build_expression_storage
144
+ #
145
+ # the engine persistence (persisting the expression instances
146
+ # that make up process instances)
147
+
148
+ build_participant_map
149
+ #
150
+ # building the services that maps participant names to
151
+ # participant implementations / instances.
152
+
153
+ build_error_journal
154
+ #
155
+ # builds the error journal (keeping track of failures
156
+ # in business process executions, and an opportunity to
157
+ # fix and replay)
158
+
159
+ linfo { "new() --- engine started --- #{self.object_id}" }
160
+ end
161
+
162
+ #
163
+ # Call this method once the participants for a persisted engine
164
+ # have been [re]added.
165
+ #
166
+ # If this method is called too soon, missing participants will
167
+ # cause trouble... Call this method after all the participants
168
+ # have been added.
169
+ #
170
+ def reschedule
171
+
172
+ get_expression_pool.reschedule()
173
+ end
174
+
175
+ alias :reload :reschedule
176
+
177
+ #
178
+ # When 'parameters' are used at the top of a process definition, this
179
+ # method can be used to assert a launchitem before launch.
180
+ # An expression will be raised if the parameters do not match the
181
+ # requirements.
182
+ #
183
+ # Note that the launch method will raise those exceptions as well.
184
+ # This method can be useful in some scenarii though.
185
+ #
186
+ def pre_launch_check (launchitem)
187
+
188
+ get_expression_pool.prepare_raw_expression(launchitem)
189
+ end
190
+
191
+ #
192
+ # Launches a [business] process.
193
+ # The 'launch_object' param may contain either a LaunchItem instance,
194
+ # either a String containing the URL of the process definition
195
+ # to launch (with an empty LaunchItem created on the fly).
196
+ #
197
+ # The launch object can also be a String containing the XML process
198
+ # definition or directly a class extending OpenWFE::ProcessDefinition
199
+ # (Ruby process definition).
200
+ #
201
+ # Returns the FlowExpressionId instance of the expression at the
202
+ # root of the newly launched process.
203
+ #
204
+ # Options for scheduled launches like :at, :in and :cron are accepted
205
+ # via the 'options' optional parameter.
206
+ # For example :
207
+ #
208
+ # engine.launch(launch_item)
209
+ # # will launch immediately
210
+ #
211
+ # engine.launch(launch_item, :in => "1d20m")
212
+ # # will launch in one day and twenty minutes
213
+ #
214
+ # engine.launch(launch_item, :at => "Tue Sep 11 20:23:02 +0900 2007")
215
+ # # will launch at that point in time
216
+ #
217
+ # engine.launch(launch_item, :cron => "0 5 * * *")
218
+ # # will launch that same process every day,
219
+ # # five minutes after midnight (see "man 5 crontab")
220
+ #
221
+ def launch (launch_object, options={})
222
+
223
+ launchitem = extract_launchitem launch_object
224
+
225
+ fei = get_expression_pool.launch launchitem, options
226
+
227
+ #linfo { "launch() #{fei.wfid} : #{fei.wfname} #{fei.wfrevision}" }
228
+
229
+ fei.dup
230
+ #
231
+ # so that users of this launch() method can play with their
232
+ # fei without breaking things
233
+ end
234
+
235
+ #
236
+ # This method is used to feed a workitem back to the engine (after
237
+ # it got sent to a worklist or wherever by a participant).
238
+ # Participant implementations themselves do call this method usually.
239
+ #
240
+ # This method also accepts LaunchItem instances.
241
+ #
242
+ # Since OpenWFEru 0.9.16, this reply method accepts InFlowWorkitem
243
+ # that don't belong to a process instance (ie whose flow_expression_id
244
+ # is nil). It will simply notify the participant_map of the reply
245
+ # for the given participant_name. If there is no participant_name
246
+ # specified for this orphan workitem, an exception will be raised.
247
+ #
248
+ def reply (workitem)
249
+
250
+ if workitem.is_a?(InFlowWorkItem)
251
+
252
+ if workitem.flow_expression_id
253
+ #
254
+ # vanilla case, workitem coming back
255
+ # (from listener probably)
256
+
257
+ return get_expression_pool.reply(
258
+ workitem.flow_expression_id, workitem)
259
+ end
260
+
261
+ if workitem.participant_name
262
+ #
263
+ # a workitem that doesn't belong to a process instance
264
+ # but bears a participant name.
265
+ # Notify, there may be something listening on
266
+ # this channel (see the 'listen' expression).
267
+
268
+ return get_participant_map.onotify(
269
+ workitem.participant_name, :reply, workitem)
270
+ end
271
+
272
+ raise \
273
+ "InFlowWorkitem doesn't belong to a process instance" +
274
+ " nor to a participant"
275
+ end
276
+
277
+ return get_expression_pool.launch(workitem) \
278
+ if workitem.is_a?(LaunchItem)
279
+ #
280
+ # launchitem coming from listener
281
+ # let's attempt to launch a new process instance
282
+
283
+ raise \
284
+ "engine.reply() " +
285
+ "cannot handle instances of #{workitem.class}"
286
+ end
287
+
288
+ alias :forward :reply
289
+ alias :proceed :reply
290
+
291
+ #
292
+ # Adds a workitem listener to this engine.
293
+ #
294
+ # The 'freq' parameters if present might indicate how frequently
295
+ # the resource should be polled for incoming workitems.
296
+ #
297
+ # engine.add_workitem_listener(listener, "3m10s")
298
+ # # every 3 minutes and 10 seconds
299
+ #
300
+ # engine.add_workitem_listener(listener, "0 22 * * 1-5")
301
+ # # every weekday at 10pm
302
+ #
303
+ # TODO : block handling...
304
+ #
305
+ def add_workitem_listener (listener, freq=nil)
306
+
307
+ name = nil
308
+
309
+ if listener.kind_of? Class
310
+
311
+ listener = init_service nil, listener
312
+
313
+ name = listener.service_name
314
+ else
315
+
316
+ name = listener.name if listener.respond_to? :name
317
+ name = "#{listener.class}::#{listener.object_id}" unless name
318
+
319
+ @application_context[name] = listener
320
+ end
321
+
322
+ result = nil
323
+
324
+ if freq
325
+
326
+ freq = freq.to_s.strip
327
+
328
+ result = if Rufus::Scheduler.is_cron_string(freq)
329
+
330
+ get_scheduler.schedule(freq, listener)
331
+ else
332
+
333
+ get_scheduler.schedule_every(freq, listener)
334
+ end
335
+ end
336
+
337
+ linfo { "add_workitem_listener() added '#{name}'" }
338
+
339
+ result
340
+ end
341
+
342
+ #
343
+ # Makes the current thread join the engine's scheduler thread
344
+ #
345
+ # You can thus make an engine standalone with something like :
346
+ #
347
+ # require 'openwfe/engine/engine'
348
+ #
349
+ # the_engine = OpenWFE::Engine.new
350
+ # the_engine.join
351
+ #
352
+ # And you'll have to hit CTRL-C to make it stop.
353
+ #
354
+ def join
355
+
356
+ get_scheduler.join
357
+ end
358
+
359
+ #
360
+ # Calling this method makes the control flow block until the
361
+ # workflow engine is inactive.
362
+ #
363
+ # TODO : implement idle_for
364
+ #
365
+ def join_until_idle
366
+
367
+ storage = get_expression_storage
368
+
369
+ while storage.size > 1
370
+ sleep 1
371
+ end
372
+ end
373
+
374
+ #
375
+ # Enabling the console means that hitting CTRL-C on the window /
376
+ # term / dos box / whatever does run the OpenWFEru engine will
377
+ # open an IRB interactive console for directly manipulating the
378
+ # engine instance.
379
+ #
380
+ # Hit CTRL-D to get out of the console.
381
+ #
382
+ def enable_irb_console
383
+
384
+ OpenWFE::trap_int_irb(binding)
385
+ end
386
+
387
+ #--
388
+ # Makes sure that hitting CTRL-C will actually kill the engine VM and
389
+ # not open an IRB console.
390
+ #
391
+ #def disable_irb_console
392
+ # $openwfe_irb = nil
393
+ # trap 'INT' do
394
+ # exit 0
395
+ # end
396
+ #end
397
+ #++
398
+
399
+ #
400
+ # Stopping the engine will stop all the services in the
401
+ # application context.
402
+ #
403
+ def stop
404
+
405
+ linfo { "stop() stopping engine '#{@service_name}'" }
406
+
407
+ @application_context.each do |sname, service|
408
+
409
+ next if sname == self.service_name
410
+
411
+ #if service.kind_of?(ServiceMixin)
412
+ if service.respond_to?(:stop)
413
+
414
+ service.stop
415
+
416
+ linfo do
417
+ "stop() stopped service '#{sname}' (#{service.class})"
418
+ end
419
+ end
420
+ end
421
+
422
+ linfo { "stop() stopped engine '#{@service_name}'" }
423
+
424
+ nil
425
+ end
426
+
427
+ #
428
+ # Waits for a given process instance to terminate.
429
+ # The method only exits when the flow terminates, but beware : if
430
+ # the process already terminated, the method will never exit.
431
+ #
432
+ # The parameter can be a FlowExpressionId instance, for example the
433
+ # one given back by a launch(), or directly a workflow instance id
434
+ # (String).
435
+ #
436
+ # This method is mainly used in utests.
437
+ #
438
+ def wait_for (fei_or_wfid)
439
+
440
+ wfid = if fei_or_wfid.kind_of?(FlowExpressionId)
441
+ fei_or_wfid.workflow_instance_id
442
+ else
443
+ fei_or_wfid
444
+ end
445
+
446
+ t = Thread.new { Thread.stop }
447
+
448
+ to = get_expression_pool.add_observer(:terminate) do |c, fe, wi|
449
+ t.wakeup if (fe.fei.workflow_instance_id == wfid and t.alive?)
450
+ end
451
+ te = get_expression_pool.add_observer(:error) do |c, fei, m, i, e|
452
+ t.wakeup if (fei.parent_wfid == wfid and t.alive?)
453
+ end
454
+
455
+ t.join
456
+
457
+ #tc = get_expression_pool.add_observer(:cancel) do |c, fe|
458
+ # if (fe.fei.wfid == wfid and fe.fei.expid == "0" and t.alive?)
459
+ # sleep 0.500
460
+ # t.wakeup
461
+ # end
462
+ #end
463
+
464
+ linfo { "wait_for() #{wfid}" }
465
+
466
+ get_expression_pool.remove_observer to, :terminate
467
+ get_expression_pool.remove_observer te, :error
468
+ #get_expression_pool.remove_observer tc, :cancel
469
+ #
470
+ # it would work as well without specifying the channel,
471
+ # but it's thus a little bit faster
472
+ end
473
+
474
+ #
475
+ # Pauses a process (sets its /__paused__ variable to true).
476
+ #
477
+ def pause_process (wfid)
478
+
479
+ wfid = extract_wfid wfid
480
+
481
+ root_expression = get_expression_pool.fetch_root wfid
482
+
483
+ get_expression_pool.paused_instances[wfid] = true
484
+ root_expression.set_variable VAR_PAUSED, true
485
+ end
486
+
487
+ #
488
+ # Restarts a process : removes its 'paused' flag (variable) and makes
489
+ # sure to 'replay' events (replies) that came for it while it was
490
+ # in pause.
491
+ #
492
+ def resume_process (wfid)
493
+
494
+ wfid = extract_wfid wfid
495
+
496
+ root_expression = get_expression_pool.fetch_root wfid
497
+
498
+ #
499
+ # remove 'paused' flag
500
+
501
+ get_expression_pool.paused_instances.delete wfid
502
+ root_expression.unset_variable VAR_PAUSED
503
+
504
+ #
505
+ # replay
506
+ #
507
+ # select PausedError instances in separate list
508
+
509
+ errors = get_error_journal.get_error_log wfid
510
+ error_class = PausedError.name
511
+ paused_errors = errors.select { |e| e.error_class == error_class }
512
+
513
+ return if paused_errors.size < 1
514
+
515
+ # replay select PausedError instances
516
+
517
+ paused_errors.each do |e|
518
+ replay_at_error e
519
+ end
520
+ end
521
+
522
+ #
523
+ # Takes care of removing an error from the error journal and
524
+ # they replays its process at that point.
525
+ #
526
+ def replay_at_error (error)
527
+
528
+ get_error_journal.remove_errors(
529
+ error.fei.parent_wfid,
530
+ error)
531
+
532
+ get_workqueue.push(
533
+ get_expression_pool,
534
+ :do_apply_reply,
535
+ error.message,
536
+ error.fei,
537
+ error.workitem)
538
+ end
539
+
540
+ #
541
+ # Looks up a process variable in a process.
542
+ # If fei_or_wfid is not given, will simply look in the
543
+ # 'engine environment' (where the top level variables '//' do reside).
544
+ #
545
+ def lookup_variable (var_name, fei_or_wfid=nil)
546
+
547
+ return get_expression_pool.fetch_engine_environment[var_name] \
548
+ unless fei_or_wfid
549
+
550
+ fetch_exp(fei_or_wfid).lookup_variable var_name
551
+ end
552
+
553
+ #
554
+ # Returns the variables set for a process or an expression.
555
+ #
556
+ # If a process (wfid) is given, variables of the process environment
557
+ # will be returned, else variables in the environment valid for the
558
+ # expression (fei) will be returned.
559
+ #
560
+ # If nothing (or nil) is given, the variables set in the engine
561
+ # environment will be returned.
562
+ #
563
+ def get_variables (fei_or_wfid=nil)
564
+
565
+ return get_expression_pool.fetch_engine_environment.variables \
566
+ unless fei_or_wfid
567
+
568
+ fetch_exp(fei_or_wfid).get_environment.variables
569
+ end
570
+
571
+ #
572
+ # Returns an array of wfid (workflow instance ids) whose root
573
+ # environment containes the given variable
574
+ #
575
+ # If there are no matches, an empty array will be returned.
576
+ #
577
+ # Regular expressions are accepted as values.
578
+ #
579
+ # If no value is given, all processes with the given variable name
580
+ # set will be returned.
581
+ #
582
+ def lookup_processes (var_name, value=nil)
583
+
584
+ # TODO : maybe this would be better in the ExpressionPool
585
+
586
+ regexp = if value
587
+ if value.is_a?(Regexp)
588
+ value
589
+ else
590
+ Regexp.compile(value.to_s)
591
+ end
592
+ else
593
+ nil
594
+ end
595
+
596
+ envs = get_expression_storage.find_expressions(
597
+ :include_classes => Environment)
598
+
599
+ envs = envs.find_all do |env|
600
+ val = env.variables[var_name]
601
+ (val and ((not regexp) or (regexp.match(val))))
602
+ end
603
+ envs.collect do |env|
604
+ env.fei.wfid
605
+ end
606
+
607
+ #envs.inject([]) do |r, env|
608
+ # val = env.variables[var_name]
609
+ # r << env.fei.wfid \
610
+ # if (val and ((not regexp) or (regexp.match(val))))
611
+ # r
612
+ #end
613
+ #
614
+ # seems slower...
615
+ end
616
+
617
+ protected
618
+
619
+ #--
620
+ # the following methods may get overridden upon extension
621
+ # see for example file_persisted_engine.rb
622
+ #++
623
+
624
+ #
625
+ # Builds the ExpressionMap (the mapping between expression names
626
+ # and expression implementations).
627
+ #
628
+ def build_expression_map
629
+
630
+ @application_context[S_EXPRESSION_MAP] = ExpressionMap.new
631
+ #
632
+ # the expression map is not a Service anymore,
633
+ # it's a simple instance (that will be reused in other
634
+ # OpenWFEru components)
635
+ end
636
+
637
+ #
638
+ # This implementation builds a KotobaWfidGenerator instance and
639
+ # binds it in the engine context.
640
+ # There are other WfidGeneration implementations available, like
641
+ # UuidWfidGenerator or FieldWfidGenerator.
642
+ #
643
+ def build_wfid_generator
644
+
645
+ #init_service S_WFID_GENERATOR, DefaultWfidGenerator
646
+ #init_service S_WFID_GENERATOR, UuidWfidGenerator
647
+ init_service S_WFID_GENERATOR, KotobaWfidGenerator
648
+
649
+ #g = FieldWfidGenerator.new(
650
+ # S_WFID_GENERATOR, @application_context, "wfid")
651
+ #
652
+ # showing how to initialize a FieldWfidGenerator that
653
+ # will take as workflow instance id the value found in
654
+ # the field "wfid" of the LaunchItem.
655
+ end
656
+
657
+ #
658
+ # Builds the workqueue where apply/reply work is queued
659
+ # and processed.
660
+ #
661
+ def build_workqueue
662
+
663
+ init_service S_WORKQUEUE, WorkQueue
664
+ end
665
+
666
+ #
667
+ # Builds the OpenWFEru expression pool (the core of the engine)
668
+ # and binds it in the engine context.
669
+ # There is only one implementation of the expression pool, so
670
+ # this method is usually never overriden.
671
+ #
672
+ def build_expression_pool
673
+
674
+ init_service S_EXPRESSION_POOL, ExpressionPool
675
+ end
676
+
677
+ #
678
+ # The implementation here builds an InMemoryExpressionStorage
679
+ # instance.
680
+ #
681
+ # See FilePersistedEngine or CachedFilePersistedEngine for
682
+ # overrides of this method.
683
+ #
684
+ def build_expression_storage
685
+
686
+ init_service S_EXPRESSION_STORAGE, InMemoryExpressionStorage
687
+ end
688
+
689
+ #
690
+ # The ParticipantMap is a mapping between participant names
691
+ # (well rather regular expressions) and participant implementations
692
+ # (see http://openwferu.rubyforge.org/participants.html)
693
+ #
694
+ def build_participant_map
695
+
696
+ init_service S_PARTICIPANT_MAP, ParticipantMap
697
+ end
698
+
699
+ #
700
+ # There is only one Scheduler implementation, that's the one
701
+ # built and bound here.
702
+ #
703
+ def build_scheduler
704
+
705
+ s = Rufus::Scheduler.new(
706
+ :thread_name =>
707
+ "rufus scheduler for Ruote (engine #{self.object_id})")
708
+
709
+ @application_context[S_SCHEDULER] = s
710
+
711
+ s.start
712
+ end
713
+
714
+ #
715
+ # The default implementation of this method uses an
716
+ # InMemoryErrorJournal (do not use in production).
717
+ #
718
+ def build_error_journal
719
+
720
+ init_service S_ERROR_JOURNAL, InMemoryErrorJournal
721
+ end
722
+
723
+ #
724
+ # Turns the raw launch request info into a LaunchItem instance.
725
+ #
726
+ def extract_launchitem (launch_object)
727
+
728
+ if launch_object.kind_of?(OpenWFE::LaunchItem)
729
+
730
+ launch_object
731
+
732
+ elsif launch_object.kind_of?(Class)
733
+
734
+ LaunchItem.new launch_object
735
+
736
+ elsif launch_object.kind_of?(String)
737
+
738
+ li = OpenWFE::LaunchItem.new
739
+
740
+ if launch_object[0, 1] == '<' or launch_object.index("\n")
741
+
742
+ li.workflow_definition_url = "field:__definition"
743
+ li['__definition'] = launch_object
744
+
745
+ else
746
+
747
+ li.workflow_definition_url = launch_object
748
+ end
749
+
750
+ li
751
+ end
752
+ end
753
+ end
754
+
755
+ end
756
+