openwferu 0.9.1 → 0.9.2

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 (104) hide show
  1. data/{README → README.txt} +16 -13
  2. data/bin/validate-workflow.rb +46 -22
  3. data/examples/README.txt +8 -0
  4. data/examples/homeworkreview.rb +66 -0
  5. data/examples/quotereporter.rb +154 -0
  6. data/lib/{openwferu.rb → openwfe.rb} +6 -8
  7. data/lib/{ru → openwfe}/contextual.rb +11 -3
  8. data/lib/{ru → openwfe/engine}/engine.rb +50 -36
  9. data/lib/{ru/participant.rb → openwfe/engine/file_persisted_engine.rb} +21 -22
  10. data/lib/openwfe/expool/expressionpool.rb +534 -0
  11. data/lib/openwfe/expool/expstorage.rb +184 -0
  12. data/lib/openwfe/expool/journalexpstorage.rb +312 -0
  13. data/lib/openwfe/expool/yamlexpstorage.rb +127 -0
  14. data/lib/{ru → openwfe/expressions}/environment.rb +19 -14
  15. data/lib/{ru → openwfe/expressions}/expressionmap.rb +48 -21
  16. data/lib/{ru → openwfe/expressions}/fe_concurrence.rb +111 -35
  17. data/lib/openwfe/expressions/fe_cursor.rb +236 -0
  18. data/lib/{ru → openwfe/expressions}/fe_define.rb +5 -5
  19. data/lib/openwfe/expressions/fe_fqv.rb +99 -0
  20. data/lib/openwfe/expressions/fe_iterator.rb +182 -0
  21. data/lib/{ru/fe_misc.rb → openwfe/expressions/fe_losfor.rb} +14 -56
  22. data/lib/openwfe/expressions/fe_misc.rb +102 -0
  23. data/lib/{ru → openwfe/expressions}/fe_participant.rb +25 -14
  24. data/lib/{ru → openwfe/expressions}/fe_raw.rb +39 -75
  25. data/lib/{ru/fe_base.rb → openwfe/expressions/fe_sequence.rb} +40 -35
  26. data/lib/{ru → openwfe/expressions}/fe_subprocess.rb +30 -14
  27. data/lib/{ru → openwfe/expressions}/fe_time.rb +59 -31
  28. data/lib/{ru → openwfe/expressions}/fe_utils.rb +42 -26
  29. data/lib/{ru → openwfe/expressions}/fe_value.rb +20 -14
  30. data/lib/openwfe/expressions/flowexpression.rb +434 -0
  31. data/lib/openwfe/expressions/raw_prog.rb +391 -0
  32. data/lib/openwfe/expressions/raw_xml.rb +128 -0
  33. data/lib/openwfe/flowexpressionid.rb +148 -0
  34. data/lib/{ru → openwfe}/logging.rb +10 -6
  35. data/lib/{osocket.rb → openwfe/osocket.rb} +36 -35
  36. data/lib/{otime.rb → openwfe/otime.rb} +71 -21
  37. data/lib/openwfe/participants/atomparticipants.rb +144 -0
  38. data/lib/openwfe/participants/enoparticipant.rb +73 -0
  39. data/lib/openwfe/participants/participant.rb +85 -0
  40. data/lib/{ru → openwfe/participants}/participantmap.rb +40 -12
  41. data/lib/{ru → openwfe/participants}/participants.rb +41 -12
  42. data/lib/openwfe/participants/soapparticipants.rb +96 -0
  43. data/lib/{controlclient.rb → openwfe/rest/controlclient.rb} +12 -13
  44. data/lib/{definitions.rb → openwfe/rest/definitions.rb} +3 -3
  45. data/lib/{exception.rb → openwfe/rest/exception.rb} +3 -3
  46. data/lib/{restclient.rb → openwfe/rest/restclient.rb} +13 -22
  47. data/lib/{worklistclient.rb → openwfe/rest/worklistclient.rb} +33 -46
  48. data/lib/openwfe/rest/xmlcodec.rb +575 -0
  49. data/lib/{ru → openwfe}/rudefinitions.rb +32 -4
  50. data/lib/{ru → openwfe}/service.rb +20 -8
  51. data/lib/openwfe/storage/yamlfilestorage.rb +159 -0
  52. data/lib/{ru → openwfe/util}/dollar.rb +10 -8
  53. data/lib/openwfe/util/lru_cache.rb +149 -0
  54. data/lib/{ru → openwfe/util}/scheduler.rb +18 -10
  55. data/lib/{ru → openwfe/util}/schedulers.rb +7 -7
  56. data/lib/{utils.rb → openwfe/utils.rb} +93 -9
  57. data/lib/openwfe/workitem.rb +366 -0
  58. data/lib/openwfe/worklist/worklists.rb +175 -0
  59. data/test/README.txt +27 -0
  60. data/test/atomtest.rb +99 -0
  61. data/test/crontest.rb +58 -0
  62. data/test/dollartest.rb +3 -3
  63. data/test/feitest.rb +42 -14
  64. data/test/file_persistence_test.rb +93 -0
  65. data/test/flowtestbase.rb +72 -26
  66. data/test/ft_0.rb +1 -97
  67. data/test/ft_0b_sequence.rb +33 -0
  68. data/test/ft_0c_testname.rb +29 -0
  69. data/test/ft_10_loop.rb +48 -0
  70. data/test/ft_11_ppd.rb +292 -0
  71. data/test/ft_12_blockparticipant.rb +45 -0
  72. data/test/ft_13_eno.rb +51 -0
  73. data/test/ft_14_subprocess.rb +90 -0
  74. data/test/ft_14b_subprocess.rb +40 -0
  75. data/test/ft_15_iterator.rb +70 -0
  76. data/test/ft_16_fqv.rb +57 -0
  77. data/test/ft_1_unset.rb +25 -1
  78. data/test/ft_2_concurrence.rb +10 -5
  79. data/test/ft_3_equals.rb +35 -1
  80. data/test/ft_4_misc.rb +16 -1
  81. data/test/ft_5_time.rb +26 -1
  82. data/test/ft_6_lambda.rb +2 -1
  83. data/test/{ft_7_losfor.rb → ft_7_lose.rb} +41 -35
  84. data/test/ft_8_forget.rb +46 -0
  85. data/test/ft_9_cursor.rb +94 -0
  86. data/test/journal_persistence_test.rb +147 -0
  87. data/test/misctest.rb +13 -9
  88. data/test/rake_ptest.rb +18 -0
  89. data/test/rake_qtest.rb +43 -0
  90. data/test/{fulltest.rb → rake_test.rb} +2 -2
  91. data/test/raw_prog_test.rb +236 -0
  92. data/test/rest_test.rb +189 -0
  93. data/test/rutest_utils.rb +1 -1
  94. data/test/timetest.rb +42 -34
  95. metadata +125 -82
  96. data/lib/codec.rb +0 -573
  97. data/lib/flowexpressionid.rb +0 -139
  98. data/lib/ru/expressionpool.rb +0 -382
  99. data/lib/ru/expressionstorage.rb +0 -99
  100. data/lib/ru/flowexpression.rb +0 -272
  101. data/lib/ru/ruutils.rb +0 -70
  102. data/lib/test.rb +0 -222
  103. data/lib/workitem.rb +0 -249
  104. data/test/quicktest.rb +0 -21
