1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/soap/baseData.rb: Introduce SOAPType as the common ancestor of

SOAPBasetype and SOAPCompoundtype.

* lib/soap/generator.rb, lib/soap/element.rb, lib/soap/encodingstyle/*:
  Encoding methods signature change.  Pass SOAPGenerator as a parameter.

* lib/soap/mapping/*, test/soap/marshal/test_marshal.rb: Refactoring for better
  marshalling/unmarshalling support.  Now I think SOAP marshaller supports all
  kind of object graph which is supported by Ruby's original marshaller.  Of
  course there could be bugs as always.  Find it.  :-)

* lib/soap/rpc/standaloneServer.rb: Set severity threshould to INFO.  DEBUG is
  too noisy.

* lib/xsd/datatypes.rb: DateTime#of is obsoleted.  Use DateTime#offset.

* test/wsdl/emptycomplextype.wsdl, test/xsd/xmlschema.xml: Avoid useless
  warning.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4760 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nahi 2003-10-14 15:14:02 +00:00
parent 0b841783b5
commit 9cba39a1a1
21 changed files with 716 additions and 402 deletions

View file

@ -40,10 +40,17 @@ public
end
###
## Marker of SOAP/DM types.
#
module SOAPType; end
###
## Mix-in module for SOAP base type instances.
#
module SOAPBasetype
include SOAPType
include SOAP
attr_accessor :encodingstyle
@ -75,6 +82,7 @@ end
## Mix-in module for SOAP compound type instances.
#
module SOAPCompoundtype
include SOAPType
include SOAP
attr_accessor :encodingstyle
@ -168,7 +176,7 @@ public
d
end
def SOAPReference.create_refid(obj)
def self.create_refid(obj)
'id' << obj.__id__.to_s
end
end
@ -597,7 +605,7 @@ public
data = retrieve(idxary[0, idxary.size - 1])
data[idxary.last] = value
if value.is_a?(SOAPBasetype) || value.is_a?(SOAPCompoundtype)
if value.is_a?(SOAPType)
value.elename = value.elename.dup_name('item')
# Sync type

View file

@ -84,17 +84,17 @@ public
end
end
def encode(buf, ns, attrs = {}, indent = '')
def encode(generator, ns, attrs = {})
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
yield(self.faultcode, false)
yield(self.faultstring, false)
yield(self.faultactor, false)
yield(self.detail, false) if self.detail
SOAPGenerator.encode_tag_end(buf, name, indent, true)
generator.encode_tag_end(name, true)
end
end
@ -112,9 +112,9 @@ public
@is_fault = is_fault
end
def encode(buf, ns, attrs = {}, indent = '')
def encode(generator, ns, attrs = {})
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
if @is_fault
yield(@data, true)
else
@ -122,7 +122,7 @@ public
yield(data, true)
end
end
SOAPGenerator.encode_tag_end(buf, name, indent, true)
generator.encode_tag_end(name, true)
end
def root_node
@ -160,7 +160,7 @@ public
@encodingstyle = encodingstyle || LiteralNamespace
end
def encode(buf, ns, attrs = {}, indent = '')
def encode(generator, ns, attrs = {})
attrs.each do |key, value|
@content.attr[key] = value
end
@ -185,13 +185,13 @@ class SOAPHeader < SOAPArray
@encodingstyle = nil
end
def encode(buf, ns, attrs = {}, indent = '')
def encode(generator, ns, attrs = {})
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
@data.each do |data|
yield(data, true)
end
SOAPGenerator.encode_tag_end(buf, name, indent, true)
generator.encode_tag_end(name, true)
end
def length
@ -215,16 +215,16 @@ class SOAPEnvelope < XSD::NSDBase
@body = body
end
def encode(buf, ns, attrs = {}, indent = '')
def encode(generator, ns, attrs = {})
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace,
SOAPNamespaceTag)
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
yield(@header, true) if @header and @header.length > 0
yield(@body, true)
SOAPGenerator.encode_tag_end(buf, name, indent, true)
generator.encode_tag_end(name, true)
end
end

View file

@ -38,7 +38,7 @@ class ASPDotNetHandler < Handler
###
## encode interface.
#
def encode_data(buf, ns, qualified, data, parent, indent = '')
def encode_data(generator, ns, qualified, data, parent)
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
@ -49,17 +49,16 @@ class ASPDotNetHandler < Handler
case data
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.each do |key, value|
if !value.elename.namespace
value.elename.namespace = data.elename.namespace
@ -67,7 +66,7 @@ class ASPDotNetHandler < Handler
yield(value, true)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = nil
yield(child, true)
@ -78,14 +77,14 @@ yle.")
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent = "")
def encode_data_end(generator, ns, qualified, data, parent)
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
cr = data.is_a?(SOAPCompoundtype)
SOAPGenerator.encode_tag_end(buf, name, indent, cr)
generator.encode_tag_end(name, cr)
end

View file

@ -69,11 +69,11 @@ class Handler
## encode interface.
#
# Returns a XML instance as a string.
def encode_data(buf, ns, qualified, data, parent, indent)
def encode_data(generator, ns, qualified, data, parent)
raise NotImplementError.new('Method encode_data must be defined in derived class.')
end
def encode_data_end(buf, ns, qualified, data, parent, indent)
def encode_data_end(generator, ns, qualified, data, parent)
raise NotImplementError.new('Method encode_data must be defined in derived class.')
end

View file

@ -37,7 +37,7 @@ class LiteralHandler < Handler
###
## encode interface.
#
def encode_data(buf, ns, qualified, data, parent, indent = '')
def encode_data(generator, ns, qualified, data, parent)
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
@ -48,31 +48,29 @@ class LiteralHandler < Handler
case data
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.each do |key, value|
value.elename.namespace = data.elename.namespace if !value.elename.namespace
yield(value, true)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = nil
yield(child, true)
end
when SOAPElement
SOAPGenerator.encode_tag(buf, name, attrs.update(data.extraattr),
indent)
buf << data.text if data.text
generator.encode_tag(name, attrs.update(data.extraattr))
generator.encode_rawstring(data.text) if data.text
data.each do |key, value|
value.elename.namespace = data.elename.namespace if !value.elename.namespace
#yield(value, data.qualified)
@ -83,13 +81,13 @@ class LiteralHandler < Handler
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent)
def encode_data_end(generator, ns, qualified, data, parent)
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
SOAPGenerator.encode_tag_end(buf, name, indent)
generator.encode_tag_end(name)
end

View file

@ -40,8 +40,8 @@ class SOAPHandler < Handler
###
## encode interface.
#
def encode_data(buf, ns, qualified, data, parent, indent = '')
attrs = encode_attrs(ns, qualified, data, parent)
def encode_data(generator, ns, qualified, data, parent)
attrs = encode_attrs(generator, ns, data, parent)
if parent && parent.is_a?(SOAPArray) && parent.position
attrs[ns.name(AttrPositionName)] = '[' << parent.position.join(',') << ']'
@ -55,32 +55,26 @@ class SOAPHandler < Handler
name = data.elename.name
end
if data.respond_to?(:encode)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
return data.encode(buf, ns, attrs, indent)
end
case data
when SOAPReference
attrs['href'] = '#' << data.refid
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.each do |key, value|
yield(value, false)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = data.sparse ? rank : nil
yield(child, false)
@ -91,14 +85,14 @@ class SOAPHandler < Handler
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent = '')
def encode_data_end(generator, ns, qualified, data, parent)
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
cr = data.is_a?(SOAPCompoundtype)
SOAPGenerator.encode_tag_end(buf, name, indent, cr)
generator.encode_tag_end(name, cr)
end
@ -292,7 +286,7 @@ private
content_typename(data.arytype.name) << '[' << data.size.join(',') << ']')
end
def encode_attrs(ns, qualified, data, parent)
def encode_attrs(generator, ns, data, parent)
return {} if data.is_a?(SOAPReference)
attrs = {}
@ -330,7 +324,7 @@ private
data.extraattr.each do |key, value|
SOAPGenerator.assign_ns(attrs, ns, key.namespace)
attrs[ns.name(key)] = value # ns.name(value) ?
attrs[ns.name(key)] = encode_attr_value(generator, ns, key, value)
end
if data.id
attrs['id'] = data.id
@ -338,6 +332,17 @@ private
attrs
end
def encode_attr_value(generator, ns, qname, value)
if value.is_a?(SOAPType)
refid = SOAPReference.create_refid(value)
value.id = refid
generator.add_reftarget(qname.name, value)
'#' + refid
else
value.to_s
end
end
def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr)
if parent.class == SOAPBody
# Unqualified name is allowed here.
@ -423,11 +428,13 @@ private
end
if (klass = TypeMap[type])
klass.decode(elename)
else
# Unknown type... Struct or String
SOAPUnknown.new(self, elename, type, extraattr)
node = klass.decode(elename)
node.extraattr.update(extraattr)
return node
end
# Unknown type... Struct or String
SOAPUnknown.new(self, elename, type, extraattr)
end
def decode_textbuf(node)
@ -508,12 +515,22 @@ private
id = value
next
end
extraattr[qname] = value
extraattr[qname] = decode_attr_value(ns, qname, value)
end
return is_nil, type, arytype, root, offset, position, href, id, extraattr
end
def decode_attr_value(ns, qname, value)
if /\A#/ =~ value
o = SOAPReference.new(value)
@refpool << o
o
else
value
end
end
def decode_arypos(position)
/^\[(.+)\]$/ =~ position
$1.split(',').collect { |s| s.to_i }
@ -524,7 +541,7 @@ private
while !@refpool.empty? && count > 0
@refpool = @refpool.find_all { |ref|
o = @idpool.find { |item|
('#' << item.id == ref.refid)
'#' + item.id == ref.refid
}
unless o
raise EncodingStyleError.new("Unresolved reference: #{ ref.refid }.")

View file

@ -39,7 +39,6 @@ public
attr_accessor :charset
attr_accessor :default_encodingstyle
attr_accessor :generate_explicit_type
attr_accessor :pretty
def initialize(opt = {})
@reftarget = nil
@ -48,37 +47,38 @@ public
@default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
@generate_explicit_type =
opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true
@pretty = true # opt[:pretty]
@buf = @indent = @curr = nil
end
def generate(obj, io = nil)
@buf = io || ''
@indent = ''
prologue
@handlers.each do |uri, handler|
handler.encode_prologue
end
io = '' if io.nil?
ns = XSD::NS.new
io << xmldecl
encode_data(io, ns, true, obj, nil, 0)
@buf << xmldecl
encode_data(ns, true, obj, nil)
@handlers.each do |uri, handler|
handler.encode_epilogue
end
epilogue
io
@buf
end
def encode_data(buf, ns, qualified, obj, parent, indent)
def encode_data(ns, qualified, obj, parent)
if obj.is_a?(SOAPEnvelopeElement)
encode_element(buf, ns, qualified, obj, parent, indent)
encode_element(ns, qualified, obj, parent)
return
end
if @reftarget && !obj.precedents.empty?
@reftarget.add(obj.elename.name, obj)
add_reftarget(obj.elename.name, obj)
ref = SOAPReference.new
ref.elename.name = obj.elename.name
ref.__setobj__(obj)
@ -102,22 +102,29 @@ public
raise FormatEncodeError.new("Element name not defined: #{ obj }.")
end
indent_str = ' ' * indent
child_indent = @pretty ? indent + 2 : indent
handler.encode_data(buf, ns, qualified, obj, parent, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
handler.encode_data(self, ns, qualified, obj, parent) do |child, child_q|
indent_backup, @indent = @indent, @indent + ' '
encode_data(ns.clone_ns, child_q, child, obj)
@indent = indent_backup
end
handler.encode_data_end(buf, ns, qualified, obj, parent, indent_str)
handler.encode_data_end(self, ns, qualified, obj, parent)
end
def encode_element(buf, ns, qualified, obj, parent, indent)
indent_str = ' ' * indent
child_indent = @pretty ? indent + 2 : indent
def add_reftarget(name, node)
unless @reftarget
raise FormatEncodeError.new("Reftarget is not defined.")
end
@reftarget.add(name, node)
end
def encode_element(ns, qualified, obj, parent)
attrs = {}
if obj.is_a?(SOAPBody)
@reftarget = obj
obj.encode(buf, ns, attrs, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
obj.encode(self, ns, attrs) do |child, child_q|
indent_backup, @indent = @indent, @indent + ' '
encode_data(ns.clone_ns, child_q, child, obj)
@indent = indent_backup
end
@reftarget = nil
else
@ -129,39 +136,38 @@ public
SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag)
end
end
obj.encode(buf, ns, attrs, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
obj.encode(self, ns, attrs) do |child, child_q|
indent_backup, @indent = @indent, @indent + ' '
encode_data(ns.clone_ns, child_q, child, obj)
@indent = indent_backup
end
end
end
def self.assign_ns(attrs, ns, namespace, tag = nil)
unless ns.assigned?(namespace)
tag = ns.assign(namespace, tag)
attrs['xmlns:' << tag] = namespace
end
end
def self.encode_tag(buf, elename, attrs = nil, indent = '')
def encode_tag(elename, attrs = nil)
if attrs
buf << "\n#{ indent }<#{ elename }" <<
@buf << "\n#{ @indent }<#{ elename }" <<
attrs.collect { |key, value|
%Q[ #{ key }="#{ value }"]
}.join <<
'>'
else
buf << "\n#{ indent }<#{ elename }>"
@buf << "\n#{ @indent }<#{ elename }>"
end
end
def self.encode_tag_end(buf, elename, indent = '', cr = nil)
def encode_tag_end(elename, cr = nil)
if cr
buf << "\n#{ indent }</#{ elename }>"
@buf << "\n#{ @indent }</#{ elename }>"
else
buf << "</#{ elename }>"
@buf << "</#{ elename }>"
end
end
def encode_rawstring(str)
@buf << str
end
EncodeMap = {
'&' => '&amp;',
'<' => '&lt;',
@ -171,8 +177,15 @@ public
"\r" => '&#xd;'
}
EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]")
def self.encode_str(str)
str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] }
def encode_string(str)
@buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] }
end
def self.assign_ns(attrs, ns, namespace, tag = nil)
if namespace and !ns.assigned?(namespace)
tag = ns.assign(namespace, tag)
attrs['xmlns:' << tag] = namespace
end
end
private

View file

@ -24,6 +24,10 @@ module Mapping
class Factory
include TraverseSupport
def initialize
# nothing to do
end
def obj2soap(soap_class, obj, info, map)
raise NotImplementError.new
# return soap_obj
@ -48,24 +52,13 @@ class Factory
end
end
def set_instance_vars(obj, values)
values.each do |name, value|
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_eval("@#{ name } = value")
end
end
end
def setiv2obj(obj, node, map)
return if node.nil?
vars = {}
node.each do |name, value|
vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
set_instance_vars(obj, vars)
Mapping.set_instance_vars(obj, vars)
end
def setiv2soap(node, obj, map)
@ -76,13 +69,6 @@ class Factory
end
end
def addiv2soap(node, obj, map)
return if obj.instance_variables.empty?
ivars = SOAPStruct.new # Undefined type.
setiv2soap(ivars, obj, map)
node.add('ivars', ivars)
end
# It breaks Thread.current[:SOAPMarshalDataKey].
def mark_marshalled_obj(obj, soap_obj)
Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
@ -103,14 +89,21 @@ class Factory
end
class StringFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
begin
if XSD::Charset.is_ces(obj, $KCODE)
encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
soap_obj = soap_class.new(encoded)
else
return nil
unless XSD::Charset.is_ces(obj, $KCODE)
return nil
end
encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
soap_obj = soap_class.new(encoded)
rescue XSD::ValueSpaceError
return nil
end
@ -119,14 +112,24 @@ class StringFactory_ < Factory
end
def soap2obj(obj_class, node, info, map)
obj = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
obj = create_empty_object(obj_class)
decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
obj.replace(decoded)
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class BasetypeFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
@ -145,7 +148,16 @@ class BasetypeFactory_ < Factory
end
class DateTimeFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and
Time === obj and !obj.instance_variables.empty?
return nil
end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
@ -176,6 +188,7 @@ end
class Base64Factory_ < Factory
def obj2soap(soap_class, obj, info, map)
return nil unless obj.instance_variables.empty?
soap_obj = soap_class.new(obj)
mark_marshalled_obj(obj, soap_obj) if soap_obj
soap_obj
@ -189,9 +202,17 @@ class Base64Factory_ < Factory
end
class ArrayFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
# [[1], [2]] is converted to Array of Array, not 2-D Array.
# To create M-D Array, you must call Mapping.ary2md.
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
@ -217,7 +238,15 @@ class ArrayFactory_ < Factory
end
class TypedArrayFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
arytype = info[:type] || info[0]
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
@ -271,9 +300,17 @@ end
MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
class HashFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if obj.default or
(obj.respond_to?(:default_proc) and obj.default_proc)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
if !obj.default.nil? or
(obj.respond_to?(:default_proc) and obj.default_proc)
return nil
end
param = SOAPStruct.new(MapQName)

View file

@ -129,6 +129,16 @@ module Mapping
return registry.soap2obj(node.class, node)
end
def self.set_instance_vars(obj, values)
values.each do |name, value|
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_eval("@#{ name } = value")
end
end
end
# Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
# Caution: '.' is not allowed here.

View file

@ -39,6 +39,8 @@ module MappedException; end
RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
# Inner class to pass an exception.
@ -217,11 +219,11 @@ class Registry
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
[::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDate, BasetypeFactory],
[::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Time, ::SOAP::SOAPTime, BasetypeFactory],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
@ -261,11 +263,11 @@ class Registry
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
[::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDate, BasetypeFactory],
[::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Time, ::SOAP::SOAPTime, BasetypeFactory],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
@ -304,18 +306,18 @@ class Registry
@config = config
@map = Map.new(self)
if @config[:allow_original_mapping]
allow_original_mapping = true
@allow_original_mapping = true
@map.init(RubyOriginalMap)
else
allow_original_mapping = false
@allow_original_mapping = false
@map.init(SOAPBaseMap)
end
allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@config[:allow_untyped_struct] : true
@rubytype_factory = RubytypeFactory.new(
:allow_untyped_struct => allow_untyped_struct,
:allow_original_mapping => allow_original_mapping
:allow_untyped_struct => @allow_untyped_struct,
:allow_original_mapping => @allow_original_mapping
)
@default_factory = @rubytype_factory
@excn_handler_obj2soap = nil
@ -329,53 +331,20 @@ class Registry
# This mapping registry ignores type hint.
def obj2soap(klass, obj, type = nil)
ret = nil
if obj.is_a?(SOAPStruct) || obj.is_a?(SOAPArray)
obj.replace do |ele|
Mapping._obj2soap(ele, self)
end
return obj
elsif obj.is_a?(SOAPBasetype)
return obj
soap = _obj2soap(klass, obj, type)
if @allow_original_mapping
addextend2soap(soap, obj)
end
begin
ret = @map.obj2soap(klass, obj) ||
@default_factory.obj2soap(klass, obj, nil, self)
rescue MappingError
end
return ret if ret
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
end
return ret if ret
raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
soap
end
def soap2obj(klass, node)
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
return obj if conv
else
conv, obj = @map.soap2obj(klass, node)
return obj if conv
conv, obj = @default_factory.soap2obj(klass, node, nil, self)
return obj if conv
obj = _soap2obj(klass, node)
if @allow_original_mapping
addextend2obj(obj, node.extraattr[RubyExtendName])
addiv2obj(obj, node.extraattr[RubyIVarName])
end
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping._soap2obj(yield_node, self)
}
rescue Exception
end
end
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
obj
end
def default_factory=(factory)
@ -397,6 +366,86 @@ class Registry
def find_mapped_obj_class(soap_class)
@map.find_mapped_obj_class(soap_class)
end
private
def _obj2soap(klass, obj, type)
ret = nil
if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
obj.replace do |ele|
Mapping._obj2soap(ele, self)
end
return obj
elsif obj.is_a?(SOAPBasetype)
return obj
end
begin
ret = @map.obj2soap(klass, obj) ||
@default_factory.obj2soap(klass, obj, nil, self)
rescue MappingError
end
return ret if ret
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
end
return ret if ret
raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
end
# Might return nil as a mapping result.
def _soap2obj(klass, node)
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
return obj if conv
else
conv, obj = @map.soap2obj(klass, node)
return obj if conv
conv, obj = @default_factory.soap2obj(klass, node, nil, self)
return obj if conv
end
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping._soap2obj(yield_node, self)
}
rescue Exception
end
end
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
end
def addiv2obj(obj, attr)
return unless attr
vars = {}
attr.__getobj__.each do |name, value|
vars[name] = Mapping._soap2obj(value, self)
end
Mapping.set_instance_vars(obj, vars)
end
def addextend2obj(obj, attr)
return unless attr
attr.split(/ /).reverse_each do |mstr|
obj.extend(Mapping.class_from_name(mstr))
end
end
def addextend2soap(node, obj)
return if obj.is_a?(Symbol) or obj.is_a?(Fixnum)
list = (class << obj; self; end).ancestors - obj.class.ancestors
unless list.empty?
node.extraattr[RubyExtendName] = list.collect { |c|
if c.name.empty?
raise TypeError.new("singleton can't be dumped #{ obj }")
end
c.name
}.join(" ")
end
end
end

View file

@ -22,22 +22,28 @@ module Mapping
class RubytypeFactory < Factory
TYPE_STRING = 'String'
TYPE_ARRAY = 'Array'
TYPE_REGEXP = 'Regexp'
TYPE_RANGE = 'Range'
TYPE_CLASS = 'Class'
TYPE_MODULE = 'Module'
TYPE_SYMBOL = 'Symbol'
TYPE_STRUCT = 'Struct'
TYPE_HASH = 'Map'
TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String')
TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time')
TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array')
TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp')
TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range')
TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class')
TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module')
TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol')
TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct')
TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map')
def initialize(config = {})
@config = config
@allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@config[:allow_untyped_struct] : true
@allow_original_mapping = @config.key?(:allow_original_mapping) ?
@config[:allow_original_mapping] : false
@string_factory = StringFactory_.new(true)
@basetype_factory = BasetypeFactory_.new(true)
@datetime_factory = DateTimeFactory_.new(true)
@array_factory = ArrayFactory_.new(true)
@hash_factory = HashFactory_.new(true)
end
def obj2soap(soap_class, obj, info, map)
@ -47,48 +53,83 @@ class RubytypeFactory < Factory
unless @allow_original_mapping
return nil
end
unless XSD::Charset.is_ces(obj, $KCODE)
return nil
end
encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRING))
mark_marshalled_obj(obj, param)
param.add('string', SOAPString.new(encoded))
param = @string_factory.obj2soap(SOAPString, obj, info, map)
if obj.class != String
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when Time
unless @allow_original_mapping
return nil
end
param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map)
if obj.class != Time
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when Array
unless @allow_original_mapping
return nil
end
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
else
arytype = XSD::AnyTypeName
end
if obj.instance_variables.empty?
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
obj.each do |var|
param.add(Mapping._obj2soap(var, map))
end
else
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_ARRAY))
mark_marshalled_obj(obj, param)
ary = SOAPArray.new(ValueArrayName, 1, arytype)
obj.each do |var|
ary.add(Mapping._obj2soap(var, map))
end
param.add('array', ary)
addiv2soap(param, obj, map)
end
param = @array_factory.obj2soap(nil, obj, info, map)
if obj.class != Array
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when NilClass
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPNil, obj, info, map)
addiv2soapattr(param, obj, map)
when FalseClass, TrueClass
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map)
addiv2soapattr(param, obj, map)
when Integer
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPInt, obj, info, map)
param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map)
param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map)
addiv2soapattr(param, obj, map)
when Float
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map)
if obj.class != Float
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when Hash
unless @allow_original_mapping
return nil
end
if obj.respond_to?(:default_proc) && obj.default_proc
raise TypeError.new("cannot dump hash with default proc")
end
param = SOAPStruct.new(TYPE_HASH)
mark_marshalled_obj(obj, param)
if obj.class != Hash
param.extraattr[RubyTypeName] = obj.class.name
end
obj.each do |key, value|
elem = SOAPStruct.new # Undefined type.
elem.add("key", Mapping._obj2soap(key, map))
elem.add("value", Mapping._obj2soap(value, map))
param.add("item", elem)
end
param.add('default', Mapping._obj2soap(obj.default, map))
addiv2soapattr(param, obj, map)
when Regexp
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_REGEXP))
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_REGEXP)
mark_marshalled_obj(obj, param)
if obj.class != Regexp
param.extraattr[RubyTypeName] = obj.class.name
@ -119,9 +160,12 @@ class RubytypeFactory < Factory
end
end
param.add('options', SOAPInt.new(options))
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when Range
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_RANGE))
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_RANGE)
mark_marshalled_obj(obj, param)
if obj.class != Range
param.extraattr[RubyTypeName] = obj.class.name
@ -129,57 +173,42 @@ class RubytypeFactory < Factory
param.add('begin', Mapping._obj2soap(obj.begin, map))
param.add('end', Mapping._obj2soap(obj.end, map))
param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?))
addiv2soap(param, obj, map)
when Hash
addiv2soapattr(param, obj, map)
when Class
unless @allow_original_mapping
return nil
end
if obj.respond_to?(:default_proc) && obj.default_proc
raise TypeError.new("cannot dump hash with default proc")
end
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_HASH))
mark_marshalled_obj(obj, param)
if obj.class != Hash
param.extraattr[RubyTypeName] = obj.class.name
end
obj.each do |key, value|
elem = SOAPStruct.new # Undefined type.
elem.add("key", Mapping._obj2soap(key, map))
elem.add("value", Mapping._obj2soap(value, map))
param.add("item", elem)
end
param.add('default', Mapping._obj2soap(obj.default, map))
addiv2soap(param, obj, map)
when Class
if obj.name.empty?
raise TypeError.new("Can't dump anonymous class #{ obj }.")
end
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_CLASS))
param = SOAPStruct.new(TYPE_CLASS)
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when Module
unless @allow_original_mapping
return nil
end
if obj.name.empty?
raise TypeError.new("Can't dump anonymous module #{ obj }.")
end
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_MODULE))
param = SOAPStruct.new(TYPE_MODULE)
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when Symbol
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_SYMBOL))
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_SYMBOL)
mark_marshalled_obj(obj, param)
param.add('id', SOAPString.new(obj.id2name))
addiv2soap(param, obj, map)
when Exception
typestr = Mapping.name2elename(obj.class.to_s)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
mark_marshalled_obj(obj, param)
param.add('message', Mapping._obj2soap(obj.message, map))
param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when Struct
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRUCT))
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_STRUCT)
mark_marshalled_obj(obj, param)
param.add('type', ele_type = SOAPString.new(obj.class.to_s))
ele_member = SOAPStruct.new
@ -188,29 +217,23 @@ class RubytypeFactory < Factory
Mapping._obj2soap(obj[member], map))
end
param.add('member', ele_member)
addiv2soap(param, obj, map)
addiv2soapattr(param, obj, map)
when IO, Binding, Continuation, Data, Dir, File::Stat, MatchData, Method,
Proc, Thread, ThreadGroup
Proc, Thread, ThreadGroup # from 1.8: Process::Status, UnboundMethod
return nil
when ::SOAP::Mapping::Object
param = SOAPStruct.new(XSD::AnyTypeName)
mark_marshalled_obj(obj, param)
setiv2soap(param, obj, map) # addiv2soap?
else
if obj.class.name.empty?
raise TypeError.new("Can't dump anonymous class #{ obj }.")
end
if check_singleton(obj)
raise TypeError.new("singleton can't be dumped #{ obj }")
end
type = Mapping.class2element(obj.class)
param = SOAPStruct.new(type)
addiv2soapattr(param, obj, map)
when Exception
typestr = Mapping.name2elename(obj.class.to_s)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
mark_marshalled_obj(obj, param)
if obj.class <= Marshallable
setiv2soap(param, obj, map)
else
setiv2soap(param, obj, map) # Should not be marshalled?
end
param.add('message', Mapping._obj2soap(obj.message, map))
param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
addiv2soapattr(param, obj, map)
else
param = unknownobj2soap(soap_class, obj, info, map)
end
param
end
@ -218,26 +241,42 @@ class RubytypeFactory < Factory
def soap2obj(obj_class, node, info, map)
rubytype = node.extraattr[RubyTypeName]
if rubytype or node.type.namespace == RubyTypeNamespace
rubytype2obj(node, map, rubytype)
rubytype2obj(node, info, map, rubytype)
elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
anytype2obj(node, map)
anytype2obj(node, info, map)
else
unknowntype2obj(node, map)
unknowntype2obj(node, info, map)
end
end
private
def check_singleton(obj)
unless singleton_methods_true(obj).empty?
return true
def addiv2soapattr(node, obj, map)
return if obj.instance_variables.empty?
ivars = SOAPStruct.new # Undefined type.
setiv2soap(ivars, obj, map)
node.extraattr[RubyIVarName] = ivars
end
def unknownobj2soap(soap_class, obj, info, map)
if obj.class.name.empty?
raise TypeError.new("Can't dump anonymous class #{ obj }.")
end
singleton_class = class << obj; self; end
if !singleton_class.instance_variables.empty? or
!(singleton_class.ancestors - obj.class.ancestors).empty?
return true
if !singleton_methods_true(obj).empty? or
!singleton_class.instance_variables.empty?
raise TypeError.new("singleton can't be dumped #{ obj }")
end
false
if !(singleton_class.ancestors - obj.class.ancestors).empty?
typestr = Mapping.name2elename(obj.class.to_s)
type = XSD::QName.new(RubyTypeNamespace, typestr)
else
type = Mapping.class2element(obj.class)
end
param = SOAPStruct.new(type)
mark_marshalled_obj(obj, param)
setiv2soap(param, obj, map)
param
end
if RUBY_VERSION >= '1.8.0'
@ -250,53 +289,36 @@ private
end
end
def rubytype2obj(node, map, rubytype)
def rubytype2obj(node, info, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : nil
obj = nil
case node.class
case node
when SOAPString
obj = string2obj(node, map, rubytype)
obj.replace(node.data)
return @string_factory.soap2obj(klass || String, node, info, map)
when SOAPDateTime
#return @datetime_factory.soap2obj(klass || Time, node, info, map)
klass ||= Time
t = node.to_time
arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec]
obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg)
mark_unmarshalled_obj(node, obj)
return true, obj
when SOAPArray
obj = array2obj(node, map, rubytype)
node.soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
return true, obj
return @array_factory.soap2obj(klass || Array, node, info, map)
when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble
return @basetype_factory.soap2obj(nil, node, info, map)
when SOAPStruct
return rubytypestruct2obj(node, info, map, rubytype)
else
raise
end
end
case node.type.name
when TYPE_STRING
obj = string2obj(node, map, rubytype)
obj.replace(node['string'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_ARRAY
obj = array2obj(node, map, rubytype)
node['array'].soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
setiv2obj(obj, node['ivars'], map)
when TYPE_REGEXP
klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
source = node['source'].string
options = node['options'].data || 0
obj.instance_eval { initialize(source, options) }
setiv2obj(obj, node['ivars'], map)
when TYPE_RANGE
klass = rubytype ? Mapping.class_from_name(rubytype) : Range
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
first = Mapping._soap2obj(node['begin'], map)
last = Mapping._soap2obj(node['end'], map)
exclude_end = node['exclude_end'].data
obj.instance_eval { initialize(first, last, exclude_end) }
setiv2obj(obj, node['ivars'], map)
def rubytypestruct2obj(node, info, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : nil
obj = nil
case node.type
when TYPE_HASH
unless @allow_original_mapping
return false
end
klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
@ -308,16 +330,27 @@ private
if node.key?('default')
obj.default = Mapping._soap2obj(node['default'], map)
end
setiv2obj(obj, node['ivars'], map)
when TYPE_REGEXP
klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
source = node['source'].string
options = node['options'].data || 0
Regexp.instance_method(:initialize).bind(obj).call(source, options)
when TYPE_RANGE
klass = rubytype ? Mapping.class_from_name(rubytype) : Range
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
first = Mapping._soap2obj(node['begin'], map)
last = Mapping._soap2obj(node['end'], map)
exclude_end = node['exclude_end'].data
Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end)
when TYPE_CLASS
obj = Mapping.class_from_name(node['name'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_MODULE
obj = Mapping.class_from_name(node['name'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_SYMBOL
obj = node['id'].data.intern
setiv2obj(obj, node['ivars'], map)
when TYPE_STRUCT
typestr = Mapping.elename2name(node['type'].data)
klass = Mapping.class_from_name(typestr)
@ -333,40 +366,15 @@ private
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
node['member'].each do |name, value|
obj[Mapping.elename2name(name)] =
Mapping._soap2obj(value, map)
obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
setiv2obj(obj, node['ivars'], map)
else
conv, obj = exception2obj(node, map)
unless conv
return false
end
setiv2obj(obj, node['ivars'], map)
return unknowntype2obj(node, info, map)
end
return true, obj
end
def exception2obj(node, map)
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.nil?
return false
end
unless klass <= Exception
return false
end
message = Mapping._soap2obj(node['message'], map)
backtrace = Mapping._soap2obj(node['backtrace'], map)
obj = create_empty_object(klass)
obj = obj.exception(message)
mark_unmarshalled_obj(node, obj)
obj.set_backtrace(backtrace)
setiv2obj(obj, node['ivars'], map)
return true, obj
end
def anytype2obj(node, map)
def anytype2obj(node, info, map)
case node
when SOAPBasetype
return true, node.data
@ -383,22 +391,24 @@ private
end
end
def unknowntype2obj(node, map)
def unknowntype2obj(node, info, map)
if node.is_a?(SOAPStruct)
obj = struct2obj(node, map)
obj = unknownstruct2obj(node, info, map)
return true, obj if obj
if !@allow_untyped_struct
return false
end
return anytype2obj(node, map)
return anytype2obj(node, info, map)
else
# Basetype which is not defined...
return false
end
end
def struct2obj(node, map)
obj = nil
def unknownstruct2obj(node, info, map)
unless node.type.name
return nil
end
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.nil?
@ -407,6 +417,9 @@ private
if klass.nil?
return nil
end
if klass <= ::Exception
return exception2obj(klass, node, map)
end
klass_type = Mapping.class2qname(klass)
return nil unless node.type.match(klass_type)
obj = create_empty_object(klass)
@ -415,6 +428,16 @@ private
obj
end
def exception2obj(klass, node, map)
message = Mapping._soap2obj(node['message'], map)
backtrace = Mapping._soap2obj(node['backtrace'], map)
obj = create_empty_object(klass)
obj = obj.exception(message)
mark_unmarshalled_obj(node, obj)
obj.set_backtrace(backtrace)
obj
end
# Only creates empty array. Do String#replace it with real string.
def array2obj(node, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : Array

View file

@ -58,10 +58,10 @@ module Marshal
def unmarshal(stream, mapping_registry = MarshalMappingRegistry)
header, body = SOAP::Processor.unmarshal(stream)
#Mapping.soap2obj(body.root_node, mapping_registry)
Mapping.soap2obj(body.root_node, mapping_registry)
end
end
end

View file

@ -50,6 +50,7 @@ class StandaloneServer < Logger::Application
def initialize(app_name, namespace, host = "0.0.0.0", port = 8080)
super(app_name)
self.level = Logger::Severity::INFO
@namespace = namespace
@host = host
@port = port

View file

@ -223,7 +223,8 @@ class WSDLDriver
@endpoint_url = nil
@wiredump_dev = nil
@wiredump_file_base = nil
@httpproxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
name = 'http_proxy'
@httpproxy = ENV[name] || ENV[name.upcase]
@wsdl_elements = @wsdl.collect_elements
@wsdl_types = @wsdl.collect_complextypes

View file

@ -485,7 +485,7 @@ module XSDDateTimeImpl
def to_time
begin
if @data.of * SecInDay == Time.now.utc_offset
if @data.offset * SecInDay == Time.now.utc_offset
d = @data
usec = (d.sec_fraction * SecInDay * 1000000).to_f
Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec)
@ -643,7 +643,7 @@ private
s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec)
if @data.sec_fraction.nonzero?
fr = @data.sec_fraction * SecInDay
shiftsize = fr.denominator.to_s.size
shiftsize = fr.denominator.to_s.size + 1
fr_s = (fr * (10 ** shiftsize)).to_i.to_s
s << '.' << '0' * (shiftsize - fr_s.size) << fr_s.sub(/0+$/, '')
end

View file

@ -60,6 +60,10 @@ class NamedElements
@elements << rhs
self
end
def delete(rhs)
@elements.delete(rhs)
end
def +(rhs)
o = NamedElements.new

View file

@ -39,8 +39,7 @@ STDERR.reopen(File.open(errout, "w"))
STDERR.sync = true
Dir.chdir(#{q(DIR)})
cmd = "\\"#{ruby}\\" \\"endblockwarn.rb\\""
exec(cmd)
exit!("must not reach here")
system(cmd)
EOF
launcher.close
launcherpath = launcher.path

View file

@ -252,6 +252,19 @@ module MarshalTestLib
marshal_equal(o) {|obj| class << obj; ancestors end}
end
def test_extend_string
o = String.new
o.extend Mod1
marshal_equal(o) { |obj| obj.kind_of? Mod1 }
o = String.new
o.extend Module.new
assert_raises(TypeError) { marshaltest(o) }
o = String.new
o.extend Mod1
o.extend Mod2
marshal_equal(o) {|obj| class << obj; ancestors end}
end
def test_anonymous
c = Class.new
assert_raises(TypeError) { marshaltest(c) }

View file

@ -7,6 +7,10 @@ module Marshal
module MarshalTestLib
module Mod1; end
module Mod2; end
def encode(o)
SOAPMarshal.dump(o)
end
@ -23,19 +27,20 @@ module MarshalTestLib
o2
end
def marshal_equal(o1)
def marshal_equal(o1, msg = nil)
msg = msg ? msg + "(#{ caller[0] })" : caller[0]
o2 = marshaltest(o1)
assert_equal(o1.class, o2.class, caller[0])
assert_equal(o1.class, o2.class, msg)
iv1 = o1.instance_variables.sort
iv2 = o2.instance_variables.sort
assert_equal(iv1, iv2)
val1 = iv1.map {|var| o1.instance_eval {eval var}}
val2 = iv1.map {|var| o2.instance_eval {eval var}}
assert_equal(val1, val2, caller[0])
assert_equal(val1, val2, msg)
if block_given?
assert_equal(yield(o1), yield(o2), caller[0])
assert_equal(yield(o1), yield(o2), msg)
else
assert_equal(o1, o2, caller[0])
assert_equal(o1, o2, msg)
end
end
@ -50,6 +55,30 @@ module MarshalTestLib
marshal_equal(MyObject.new(2)) {|o| o.v}
end
def test_object_extend
o1 = Object.new
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
def test_object_subclass_extend
o1 = MyObject.new(2)
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
class MyArray < Array; def initialize(v, *args) super args; @v = v; end end
def test_array
marshal_equal([1,2,3])
@ -59,6 +88,12 @@ module MarshalTestLib
marshal_equal(MyArray.new(0, 1,2,3))
end
def test_array_ivar
o1 = Array.new
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
class MyException < Exception; def initialize(v, *args) super(*args); @v = v; end; attr_reader :v; end
def test_exception
marshal_equal(Exception.new('foo')) {|o| o.message}
@ -94,6 +129,36 @@ module MarshalTestLib
assert_raises(TypeError) { marshaltest(h) }
end
def test_hash_ivar
o1 = Hash.new
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
def test_hash_extend
o1 = Hash.new
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
def test_hash_subclass_extend
o1 = MyHash.new(2)
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
def test_bignum
marshal_equal(-0x4000_0000_0000_0001)
marshal_equal(-0x4000_0001)
@ -122,6 +187,24 @@ module MarshalTestLib
marshal_equal(-0.0) {|o| 1.0/o}
end
def test_float_ivar
o1 = 1.23
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
def test_float_extend
o1 = 0.0/0.0
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end
def test_range
marshal_equal(1..2)
@ -129,19 +212,17 @@ module MarshalTestLib
end
def test_range_subclass
STDERR.puts("test_range_subclass: known bug should be fixed.")
return
marshal_equal(MyRange.new(4,5,8, false))
end
class MyRegexp < Regexp; def initialize(v, *args) super(*args); @v = v; end end
def test_regexp
marshal_equal(/a/)
marshal_equal(/A/i)
marshal_equal(/A/mx)
end
def test_regexp_subclass
STDERR.puts("test_regexp_subclass: known bug should be fixed.")
return
marshal_equal(MyRegexp.new(10, "a"))
end
@ -150,10 +231,34 @@ module MarshalTestLib
marshal_equal("abc")
end
def test_string_ivar
o1 = String.new
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
def test_string_subclass
marshal_equal(MyString.new(10, "a"))
end
def test_string_subclass_cycle
str = MyString.new(10, "b")
str.instance_eval { @v = str }
marshal_equal(str) { |o|
assert_equal(o.__id__, o.instance_eval { @v }.__id__)
o.instance_eval { @v }
}
end
def test_string_subclass_extend
o = "abc"
o.extend(Mod1)
str = MyString.new(o, "c")
marshal_equal(str) { |o|
assert(o.instance_eval { @v }).kind_of?(Mod1)
}
end
MyStruct = Struct.new("MyStruct", :a, :b)
class MySubStruct < MyStruct; def initialize(v, *args) super(*args); @v = v; end end
def test_struct
@ -164,6 +269,24 @@ module MarshalTestLib
marshal_equal(MySubStruct.new(10,1,2))
end
def test_struct_ivar
o1 = MyStruct.new
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
def test_struct_subclass_extend
o1 = MyStruct.new
o1.extend(Mod1)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
o1.extend(Mod2)
marshal_equal(o1) { |o|
(class << self; self; end).ancestors
}
end
def test_symbol
marshal_equal(:a)
marshal_equal(:a?)
@ -201,16 +324,21 @@ module MarshalTestLib
def test_time
# once there was a bug caused by usec overflow. try a little harder.
10.times do
marshal_equal(Time.now)
t = Time.now
marshal_equal(t, t.usec.to_s)
end
end
def test_time_subclass
STDERR.puts("test_time_subclass: known bug should be fixed.")
return
marshal_equal(MyTime.new(10))
end
def test_time_ivar
o1 = Time.now
o1.instance_eval { @iv = 1 }
marshal_equal(o1) {|o| o.instance_eval { @iv }}
end
def test_true
marshal_equal(true)
end
@ -250,15 +378,7 @@ module MarshalTestLib
assert_raises(TypeError) { marshaltest(ENV) }
end
module Mod1 end
module Mod2 end
def test_extend
o = Object.new
o.extend Module.new
assert_raises(TypeError) { marshaltest(o) }
STDERR.puts("test_range_subclass: known bug should be fixed.")
return
o = Object.new
o.extend Mod1
marshal_equal(o) { |obj| obj.kind_of? Mod1 }
@ -266,6 +386,22 @@ module MarshalTestLib
o.extend Mod1
o.extend Mod2
marshal_equal(o) {|obj| class << obj; ancestors end}
o = Object.new
o.extend Module.new
assert_raises(TypeError) { marshaltest(o) }
end
def test_extend_string
o = String.new
o.extend Mod1
marshal_equal(o) { |obj| obj.kind_of? Mod1 }
o = String.new
o.extend Mod1
o.extend Mod2
marshal_equal(o) {|obj| class << obj; ancestors end}
o = String.new
o.extend Module.new
assert_raises(TypeError) { marshaltest(o) }
end
def test_anonymous

View file

@ -8,7 +8,6 @@
xmlns:i2="http://www.winfessor.com/SoapBoxWebService/ExceptionDataSet.xsd"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:i0="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://www.winfessor.com/SoapBoxWebService/SoapBoxWebService"
xmlns="http://schemas.xmlsoap.org/wsdl/">

View file

@ -1,8 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:mstns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd" id="MessageDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element msdata:IsDataSet="true" name="MessageDataSet">
<xs:schema
xmlns:mstns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd"
xmlns="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://www.winfessor.com/SoapBoxWebService/MessageDataSet.xsd"
id="MessageDataSet"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MessageDataSet">
<xs:complexType>
<xs:choice maxOccurs="unbounded" />
</xs:complexType>
</xs:element>
</xs:schema>
</xs:schema>