ruote 0.9.18

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