@@ -0,0 +1,184 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2007, Nicolas Modryzk and 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
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "made in Japan"
38
+ #
39
+ # Nicolas Modrzyk at openwfe.org
40
+ # John Mettraux at openwfe.org
41
+ #
42
+
43
+ require 'fileutils'
44
+
45
+ require 'openwfe/service'
46
+ require 'openwfe/util/lru_cache'
47
+ require 'openwfe/flowexpressionid'
48
+
49
+ module OpenWFE
50
+
51
+ #
52
+ # Create a composite expression storage.
53
+ # This will take parameters from the application context to create
54
+ # the resulting composite storage
55
+ class CompositeExpressionStorage
56
+ include ServiceMixin
57
+
58
+ attr_accessor \
59
+ :persistence, \
60
+ :cache, \
61
+ :journal
62
+
63
+ def initialize (serviceName, applicationContext)
64
+
65
+ service_init(serviceName, applicationContext)
66
+
67
+ @cache = @application_context[:cached_expression_storage]
68
+ @journal = @application_context[:journalized_expression_storage]
69
+ @persistence = @application_context[:file_expression_storage]
70
+ end
71
+
72
+ #
73
+ # call the add method for each registered storage
74
+ def []= (fei, flowExpression)
75
+ @journal[fei] = flowExpression if @journal
76
+ @cache[fei] = flowExpression if @cache
77
+ @persistence[fei] = flowExpression
78
+ end
79
+
80
+ #
81
+ # remove the expressionid from each registered storage
82
+ def remove (fei, workitem)
83
+ @journal.remove(fei, workitem) if @journal
84
+ @cache.remove(fei, workitem) if @cache
85
+ @persistence.remove(fei,workitem)
86
+ end
87
+
88
+ #
89
+ # slightly different method. Try to get the value from the cache storage if one
90
+ # if not retrieve it, and then add it to the cache.
91
+ def [] (fei)
92
+ return @cache[fei] if @cache
93
+ flow_expression = @persistence[fei]
94
+ @cache[fei] = flow_expression if @cache
95
+ return flow_expression
96
+ end
97
+ end
98
+
99
+ #
100
+ # implementation of a LRU caching storage.
101
+ class LruCachedExpressionStorage
102
+ include ServiceMixin
103
+
104
+ DEFAULT_LRU_SIZE = 10
105
+
106
+ def initialize (service_name, application_context)
107
+ service_init(service_name, application_context)
108
+ size = if (@application_context)
109
+ @application_context[:lru_storage_size]
110
+ else
111
+ DEFAULT_LRU_SIZE
112
+ end
113
+ @cache = LRUCache.new(size)
114
+ end
115
+
116
+ def []= (fei, flowExpression)
117
+ @cache[fei]=flowExpression
118
+ end
119
+
120
+ #
121
+ # interface method to remove an entry for the given expression_id
122
+ def remove (fei, workitem)
123
+ @cache.delete(fei)
124
+ end
125
+
126
+ #
127
+ # check if the value is in the cache
128
+ def is_in_cache?(fei)
129
+ @cache.include?(fei)
130
+ end
131
+ alias has_key? is_in_cache?
132
+
133
+ #
134
+ # interface method, return the value associated with the given id,
135
+ # or nil if not in cache.
136
+ def [] (fei)
137
+ if(@cache.include?(fei))
138
+ return @cache[fei]
139
+ else
140
+ return nil
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ #
147
+ # Memory consuming in-memory storage.
148
+ # No memory limit, puts everything in a Hash
149
+ #
150
+ class InMemoryExpressionStorage < Hash
151
+ include ServiceMixin
152
+
153
+ def initialize (service_name, application_context)
154
+ @service_name = service_name
155
+ @application_context = application_context
156
+ end
157
+
158
+ def remove (fei, workitem)
159
+ delete(fei)
160
+ end
161
+
162
+ def purge
163
+ self.clear
164
+ end
165
+
166
+ def to_s
167
+ s = "\n\n==== #{self.class} ===="
168
+ each do |k, v|
169
+ s << "\n"
170
+ if v.kind_of?(RawExpression)
171
+ s << "*raw"
172
+ else
173
+ s << " "
174
+ end
175
+ s << v.to_s
176
+ s << " key/value mismatch !" if k != v.fei
177
+ end
178
+ s << "\n==== . ====\n"
179
+ return s
180
+ end
181
+
182
+ end
183
+
184
+ end
@@ -0,0 +1,312 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2007, Nicolas Modryzk and 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
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "made in Japan"
38
+ #
39
+ # Nicolas Modrzyk at openwfe.org
40
+ # John Mettraux at openwfe.org
41
+ #
42
+
43
+ require 'fileutils'
44
+ require 'base64'
45
+
46
+ require 'openwfe/service'
47
+ require 'openwfe/workitem'
48
+ require 'openwfe/flowexpressionid'
49
+ require 'openwfe/expressions/expressionmap'
50
+
51
+
52
+ module OpenWFE
53
+
54
+ #
55
+ # by default the journals are stored into "work/journal"
56
+ #
57
+ DEFAULT_STORAGE_PATH = "work/"
58
+
59
+ #
60
+ # this is the container class for storing entries in the the journal
61
+ #
62
+ class JournalEntry
63
+
64
+ # reused for
65
+ ENTRY_DELIM = ' -- '
66
+
67
+ attr_reader :fei, :action, :fe, :time
68
+
69
+
70
+ def initialize (action, fei, fe, stime=nil)
71
+ @action = action
72
+ @fei = fei
73
+ @fe = fe
74
+ @time = if stime
75
+ stime
76
+ else
77
+ Time.new
78
+ end
79
+ end
80
+
81
+ #
82
+ # parse the entry from a line read from a log file
83
+ def JournalEntry.parse_from_string (line)
84
+ # offset includes iso formatting and delim
85
+ time_offset = line.index(ENTRY_DELIM)
86
+
87
+ time = Time.iso8601(line.slice(0..time_offset))
88
+
89
+ line = line.slice(time_offset+ ENTRY_DELIM.length..line.length)
90
+ action = line[0..2]
91
+
92
+ index = line.index(ENTRY_DELIM,7)
93
+ fei = OpenWFE::FlowExpressionId.to_fei(line[8..index-1])
94
+
95
+ if action == :put.to_s
96
+ fe_64_yaml = line[index+ENTRY_DELIM.length,line.length].rstrip
97
+ fe_yaml = Base64.decode64(fe_64_yaml.gsub("**","\n"))
98
+ fe = YAML.load(fe_yaml)
99
+ return JournalEntry.new(:put, fei, fe, time)
100
+ else
101
+ return JournalEntry.new(action, fei, nil, time)
102
+ end
103
+ end
104
+
105
+ #
106
+ # this is directly used to store the entry in the journal.
107
+ # This is using base64 encoding to wrap the encoded object, and is not readable. Use to_human_s to decrypt
108
+ def to_s
109
+ if @action == :put
110
+ base64 = Base64.encode64(YAML.dump(@fe)).gsub("\n","**") + "\n"
111
+ @time.iso8601 + ENTRY_DELIM + @action.to_s + ENTRY_DELIM + @fei.to_s + ENTRY_DELIM + base64
112
+ else
113
+ @time.iso8601 + ENTRY_DELIM + @action.to_s + ENTRY_DELIM + @fei.to_s + ENTRY_DELIM + "\n"
114
+ end
115
+ end
116
+
117
+ #
118
+ # same as above,except the encoded object is fully expanded. The return value cannot be processed.
119
+ def to_human_s
120
+ if @action == :put
121
+ @time.iso8601 + ENTRY_DELIM + @action.to_s + ENTRY_DELIM + @fei.to_s + ENTRY_DELIM + "\n" + YAML.dump(@fe).to_s + "---\n"
122
+ else
123
+ to_s
124
+ end
125
+ end
126
+ end
127
+
128
+ #
129
+ # the class responsible for handling replay of a log file
130
+ class JournalReplay
131
+
132
+ def initialize(storage=nil)
133
+ if not storage
134
+ @storage = @application_context[S_EXPRESSION_STORAGE]
135
+ else
136
+ @storage = storage
137
+ end
138
+ end
139
+
140
+ #
141
+ # from the content of path_to_journal, will replay all the entries one by one on the given storage
142
+ def replay(path_to_journal)
143
+ datalines = IO.readlines(path_to_journal)
144
+ datalines.each {
145
+ |line_read|
146
+ entry = (JournalEntry.parse_from_string(line_read))
147
+ if(entry.action == :put)
148
+ @storage[entry.fei]=entry.fe
149
+ else
150
+ #TODO: implement delete
151
+ #@storage.delete(entry.fei)
152
+ @storage.remove(entry.fei)
153
+ end
154
+ }
155
+ end
156
+
157
+ end
158
+
159
+ #
160
+ # this is the main class for journalized storage
161
+ class JournalizedExpressionStorage
162
+ include ServiceMixin
163
+
164
+ attr_accessor :basepath
165
+
166
+ def initialize (serviceName, applicationContext)
167
+ service_init(serviceName, applicationContext)
168
+ path = if (@application_context)
169
+ @application_context[:file_expression_storage_path]
170
+ else
171
+ DEFAULT_STORAGE_PATH
172
+ end
173
+ @basepath = path + "/journal"
174
+ FileUtils.makedirs @basepath
175
+ end
176
+
177
+ #
178
+ # remove the file corresponding to the journal of this workflow instance
179
+ def clean (workflow_id)
180
+ fei_path = compute_file_path_id(workflow_id)
181
+ if (File.exist?(fei_path))
182
+ File.delete(fei_path)
183
+ end
184
+ end
185
+
186
+ #
187
+ # backup the journal file corresponding to the give workflow instance
188
+ # by default, deletes the original journal file.
189
+ def backup (workflow_id, delete_original = true, backup_path = nil)
190
+ path_to_journal = compute_file_path_id(workflow_id)
191
+ temporary_journal = if not backup_path
192
+ path_to_journal+".0"
193
+ else
194
+ backup_path
195
+ end
196
+ FileUtils.copy_file(path_to_journal, temporary_journal)
197
+ File.delete(path_to_journal) if delete_original
198
+ return temporary_journal
199
+ end
200
+
201
+ #
202
+ # truncate the content of the log file:
203
+ # - number of lines
204
+ # - before a given date
205
+ def truncate! (workflow_id, number_of_lines=nil, after_date=nil)
206
+ return 0 if not number_of_lines and not after_date
207
+
208
+ fei_path = compute_file_path_id(workflow_id)
209
+ datalines = IO.readlines(fei_path)
210
+ entries = Array.new
211
+
212
+ datalines.each { |line_read|
213
+ entry = JournalEntry.parse_from_string(line_read)
214
+ break if after_date and entry.time >= after_date
215
+ break if number_of_lines and entries.length >= number_of_lines
216
+ entries.push entry
217
+ }
218
+
219
+ backup(workflow_id)
220
+
221
+ fd = IO.sysopen(fei_path, File::WRONLY|File::CREAT, 0666)
222
+ io = IO.open(fd , "w")
223
+
224
+ entries.each{ |entry|
225
+ io.write(entry.to_s)
226
+ }
227
+ io.close
228
+
229
+ return entries.length
230
+ end
231
+
232
+ #
233
+ # create a human readable log file for the given workflow instance.
234
+ # Note that this will override any existing previously created file
235
+ def to_human_s(workflow_id)
236
+ fei_path = compute_file_path_id(workflow_id)
237
+ if (File.exist?(fei_path))
238
+ fei_new_path = fei_path[0,fei_path.length-5] + ".txt"
239
+ File.delete(fei_new_path) if (File.exist?(fei_new_path))
240
+
241
+ fd = IO.sysopen(fei_new_path, File::WRONLY|File::CREAT, 0666)
242
+ io = IO.open(fd , "w")
243
+
244
+ datalines = IO.readlines(fei_path)
245
+ datalines.each { |line_read| human = (JournalEntry.parse_from_string(line_read)).to_human_s ; io.write(human) }
246
+
247
+ io.close
248
+ else
249
+ raise "workflow journal does not exist for given id:"+workflow_id
250
+ end
251
+ end
252
+
253
+ #
254
+ # interface method for the persistence. add a flow expression to the storage
255
+ def []= (fei, flow_expression)
256
+ write_to_journal(JournalEntry.new(:put, fei, flow_expression))
257
+ end
258
+
259
+ #
260
+ # interface method: remove the expressionid and persist the related workitem
261
+ def remove (fei, workitem=nil)
262
+ write_to_journal(JournalEntry.new(:del, fei, nil))
263
+ end
264
+
265
+ #
266
+ # compute the size of the journal (number of entries) in the journal for the
267
+ # given workflow id
268
+ def size (workflow_instance_id)
269
+ fei_path = compute_file_path_id(workflow_instance_id)
270
+ return 0 if not File.exist?(fei_path)
271
+
272
+ datalines = IO.readlines(fei_path)
273
+ return datalines.length
274
+ end
275
+
276
+ #
277
+ # alias for the protected compute_file_path with a better name.
278
+ # Return the path of the log for the given workflow instance
279
+ def where_is_journal_for (workflow_instance_id)
280
+ compute_file_path(workflow_instance_id)
281
+ end
282
+
283
+ #
284
+ # write an entry to the journal. This call the to_s method of the entry
285
+ # and append the resulting line to the log file
286
+ def write_to_journal (journal_entry)
287
+ fei_path = compute_file_path(journal_entry.fei)
288
+ fei_parent_path = File.dirname(fei_path)
289
+
290
+ FileUtils.makedirs fei_parent_path if not (File.exist?(fei_parent_path))
291
+
292
+ fd = IO.sysopen(fei_path, File::WRONLY|File::APPEND|File::CREAT, 0666)
293
+ io = IO.open(fd , "w")
294
+
295
+ io.write(journal_entry.to_s)
296
+
297
+ io.close
298
+ end
299
+
300
+ protected
301
+
302
+ def compute_file_path (fei)
303
+ compute_file_path_id(fei.parent_workflow_instance_id)
304
+ end
305
+
306
+ def compute_file_path_id (parent_workflow_instance_id)
307
+ @basepath + "/" + parent_workflow_instance_id.to_s + ".yaml"
308
+ end
309
+
310
+ end
311
+
312
+ end