#
#
# Copyright (c) 2005-2006, John Mettraux, OpenWFE.org
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# . Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# . Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# $Id: codec.rb 2865 2006-06-23 14:54:07Z jmettraux $
#
#
# "hecho en Costa Rica"
#
#require 'base64'
require 'rexml/document'
require 'definitions'
require 'utils'
require 'workitem'
module OpenWFE
#
# Takes as input some XML element and returns is decoded (as an instance)
#
def OpenWFE.decode (xmlElt)
return nil if not xmlElt
#puts "decode() xmlElt.name is >#{xmlElt.name}<"
return decodeList(xmlElt) if xmlElt.name == STORES
return decodeStore(xmlElt) if xmlElt.name == STORE
return decodeList(xmlElt) if xmlElt.name == HEADERS
return decodeHeader(xmlElt) if xmlElt.name == HEADER
return decodeLaunchOk(xmlElt) if xmlElt.name == OK
return decodeList(xmlElt) if xmlElt.name == HISTORY
return decodeHistoryItem(xmlElt) if xmlElt.name == HISTORY_ITEM
return decodeList(xmlElt) \
if xmlElt.name == FLOW_EXPRESSION_IDS
return decodeFlowExpressionId(xmlElt) \
if xmlElt.name == FLOW_EXPRESSION_ID
return decodeInFlowWorkItem(xmlElt) \
if xmlElt.name == IN_FLOW_WORKITEM
return decodeList(xmlElt) if xmlElt.name == LAUNCHABLES
return decodeLaunchable(xmlElt) if xmlElt.name == LAUNCHABLE
return decodeList(xmlElt) if xmlElt.name == EXPRESSIONS
return decodeExpression(xmlElt) if xmlElt.name == EXPRESSION
return decodeAttribute(xmlElt.elements[1]) if xmlElt.name == ATTRIBUTES
#
# default
return decodeAttribute(xmlElt)
#raise \
# ArgumentException, \
# "Cannot decode : '"+xmlElt.name+"' "+xmlElt.to_s()
end
#
# Takes some OpenWFE Ruby instance and returns it as XML
#
def OpenWFE.encode (owfeData)
#puts "encode() #{owfeData.inspect}"
return encodeLaunchItem(owfeData) \
if owfeData.kind_of?(LaunchItem)
return encodeFlowExpressionId(owfeData) \
if owfeData.kind_of?(FlowExpressionId)
return encodeInFlowWorkItem(owfeData) \
if owfeData.kind_of?(InFlowWorkItem)
raise \
ArgumentException, \
"Cannot encode : "+owfeData.inspect()
end
private
#
# DECODE
#
def OpenWFE.decodeList (xmlElt)
l = []
xmlElt.elements.each do |elt|
#puts " ... #{elt.inspect()}"
l.push(decode(elt))
end
return l
end
def OpenWFE.decodeLaunchable (xmlElt)
launchable = Launchable.new()
launchable.url = xmlElt.attributes[URL]
launchable.engineId = xmlElt.attributes[ENGINE_ID]
return launchable
end
def OpenWFE.decodeExpression (xmlElt)
exp = Expression.new()
#exp.id = decode(firstElement(xmlElt, "//"+FLOW_EXPRESSION_ID))
exp.id = decode(firstElement(xmlElt))
exp.applyTime = xmlElt.attributes[APPLY_TIME]
exp.state = xmlElt.attributes[STATE]
exp.stateSince = xmlElt.attributes[STATE_SINCE]
return exp
end
def OpenWFE.decodeStore (xmlElt)
store = Store.new()
store.name = xmlElt.attributes[NAME]
store.workitemCount = xmlElt.attributes[WORKITEM_COUNT]
store.workitemCount = Integer(store.workitemCount)
store.permissions = xmlElt.attributes[PERMISSIONS]
return store
end
def OpenWFE.decodeHeader (xmlElt)
header = Header.new()
header.lastModified = xmlElt.attributes[A_LAST_MODIFIED]
header.locked = parseBoolean(xmlElt.attributes[A_LOCKED])
header.flowExpressionId = decode(firstElement(xmlElt, FLOW_EXPRESSION_ID))
header.attributes = decode(firstElement(xmlElt, ATTRIBUTES))
return header
end
def OpenWFE.decodeFlowExpressionId (xmlElt)
fei = FlowExpressionId.new()
fei.owfeVersion = xmlElt.attributes[OWFE_VERSION]
fei.engineId = xmlElt.attributes[ENGINE_ID]
fei.initialEngineId = xmlElt.attributes[INITIAL_ENGINE_ID]
fei.workflowDefinitionUrl = xmlElt.attributes[WORKFLOW_DEFINITION_URL]
fei.workflowDefinitionName = xmlElt.attributes[WORKFLOW_DEFINITION_NAME]
fei.workflowDefinitionRevision = xmlElt.attributes[WORKFLOW_DEFINITION_REVISION]
fei.workflowInstanceId = xmlElt.attributes[WORKFLOW_INSTANCE_ID]
fei.expressionName = xmlElt.attributes[EXPRESSION_NAME]
fei.expressionId = xmlElt.attributes[EXPRESSION_ID]
#puts " ... fei.expressionName is >#{fei.expressionName}<"
#puts " ... fei.wfid is >#{fei.workflowInstanceId}<"
return fei
end
def OpenWFE.decodeAttribute (xmlElt)
#puts "decodeAttribute() '#{xmlElt.name}' --> '#{xmlElt.text}'"
#
# atomic types
return xmlElt.text if xmlElt.name == E_STRING
return Integer(xmlElt.text) if xmlElt.name == E_INTEGER
return Integer(xmlElt.text) if xmlElt.name == E_LONG
return Float(xmlElt.text) if xmlElt.name == E_DOUBLE
return parseBoolean(xmlElt.text) if xmlElt.name == E_BOOLEAN
return xmlElt if xmlElt.name == E_XML
return Base64Attribute.new(xmlElt.txt) if xmlElt.name == E_BASE64
#
# composite types
return decodeList(xmlElt) if xmlElt.name == E_LIST
if xmlElt.name == E_SMAP or xmlElt.name == E_MAP
map = {}
map[MAP_TYPE] = xmlElt.name
#xmlElt.elements.each("//"+M_ENTRY) do |e|
xmlElt.elements.each(M_ENTRY) do |e|
#puts "decodeAttribute() >#{e}<"
decodeEntry(e, map)
end
return map
end
#puts docToString(xmlElt.document())
raise \
ArgumentError, \
"Cannot decode <#{xmlElt.name}/> in \n"+\
docToString(xmlElt.document())
end
def OpenWFE.decodeEntry (xmlElt, map)
key = xmlElt.elements[1]
val = xmlElt.elements[2]
#
# this parse method supports the old style and the [new] light
# style/schema
#
key = key.elements[1] if key.name == M_KEY
val = val.elements[1] if val.name == M_VALUE
key = decode(key)
val = decode(val)
#puts "decodeEntry() k >#{key}< v >#{val}<"
#puts "decodeEntry() subject '#{val}'" if key == '__subject__'
map[key] = val
end
def OpenWFE.parseBoolean (string)
return string.strip.downcase == 'true'
end
def OpenWFE.decodeHistoryItem (xmlElt)
hi = HistoryItem.new
hi.author = xmlElt.attributes[A_AUTHOR]
hi.date = xmlElt.attributes[A_DATE]
hi.host = xmlElt.attributes[A_HOST]
hi.text = xmlElt.text
hi.wfdName = xmlElt.attributes[WORKFLOW_DEFINITION_NAME]
hi.wfdRevision = xmlElt.attributes[WORKFLOW_DEFINITION_REVISION]
hi.wfInstanceId = xmlElt.attributes[WORKFLOW_INSTANCE_ID]
hi.expressionId = xmlElt.attributes[EXPRESSION_ID]
return hi
end
def OpenWFE.decodeLaunchOk (xmlElt)
sFei = xmlElt.attributes[A_FLOW_ID]
return true if not sFei
return FlowExpressionId.strToFei(sFei)
end
def OpenWFE.decodeInFlowWorkItem (xmlElt)
wi = InFlowWorkItem.new()
wi.lastModified = xmlElt.attributes[A_LAST_MODIFIED]
wi.attributes = decode(firstElement(xmlElt, ATTRIBUTES))
wi.participantName = xmlElt.attributes[A_PARTICIPANT_NAME]
wi.flowExpressionId = decode(firstElement(firstElement(xmlElt, E_LAST_EXPRESSION_ID), FLOW_EXPRESSION_ID))
wi.dispatchTime = xmlElt.attributes[A_DISPATCH_TIME]
# TODO : decode filter
wi.history = decode(firstElement(xmlElt, HISTORY))
return wi
end
#
# ENCODE
#
def OpenWFE.docToString (xml, decl=true)
s = ""
if decl and xml[0].kind_of? REXML::XMLDecl
xml << REXML::XMLDecl.new()
end
xml.write(s, 0)
return s
end
def OpenWFE.encodeItem (item, elt)
elt.attributes[A_LAST_MODIFIED] = item.lastModified
eAttributes = REXML::Element.new(ATTRIBUTES)
eAttributes << encodeAttribute(item.attributes)
elt << eAttributes
end
def OpenWFE.encodeLaunchItem (launchitem)
doc = REXML::Document.new()
root = REXML::Element.new(E_LAUNCHITEM)
encodeItem(launchitem, root)
root.attributes[WORKFLOW_DEFINITION_URL] = \
launchitem.workflowDefinitionUrl
# TODO :
#
# - encode descriptionMap
#
# - replyTo is not necessary
#doc.root = root
doc << root
return docToString(doc)
end
def OpenWFE.encodeInFlowItem (item, elt)
encodeItem(item, elt)
elt.attributes[A_PARTICIPANT_NAME] = item.participantName
eLastExpressionId = REXML::Element.new(E_LAST_EXPRESSION_ID)
eLastExpressionId << encodeFlowExpressionId(item.lastExpressionId)
elt << eLastExpressionId
end
def OpenWFE.encodeInFlowWorkItem (item)
doc = REXML::Document.new()
root = REXML::Element.new(IN_FLOW_WORKITEM)
encodeInFlowItem(item, root)
root.attributes[A_DISPATCH_TIME] = item.dispatchTime
# add filter ? no
encodeHistory(item, root)
doc << root
s = docToString(doc)
#puts "encoded :\n#{s}"
return s
end
def OpenWFE.encodeHistory (item, elt)
eHistory = REXML::Element.new(HISTORY)
item.history.each do |hi|
ehi = REXML::Element.new(HISTORY_ITEM)
ehi.attributes[A_AUTHOR] = hi.author
ehi.attributes[A_DATE] = hi.date
ehi.attributes[A_HOST] = hi.host
ehi.attributes[WORKFLOW_DEFINITION_NAME] = hi.wfdName
ehi.attributes[WORKFLOW_DEFINITION_REVISION] = hi.wfdRevision
ehi.attributes[WORKFLOW_INSTANCE_ID] = hi.wfInstanceId
ehi.attributes[EXPRESSION_ID] = hi.expressionId
eHistory << ehi
end
elt << eHistory
end
def OpenWFE.encodeAttribute (att)
#puts "encodeAttribute() att.class is #{att.class}"
return encodeAtomicAttribute(E_STRING, att) \
if att.kind_of? String
return encodeAtomicAttribute(E_INTEGER, att) \
if att.kind_of? Fixnum
return encodeAtomicAttribute(E_DOUBLE, att) \
if att.kind_of? Float
return encodeXmlAttribute(att) \
if att.kind_of? REXML::Element
return encodeAtomicAttribute(E_BOOLEAN, true) \
if att.kind_of? TrueClass
return encodeAtomicAttribute(E_BOOLEAN, false) \
if att.kind_of? FalseClass
return encodeBase64Attribute(att) \
if att.kind_of? Base64Attribute
#
# missing : BASE64...
return encodeMapAttribute(att) if att.kind_of? Hash
return encodeListAttribute(att) if att.kind_of? Array
#
# default
return encodeAtomicAttribute(E_STRING, att)
#raise \
# ArgumentException, \
# "Cannot encode attribute of class '#{att.class}'"
end
def OpenWFE.encodeXmlAttribute (elt)
return elt if elt.name == E_XML
#
# else, wrap within ...
e = REXML::Element.new(E_XML)
e << elt
return e
end
def OpenWFE.encodeBase64Attribute (att)
e = REXML::Element.new(E_BASE64)
e.text = att.content
return e
end
def OpenWFE.encodeAtomicAttribute (name, value)
elt = REXML::Element.new(name)
#elt << REXML::Text.new(value.to_s())
elt.add_text(value.to_s())
return elt
end
def OpenWFE.encodeListAttribute (list)
elt = REXML::Element.new(E_LIST)
list.each do |e|
elt << encodeAttribute(e)
end
return elt
end
def OpenWFE.encodeMapAttribute (hash)
name = hash[MAP_TYPE]
name = 'map' if name == nil
elt = REXML::Element.new(name)
hash.each_key do |key|
next if key == MAP_TYPE
eEntry = REXML::Element.new(M_ENTRY)
val = hash[key]
eEntry << encodeAttribute(key)
eEntry << encodeAttribute(val)
elt << eEntry
end
return elt
end
def OpenWFE.encodeFlowExpressionId (fei)
elt = REXML::Element.new(FLOW_EXPRESSION_ID)
elt.attributes[OWFE_VERSION] = fei.owfeVersion
elt.attributes[ENGINE_ID] = fei.engineId
elt.attributes[INITIAL_ENGINE_ID] = fei.initialEngineId
elt.attributes[WORKFLOW_DEFINITION_URL] = fei.workflowDefinitionUrl
elt.attributes[WORKFLOW_DEFINITION_NAME] = fei.workflowDefinitionName
elt.attributes[WORKFLOW_DEFINITION_REVISION] = fei.workflowDefinitionRevision
elt.attributes[WORKFLOW_INSTANCE_ID] = fei.workflowInstanceId
elt.attributes[EXPRESSION_NAME] = fei.expressionName
elt.attributes[EXPRESSION_ID] = fei.expressionId
return elt
end
end