diff options
Diffstat (limited to 'lib/soap/wsdlDriver.rb')
-rw-r--r-- | lib/soap/wsdlDriver.rb | 248 |
1 files changed, 166 insertions, 82 deletions
diff --git a/lib/soap/wsdlDriver.rb b/lib/soap/wsdlDriver.rb index f13aa94f94..3431d5d673 100644 --- a/lib/soap/wsdlDriver.rb +++ b/lib/soap/wsdlDriver.rb @@ -1,5 +1,5 @@ # SOAP4R - SOAP WSDL driver -# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <[email protected]>. +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <[email protected]>. # 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; @@ -9,19 +9,11 @@ require 'wsdl/parser' require 'wsdl/importer' require 'xsd/qname' -require 'soap/element' -require 'soap/baseData' -require 'soap/streamHandler' -require 'soap/mimemessage' -require 'soap/mapping' +require 'xsd/codegen/gensupport' require 'soap/mapping/wsdlencodedregistry' require 'soap/mapping/wsdlliteralregistry' -require 'soap/rpc/rpc' -require 'soap/rpc/element' -require 'soap/rpc/proxy' -require 'soap/processor' -require 'soap/header/handlerset' -require 'xsd/codegen/gensupport' +require 'soap/rpc/driver' +require 'wsdl/soap/methodDefCreator' module SOAP @@ -32,60 +24,165 @@ class WSDLDriverFactory attr_reader :wsdl - def initialize(wsdl, logdev = nil) - @logdev = logdev + def initialize(wsdl) @wsdl = import(wsdl) + @methoddefcreator = WSDL::SOAP::MethodDefCreator.new(@wsdl) end def inspect "#<#{self.class}:#{@wsdl.name}>" end + def create_rpc_driver(servicename = nil, portname = nil) + port = find_port(servicename, portname) + drv = SOAP::RPC::Driver.new(port.soap_address.location) + init_driver(drv, port) + add_operation(drv, port) + drv + end + + # depricated old interface def create_driver(servicename = nil, portname = nil) - service = if servicename - @wsdl.service(XSD::QName.new(@wsdl.targetnamespace, servicename)) - else - @wsdl.services[0] - end + warn("WSDLDriverFactory#create_driver is depricated. Use create_rpc_driver instead.") + port = find_port(servicename, portname) + WSDLDriver.new(@wsdl, port, @logdev) + end + + # Backward compatibility. + alias createDriver create_driver + +private + + def find_port(servicename = nil, portname = nil) + service = port = nil + if servicename + service = @wsdl.service( + XSD::QName.new(@wsdl.targetnamespace, servicename)) + else + service = @wsdl.services[0] + end if service.nil? - raise FactoryError.new("Service #{ servicename } not found in WSDL.") + raise FactoryError.new("service #{servicename} not found in WSDL") + end + if portname + port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)] + else + port = service.ports[0] end - port = if portname - service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)] - else - service.ports[0] - end if port.nil? - raise FactoryError.new("Port #{ portname } not found in WSDL.") + raise FactoryError.new("port #{portname} not found in WSDL") end if port.soap_address.nil? - raise FactoryError.new("soap:address element not found in WSDL.") + raise FactoryError.new("soap:address element not found in WSDL") end - WSDLDriver.new(@wsdl, port, @logdev) + port end - # Backward compatibility. - alias createDriver create_driver + def init_driver(drv, port) + wsdl_elements = @wsdl.collect_elements + wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes + rpc_decode_typemap = wsdl_types + + @wsdl.soap_rpc_complextypes(port.find_binding) + drv.proxy.mapping_registry = + Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap) + drv.proxy.literal_mapping_registry = + Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements) + end + + def add_operation(drv, port) + port.find_binding.operations.each do |op_bind| + op_name = op_bind.soapoperation_name + soapaction = op_bind.soapaction || '' + orgname = op_name.name + name = XSD::CodeGen::GenSupport.safemethodname(orgname) + param_def = create_param_def(op_bind) + opt = {} + opt[:request_style] = opt[:response_style] = op_bind.soapoperation_style + opt[:request_use] = (op_bind.input.soapbody.use || 'literal').intern + opt[:response_use] = (op_bind.output.soapbody.use || 'literal').intern + if op_bind.soapoperation_style == :rpc + drv.add_rpc_operation(op_name, soapaction, name, param_def, opt) + else + drv.add_document_operation(soapaction, name, param_def, opt) + end + if orgname != name and orgname.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(drv, orgname) do |*arg| + __send__(name, *arg) + end + end + end + end -private - def import(location) WSDL::Importer.import(location) end + + def create_param_def(op_bind) + op = op_bind.find_operation + if op_bind.soapoperation_style == :rpc + param_def = @methoddefcreator.collect_rpcparameter(op) + else + param_def = @methoddefcreator.collect_documentparameter(op) + end + # the first element of typedef in param_def is a String like + # "::SOAP::SOAPStruct". turn this String to a class. + param_def.collect { |io, typedef, name| + typedef[0] = Mapping.class_from_name(typedef[0]) + [io, name, typedef] + } + end + + def partqname(part) + if part.type + part.type + else + part.element + end + end + + def param_def(type, name, klass, partqname) + [type, name, [klass, partqname.namespace, partqname.name]] + end + + def filter_parts(partsdef, partssource) + parts = partsdef.split(/\s+/) + partssource.find_all { |part| parts.include?(part.name) } + end end class WSDLDriver class << self def __attr_proxy(symbol, assignable = false) - name = symbol.to_s - self.__send__(:define_method, name, proc { - @servant.__send__(name) - }) - if assignable - self.__send__(:define_method, name + '=', proc { |rhs| - @servant.__send__(name + '=', rhs) + end + + if RUBY_VERSION >= "1.7.0" + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + self.__send__(:define_method, name, proc { + @servant.__send__(name) }) + if assignable + self.__send__(:define_method, name + '=', proc { |rhs| + @servant.__send__(name + '=', rhs) + }) + end + end + else + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + module_eval <<-EOS + def #{name} + @servant.#{name} + end + EOS + if assignable + module_eval <<-EOS + def #{name}=(value) + @servant.#{name} = value + end + EOS + end end end end @@ -179,8 +276,10 @@ class WSDLDriver @wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes @rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) - @wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new(@rpc_decode_typemap) - @doc_mapper = Mapping::WSDLLiteralRegistry.new(@wsdl_elements, @wsdl_types) + @wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new( + @rpc_decode_typemap) + @doc_mapper = Mapping::WSDLLiteralRegistry.new( + @wsdl_types, @wsdl_elements) endpoint_url = @port.soap_address.location # Convert a map which key is QName, to a Hash which key is String. @operation = {} @@ -222,15 +321,16 @@ class WSDLDriver def rpc_call(name, *values) set_wiredump_file_base(name) unless op_info = @operation[name] - raise MethodDefinitionError, "Method: #{name} not defined." + raise RuntimeError, "method: #{name} not defined" end req_header = create_request_header req_body = create_request_body(op_info, *values) - opt = create_options({ - :soapaction => op_info.soapaction || @soapaction, + reqopt = create_options({ + :soapaction => op_info.soapaction || @soapaction}) + resopt = create_options({ :decode_typemap => @rpc_decode_typemap}) - env = @proxy.invoke(req_header, req_body, opt) - raise EmptyResponseError.new("Empty response.") unless env + env = @proxy.route(req_header, req_body, reqopt, resopt) + raise EmptyResponseError unless env receive_headers(env.header) begin @proxy.check_fault(env.body) @@ -249,21 +349,6 @@ class WSDLDriver end end - def document_call(name, param) - set_wiredump_file_base(name) - op_info = @operation[name] - req_header = header_from_obj(header_obj, op_info) - req_body = body_from_obj(body_obj, op_info) - env = @proxy.invoke(req_header, req_body, op_info.soapaction || @soapaction, @wsdl_types) - raise EmptyResponseError.new("Empty response.") unless env - if env.body.fault - raise ::SOAP::FaultError.new(env.body.fault) - end - res_body_obj = env.body.response ? - Mapping.soap2obj(env.body.response, @mapping_registry) : nil - return env.header, res_body_obj - end - # req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...] # req_body: SOAPBasetype/SOAPCompoundtype def document_send(name, header_obj, body_obj) @@ -275,7 +360,7 @@ class WSDLDriver :soapaction => op_info.soapaction || @soapaction, :decode_typemap => @wsdl_types}) env = @proxy.invoke(req_header, req_body, opt) - raise EmptyResponseError.new("Empty response.") unless env + raise EmptyResponseError unless env if env.body.fault raise ::SOAP::FaultError.new(env.body.fault) end @@ -297,7 +382,7 @@ class WSDLDriver def set_wiredump_file_base(name) if @wiredump_file_base - @proxy.set_wiredump_file_base(@wiredump_file_base + "_#{ name }") + @proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}") end end @@ -326,7 +411,7 @@ class WSDLDriver def create_method_struct(op_info, *params) parts_names = op_info.bodyparts.collect { |part| part.name } obj = create_method_obj(parts_names, params) - method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.optype_name) + method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name) if method.members.size != parts_names.size new_method = SOAPStruct.new method.each do |key, value| @@ -356,7 +441,7 @@ class WSDLDriver if obj.nil? nil else - raise RuntimeError.new("No header definition in schema.") + raise RuntimeError.new("no header definition in schema: #{obj}") end elsif op_info.headerparts.size == 1 part = op_info.headerparts[0] @@ -366,7 +451,7 @@ class WSDLDriver else header = SOAPHeader.new() op_info.headerparts.each do |part| - child = Mapping.find_attribute(obj, part.name) + child = Mapping.get_attribute(obj, part.name) ele = headeritem_from_obj(child, part.element || part.eletype) header.add(part.name, ele) end @@ -391,7 +476,7 @@ class WSDLDriver if obj.nil? nil else - raise RuntimeError.new("No body found in schema.") + raise RuntimeError.new("no body found in schema") end elsif op_info.bodyparts.size == 1 part = op_info.bodyparts[0] @@ -400,7 +485,7 @@ class WSDLDriver else body = SOAPBody.new op_info.bodyparts.each do |part| - child = Mapping.find_attribute(obj, part.name) + child = Mapping.get_attribute(obj, part.name) ele = bodyitem_from_obj(child, part.element || part.type) body.add(ele.elename.name, ele) end @@ -419,39 +504,40 @@ class WSDLDriver end def add_method_interface(op_info) - name = ::XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name) + name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name) + orgname = op_info.op_name.name + parts_names = op_info.bodyparts.collect { |part| part.name } case op_info.style when :document - add_document_method_interface(name) + if orgname != name and orgname.capitalize == name.capitalize + add_document_method_interface(orgname, parts_names) + end + add_document_method_interface(name, parts_names) when :rpc - parts_names = op_info.bodyparts.collect { |part| part.name } - orgname = op_info.op_name.name if orgname != name and orgname.capitalize == name.capitalize add_rpc_method_interface(orgname, parts_names) end add_rpc_method_interface(name, parts_names) else - raise RuntimeError.new("Unknown style: #{op_info.style}") + raise RuntimeError.new("unknown style: #{op_info.style}") end end def add_rpc_method_interface(name, parts_names) - sclass = class << @host; self; end - sclass.__send__(:define_method, name, proc { |*arg| + ::SOAP::Mapping.define_singleton_method(@host, name) do |*arg| unless arg.size == parts_names.size raise ArgumentError.new( "wrong number of arguments (#{arg.size} for #{parts_names.size})") end @servant.rpc_call(name, *arg) - }) + end @host.method(name) end - def add_document_method_interface(name) - sclass = class << @host; self; end - sclass.__send__(:define_method, name, proc { |h, b| + def add_document_method_interface(name, parts_names) + ::SOAP::Mapping.define_singleton_method(@host, name) do |*arg| @servant.document_send(name, h, b) - }) + end @host.method(name) end @@ -476,5 +562,3 @@ end end - - |