ruote 0.9.18 → 0.9.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (323) hide show
  1. data/README.txt +2 -0
  2. data/examples/about_state.rb +29 -29
  3. data/examples/bigflow.rb +9 -9
  4. data/examples/csv_weather.rb +4 -4
  5. data/examples/engine_template.rb +141 -129
  6. data/examples/flowtracing.rb +8 -8
  7. data/examples/homeworkreview.rb +15 -15
  8. data/examples/kotoba.rb +9 -9
  9. data/examples/mano_tracker.rb +63 -63
  10. data/examples/openwferu.rb +22 -20
  11. data/examples/quotereporter.rb +79 -79
  12. data/lib/openwfe/contextual.rb +72 -72
  13. data/lib/openwfe/def.rb +21 -21
  14. data/lib/openwfe/engine.rb +19 -19
  15. data/lib/openwfe/engine/engine.rb +578 -614
  16. data/lib/openwfe/engine/expool_methods.rb +144 -115
  17. data/lib/openwfe/engine/file_persisted_engine.rb +77 -77
  18. data/lib/openwfe/engine/participant_methods.rb +96 -96
  19. data/lib/openwfe/engine/status_methods.rb +271 -247
  20. data/lib/openwfe/engine/update_exp_methods.rb +69 -69
  21. data/lib/openwfe/exceptions.rb +25 -25
  22. data/lib/openwfe/expool/errorjournal.rb +334 -348
  23. data/lib/openwfe/expool/expool_pause_methods.rb +98 -0
  24. data/lib/openwfe/expool/expressionpool.rb +793 -800
  25. data/lib/openwfe/expool/expstorage.rb +284 -313
  26. data/lib/openwfe/expool/history.rb +193 -105
  27. data/lib/openwfe/expool/journal.rb +163 -163
  28. data/lib/openwfe/expool/journal_replay.rb +228 -228
  29. data/lib/openwfe/expool/parser.rb +178 -142
  30. data/lib/openwfe/{orest/exception.rb → expool/paused_error.rb} +49 -32
  31. data/lib/openwfe/expool/representation.rb +59 -59
  32. data/lib/openwfe/expool/threadedexpstorage.rb +137 -134
  33. data/lib/openwfe/expool/wfidgen.rb +289 -287
  34. data/lib/openwfe/expool/yamlexpstorage.rb +154 -154
  35. data/lib/openwfe/expressions/condition.rb +175 -168
  36. data/lib/openwfe/expressions/environment.rb +165 -165
  37. data/lib/openwfe/expressions/expressionmap.rb +135 -131
  38. data/lib/openwfe/expressions/fe_cancel.rb +68 -68
  39. data/lib/openwfe/expressions/fe_command.rb +190 -190
  40. data/lib/openwfe/expressions/fe_concurrence.rb +531 -531
  41. data/lib/openwfe/expressions/fe_cron.rb +152 -197
  42. data/lib/openwfe/expressions/fe_cursor.rb +152 -186
  43. data/lib/openwfe/expressions/fe_define.rb +118 -118
  44. data/lib/openwfe/expressions/fe_do.rb +109 -109
  45. data/lib/openwfe/expressions/fe_equals.rb +219 -219
  46. data/lib/openwfe/expressions/fe_filter.rb +98 -98
  47. data/lib/openwfe/expressions/fe_filter_definition.rb +122 -122
  48. data/lib/openwfe/expressions/fe_fqv.rb +203 -203
  49. data/lib/openwfe/expressions/fe_http.rb +212 -0
  50. data/lib/openwfe/expressions/fe_if.rb +214 -214
  51. data/lib/openwfe/expressions/fe_iterator.rb +91 -91
  52. data/lib/openwfe/expressions/fe_listen.rb +268 -268
  53. data/lib/openwfe/expressions/fe_losfor.rb +73 -73
  54. data/lib/openwfe/expressions/fe_misc.rb +343 -351
  55. data/lib/openwfe/expressions/fe_participant.rb +206 -206
  56. data/lib/openwfe/expressions/fe_reserve.rb +153 -142
  57. data/lib/openwfe/expressions/fe_save.rb +226 -226
  58. data/lib/openwfe/expressions/fe_sequence.rb +66 -56
  59. data/lib/openwfe/expressions/fe_set.rb +80 -80
  60. data/lib/openwfe/expressions/fe_sleep.rb +132 -125
  61. data/lib/openwfe/expressions/fe_step.rb +113 -111
  62. data/lib/openwfe/expressions/fe_subprocess.rb +139 -136
  63. data/lib/openwfe/expressions/fe_timeout.rb +74 -78
  64. data/lib/openwfe/expressions/fe_wait.rb +48 -49
  65. data/lib/openwfe/expressions/fe_when.rb +106 -106
  66. data/lib/openwfe/expressions/filter.rb +60 -60
  67. data/lib/openwfe/expressions/flowexpression.rb +618 -612
  68. data/lib/openwfe/expressions/iterator.rb +158 -158
  69. data/lib/openwfe/expressions/merge.rb +53 -53
  70. data/lib/openwfe/expressions/raw.rb +396 -397
  71. data/lib/openwfe/expressions/rprocdef.rb +261 -266
  72. data/lib/openwfe/expressions/time.rb +238 -243
  73. data/lib/openwfe/expressions/timeout.rb +135 -135
  74. data/lib/openwfe/expressions/value.rb +55 -55
  75. data/lib/openwfe/extras/engine/db_persisted_engine.rb +94 -0
  76. data/lib/openwfe/extras/expool/dberrorjournal.rb +189 -0
  77. data/lib/openwfe/extras/expool/dbexpstorage.rb +355 -0
  78. data/lib/openwfe/extras/expool/dbhistory.rb +135 -0
  79. data/lib/openwfe/extras/listeners/sqslisteners.rb +146 -0
  80. data/lib/openwfe/extras/misc/activityfeed.rb +264 -0
  81. data/lib/openwfe/extras/misc/basecamp.rb +485 -0
  82. data/lib/openwfe/extras/participants/activeparticipants.rb +749 -0
  83. data/lib/openwfe/extras/participants/atomfeed_participants.rb +173 -0
  84. data/lib/openwfe/extras/participants/atompub_participants.rb +267 -0
  85. data/lib/openwfe/extras/participants/basecamp_participants.rb +87 -0
  86. data/lib/openwfe/extras/participants/csvparticipants.rb +127 -0
  87. data/lib/openwfe/extras/participants/sqsparticipants.rb +125 -0
  88. data/lib/openwfe/extras/participants/twitterparticipants.rb +176 -0
  89. data/lib/openwfe/filterdef.rb +191 -191
  90. data/lib/openwfe/flowexpressionid.rb +271 -269
  91. data/lib/openwfe/listeners/listener.rb +61 -61
  92. data/lib/openwfe/listeners/listeners.rb +81 -81
  93. data/lib/openwfe/listeners/socketlisteners.rb +189 -189
  94. data/lib/openwfe/logging.rb +74 -74
  95. data/lib/openwfe/omixins.rb +55 -54
  96. data/lib/openwfe/orest/definitions.rb +90 -90
  97. data/lib/openwfe/orest/osocket.rb +91 -91
  98. data/lib/openwfe/orest/xmlcodec.rb +471 -459
  99. data/lib/openwfe/participants.rb +19 -19
  100. data/lib/openwfe/participants/enoparticipants.rb +187 -187
  101. data/lib/openwfe/participants/participant.rb +100 -100
  102. data/lib/openwfe/participants/participantmap.rb +170 -170
  103. data/lib/openwfe/participants/participants.rb +316 -316
  104. data/lib/openwfe/participants/soapparticipants.rb +90 -90
  105. data/lib/openwfe/participants/socketparticipants.rb +143 -143
  106. data/lib/openwfe/participants/storeparticipants.rb +198 -198
  107. data/lib/openwfe/rexml.rb +44 -0
  108. data/lib/openwfe/rudefinitions.rb +87 -91
  109. data/lib/openwfe/service.rb +65 -65
  110. data/lib/openwfe/storage/yamlcustom.rb +71 -71
  111. data/lib/openwfe/storage/yamlfilestorage.rb +190 -190
  112. data/lib/openwfe/tools/flowtracer.rb +41 -45
  113. data/lib/openwfe/util/dollar.rb +125 -139
  114. data/lib/openwfe/util/irb.rb +42 -42
  115. data/lib/openwfe/util/observable.rb +93 -99
  116. data/lib/openwfe/util/ometa.rb +36 -36
  117. data/lib/openwfe/util/treechecker.rb +122 -0
  118. data/lib/openwfe/util/workqueue.rb +73 -73
  119. data/lib/openwfe/util/xml.rb +285 -279
  120. data/lib/openwfe/utils.rb +415 -442
  121. data/lib/openwfe/version.rb +1 -1
  122. data/lib/openwfe/workitem.rb +444 -437
  123. data/lib/openwfe/worklist/oldrest.rb +161 -161
  124. data/lib/openwfe/worklist/storelocks.rb +218 -218
  125. data/lib/openwfe/worklist/storeparticipant.rb +19 -19
  126. data/lib/openwfe/worklist/worklist.rb +223 -223
  127. data/test/back_0916_test.rb +57 -59
  128. data/test/bm/bm_1_xml_vs_prog.rb +25 -22
  129. data/test/bm/bm_2_step.rb +81 -81
  130. data/test/bm/ft_0f_5ms.rb +13 -13
  131. data/test/bm/ft_26_load.rb +177 -179
  132. data/test/bm/ft_26b_load.rb +57 -59
  133. data/test/bm/ft_26c_load.rb +70 -65
  134. data/test/bm/ft_recu.rb +51 -51
  135. data/test/clone_test.rb +145 -99
  136. data/test/concurrence_test.rb +41 -41
  137. data/test/condition_test.rb +104 -90
  138. data/test/description_test.rb +46 -45
  139. data/test/eno_test.rb +36 -36
  140. data/test/expmap_test.rb +26 -26
  141. data/test/extras/README.txt +5 -0
  142. data/test/extras/active_connection.rb +48 -0
  143. data/test/extras/active_with_engine_test.rb +140 -0
  144. data/test/extras/activityfeed_test.rb +85 -0
  145. data/test/extras/ap_0_test.rb +287 -0
  146. data/test/extras/ap_1_test.rb +53 -0
  147. data/test/extras/ap_test_base.rb +24 -0
  148. data/test/extras/atomfeedp_test.rb +113 -0
  149. data/test/extras/atompubp_test.rb +91 -0
  150. data/test/extras/basecamp_test.rb +53 -0
  151. data/test/extras/db_errorjournal_utest.rb +75 -0
  152. data/test/extras/db_expstorage_utest.rb +171 -0
  153. data/test/extras/db_history_0_test.rb +58 -0
  154. data/test/extras/ft_19_csv.rb +58 -0
  155. data/test/extras/ft_71_b14008.rb +85 -0
  156. data/test/extras/sqs_test.rb +57 -0
  157. data/test/extras/twitter_test.rb +62 -0
  158. data/test/fe_lookup_att_test.rb +41 -41
  159. data/test/fei_test.rb +131 -131
  160. data/test/file_persisted_engine_test.rb +30 -30
  161. data/test/file_persistence_test.rb +112 -111
  162. data/test/filep_cancel_test.rb +58 -58
  163. data/test/filter_test.rb +67 -67
  164. data/test/flowtestbase.rb +207 -219
  165. data/test/ft_0.rb +35 -35
  166. data/test/ft_0b_sequence.rb +15 -15
  167. data/test/ft_0c_testname.rb +12 -12
  168. data/test/ft_0d_participant.rb +9 -9
  169. data/test/ft_0e_multibody.rb +11 -11
  170. data/test/ft_10_loop.rb +103 -104
  171. data/test/ft_11_ppd.rb +285 -289
  172. data/test/ft_11b_ppd.rb +26 -26
  173. data/test/ft_12_blockparticipant.rb +57 -57
  174. data/test/ft_13_eno.rb +31 -31
  175. data/test/ft_14_subprocess.rb +45 -45
  176. data/test/ft_14b_subprocess.rb +107 -107
  177. data/test/ft_14c_subprocess.rb +33 -33
  178. data/test/ft_15_iterator.rb +127 -127
  179. data/test/ft_15b_iterator.rb +41 -41
  180. data/test/ft_16_fqv.rb +44 -44
  181. data/test/ft_17_condition.rb +48 -48
  182. data/test/ft_18_pname.rb +26 -26
  183. data/test/ft_1_unset.rb +140 -140
  184. data/test/ft_1b_unset.rb +17 -17
  185. data/test/ft_20_cron.rb +33 -33
  186. data/test/ft_21_cron.rb +51 -51
  187. data/test/ft_21b_cron_pause.rb +41 -41
  188. data/test/ft_22_history.rb +45 -41
  189. data/test/ft_23_when.rb +51 -51
  190. data/test/ft_23b_when.rb +43 -43
  191. data/test/ft_23c_wait.rb +48 -48
  192. data/test/ft_23d_cww.rb +28 -28
  193. data/test/ft_24_def.rb +15 -15
  194. data/test/ft_25_cancel.rb +57 -54
  195. data/test/ft_27_getflowpos.rb +79 -83
  196. data/test/ft_28_fileparticipant.rb +25 -25
  197. data/test/ft_29_httprb.rb +57 -57
  198. data/test/ft_2_concurrence.rb +99 -97
  199. data/test/ft_2b_concurrence.rb +132 -132
  200. data/test/ft_2c_concurrence.rb +37 -37
  201. data/test/ft_30_socketlistener.rb +133 -133
  202. data/test/ft_31_flowname.rb +15 -16
  203. data/test/ft_32_journal.rb +48 -48
  204. data/test/ft_32c_journal.rb +54 -54
  205. data/test/ft_32d_journal.rb +43 -46
  206. data/test/ft_33_description.rb +62 -62
  207. data/test/ft_34_cancelwfid.rb +37 -37
  208. data/test/ft_35_localdefs.rb +36 -34
  209. data/test/ft_36_subprocids.rb +61 -61
  210. data/test/ft_37_pnames.rb +33 -33
  211. data/test/ft_38_tag.rb +82 -82
  212. data/test/ft_38b_tag.rb +97 -97
  213. data/test/ft_38c_tag.rb +50 -50
  214. data/test/ft_38d_tag.rb +53 -0
  215. data/test/ft_39_reserve.rb +33 -33
  216. data/test/ft_39b_reserve.rb +59 -59
  217. data/test/ft_3_equals.rb +131 -131
  218. data/test/ft_3b_lookup_vf.rb +43 -43
  219. data/test/ft_40_defined.rb +33 -33
  220. data/test/ft_41_case.rb +80 -80
  221. data/test/ft_42_environments.rb +48 -48
  222. data/test/ft_43_pat10.rb +51 -51
  223. data/test/ft_44_save.rb +37 -37
  224. data/test/ft_44b_restore.rb +151 -151
  225. data/test/ft_45_citerator.rb +149 -149
  226. data/test/ft_45b_citerator.rb +77 -0
  227. data/test/ft_46_pparams.rb +27 -27
  228. data/test/ft_47_filter.rb +100 -100
  229. data/test/ft_48_fe_filter.rb +41 -41
  230. data/test/ft_49_condition.rb +101 -94
  231. data/test/ft_4_misc.rb +185 -190
  232. data/test/ft_50_xml_attribute.rb +101 -104
  233. data/test/ft_51_stack.rb +30 -30
  234. data/test/ft_52_obs_participant.rb +73 -73
  235. data/test/ft_53_null_noop_participant.rb +31 -31
  236. data/test/ft_54_listen.rb +183 -183
  237. data/test/ft_54b_listen.rb +32 -32
  238. data/test/ft_54c_listen.rb +60 -60
  239. data/test/ft_55_ptimeout.rb +29 -30
  240. data/test/ft_56_timeout.rb +29 -29
  241. data/test/ft_57_a.rb +105 -102
  242. data/test/ft_58_ejournal.rb +83 -80
  243. data/test/ft_58b_ejournal.rb +82 -0
  244. data/test/ft_59_ps.rb +148 -86
  245. data/test/ft_5_time.rb +77 -77
  246. data/test/ft_60_ecancel.rb +98 -98
  247. data/test/ft_61_elsub.rb +23 -23
  248. data/test/ft_62_procparticipant.rb +46 -46
  249. data/test/ft_63_pause.rb +82 -69
  250. data/test/ft_64_alias.rb +56 -57
  251. data/test/ft_65_stringlaunch.rb +29 -29
  252. data/test/ft_66_subforget.rb +42 -42
  253. data/test/ft_67_schedlaunch.rb +58 -59
  254. data/test/ft_68_ifparticipant.rb +39 -39
  255. data/test/ft_69_cancelmissing.rb +23 -21
  256. data/test/ft_6_lambda.rb +37 -37
  257. data/test/ft_70_lookupvar.rb +25 -25
  258. data/test/ft_71_log.rb +35 -35
  259. data/test/ft_72_lookup_processes.rb +43 -40
  260. data/test/ft_73_cancel_sub.rb +79 -79
  261. data/test/ft_74_block_and_workitem_dup.rb +42 -42
  262. data/test/ft_75_ruby_attributes.rb +53 -51
  263. data/test/ft_76_merge_isolate.rb +57 -57
  264. data/test/ft_77_segments.rb +13 -13
  265. data/test/ft_78_eval.rb +94 -94
  266. data/test/ft_79_tticket.rb +79 -79
  267. data/test/ft_79b_tticket.rb +73 -73
  268. data/test/ft_79c_outcome.rb +36 -36
  269. data/test/ft_7_lose.rb +73 -73
  270. data/test/ft_7b_lose.rb +49 -49
  271. data/test/ft_80_spname.rb +65 -65
  272. data/test/ft_81_exp.rb +30 -30
  273. data/test/ft_82_trecu.rb +30 -24
  274. data/test/ft_83_badpause.rb +35 -35
  275. data/test/ft_84_updateexp.rb +118 -118
  276. data/test/ft_84b_subrepr.rb +72 -0
  277. data/test/ft_85_dolhash.rb +18 -18
  278. data/test/ft_86_dollar_fv.rb +33 -33
  279. data/test/ft_87_define.rb +47 -47
  280. data/test/ft_88_http.rb +100 -0
  281. data/test/ft_8_forget.rb +25 -25
  282. data/test/ft_9_cursor.rb +119 -110
  283. data/test/ft_9b_cursor.rb +70 -70
  284. data/test/ft_tests.rb +6 -0
  285. data/test/hash_test.rb +52 -34
  286. data/test/hparticipant_test.rb +92 -88
  287. data/test/lookup_att_test.rb +70 -70
  288. data/test/lookup_vf_test.rb +52 -52
  289. data/test/misc_test.rb +55 -51
  290. data/test/obs_test.rb +82 -82
  291. data/test/param_test.rb +181 -181
  292. data/test/participant_test.rb +46 -46
  293. data/test/pending.rb +12 -12
  294. data/test/ps_representation.rb +70 -70
  295. data/test/rake_ltest.rb +2 -2
  296. data/test/rake_qtest.rb +11 -11
  297. data/test/raw_prog_test.rb +303 -308
  298. data/test/restart_cron_test.rb +74 -74
  299. data/test/restart_paused_test.rb +52 -47
  300. data/test/restart_sleep_test.rb +80 -80
  301. data/test/restart_when_test.rb +64 -64
  302. data/test/ruby_procdef_test.rb +71 -71
  303. data/test/rutest_utils.rb +32 -32
  304. data/test/sec_test.rb +143 -142
  305. data/test/slock_test.rb +41 -41
  306. data/test/storage_test.rb +15 -15
  307. data/test/timeout_test.rb +53 -53
  308. data/test/treechecker_test.rb +111 -0
  309. data/test/util_xml_test.rb +57 -57
  310. data/test/wfid_test.rb +93 -93
  311. data/test/wi_test.rb +58 -58
  312. metadata +64 -19
  313. data/examples/scheduler_cron_usage.rb +0 -48
  314. data/examples/scheduler_usage.rb +0 -56
  315. data/lib/openwfe/orest/controlclient.rb +0 -119
  316. data/lib/openwfe/orest/oldrestservlet.rb +0 -279
  317. data/lib/openwfe/orest/restclient.rb +0 -176
  318. data/lib/openwfe/orest/workitem.rb +0 -206
  319. data/lib/openwfe/orest/worklistclient.rb +0 -272
  320. data/test/bm/ft_26d_load.rb +0 -97
  321. data/test/ft_59b_ps_for_pat.rb +0 -58
  322. data/test/ft_64_clone.rb +0 -69
  323. data/test/orest_test.rb +0 -251
