aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
diff options
context:
space:
mode:
authorLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
committerLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
commitaaea48fe9826b9e5d2d5b92795a297b8f238c58d (patch)
treee7c01c7f95d467f837c1f96d58dac74c3c902610 /actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
parentaa09c770e9b5400683be11952673017295246de7 (diff)
downloadrails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.gz
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.bz2
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.zip
* collapse 'ws' back into protocols, it just added complexity and indirection, and was hard to extend.
* extract casting into seperate support file * ensure casting always does the right thing for return values, should fix interoperability issues with Ecto and possibly other XML-RPC clients * add functional unit tests for scaffolding * represent signature items with classes instead of symbols/Class objects, much more flexible * tweak logging to always show casted versions of parameters and return values, if possible. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1072 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionwebservice/lib/action_web_service/protocol/soap_protocol.rb')
-rw-r--r--actionwebservice/lib/action_web_service/protocol/soap_protocol.rb111
1 files changed, 98 insertions, 13 deletions
diff --git a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
index 5e56748ae3..cc3e90a4cc 100644
--- a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
+++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
@@ -1,3 +1,5 @@
+require 'action_web_service/protocol/soap_protocol/marshaler'
+
module ActionWebService # :nodoc:
module Protocol # :nodoc:
module Soap # :nodoc:
@@ -7,28 +9,105 @@ module ActionWebService # :nodoc:
end
class SoapProtocol < AbstractProtocol # :nodoc:
- def initialize
- @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
- @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
+ def marshaler
+ @marshaler ||= SoapMarshaler.new
+ end
+
+ def decode_action_pack_request(action_pack_request)
+ return nil unless has_valid_soap_action?(action_pack_request)
+ service_name = action_pack_request.parameters['action']
+ decode_request(action_pack_request.raw_post, service_name)
+ end
+
+ def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
+ request = super
+ request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
+ request
end
- def unmarshal_request(ap_request)
- return nil unless has_valid_soap_action?(ap_request)
- method_name, params = @encoder.decode_rpc_call(ap_request.raw_post)
- params = params.map{|x| @marshaler.unmarshal(x)}
- service_name = ap_request.parameters['action']
+ def decode_request(raw_request, service_name)
+ envelope = SOAP::Processor.unmarshal(raw_request)
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ request = envelope.body.request
+ method_name = request.elename.name
+ params = request.collect{ |k, v| marshaler.soap_to_ruby(request[k]) }
Request.new(self, method_name, params, service_name)
end
+ def encode_request(method_name, params, param_types)
+ param_types.each{ |type| marshaler.register_type(type) } if param_types
+ qname = XSD::QName.new(marshaler.type_namespace, method_name)
+ param_def = []
+ i = 0
+ if param_types
+ params = params.map do |param|
+ param_type = param_types[i]
+ param_def << ['in', param_type.name, marshaler.lookup_type(param_type).mapping]
+ i += 1
+ [param_type.name, marshaler.ruby_to_soap(param)]
+ end
+ else
+ params = []
+ end
+ request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
+ request.set_param(params)
+ envelope = create_soap_envelope(request)
+ SOAP::Processor.marshal(envelope)
+ end
+
+ def decode_response(raw_response)
+ envelope = SOAP::Processor.unmarshal(raw_response)
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ method_name = envelope.body.request.elename.name
+ return_value = envelope.body.response
+ return_value = marshaler.soap_to_ruby(return_value) unless return_value.nil?
+ [method_name, return_value]
+ end
+
+ def encode_response(method_name, return_value, return_type)
+ if return_type
+ return_binding = marshaler.register_type(return_type)
+ marshaler.annotate_arrays(return_binding, return_value)
+ end
+ qname = XSD::QName.new(marshaler.type_namespace, method_name)
+ if return_value.nil?
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ else
+ if return_value.is_a?(Exception)
+ detail = SOAP::Mapping::SOAPException.new(return_value)
+ response = SOAP::SOAPFault.new(
+ SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
+ SOAP::SOAPString.new(return_value.to_s),
+ SOAP::SOAPString.new(self.class.name),
+ marshaler.ruby_to_soap(detail))
+ else
+ if return_type
+ param_def = [['retval', 'return', marshaler.lookup_type(return_type).mapping]]
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
+ response.retval = marshaler.ruby_to_soap(return_value)
+ else
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ end
+ end
+ end
+ envelope = create_soap_envelope(response)
+ Response.new(SOAP::Processor.marshal(envelope), 'text/xml', return_value)
+ end
+
def protocol_client(api, protocol_name, endpoint_uri, options={})
return nil unless protocol_name == :soap
ActionWebService::Client::Soap.new(api, endpoint_uri, options)
end
- def create_action_pack_request(service_name, public_method_name, raw_body, options={})
- request = super
- request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
- request
+ def register_api(api)
+ api.api_methods.each do |name, method|
+ method.expects.each{ |type| marshaler.register_type(type) } if method.expects
+ method.returns.each{ |type| marshaler.register_type(type) } if method.returns
+ end
end
private
@@ -43,7 +122,13 @@ module ActionWebService # :nodoc:
return nil if soap_action.empty?
soap_action
end
- end
+
+ def create_soap_envelope(body)
+ header = SOAP::SOAPHeader.new
+ body = SOAP::SOAPBody.new(body)
+ SOAP::SOAPEnvelope.new(header, body)
+ end
+ end
end
end
end