summaryrefslogtreecommitdiff
path: root/lib/soap/rpc/router.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/rpc/router.rb')
-rw-r--r--lib/soap/rpc/router.rb221
1 files changed, 140 insertions, 81 deletions
diff --git a/lib/soap/rpc/router.rb b/lib/soap/rpc/router.rb
index 9d8d1c8da6..e9147af13a 100644
--- a/lib/soap/rpc/router.rb
+++ b/lib/soap/rpc/router.rb
@@ -9,6 +9,7 @@
require 'soap/soap'
require 'soap/processor'
require 'soap/mapping'
+require 'soap/mapping/wsdlliteralregistry'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/streamHandler'
@@ -27,26 +28,48 @@ class Router
attr_accessor :allow_unqualified_element
attr_accessor :default_encodingstyle
attr_accessor :mapping_registry
+ attr_accessor :literal_mapping_registry
attr_reader :headerhandler
def initialize(actor)
@actor = actor
- @receiver = {}
- @method_name = {}
- @method = {}
@allow_unqualified_element = false
@default_encodingstyle = nil
@mapping_registry = nil
@headerhandler = Header::HandlerSet.new
+ @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new
+ @operation = {}
end
- def add_method(receiver, qname, soapaction, name, param_def)
- fqname = fqname(qname)
- @receiver[fqname] = receiver
- @method_name[fqname] = name
- @method[fqname] = RPC::SOAPMethodRequest.new(qname, param_def, soapaction)
+ def add_rpc_method(receiver, qname, soapaction, name, param_def, opt = {})
+ opt[:request_style] ||= :rpc
+ opt[:response_style] ||= :rpc
+ opt[:request_use] ||= :encoded
+ opt[:response_use] ||= :encoded
+ add_operation(qname, soapaction, receiver, name, param_def, opt)
end
+ def add_document_method(receiver, qname, soapaction, name, param_def, opt = {})
+ opt[:request_style] ||= :document
+ opt[:response_style] ||= :document
+ opt[:request_use] ||= :encoded
+ opt[:response_use] ||= :encoded
+ if opt[:request_style] == :document
+ inputdef = param_def.find { |inout, paramname, typeinfo| inout == "input" }
+ klass, nsdef, namedef = inputdef[2]
+ qname = ::XSD::QName.new(nsdef, namedef)
+ end
+ add_operation(qname, soapaction, receiver, name, param_def, opt)
+ end
+
+ def add_operation(qname, soapaction, receiver, name, param_def, opt)
+ @operation[fqname(qname)] = Operation.new(qname, soapaction, receiver,
+ name, param_def, opt)
+ end
+
+ # add_method is for shortcut of typical use="encoded" method definition.
+ alias add_method add_rpc_method
+
def route(conn_data)
soap_response = nil
begin
@@ -55,33 +78,17 @@ class Router
raise ArgumentError.new("Illegal SOAP marshal format.")
end
receive_headers(env.header)
- soap_request = env.body.request
- unless soap_request.is_a?(SOAPStruct)
- raise RPCRoutingError.new("Not an RPC style.")
+ request = env.body.request
+ op = @operation[fqname(request.elename)]
+ unless op
+ raise RPCRoutingError.new("Method: #{request.elename} not supported.")
end
- soap_response = dispatch(soap_request)
+ soap_response = op.call(request, @mapping_registry, @literal_mapping_registry)
rescue Exception
soap_response = fault($!)
conn_data.is_fault = true
end
-
- opt = options
- opt[:external_content] = nil
- header = call_headers
- body = SOAPBody.new(soap_response)
- env = SOAPEnvelope.new(header, body)
- response_string = Processor.marshal(env, opt)
- conn_data.send_string = response_string
- 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
+ marshal(conn_data, op, soap_response)
conn_data
end
@@ -118,9 +125,9 @@ private
else
h = ::SOAP::SOAPHeader.new
headers.each do |header|
- h.add(header.elename.name, header)
- end
- h
+ h.add(header.elename.name, header)
+ end
+ h
end
end
@@ -153,32 +160,28 @@ private
env
end
- # Create new response.
- def create_response(qname, result)
- name = fqname(qname)
- if (@method.key?(name))
- method = @method[name]
- else
- raise RPCRoutingError.new("Method: #{ name } not defined.")
+ def marshal(conn_data, op, soap_response)
+ response_opt = options
+ response_opt[:external_content] = nil
+ if op and !conn_data.is_fault and op.response_use == :document
+ response_opt[:default_encodingstyle] =
+ ::SOAP::EncodingStyle::ASPDotNetHandler::Namespace
end
-
- soap_response = method.create_method_response
- if soap_response.have_outparam?
- unless result.is_a?(Array)
- raise RPCRoutingError.new("Out parameter was not returned.")
- end
- outparams = {}
- i = 1
- soap_response.each_param_name('out', 'inout') do |outparam|
- outparams[outparam] = Mapping.obj2soap(result[i], @mapping_registry)
- i += 1
+ header = call_headers
+ body = SOAPBody.new(soap_response)
+ env = SOAPEnvelope.new(header, body)
+ response_string = Processor.marshal(env, response_opt)
+ conn_data.send_string = response_string
+ if ext = response_opt[:external_content]
+ mime = MIMEMessage.new
+ ext.each do |k, v|
+ mime.add_attachment(v.data)
end
- soap_response.set_outparam(outparams)
- soap_response.retval = Mapping.obj2soap(result[0], @mapping_registry)
- else
- soap_response.retval = Mapping.obj2soap(result, @mapping_registry)
+ 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
- soap_response
end
# Create fault response.
@@ -191,31 +194,6 @@ private
Mapping.obj2soap(detail, @mapping_registry))
end
- # Dispatch to defined method.
- def dispatch(soap_method)
- request_struct = Mapping.soap2obj(soap_method, @mapping_registry)
- values = soap_method.collect { |key, value| request_struct[key] }
- method = lookup(soap_method.elename, values)
- unless method
- raise RPCRoutingError.new(
- "Method: #{ soap_method.elename } not supported.")
- end
-
- result = method.call(*values)
- create_response(soap_method.elename, result)
- end
-
- # Method lookup
- def lookup(qname, values)
- name = fqname(qname)
- # It may be necessary to check all part of method signature...
- if @method.member?(name)
- @receiver[name].method(@method_name[name].intern)
- else
- nil
- end
- end
-
def fqname(qname)
"#{ qname.namespace }:#{ qname.name }"
end
@@ -228,6 +206,87 @@ private
end
opt
end
+
+ class Operation
+ attr_reader :receiver
+ attr_reader :name
+ attr_reader :soapaction
+ attr_reader :request_style
+ attr_reader :response_style
+ attr_reader :request_use
+ attr_reader :response_use
+
+ def initialize(qname, soapaction, receiver, name, param_def, opt)
+ @soapaction = soapaction
+ @receiver = receiver
+ @name = name
+ @request_style = opt[:request_style]
+ @response_style = opt[:response_style]
+ @request_use = opt[:request_use]
+ @response_use = opt[:response_use]
+ if @response_style == :rpc
+ @rpc_response_factory =
+ RPC::SOAPMethodRequest.new(qname, param_def, @soapaction)
+ else
+ outputdef = param_def.find { |inout, paramname, typeinfo| inout == "output" }
+ klass, nsdef, namedef = outputdef[2]
+ @document_response_qname = ::XSD::QName.new(nsdef, namedef)
+ end
+ end
+
+ def call(request, mapping_registry, literal_mapping_registry)
+ if @request_style == :rpc
+ param = Mapping.soap2obj(request, mapping_registry)
+ result = rpc_call(request, param)
+ else
+ param = Mapping.soap2obj(request, literal_mapping_registry)
+ result = document_call(request, param)
+ end
+ if @response_style == :rpc
+ rpc_response(result, mapping_registry)
+ else
+ document_response(result, literal_mapping_registry)
+ end
+ end
+
+ private
+
+ def rpc_call(request, param)
+ unless request.is_a?(SOAPStruct)
+ raise RPCRoutingError.new("Not an RPC style.")
+ end
+ values = request.collect { |key, value| param[key] }
+ @receiver.method(@name.intern).call(*values)
+ end
+
+ def document_call(request, param)
+ @receiver.method(@name.intern).call(param)
+ end
+
+ def rpc_response(result, mapping_registry)
+ soap_response = @rpc_response_factory.create_method_response
+ if soap_response.have_outparam?
+ unless result.is_a?(Array)
+ raise RPCRoutingError.new("Out parameter was not returned.")
+ end
+ outparams = {}
+ i = 1
+ soap_response.each_param_name('out', 'inout') do |outparam|
+ outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry)
+ i += 1
+ end
+ soap_response.set_outparam(outparams)
+ soap_response.retval = Mapping.obj2soap(result[0], mapping_registry)
+ else
+ soap_response.retval = Mapping.obj2soap(result, mapping_registry)
+ end
+ soap_response
+ end
+
+ def document_response(result, literal_mapping_registry)
+ literal_mapping_registry.obj2soap(result, @document_response_qname)
+ end
+ end
end