diff options
80 files changed, 3853 insertions, 597 deletions
@@ -1,3 +1,87 @@ +Thu Sep 15 23:25:21 2005 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp> + + * lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.5. + + #nnn is a ticket number at http://dev.ctor.org/soap4r + + * SOAP + + * allow to configure an envelope namespace of SOAP request. (#124) + TemporaryNamespace = 'http://www.w3.org/2003/05/soap-envelope' + @client.options["soap.envelope.requestnamespace"] = + TemporaryNamespace + @client.options["soap.envelope.responsenamespace"] = + TemporaryNamespace + @client.do_proc(...) + + * let SOAP request XML indent space configuable. see + "soap.envelope.no_indent" option. (#130) + + * let external CES configuable. + ex. client["soap.mapping.external_ces"] = 'SJIS'. $KCODE is used + by default. (#133) + external CES ::= CES used in Ruby object of client and server + internal CES ::= CES used in SOAP/OM + + * add iso-8859-1 external CES support. (#106) + + * fixed illegal 'qualified' handling of elements. it caused + ASP.NET inteoperability problem. (#144) + + * added 'soap.envelope.use_numeric_character_reference' (boolean) + option to let query XML use numeric character reference in XML, + not plain UTF-8 character. !GoogleSearch server seems to not + allow plain UTF-8 character since 2005-08-15 update. (#147) + + * SOAP::Header::SimpleHeader (de)serialization throws an exception + on !SimpleHeader.on_(in|out)bound when header is a String. so we + could not use a simple single element headerItem. fixed. thanks + to emil. (#129) + + * out parameter of rpc operation did not work. (#132) + + * follow HTTP redirect only if using http-access2. (#125) (#145) + + * add a workaround for importing an WSDL whose path begins with + drive letter. (#115) + + * WSDL + + * SOAP Data which is defined as a simpletype was not mapped + correctly to Ruby obj when using wsdl2ruby.rb generated classdef + file. (#123) + + * rpc/literal support. (#118) + + * re-implemented local element qualify/unqualify control. handles + elementFormDefault and form in WSDL. (#119) + + * Array of an element which has simpleType causes a crash. (#128) + + * prarmeterOrder may not contain return part so it can be shorter + than parts size. Thanks to Hugh. (#139) + + * Samples + + * added !BasicAuth client sample. (#117) + + * added Base64 client/server sample. + + * added Flickr SOAP interface client sample. (#122) + + * added !SalesForce client sample. (#135) + + * updated Thawte CA certificate for !GoogleAdWords sample. + + * updated a client script with the newer version made by Johan. + thanks! + + * shortened long file names. (#120) + + * fixed typo in authheader sample. (#129) + + * updated deprecated method usage. (#138) + Thu Sep 15 22:40:27 2005 NAKAMURA Usaku <usa@ruby-lang.org> * test/ruby/test_signal.rb (test_exit_action): skip the test using diff --git a/lib/soap/baseData.rb b/lib/soap/baseData.rb index 6d0f628be..0e8b00d45 100644 --- a/lib/soap/baseData.rb +++ b/lib/soap/baseData.rb @@ -44,9 +44,9 @@ module SOAPType attr_accessor :definedtype def initialize(*arg) - super(*arg) + super @encodingstyle = nil - @elename = XSD::QName.new + @elename = XSD::QName::EMPTY @id = nil @precedents = [] @root = false @@ -82,7 +82,7 @@ module SOAPBasetype include SOAP def initialize(*arg) - super(*arg) + super end end @@ -95,7 +95,7 @@ module SOAPCompoundtype include SOAP def initialize(*arg) - super(*arg) + super end end @@ -114,7 +114,7 @@ public # Override the definition in SOAPBasetype. def initialize(obj = nil) super() - @type = XSD::QName.new + @type = XSD::QName::EMPTY @refid = nil @obj = nil __setobj__(obj) if obj @@ -178,7 +178,7 @@ class SOAPExternalReference < XSD::NSDBase def initialize super() - @type = XSD::QName.new + @type = XSD::QName::EMPTY end def referred @@ -399,7 +399,7 @@ public def initialize(type = nil) super() - @type = type || XSD::QName.new + @type = type || XSD::QName::EMPTY @array = [] @data = [] end @@ -470,8 +470,10 @@ public end def each - for i in 0..(@array.length - 1) - yield(@array[i], @data[i]) + idx = 0 + while idx < @array.length + yield(@array[idx], @data[idx]) + idx += 1 end end @@ -529,7 +531,7 @@ class SOAPElement @position = nil @extraattr = {} - @qualified = false + @qualified = nil @array = [] @data = [] @@ -598,8 +600,10 @@ class SOAPElement end def each - for i in 0..(@array.length - 1) - yield(@array[i], @data[i]) + idx = 0 + while idx < @array.length + yield(@array[idx], @data[idx]) + idx += 1 end end @@ -737,27 +741,25 @@ public " does not match rank: #{@rank}") end - for i in 0..(idxary.size - 1) - if idxary[i] + 1 > @size[i] - @size[i] = idxary[i] + 1 + idx = 0 + while idx < idxary.size + if idxary[idx] + 1 > @size[idx] + @size[idx] = idxary[idx] + 1 end + idx += 1 end data = retrieve(idxary[0, idxary.size - 1]) data[idxary.last] = value if value.is_a?(SOAPType) - value.elename = value.elename.dup_name('item') - + value.elename = ITEM_NAME # Sync type unless @type.name @type = XSD::QName.new(value.type.namespace, SOAPArray.create_arytype(value.type.name, @rank)) end - - unless value.type - value.type = @type - end + value.type ||= @type end @offset = idxary @@ -787,7 +789,7 @@ public deep_map(ele, &block) else new_obj = block.call(ele) - new_obj.elename = new_obj.elename.dup_name('item') + new_obj.elename = ITEM_NAME new_obj end end @@ -815,13 +817,15 @@ public def soap2array(ary) traverse_data(@data) do |v, *position| iteary = ary - for rank in 1..(position.size - 1) + rank = 1 + while rank < position.size idx = position[rank - 1] if iteary[idx].nil? iteary = iteary[idx] = Array.new else iteary = iteary[idx] end + rank += 1 end if block_given? iteary[position.last] = yield(v) @@ -837,21 +841,26 @@ public private + ITEM_NAME = XSD::QName.new(nil, 'item') + def retrieve(idxary) data = @data - for rank in 1..(idxary.size) + rank = 1 + while rank <= idxary.size idx = idxary[rank - 1] if data[idx].nil? data = data[idx] = Array.new else data = data[idx] end + rank += 1 end data end def traverse_data(data, rank = 1) - for idx in 0..(ranksize(rank) - 1) + idx = 0 + while idx < ranksize(rank) if rank < @rank traverse_data(data[idx], rank + 1) do |*v| v[1, 0] = idx @@ -860,6 +869,7 @@ private else yield(data[idx], idx) end + idx += 1 end end diff --git a/lib/soap/element.rb b/lib/soap/element.rb index 20d7c3bb2..cc58b5d34 100644 --- a/lib/soap/element.rb +++ b/lib/soap/element.rb @@ -83,10 +83,10 @@ public attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace name = ns.name(@elename) generator.encode_tag(name, attrs) - yield(self.faultcode, false) - yield(self.faultstring, false) - yield(self.faultactor, false) - yield(self.detail, false) if self.detail + yield(self.faultcode) + yield(self.faultstring) + yield(self.faultactor) + yield(self.detail) if self.detail generator.encode_tag_end(name, true) end end @@ -115,10 +115,10 @@ class SOAPBody < SOAPStruct name = ns.name(@elename) generator.encode_tag(name, attrs) if @is_fault - yield(@data, true) + yield(@data) else @data.each do |data| - yield(data, true) + yield(data) end end generator.encode_tag_end(name, true) @@ -171,7 +171,7 @@ public @element.extraattr[ns.name(AttrEncodingStyleName)] = @encodingstyle end @element.encodingstyle = @encodingstyle if !@element.encodingstyle - yield(@element, true) + yield(@element) end end @@ -189,7 +189,7 @@ class SOAPHeader < SOAPStruct name = ns.name(@elename) generator.encode_tag(name, attrs) @data.each do |data| - yield(data, true) + yield(data) end generator.encode_tag_end(name, true) end @@ -239,12 +239,12 @@ class SOAPEnvelope < XSD::NSDBase end def encode(generator, ns, attrs = {}) - SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace, SOAPNamespaceTag) + SOAPGenerator.assign_ns(attrs, ns, elename.namespace, SOAPNamespaceTag) name = ns.name(@elename) generator.encode_tag(name, attrs) - yield(@header, true) if @header and @header.length > 0 - yield(@body, true) + yield(@header) if @header and @header.length > 0 + yield(@body) generator.encode_tag_end(name, true) end diff --git a/lib/soap/encodingstyle/aspDotNetHandler.rb b/lib/soap/encodingstyle/aspDotNetHandler.rb index e4b2028f8..fd7e0fa21 100644 --- a/lib/soap/encodingstyle/aspDotNetHandler.rb +++ b/lib/soap/encodingstyle/aspDotNetHandler.rb @@ -27,38 +27,36 @@ class ASPDotNetHandler < Handler ### ## encode interface. # - def encode_data(generator, ns, qualified, data, parent) + def encode_data(generator, ns, data, parent) attrs = {} - name = if qualified and data.elename.namespace - SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') - ns.name(data.elename) - else - data.elename.name - end - + # ASPDotNetHandler is intended to be used for accessing an ASP.NET doc/lit + # service as an rpc/encoded service. in the situation, local elements + # should be qualified. propagate parent's namespace to children. + if data.elename.namespace.nil? + data.elename.namespace = parent.elename.namespace + end + name = generator.encode_name(ns, data, attrs) case data when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) - generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) + generator.encode_string(@charset ? + XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| - if !value.elename.namespace - value.elename.namespace = data.elename.namespace - end - yield(value, true) + generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil - yield(child, true) + generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( @@ -66,12 +64,8 @@ class ASPDotNetHandler < Handler end end - 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 + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end diff --git a/lib/soap/encodingstyle/handler.rb b/lib/soap/encodingstyle/handler.rb index 7bf65a2fd..c01541743 100644 --- a/lib/soap/encodingstyle/handler.rb +++ b/lib/soap/encodingstyle/handler.rb @@ -58,12 +58,12 @@ class Handler ## encode interface. # # Returns a XML instance as a string. - def encode_data(generator, ns, qualified, data, parent) - raise NotImplementError.new('Method encode_data must be defined in derived class.') + def encode_data(generator, ns, data, parent) + raise NotImplementError end - def encode_data_end(generator, ns, qualified, data, parent) - raise NotImplementError.new('Method encode_data must be defined in derived class.') + def encode_data_end(generator, ns, data, parent) + raise NotImplementError end def encode_prologue diff --git a/lib/soap/encodingstyle/literalHandler.rb b/lib/soap/encodingstyle/literalHandler.rb index 9a494f929..59c720536 100644 --- a/lib/soap/encodingstyle/literalHandler.rb +++ b/lib/soap/encodingstyle/literalHandler.rb @@ -26,15 +26,11 @@ class LiteralHandler < Handler ### ## encode interface. # - def encode_data(generator, ns, qualified, data, parent) + def encode_data(generator, ns, data, parent) attrs = {} - name = if qualified and data.elename.namespace - SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') - ns.name(data.elename) - else - data.elename.name - end + name = generator.encode_name(ns, data, attrs) data.extraattr.each do |k, v| + # ToDo: check generator.attributeformdefault here if k.is_a?(XSD::QName) if k.namespace SOAPGenerator.assign_ns(attrs, ns, k.namespace) @@ -45,7 +41,6 @@ class LiteralHandler < Handler end attrs[k] = v end - case data when SOAPRawString generator.encode_tag(name, attrs) @@ -61,22 +56,25 @@ class LiteralHandler < Handler when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| - if !value.elename.namespace - value.elename.namespace = data.elename.namespace - end - yield(value, true) + generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil - yield(child, true) + generator.encode_child(ns, child, data) end when SOAPElement + # passes 2 times for simplifying namespace definition + data.each do |key, value| + if value.elename.namespace + SOAPGenerator.assign_ns(attrs, ns, value.elename.namespace) + end + end generator.encode_tag(name, attrs) generator.encode_rawstring(data.text) if data.text data.each do |key, value| - yield(value, qualified) + generator.encode_child(ns, value, data) end else raise EncodingStyleError.new( @@ -84,12 +82,8 @@ class LiteralHandler < Handler end end - 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 + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) cr = (data.is_a?(SOAPCompoundtype) or (data.is_a?(SOAPElement) and !data.text)) generator.encode_tag_end(name, cr) diff --git a/lib/soap/encodingstyle/soapHandler.rb b/lib/soap/encodingstyle/soapHandler.rb index f9152e0df..a52239262 100644 --- a/lib/soap/encodingstyle/soapHandler.rb +++ b/lib/soap/encodingstyle/soapHandler.rb @@ -29,21 +29,12 @@ class SOAPHandler < Handler ### ## encode interface. # - def encode_data(generator, ns, qualified, data, parent) + def encode_data(generator, ns, data, parent) attrs = encode_attrs(generator, ns, data, parent) - if parent && parent.is_a?(SOAPArray) && parent.position attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]" end - - name = nil - if qualified and data.elename.namespace - SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace) - name = ns.name(data.elename) - else - name = data.elename.name - end - + name = generator.encode_name(ns, data, attrs) case data when SOAPReference attrs['href'] = data.refidstr @@ -65,13 +56,13 @@ class SOAPHandler < Handler when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| - yield(value, false) + generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = data.sparse ? rank : nil - yield(child, false) + generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( @@ -79,12 +70,8 @@ class SOAPHandler < Handler end end - 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 + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end @@ -268,8 +255,8 @@ private end def encode_attrs(generator, ns, data, parent) - return {} if data.is_a?(SOAPReference) attrs = {} + return attrs if data.is_a?(SOAPReference) if !parent || parent.encodingstyle != EncodingNamespace if @generate_explicit_type diff --git a/lib/soap/generator.rb b/lib/soap/generator.rb index a44d1468b..f179555e1 100644 --- a/lib/soap/generator.rb +++ b/lib/soap/generator.rb @@ -1,5 +1,5 @@ # SOAP4R - SOAP XML Instance Generator library. -# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -28,14 +28,19 @@ public attr_accessor :charset attr_accessor :default_encodingstyle attr_accessor :generate_explicit_type + attr_accessor :use_numeric_character_reference def initialize(opt = {}) @reftarget = nil @handlers = {} - @charset = opt[:charset] || XSD::Charset.encoding_label + @charset = opt[:charset] || XSD::Charset.xml_encoding_label @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @generate_explicit_type = opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true + @elementformdefault = opt[:elementformdefault] + @attributeformdefault = opt[:attributeformdefault] + @use_numeric_character_reference = opt[:use_numeric_character_reference] + @indentstr = opt[:no_indent] ? '' : ' ' @buf = @indent = @curr = nil end @@ -50,7 +55,7 @@ public ns = XSD::NS.new @buf << xmldecl - encode_data(ns, true, obj, nil) + encode_data(ns, obj, nil) @handlers.each do |uri, handler| handler.encode_epilogue @@ -60,42 +65,33 @@ public @buf end - def encode_data(ns, qualified, obj, parent) + def encode_data(ns, obj, parent) if obj.is_a?(SOAPEnvelopeElement) - encode_element(ns, qualified, obj, parent) + encode_element(ns, obj, parent) return end - if @reftarget && !obj.precedents.empty? add_reftarget(obj.elename.name, obj) ref = SOAPReference.new(obj) - ref.elename.name = obj.elename.name + ref.elename = ref.elename.dup_name(obj.elename.name) obj.precedents.clear # Avoid cyclic delay. obj.encodingstyle = parent.encodingstyle # SOAPReference is encoded here. obj = ref end - encodingstyle = obj.encodingstyle # Children's encodingstyle is derived from its parent. encodingstyle ||= parent.encodingstyle if parent obj.encodingstyle = encodingstyle - handler = find_handler(encodingstyle || @default_encodingstyle) unless handler raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end - if !obj.elename.name raise FormatEncodeError.new("Element name not defined: #{ obj }.") end - - handler.encode_data(self, ns, qualified, obj, parent) do |child, nextq| - indent_backup, @indent = @indent, @indent + ' ' - encode_data(ns.clone_ns, nextq, child, obj) - @indent = indent_backup - end - handler.encode_data_end(self, ns, qualified, obj, parent) + handler.encode_data(self, ns, obj, parent) + handler.encode_data_end(self, ns, obj, parent) end def add_reftarget(name, node) @@ -105,13 +101,19 @@ public @reftarget.add(name, node) end - def encode_element(ns, qualified, obj, parent) + def encode_child(ns, child, parent) + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, parent) + @indent = indent_backup + end + + def encode_element(ns, obj, parent) attrs = {} if obj.is_a?(SOAPBody) @reftarget = obj - obj.encode(self, ns, attrs) do |child, nextq| - indent_backup, @indent = @indent, @indent + ' ' - encode_data(ns.clone_ns, nextq, child, obj) + obj.encode(self, ns, attrs) do |child| + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, obj) @indent = indent_backup end @reftarget = nil @@ -124,14 +126,35 @@ public SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag) end end - obj.encode(self, ns, attrs) do |child, nextq| - indent_backup, @indent = @indent, @indent + ' ' - encode_data(ns.clone_ns, nextq, child, obj) + obj.encode(self, ns, attrs) do |child| + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, obj) @indent = indent_backup end end end + def encode_name(ns, data, attrs) + if element_local?(data) + data.elename.name + else + if element_qualified?(data) + SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') + else + SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace) + end + ns.name(data.elename) + end + end + + def encode_name_end(ns, data) + if element_local?(data) + data.elename.name + else + ns.name(data.elename) + end + end + def encode_tag(elename, attrs = nil) if !attrs or attrs.empty? @buf << "\n#{ @indent }<#{ elename }>" @@ -142,7 +165,7 @@ public @buf << "\n#{ @indent }<#{ elename } " << attrs.collect { |key, value| %Q[#{ key }="#{ value }"] - }.join("\n#{ @indent } ") << + }.join("\n#{ @indent }#{ @indentstr * 2 }") << '>' end end @@ -169,11 +192,41 @@ public } EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]") def encode_string(str) - @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } + if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str) + str.gsub!(EncodeCharRegexp) { |c| EncodeMap[c] } + @buf << str.unpack("U*").collect { |c| + if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f) + c.chr + else + sprintf("&#x%x;", c) + end + }.join + else + @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } + end + end + + def element_local?(element) + element.elename.namespace.nil? + end + + def element_qualified?(element) + if element.respond_to?(:qualified) + if element.qualified.nil? + @elementformdefault + else + element.qualified + end + else + @elementformdefault + end end def self.assign_ns(attrs, ns, namespace, tag = nil) - if namespace and !ns.assigned?(namespace) + if namespace.nil? + raise FormatEncodeError.new("empty namespace") + end + unless ns.assigned?(namespace) tag = ns.assign(namespace, tag) if tag == '' attr = 'xmlns' diff --git a/lib/soap/header/simplehandler.rb b/lib/soap/header/simplehandler.rb index 4c6b00ab9..7b206f77d 100644 --- a/lib/soap/header/simplehandler.rb +++ b/lib/soap/header/simplehandler.rb @@ -19,12 +19,12 @@ class SimpleHandler < SOAP::Header::Handler super(elename) end - # Should return a Hash or nil. + # Should return a Hash, String or nil. def on_simple_outbound nil end - # Given header is a Hash or nil. + # Given header is a Hash, String or nil. def on_simple_inbound(header, mustunderstand) end @@ -34,7 +34,7 @@ class SimpleHandler < SOAP::Header::Handler end def on_inbound(header, mustunderstand) - h = header.to_obj + h = header.respond_to?(:to_obj) ? header.to_obj : header.data on_simple_inbound(h, mustunderstand) end end diff --git a/lib/soap/httpconfigloader.rb b/lib/soap/httpconfigloader.rb index ebc17d8f9..cd7bca8a6 100644 --- a/lib/soap/httpconfigloader.rb +++ b/lib/soap/httpconfigloader.rb @@ -60,6 +60,9 @@ module_function def set_ssl_config(client, ssl_config) ssl_config.each do |key, value| cfg = client.ssl_config + if cfg.nil? + raise NotImplementedError.new("SSL not supported") + end case key when 'client_cert' cfg.client_cert = cert_from_file(value) diff --git a/lib/soap/mapping/factory.rb b/lib/soap/mapping/factory.rb index 13dffc2dd..978b303b3 100644 --- a/lib/soap/mapping/factory.rb +++ b/lib/soap/mapping/factory.rb @@ -87,10 +87,11 @@ class StringFactory_ < Factory return nil end begin - unless XSD::Charset.is_ces(obj, $KCODE) - return nil + unless XSD::Charset.is_ces(obj, Thread.current[:SOAPExternalCES]) + return nil end - encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) + encoded = XSD::Charset.encoding_conv(obj, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = soap_class.new(encoded) rescue XSD::ValueSpaceError return nil @@ -101,7 +102,8 @@ class StringFactory_ < Factory def soap2obj(obj_class, node, info, map) obj = Mapping.create_empty_object(obj_class) - decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE) + decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, + Thread.current[:SOAPExternalCES]) obj.replace(decoded) mark_unmarshalled_obj(node, obj) return true, obj diff --git a/lib/soap/mapping/registry.rb b/lib/soap/mapping/registry.rb index e733f5c95..823e80666 100644 --- a/lib/soap/mapping/registry.rb +++ b/lib/soap/mapping/registry.rb @@ -49,8 +49,7 @@ class SOAPException; include Marshallable e.set_backtrace(@cause.backtrace) return e end - klass = Mapping.class_from_name( - Mapping.elename2name(@excn_type_name.to_s)) + klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s)) if klass.nil? or not klass <= ::Exception return RuntimeError.new(@cause.inspect) end @@ -89,6 +88,10 @@ class Object; include Marshallable @__xmlele.each do |k, v| return v if k == qname end + # fallback + @__xmlele.each do |k, v| + return v if k.name == qname.name + end nil end diff --git a/lib/soap/mapping/wsdlRegistry.rb b/lib/soap/mapping/wsdlRegistry.rb deleted file mode 100644 index 64f49f226..000000000 --- a/lib/soap/mapping/wsdlRegistry.rb +++ /dev/null @@ -1,155 +0,0 @@ -# SOAP4R - WSDL mapping registry. -# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. - -# This program is copyrighted free software by NAKAMURA, Hiroshi. You can -# redistribute it and/or modify it under the same terms of Ruby's license; -# either the dual license version in 2003, or any later version. - - -require 'soap/baseData' -require 'soap/mapping/mapping' -require 'soap/mapping/typeMap' - - -module SOAP -module Mapping - - -class WSDLRegistry - include TraverseSupport - - attr_reader :definedtypes - - def initialize(definedtypes, config = {}) - @definedtypes = definedtypes - @config = config - @excn_handler_obj2soap = nil - # For mapping AnyType element. - @rubytype_factory = RubytypeFactory.new( - :allow_untyped_struct => true, - :allow_original_mapping => true - ) - end - - def obj2soap(klass, obj, type_qname) - soap_obj = nil - if obj.nil? - soap_obj = SOAPNil.new - elsif obj.is_a?(XSD::NSDBase) - soap_obj = soap2soap(obj, type_qname) - elsif type = @definedtypes[type_qname] - soap_obj = obj2type(obj, type) - elsif (type = TypeMap[type_qname]) - soap_obj = base2soap(obj, type) - elsif type_qname == XSD::AnyTypeName - soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, nil) - end - return soap_obj if soap_obj - if @excn_handler_obj2soap - soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| - Mapping._obj2soap(yield_obj, self) - } - end - return soap_obj if soap_obj - raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.") - end - - def soap2obj(klass, node) - raise RuntimeError.new("#{ self } is for obj2soap only.") - end - - def excn_handler_obj2soap=(handler) - @excn_handler_obj2soap = handler - end - -private - - def soap2soap(obj, type_qname) - if obj.is_a?(SOAPBasetype) - obj - elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname]) - soap_obj = obj - mark_marshalled_obj(obj, soap_obj) - elements2soap(obj, soap_obj, type.content.elements) - soap_obj - elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname]) - soap_obj = obj - contenttype = type.child_type - mark_marshalled_obj(obj, soap_obj) - obj.replace do |ele| - Mapping._obj2soap(ele, self, contenttype) - end - soap_obj - else - nil - end - end - - def obj2type(obj, type) - if type.is_a?(::WSDL::XMLSchema::SimpleType) - simple2soap(obj, type) - else - complex2soap(obj, type) - end - end - - def simple2soap(obj, type) - o = base2soap(obj, TypeMap[type.base]) - if type.restriction.enumeration.empty? - STDERR.puts("#{type.name}: simpleType which is not enum type not supported.") - return o - end - type.check_lexical_format(obj) - o - end - - def complex2soap(obj, type) - case type.compoundtype - when :TYPE_STRUCT - struct2soap(obj, type.name, type) - when :TYPE_ARRAY - array2soap(obj, type.name, type) - end - end - - def base2soap(obj, type) - soap_obj = nil - if type <= XSD::XSDString - soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? - XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) - mark_marshalled_obj(obj, soap_obj) - else - soap_obj = type.new(obj) - end - soap_obj - end - - def struct2soap(obj, type_qname, type) - soap_obj = SOAPStruct.new(type_qname) - mark_marshalled_obj(obj, soap_obj) - elements2soap(obj, soap_obj, type.content.elements) - soap_obj - end - - def array2soap(obj, type_qname, type) - contenttype = type.child_type - soap_obj = SOAPArray.new(ValueArrayName, 1, contenttype) - mark_marshalled_obj(obj, soap_obj) - obj.each do |item| - soap_obj.add(Mapping._obj2soap(item, self, contenttype)) - end - soap_obj - end - - def elements2soap(obj, soap_obj, elements) - elements.each do |element| - name = element.name.name - child_obj = obj.instance_eval("@#{ name }") - soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type)) - end - end -end - - -end -end diff --git a/lib/soap/mapping/wsdlencodedregistry.rb b/lib/soap/mapping/wsdlencodedregistry.rb index 8d495668e..4efb60188 100644 --- a/lib/soap/mapping/wsdlencodedregistry.rb +++ b/lib/soap/mapping/wsdlencodedregistry.rb @@ -149,8 +149,9 @@ private def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString - soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? - XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) + str = XSD::Charset.encoding_conv(obj.to_s, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) + soap_obj = type.new(str) mark_marshalled_obj(obj, soap_obj) else soap_obj = type.new(obj) @@ -234,7 +235,9 @@ private elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| - if class_name = elements[name] + item = elements.find { |k, v| k.name == name } + if item + elename, class_name = item if klass = Mapping.class_from_name(class_name) # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) @@ -246,6 +249,14 @@ private else child = Mapping._soap2obj(value, self, klass) end + elsif klass = Mapping.module_from_name(class_name) + # simpletype + if value.respond_to?(:data) + child = value.data + else + raise MappingError.new( + "cannot map to a module value: #{class_name}") + end else raise MappingError.new("unknown class: #{class_name}") end diff --git a/lib/soap/mapping/wsdlliteralregistry.rb b/lib/soap/mapping/wsdlliteralregistry.rb index 59acf2f65..7bb8e1220 100644 --- a/lib/soap/mapping/wsdlliteralregistry.rb +++ b/lib/soap/mapping/wsdlliteralregistry.rb @@ -38,14 +38,14 @@ class WSDLLiteralRegistry < Registry if ele = @definedelements[qname] soap_obj = obj2elesoap(obj, ele) elsif type = @definedtypes[qname] - soap_obj = obj2typesoap(obj, type) + soap_obj = obj2typesoap(obj, type, true) else soap_obj = any2soap(obj, qname) end return soap_obj if soap_obj if @excn_handler_obj2soap soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| - Mapping._obj2soap(yield_obj, self) + Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT) } return soap_obj if soap_obj end @@ -54,9 +54,7 @@ class WSDLLiteralRegistry < Registry # node should be a SOAPElement def soap2obj(node, obj_class = nil) - unless obj_class.nil? - raise MappingError.new("must not reach here") - end + # obj_class is given when rpc/literal service. but ignored for now. begin return any2obj(node) rescue MappingError @@ -64,45 +62,50 @@ class WSDLLiteralRegistry < Registry if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| - Mapping._soap2obj(yield_node, self) + Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT) } rescue Exception end end - raise MappingError.new("cannot map #{node.type.name} to Ruby object") + if node.respond_to?(:type) + raise MappingError.new("cannot map #{node.type.name} to Ruby object") + else + raise MappingError.new("cannot map #{node.elename.name} to Ruby object") + end end private + MAPPING_OPT = { :no_reference => true } + def obj2elesoap(obj, ele) o = nil + qualified = (ele.elementform == 'qualified') if ele.type if type = @definedtypes[ele.type] - o = obj2typesoap(obj, type) + o = obj2typesoap(obj, type, qualified) elsif type = TypeMap[ele.type] o = base2soap(obj, type) else raise MappingError.new("cannot find type #{ele.type}") end - o.elename = ele.name elsif ele.local_complextype - o = obj2typesoap(obj, ele.local_complextype) - o.elename = ele.name + o = obj2typesoap(obj, ele.local_complextype, qualified) add_attributes2soap(obj, o) elsif ele.local_simpletype - o = obj2typesoap(obj, ele.local_simpletype) - o.elename = ele.name + o = obj2typesoap(obj, ele.local_simpletype, qualified) else raise MappingError.new('illegal schema?') end + o.elename = ele.name o end - def obj2typesoap(obj, type) + def obj2typesoap(obj, type, qualified) if type.is_a?(::WSDL::XMLSchema::SimpleType) simpleobj2soap(obj, type) else - complexobj2soap(obj, type) + complexobj2soap(obj, type, qualified) end end @@ -113,15 +116,17 @@ private o end - def complexobj2soap(obj, type) + def complexobj2soap(obj, type, qualified) o = SOAPElement.new(type.name) + o.qualified = qualified type.each_element do |child_ele| child = Mapping.get_attribute(obj, child_ele.name.name) if child.nil? if child_ele.nillable # ToDo: test # add empty element - o.add(obj2elesoap(nil)) + child_soap = obj2elesoap(nil, child_ele) + o.add(child_soap) elsif Integer(child_ele.minoccurs) == 0 # nothing to do else @@ -129,10 +134,12 @@ private end elsif child_ele.map_as_array? child.each do |item| - o.add(obj2elesoap(item, child_ele)) + child_soap = obj2elesoap(item, child_ele) + o.add(child_soap) end else - o.add(obj2elesoap(child, child_ele)) + child_soap = obj2elesoap(child, child_ele) + o.add(child_soap) end end o @@ -153,7 +160,7 @@ private # expected to be a basetype or an anyType. # SOAPStruct, etc. is used instead of SOAPElement. begin - ele = Mapping.obj2soap(obj) + ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT) ele.elename = qname ele rescue MappingError @@ -170,6 +177,9 @@ private def stubobj2soap(obj, qname) ele = SOAPElement.new(qname) + ele.qualified = + (obj.class.class_variables.include?('@@schema_qualified') and + obj.class.class_eval('@@schema_qualified')) add_elements2soap(obj, ele) add_attributes2soap(obj, ele) ele @@ -196,15 +206,17 @@ private elements, as_array = schema_element_definition(obj.class) if elements elements.each do |elename, type| - child = Mapping.get_attribute(obj, elename) - unless child.nil? - name = XSD::QName.new(nil, elename) - if as_array.include?(type) + if child = Mapping.get_attribute(obj, elename.name) + if as_array.include?(elename.name) child.each do |item| - ele.add(obj2soap(item, name)) + ele.add(obj2soap(item, elename)) end else - ele.add(obj2soap(child, name)) + ele.add(obj2soap(child, elename)) + end + elsif obj.is_a?(::Array) and as_array.include?(elename.name) + obj.each do |item| + ele.add(obj2soap(item, elename)) end end end @@ -225,8 +237,9 @@ private def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString - soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? - XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) + str = XSD::Charset.encoding_conv(obj.to_s, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) + soap_obj = type.new(str) else soap_obj = type.new(obj) end @@ -253,7 +266,7 @@ private # SOAPArray for literal? soapele2plainobj(node) else - obj = Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class) + obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT) add_attributes2plainobj(node, obj) obj end @@ -277,8 +290,11 @@ private elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| - if class_name = elements[name] + item = elements.find { |k, v| k.name == name } + if item + elename, class_name = item if klass = Mapping.class_from_name(class_name) + # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) if value.respond_to?(:data) child = klass.new(value.data).data @@ -288,13 +304,21 @@ private else child = any2obj(value, klass) end + elsif klass = Mapping.module_from_name(class_name) + # simpletype + if value.respond_to?(:data) + child = value.data + else + raise MappingError.new( + "cannot map to a module value: #{class_name}") + end else - raise MappingError.new("unknown class: #{class_name}") + raise MappingError.new("unknown class/module: #{class_name}") end else # untyped element is treated as anyType. child = any2obj(value) end - if as_array.include?(class_name) + if as_array.include?(elename.name) (vars[name] ||= []) << child else vars[name] = child @@ -323,7 +347,7 @@ private def add_elements2plainobj(node, obj) node.each do |name, value| - obj.__add_xmlele_value(XSD::QName.new(nil, name), any2obj(value)) + obj.__add_xmlele_value(value.elename, any2obj(value)) end end diff --git a/lib/soap/mimemessage.rb b/lib/soap/mimemessage.rb index 1197cebc8..acb4322e1 100644 --- a/lib/soap/mimemessage.rb +++ b/lib/soap/mimemessage.rb @@ -112,6 +112,7 @@ class MIMEMessage @headers = Headers.new @headers.add("Content-Transfer-Encoding", "8bit") @body = nil + @contentid = nil end def self.parse(str) @@ -147,6 +148,7 @@ class MIMEMessage def initialize @parts = [] @headers = Headers.new + @root = nil end def self.parse(head, str) @@ -197,7 +199,7 @@ class MIMEMessage def add_part(content) part = Part.new part.headers.add("Content-Type", - "text/xml; charset=" + XSD::Charset.encoding_label) + "text/xml; charset=" + XSD::Charset.xml_encoding_label) part.headers.add("Content-ID", Attachment.contentid(part)) part.body = content @parts.unshift(part) diff --git a/lib/soap/parser.rb b/lib/soap/parser.rb index 14704a6d9..412fd4855 100644 --- a/lib/soap/parser.rb +++ b/lib/soap/parser.rb @@ -60,6 +60,7 @@ private public + attr_accessor :envelopenamespace attr_accessor :default_encodingstyle attr_accessor :decode_typemap attr_accessor :allow_unqualified_element @@ -70,6 +71,7 @@ public @parsestack = nil @lastnode = nil @handlers = {} + @envelopenamespace = opt[:envelopenamespace] || EnvelopeNamespace @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @decode_typemap = opt[:decode_typemap] || nil @allow_unqualified_element = opt[:allow_unqualified_element] || false @@ -134,10 +136,7 @@ public lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. - ns = lastframe.ns - parent = lastframe.node - encodingstyle = lastframe.encodingstyle - decode_text(ns, text, encodingstyle) + decode_text(lastframe.ns, text, lastframe.encodingstyle) else # Ignore Text outside of SOAP Envelope. p text if $DEBUG @@ -157,7 +156,7 @@ private def find_encodingstyle(ns, attrs) attrs.each do |key, value| - if (ns.compare(EnvelopeNamespace, AttrEncodingStyle, key)) + if (ns.compare(@envelopenamespace, AttrEncodingStyle, key)) return value end end @@ -168,7 +167,7 @@ private ele = ns.parse(name) # Envelope based parsing. - if ((ele.namespace == EnvelopeNamespace) || + if ((ele.namespace == @envelopenamespace) || (@allow_unqualified_element && ele.namespace.nil?)) o = decode_soap_envelope(ns, ele, attrs, parent) return o if o diff --git a/lib/soap/rpc/driver.rb b/lib/soap/rpc/driver.rb index 096a54f01..0fb4e8248 100644 --- a/lib/soap/rpc/driver.rb +++ b/lib/soap/rpc/driver.rb @@ -205,7 +205,7 @@ private opt.add_hook("protocol.wiredump_file_base") do |key, value| @wiredump_file_base = value end - opt["protocol.http.charset"] ||= XSD::Charset.encoding_label + opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label opt["protocol.http.proxy"] ||= Env::HTTP_PROXY opt["protocol.http.no_proxy"] ||= Env::NO_PROXY opt diff --git a/lib/soap/rpc/element.rb b/lib/soap/rpc/element.rb index e6cae2f7e..c224b03d0 100644 --- a/lib/soap/rpc/element.rb +++ b/lib/soap/rpc/element.rb @@ -20,21 +20,25 @@ class SOAPBody < SOAPStruct end def response + root = root_node if !@is_fault - if void? + if root.nil? nil + elsif root.is_a?(SOAPBasetype) + root else # Initial element is [retval]. - root_node[0] + root[0] end else - root_node + root end end def outparams - if !@is_fault and !void? - op = root_node[1..-1] + root = root_node + if !@is_fault and !root.nil? and !root.is_a?(SOAPBasetype) + op = root[1..-1] op = nil if op && op.empty? op else @@ -42,10 +46,6 @@ class SOAPBody < SOAPStruct end end - def void? - root_node.nil? - end - def fault if @is_fault self['fault'] diff --git a/lib/soap/rpc/proxy.rb b/lib/soap/rpc/proxy.rb index b9d80541a..7dfda6200 100644 --- a/lib/soap/rpc/proxy.rb +++ b/lib/soap/rpc/proxy.rb @@ -92,6 +92,14 @@ public opt[:response_style] ||= :document opt[:request_use] ||= :literal opt[:response_use] ||= :literal + # default values of these values are unqualified in XML Schema. + # set true for backward compatibility. + unless opt.key?(:elementformdefault) + opt[:elementformdefault] = true + end + unless opt.key?(:attributeformdefault) + opt[:attributeformdefault] = true + end @operation[name] = Operation.new(soapaction, param_def, opt) end @@ -101,7 +109,7 @@ public alias add_document_method add_document_operation def invoke(req_header, req_body, opt = nil) - opt ||= create_options + opt ||= create_encoding_opt route(req_header, req_body, opt, opt) end @@ -109,15 +117,27 @@ public unless op_info = @operation[name] raise MethodDefinitionError, "method: #{name} not defined" end + mapping_opt = create_mapping_opt req_header = create_request_header req_body = SOAPBody.new( - op_info.request_body(params, @mapping_registry, @literal_mapping_registry) + op_info.request_body(params, @mapping_registry, + @literal_mapping_registry, mapping_opt) ) - reqopt = create_options({ + reqopt = create_encoding_opt( :soapaction => op_info.soapaction || @soapaction, - :default_encodingstyle => op_info.request_default_encodingstyle}) - resopt = create_options({ - :default_encodingstyle => op_info.response_default_encodingstyle}) + :envelopenamespace => @options["soap.envelope.requestnamespace"], + :default_encodingstyle => + @default_encodingstyle || op_info.request_default_encodingstyle, + :elementformdefault => op_info.elementformdefault, + :attributeformdefault => op_info.attributeformdefault + ) + resopt = create_encoding_opt( + :envelopenamespace => @options["soap.envelope.responsenamespace"], + :default_encodingstyle => + @default_encodingstyle || op_info.response_default_encodingstyle, + :elementformdefault => op_info.elementformdefault, + :attributeformdefault => op_info.attributeformdefault + ) env = route(req_header, req_body, reqopt, resopt) raise EmptyResponseError unless env receive_headers(env.header) @@ -126,11 +146,15 @@ public rescue ::SOAP::FaultError => e op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry) end - op_info.response_obj(env.body, @mapping_registry, @literal_mapping_registry) + op_info.response_obj(env.body, @mapping_registry, + @literal_mapping_registry, mapping_opt) end def route(req_header, req_body, reqopt, resopt) - req_env = SOAPEnvelope.new(req_header, req_body) + req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body) + unless reqopt[:envelopenamespace].nil? + set_envelopenamespace(req_env, reqopt[:envelopenamespace]) + end reqopt[:external_content] = nil conn_data = marshal(req_env, reqopt) if ext = reqopt[:external_content] @@ -159,6 +183,16 @@ public private + def set_envelopenamespace(env, namespace) + env.elename = XSD::QName.new(namespace, env.elename.name) + if env.header + env.header.elename = XSD::QName.new(namespace, env.header.elename.name) + end + if env.body + env.body.elename = XSD::QName.new(namespace, env.body.elename.name) + end + end + def create_request_header headers = @headerhandler.on_outbound if headers.empty? @@ -201,6 +235,10 @@ private ::SOAP::StreamHandler.parse_media_type(contenttype) env = Processor.unmarshal(conn_data.receive_string, opt) end + unless env.is_a?(::SOAP::SOAPEnvelope) + raise ResponseFormatError.new( + "response is not a SOAP envelope: #{conn_data.receive_string}") + end env end @@ -212,11 +250,22 @@ private header end - def create_options(hash = nil) + def create_encoding_opt(hash = nil) opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type + opt[:no_indent] = @options["soap.envelope.no_indent"] + opt[:use_numeric_character_reference] = + @options["soap.envelope.use_numeric_character_reference"] + opt.update(hash) if hash + opt + end + + def create_mapping_opt(hash = nil) + opt = { + :external_ces => @options["soap.mapping.external_ces"] + } opt.update(hash) if hash opt end @@ -227,6 +276,8 @@ private attr_reader :response_style attr_reader :request_use attr_reader :response_use + attr_reader :elementformdefault + attr_reader :attributeformdefault def initialize(soapaction, param_def, opt) @soapaction = soapaction @@ -234,6 +285,9 @@ private @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] + # set nil(unqualified) by default + @elementformdefault = opt[:elementformdefault] + @attributeformdefault = opt[:attributeformdefault] check_style(@request_style) check_style(@response_style) check_use(@request_use) @@ -247,17 +301,22 @@ private RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction) else @doc_request_qnames = [] + @doc_request_qualified = [] @doc_response_qnames = [] - param_def.each do |inout, paramname, typeinfo| + @doc_response_qualified = [] + param_def.each do |inout, paramname, typeinfo, eleinfo| klass_not_used, nsdef, namedef = typeinfo + qualified = eleinfo if namedef.nil? raise MethodDefinitionError.new("qname must be given") end case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) + @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) + @doc_response_qualified << qualified else raise MethodDefinitionError.new( "illegal inout definition for document style: #{inout}") @@ -274,19 +333,19 @@ private (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end - def request_body(values, mapping_registry, literal_mapping_registry) + def request_body(values, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc - request_rpc(values, mapping_registry, literal_mapping_registry) + request_rpc(values, mapping_registry, literal_mapping_registry, opt) else - request_doc(values, mapping_registry, literal_mapping_registry) + request_doc(values, mapping_registry, literal_mapping_registry, opt) end end - def response_obj(body, mapping_registry, literal_mapping_registry) + def response_obj(body, mapping_registry, literal_mapping_registry, opt) if @response_style == :rpc - response_rpc(body, mapping_registry, literal_mapping_registry) + response_rpc(body, mapping_registry, literal_mapping_registry, opt) else - response_doc(body, mapping_registry, literal_mapping_registry) + response_doc(body, mapping_registry, literal_mapping_registry, opt) end end @@ -312,86 +371,89 @@ private end end - def request_rpc(values, mapping_registry, literal_mapping_registry) + def request_rpc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded - request_rpc_enc(values, mapping_registry) + request_rpc_enc(values, mapping_registry, opt) else - request_rpc_lit(values, literal_mapping_registry) + request_rpc_lit(values, literal_mapping_registry, opt) end end - def request_doc(values, mapping_registry, literal_mapping_registry) + def request_doc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded - request_doc_enc(values, mapping_registry) + request_doc_enc(values, mapping_registry, opt) else - request_doc_lit(values, literal_mapping_registry) + request_doc_lit(values, literal_mapping_registry, opt) end end - def request_rpc_enc(values, mapping_registry) + def request_rpc_enc(values, mapping_registry, opt) method = @rpc_method_factory.dup names = method.input_params obj = create_request_obj(names, values) - soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname) + soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname, opt) method.set_param(soap) method end - def request_rpc_lit(values, mapping_registry) + def request_rpc_lit(values, mapping_registry, opt) method = @rpc_method_factory.dup params = {} idx = 0 method.input_params.each do |name| params[name] = Mapping.obj2soap(values[idx], mapping_registry, - XSD::QName.new(nil, name)) + XSD::QName.new(nil, name), opt) idx += 1 end method.set_param(params) method end - def request_doc_enc(values, mapping_registry) + def request_doc_enc(values, mapping_registry, opt) (0...values.size).collect { |idx| - ele = Mapping.obj2soap(values[idx], mapping_registry) + ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt) ele.elename = @doc_request_qnames[idx] ele } end - def request_doc_lit(values, mapping_registry) + def request_doc_lit(values, mapping_registry, opt) (0...values.size).collect { |idx| ele = Mapping.obj2soap(values[idx], mapping_registry, - @doc_request_qnames[idx]) + @doc_request_qnames[idx], opt) ele.encodingstyle = LiteralNamespace + if ele.respond_to?(:qualified) + ele.qualified = @doc_request_qualified[idx] + end ele } end - def response_rpc(body, mapping_registry, literal_mapping_registry) + def response_rpc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded - response_rpc_enc(body, mapping_registry) + response_rpc_enc(body, mapping_registry, opt) else - response_rpc_lit(body, literal_mapping_registry) + response_rpc_lit(body, literal_mapping_registry, opt) end end - def response_doc(body, mapping_registry, literal_mapping_registry) + def response_doc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded - return *response_doc_enc(body, mapping_registry) + return *response_doc_enc(body, mapping_registry, opt) else - return *response_doc_lit(body, literal_mapping_registry) + return *response_doc_lit(body, literal_mapping_registry, opt) end end - def response_rpc_enc(body, mapping_registry) + def response_rpc_enc(body, mapping_registry, opt) ret = nil if body.response ret = Mapping.soap2obj(body.response, mapping_registry, - @rpc_method_factory.retval_class_name) + @rpc_method_factory.retval_class_name, opt) end if body.outparams outparams = body.outparams.collect { |outparam| - Mapping.soap2obj(outparam, mapping_regisry) + Mapping.soap2obj(outparam, mapping_registry, nil, opt) } [ret].concat(outparams) else @@ -399,20 +461,20 @@ private end end - def response_rpc_lit(body, mapping_registry) + def response_rpc_lit(body, mapping_registry, opt) body.root_node.collect { |key, value| Mapping.soap2obj(value, mapping_registry, - @rpc_method_factory.retval_class_name) + @rpc_method_factory.retval_class_name, opt) } end - def response_doc_enc(body, mapping_registry) + def response_doc_enc(body, mapping_registry, opt) body.collect { |key, value| - Mapping.soap2obj(value, mapping_registry) + Mapping.soap2obj(value, mapping_registry, nil, opt) } end - def response_doc_lit(body, mapping_registry) + def response_doc_lit(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry) } @@ -420,8 +482,10 @@ private def create_request_obj(names, params) o = Object.new - for idx in 0 ... params.length + idx = 0 + while idx < params.length o.instance_variable_set('@' + names[idx], params[idx]) + idx += 1 end o end diff --git a/lib/soap/rpc/router.rb b/lib/soap/rpc/router.rb index 1d11bc17d..71c6eb625 100644 --- a/lib/soap/rpc/router.rb +++ b/lib/soap/rpc/router.rb @@ -28,6 +28,7 @@ class Router attr_accessor :mapping_registry attr_accessor :literal_mapping_registry attr_accessor :generate_explicit_type + attr_accessor :external_ces def initialize(actor) @actor = actor @@ -35,6 +36,7 @@ class Router @headerhandler = Header::HandlerSet.new @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new @generate_explicit_type = true + @external_ces = nil @operation_by_soapaction = {} @operation_by_qname = {} @headerhandlerfactory = [] @@ -163,7 +165,8 @@ class Router soap_response = default_encodingstyle = nil begin soap_response = - op.call(env.body, @mapping_registry, @literal_mapping_registry) + op.call(env.body, @mapping_registry, @literal_mapping_registry, + create_mapping_opt) default_encodingstyle = op.response_default_encodingstyle rescue Exception soap_response = fault($!) @@ -240,7 +243,8 @@ private return op end if soapaction - raise RPCRoutingError.new("operation: #{soapaction} not supported") + raise RPCRoutingError.new( + "operation: #{soapaction} #{qname} not supported") else raise RPCRoutingError.new("operation: #{qname} not supported") end @@ -323,6 +327,10 @@ private Mapping.obj2soap(detail, @mapping_registry)) end + def create_mapping_opt + { :external_ces => @external_ces } + end + class Operation attr_reader :name attr_reader :soapaction @@ -349,14 +357,19 @@ private @rpc_response_qname = opt[:response_qname] else @doc_request_qnames = [] + @doc_request_qualified = [] @doc_response_qnames = [] - param_def.each do |inout, paramname, typeinfo| + @doc_response_qualified = [] + param_def.each do |inout, paramname, typeinfo, eleinfo| klass, nsdef, namedef = typeinfo + qualified = eleinfo case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) + @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) + @doc_response_qualified << qualified else raise ArgumentError.new( "illegal inout definition for document style: #{inout}") @@ -373,18 +386,20 @@ private (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end - def call(body, mapping_registry, literal_mapping_registry) + def call(body, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc - values = request_rpc(body, mapping_registry, literal_mapping_registry) + values = request_rpc(body, mapping_registry, literal_mapping_registry, + opt) else - values = request_document(body, mapping_registry, literal_mapping_registry) + values = request_document(body, mapping_registry, + literal_mapping_registry, opt) end result = receiver.method(@name.intern).call(*values) return result if result.is_a?(SOAPFault) if @response_style == :rpc - response_rpc(result, mapping_registry, literal_mapping_registry) + response_rpc(result, mapping_registry, literal_mapping_registry, opt) else - response_doc(result, mapping_registry, literal_mapping_registry) + response_doc(result, mapping_registry, literal_mapping_registry, opt) end end @@ -394,61 +409,61 @@ private raise NotImplementedError.new('must be defined in derived class') end - def request_rpc(body, mapping_registry, literal_mapping_registry) + def request_rpc(body, mapping_registry, literal_mapping_registry, opt) request = body.request unless request.is_a?(SOAPStruct) raise RPCRoutingError.new("not an RPC style") end if @request_use == :encoded - request_rpc_enc(request, mapping_registry) + request_rpc_enc(request, mapping_registry, opt) else - request_rpc_lit(request, literal_mapping_registry) + request_rpc_lit(request, literal_mapping_registry, opt) end end - def request_document(body, mapping_registry, literal_mapping_registry) + def request_document(body, mapping_registry, literal_mapping_registry, opt) # ToDo: compare names with @doc_request_qnames if @request_use == :encoded - request_doc_enc(body, mapping_registry) + request_doc_enc(body, mapping_registry, opt) else - request_doc_lit(body, literal_mapping_registry) + request_doc_lit(body, literal_mapping_registry, opt) end end - def request_rpc_enc(request, mapping_registry) - param = Mapping.soap2obj(request, mapping_registry) + def request_rpc_enc(request, mapping_registry, opt) + param = Mapping.soap2obj(request, mapping_registry, nil, opt) request.collect { |key, value| param[key] } end - def request_rpc_lit(request, mapping_registry) + def request_rpc_lit(request, mapping_registry, opt) request.collect { |key, value| - Mapping.soap2obj(value, mapping_registry) + Mapping.soap2obj(value, mapping_registry, nil, opt) } end - def request_doc_enc(body, mapping_registry) + def request_doc_enc(body, mapping_registry, opt) body.collect { |key, value| - Mapping.soap2obj(value, mapping_registry) + Mapping.soap2obj(value, mapping_registry, nil, opt) } end - def request_doc_lit(body, mapping_registry) + def request_doc_lit(body, mapping_registry, opt) body.collect { |key, value| - Mapping.soap2obj(value, mapping_registry) + Mapping.soap2obj(value, mapping_registry, nil, opt) } end - def response_rpc(result, mapping_registry, literal_mapping_registry) + def response_rpc(result, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded - response_rpc_enc(result, mapping_registry) + response_rpc_enc(result, mapping_registry, opt) else - response_rpc_lit(result, literal_mapping_registry) + response_rpc_lit(result, literal_mapping_registry, opt) end end - def response_doc(result, mapping_registry, literal_mapping_registry) + def response_doc(result, mapping_registry, literal_mapping_registry, opt) if @doc_response_qnames.size == 1 and !result.is_a?(Array) result = [result] end @@ -457,13 +472,13 @@ private "but #{result.size} given" end if @response_use == :encoded - response_doc_enc(result, mapping_registry) + response_doc_enc(result, mapping_registry, opt) else - response_doc_lit(result, literal_mapping_registry) + response_doc_lit(result, literal_mapping_registry, opt) end end - def response_rpc_enc(result, mapping_registry) + def response_rpc_enc(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? @@ -473,18 +488,21 @@ private outparams = {} i = 1 soap_response.output_params.each do |outparam| - outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry) + outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, + nil, opt) i += 1 end soap_response.set_outparam(outparams) - soap_response.retval = Mapping.obj2soap(result[0], mapping_registry) + soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, + nil, opt) else - soap_response.retval = Mapping.obj2soap(result, mapping_registry) + soap_response.retval = Mapping.obj2soap(result, mapping_registry, nil, + opt) end soap_response end - def response_rpc_lit(result, mapping_registry) + def response_rpc_lit(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? @@ -495,30 +513,36 @@ private i = 1 soap_response.output_params.each do |outparam| outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, - XSD::QName.new(nil, outparam)) + XSD::QName.new(nil, outparam), opt) i += 1 end soap_response.set_outparam(outparams) soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, - XSD::QName.new(nil, soap_response.elename)) + XSD::QName.new(nil, soap_response.elename), opt) else soap_response.retval = Mapping.obj2soap(result, mapping_registry, - XSD::QName.new(nil, soap_response.elename)) + XSD::QName.new(nil, soap_response.elename), opt) end soap_response end - def response_doc_enc(result, mapping_registry) + def response_doc_enc(result, mapping_registry, opt) (0...result.size).collect { |idx| - ele = Mapping.obj2soap(result[idx], mapping_registry) + ele = Mapping.obj2soap(result[idx], mapping_registry, nil, opt) ele.elename = @doc_response_qnames[idx] ele } end - def response_doc_lit(result, mapping_registry) + def response_doc_lit(result, mapping_registry, opt) (0...result.size).collect { |idx| - mapping_registry.obj2soap(result[idx], @doc_response_qnames[idx]) + ele = Mapping.obj2soap(result[idx], mapping_registry, + @doc_response_qnames[idx]) + ele.encodingstyle = LiteralNamespace + if ele.respond_to?(:qualified) + ele.qualified = @doc_response_qualified[idx] + end + ele } end diff --git a/lib/soap/soap.rb b/lib/soap/soap.rb index 0072a8dcf..12e09eccf 100644 --- a/lib/soap/soap.rb +++ b/lib/soap/soap.rb @@ -13,7 +13,7 @@ require 'xsd/charset' module SOAP -VERSION = Version = '1.5.4' +VERSION = Version = '1.5.5' PropertyName = 'soap/property' EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' @@ -40,21 +40,21 @@ AttrOffset = 'offset' AttrPosition = 'position' ValueArray = 'Array' -EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope) -EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader) -EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody) -EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault) -EleFaultStringName = XSD::QName.new(nil, EleFaultString) -EleFaultActorName = XSD::QName.new(nil, EleFaultActor) -EleFaultCodeName = XSD::QName.new(nil, EleFaultCode) -EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail) -AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand) -AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle) -AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot) -AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType) -AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset) -AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition) -ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray) +EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope).freeze +EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader).freeze +EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody).freeze +EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault).freeze +EleFaultStringName = XSD::QName.new(nil, EleFaultString).freeze +EleFaultActorName = XSD::QName.new(nil, EleFaultActor).freeze +EleFaultCodeName = XSD::QName.new(nil, EleFaultCode).freeze +EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail).freeze +AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand).freeze +AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle).freeze +AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot).freeze +AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType).freeze +AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset).freeze +AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition).freeze +ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray).freeze Base64Literal = 'base64' @@ -76,6 +76,7 @@ class ArrayStoreError < Error; end class RPCRoutingError < Error; end class EmptyResponseError < Error; end +class ResponseFormatError < Error; end class UnhandledMustUnderstandHeaderError < Error; end diff --git a/lib/soap/streamHandler.rb b/lib/soap/streamHandler.rb index 3890ac263..672396ecc 100644 --- a/lib/soap/streamHandler.rb +++ b/lib/soap/streamHandler.rb @@ -20,18 +20,6 @@ module SOAP class StreamHandler - Client = begin - require 'http-access2' - if HTTPAccess2::VERSION < "2.0" - raise LoadError.new("http-access/2.0 or later is required.") - end - HTTPAccess2::Client - rescue LoadError - warn("Loading http-access2 failed. Net/http is used.") if $DEBUG - require 'soap/netHttpClient' - SOAP::NetHttpClient - end - RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]" class ConnectionData @@ -70,12 +58,27 @@ end class HTTPStreamHandler < StreamHandler include SOAP + begin + require 'http-access2' + if HTTPAccess2::VERSION < "2.0" + raise LoadError.new("http-access/2.0 or later is required.") + end + Client = HTTPAccess2::Client + RETRYABLE = true + rescue LoadError + warn("Loading http-access2 failed. Net/http is used.") if $DEBUG + require 'soap/netHttpClient' + Client = SOAP::NetHttpClient + RETRYABLE = false + end + + public attr_reader :client attr_accessor :wiredump_file_base - NofRetry = 10 # [times] + MAX_RETRY_COUNT = 10 # [times] def initialize(options) super() @@ -119,7 +122,7 @@ private def set_options HTTPConfigLoader.set_options(@client, @options) - @charset = @options["charset"] || XSD::Charset.charset_label($KCODE) + @charset = @options["charset"] || XSD::Charset.xml_encoding_label @options.add_hook("charset") do |key, value| @charset = value end @@ -140,6 +143,7 @@ private end def set_cookie_store_file(value) + value = nil if value and value.empty? @cookie_store = value @client.set_cookie_store(@cookie_store) if @cookie_store end @@ -161,7 +165,20 @@ private send_string = conn_data.send_string @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev begin - res = @client.post(endpoint_url, send_string, extra) + retry_count = 0 + while true + res = @client.post(endpoint_url, send_string, extra) + if RETRYABLE and HTTP::Status.redirect?(res.status) + retry_count += 1 + if retry_count >= MAX_RETRY_COUNT + raise HTTPStreamError.new("redirect count exceeded") + end + endpoint_url = res.header["location"][0] + puts "redirected to #{endpoint_url}" if $DEBUG + else + break + end + end rescue @client.reset(endpoint_url) raise diff --git a/lib/wsdl/operation.rb b/lib/wsdl/operation.rb index 727bb9a56..fb7f4a80f 100644 --- a/lib/wsdl/operation.rb +++ b/lib/wsdl/operation.rb @@ -120,9 +120,8 @@ private if result.length == 0 return parts.dup end - if parts.length != result.length - raise RuntimeError.new("Incomplete prarmeterOrder list.") - end + # result length can be shorter than parts's. + # return part must not be a part of the parameterOrder. result end end diff --git a/lib/wsdl/param.rb b/lib/wsdl/param.rb index 08ba07ee9..b6836b7de 100644 --- a/lib/wsdl/param.rb +++ b/lib/wsdl/param.rb @@ -36,6 +36,14 @@ class Param < Info root.message(@message) or raise RuntimeError.new("#{@message} not found") end + def soapbody_use + if @soapbody + @soapbody.use || :literal + else + raise RuntimeError.new("soap:body not found") + end + end + def parse_element(element) case element when SOAPBodyName diff --git a/lib/wsdl/soap/body.rb b/lib/wsdl/soap/body.rb index 47e99f381..824f8121a 100644 --- a/lib/wsdl/soap/body.rb +++ b/lib/wsdl/soap/body.rb @@ -36,7 +36,11 @@ class Body < Info when PartsAttrName @parts = value.source when UseAttrName - @use = value.source + if ['literal', 'encoded'].include?(value.source) + @use = value.source.intern + else + raise RuntimeError.new("unknown use of soap:body: #{value.source}") + end when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName diff --git a/lib/wsdl/soap/cgiStubCreator.rb b/lib/wsdl/soap/cgiStubCreator.rb index 0a76dc43a..2c4dff2f6 100644 --- a/lib/wsdl/soap/cgiStubCreator.rb +++ b/lib/wsdl/soap/cgiStubCreator.rb @@ -53,12 +53,12 @@ Methods = [ <<-EOD super(*arg) servant = #{class_name}.new - #{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style| - if style == :document - @router.add_document_operation(servant, soapaction, name, param_def) + #{class_name}::Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + @router.add_document_operation(servant, *definitions) else - qname = XSD::QName.new(namespace, name_as) - @router.add_rpc_operation(servant, qname, soapaction, name, param_def) + @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry diff --git a/lib/wsdl/soap/classDefCreator.rb b/lib/wsdl/soap/classDefCreator.rb index deda4f131..aeb67c061 100644 --- a/lib/wsdl/soap/classDefCreator.rb +++ b/lib/wsdl/soap/classDefCreator.rb @@ -57,7 +57,8 @@ private def dump_element @elements.collect { |ele| if ele.local_complextype - dump_classdef(ele.name, ele.local_complextype) + dump_classdef(ele.name, ele.local_complextype, + ele.elementform == 'qualified') elsif ele.local_simpletype dump_simpletypedef(ele.name, ele.local_simpletype) else @@ -117,7 +118,7 @@ private c.dump end - def dump_classdef(qname, typedef) + def dump_classdef(qname, typedef, qualified = false) if @faulttypes and @faulttypes.index(qname) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::StandardError') @@ -127,6 +128,7 @@ private c.comment = "#{qname}" c.def_classvar('schema_type', ndq(qname.name)) c.def_classvar('schema_ns', ndq(qname.namespace)) + c.def_classvar('schema_qualified', dq('true')) if qualified schema_element = [] init_lines = '' params = [] @@ -158,7 +160,10 @@ private else params << "#{varname} = nil" end - eleqname = (varname == name) ? nil : element.name + # nil means @@schema_ns + varname + eleqname = + (varname == name && element.name.namespace == qname.namespace) ? + nil : element.name schema_element << [varname, eleqname, type] end unless typedef.attributes.empty? @@ -256,13 +261,50 @@ private raise RuntimeError.new("cannot define name of #{attribute}") end + DEFAULT_ITEM_NAME = XSD::QName.new(nil, 'item') + def dump_arraydef(complextype) qname = complextype.name c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::Array') c.comment = "#{qname}" - type = complextype.child_type - c.def_classvar('schema_type', ndq(type.name)) - c.def_classvar('schema_ns', ndq(type.namespace)) + child_type = complextype.child_type + c.def_classvar('schema_type', ndq(child_type.name)) + c.def_classvar('schema_ns', ndq(child_type.namespace)) + child_element = complextype.find_aryelement + schema_element = [] + if child_type == XSD::AnyTypeName + type = nil + elsif child_element and (klass = element_basetype(child_element)) + type = klass.name + elsif child_type + type = create_class_name(child_type) + else + type = nil + end + if child_element + if child_element.map_as_array? + type << '[]' if type + end + child_element_name = child_element.name + else + child_element_name = DEFAULT_ITEM_NAME + end + schema_element << [child_element_name.name, child_element_name, type] + c.def_classvar('schema_element', + '[' + + schema_element.collect { |varname, name, type| + '[' + + ( + if name + varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' + else + varname.dump + ', ' + ndq(type) + end + ) + + ']' + }.join(', ') + + ']' + ) c.dump end end diff --git a/lib/wsdl/soap/clientSkeltonCreator.rb b/lib/wsdl/soap/clientSkeltonCreator.rb index 0b9e79c71..916f0d4dc 100644 --- a/lib/wsdl/soap/clientSkeltonCreator.rb +++ b/lib/wsdl/soap/clientSkeltonCreator.rb @@ -42,8 +42,8 @@ private endpoint_url = ARGV.shift obj = #{ drv_name }.new(endpoint_url) -# Uncomment the below line to see SOAP wiredumps. -# obj.wiredump_dev = STDERR +# run ruby with -d to see SOAP wiredumps. +obj.wiredump_dev = STDERR if $DEBUG __EOD__ @definitions.porttype(name).operations.each do |operation| diff --git a/lib/wsdl/soap/complexType.rb b/lib/wsdl/soap/complexType.rb index bba50fd15..b2e13d056 100644 --- a/lib/wsdl/soap/complexType.rb +++ b/lib/wsdl/soap/complexType.rb @@ -106,18 +106,43 @@ class ComplexType < Info end end if check_array_content(complexcontent.content) - return complexcontent.content.elements[0].type + return element_simpletype(complexcontent.content.elements[0]) end elsif check_array_content(content) - return content.elements[0].type + return element_simpletype(content.elements[0]) end raise RuntimeError.new("Assert: Unknown array definition.") end + def find_aryelement + unless compoundtype == :TYPE_ARRAY + raise RuntimeError.new("Assert: not for array") + end + if complexcontent + if check_array_content(complexcontent.content) + return complexcontent.content.elements[0] + end + elsif check_array_content(content) + return content.elements[0] + end + nil # use default item name + end + private + def element_simpletype(element) + if element.type + element.type + elsif element.local_simpletype + element.local_simpletype.base + else + nil + end + end + def check_array_content(content) - content.elements.size == 1 and content.elements[0].maxoccurs != '1' + content and content.elements.size == 1 and + content.elements[0].maxoccurs != '1' end def content_arytype diff --git a/lib/wsdl/soap/driverCreator.rb b/lib/wsdl/soap/driverCreator.rb index dd504210f..eba7c158a 100644 --- a/lib/wsdl/soap/driverCreator.rb +++ b/lib/wsdl/soap/driverCreator.rb @@ -69,18 +69,18 @@ Methods = [ end c.def_privatemethod("init_methods") do <<-EOD - Methods.each do |name_as, name, params, soapaction, namespace, style| - qname = XSD::QName.new(namespace, name_as) - if style == :document - @proxy.add_document_method(soapaction, name, params) - add_document_method_interface(name, params) + Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + add_document_operation(*definitions) else - @proxy.add_rpc_method(qname, soapaction, name, params) - add_rpc_method_interface(name, params) - end - if name_as != name and name_as.capitalize == name.capitalize - ::SOAP::Mapping.define_singleton_method(self, name_as) do |*arg| - __send__(name, *arg) + add_rpc_operation(*definitions) + qname = definitions[0] + name = definitions[2] + if qname.name != name and qname.name.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| + __send__(name, *arg) + end end end end diff --git a/lib/wsdl/soap/methodDefCreator.rb b/lib/wsdl/soap/methodDefCreator.rb index f256b4245..f3ffadbe6 100644 --- a/lib/wsdl/soap/methodDefCreator.rb +++ b/lib/wsdl/soap/methodDefCreator.rb @@ -46,18 +46,18 @@ class MethodDefCreator def collect_rpcparameter(operation) result = operation.inputparts.collect { |part| collect_type(part.type) - param_set(::SOAP::RPC::SOAPMethod::IN, rpcdefinedtype(part), part.name) + param_set(::SOAP::RPC::SOAPMethod::IN, part.name, rpcdefinedtype(part)) } outparts = operation.outputparts if outparts.size > 0 retval = outparts[0] collect_type(retval.type) - result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, - rpcdefinedtype(retval), retval.name) + result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, retval.name, + rpcdefinedtype(retval)) cdr(outparts).each { |part| collect_type(part.type) - result << param_set(::SOAP::RPC::SOAPMethod::OUT, rpcdefinedtype(part), - part.name) + result << param_set(::SOAP::RPC::SOAPMethod::OUT, part.name, + rpcdefinedtype(part)) } end result @@ -66,12 +66,12 @@ class MethodDefCreator def collect_documentparameter(operation) param = [] operation.inputparts.each do |input| - param << param_set(::SOAP::RPC::SOAPMethod::IN, - documentdefinedtype(input), input.name) + param << param_set(::SOAP::RPC::SOAPMethod::IN, input.name, + documentdefinedtype(input), elementqualified(input)) end operation.outputparts.each do |output| - param << param_set(::SOAP::RPC::SOAPMethod::OUT, - documentdefinedtype(output), output.name) + param << param_set(::SOAP::RPC::SOAPMethod::OUT, output.name, + documentdefinedtype(output), elementqualified(output)) end param end @@ -82,23 +82,38 @@ private name = safemethodname(operation.name.name) name_as = operation.name.name style = binding.soapoperation_style + inputuse = binding.input.soapbody_use + outputuse = binding.output.soapbody_use namespace = binding.input.soapbody.namespace if style == :rpc + qname = XSD::QName.new(namespace, name_as) paramstr = param2str(collect_rpcparameter(operation)) else + qname = nil paramstr = param2str(collect_documentparameter(operation)) end if paramstr.empty? paramstr = '[]' else - paramstr = "[\n" << paramstr.gsub(/^/, ' ') << "\n ]" + paramstr = "[ " << paramstr.split(/\r?\n/).join("\n ") << " ]" end - return <<__EOD__ -[#{dq(name_as)}, #{dq(name)}, + definitions = <<__EOD__ +#{ndq(binding.soapaction)}, + #{dq(name)}, #{paramstr}, - #{ndq(binding.soapaction)}, #{ndq(namespace)}, #{sym(style.id2name)} -] + { :request_style => #{sym(style.id2name)}, :request_use => #{sym(inputuse.id2name)}, + :response_style => #{sym(style.id2name)}, :response_use => #{sym(outputuse.id2name)} } __EOD__ + if style == :rpc + return <<__EOD__ +[ #{qname.dump}, + #{definitions}] +__EOD__ + else + return <<__EOD__ +[ #{definitions}] +__EOD__ + end end def rpcdefinedtype(part) @@ -144,8 +159,22 @@ __EOD__ end end - def param_set(io_type, type, name) - [io_type, type, name] + def elementqualified(part) + if mapped = basetype_mapped_class(part.type) + false + elsif definedtype = @simpletypes[part.type] + false + elsif definedtype = @elements[part.element] + definedtype.elementform == 'qualified' + elsif definedtype = @complextypes[part.type] + false + else + raise RuntimeError.new("part: #{part.name} cannot be resolved") + end + end + + def param_set(io_type, name, type, ele = nil) + [io_type, name, type, ele] end def collect_type(type) @@ -161,7 +190,12 @@ __EOD__ def param2str(params) params.collect { |param| - "[#{dq(param[0])}, #{dq(param[2])}, #{type2str(param[1])}]" + io, name, type, ele = param + unless ele.nil? + "[#{dq(io)}, #{dq(name)}, #{type2str(type)}, #{ele2str(ele)}]" + else + "[#{dq(io)}, #{dq(name)}, #{type2str(type)}]" + end }.join(",\n") end @@ -173,6 +207,15 @@ __EOD__ end end + def ele2str(ele) + qualified = ele + if qualified + "true" + else + "false" + end + end + def cdr(ary) result = ary.dup result.shift diff --git a/lib/wsdl/soap/standaloneServerStubCreator.rb b/lib/wsdl/soap/standaloneServerStubCreator.rb index 243ac1221..0b751b515 100644 --- a/lib/wsdl/soap/standaloneServerStubCreator.rb +++ b/lib/wsdl/soap/standaloneServerStubCreator.rb @@ -55,12 +55,12 @@ Methods = [ <<-EOD super(*arg) servant = #{class_name}.new - #{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style| - if style == :document - @router.add_document_operation(servant, soapaction, name, param_def) + #{class_name}::Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + @router.add_document_operation(servant, *definitions) else - qname = XSD::QName.new(namespace, name_as) - @router.add_rpc_operation(servant, qname, soapaction, name, param_def) + @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry diff --git a/lib/wsdl/xmlSchema/all.rb b/lib/wsdl/xmlSchema/all.rb index 1cb1ac16e..bb9566fea 100644 --- a/lib/wsdl/xmlSchema/all.rb +++ b/lib/wsdl/xmlSchema/all.rb @@ -29,6 +29,10 @@ class All < Info parent.targetnamespace end + def elementformdefault + parent.elementformdefault + end + def <<(element) @elements << element end diff --git a/lib/wsdl/xmlSchema/attribute.rb b/lib/wsdl/xmlSchema/attribute.rb index c82bd13bd..f9048661a 100644 --- a/lib/wsdl/xmlSchema/attribute.rb +++ b/lib/wsdl/xmlSchema/attribute.rb @@ -18,9 +18,8 @@ class Attribute < Info if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s - iv = "@#{name}" define_method(name) { - instance_variable_get(iv) || + instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end @@ -94,7 +93,11 @@ class Attribute < Info when FormAttrName @form = value.source when NameAttrName - @name = XSD::QName.new(targetnamespace, value.source) + if directelement? + @name = XSD::QName.new(targetnamespace, value.source) + else + @name = XSD::QName.new(nil, value.source) + end when TypeAttrName @type = value when DefaultAttrName @@ -111,6 +114,12 @@ class Attribute < Info nil end end + +private + + def directelement? + parent.is_a?(Schema) + end end diff --git a/lib/wsdl/xmlSchema/choice.rb b/lib/wsdl/xmlSchema/choice.rb index 435fd48e4..f6d27fa38 100644 --- a/lib/wsdl/xmlSchema/choice.rb +++ b/lib/wsdl/xmlSchema/choice.rb @@ -29,6 +29,10 @@ class Choice < Info parent.targetnamespace end + def elementformdefault + parent.elementformdefault + end + def <<(element) @elements << element end diff --git a/lib/wsdl/xmlSchema/complexType.rb b/lib/wsdl/xmlSchema/complexType.rb index 0d9c622c7..dc9ec954f 100644 --- a/lib/wsdl/xmlSchema/complexType.rb +++ b/lib/wsdl/xmlSchema/complexType.rb @@ -37,7 +37,13 @@ class ComplexType < Info end def targetnamespace - parent.is_a?(WSDL::XMLSchema::Element) ? nil : parent.targetnamespace + # inner elements can be qualified + # parent.is_a?(WSDL::XMLSchema::Element) ? nil : parent.targetnamespace + parent.targetnamespace + end + + def elementformdefault + parent.elementformdefault end AnyAsElement = Element.new(XSD::QName.new(nil, 'any'), XSD::AnyTypeName) diff --git a/lib/wsdl/xmlSchema/element.rb b/lib/wsdl/xmlSchema/element.rb index 4a144cd52..fffb6485d 100644 --- a/lib/wsdl/xmlSchema/element.rb +++ b/lib/wsdl/xmlSchema/element.rb @@ -18,9 +18,8 @@ class Element < Info if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s - iv = "@#{name}" define_method(name) { - instance_variable_get(iv) || + instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end @@ -37,6 +36,7 @@ class Element < Info end attr_writer :name # required + attr_writer :form attr_writer :type attr_writer :local_simpletype attr_writer :local_complextype @@ -46,6 +46,7 @@ class Element < Info attr_writer :nillable attr_reader_ref :name + attr_reader_ref :form attr_reader_ref :type attr_reader_ref :local_simpletype attr_reader_ref :local_complextype @@ -59,6 +60,7 @@ class Element < Info def initialize(name = nil, type = nil) super() @name = name + @form = nil @type = type @local_simpletype = @local_complextype = nil @constraint = nil @@ -70,18 +72,21 @@ class Element < Info end def refelement - @refelement ||= root.collect_elements[@ref] + @refelement ||= (@ref ? root.collect_elements[@ref] : nil) end def targetnamespace parent.targetnamespace end - def elementform - # ToDo: must be overwritten. + def elementformdefault parent.elementformdefault end + def elementform + self.form.nil? ? parent.elementformdefault : self.form + end + def parse_element(element) case element when SimpleTypeName @@ -102,7 +107,14 @@ class Element < Info def parse_attr(attr, value) case attr when NameAttrName - @name = XSD::QName.new(targetnamespace, value.source) + # namespace may be nil + if directelement? or elementform == 'qualified' + @name = XSD::QName.new(targetnamespace, value.source) + else + @name = XSD::QName.new(nil, value.source) + end + when FormAttrName + @form = value.source when TypeAttrName @type = value when RefAttrName @@ -110,14 +122,16 @@ class Element < Info when MaxOccursAttrName if parent.is_a?(All) if value.source != '1' - raise Parser::AttrConstraintError.new("cannot parse #{value} for #{attr}") + raise Parser::AttrConstraintError.new( + "cannot parse #{value} for #{attr}") end end @maxoccurs = value.source when MinOccursAttrName if parent.is_a?(All) unless ['0', '1'].include?(value.source) - raise Parser::AttrConstraintError.new("cannot parse #{value} for #{attr}") + raise Parser::AttrConstraintError.new( + "cannot parse #{value} for #{attr}") end end @minoccurs = value.source @@ -127,6 +141,12 @@ class Element < Info nil end end + +private + + def directelement? + parent.is_a?(Schema) + end end diff --git a/lib/wsdl/xmlSchema/schema.rb b/lib/wsdl/xmlSchema/schema.rb index 43447f9fb..ec97d07aa 100644 --- a/lib/wsdl/xmlSchema/schema.rb +++ b/lib/wsdl/xmlSchema/schema.rb @@ -1,5 +1,5 @@ # WSDL4R - XMLSchema schema definition for WSDL. -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2002, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -34,7 +34,8 @@ class Schema < Info @elements = XSD::NamedElements.new @attributes = XSD::NamedElements.new @imports = [] - @elementformdefault = "qualified" + @attributeformdefault = "unqualified" + @elementformdefault = "unqualified" @importedschema = {} @location = nil @root = self diff --git a/lib/wsdl/xmlSchema/sequence.rb b/lib/wsdl/xmlSchema/sequence.rb index bffb6a009..823fa3b7f 100644 --- a/lib/wsdl/xmlSchema/sequence.rb +++ b/lib/wsdl/xmlSchema/sequence.rb @@ -29,6 +29,10 @@ class Sequence < Info parent.targetnamespace end + def elementformdefault + parent.elementformdefault + end + def <<(element) @elements << element end diff --git a/lib/xsd/charset.rb b/lib/xsd/charset.rb index ccd22a774..15d5500fc 100644 --- a/lib/xsd/charset.rb +++ b/lib/xsd/charset.rb @@ -1,5 +1,5 @@ # XSD4R - Charset handling library. -# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -10,7 +10,7 @@ module XSD module Charset - @encoding = $KCODE + @internal_encoding = $KCODE class XSDError < StandardError; end class CharsetError < XSDError; end @@ -24,27 +24,40 @@ public # EncodingConvertMap = {} def Charset.init + EncodingConvertMap[['UTF8', 'X_ISO8859_1']] = + Proc.new { |str| str.unpack('U*').pack('C*') } + EncodingConvertMap[['X_ISO8859_1', 'UTF8']] = + Proc.new { |str| str.unpack('C*').pack('U*') } begin require 'xsd/iconvcharset' - @encoding = 'UTF8' - sjtag = (/(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM) ? 'cp932' : 'shift_jis' - EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) } - EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) } - EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "euc-jp", str) } - EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "utf-8", str) } - EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", sjtag, str) } - EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", sjtag, str) } + @internal_encoding = 'UTF8' + sjtag = (/(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM) ? 'cp932' : + 'shift_jis' + EncodingConvertMap[['UTF8', 'EUC' ]] = + Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) } + EncodingConvertMap[['EUC' , 'UTF8']] = + Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) } + EncodingConvertMap[['EUC' , 'SJIS']] = + Proc.new { |str| IconvCharset.safe_iconv(sjtag, "euc-jp", str) } + EncodingConvertMap[['UTF8', 'SJIS']] = + Proc.new { |str| IconvCharset.safe_iconv(sjtag, "utf-8", str) } + EncodingConvertMap[['SJIS', 'UTF8']] = + Proc.new { |str| IconvCharset.safe_iconv("utf-8", sjtag, str) } + EncodingConvertMap[['SJIS', 'EUC' ]] = + Proc.new { |str| IconvCharset.safe_iconv("euc-jp", sjtag, str) } rescue LoadError begin require 'nkf' - EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| NKF.nkf('-sXm0', str) } - EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| NKF.nkf('-eXm0', str) } + EncodingConvertMap[['EUC' , 'SJIS']] = + Proc.new { |str| NKF.nkf('-sXm0', str) } + EncodingConvertMap[['SJIS', 'EUC' ]] = + Proc.new { |str| NKF.nkf('-eXm0', str) } rescue LoadError end begin require 'uconv' - @encoding = 'UTF8' + @internal_encoding = 'UTF8' EncodingConvertMap[['UTF8', 'EUC' ]] = Uconv.method(:u8toeuc) EncodingConvertMap[['UTF8', 'SJIS']] = Uconv.method(:u8tosjis) EncodingConvertMap[['EUC' , 'UTF8']] = Uconv.method(:euctou8) @@ -60,6 +73,8 @@ public 'EUC' => 'euc-jp', 'SJIS' => 'shift_jis', 'UTF8' => 'utf-8', + 'X_ISO_8859_1' => 'iso-8859-1', + 'X_UNKNOWN' => nil, } @@ -67,24 +82,24 @@ public ## handlers # def Charset.encoding - @encoding + @internal_encoding end def Charset.encoding=(encoding) warn("xsd charset is set to #{encoding}") if $DEBUG - @encoding = encoding + @internal_encoding = encoding end - def Charset.encoding_label - charset_label(@encoding) + def Charset.xml_encoding_label + charset_label(@internal_encoding) end def Charset.encoding_to_xml(str, charset) - encoding_conv(str, @encoding, charset_str(charset)) + encoding_conv(str, @internal_encoding, charset_str(charset)) end def Charset.encoding_from_xml(str, charset) - encoding_conv(str, charset_str(charset), @encoding) + encoding_conv(str, charset_str(charset), @internal_encoding) end def Charset.encoding_conv(str, enc_from, enc_to) @@ -94,7 +109,7 @@ public converter.call(str) else raise CharsetConversionError.new( - "Converter not found: #{ enc_from } -> #{ enc_to }") + "Converter not found: #{enc_from} -> #{enc_to}") end end @@ -104,26 +119,26 @@ public def Charset.charset_str(label) if CharsetMap.respond_to?(:key) - CharsetMap.key(label.downcase) + CharsetMap.key(label.downcase) || 'X_UNKNOWN' else - CharsetMap.index(label.downcase) + CharsetMap.index(label.downcase) || 'X_UNKNOWN' end end # us_ascii = '[\x00-\x7F]' us_ascii = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted. - USASCIIRegexp = Regexp.new("\\A#{ us_ascii }*\\z", nil, "NONE") + USASCIIRegexp = Regexp.new("\\A#{us_ascii}*\\z", nil, "NONE") twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])' threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])' - character_euc = "(?:#{ us_ascii }|#{ twobytes_euc }|#{ threebytes_euc })" - EUCRegexp = Regexp.new("\\A#{ character_euc }*\\z", nil, "NONE") + character_euc = "(?:#{us_ascii}|#{twobytes_euc}|#{threebytes_euc})" + EUCRegexp = Regexp.new("\\A#{character_euc}*\\z", nil, "NONE") # onebyte_sjis = '[\x00-\x7F\xA1-\xDF]' onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted. twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])' - character_sjis = "(?:#{ onebyte_sjis }|#{ twobytes_sjis })" - SJISRegexp = Regexp.new("\\A#{ character_sjis }*\\z", nil, "NONE") + character_sjis = "(?:#{onebyte_sjis}|#{twobytes_sjis})" + SJISRegexp = Regexp.new("\\A#{character_sjis}*\\z", nil, "NONE") # 0xxxxxxx # 110yyyyy 10xxxxxx @@ -132,8 +147,9 @@ public threebytes_utf8 = '(?:[\xE0-\xEF][\x80-\xBF][\x80-\xBF])' # 11110uuu 10uuuzzz 10yyyyyy 10xxxxxx fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])' - character_utf8 = "(?:#{ us_ascii }|#{ twobytes_utf8 }|#{ threebytes_utf8 }|#{ fourbytes_utf8 })" - UTF8Regexp = Regexp.new("\\A#{ character_utf8 }*\\z", nil, "NONE") + character_utf8 = + "(?:#{us_ascii}|#{twobytes_utf8}|#{threebytes_utf8}|#{fourbytes_utf8})" + UTF8Regexp = Regexp.new("\\A#{character_utf8}*\\z", nil, "NONE") def Charset.is_us_ascii(str) USASCIIRegexp =~ str @@ -162,7 +178,7 @@ public when 'SJIS' is_sjis(str) else - raise UnknownCharsetError.new("Unknown charset: #{ code }") + raise UnknownCharsetError.new("Unknown charset: #{code}") end end end diff --git a/lib/xsd/codegen/gensupport.rb b/lib/xsd/codegen/gensupport.rb index 854534154..1e85d3668 100644 --- a/lib/xsd/codegen/gensupport.rb +++ b/lib/xsd/codegen/gensupport.rb @@ -1,5 +1,5 @@ # XSD4R - Code generation support -# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. +# Copyright (C) 2004, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; @@ -10,7 +10,8 @@ module XSD module CodeGen # from the file 'keywords' in 1.9. -KEYWORD = %w( +KEYWORD = {} +%w( __LINE__ __FILE__ BEGIN @@ -51,7 +52,7 @@ until when while yield -) +).each { |k| KEYWORD[k] = nil } module GenSupport def capitalize(target) @@ -96,12 +97,12 @@ module GenSupport module_function :safemethodname? def safevarname(name) - safename = name.scan(/[a-zA-Z0-9_]+/).join('_') - safename = uncapitalize(safename) + safename = uncapitalize(name.scan(/[a-zA-Z0-9_]+/).join('_')) if /^[a-z]/ !~ safename or keyword?(safename) - safename = "v_#{safename}" + "v_#{safename}" + else + safename end - safename end module_function :safevarname @@ -111,7 +112,7 @@ module GenSupport module_function :safevarname? def keyword?(word) - KEYWORD.include?(word) + KEYWORD.key?(word) end module_function :keyword? diff --git a/lib/xsd/datatypes.rb b/lib/xsd/datatypes.rb index d0fc44d69..bbe6c8578 100644 --- a/lib/xsd/datatypes.rb +++ b/lib/xsd/datatypes.rb @@ -560,23 +560,20 @@ module XSDDateTimeImpl def screen_data(t) # convert t to a DateTime as an internal representation. - if t.is_a?(DateTime) + if t.respond_to?(:to_datetime) # 1.9 or later + t.to_datetime + elsif t.is_a?(DateTime) t elsif t.is_a?(Date) - if t.respond_to?(:to_datetime) # from 1.9 - t.to_datetime - else - t = screen_data_str(t) - t <<= 12 if t.year < 0 - t - end + t = screen_data_str(t) + t <<= 12 if t.year < 0 + t elsif t.is_a?(Time) - sec, min, hour, mday, month, year = t.to_a[0..5] - diffday = t.usec.to_r / 1000000 / SecInDay + jd = DateTime.civil_to_jd(t.year, t.mon, t.mday, DateTime::ITALY) + fr = DateTime.time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + + t.usec.to_r / 1000000 / SecInDay of = t.utc_offset.to_r / SecInDay - data = DateTime.civil(year, month, mday, hour, min, sec, of) - data += diffday - data + DateTime.new0(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) else screen_data_str(t) end diff --git a/lib/xsd/ns.rb b/lib/xsd/ns.rb index b63a8a5cd..53eeae713 100644 --- a/lib/xsd/ns.rb +++ b/lib/xsd/ns.rb @@ -72,7 +72,7 @@ public if (name.namespace == @default_namespace) name.name elsif @ns2tag.key?(name.namespace) - @ns2tag[name.namespace] + ':' << name.name + "#{@ns2tag[name.namespace]}:#{name.name}" else raise FormatError.new("namespace: #{name.namespace} not defined yet") end diff --git a/lib/xsd/qname.rb b/lib/xsd/qname.rb index 18b002764..bb9763a69 100644 --- a/lib/xsd/qname.rb +++ b/lib/xsd/qname.rb @@ -31,9 +31,6 @@ class QName end def match(rhs) - unless self.class === rhs - return false - end if rhs.namespace and (rhs.namespace != @namespace) return false end @@ -44,7 +41,7 @@ class QName end def ==(rhs) - (self.class === rhs && @namespace == rhs.namespace && @name == rhs.name) + !rhs.nil? and @namespace == rhs.namespace and @name == rhs.name end def ===(rhs) @@ -73,6 +70,8 @@ class QName NormalizedNameRegexp =~ str self.new($1, $2) end + + EMPTY = QName.new.freeze end diff --git a/test/soap/asp.net/hello.wsdl b/test/soap/asp.net/hello.wsdl new file mode 100644 index 000000000..b94129c15 --- /dev/null +++ b/test/soap/asp.net/hello.wsdl @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="utf-8"?> +<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" +xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" +xmlns:s="http://www.w3.org/2001/XMLSchema" +xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" +xmlns:tns="http://localhost/WebService/" +xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" +xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" +targetNamespace="http://localhost/WebService/" +xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <wsdl:types> + <s:schema elementFormDefault="qualified" +targetNamespace="http://localhost/WebService/"> + <s:element name="HelloWorld"> + <s:complexType /> + </s:element> + <s:element name="HelloWorldResponse"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" +name="HelloWorldResult" type="s:string" /> + </s:sequence> + </s:complexType> + </s:element> + <s:element name="SayHello"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="name" +type="s:string" /> + </s:sequence> + </s:complexType> + </s:element> + <s:element name="SayHelloResponse"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" +name="SayHelloResult" type="s:string" /> + </s:sequence> + </s:complexType> + </s:element> + </s:schema> + </wsdl:types> + <wsdl:message name="HelloWorldSoapIn"> + <wsdl:part name="parameters" element="tns:HelloWorld" /> + </wsdl:message> + <wsdl:message name="HelloWorldSoapOut"> + <wsdl:part name="parameters" element="tns:HelloWorldResponse" /> + </wsdl:message> + <wsdl:message name="SayHelloSoapIn"> + <wsdl:part name="parameters" element="tns:SayHello" /> + </wsdl:message> + <wsdl:message name="SayHelloSoapOut"> + <wsdl:part name="parameters" element="tns:SayHelloResponse" /> + </wsdl:message> + <wsdl:portType name="Service1Soap"> + <wsdl:operation name="HelloWorld"> + <wsdl:input message="tns:HelloWorldSoapIn" /> + <wsdl:output message="tns:HelloWorldSoapOut" /> + </wsdl:operation> + <wsdl:operation name="SayHello"> + <wsdl:input message="tns:SayHelloSoapIn" /> + <wsdl:output message="tns:SayHelloSoapOut" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="Service1Soap" type="tns:Service1Soap"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" +style="document" /> + <wsdl:operation name="HelloWorld"> + <soap:operation +soapAction="http://localhost/WebService/HelloWorld" style="document" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="SayHello"> + <soap:operation soapAction="http://localhost/WebService/SayHello" +style="document" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="Service1"> + <documentation xmlns="http://schemas.xmlsoap.org/wsdl/" /> + <wsdl:port name="Service1Soap" binding="tns:Service1Soap"> + <soap:address +location="http://localhost/WebService/Service1.asmx" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/test/soap/asp.net/test_aspdotnet.rb b/test/soap/asp.net/test_aspdotnet.rb new file mode 100644 index 000000000..7d5f3fd28 --- /dev/null +++ b/test/soap/asp.net/test_aspdotnet.rb @@ -0,0 +1,111 @@ +require 'test/unit' +require 'soap/rpc/standaloneServer' +require 'soap/rpc/driver' + + +module SOAP; module ASPDotNet + + +class TestASPDotNet < Test::Unit::TestCase + class Server < ::SOAP::RPC::StandaloneServer + Namespace = "http://localhost/WebService/" + + def on_init + add_document_method( + self, + Namespace + 'SayHello', + 'sayHello', + XSD::QName.new(Namespace, 'SayHello'), + XSD::QName.new(Namespace, 'SayHelloResponse') + ) + end + + def sayHello(arg) + name = arg['name'] + "Hello #{name}" + end + end + + Port = 17171 + Endpoint = "http://localhost:#{Port}/" + + def setup + setup_server + @client = nil + end + + def teardown + teardown_server + @client.reset_stream if @client + end + + def setup_server + @server = Server.new('Test', Server::Namespace, '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @server_thread = start_server_thread(@server) + end + + def teardown_server + @server.shutdown + @server_thread.kill + @server_thread.join + end + + def start_server_thread(server) + t = Thread.new { + Thread.current.abort_on_exception = true + server.start + } + t + end + + def test_document_method + @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) + @client.wiredump_dev = STDOUT if $DEBUG + @client.add_document_method('sayHello', Server::Namespace + 'SayHello', + XSD::QName.new(Server::Namespace, 'SayHello'), + XSD::QName.new(Server::Namespace, 'SayHelloResponse')) + assert_equal("Hello Mike", @client.sayHello(:name => "Mike")) + end + + def test_aspdotnethandler + @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) + @client.wiredump_dev = STDOUT if $DEBUG + @client.add_method_with_soapaction('sayHello', Server::Namespace + 'SayHello', 'name') + @client.default_encodingstyle = SOAP::EncodingStyle::ASPDotNetHandler::Namespace + assert_equal("Hello Mike", @client.sayHello("Mike")) + end + + if defined?(HTTPAccess2) + + # qualified! + REQUEST_ASPDOTNETHANDLER = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:sayHello xmlns:n1="http://localhost/WebService/"> + <n1:name>Mike</n1:name> + </n1:sayHello> + </env:Body> +</env:Envelope>] + + def test_aspdotnethandler_envelope + @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) + @client.wiredump_dev = str = '' + @client.add_method_with_soapaction('sayHello', Server::Namespace + 'SayHello', 'name') + @client.default_encodingstyle = SOAP::EncodingStyle::ASPDotNetHandler::Namespace + assert_equal("Hello Mike", @client.sayHello("Mike")) + assert_equal(REQUEST_ASPDOTNETHANDLER, parse_requestxml(str)) + end + + def parse_requestxml(str) + str.split(/\r?\n\r?\n/)[3] + end + + end +end + + +end; end diff --git a/test/soap/header/test_simplehandler.rb b/test/soap/header/test_simplehandler.rb new file mode 100644 index 000000000..75dbd4a55 --- /dev/null +++ b/test/soap/header/test_simplehandler.rb @@ -0,0 +1,116 @@ +require 'test/unit' +require 'soap/rpc/driver' +require 'soap/rpc/standaloneServer' +require 'soap/header/simplehandler' + + +module SOAP +module Header + + +class TestSimpleHandler < Test::Unit::TestCase + Port = 17171 + PortName = 'http://tempuri.org/authHeaderPort' + + class PingPortServer < SOAP::RPC::StandaloneServer + class PingService + def self.create + new + end + + def ping + Thread.current[:pingheader] + end + end + + def initialize(*arg) + super + add_rpc_servant(PingService.new, PortName) + add_request_headerhandler(PingServerHeaderHandler) + end + + class PingServerHeaderHandler < SOAP::Header::SimpleHandler + MyHeaderName = XSD::QName.new("http://xmlsoap.org/Ping", "PingHeader") + + def self.create + new + end + + def initialize() + super(MyHeaderName) + end + + def on_simple_outbound + "dummy" + end + + def on_simple_inbound(my_header, mu) + Thread.current[:pingheader] = my_header + end + end + end + + class PingClientHeaderHandler < SOAP::Header::SimpleHandler + MyHeaderName = XSD::QName.new("http://xmlsoap.org/Ping", "PingHeader") + + def initialize(pingHeader) + super(MyHeaderName) + @pingHeader = pingHeader + @mustunderstand = false + end + + def on_simple_outbound + @pingHeader # --- note, not a Hash + end + + def on_simple_inbound(my_header, mustunderstand) + Thread.current[:pingheader] = my_header + end + end + + def setup + @endpoint = "http://localhost:#{Port}/" + setup_server + setup_client + end + + def setup_server + @server = PingPortServer.new(self.class.name, nil, '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @t = Thread.new { + @server.start + } + end + + def setup_client + @client = SOAP::RPC::Driver.new(@endpoint, PortName) + @client.wiredump_dev = STDERR if $DEBUG + @client.add_method('ping') + end + + def teardown + teardown_server + teardown_client + end + + def teardown_server + @server.shutdown + @t.kill + @t.join + end + + def teardown_client + @client.reset_stream + end + + def test_string + h = PingClientHeaderHandler.new('pingheader') + @client.headerhandler << h + assert_equal("pingheader", @client.ping) + assert_equal("dummy", Thread.current[:pingheader]) + end +end + + +end +end diff --git a/test/soap/ssl/test_ssl.rb b/test/soap/ssl/test_ssl.rb index d6df97016..38f859acd 100644 --- a/test/soap/ssl/test_ssl.rb +++ b/test/soap/ssl/test_ssl.rb @@ -179,14 +179,14 @@ __EOP__ cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "ca.cert") cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "subca.cert") #cfg.timeout = 123 - assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) - # cfg["protocol.http.ssl_config.ciphers"] = "!ALL" + # begin @client.hello_world("ssl client") assert(false) rescue OpenSSL::SSL::SSLError => ssle - assert_equal("no ciphers available", ssle.message) + # depends on OpenSSL version. (?:0.9.8|0.9.7) + assert_match(/\A(?:SSL_CTX_set_cipher_list:: no cipher match|no ciphers available)\z/, ssle.message) end # cfg["protocol.http.ssl_config.ciphers"] = "ALL" @@ -201,7 +201,7 @@ private def setup_server svrcmd = "#{q(RUBY)} " - svrcmd << "-d " if $DEBUG + #svrcmd << "-d " if $DEBUG svrcmd << File.join(DIR, "sslsvr.rb") svrout = IO.popen(svrcmd) @serverpid = Integer(svrout.gets.chomp) diff --git a/test/soap/swa/test_file.rb b/test/soap/swa/test_file.rb index 8389d8826..1ec7aa92a 100644 --- a/test/soap/swa/test_file.rb +++ b/test/soap/swa/test_file.rb @@ -47,11 +47,14 @@ class TestFile < Test::Unit::TestCase @client.reset_stream end - def test_file + def test_get_file assert_equal( File.open(THIS_FILE) { |f| f.read }, @client.get_file['file'].content ) + end + + def test_put_file assert_equal( "File 'foo' was received ok.", @client.put_file('foo', diff --git a/test/soap/test_envelopenamespace.rb b/test/soap/test_envelopenamespace.rb new file mode 100644 index 000000000..5b7d28134 --- /dev/null +++ b/test/soap/test_envelopenamespace.rb @@ -0,0 +1,92 @@ +require 'test/unit' +require 'soap/rpc/driver' +require 'webrick' +require 'logger' + + +module SOAP + + +class TestEnvelopeNamespace < Test::Unit::TestCase + Port = 17171 + TemporaryNamespace = 'urn:foo' + + def setup + @logger = Logger.new(STDERR) + @logger.level = Logger::Severity::ERROR + @url = "http://localhost:#{Port}/" + @server = @client = nil + @server_thread = nil + setup_server + setup_client + end + + def teardown + teardown_client + teardown_server + end + + def setup_server + @server = WEBrick::HTTPServer.new( + :BindAddress => "0.0.0.0", + :Logger => @logger, + :Port => Port, + :AccessLog => [], + :DocumentRoot => File.dirname(File.expand_path(__FILE__)) + ) + @server.mount( + '/', + WEBrick::HTTPServlet::ProcHandler.new(method(:do_server_proc).to_proc) + ) + @server_thread = start_server_thread(@server) + end + + def setup_client + @client = SOAP::RPC::Driver.new(@url, '') + @client.add_method("do_server_proc") + end + + def teardown_server + @server.shutdown + @server_thread.kill + @server_thread.join + end + + def teardown_client + @client.reset_stream + end + + def start_server_thread(server) + t = Thread.new { + Thread.current.abort_on_exception = true + server.start + } + t + end + + def do_server_proc(req, res) + res['content-type'] = 'text/xml' + res.body = <<__EOX__ +<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:env="#{TemporaryNamespace}"> + <env:Body> + <n1:do_server_proc xmlns:n1="urn:foo" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> + <return>hello world</return> + </n1:do_server_proc> + </env:Body> +</env:Envelope> +__EOX__ + end + + def test_normal + assert_raise(SOAP::ResponseFormatError) do + @client.do_server_proc + end + @client.options["soap.envelope.requestnamespace"] = TemporaryNamespace + @client.options["soap.envelope.responsenamespace"] = TemporaryNamespace + assert_equal('hello world', @client.do_server_proc) + end +end + + +end diff --git a/test/soap/test_httpconfigloader.rb b/test/soap/test_httpconfigloader.rb new file mode 100644 index 000000000..b06243f66 --- /dev/null +++ b/test/soap/test_httpconfigloader.rb @@ -0,0 +1,39 @@ +require 'test/unit' +require 'soap/httpconfigloader' +require 'soap/rpc/driver' + +if defined?(HTTPAccess2) + +module SOAP + + +class TestHTTPConfigLoader < Test::Unit::TestCase + DIR = File.dirname(File.expand_path(__FILE__)) + + def setup + @client = SOAP::RPC::Driver.new(nil, nil) + end + + def test_property + testpropertyname = File.join(DIR, 'soapclient.properties') + File.open(testpropertyname, "w") do |f| + f <<<<__EOP__ +protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER +# depth: 1 causes an error (intentional) +protocol.http.ssl_config.verify_depth = 1 +protocol.http.ssl_config.ciphers = ALL +__EOP__ + end + begin + @client.loadproperty(testpropertyname) + assert_equal('ALL', @client.options['protocol.http.ssl_config.ciphers']) + ensure + File.unlink(testpropertyname) + end + end +end + + +end + +end diff --git a/test/soap/test_no_indent.rb b/test/soap/test_no_indent.rb new file mode 100644 index 000000000..f49fb7389 --- /dev/null +++ b/test/soap/test_no_indent.rb @@ -0,0 +1,86 @@ +require 'test/unit' +require 'soap/rpc/standaloneServer' +require 'soap/rpc/driver' + +if defined?(HTTPAccess2) + +module SOAP + + +class TestNoIndent < Test::Unit::TestCase + Port = 17171 + + class NopServer < SOAP::RPC::StandaloneServer + def initialize(*arg) + super + add_rpc_method(self, 'nop') + end + + def nop + SOAP::RPC::SOAPVoid.new + end + end + + def setup + @server = NopServer.new(self.class.name, nil, '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @t = Thread.new { + @server.start + } + @endpoint = "http://localhost:#{Port}/" + @client = SOAP::RPC::Driver.new(@endpoint) + @client.add_rpc_method('nop') + end + + def teardown + @server.shutdown + @t.kill + @t.join + @client.reset_stream + end + + INDENT_XML = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <nop env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> + </nop> + </env:Body> +</env:Envelope>] + + NO_INDENT_XML = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" +xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<env:Body> +<nop env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> +</nop> +</env:Body> +</env:Envelope>] + + def test_indent + @client.wiredump_dev = str = '' + @client.options["soap.envelope.no_indent"] = false + @client.nop + assert_equal(INDENT_XML, parse_requestxml(str)) + end + + def test_no_indent + @client.wiredump_dev = str = '' + @client.options["soap.envelope.no_indent"] = true + @client.nop + assert_equal(NO_INDENT_XML, parse_requestxml(str)) + end + + def parse_requestxml(str) + str.split(/\r?\n\r?\n/)[3] + end +end + + +end + +end diff --git a/test/soap/test_soapelement.rb b/test/soap/test_soapelement.rb index 6cf91f93d..66e2a836a 100644 --- a/test/soap/test_soapelement.rb +++ b/test/soap/test_soapelement.rb @@ -1,5 +1,6 @@ require 'test/unit' require 'soap/baseData' +require 'soap/mapping' module SOAP @@ -36,7 +37,7 @@ class TestSOAPElement < Test::Unit::TestCase assert_equal(LiteralNamespace, obj.encodingstyle) assert_equal({}, obj.extraattr) assert_equal([], obj.precedents) - assert_equal(false, obj.qualified) + assert_equal(nil, obj.qualified) assert_equal(nil, obj.text) assert(obj.members.empty?) diff --git a/test/soap/test_streamhandler.rb b/test/soap/test_streamhandler.rb index a8d06d5f2..c31254513 100644 --- a/test/soap/test_streamhandler.rb +++ b/test/soap/test_streamhandler.rb @@ -98,7 +98,7 @@ __EOX__ end def parse_req_header(str) - if ::SOAP::StreamHandler::Client.to_s == 'SOAP::NetHttpClient' + if ::SOAP::HTTPStreamHandler::Client.to_s == 'SOAP::NetHttpClient' str = eval(str.split(/\r?\n/)[4][3..-1]) end parse_req_header_http_access2(str) diff --git a/test/wsdl/any/any.wsdl b/test/wsdl/any/any.wsdl new file mode 100644 index 000000000..4d1f73a8c --- /dev/null +++ b/test/wsdl/any/any.wsdl @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<definitions name="echo" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="urn:example.com:echo" + xmlns:txd="urn:example.com:echo-type" + targetNamespace="urn:example.com:echo" + xmlns="http://schemas.xmlsoap.org/wsdl/"> + <types> + <xsd:schema targetNamespace="urn:example.com:echo-type"> + <xsd:complexType name="foo.bar"> + <xsd:sequence> + <xsd:any /> + </xsd:sequence> + </xsd:complexType> + </xsd:schema> + </types> + + <message name="msg_echoitem"> + <part name="echoitem" type="txd:foo.bar"/> + </message> + + <portType name="echo_port_type"> + <operation name="echo"> + <input message="tns:msg_echoitem"/> + <output message="tns:msg_echoitem"/> + </operation> + </portType> + + <binding name="echo_binding" type="tns:echo_port_type"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/> + <operation name="echo"> + <soap:operation soapAction="urn:example.com:echo"/> + <input> + <soap:body use="encoded" namespace="urn:example.com:echo" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body use="encoded" namespace="urn:example.com:echo" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + </binding> + + <service name="echo_service"> + <port name="echo_port" binding="tns:echo_binding"> + <soap:address location="http://localhost:10080"/> + </port> + </service> +</definitions> diff --git a/test/wsdl/any/expectedDriver.rb b/test/wsdl/any/expectedDriver.rb new file mode 100644 index 000000000..6d1827fb9 --- /dev/null +++ b/test/wsdl/any/expectedDriver.rb @@ -0,0 +1,54 @@ +require 'echo.rb' + +require 'soap/rpc/driver' + +class Echo_port_type < ::SOAP::RPC::Driver + DefaultEndpointUrl = "http://localhost:10080" + MappingRegistry = ::SOAP::Mapping::Registry.new + + MappingRegistry.set( + FooBar, + ::SOAP::SOAPStruct, + ::SOAP::Mapping::Registry::TypedStructFactory, + { :type => XSD::QName.new("urn:example.com:echo-type", "foo.bar") } + ) + + Methods = [ + [ XSD::QName.new("urn:example.com:echo", "echo"), + "urn:example.com:echo", + "echo", + [ ["in", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]], + ["retval", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ] + ] + + def initialize(endpoint_url = nil) + endpoint_url ||= DefaultEndpointUrl + super(endpoint_url, nil) + self.mapping_registry = MappingRegistry + init_methods + end + +private + + def init_methods + Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + add_document_operation(*definitions) + else + add_rpc_operation(*definitions) + qname = definitions[0] + name = definitions[2] + if qname.name != name and qname.name.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| + __send__(name, *arg) + end + end + end + end + end +end + diff --git a/test/wsdl/any/expectedEcho.rb b/test/wsdl/any/expectedEcho.rb new file mode 100644 index 000000000..456950dfe --- /dev/null +++ b/test/wsdl/any/expectedEcho.rb @@ -0,0 +1,14 @@ +require 'xsd/qname' + +# {urn:example.com:echo-type}foo.bar +class FooBar + @@schema_type = "foo.bar" + @@schema_ns = "urn:example.com:echo-type" + @@schema_element = [["any", [nil, XSD::QName.new(nil, "any")]]] + + attr_accessor :any + + def initialize(any = nil) + @any = any + end +end diff --git a/test/wsdl/any/expectedService.rb b/test/wsdl/any/expectedService.rb new file mode 100644 index 000000000..e3885e7c6 --- /dev/null +++ b/test/wsdl/any/expectedService.rb @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby +require 'echoServant.rb' + +require 'soap/rpc/standaloneServer' +require 'soap/mapping/registry' + +class Echo_port_type + MappingRegistry = ::SOAP::Mapping::Registry.new + + MappingRegistry.set( + FooBar, + ::SOAP::SOAPStruct, + ::SOAP::Mapping::Registry::TypedStructFactory, + { :type => XSD::QName.new("urn:example.com:echo-type", "foo.bar") } + ) + + Methods = [ + [ XSD::QName.new("urn:example.com:echo", "echo"), + "urn:example.com:echo", + "echo", + [ ["in", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]], + ["retval", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ] + ] +end + +class Echo_port_typeApp < ::SOAP::RPC::StandaloneServer + def initialize(*arg) + super(*arg) + servant = Echo_port_type.new + Echo_port_type::Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + @router.add_document_operation(servant, *definitions) + else + @router.add_rpc_operation(servant, *definitions) + end + end + self.mapping_registry = Echo_port_type::MappingRegistry + end +end + +if $0 == __FILE__ + # Change listen port. + server = Echo_port_typeApp.new('app', nil, '0.0.0.0', 10080) + trap(:INT) do + server.shutdown + end + server.start +end diff --git a/test/wsdl/any/test_any.rb b/test/wsdl/any/test_any.rb new file mode 100644 index 000000000..7b0e480be --- /dev/null +++ b/test/wsdl/any/test_any.rb @@ -0,0 +1,46 @@ +require 'test/unit' +require 'wsdl/parser' +require 'wsdl/soap/wsdl2ruby' +module WSDL; module Any + + +class TestAny < Test::Unit::TestCase + DIR = File.dirname(File.expand_path(__FILE__)) + def pathname(filename) + File.join(DIR, filename) + end + + def test_any + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("any.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['driver'] = nil + gen.opt['client_skelton'] = nil + gen.opt['servant_skelton'] = nil + gen.opt['standalone_server_stub'] = nil + gen.opt['force'] = true + gen.run + compare("expectedDriver.rb", "echoDriver.rb") + compare("expectedEcho.rb", "echo.rb") + compare("expectedService.rb", "echo_service.rb") + + File.unlink(pathname("echo_service.rb")) + File.unlink(pathname("echo.rb")) + File.unlink(pathname("echo_serviceClient.rb")) + File.unlink(pathname("echoDriver.rb")) + File.unlink(pathname("echoServant.rb")) + end + + def compare(expected, actual) + assert_equal(loadfile(expected), loadfile(actual), actual) + end + + def loadfile(file) + File.open(pathname(file)) { |f| f.read } + end +end + + +end; end diff --git a/test/wsdl/document/echo.rb b/test/wsdl/document/echo.rb index 05f00412f..c6df75aca 100644 --- a/test/wsdl/document/echo.rb +++ b/test/wsdl/document/echo.rb @@ -5,7 +5,7 @@ class Echoele @@schema_type = "echoele" @@schema_ns = "urn:docrpc" @@schema_attribute = {XSD::QName.new(nil, "attr_string") => "SOAP::SOAPString", XSD::QName.new(nil, "attr-int") => "SOAP::SOAPInt"} - @@schema_element = [["struct1", "Echo_struct"], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] + @@schema_element = [["struct1", ["Echo_struct", XSD::QName.new(nil, "struct1")]], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] attr_accessor :struct1 attr_accessor :struct_2 @@ -38,7 +38,7 @@ class Echo_response @@schema_type = "echo_response" @@schema_ns = "urn:docrpc" @@schema_attribute = {XSD::QName.new(nil, "attr_string") => "SOAP::SOAPString", XSD::QName.new(nil, "attr-int") => "SOAP::SOAPInt"} - @@schema_element = [["struct1", "Echo_struct"], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] + @@schema_element = [["struct1", ["Echo_struct", XSD::QName.new(nil, "struct1")]], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] attr_accessor :struct1 attr_accessor :struct_2 @@ -70,18 +70,18 @@ end class Echo_struct @@schema_type = "echo_struct" @@schema_ns = "urn:docrpc" - @@schema_attribute = {XSD::QName.new("urn:docrpc", "m_attr") => "SOAP::SOAPString"} - @@schema_element = [["m_string", "SOAP::SOAPString"], ["m_datetime", "SOAP::SOAPDateTime"]] + @@schema_attribute = {XSD::QName.new(nil, "m_attr") => "SOAP::SOAPString"} + @@schema_element = [["m_string", ["SOAP::SOAPString", XSD::QName.new(nil, "m_string")]], ["m_datetime", ["SOAP::SOAPDateTime", XSD::QName.new(nil, "m_datetime")]]] attr_accessor :m_string attr_accessor :m_datetime def xmlattr_m_attr - (@__xmlattr ||= {})[XSD::QName.new("urn:docrpc", "m_attr")] + (@__xmlattr ||= {})[XSD::QName.new(nil, "m_attr")] end def xmlattr_m_attr=(value) - (@__xmlattr ||= {})[XSD::QName.new("urn:docrpc", "m_attr")] = value + (@__xmlattr ||= {})[XSD::QName.new(nil, "m_attr")] = value end def initialize(m_string = nil, m_datetime = nil) diff --git a/test/wsdl/marshal/person_org.rb b/test/wsdl/marshal/person_org.rb index 55405b658..f8c0e0db7 100644 --- a/test/wsdl/marshal/person_org.rb +++ b/test/wsdl/marshal/person_org.rb @@ -4,7 +4,7 @@ require 'xsd/qname' class Person @@schema_type = "Person" @@schema_ns = "http://www.jin.gr.jp/~nahi/xmlns/sample/Person" - @@schema_element = [["familyname", "SOAP::SOAPString"], ["givenname", "SOAP::SOAPString"], ["var1", "SOAP::SOAPInt"], ["var2", "SOAP::SOAPDouble"], ["var3", "SOAP::SOAPString"]] + @@schema_element = [["familyname", ["SOAP::SOAPString", XSD::QName.new(nil, "familyname")]], ["givenname", ["SOAP::SOAPString", XSD::QName.new(nil, "givenname")]], ["var1", ["SOAP::SOAPInt", XSD::QName.new(nil, "var1")]], ["var2", ["SOAP::SOAPDouble", XSD::QName.new(nil, "var2")]], ["var3", ["SOAP::SOAPString", XSD::QName.new(nil, "var3")]]] attr_accessor :familyname attr_accessor :givenname diff --git a/test/wsdl/qualified/lp.wsdl b/test/wsdl/qualified/lp.wsdl new file mode 100644 index 000000000..b107b7b39 --- /dev/null +++ b/test/wsdl/qualified/lp.wsdl @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<definitions + name="lp" + targetNamespace="urn:lp" + xmlns:tns="urn:lp" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns="http://schemas.xmlsoap.org/wsdl/"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema"> + <import namespace="urn:lp" schemaLocation="lp.xsd"/> + </schema> + </types> + + <message name="login_in"> + <part name="parameters" element="tns:login" /> + </message> + <message name="login_out"> + <part name="parameters" element="tns:loginResponse" /> + </message> + + <portType name="lp_porttype"> + <operation name="login"> + <input message="tns:login_in" /> + <output message="tns:login_out" /> + </operation> + </portType> + + <binding name="lp_binding" type="tns:lp_porttype"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> + <operation name="login"> + <soap:operation soapAction="urn:lp:login" style="document" /> + <input> + <soap:body use="literal" /> + </input> + <output> + <soap:body use="literal" /> + </output> + </operation> + </binding> + + <service name="lp_service"> + <port name="lp_service_port" binding="tns:lp_binding"> + <soap:address location="http://localhost:17171/" /> + </port> + </service> +</definitions> diff --git a/test/wsdl/qualified/lp.xsd b/test/wsdl/qualified/lp.xsd new file mode 100644 index 000000000..12bcbd8ce --- /dev/null +++ b/test/wsdl/qualified/lp.xsd @@ -0,0 +1,26 @@ +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:lp="urn:lp" targetNamespace="urn:lp" elementFormDefault="unqualified"> + + <xs:complexType name="login"> + <xs:sequence> + <xs:element name="username" type="xs:string"/> + <xs:element name="password" type="xs:string"/> + <xs:element name="timezone" type="xs:string" minOccurs="0" maxOccurs="1"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="login" type="lp:login"/> + + <xs:complexType name="loginResponse"> + <xs:sequence> + <xs:element name="loginResult"> + <xs:complexType> + <xs:sequence> + <xs:element name="sessionID" type="xs:string"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:element name="loginResponse" type="lp:loginResponse"/> +</xs:schema> diff --git a/test/wsdl/qualified/np.wsdl b/test/wsdl/qualified/np.wsdl new file mode 100644 index 000000000..e2b7253d0 --- /dev/null +++ b/test/wsdl/qualified/np.wsdl @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www50.brinkster.com/vbfacileinpt/np" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://www50.brinkster.com/vbfacileinpt/np" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <wsdl:types> + <s:schema elementFormDefault="qualified" targetNamespace="http://www50.brinkster.com/vbfacileinpt/np"> + <s:element name="GetPrimeNumbers"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="Max" type="s:string" /> + </s:sequence> + </s:complexType> + </s:element> + <s:element name="GetPrimeNumbersResponse"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="GetPrimeNumbersResult" type="s:string" /> + </s:sequence> + </s:complexType> + </s:element> + </s:schema> + </wsdl:types> + <wsdl:message name="GetPrimeNumbersSoapIn"> + <wsdl:part name="parameters" element="tns:GetPrimeNumbers" /> + </wsdl:message> + <wsdl:message name="GetPrimeNumbersSoapOut"> + <wsdl:part name="parameters" element="tns:GetPrimeNumbersResponse" /> + </wsdl:message> + <wsdl:portType name="pnumSoap"> + <wsdl:operation name="GetPrimeNumbers"> + <wsdl:input message="tns:GetPrimeNumbersSoapIn" /> + <wsdl:output message="tns:GetPrimeNumbersSoapOut" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="pnumSoap" type="tns:pnumSoap"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> + <wsdl:operation name="GetPrimeNumbers"> + <soap:operation soapAction="http://www50.brinkster.com/vbfacileinpt/np/GetPrimeNumbers" style="document" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="pnum"> + <wsdl:port name="pnumSoap" binding="tns:pnumSoap"> + <soap:address location="http://www50.brinkster.com/vbfacileinpt/np.asmx" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions>
\ No newline at end of file diff --git a/test/wsdl/qualified/test_qualified.rb b/test/wsdl/qualified/test_qualified.rb new file mode 100644 index 000000000..d6c1159a8 --- /dev/null +++ b/test/wsdl/qualified/test_qualified.rb @@ -0,0 +1,154 @@ +require 'test/unit' +require 'wsdl/soap/wsdl2ruby' +require 'soap/rpc/standaloneServer' +require 'soap/wsdlDriver' + +if defined?(HTTPAccess2) + +module WSDL + + +class TestQualified < Test::Unit::TestCase + class Server < ::SOAP::RPC::StandaloneServer + Namespace = 'http://www50.brinkster.com/vbfacileinpt/np' + + def on_init + add_document_method( + self, + Namespace + '/GetPrimeNumbers', + 'GetPrimeNumbers', + XSD::QName.new(Namespace, 'GetPrimeNumbers'), + XSD::QName.new(Namespace, 'GetPrimeNumbersResponse') + ) + end + + def GetPrimeNumbers(arg) + nil + end + end + + DIR = File.dirname(File.expand_path(__FILE__)) + Port = 17171 + + def setup + setup_server + setup_clientdef + @client = nil + end + + def teardown + teardown_server + unless $DEBUG + File.unlink(pathname('default.rb')) + File.unlink(pathname('defaultDriver.rb')) + end + @client.reset_stream if @client + end + + def setup_server + @server = Server.new('Test', "urn:lp", '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @server_thread = start_server_thread(@server) + end + + def setup_clientdef + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("np.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['driver'] = nil + gen.opt['force'] = true + gen.run + require pathname('default.rb') + ensure + Dir.chdir(backupdir) + end + end + + def teardown_server + @server.shutdown + @server_thread.kill + @server_thread.join + end + + def start_server_thread(server) + t = Thread.new { + Thread.current.abort_on_exception = true + server.start + } + t + end + + def pathname(filename) + File.join(DIR, filename) + end + + LOGIN_REQUEST_QUALIFIED_NS = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:GetPrimeNumbers xmlns:n1="http://www50.brinkster.com/vbfacileinpt/np"> + <n1:Max>10</n1:Max> + </n1:GetPrimeNumbers> + </env:Body> +</env:Envelope>] + + LOGIN_REQUEST_QUALIFIED = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <GetPrimeNumbers xmlns="http://www50.brinkster.com/vbfacileinpt/np"> + <Max>10</Max> + </GetPrimeNumbers> + </env:Body> +</env:Envelope>] + + def test_wsdl + wsdl = File.join(DIR, 'np.wsdl') + @client = nil + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver + ensure + Dir.chdir(backupdir) + end + @client.endpoint_url = "http://localhost:#{Port}/" + @client.wiredump_dev = str = '' + @client.GetPrimeNumbers(:Max => 10) + assert_equal(LOGIN_REQUEST_QUALIFIED_NS, parse_requestxml(str)) + end + + include ::SOAP + def test_naive + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + require pathname('defaultDriver') + ensure + Dir.chdir(backupdir) + end + @client = PnumSoap.new("http://localhost:#{Port}/") + + @client.wiredump_dev = str = '' + @client.getPrimeNumbers(GetPrimeNumbers.new(10)) + assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) + end + + def parse_requestxml(str) + str.split(/\r?\n\r?\n/)[3] + end +end + + +end + +end diff --git a/test/wsdl/qualified/test_unqualified.rb b/test/wsdl/qualified/test_unqualified.rb new file mode 100644 index 000000000..bcfed73e5 --- /dev/null +++ b/test/wsdl/qualified/test_unqualified.rb @@ -0,0 +1,143 @@ +require 'test/unit' +require 'wsdl/soap/wsdl2ruby' +require 'soap/rpc/standaloneServer' +require 'soap/wsdlDriver' + +if defined?(HTTPAccess2) + +module WSDL + + +class TestUnqualified < Test::Unit::TestCase + class Server < ::SOAP::RPC::StandaloneServer + Namespace = 'urn:lp' + + def on_init + add_document_method( + self, + Namespace + ':login', + 'login', + XSD::QName.new(Namespace, 'login'), + XSD::QName.new(Namespace, 'loginResponse') + ) + end + + def login(arg) + nil + end + end + + DIR = File.dirname(File.expand_path(__FILE__)) + Port = 17171 + + def setup + setup_server + setup_clientdef + @client = nil + end + + def teardown + teardown_server + File.unlink(pathname('lp.rb')) + File.unlink(pathname('lpDriver.rb')) + @client.reset_stream if @client + end + + def setup_server + @server = Server.new('Test', "urn:lp", '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @server_thread = start_server_thread(@server) + end + + def setup_clientdef + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("lp.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['driver'] = nil + gen.opt['force'] = true + gen.run + require pathname('lp') + ensure + Dir.chdir(backupdir) + end + end + + def teardown_server + @server.shutdown + @server_thread.kill + @server_thread.join + end + + def start_server_thread(server) + t = Thread.new { + Thread.current.abort_on_exception = true + server.start + } + t + end + + def pathname(filename) + File.join(DIR, filename) + end + + LOGIN_REQUEST_QUALIFIED = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:login xmlns:n1="urn:lp"> + <username>NaHi</username> + <password>passwd</password> + <timezone>JST</timezone> + </n1:login> + </env:Body> +</env:Envelope>] + + def test_wsdl + wsdl = File.join(DIR, 'lp.wsdl') + @client = nil + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver + ensure + Dir.chdir(backupdir) + end + @client.endpoint_url = "http://localhost:#{Port}/" + @client.wiredump_dev = str = '' + @client.login(:timezone => 'JST', :password => 'passwd', + :username => 'NaHi') + assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) + end + + include ::SOAP + def test_naive + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + require pathname('lpDriver') + ensure + Dir.chdir(backupdir) + end + @client = Lp_porttype.new("http://localhost:#{Port}/") + + @client.wiredump_dev = str = '' + @client.login(Login.new('NaHi', 'passwd', 'JST')) + assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) + end + + def parse_requestxml(str) + str.split(/\r?\n\r?\n/)[3] + end +end + + +end + +end diff --git a/test/wsdl/ref/expectedProduct.rb b/test/wsdl/ref/expectedProduct.rb new file mode 100644 index 000000000..91c6e4c56 --- /dev/null +++ b/test/wsdl/ref/expectedProduct.rb @@ -0,0 +1,90 @@ +require 'xsd/qname' + +# {urn:product}Rating +module Rating + C_0 = "0" + C_1 = "+1" + C_1_2 = "-1" +end + +# {urn:product}Product-Bag +class ProductBag + @@schema_type = "Product-Bag" + @@schema_ns = "urn:product" + @@schema_attribute = {XSD::QName.new("urn:product", "version") => "SOAP::SOAPString", XSD::QName.new("urn:product", "yesno") => "SOAP::SOAPString"} + @@schema_element = [["bag", ["Product[]", XSD::QName.new(nil, "bag")]], ["rating", ["SOAP::SOAPString[]", XSD::QName.new("urn:product", "Rating")]], ["product_Bag", [nil, XSD::QName.new("urn:product", "Product-Bag")]], ["comment_1", [nil, XSD::QName.new(nil, "comment_1")]], ["comment_2", ["Comment[]", XSD::QName.new(nil, "comment-2")]]] + + attr_accessor :bag + attr_accessor :product_Bag + attr_accessor :comment_1 + attr_accessor :comment_2 + + def Rating + @rating + end + + def Rating=(value) + @rating = value + end + + def xmlattr_version + (@__xmlattr ||= {})[XSD::QName.new("urn:product", "version")] + end + + def xmlattr_version=(value) + (@__xmlattr ||= {})[XSD::QName.new("urn:product", "version")] = value + end + + def xmlattr_yesno + (@__xmlattr ||= {})[XSD::QName.new("urn:product", "yesno")] + end + + def xmlattr_yesno=(value) + (@__xmlattr ||= {})[XSD::QName.new("urn:product", "yesno")] = value + end + + def initialize(bag = [], rating = [], product_Bag = nil, comment_1 = [], comment_2 = []) + @bag = bag + @rating = rating + @product_Bag = product_Bag + @comment_1 = comment_1 + @comment_2 = comment_2 + @__xmlattr = {} + end +end + +# {urn:product}Creator +class Creator + @@schema_type = "Creator" + @@schema_ns = "urn:product" + @@schema_element = [] + + def initialize + end +end + +# {urn:product}Product +class Product + @@schema_type = "Product" + @@schema_ns = "urn:product" + @@schema_element = [["name", ["SOAP::SOAPString", XSD::QName.new(nil, "name")]], ["rating", ["SOAP::SOAPString", XSD::QName.new("urn:product", "Rating")]]] + + attr_accessor :name + + def Rating + @rating + end + + def Rating=(value) + @rating = value + end + + def initialize(name = nil, rating = nil) + @name = name + @rating = rating + end +end + +# {urn:product}Comment +class Comment < String +end diff --git a/test/wsdl/ref/product.wsdl b/test/wsdl/ref/product.wsdl new file mode 100644 index 000000000..993fe217a --- /dev/null +++ b/test/wsdl/ref/product.wsdl @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<definitions name="product" + targetNamespace="urn:product" + xmlns:tns="urn:product" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns="http://schemas.xmlsoap.org/wsdl/"> + <types> + <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" + targetNamespace="urn:product"> + <simpleType name="non-empty-string"> + <restriction base="xsd:string"> + <minLength value="1"/> + </restriction> + </simpleType> + + <complexType name="Product"> + <all> + <element name="name" type="xsd:string"/> + <element ref="tns:Rating"/> + </all> + </complexType> + + <complexType name="Comment"> + <simpleContent> + <extension base="xsd:string"> + <attribute name="msgid" type="xsd:string" use="required"/> + </extension> + </simpleContent> + </complexType> + + <attribute name="version" type="tns:non-empty-string"/> + + <attribute default="Y" name="yesno"> + <simpleType> + <restriction base="xsd:string"> + <enumeration value="Y"/> + <enumeration value="N"/> + </restriction> + </simpleType> + </attribute> + + <element name="Rating"> + <simpleType> + <restriction base="xsd:string"> + <enumeration value="+1"/> + <enumeration value="0"/> + <enumeration value="-1"/> + </restriction> + </simpleType> + </element> + + <element name="Product-Bag"> + <complexType> + <sequence> + <element name="bag" type="tns:Product" minOccurs="0" maxOccurs="unbounded"/> + <element ref="tns:Rating" minOccurs="0" maxOccurs="unbounded"/> + <element ref="tns:Product-Bag"/> + <element name="comment_1" minOccurs="0" maxOccurs="unbounded"> + <complexType> + <simpleContent> + <extension base="xsd:string"> + <attribute name="msgid" type="xsd:string" use="required"/> + </extension> + </simpleContent> + </complexType> + </element> + <element name="comment-2" type="tns:Comment" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + <attribute ref="tns:version"/> + <attribute ref="tns:yesno"/> + </complexType> + </element> + + <element name="Creator" minOccurs="0" maxOccurs="unbounded"> + <complexType> + <simpleContent> + <extension base="xsd:string"> + <attribute name="Role" type="xs:string" use="required"/> + </extension> + </simpleContent> + </complexType> + </element> + </xsd:schema> + </types> +</definitions> diff --git a/test/wsdl/ref/test_ref.rb b/test/wsdl/ref/test_ref.rb new file mode 100644 index 000000000..165a8643e --- /dev/null +++ b/test/wsdl/ref/test_ref.rb @@ -0,0 +1,42 @@ +require 'test/unit' +require 'soap/rpc/standaloneServer' +require 'soap/wsdlDriver' +require 'wsdl/soap/wsdl2ruby' + + +module WSDL +module Ref + + +class TestRef < Test::Unit::TestCase + DIR = File.dirname(File.expand_path(__FILE__)) + Port = 17171 + + def test_classdef + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("product.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['force'] = true + gen.run + compare("expectedProduct.rb", "product.rb") + File.unlink(pathname('product.rb')) + end + + def compare(expected, actual) + assert_equal(loadfile(expected), loadfile(actual), actual) + end + + def loadfile(file) + File.open(pathname(file)) { |f| f.read } + end + + def pathname(filename) + File.join(DIR, filename) + end +end + + +end +end diff --git a/test/wsdl/rpc/test-rpc-lit.wsdl b/test/wsdl/rpc/test-rpc-lit.wsdl new file mode 100644 index 000000000..72de747e3 --- /dev/null +++ b/test/wsdl/rpc/test-rpc-lit.wsdl @@ -0,0 +1,364 @@ +<?xml version="1.0"?> + +<definitions name="RPC-Literal-TestDefinitions" + targetNamespace="http://whitemesa.net/wsdl/rpc-lit-test" + xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:soap11="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="http://whitemesa.net/wsdl/rpc-lit-test" + xmlns:types="http://soapbuilders.org/rpc-lit-test/types" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soapbuilders.org/rpc-lit-test/types"> + + <element name="stringItem" type="xsd:string" /> + <complexType name="ArrayOfstring"> + <sequence> + <element ref="types:stringItem" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <complexType name="ArrayOfstringInline"> + <sequence> + <element name="stringItem" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <complexType name="ArrayOfint"> + <sequence> + <element name="integer" type="xsd:int" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="structItem" type="types:SOAPStruct" /> + <complexType name="SOAPStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + </all> + </complexType> + + <complexType name="ArrayOfSOAPStruct"> + <sequence> + <element ref="types:structItem" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <complexType name="SOAPStructStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + <element ref="types:structItem" /> + </all> + </complexType> + + <complexType name="SOAPArrayStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + <element name="varArray" type="types:ArrayOfstring"/> + </all> + </complexType> + + </schema> + + </types> + + <!-- echoStruct rpc operation --> + <message name="echoStructRequest"> + <part name="inputStruct" type="types:SOAPStruct"/> + </message> + <message name="echoStructResponse"> + <part name="return" type="types:SOAPStruct"/> + </message> + + <!-- echoStructArray rpc operation --> + <message name="echoStructArrayRequest"> + <part name="inputStructArray" type="types:ArrayOfSOAPStruct"/> + </message> + <message name="echoStructArrayResponse"> + <part name="return" type="types:ArrayOfSOAPStruct"/> + </message> + + <!-- echoStructAsSimpleTypes rpc operation --> + <message name="echoStructAsSimpleTypesRequest"> + <part name="inputStruct" type="types:SOAPStruct"/> + </message> + <message name="echoStructAsSimpleTypesResponse"> + <part name="outputString" type="xsd:string"/> + <part name="outputInteger" type="xsd:int"/> + <part name="outputFloat" type="xsd:float"/> + </message> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <message name="echoSimpleTypesAsStructRequest"> + <part name="inputString" type="xsd:string"/> + <part name="inputInteger" type="xsd:int"/> + <part name="inputFloat" type="xsd:float"/> + </message> + <message name="echoSimpleTypesAsStructResponse"> + <part name="return" type="types:SOAPStruct"/> + </message> + + <!-- echoNestedStruct rpc operation --> + <message name="echoNestedStructRequest"> + <part name="inputStruct" type="types:SOAPStructStruct"/> + </message> + <message name="echoNestedStructResponse"> + <part name="return" type="types:SOAPStructStruct"/> + </message> + + <!-- echoNestedArray rpc operation --> + <message name="echoNestedArrayRequest"> + <part name="inputStruct" type="types:SOAPArrayStruct"/> + </message> + <message name="echoNestedArrayResponse"> + <part name="return" type="types:SOAPArrayStruct"/> + </message> + + <!-- echoStringArray rpc operation --> + <message name="echoStringArrayRequest"> + <part name="inputStringArray" type="types:ArrayOfstring"/> + </message> + <message name="echoStringArrayResponse"> + <part name="return" type="types:ArrayOfstring"/> + </message> + + <message name="echoStringArrayInlineRequest"> + <part name="inputStringArray" type="types:ArrayOfstringInline"/> + </message> + <message name="echoStringArrayInlineResponse"> + <part name="return" type="types:ArrayOfstringInline"/> + </message> + + <!-- echoIntegerArray rpc operation --> + <message name="echoIntegerArrayRequest"> + <part name="inputIntegerArray" type="types:ArrayOfint"/> + </message> + <message name="echoIntegerArrayResponse"> + <part name="return" type="types:ArrayOfint"/> + </message> + + <!-- echoBoolean rpc operation --> + <message name="echoBooleanRequest"> + <part name="inputBoolean" type="xsd:boolean"/> + </message> + <message name="echoBooleanResponse"> + <part name="return" type="xsd:boolean"/> + </message> + + <!-- echoString rpc operation --> + <message name="echoStringRequest"> + <part name="inputString" type="xsd:string"/> + </message> + <message name="echoStringResponse"> + <part name="return" type="xsd:string"/> + </message> + + + <portType name="SoapTestPortTypeRpc"> + + <!-- echoStruct rpc operation --> + <operation name="echoStruct" parameterOrder="inputStruct"> + <input message="tns:echoStructRequest"/> + <output message="tns:echoStructResponse"/> + </operation> + + <!-- echoStructArray rpc operation --> + <operation name="echoStructArray" parameterOrder="inputStructArray"> + <input message="tns:echoStructArrayRequest"/> + <output message="tns:echoStructArrayResponse"/> + </operation> + + <!-- echoStructAsSimpleTypes rpc operation --> + <operation name="echoStructAsSimpleTypes" parameterOrder="inputStruct outputString outputInteger outputFloat"> + <input message="tns:echoStructAsSimpleTypesRequest"/> + <output message="tns:echoStructAsSimpleTypesResponse"/> + </operation> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <operation name="echoSimpleTypesAsStruct" parameterOrder="inputString inputInteger inputFloat"> + <input message="tns:echoSimpleTypesAsStructRequest"/> + <output message="tns:echoSimpleTypesAsStructResponse"/> + </operation> + + <!-- echoNestedStruct rpc operation --> + <operation name="echoNestedStruct" parameterOrder="inputStruct"> + <input message="tns:echoNestedStructRequest"/> + <output message="tns:echoNestedStructResponse"/> + </operation> + + <!-- echoNestedArray rpc operation --> + <operation name="echoNestedArray" parameterOrder="inputStruct"> + <input message="tns:echoNestedArrayRequest"/> + <output message="tns:echoNestedArrayResponse"/> + </operation> + + <!-- echoStringArray rpc operation --> + <operation name="echoStringArray" parameterOrder="inputStringArray"> + <input message="tns:echoStringArrayRequest"/> + <output message="tns:echoStringArrayResponse"/> + </operation> + + <operation name="echoStringArrayInline" parameterOrder="inputStringArray"> + <input message="tns:echoStringArrayInlineRequest"/> + <output message="tns:echoStringArrayInlineResponse"/> + </operation> + + <!-- echoIntegerArray rpc operation --> + <operation name="echoIntegerArray" parameterOrder="inputIntegerArray"> + <input message="tns:echoIntegerArrayRequest"/> + <output message="tns:echoIntegerArrayResponse"/> + </operation> + + <!-- echoBoolean rpc operation --> + <operation name="echoBoolean" parameterOrder="inputBoolean"> + <input message="tns:echoBooleanRequest"/> + <output message="tns:echoBooleanResponse"/> + </operation> + + <!-- echoString rpc operation --> + <operation name="echoString" parameterOrder="inputString"> + <input message="tns:echoStringRequest"/> + <output message="tns:echoStringResponse"/> + </operation> + + </portType> + + <binding name="Soap11TestRpcLitBinding" type="tns:SoapTestPortTypeRpc"> + <soap11:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + + <!-- echoStruct rpc operation --> + <operation name="echoStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructArray rpc operation --> + <operation name="echoStructArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructAsSimpleTypes rpc operation --> + <operation name="echoStructAsSimpleTypes"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <operation name="echoSimpleTypesAsStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedStruct rpc operation --> + <operation name="echoNestedStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedArray rpc operation --> + <operation name="echoNestedArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStringArray rpc operation --> + <operation name="echoStringArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <operation name="echoStringArrayInline"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoIntegerArray rpc operation --> + <operation name="echoIntegerArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoBoolean rpc operation --> + <operation name="echoBoolean"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoString rpc operation --> + <operation name="echoString"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + </binding> + + <service name="WhiteMesaSoapRpcLitTestSvc"> + + <port name="Soap11TestRpcLitPort" binding="tns:Soap11TestRpcLitBinding"> + <soap11:address location="http://www.whitemesa.net/test-rpc-lit"/> + </port> + + </service> + +</definitions> diff --git a/test/wsdl/rpc/test-rpc-lit12.wsdl b/test/wsdl/rpc/test-rpc-lit12.wsdl new file mode 100644 index 000000000..901cde6f9 --- /dev/null +++ b/test/wsdl/rpc/test-rpc-lit12.wsdl @@ -0,0 +1,455 @@ +<?xml version="1.0"?> + +<definitions name="RPC-Literal-TestDefinitions" + targetNamespace="http://whitemesa.net/wsdl/rpc-lit-test" + xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" + xmlns:soap11="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="http://whitemesa.net/wsdl/rpc-lit-test" + xmlns:types="http://soapbuilders.org/rpc-lit-test/types" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soapbuilders.org/rpc-lit-test/types"> + + <element name="stringItem" type="xsd:string" /> + <complexType name="ArrayOfstring"> + <sequence> + <element ref="types:stringItem" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <complexType name="ArrayOfint"> + <sequence> + <element name="integer" type="xsd:int" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="structItem" type="types:SOAPStruct" /> + <complexType name="SOAPStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + </all> + </complexType> + + <complexType name="ArrayOfSOAPStruct"> + <sequence> + <element ref="types:structItem" minOccurs="0" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <complexType name="SOAPStructStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + <element ref="types:structItem" /> + </all> + </complexType> + + <complexType name="SOAPArrayStruct"> + <all> + <element name="varString" type="xsd:string"/> + <element name="varInt" type="xsd:int"/> + <element name="varFloat" type="xsd:float"/> + <element name="varArray" type="types:ArrayOfstring"/> + </all> + </complexType> + + </schema> + + </types> + + <!-- echoStruct rpc operation --> + <message name="echoStructRequest"> + <part name="inputStruct" type="types:SOAPStruct"/> + </message> + <message name="echoStructResponse"> + <part name="return" type="types:SOAPStruct"/> + </message> + + <!-- echoStructArray rpc operation --> + <message name="echoStructArrayRequest"> + <part name="inputStructArray" type="types:ArrayOfSOAPStruct"/> + </message> + <message name="echoStructArrayResponse"> + <part name="return" type="types:ArrayOfSOAPStruct"/> + </message> + + <!-- echoStructAsSimpleTypes rpc operation --> + <message name="echoStructAsSimpleTypesRequest"> + <part name="inputStruct" type="types:SOAPStruct"/> + </message> + <message name="echoStructAsSimpleTypesResponse"> + <part name="outputString" type="xsd:string"/> + <part name="outputInteger" type="xsd:int"/> + <part name="outputFloat" type="xsd:float"/> + </message> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <message name="echoSimpleTypesAsStructRequest"> + <part name="inputString" type="xsd:string"/> + <part name="inputInteger" type="xsd:int"/> + <part name="inputFloat" type="xsd:float"/> + </message> + <message name="echoSimpleTypesAsStructResponse"> + <part name="return" type="types:SOAPStruct"/> + </message> + + <!-- echoNestedStruct rpc operation --> + <message name="echoNestedStructRequest"> + <part name="inputStruct" type="types:SOAPStructStruct"/> + </message> + <message name="echoNestedStructResponse"> + <part name="return" type="types:SOAPStructStruct"/> + </message> + + <!-- echoNestedArray rpc operation --> + <message name="echoNestedArrayRequest"> + <part name="inputStruct" type="types:SOAPArrayStruct"/> + </message> + <message name="echoNestedArrayResponse"> + <part name="return" type="types:SOAPArrayStruct"/> + </message> + + <!-- echoStringArray rpc operation --> + <message name="echoStringArrayRequest"> + <part name="inputStringArray" type="types:ArrayOfstring"/> + </message> + <message name="echoStringArrayResponse"> + <part name="return" type="types:ArrayOfstring"/> + </message> + + <!-- echoIntegerArray rpc operation --> + <message name="echoIntegerArrayRequest"> + <part name="inputIntegerArray" type="types:ArrayOfint"/> + </message> + <message name="echoIntegerArrayResponse"> + <part name="return" type="types:ArrayOfint"/> + </message> + + <!-- echoBoolean rpc operation --> + <message name="echoBooleanRequest"> + <part name="inputBoolean" type="xsd:boolean"/> + </message> + <message name="echoBooleanResponse"> + <part name="return" type="xsd:boolean"/> + </message> + + <!-- echoString rpc operation --> + <message name="echoStringRequest"> + <part name="inputString" type="xsd:string"/> + </message> + <message name="echoStringResponse"> + <part name="return" type="xsd:string"/> + </message> + + + <portType name="SoapTestPortTypeRpc"> + + <!-- echoStruct rpc operation --> + <operation name="echoStruct" parameterOrder="inputStruct"> + <input message="tns:echoStructRequest"/> + <output message="tns:echoStructResponse"/> + </operation> + + <!-- echoStructArray rpc operation --> + <operation name="echoStructArray" parameterOrder="inputStructArray"> + <input message="tns:echoStructArrayRequest"/> + <output message="tns:echoStructArrayResponse"/> + </operation> + + <!-- echoStructAsSimpleTypes rpc operation --> + <operation name="echoStructAsSimpleTypes" parameterOrder="inputStruct outputString outputInteger outputFloat"> + <input message="tns:echoStructAsSimpleTypesRequest"/> + <output message="tns:echoStructAsSimpleTypesResponse"/> + </operation> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <operation name="echoSimpleTypesAsStruct" parameterOrder="inputString inputInteger inputFloat"> + <input message="tns:echoSimpleTypesAsStructRequest"/> + <output message="tns:echoSimpleTypesAsStructResponse"/> + </operation> + + <!-- echoNestedStruct rpc operation --> + <operation name="echoNestedStruct" parameterOrder="inputStruct"> + <input message="tns:echoNestedStructRequest"/> + <output message="tns:echoNestedStructResponse"/> + </operation> + + <!-- echoNestedArray rpc operation --> + <operation name="echoNestedArray" parameterOrder="inputStruct"> + <input message="tns:echoNestedArrayRequest"/> + <output message="tns:echoNestedArrayResponse"/> + </operation> + + <!-- echoStringArray rpc operation --> + <operation name="echoStringArray" parameterOrder="inputStringArray"> + <input message="tns:echoStringArrayRequest"/> + <output message="tns:echoStringArrayResponse"/> + </operation> + + <!-- echoIntegerArray rpc operation --> + <operation name="echoIntegerArray" parameterOrder="inputIntegerArray"> + <input message="tns:echoIntegerArrayRequest"/> + <output message="tns:echoIntegerArrayResponse"/> + </operation> + + <!-- echoBoolean rpc operation --> + <operation name="echoBoolean" parameterOrder="inputBoolean"> + <input message="tns:echoBooleanRequest"/> + <output message="tns:echoBooleanResponse"/> + </operation> + + <!-- echoString rpc operation --> + <operation name="echoString" parameterOrder="inputString"> + <input message="tns:echoStringRequest"/> + <output message="tns:echoStringResponse"/> + </operation> + + </portType> + + <binding name="Soap11TestRpcLitBinding" type="tns:SoapTestPortTypeRpc"> + <soap11:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + + <!-- echoStruct rpc operation --> + <operation name="echoStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructArray rpc operation --> + <operation name="echoStructArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructAsSimpleTypes rpc operation --> + <operation name="echoStructAsSimpleTypes"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <operation name="echoSimpleTypesAsStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedStruct rpc operation --> + <operation name="echoNestedStruct"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedArray rpc operation --> + <operation name="echoNestedArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStringArray rpc operation --> + <operation name="echoStringArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoIntegerArray rpc operation --> + <operation name="echoIntegerArray"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoBoolean rpc operation --> + <operation name="echoBoolean"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoString rpc operation --> + <operation name="echoString"> + <soap11:operation soapAction="http://soapinterop.org/"/> + <input> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap11:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + </binding> + + <binding name="Soap12TestRpcLitBinding" type="tns:SoapTestPortTypeRpc"> + <soap12:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + + <!-- echoStruct rpc operation --> + <operation name="echoStruct"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructArray rpc operation --> + <operation name="echoStructArray"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStructAsSimpleTypes rpc operation --> + <operation name="echoStructAsSimpleTypes"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoSimpleTypesAsStruct rpc operation --> + <operation name="echoSimpleTypesAsStruct"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedStruct rpc operation --> + <operation name="echoNestedStruct"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoNestedArray rpc operation --> + <operation name="echoNestedArray"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoStringArray rpc operation --> + <operation name="echoStringArray"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoIntegerArray rpc operation --> + <operation name="echoIntegerArray"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoBoolean rpc operation --> + <operation name="echoBoolean"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + <!-- echoString rpc operation --> + <operation name="echoString"> + <soap12:operation/> + <input> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </input> + <output> + <soap12:body use="literal" namespace="http://soapbuilders.org/rpc-lit-test" /> + </output> + </operation> + + </binding> + + <service name="WhiteMesaSoapRpcLitTestSvc"> + + <port name="Soap12TestRpcLitPort" binding="tns:Soap12TestRpcLitBinding"> + <soap12:address location="http://www.whitemesa.net/soap12/test-rpc-lit"/> + </port> + <port name="Soap11TestRpcLitPort" binding="tns:Soap11TestRpcLitBinding"> + <soap11:address location="http://www.whitemesa.net/test-rpc-lit"/> + </port> + + </service> + +</definitions> diff --git a/test/wsdl/rpc/test_rpc_lit.rb b/test/wsdl/rpc/test_rpc_lit.rb new file mode 100644 index 000000000..080dbb82c --- /dev/null +++ b/test/wsdl/rpc/test_rpc_lit.rb @@ -0,0 +1,399 @@ +require 'test/unit' +require 'wsdl/soap/wsdl2ruby' +require 'soap/rpc/standaloneServer' +require 'soap/wsdlDriver' + +if defined?(HTTPAccess2) and defined?(OpenSSL) + +module WSDL; module RPC + + +class TestRPCLIT < Test::Unit::TestCase + class Server < ::SOAP::RPC::StandaloneServer + Namespace = "http://soapbuilders.org/rpc-lit-test" + + def on_init + self.generate_explicit_type = false + add_rpc_operation(self, + XSD::QName.new(Namespace, 'echoStringArray'), + nil, + 'echoStringArray', [ + ['in', 'inputStringArray', nil], + ['retval', 'return', nil] + ], + { + :request_style => :rpc, + :request_use => :literal, + :response_style => :rpc, + :response_use => :literal + } + ) + add_rpc_operation(self, + XSD::QName.new(Namespace, 'echoStringArrayInline'), + nil, + 'echoStringArrayInline', [ + ['in', 'inputStringArray', nil], + ['retval', 'return', nil] + ], + { + :request_style => :rpc, + :request_use => :literal, + :response_style => :rpc, + :response_use => :literal + } + ) + add_rpc_operation(self, + XSD::QName.new(Namespace, 'echoNestedStruct'), + nil, + 'echoNestedStruct', [ + ['in', 'inputNestedStruct', nil], + ['retval', 'return', nil] + ], + { + :request_style => :rpc, + :request_use => :literal, + :response_style => :rpc, + :response_use => :literal + } + ) + add_rpc_operation(self, + XSD::QName.new(Namespace, 'echoStructArray'), + nil, + 'echoStructArray', [ + ['in', 'inputStructArray', nil], + ['retval', 'return', nil] + ], + { + :request_style => :rpc, + :request_use => :literal, + :response_style => :rpc, + :response_use => :literal + } + ) + end + + def echoStringArray(strings) + # strings.stringItem => Array + ArrayOfstring[*strings.stringItem] + end + + def echoStringArrayInline(strings) + ArrayOfstringInline[*strings.stringItem] + end + + def echoNestedStruct(struct) + struct + end + + def echoStructArray(ary) + ary + end + end + + DIR = File.dirname(File.expand_path(__FILE__)) + + Port = 17171 + + def setup + setup_server + setup_classdef + @client = nil + end + + def teardown + teardown_server + unless $DEBUG + File.unlink(pathname('RPC-Literal-TestDefinitions.rb')) + File.unlink(pathname('RPC-Literal-TestDefinitionsDriver.rb')) + end + @client.reset_stream if @client + end + + def setup_server + @server = Server.new('Test', Server::Namespace, '0.0.0.0', Port) + @server.level = Logger::Severity::ERROR + @server_thread = start_server_thread(@server) + end + + def setup_classdef + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("test-rpc-lit.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['driver'] = nil + gen.opt['force'] = true + gen.run + backupdir = Dir.pwd + begin + Dir.chdir(DIR) + require pathname('RPC-Literal-TestDefinitions.rb') + require pathname('RPC-Literal-TestDefinitionsDriver.rb') + ensure + Dir.chdir(backupdir) + end + end + + def teardown_server + @server.shutdown + @server_thread.kill + @server_thread.join + end + + def start_server_thread(server) + t = Thread.new { + Thread.current.abort_on_exception = true + server.start + } + t + end + + def pathname(filename) + File.join(DIR, filename) + end + + def test_wsdl_echoStringArray + wsdl = pathname('test-rpc-lit.wsdl') + @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver + @client.endpoint_url = "http://localhost:#{Port}/" + @client.wiredump_dev = STDOUT if $DEBUG + # response contains only 1 part. + result = @client.echoStringArray(ArrayOfstring["a", "b", "c"])[0] + assert_equal(["a", "b", "c"], result.stringItem) + end + + ECHO_STRING_ARRAY_REQUEST = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStringArray xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <inputStringArray xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <n2:stringItem>a</n2:stringItem> + <n2:stringItem>b</n2:stringItem> + <n2:stringItem>c</n2:stringItem> + </inputStringArray> + </n1:echoStringArray> + </env:Body> +</env:Envelope>] + + ECHO_STRING_ARRAY_RESPONSE = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStringArrayResponse xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <return xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <n2:stringItem>a</n2:stringItem> + <n2:stringItem>b</n2:stringItem> + <n2:stringItem>c</n2:stringItem> + </return> + </n1:echoStringArrayResponse> + </env:Body> +</env:Envelope>] + + def test_stub_echoStringArray + drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") + drv.wiredump_dev = str = '' + # response contains only 1 part. + result = drv.echoStringArray(ArrayOfstring["a", "b", "c"])[0] + assert_equal(["a", "b", "c"], result.stringItem) + assert_equal(ECHO_STRING_ARRAY_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_STRING_ARRAY_RESPONSE, parse_responsexml(str)) + end + + ECHO_STRING_ARRAY_INLINE_REQUEST = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStringArrayInline xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <inputStringArray> + <stringItem>a</stringItem> + <stringItem>b</stringItem> + <stringItem>c</stringItem> + </inputStringArray> + </n1:echoStringArrayInline> + </env:Body> +</env:Envelope>] + + ECHO_STRING_ARRAY_INLINE_RESPONSE = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStringArrayInlineResponse xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <return> + <stringItem>a</stringItem> + <stringItem>b</stringItem> + <stringItem>c</stringItem> + </return> + </n1:echoStringArrayInlineResponse> + </env:Body> +</env:Envelope>] + + def test_stub_echoStringArrayInline + drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") + drv.wiredump_dev = str = '' + # response contains only 1 part. + result = drv.echoStringArrayInline(ArrayOfstringInline["a", "b", "c"])[0] + assert_equal(["a", "b", "c"], result.stringItem) + assert_equal(ECHO_STRING_ARRAY_INLINE_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_STRING_ARRAY_INLINE_RESPONSE, parse_responsexml(str)) + end + + ECHO_NESTED_STRUCT_REQUEST = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoNestedStruct xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <inputStruct xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <varString>str</varString> + <varInt>1</varInt> + <varFloat>+1</varFloat> + <n2:structItem> + <varString>str</varString> + <varInt>1</varInt> + <varFloat>+1</varFloat> + </n2:structItem> + </inputStruct> + </n1:echoNestedStruct> + </env:Body> +</env:Envelope>] + + ECHO_NESTED_STRUCT_RESPONSE = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoNestedStructResponse xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <return xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <varString>str</varString> + <varInt>1</varInt> + <varFloat>+1</varFloat> + <n2:structItem> + <varString>str</varString> + <varInt>1</varInt> + <varFloat>+1</varFloat> + </n2:structItem> + </return> + </n1:echoNestedStructResponse> + </env:Body> +</env:Envelope>] + + def test_wsdl_echoNestedStruct + wsdl = pathname('test-rpc-lit.wsdl') + @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver + @client.endpoint_url = "http://localhost:#{Port}/" + @client.wiredump_dev = str = '' + # response contains only 1 part. + result = @client.echoNestedStruct(SOAPStructStruct.new("str", 1, 1.0, SOAPStruct.new("str", 1, 1.0)))[0] + assert_equal('str', result.varString) + assert_equal('1', result.varInt) + assert_equal('+1', result.varFloat) + assert_equal('str', result.structItem.varString) + assert_equal('1', result.structItem.varInt) + assert_equal('+1', result.structItem.varFloat) + assert_equal(ECHO_NESTED_STRUCT_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_NESTED_STRUCT_RESPONSE, parse_responsexml(str)) + end + + def test_stub_echoNestedStruct + drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") + drv.wiredump_dev = str = '' + # response contains only 1 part. + result = drv.echoNestedStruct(SOAPStructStruct.new("str", 1, 1.0, SOAPStruct.new("str", 1, 1.0)))[0] + assert_equal('str', result.varString) + assert_equal('1', result.varInt) + assert_equal('+1', result.varFloat) + assert_equal('str', result.structItem.varString) + assert_equal('1', result.structItem.varInt) + assert_equal('+1', result.structItem.varFloat) + assert_equal(ECHO_NESTED_STRUCT_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_NESTED_STRUCT_RESPONSE, parse_responsexml(str)) + end + + ECHO_STRUCT_ARRAY_REQUEST = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStructArray xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <inputStructArray xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <n2:structItem> + <varString>str</varString> + <varInt>2</varInt> + <varFloat>+2.1</varFloat> + </n2:structItem> + <n2:structItem> + <varString>str</varString> + <varInt>2</varInt> + <varFloat>+2.1</varFloat> + </n2:structItem> + </inputStructArray> + </n1:echoStructArray> + </env:Body> +</env:Envelope>] + + ECHO_STRUCT_ARRAY_RESPONSE = +%q[<?xml version="1.0" encoding="utf-8" ?> +<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <env:Body> + <n1:echoStructArrayResponse xmlns:n1="http://soapbuilders.org/rpc-lit-test"> + <return xmlns:n2="http://soapbuilders.org/rpc-lit-test/types"> + <n2:structItem> + <varString>str</varString> + <varInt>2</varInt> + <varFloat>+2.1</varFloat> + </n2:structItem> + <n2:structItem> + <varString>str</varString> + <varInt>2</varInt> + <varFloat>+2.1</varFloat> + </n2:structItem> + </return> + </n1:echoStructArrayResponse> + </env:Body> +</env:Envelope>] + + def test_wsdl_echoStructArray + wsdl = pathname('test-rpc-lit.wsdl') + @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver + @client.endpoint_url = "http://localhost:#{Port}/" + @client.wiredump_dev = str = '' + # response contains only 1 part. + e = SOAPStruct.new("str", 2, 2.1) + result = @client.echoStructArray(ArrayOfSOAPStruct[e, e]) + assert_equal(ECHO_STRUCT_ARRAY_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_STRUCT_ARRAY_RESPONSE, parse_responsexml(str)) + end + + def test_stub_echoStructArray + drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") + drv.wiredump_dev = str = '' + # response contains only 1 part. + e = SOAPStruct.new("str", 2, 2.1) + result = drv.echoStructArray(ArrayOfSOAPStruct[e, e]) + assert_equal(ECHO_STRUCT_ARRAY_REQUEST, parse_requestxml(str)) + assert_equal(ECHO_STRUCT_ARRAY_RESPONSE, parse_responsexml(str)) + end + + def parse_requestxml(str) + str.split(/\r?\n\r?\n/)[3] + end + + def parse_responsexml(str) + str.split(/\r?\n\r?\n/)[6] + end +end + + +end; end + +end diff --git a/test/wsdl/simpletype/rpc/expectedClient.rb b/test/wsdl/simpletype/rpc/expectedClient.rb new file mode 100644 index 000000000..55eb58c3d --- /dev/null +++ b/test/wsdl/simpletype/rpc/expectedClient.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'echo_versionDriver.rb' + +endpoint_url = ARGV.shift +obj = Echo_version_port_type.new(endpoint_url) + +# run ruby with -d to see SOAP wiredumps. +obj.wiredump_dev = STDERR if $DEBUG + +# SYNOPSIS +# echo_version(version) +# +# ARGS +# version Version - {urn:example.com:simpletype-rpc-type}version +# +# RETURNS +# version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct +# +version = nil +puts obj.echo_version(version) + +# SYNOPSIS +# echo_version_r(version_struct) +# +# ARGS +# version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct +# +# RETURNS +# version Version - {urn:example.com:simpletype-rpc-type}version +# +version_struct = nil +puts obj.echo_version_r(version_struct) + + diff --git a/test/wsdl/simpletype/rpc/expectedDriver.rb b/test/wsdl/simpletype/rpc/expectedDriver.rb new file mode 100644 index 000000000..81c72d1ac --- /dev/null +++ b/test/wsdl/simpletype/rpc/expectedDriver.rb @@ -0,0 +1,62 @@ +require 'echo_version.rb' + +require 'soap/rpc/driver' + +class Echo_version_port_type < ::SOAP::RPC::Driver + DefaultEndpointUrl = "http://localhost:10080" + MappingRegistry = ::SOAP::Mapping::Registry.new + + MappingRegistry.set( + Version_struct, + ::SOAP::SOAPStruct, + ::SOAP::Mapping::Registry::TypedStructFactory, + { :type => XSD::QName.new("urn:example.com:simpletype-rpc-type", "version_struct") } + ) + + Methods = [ + [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version"), + "urn:example.com:simpletype-rpc", + "echo_version", + [ ["in", "version", ["::SOAP::SOAPString"]], + ["retval", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ], + [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version_r"), + "urn:example.com:simpletype-rpc", + "echo_version_r", + [ ["in", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]], + ["retval", "version", ["::SOAP::SOAPString"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ] + ] + + def initialize(endpoint_url = nil) + endpoint_url ||= DefaultEndpointUrl + super(endpoint_url, nil) + self.mapping_registry = MappingRegistry + init_methods + end + +private + + def init_methods + Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + add_document_operation(*definitions) + else + add_rpc_operation(*definitions) + qname = definitions[0] + name = definitions[2] + if qname.name != name and qname.name.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| + __send__(name, *arg) + end + end + end + end + end +end + diff --git a/test/wsdl/simpletype/rpc/expectedEchoVersion.rb b/test/wsdl/simpletype/rpc/expectedEchoVersion.rb new file mode 100644 index 000000000..806ece162 --- /dev/null +++ b/test/wsdl/simpletype/rpc/expectedEchoVersion.rb @@ -0,0 +1,23 @@ +require 'xsd/qname' + +# {urn:example.com:simpletype-rpc-type}version_struct +class Version_struct + @@schema_type = "version_struct" + @@schema_ns = "urn:example.com:simpletype-rpc-type" + @@schema_element = [["version", ["SOAP::SOAPString", XSD::QName.new(nil, "version")]], ["msg", ["SOAP::SOAPString", XSD::QName.new(nil, "msg")]]] + + attr_accessor :version + attr_accessor :msg + + def initialize(version = nil, msg = nil) + @version = version + @msg = msg + end +end + +# {urn:example.com:simpletype-rpc-type}version +module Version + C_16 = "1.6" + C_18 = "1.8" + C_19 = "1.9" +end diff --git a/test/wsdl/simpletype/rpc/expectedServant.rb b/test/wsdl/simpletype/rpc/expectedServant.rb new file mode 100644 index 000000000..81cf50218 --- /dev/null +++ b/test/wsdl/simpletype/rpc/expectedServant.rb @@ -0,0 +1,32 @@ +require 'echo_version.rb' + +class Echo_version_port_type + # SYNOPSIS + # echo_version(version) + # + # ARGS + # version Version - {urn:example.com:simpletype-rpc-type}version + # + # RETURNS + # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct + # + def echo_version(version) + p [version] + raise NotImplementedError.new + end + + # SYNOPSIS + # echo_version_r(version_struct) + # + # ARGS + # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct + # + # RETURNS + # version Version - {urn:example.com:simpletype-rpc-type}version + # + def echo_version_r(version_struct) + p [version_struct] + raise NotImplementedError.new + end +end + diff --git a/test/wsdl/simpletype/rpc/expectedService.rb b/test/wsdl/simpletype/rpc/expectedService.rb new file mode 100644 index 000000000..be6f99656 --- /dev/null +++ b/test/wsdl/simpletype/rpc/expectedService.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby +require 'echo_versionServant.rb' + +require 'soap/rpc/standaloneServer' +require 'soap/mapping/registry' + +class Echo_version_port_type + MappingRegistry = ::SOAP::Mapping::Registry.new + + MappingRegistry.set( + Version_struct, + ::SOAP::SOAPStruct, + ::SOAP::Mapping::Registry::TypedStructFactory, + { :type => XSD::QName.new("urn:example.com:simpletype-rpc-type", "version_struct") } + ) + + Methods = [ + [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version"), + "urn:example.com:simpletype-rpc", + "echo_version", + [ ["in", "version", ["::SOAP::SOAPString"]], + ["retval", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ], + [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version_r"), + "urn:example.com:simpletype-rpc", + "echo_version_r", + [ ["in", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]], + ["retval", "version", ["::SOAP::SOAPString"]] ], + { :request_style => :rpc, :request_use => :encoded, + :response_style => :rpc, :response_use => :encoded } + ] + ] +end + +class Echo_version_port_typeApp < ::SOAP::RPC::StandaloneServer + def initialize(*arg) + super(*arg) + servant = Echo_version_port_type.new + Echo_version_port_type::Methods.each do |definitions| + opt = definitions.last + if opt[:request_style] == :document + @router.add_document_operation(servant, *definitions) + else + @router.add_rpc_operation(servant, *definitions) + end + end + self.mapping_registry = Echo_version_port_type::MappingRegistry + end +end + +if $0 == __FILE__ + # Change listen port. + server = Echo_version_port_typeApp.new('app', nil, '0.0.0.0', 10080) + trap(:INT) do + server.shutdown + end + server.start +end diff --git a/test/wsdl/simpletype/rpc/rpc.wsdl b/test/wsdl/simpletype/rpc/rpc.wsdl new file mode 100644 index 000000000..91f71a883 --- /dev/null +++ b/test/wsdl/simpletype/rpc/rpc.wsdl @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<definitions name="echo_version" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="urn:example.com:simpletype-rpc" + xmlns:txd="urn:example.com:simpletype-rpc-type" + targetNamespace="urn:example.com:simpletype-rpc" + xmlns="http://schemas.xmlsoap.org/wsdl/"> + <types> + <xsd:schema targetNamespace="urn:example.com:simpletype-rpc-type"> + <xsd:complexType name="version_struct"> + <xsd:all> + <xsd:element name="version" type="txd:version" /> + <xsd:element name="msg" type="xsd:string" /> + </xsd:all> + </xsd:complexType> + + <xsd:simpleType name="version"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="1.6"/> + <xsd:enumeration value="1.8"/> + <xsd:enumeration value="1.9"/> + </xsd:restriction> + </xsd:simpleType> + </xsd:schema> + </types> + + <message name="msg_version"> + <part name="version" type="txd:version"/> + </message> + + <message name="msg_version_struct"> + <part name="version_struct" type="txd:version_struct"/> + </message> + + <portType name="echo_version_port_type"> + <operation name="echo_version"> + <input message="tns:msg_version"/> + <output message="tns:msg_version_struct"/> + </operation> + + <operation name="echo_version_r"> + <input message="tns:msg_version_struct"/> + <output message="tns:msg_version"/> + </operation> + </portType> + + <binding name="echo_version_binding" type="tns:echo_version_port_type"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/> + <operation name="echo_version"> + <soap:operation soapAction="urn:example.com:simpletype-rpc"/> + <input> + <soap:body use="encoded" namespace="urn:example.com:simpletype-rpc" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body use="encoded" namespace="urn:example.com:simpletype-rpc" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + + <operation name="echo_version_r"> + <soap:operation soapAction="urn:example.com:simpletype-rpc"/> + <input> + <soap:body use="encoded" namespace="urn:example.com:simpletype-rpc" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body use="encoded" namespace="urn:example.com:simpletype-rpc" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + </binding> + + <service name="echo_version_service"> + <port name="echo_version_port" binding="tns:echo_version_binding"> + <soap:address location="http://localhost:10080"/> + </port> + </service> +</definitions> diff --git a/test/wsdl/simpletype/rpc/test_rpc.rb b/test/wsdl/simpletype/rpc/test_rpc.rb new file mode 100644 index 000000000..1d6a3eb4b --- /dev/null +++ b/test/wsdl/simpletype/rpc/test_rpc.rb @@ -0,0 +1,50 @@ +require 'test/unit' +require 'wsdl/parser' +require 'wsdl/soap/wsdl2ruby' + + +module WSDL; module SimpleType + + +class TestRPC < Test::Unit::TestCase + DIR = File.dirname(File.expand_path(__FILE__)) + def pathname(filename) + File.join(DIR, filename) + end + + def test_rpc + gen = WSDL::SOAP::WSDL2Ruby.new + gen.location = pathname("rpc.wsdl") + gen.basedir = DIR + gen.logger.level = Logger::FATAL + gen.opt['classdef'] = nil + gen.opt['driver'] = nil + gen.opt['client_skelton'] = nil + gen.opt['servant_skelton'] = nil + gen.opt['standalone_server_stub'] = nil + gen.opt['force'] = true + gen.run + compare("expectedEchoVersion.rb", "echo_version.rb") + compare("expectedDriver.rb", "echo_versionDriver.rb") + compare("expectedService.rb", "echo_version_service.rb") + compare("expectedClient.rb", "echo_version_serviceClient.rb") + compare("expectedServant.rb", "echo_versionServant.rb") + + File.unlink(pathname("echo_version.rb")) + File.unlink(pathname("echo_versionDriver.rb")) + File.unlink(pathname("echo_version_service.rb")) + File.unlink(pathname("echo_version_serviceClient.rb")) + File.unlink(pathname("echo_versionServant.rb")) + end + + def compare(expected, actual) + assert_equal(loadfile(expected), loadfile(actual), actual) + end + + def loadfile(file) + File.open(pathname(file)) { |f| f.read } + end +end + + +end; end |