From 991d0c409cc6b1d916330a32a9624aef808176a4 Mon Sep 17 00:00:00 2001 From: nahi Date: Sun, 22 May 2005 13:20:28 +0000 Subject: * lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4. == SOAP client and server == === for both client side and server side === * improved document/literal service support. style(rpc,document)/use(encoding, literal) combination are all supported. for the detail about combination, see test/soap/test_style.rb. * let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to WSDL as well as obj2soap. closes #70. * let SOAP::Mapping::Object handle XML attribute for doc/lit service. you can set/get XML attribute via accessor methods which as a name 'xmlattr_' prefixed ( -> Foo#xmlattr_name). === client side === * WSDLDriver capitalized name operation bug fixed. from 1.5.3-ruby1.8.2, operation which has capitalized name (such as KeywordSearchRequest in AWS) is defined as a method having uncapitalized name. (converted with GenSupport.safemethodname to handle operation name 'foo-bar'). it introduced serious incompatibility; in the past, it was defined as a capitalized. define capitalized method as well under that circumstance. * added new factory interface 'WSDLDriverFactory#create_rpc_driver' to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver are merged). 'WSDLDriverFactory#create_driver' still creates WSDLDriver for compatibility but it warns that the method is deprecated. please use create_rpc_driver instead of create_driver. * allow to use an URI object as an endpoint_url even with net/http, not http-access2. === server side === * added mod_ruby support to SOAP::CGIStub. rename a CGI script server.cgi to server.rb and let mod_ruby's RubyHandler handles the script. CGIStub detects if it's running under mod_ruby environment or not. * added fcgi support to SOAP::CGIStub. see the sample at sample/soap/calc/server.fcgi. (almost same as server.cgi but has fcgi handler at the bottom.) * allow to return a SOAPFault object to respond customized SOAP fault. * added the interface 'generate_explicit_type' for server side (CGIStub, HTTPServer). call 'self.generate_explicit_type = true' if you want to return simplified XML even if it's rpc/encoded service. == WSDL == === WSDL definition === * improved XML Schema support such as extension, restriction, simpleType, complexType + simpleContent, ref, length, import, include. * reduced "unknown element/attribute" warnings (warn only 1 time for each QName). * importing XSD file at schemaLocation with xsd:import. === code generation from WSDL === * generator crashed when there's '-' in defined element/attribute name. * added ApacheMap WSDL definition. * sample/{soap,wsdl}: removed. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@8502 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/soap/rpc/proxy.rb | 286 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 201 insertions(+), 85 deletions(-) (limited to 'lib/soap/rpc/proxy.rb') diff --git a/lib/soap/rpc/proxy.rb b/lib/soap/rpc/proxy.rb index ca110664f9..b9d80541af 100644 --- a/lib/soap/rpc/proxy.rb +++ b/lib/soap/rpc/proxy.rb @@ -1,5 +1,5 @@ # SOAP4R - RPC Proxy library. -# Copyright (C) 2000, 2003, 2004 NAKAMURA, Hiroshi . +# Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi . # 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; @@ -78,66 +78,77 @@ public @streamhandler.test_loopback_response end - def add_rpc_method(qname, soapaction, name, param_def, opt = {}) + def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) + opt[:request_qname] = qname opt[:request_style] ||= :rpc opt[:response_style] ||= :rpc opt[:request_use] ||= :encoded opt[:response_use] ||= :encoded - @operation[name] = Operation.new(qname, soapaction, name, param_def, opt) + @operation[name] = Operation.new(soapaction, param_def, opt) end - def add_document_method(qname, soapaction, name, param_def, opt = {}) + def add_document_operation(soapaction, name, param_def, opt = {}) opt[:request_style] ||= :document opt[:response_style] ||= :document opt[:request_use] ||= :literal opt[:response_use] ||= :literal - @operation[name] = Operation.new(qname, soapaction, name, param_def, opt) + @operation[name] = Operation.new(soapaction, param_def, opt) end # add_method is for shortcut of typical rpc/encoded method definition. - alias add_method add_rpc_method + alias add_method add_rpc_operation + alias add_rpc_method add_rpc_operation + alias add_document_method add_document_operation - def invoke(req_header, req_body, opt = create_options) - req_env = SOAPEnvelope.new(req_header, req_body) - opt[:external_content] = nil - conn_data = marshal(req_env, opt) - if ext = opt[:external_content] - mime = MIMEMessage.new - ext.each do |k, v| - mime.add_attachment(v.data) - end - mime.add_part(conn_data.send_string + "\r\n") - mime.close - conn_data.send_string = mime.content_str - conn_data.send_contenttype = mime.headers['content-type'].str - end - conn_data = @streamhandler.send(@endpoint_url, conn_data, opt[:soapaction]) - if conn_data.receive_string.empty? - return nil - end - unmarshal(conn_data, opt) + def invoke(req_header, req_body, opt = nil) + opt ||= create_options + route(req_header, req_body, opt, opt) end def call(name, *params) unless op_info = @operation[name] - raise MethodDefinitionError, "Method: #{name} not defined." + raise MethodDefinitionError, "method: #{name} not defined" end req_header = create_request_header - req_body = op_info.create_request_body(params, @mapping_registry, - @literal_mapping_registry) - opt = create_options({ + req_body = SOAPBody.new( + op_info.request_body(params, @mapping_registry, @literal_mapping_registry) + ) + reqopt = create_options({ :soapaction => op_info.soapaction || @soapaction, + :default_encodingstyle => op_info.request_default_encodingstyle}) + resopt = create_options({ :default_encodingstyle => op_info.response_default_encodingstyle}) - env = invoke(req_header, req_body, opt) + env = route(req_header, req_body, reqopt, resopt) + raise EmptyResponseError unless env receive_headers(env.header) - raise EmptyResponseError.new("Empty response.") unless env begin check_fault(env.body) rescue ::SOAP::FaultError => e - Mapping.fault2exception(e) + op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry) end - op_info.create_response_obj(env, @mapping_registry, - @literal_mapping_registry) + op_info.response_obj(env.body, @mapping_registry, @literal_mapping_registry) + end + + def route(req_header, req_body, reqopt, resopt) + req_env = SOAPEnvelope.new(req_header, req_body) + reqopt[:external_content] = nil + conn_data = marshal(req_env, reqopt) + if ext = reqopt[:external_content] + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + end + conn_data = @streamhandler.send(@endpoint_url, conn_data, + reqopt[:soapaction]) + if conn_data.receive_string.empty? + return nil + end + unmarshal(conn_data, resopt) end def check_fault(body) @@ -217,97 +228,202 @@ private attr_reader :request_use attr_reader :response_use - def initialize(qname, soapaction, name, param_def, opt) + def initialize(soapaction, param_def, opt) @soapaction = soapaction @request_style = opt[:request_style] @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] - @rpc_method_factory = @document_method_name = nil check_style(@request_style) check_style(@response_style) + check_use(@request_use) + check_use(@response_use) if @request_style == :rpc - @rpc_method_factory = SOAPMethodRequest.new(qname, param_def, - @soapaction) + @rpc_request_qname = opt[:request_qname] + if @rpc_request_qname.nil? + raise MethodDefinitionError.new("rpc_request_qname must be given") + end + @rpc_method_factory = + RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction) else - @document_method_name = {} + @doc_request_qnames = [] + @doc_response_qnames = [] param_def.each do |inout, paramname, typeinfo| - klass, namespace, name = typeinfo - case inout.to_s - when "input" - @document_method_name[:input] = ::XSD::QName.new(namespace, name) - when "output" - @document_method_name[:output] = ::XSD::QName.new(namespace, name) + klass_not_used, nsdef, namedef = typeinfo + if namedef.nil? + raise MethodDefinitionError.new("qname must be given") + end + case inout + when SOAPMethod::IN + @doc_request_qnames << XSD::QName.new(nsdef, namedef) + when SOAPMethod::OUT + @doc_response_qnames << XSD::QName.new(nsdef, namedef) else - raise MethodDefinitionError, "unknown type: " + inout + raise MethodDefinitionError.new( + "illegal inout definition for document style: #{inout}") end end end end def request_default_encodingstyle - (@request_style == :rpc) ? EncodingNamespace : LiteralNamespace + (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace end def response_default_encodingstyle - (@response_style == :rpc) ? EncodingNamespace : LiteralNamespace + (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end - # for rpc - def each_param_name(*target) + def request_body(values, mapping_registry, literal_mapping_registry) if @request_style == :rpc - @rpc_method_factory.each_param_name(*target) do |name| - yield(name) - end + request_rpc(values, mapping_registry, literal_mapping_registry) else - yield(@document_method_name[:input].name) + request_doc(values, mapping_registry, literal_mapping_registry) end end - def create_request_body(values, mapping_registry, literal_mapping_registry) - if @request_style == :rpc - values = Mapping.obj2soap(values, mapping_registry).to_a - method = @rpc_method_factory.dup - params = {} - idx = 0 - method.each_param_name(::SOAP::RPC::SOAPMethod::IN, - ::SOAP::RPC::SOAPMethod::INOUT) do |name| - params[name] = values[idx] || SOAPNil.new - idx += 1 - end - method.set_param(params) - SOAPBody.new(method) + def response_obj(body, mapping_registry, literal_mapping_registry) + if @response_style == :rpc + response_rpc(body, mapping_registry, literal_mapping_registry) else - name = @document_method_name[:input] - document = literal_mapping_registry.obj2soap(values[0], name) - SOAPBody.new(document) + response_doc(body, mapping_registry, literal_mapping_registry) end end - def create_response_obj(env, mapping_registry, literal_mapping_registry) + def raise_fault(e, mapping_registry, literal_mapping_registry) if @response_style == :rpc - ret = env.body.response ? - Mapping.soap2obj(env.body.response, mapping_registry) : nil - if env.body.outparams - outparams = env.body.outparams.collect { |outparam| - Mapping.soap2obj(outparam) - } - [ret].concat(outparams) - else - ret - end + Mapping.fault2exception(e, mapping_registry) else - Mapping.soap2obj(env.body.root_node, literal_mapping_registry) + Mapping.fault2exception(e, literal_mapping_registry) end end private - ALLOWED_STYLE = [:rpc, :document] def check_style(style) - unless ALLOWED_STYLE.include?(style) - raise MethodDefinitionError, "unknown style: " + style + unless [:rpc, :document].include?(style) + raise MethodDefinitionError.new("unknown style: #{style}") + end + end + + def check_use(use) + unless [:encoded, :literal].include?(use) + raise MethodDefinitionError.new("unknown use: #{use}") + end + end + + def request_rpc(values, mapping_registry, literal_mapping_registry) + if @request_use == :encoded + request_rpc_enc(values, mapping_registry) + else + request_rpc_lit(values, literal_mapping_registry) + end + end + + def request_doc(values, mapping_registry, literal_mapping_registry) + if @request_use == :encoded + request_doc_enc(values, mapping_registry) + else + request_doc_lit(values, literal_mapping_registry) + end + end + + def request_rpc_enc(values, mapping_registry) + method = @rpc_method_factory.dup + names = method.input_params + obj = create_request_obj(names, values) + soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname) + method.set_param(soap) + method + end + + def request_rpc_lit(values, mapping_registry) + 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)) + idx += 1 + end + method.set_param(params) + method + end + + def request_doc_enc(values, mapping_registry) + (0...values.size).collect { |idx| + ele = Mapping.obj2soap(values[idx], mapping_registry) + ele.elename = @doc_request_qnames[idx] + ele + } + end + + def request_doc_lit(values, mapping_registry) + (0...values.size).collect { |idx| + ele = Mapping.obj2soap(values[idx], mapping_registry, + @doc_request_qnames[idx]) + ele.encodingstyle = LiteralNamespace + ele + } + end + + def response_rpc(body, mapping_registry, literal_mapping_registry) + if @response_use == :encoded + response_rpc_enc(body, mapping_registry) + else + response_rpc_lit(body, literal_mapping_registry) + end + end + + def response_doc(body, mapping_registry, literal_mapping_registry) + if @response_use == :encoded + return *response_doc_enc(body, mapping_registry) + else + return *response_doc_lit(body, literal_mapping_registry) + end + end + + def response_rpc_enc(body, mapping_registry) + ret = nil + if body.response + ret = Mapping.soap2obj(body.response, mapping_registry, + @rpc_method_factory.retval_class_name) + end + if body.outparams + outparams = body.outparams.collect { |outparam| + Mapping.soap2obj(outparam, mapping_regisry) + } + [ret].concat(outparams) + else + ret + end + end + + def response_rpc_lit(body, mapping_registry) + body.root_node.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, + @rpc_method_factory.retval_class_name) + } + end + + def response_doc_enc(body, mapping_registry) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry) + } + end + + def response_doc_lit(body, mapping_registry) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry) + } + end + + def create_request_obj(names, params) + o = Object.new + for idx in 0 ... params.length + o.instance_variable_set('@' + names[idx], params[idx]) end + o end end end -- cgit v1.2.3