@@ -0,0 +1,749 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2007-2008, John Mettraux, Tomaso Tosolini 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
+ # Tomaso Tosolini
39
+ #
40
+
41
+ #require 'rubygems'
42
+
43
+ #require_gem 'activerecord'
44
+ gem 'activerecord'; require 'active_record'
45
+
46
+
47
+ require 'openwfe/workitem'
48
+ require 'openwfe/flowexpressionid'
49
+ require 'openwfe/engine/engine'
50
+ require 'openwfe/participants/participant'
51
+
52
+
53
+ module OpenWFE
54
+ module Extras
55
+
56
+ #MUTEX = Mutex.new
57
+
58
+ #
59
+ # The migration for ActiveParticipant and associated classes.
60
+ #
61
+ # There are two tables 'workitems' and 'fields'. As its name implies,
62
+ # the latter table stores the fields (also called attributes in OpenWFE
63
+ # speak) of the workitems.
64
+ #
65
+ # See Workitem and Field for more details.
66
+ #
67
+ # For centralization purposes, the migration and the model are located
68
+ # in the same source file. It should be quite easy for the Rails hackers
69
+ # among you to sort that out for a Rails based usage.
70
+ #
71
+ class WorkitemTables < ActiveRecord::Migration
72
+
73
+ def self.up
74
+
75
+ create_table :workitems do |t|
76
+ t.column :fei, :string
77
+ t.column :wfid, :string
78
+ t.column :wf_name, :string
79
+ t.column :wf_revision, :string
80
+ t.column :participant_name, :string
81
+ t.column :store_name, :string
82
+ t.column :dispatch_time, :timestamp
83
+ t.column :last_modified, :timestamp
84
+
85
+ t.column :yattributes, :text
86
+ # when using compact_workitems, attributes are stored here
87
+ end
88
+ add_index :workitems, :fei, :unique => true
89
+ # with sqlite3, comment out this :unique => true on :fei :(
90
+ add_index :workitems, :wfid
91
+ add_index :workitems, :wf_name
92
+ add_index :workitems, :wf_revision
93
+ add_index :workitems, :participant_name
94
+ add_index :workitems, :store_name
95
+
96
+ create_table :fields do |t|
97
+ t.column :fkey, :string, :null => false
98
+ t.column :vclass, :string, :null => false
99
+ t.column :svalue, :string
100
+ t.column :yvalue, :text
101
+ t.column :workitem_id, :integer, :null => false
102
+ end
103
+ add_index :fields, [ :workitem_id, :fkey ], :unique => true
104
+ add_index :fields, :fkey
105
+ add_index :fields, :vclass
106
+ add_index :fields, :svalue
107
+ end
108
+
109
+ def self.down
110
+
111
+ drop_table :workitems
112
+ drop_table :fields
113
+ end
114
+ end
115
+
116
+ #
117
+ # Reopening InFlowWorkItem to add a 'db_id' attribute.
118
+ #
119
+ class OpenWFE::InFlowWorkItem
120
+
121
+ attr_accessor :db_id
122
+ end
123
+
124
+ #
125
+ # The ActiveRecord version of an OpenWFEru workitem (InFlowWorkItem).
126
+ #
127
+ # One can very easily build a worklist based on a participant name via :
128
+ #
129
+ # wl = OpenWFE::Extras::Workitem.find_all_by_participant_name("toto")
130
+ # puts "found #{wl.size} workitems for participant 'toto'"
131
+ #
132
+ # These workitems are not OpenWFEru workitems directly. But the conversion
133
+ # is pretty easy.
134
+ # Note that you probaly won't need to do the conversion by yourself,
135
+ # except for certain advanced scenarii.
136
+ #
137
+ # awi = OpenWFE::Extras::Workitem.find_by_participant_name("toto")
138
+ # #
139
+ # # returns the first workitem in the database whose participant
140
+ # # name is 'toto'.
141
+ #
142
+ # owi = awi.as_owfe_workitem
143
+ # #
144
+ # # Now we have a copy of the reference as a OpenWFEru
145
+ # # InFlowWorkItem instance.
146
+ #
147
+ # awi = OpenWFE::Extras::Workitem.from_owfe_workitem(owi)
148
+ # #
149
+ # # turns an OpenWFEru InFlowWorkItem instance into an
150
+ # # 'active workitem'.
151
+ #
152
+ class Workitem < ActiveRecord::Base
153
+
154
+ has_many :fields, :dependent => :destroy
155
+
156
+ serialize :yattributes
157
+
158
+
159
+ #
160
+ # Returns the flow expression id of this work (its unique OpenWFEru
161
+ # identifier) as a FlowExpressionId instance.
162
+ # (within the Workitem it's just stored as a String).
163
+ #
164
+ def full_fei
165
+
166
+ OpenWFE::FlowExpressionId.from_s(fei)
167
+ end
168
+
169
+ #
170
+ # Making sure last_modified is set to Time.now before each save.
171
+ #
172
+ def before_save
173
+
174
+ touch
175
+ end
176
+
177
+ #
178
+ # Generates a (new) Workitem from an OpenWFEru InFlowWorkItem instance.
179
+ #
180
+ # This is a 'static' method :
181
+ #
182
+ # awi = OpenWFE::Extras::Workitem.from_owfe_workitem(wi)
183
+ #
184
+ # (This method saves the 'ActiveWorkitem').
185
+ #
186
+ def Workitem.from_owfe_workitem (wi, store_name=nil)
187
+
188
+ i = Workitem.new
189
+ i.fei = wi.fei.to_s
190
+ i.wfid = wi.fei.wfid
191
+ i.wf_name = wi.fei.workflow_definition_name
192
+ i.wf_revision = wi.fei.workflow_definition_revision
193
+ i.participant_name = wi.participant_name
194
+ i.dispatch_time = wi.dispatch_time
195
+ i.last_modified = nil
196
+
197
+ i.store_name = store_name
198
+
199
+ i.save!
200
+ # save workitem before adding any field
201
+ # making sure it has an id...
202
+
203
+ i = Workitem.find_by_fei(wi.fei.to_s) if i.id == 0
204
+ # sometimes, the saved workitem id wasn't updated, was remaining at 0
205
+ # thus finding if necessary...
206
+
207
+ #i.fields.delete_all
208
+ # why do I need that ??? fields were getting recycled...
209
+
210
+ # This is a field set by the active participant immediately
211
+ # before calling this method.
212
+ # the default behavior is "use field method"
213
+
214
+ if wi.attributes["compact_workitems"]
215
+
216
+ wi.attributes.delete("compact_workitems")
217
+ i.yattributes = wi.attributes
218
+
219
+ else
220
+
221
+ i.yattributes = nil
222
+
223
+ wi.attributes.each do |k, v|
224
+ i.fields << Field.new_field(k, v)
225
+ end
226
+ end
227
+
228
+ i.save!
229
+ # making sure to throw an exception in case of trouble
230
+ #
231
+ # damn, insert then update :(
232
+
233
+ i
234
+ end
235
+
236
+ #
237
+ # Turns the densha Workitem into an OpenWFEru InFlowWorkItem.
238
+ #
239
+ def as_owfe_workitem
240
+
241
+ wi = OpenWFE::InFlowWorkItem.new
242
+
243
+ wi.fei = full_fei
244
+ wi.participant_name = participant_name
245
+ wi.attributes = fields_hash
246
+
247
+ wi.dispatch_time = dispatch_time
248
+ wi.last_modified = last_modified
249
+
250
+ wi.db_id = self.id
251
+
252
+ wi
253
+ end
254
+
255
+ #
256
+ # Returns a hash version of the 'fields' of this workitem.
257
+ #
258
+ # (Each time this method is called, it returns a new hash).
259
+ #
260
+ def fields_hash
261
+
262
+ return self.yattributes if self.yattributes
263
+
264
+ fields.inject({}) do |r, f|
265
+ r[f.fkey] = f.value
266
+ r
267
+ end
268
+ end
269
+
270
+ #
271
+ # Replaces the current fields of this workitem with the given hash.
272
+ #
273
+ # This method modifies the content of the db.
274
+ #
275
+ def replace_fields (fhash)
276
+
277
+ if self.yattributes
278
+
279
+ self.yattributes = fhash
280
+
281
+ else
282
+
283
+ fields.delete_all
284
+
285
+ fhash.each do |k, v|
286
+ fields << Field.new_field(k, v)
287
+ end
288
+ end
289
+
290
+ #f = Field.new_field("___map_type", "smap")
291
+ #
292
+ # an old trick for backward compatibility with OpenWFEja
293
+
294
+ save!
295
+ # making sure to throw an exception in case of trouble
296
+ end
297
+
298
+ #
299
+ # Returns the Field instance with the given key. This method accept
300
+ # symbols as well as strings as its parameter.
301
+ #
302
+ # wi.field("customer_name")
303
+ # wi.field :customer_name
304
+ #
305
+ def field (key)
306
+
307
+ if self.yattributes
308
+ return self.yattributes[key.to_s]
309
+ end
310
+
311
+ fields.find_by_fkey key.to_s
312
+ end
313
+
314
+ #
315
+ # A shortcut method, replies to the workflow engine and removes self
316
+ # from the database.
317
+ # Handy for people who don't want to play with an ActiveParticipant
318
+ # instance when just consuming workitems (that an active participant
319
+ # pushed in the database).
320
+ #
321
+ def reply (engine)
322
+
323
+ engine.reply self.as_owfe_workitem
324
+ self.destroy
325
+ end
326
+
327
+ alias :forward :reply
328
+ alias :proceed :reply
329
+
330
+ #
331
+ # Simply sets the 'last_modified' field to now.
332
+ # (Doesn't save the workitem though).
333
+ #
334
+ def touch
335
+
336
+ self.last_modified = Time.now
337
+ end
338
+
339
+ #
340
+ # Opening engine to update its reply method to accept these
341
+ # active record workitems.
342
+ #
343
+ class OpenWFE::Engine
344
+
345
+ alias :oldreply :reply
346
+
347
+ def reply (workitem)
348
+
349
+ if workitem.is_a?(Workitem)
350
+
351
+ oldreply(workitem.as_owfe_workitem)
352
+ workitem.destroy
353
+ else
354
+
355
+ oldreply(workitem)
356
+ end
357
+ end
358
+
359
+ alias :forward :reply
360
+ alias :proceed :reply
361
+ end
362
+
363
+ #
364
+ # Returns all the workitems belonging to the stores listed
365
+ # in the parameter storename_list.
366
+ # The result is a Hash whose keys are the store names and whose
367
+ # values are list of workitems.
368
+ #
369
+ def self.find_in_stores (storename_list)
370
+
371
+ workitems = find_all_by_store_name(storename_list)
372
+
373
+ result = {}
374
+
375
+ workitems.each do |wi|
376
+ (result[wi.store_name] ||= []) << wi
377
+ end
378
+
379
+ result
380
+ end
381
+
382
+ #
383
+ # A kind of 'google search' among workitems
384
+ #
385
+ # == Note
386
+ #
387
+ # when this is used on compact_workitems, it will not be able to search
388
+ # info within the fields, because they aren't used by this kind of
389
+ # workitems. In this case the search will be limited to participant_name
390
+ #
391
+ def self.search (search_string, storename_list=nil)
392
+
393
+ #t = OpenWFE::Timer.new
394
+
395
+ storename_list = Array(storename_list) if storename_list
396
+
397
+ # participant_name
398
+
399
+ result = find(
400
+ :all,
401
+ :conditions => conditions(
402
+ "participant_name", search_string, storename_list),
403
+ :order => "participant_name")
404
+ # :limit => 10)
405
+
406
+ ids = result.collect { |wi| wi.id }
407
+
408
+ # search in fields
409
+
410
+ fields = Field.search search_string, storename_list
411
+ merge_search_results ids, result, fields
412
+
413
+ #puts "... took #{t.duration} ms"
414
+
415
+ # over.
416
+
417
+ result
418
+ end
419
+
420
+ #
421
+ # Not really about 'just launched', but rather about finding the first
422
+ # workitem for a given process instance (wfid) and a participant.
423
+ # It deserves its own method because the workitem could be in a
424
+ # subprocess, thus escaping the vanilla find_by_wfid_and_participant()
425
+ #
426
+ def self.find_just_launched (wfid, participant_name)
427
+
428
+ find(
429
+ :first,
430
+ :conditions => [
431
+ "wfid LIKE ? AND participant_name = ?",
432
+ "#{wfid}%",
433
+ participant_name ])
434
+ end
435
+
436
+ protected
437
+
438
+ #
439
+ # builds the condition (the WHERE clause) for the
440
+ # search.
441
+ #
442
+ def self.conditions (keyname, search_string, storename_list)
443
+
444
+ cs = [ "#{keyname} LIKE ?", search_string ]
445
+
446
+ if storename_list
447
+
448
+ cs[0] = "#{cs[0]} AND workitems.store_name IN (?)"
449
+ cs << storename_list
450
+ end
451
+
452
+ cs
453
+ end
454
+
455
+ def self.merge_search_results (ids, wis, new_wis)
456
+
457
+ return if new_wis.size < 1
458
+
459
+ new_wis.each do |wi|
460
+ wi = wi.workitem if wi.kind_of?(Field)
461
+ next if ids.include? wi.id
462
+ ids << wi.id
463
+ wis << wi
464
+ end
465
+ end
466
+ end
467
+
468
+ #
469
+ # A workaround is in place for some classes when then have to get
470
+ # serialized. The names of thoses classes are listed in this array.
471
+ #
472
+ SPECIAL_FIELD_CLASSES = [ 'Time', 'Date', 'DateTime' ]
473
+
474
+ #
475
+ # A Field (Attribute) of a Workitem.
476
+ #
477
+ class Field < ActiveRecord::Base
478
+
479
+ belongs_to :workitem
480
+ serialize :yvalue
481
+
482
+ #
483
+ # A quick method for doing
484
+ #
485
+ # f = Field.new
486
+ # f.key = key
487
+ # f.value = value
488
+ #
489
+ # One can then quickly add fields to an [active] workitem via :
490
+ #
491
+ # wi.fields << Field.new_field("toto", "b")
492
+ #
493
+ # This method does not save the new Field.
494
+ #
495
+ def self.new_field (key, value)
496
+
497
+ f = Field.new
498
+ f.fkey = key
499
+ f.vclass = value.class.to_s
500
+ f.value = value
501
+ f
502
+ end
503
+
504
+ def value= (v)
505
+
506
+ limit = connection.native_database_types[:string][:limit]
507
+
508
+ if v.is_a?(String) and v.length <= limit
509
+
510
+ self.svalue = v
511
+
512
+ elsif SPECIAL_FIELD_CLASSES.include?(v.class.to_s)
513
+
514
+ self.svalue = v.to_yaml
515
+
516
+ else
517
+
518
+ self.yvalue = v
519
+ end
520
+ end
521
+
522
+ def value
523
+
524
+ return YAML.load(self.svalue) \
525
+ if SPECIAL_FIELD_CLASSES.include?(self.vclass)
526
+
527
+ self.svalue || self.yvalue
528
+ end
529
+
530
+ #
531
+ # Will return all the fields that contain the given text.
532
+ #
533
+ # Looks in svalue and fkey. Looks as well in yvalue if it contains
534
+ # a string.
535
+ #
536
+ # This method is used by Workitem.search()
537
+ #
538
+ def self.search (text, storename_list=nil)
539
+
540
+ cs = build_search_conditions(text)
541
+
542
+ if storename_list
543
+
544
+ cs[0] = "(#{cs[0]}) AND workitems.store_name IN (?)"
545
+ cs << storename_list
546
+ end
547
+
548
+ find :all, :conditions => cs, :include => :workitem
549
+ end
550
+
551
+ protected
552
+
553
+ #
554
+ # The search operates on the content of these columns
555
+ #
556
+ FIELDS_TO_SEARCH = %w{ svalue fkey yvalue }
557
+
558
+ #
559
+ # Builds the condition array for a pseudo text search
560
+ #
561
+ def self.build_search_conditions (text)
562
+
563
+ has_percent = (text.index("%") != nil)
564
+
565
+ conds = []
566
+
567
+ conds << FIELDS_TO_SEARCH.collect { |key|
568
+
569
+ count = has_percent ? 1 : 4
570
+
571
+ s = ([ "#{key} LIKE ?" ] * count).join(" OR ")
572
+
573
+ s = "(vclass = ? AND (#{s}))" if key == 'yvalue'
574
+
575
+ s
576
+ }.join(" OR ")
577
+
578
+ FIELDS_TO_SEARCH.each do |key|
579
+
580
+ conds << 'String' if key == 'yvalue'
581
+
582
+ conds << text
583
+
584
+ unless has_percent
585
+ conds << "% #{text} %"
586
+ conds << "% #{text}"
587
+ conds << "#{text} %"
588
+ end
589
+ end
590
+
591
+ conds
592
+ end
593
+ end
594
+
595
+
596
+ #
597
+ # A basic 'ActiveParticipant'.
598
+ # A store participant whose store is a set of ActiveRecord tables.
599
+ #
600
+ # Sample usage :
601
+ #
602
+ # class MyDefinition < OpenWFE::ProcessDefinition
603
+ # sequence do
604
+ # active0
605
+ # active1
606
+ # end
607
+ # end
608
+ #
609
+ # def play_with_the_engine
610
+ #
611
+ # engine = OpenWFE::Engine.new
612
+ #
613
+ # engine.register_participant(
614
+ # :active0, OpenWFE::Extras::ActiveParticipant)
615
+ # engine.register_participant(
616
+ # :active1, OpenWFE::Extras::ActiveParticipant)
617
+ #
618
+ # li = OpenWFE::LaunchItem.new(MyDefinition)
619
+ # li.customer_name = 'toto'
620
+ # engine.launch li
621
+ #
622
+ # sleep 0.500
623
+ # # give some slack to the engine, it's asynchronous after all
624
+ #
625
+ # wi = OpenWFE::Extras::Workitem.find_by_participant_name("active0")
626
+ #
627
+ # # ...
628
+ # end
629
+ #
630
+ # == Compact workitems
631
+ #
632
+ # It is possible to save all the workitem data into a single table,
633
+ # the workitems table, without
634
+ # splitting info between workitems and fields tables.
635
+ #
636
+ # You can configure the "compact_workitems" behavior by adding to the
637
+ # previous lines:
638
+ #
639
+ # active0 = engine.register_participant(
640
+ # :active0, OpenWFE::Extras::ActiveParticipant)
641
+ #
642
+ # active0.compact_workitems = true
643
+ #
644
+ # This behaviour is determined participant per participant, it's ok to
645
+ # have a participant instance that compacts will there is another that
646
+ # doesn't compact.
647
+ #
648
+ class ActiveParticipant
649
+ include OpenWFE::LocalParticipant
650
+
651
+ #
652
+ # when compact_workitems is set to true, the attributes of a workitem
653
+ # are stored in the yattributes column (they are not expanded into
654
+ # the Fields table).
655
+ # By default, workitem attributes are expanded.
656
+ #
657
+ attr :compact_workitems, true
658
+
659
+ #
660
+ # This is the method called by the OpenWFEru engine to hand a
661
+ # workitem to this participant.
662
+ #
663
+ def consume (workitem)
664
+
665
+ if compact_workitems
666
+ workitem.attributes["compact_workitems"] = true
667
+ end
668
+
669
+ Workitem.from_owfe_workitem workitem
670
+ end
671
+
672
+ #
673
+ # Called by the engine when the whole process instance (or just the
674
+ # segment of it that sports this participant) is cancelled.
675
+ # Will removed the workitem with the same fei as the cancelitem
676
+ # from the database.
677
+ #
678
+ # No expression will be raised if there is no corresponding workitem.
679
+ #
680
+ def cancel (cancelitem)
681
+
682
+ Workitem.destroy_all([ "fei = ?", cancelitem.fei.to_s ])
683
+ # note that delete_all was not removing workitem fields
684
+ end
685
+
686
+ #
687
+ # When the activity/work/operation whatever is over and the flow
688
+ # should resume, this is the method to use to hand back the [modified]
689
+ # workitem to the [local] engine.
690
+ #
691
+ def reply_to_engine (workitem)
692
+
693
+ super workitem.as_owfe_workitem
694
+ #
695
+ # replies to the workflow engine
696
+
697
+ workitem.destroy
698
+ #
699
+ # removes the workitem from the database
700
+ end
701
+ end
702
+
703
+ #
704
+ # An extension of ActiveParticipant. It has a 'store_name' and it
705
+ # makes sure to flag every workitem it 'consumes' with that name
706
+ # (in its 'store_name' column/field).
707
+ #
708
+ # This is the participant used mainly in 'densha' for human users.
709
+ #
710
+ class ActiveStoreParticipant < ActiveParticipant
711
+ include Enumerable
712
+
713
+ def initialize (store_name)
714
+
715
+ super()
716
+ @store_name = store_name
717
+ end
718
+
719
+ #
720
+ # This is the method called by the OpenWFEru engine to hand a
721
+ # workitem to this participant.
722
+ #
723
+ def consume (workitem)
724
+
725
+ if compact_workitems
726
+ workitem.attributes["compact_workitems"] = true
727
+ end
728
+
729
+ Workitem.from_owfe_workitem(workitem, @store_name)
730
+ end
731
+
732
+ #
733
+ # Iterates over the workitems currently in this store.
734
+ #
735
+ def each (&block)
736
+
737
+ return unless block
738
+
739
+ wis = Workitem.find_by_store_name @store_name
740
+
741
+ wis.each do |wi|
742
+ block.call wi
743
+ end
744
+ end
745
+ end
746
+
747
+ end
748
+ end
749
+