| GONE | = | "gone" | ||
| GONE_PARENT_ID | = | FlowExpressionId.new | This special flow expression id is used by the forget() method (which is used by the forget expression and the concurrence synchronization expressions) | |
| SPLIT_MAP | = | { "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" => UuidWfidGenerator, "[0-9]{8}-[a-z]*" => KotobaWfidGenerator | "module methods" | |
| VAR_PAUSED | = | '/__paused__' | When this variable is set to true (at the process root), it means the process is paused. | |
| KEYWORDS | = | [ :if, :do, :redo, :undo, :print, :sleep, :loop, :break, :when |
OpenWFE process definitions do use some Ruby
keywords… The workaround is to put an underscore just before the name
to ‘escape’ it.
‘undo’ isn‘t reserved by Ruby, but lets keep it in line with ‘do’ and ‘redo’ that are. |
|
| NAME | = | 'name' | ||
| STORE | = | 'store' | ||
| STORES | = | 'stores' | ||
| WORKITEM_COUNT | = | 'workitem-count' | ||
| PERMISSIONS | = | 'permissions' | ||
| HEADER | = | 'header' | ||
| HEADERS | = | 'headers' | ||
| A_LAST_MODIFIED | = | 'last-modified' | ||
| A_LOCKED | = | 'locked' | ||
| FLOW_EXPRESSION_ID | = | 'flow-expression-id' | ||
| ATTRIBUTES | = | 'attributes' | ||
| OWFE_VERSION | = | 'owfe-version' | ||
| ENGINE_ID | = | 'engine-id' | ||
| INITIAL_ENGINE_ID | = | 'initial-engine-id' | ||
| WORKFLOW_DEFINITION_URL | = | 'workflow-definition-url' | ||
| WORKFLOW_DEFINITION_NAME | = | 'workflow-definition-name' | ||
| WORKFLOW_DEFINITION_REVISION | = | 'workflow-definition-revision' | ||
| WORKFLOW_INSTANCE_ID | = | 'workflow-instance-id' | ||
| EXPRESSION_NAME | = | 'expression-name' | ||
| EXPRESSION_ID | = | 'expression-id' | ||
| E_STRING | = | 'string' | ||
| E_INTEGER | = | 'integer' | ||
| E_BOOLEAN | = | 'boolean' | ||
| E_LONG | = | 'long' | ||
| E_DOUBLE | = | 'double' | ||
| E_RAW_XML | = | 'raw-xml' | ||
| E_XML_DOCUMENT | = | 'xml-document' | ||
| E_BASE64 | = | 'base64' | ||
| E_LIST | = | 'list' | ||
| E_MAP | = | 'map' | ||
| E_SMAP | = | 'smap' | ||
| M_ENTRY | = | 'entry' | ||
| M_KEY | = | 'key' | ||
| M_VALUE | = | 'value' | ||
| MAP_TYPE | = | '___map_type' | ||
| FLOW_EXPRESSION_IDS | = | 'flow-expression-ids' | ||
| LAUNCHITEM | = | 'launchitem' | ||
| ENGINEID | = | "engineid" | ||
| OK | = | "ok" | ||
| A_FLOW_ID | = | "flow-id" | ||
| IN_FLOW_WORKITEM | = | 'workitem' | ||
| A_DISPATCH_TIME | = | 'dispatch-time' | ||
| A_PARTICIPANT_NAME | = | 'participant-name' | ||
| E_LAST_EXPRESSION_ID | = | 'last-expression-id' | ||
| LAUNCHABLES | = | 'launchables' | ||
| LAUNCHABLE | = | 'launchable' | ||
| URL | = | 'url' | ||
| TARGETSTORE | = | 'targetstore' | ||
| EXPRESSIONS | = | 'expressions' | ||
| EXPRESSION | = | 'expression' | ||
| APPLY_TIME | = | 'apply-time' | ||
| STATE | = | 'state' | ||
| STATE_SINCE | = | 'state-since' | ||
| HISTORY | = | 'history' | ||
| HISTORY_ITEM | = | 'history-item' | ||
| A_AUTHOR | = | 'author' | ||
| A_DATE | = | 'date' | ||
| A_HOST | = | 'host' | ||
| S_LOGGER | = | :logger | service names | |
| S_ENGINE | = | 'engine' | ||
| S_EXPRESSION_MAP | = | 'expressionMap' | ||
| S_WFID_GENERATOR | = | 'wfidGenerator' | ||
| S_EXPRESSION_POOL | = | 'expressionPool' | ||
| S_EXPRESSION_STORAGE | = | 'expressionStorage' | ||
| S_PARTICIPANT_MAP | = | 'participantMap' | ||
| S_SCHEDULER | = | 'scheduler' | ||
| S_ERROR_JOURNAL | = | 'errorJournal' | ||
| EN_ENVIRONMENT | = | 'environment' | some special expression names | |
| DEFAULT_WORK_DIRECTORY | = | 'work' | some file storage default values | |
| DSUB_SAFETY_LEVEL | = | 4 | ||
| OPENWFERU_VERSION | = | '0.9.18' | ||
| FIELD_RESULT | = | "__result__" | The convention for the result of some expressions is to store their result in a workitem field named "result". |
Some code for writing thinks like :
if async
OpenWFE::call_in_thread "launch()", self do
raw_expression.apply(wi)
end
else
raw_expression.apply(wi)
end
Returns the new thread instance.
# File lib/openwfe/utils.rb, line 291
291: def OpenWFE.call_in_thread (caller_name, caller_object=nil, &block)
292:
293: return unless block
294:
295: Thread.new do
296:
297: #set_current_thread_name "call_in_thread() for '#{caller_name}'"
298: set_current_thread_name caller_name
299:
300: begin
301: #$SAFE = safe_level
302: #
303: # (note)
304: # doesn't work : the block inherits the safety level
305: # of its surroundings, it's a closure, ne ?
306:
307: block.call
308:
309: rescue Exception => e
310: msg = "#{caller_name} caught an exception\n" + exception_to_s(e)
311: if caller_object and caller_object.respond_to? :lwarn
312: caller_object.lwarn { msg }
313: else
314: puts msg
315: end
316: end
317: end
318: # returns the thread
319: end
Pretty printing a caller() array
# File lib/openwfe/utils.rb, line 256
256: def OpenWFE.caller_to_s (start_index, max_lines=nil)
257: s = ""
258: caller(start_index + 1).each_with_index do |line, index|
259: break if max_lines and index >= max_lines
260: s << " #{line}\n"
261: end
262: s
263: end
"my//path" -> "my/path"
# File lib/openwfe/utils.rb, line 381
381: def OpenWFE.clean_path (s)
382: s.gsub(/\/+/, "/")
383: end
see wiki.rubygarden.org/Ruby/page/show/Make_A_Deep_Copy_Of_An_Object
It‘s not perfect (that‘s why fulldup() uses it only in certain cases).
For example :
TypeError: singleton can't be dumped
./lib/openwfe/utils.rb:74:in `dump'
./lib/openwfe/utils.rb:74:in `deep_clone'
# File lib/openwfe/utils.rb, line 72
72: def OpenWFE.deep_clone (object)
73:
74: Marshal::load(Marshal.dump(object))
75: end
Dispatches a workitem over TCP, the workitem will be encoded with XML The default encode_method is
# File lib/openwfe/orest/osocket.rb, line 93
93: def OpenWFE.dispatch_workitem (host, port, workitem)
94:
95: #sXml = OpenWFE.xml_encode(workitem)
96: sXml = OpenWFE::XmlCodec::encode workitem
97:
98: socket = TCPSocket.new(host, port)
99: socket.puts "xmlCoder #{sXml.length}"
100: socket.puts
101: socket.puts sXml
102: socket.puts
103: socket.close_write
104:
105: reply = socket.gets
106:
107: #reply = reply + socket.gets
108: #
109: # a bit ridiculous, but it works
110: # socket.close_write fixed it
111:
112: socket.close
113:
114: #puts "dispatch() reply is >#{reply}<"
115: end
Performs ‘dollar substitution’ on a piece of text with as input a flow expression and a workitem (fields and variables).
# File lib/openwfe/util/dollar.rb, line 62
62: def OpenWFE.dosub (text, flow_expression, workitem)
63:
64: #
65: # patch by Nick Petrella (2008/03/20)
66: #
67:
68: if text.is_a?(String)
69:
70: Rufus::dsub(text, FlowDict.new(flow_expression, workitem))
71:
72: elsif text.is_a?(Array)
73:
74: text.collect { |e| dosub(e, flow_expression, workitem) }
75:
76: elsif text.is_a?(Hash)
77:
78: text.inject({}) do |r, (k, v)|
79:
80: r[dosub(k, flow_express, workitem)] =
81: dosub(v, flow_expression, workitem)
82: r
83: end
84:
85: else
86:
87: text
88: end
89: end
Returns true if the given string ends with the ‘_end’ string.
# File lib/openwfe/utils.rb, line 237
237: def OpenWFE.ends_with (string, _end)
238: return false unless string
239: return false if string.length < _end.length
240: string[-_end.length..-1] == _end
241: end
Returns a version of s that is usable as or within a filename (removes for examples things like ’/’ or ’\’…)
# File lib/openwfe/utils.rb, line 364
364: def OpenWFE.ensure_for_filename (s)
365:
366: s = s.gsub(" ", "_")
367: s = s.gsub("/", "_")
368: s = s.gsub(":", "_")
369: s = s.gsub(";", "_")
370: s = s.gsub("\*", "_")
371: s = s.gsub("\\", "_")
372: s = s.gsub("\+", "_")
373: s = s.gsub("\?", "_")
374:
375: s
376: end
Attempts at displaying a nice stack trace
# File lib/openwfe/utils.rb, line 246
246: def OpenWFE.exception_to_s (exception)
247: s = "exception : "
248: s << "#{exception}\n"
249: s << exception.backtrace.join("\n")
250: s
251: end
Returns the first subelt of xmlElt that matches the given xpath. If xpath is null, the first elt will be returned.
# File lib/openwfe/utils.rb, line 51
51: def OpenWFE.first_element (xmlElt, elementName=nil)
52:
53: return nil if not xmlElt
54:
55: return xmlElt.elements[1] if not elementName
56:
57: xmlElt.elements.detect { |elt| elt.name == elementName }
58: end
an automatic dup implementation attempt
# File lib/openwfe/utils.rb, line 80
80: def OpenWFE.fulldup (object)
81:
82: return nil if object == nil
83:
84: return object.fulldup if object.respond_to?("fulldup")
85: # trusting client objects providing a fulldup() implementation
86: # Tomaso Tosolini 2007.12.11
87:
88: return object if object.kind_of?(Float)
89: return object if object.kind_of?(Fixnum)
90: return object if object.kind_of?(TrueClass)
91: return object if object.kind_of?(FalseClass)
92: return object if object.kind_of?(Symbol)
93:
94: return object.dup if object.kind_of?(String)
95:
96: #return deep_clone(object) if object.kind_of? REXML::Document
97:
98: #return REXML::Document.new(object.to_s) # if object.kind_of? REXML::Document
99:
100: if object.kind_of?(REXML::Element)
101: d = REXML::Document.new object.to_s
102: return d if object.kind_of?(REXML::Document)
103: return d.root
104: end
105:
106: return Rational(object.denominator, object.numerator) \
107: if object.kind_of?(Rational)
108:
109: o = nil
110:
111: begin
112: o = object.class.new
113: rescue ArgumentError => ae
114: return deep_clone(object)
115: end
116:
117: #
118: # some kind of collection ?
119:
120: if object.kind_of?(Array)
121: object.each do |i|
122: o << fulldup(i)
123: end
124: elsif object.kind_of?(Hash)
125: object.each do |k, v|
126: o[fulldup(k)] = fulldup(v)
127: end
128: end
129:
130: #
131: # duplicate the attributes of the object
132:
133: object.instance_variables.each do |v|
134:
135: #puts "v is #{v}"
136:
137: value = object.instance_variable_get(v)
138:
139: #puts "value is '#{value}'"
140:
141: value = fulldup(value)
142:
143: begin
144: o.instance_variable_set(v, value)
145: rescue
146: # ignore, must be readonly
147: end
148: end
149:
150: o
151: end
# File lib/openwfe/workitem.rb, line 481
481: def OpenWFE.get_class (h)
482:
483: cl = h[:type]
484: return nil if cl.index(";")
485: return nil if cl.index(" ")
486: eval(cl)
487: end
Returns a list of lines matching the pattern in the given file.
This is also possible :
OpenWFE::grep "^..) ", "path/to/file.txt" do |line|
puts " - '#{line.downcase}'"
end
TODO : find a ruby library and use it instead of that code
# File lib/openwfe/utils.rb, line 441
441: def OpenWFE.grep (pattern, filepath, &block)
442:
443: result = []
444: r = Regexp.new pattern
445:
446: File.open filepath do |file|
447: file.readlines.each do |l|
448: if r.match l
449: if block
450: block.call l
451: else
452: result << l
453: end
454: end
455: end
456: end
457: result unless block
458: end
This method is used within the InFlowWorkItem and the CsvTable classes.
# File lib/openwfe/utils.rb, line 410
410: def OpenWFE.has_attribute? (container, key)
411:
412: key, last_key = pop_last_key(key)
413:
414: container = lookup_attribute(container, key) if key
415:
416: if container.respond_to?(:has_key?)
417:
418: (container.has_key?(last_key) or container.has_key?(last_key.to_s))
419:
420: elsif container.is_a?(Array) and last_key.is_a?(Fixnum)
421:
422: (last_key < container.length)
423:
424: else
425:
426: false
427: end
428: end
This method is used within the InFlowWorkItem and the CsvTable classes.
# File lib/openwfe/utils.rb, line 388
388: def OpenWFE.lookup_attribute (container, key)
389:
390: key, rest = pop_key(key)
391:
392: #value = nil
393: #begin
394: # value = container[key]
395: #rescue Exception => e
396: #end
397:
398: value = flex_lookup(container, key)
399:
400: return value unless rest
401:
402: return nil unless value
403:
404: lookup_attribute(value, rest)
405: end
# File lib/openwfe/utils.rb, line 169
169: def OpenWFE.name_to_symbol (name)
170:
171: return name if name.is_a?(Symbol)
172: to_underscore(name).intern
173: end
Returns a URI instance if the given ref is a http, https, file or ftp URI. Returns nil else. The sister method parse_uri() is OK with things like mailto:, gopher:, …
# File lib/openwfe/utils.rb, line 205
205: def OpenWFE.parse_known_uri (ref)
206:
207: uri = OpenWFE::parse_uri(ref.to_s)
208:
209: return nil unless uri
210:
211: return uri if uri.scheme == "file"
212: return uri if uri.scheme == "http"
213: return uri if uri.scheme == "https"
214: return uri if uri.scheme == "ftp"
215: # what else ...
216:
217: nil
218: end
Returns an URI if the string is one, else returns nil. No exception is thrown by this method.
# File lib/openwfe/utils.rb, line 188
188: def OpenWFE.parse_uri (string)
189:
190: return nil if string.split("\n").size > 1
191:
192: begin
193: return URI::parse(string)
194: rescue Exception => e
195: end
196:
197: nil
198: end
Renders a nice, terminal oriented, representation of an Engine.get_process_status() result.
You usually directly benefit from this when doing
puts engine.get_process_status.to_s
# File lib/openwfe/engine/status_methods.rb, line 241
241: def OpenWFE.pretty_print_process_status (ps)
242:
243: # TODO : include launch_time and why is process_id so long ?
244:
245: s = ""
246: s << "process_id | name | rev | brn | err | paused? \n"
247: s << "--------------------+-------------------+---------+-----+-----+---------\n"
248:
249: ps.keys.sort.each do |wfid|
250:
251: status = ps[wfid]
252: fexp = status.expressions.first
253: ffei = fexp.fei
254:
255: s << "%-19s" % wfid[0, 19]
256: s << " | "
257: s << "%-17s" % ffei.workflow_definition_name[0, 17]
258: s << " | "
259: s << "%-7s" % ffei.workflow_definition_revision[0, 7]
260: s << " | "
261: s << "%3s" % status.expressions.size.to_s[0, 3]
262: s << " | "
263: s << "%3s" % status.errors.size.to_s[0, 3]
264: s << " | "
265: s << "%5s" % status.paused?.to_s
266: s << "\n"
267: end
268: s
269: end
This method is used within the InFlowWorkItem and the CsvTable classes.
# File lib/openwfe/utils.rb, line 463
463: def OpenWFE.set_attribute (container, key, value)
464:
465: i = key.rindex(".")
466:
467: if not i
468: container[key] = value
469: return
470: end
471:
472: container = lookup_attribute(container, key[0..i-1])
473: container[key[i+1..-1]] = value
474: end
Sets the name of the current thread (the attribute :name if it is a ruby thread, the java thread name if we‘re in JRuby)
# File lib/openwfe/utils.rb, line 269
269: def OpenWFE.set_current_thread_name (name)
270: if defined?(JRUBY_VERSION)
271: require 'java'
272: java.lang.Thread.current_thread.name = "#{name} (Ruby Thread)"
273: else
274: Thread.current[:name] = name
275: end
276: end
This method should be able to split any wfid whose scheme is implemented here.
# File lib/openwfe/expool/wfidgen.rb, line 376
376: def OpenWFE.split_wfid (wfid)
377:
378: SPLIT_MAP.each do |regex, clazz|
379: return clazz.split_wfid(wfid) if wfid.match(regex)
380: end
381: #
382: # else
383: #
384: DefaultWfidGenerator.split_wfid(wfid)
385: end
Returns true if the given string starts with the ‘start’ string.
# File lib/openwfe/utils.rb, line 223
223: def OpenWFE.starts_with (string, start)
224: #
225: # my favourite way of doing that would be by adding this
226: # method to the String class, but that could be intrusive
227: # (as OpenWFE is meant at first as an embeddable workflow engine).
228: #
229: return false unless string
230: return false if string.length < start.length
231: string[0, start.length] == start
232: end
Turns all the spaces in string into underscores. Returns the new String.
# File lib/openwfe/utils.rb, line 179
179: def OpenWFE.stu (s)
180:
181: s.gsub("\s", "_")
182: end
# File lib/openwfe/utils.rb, line 164
164: def OpenWFE.symbol_to_name (symbol)
165:
166: to_dash(symbol.to_s)
167: end
# File lib/openwfe/utils.rb, line 159
159: def OpenWFE.to_dash (string)
160:
161: string.gsub("_", "-")
162: end
# File lib/openwfe/utils.rb, line 154
154: def OpenWFE.to_underscore (string)
155:
156: string.gsub("-", "_")
157: end
Binds the SIGINT signal so that a console is opened with the bindings specified in ‘args’.
# File lib/openwfe/util/irb.rb, line 57
57: def OpenWFE.trap_int_irb (*args)
58: trap 'INT' do
59: OpenWFE.start_irb_session(*args)
60: #OpenWFE.trap_int_irb(*args) if $openwfe_irb
61: OpenWFE.trap_int_irb(*args)
62: end
63: end
This method is used within the InFlowWorkItem and the CsvTable classes.
# File lib/openwfe/utils.rb, line 479
479: def OpenWFE.unset_attribute (container, key)
480:
481: i = key.rindex(".")
482:
483: if not i
484: container.delete key
485: return
486: end
487:
488: container = lookup_attribute container, key[0..i-1]
489:
490: if container.is_a?(Array)
491:
492: container.delete_at key[i+1..-1].to_i
493: else
494:
495: container.delete key[i+1..-1]
496: end
497: end
Turns a hash into its corresponding workitem (InFlowWorkItem, CancelItem, LaunchItem).
# File lib/openwfe/workitem.rb, line 474
474: def OpenWFE.workitem_from_h (h)
475:
476: #wi_class = eval(h[:type])
477: wi_class = get_class(h)
478: wi_class.from_h(h)
479: end
An alias for OpenWFE::xmldoc_to_string()
# File lib/openwfe/orest/xmlcodec.rb, line 649
649: def OpenWFE.xml_to_s (xml, decl=true)
650:
651: OpenWFE::xmldoc_to_string(xml, decl)
652: end
Just turns some XML to a String (if decl is set to false, no XML declaration will be printed).
# File lib/openwfe/orest/xmlcodec.rb, line 633
633: def OpenWFE.xmldoc_to_string (xml, decl=true)
634:
635: #return xml if xml.is_a?(String)
636:
637: xml << REXML::XMLDecl.new \
638: if decl and (not xml[0].is_a?(REXML::XMLDecl))
639:
640: #s = ""
641: #xml.write(s, 0)
642: #return s
643: xml.to_s
644: end
looks up in a container (something that has a [] method) with a key, if nothing has been found and the key is a number, turns the the number into a String a does a last lookup.
# File lib/openwfe/utils.rb, line 541
541: def OpenWFE.flex_lookup (container, key)
542:
543: value = nil
544:
545: begin
546: value = container[key]
547: rescue Exception => e
548: end
549:
550: if value == nil and key.kind_of?(Fixnum)
551: begin
552: value = container[key.to_s]
553: rescue Exception => e
554: end
555: end
556:
557: value
558: end
# File lib/openwfe/utils.rb, line 529
529: def OpenWFE.narrow (key)
530: return 0 if key == "0"
531: i = key.to_i
532: return i if i != 0
533: key
534: end
# File lib/openwfe/utils.rb, line 517
517: def OpenWFE.pop_key (key)
518: i = key.index(".")
519: return narrow(key), nil unless i
520: [ narrow(key[0..i-1]), key[i+1..-1] ]
521: end
# File lib/openwfe/utils.rb, line 523
523: def OpenWFE.pop_last_key (key)
524: i = key.rindex(".")
525: return nil, narrow(key) unless i
526: [ key[0..i-1], narrow(key[i+1..-1]) ]
527: end
# File lib/openwfe/util/irb.rb, line 67
67: def OpenWFE.start_irb_session (*args)
68:
69: IRB::setup nil unless $openwfe_irb
70:
71: ws = IRB::WorkSpace.new *args
72:
73: $openwfe_irb = IRB::Irb.new ws
74:
75: IRB::conf[:MAIN_CONTEXT] = $openwfe_irb.context
76:
77: trap 'INT' do
78: $openwfe_irb.signal_handle
79: end
80:
81: $openwfe_irb.eval_input
82:
83: puts "\nbye!"
84: end
Returns true if this host is currently online (has access to the web / internet).
# File lib/openwfe/utils.rb, line 503
503: def online?
504:
505: require 'open-uri'
506:
507: begin
508: open("http://www.openwfe.org")
509: true
510: rescue SocketError => se
511: false
512: end
513: end
# File lib/openwfe/tools/flowtracer.rb, line 50
50: def trace_flow (process_definition)
51:
52: li = LaunchItem.new process_definition
53:
54: engine = Engine.new
55:
56: i = 0
57:
58: engine.register_participant(".*") do |workitem|
59:
60: puts "-- #{i} ------------------------------------------------------------------------"
61: puts
62: puts " participant '#{workitem.participant_name}' received workitem :"
63: puts
64: puts workitem.to_s
65: puts
66: puts "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
67: puts
68: puts " expression pool state :"
69: #puts
70: puts engine.get_expression_storage.to_s
71: puts
72: #puts
73:
74: i = i + 1
75: end
76:
77: engine.launch li
78: end