diff options
author | Leon Breedt <bitserf@gmail.com> | 2005-04-05 21:37:48 +0000 |
---|---|---|
committer | Leon Breedt <bitserf@gmail.com> | 2005-04-05 21:37:48 +0000 |
commit | 1155ea0aa3c25b4683c6343162cd49dbe0fec094 (patch) | |
tree | 3f51d6a8bb7d64cc71c8546055ca03c906cd3d7a /actionwebservice | |
parent | 81014da84c9ae4dacb70287ff6f509d7a40cc0ae (diff) | |
download | rails-1155ea0aa3c25b4683c6343162cd49dbe0fec094.tar.gz rails-1155ea0aa3c25b4683c6343162cd49dbe0fec094.tar.bz2 rails-1155ea0aa3c25b4683c6343162cd49dbe0fec094.zip |
initial go at making :layered dispatching generate WSDL for SOAP, and have
:layered process SOAP method calls correctly as well, may be unstable
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1097 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionwebservice')
8 files changed, 63 insertions, 23 deletions
diff --git a/actionwebservice/CHANGELOG b/actionwebservice/CHANGELOG index 38f01eb52e..a8e72cffc8 100644 --- a/actionwebservice/CHANGELOG +++ b/actionwebservice/CHANGELOG @@ -2,6 +2,9 @@ * Add scaffolding via ActionController::Base.web_service_scaffold for quick testing using a web browser +* The :layered dispatching mode can now be used with SOAP as well, allowing you to support SOAP and XML-RPC + clients for APIs like the metaWeblog API + * Remove ActiveRecordSoapMarshallable workaround, see #912 for details * Generalize casting code to be used by both SOAP and XML-RPC (previously, it was only XML-RPC) diff --git a/actionwebservice/README b/actionwebservice/README index d6bcea7534..8f4588cdf9 100644 --- a/actionwebservice/README +++ b/actionwebservice/README @@ -162,11 +162,10 @@ This mode is similar to _delegated_ mode, in that multiple web service objects can be attached to one controller, however, all protocol requests are sent to a single endpoint. -This mode is only usable by XML-RPC. In this mode, method names can contain -_prefixes_, which will indicate which web service object implements the API -identified by that prefix. +Use this mode when you want to share code between XML-RPC and SOAP clients, +for APIs where the XML-RPC method names have prefixes. An example of such +a method name would be <tt>blogger.newPost</tt>. -The _prefix_ can be any word, followed by a period. ==== Layered dispatching example @@ -192,8 +191,8 @@ The _prefix_ can be any word, followed by a period. end -For this example, a remote call for a method with a name like -<tt>mt.getCategories</tt> will be dispatched as the <tt>getCategories</tt> +For this example, an XML-RPC call for a method with a name like +<tt>mt.getCategories</tt> will be sent to the <tt>getCategories</tt> method on the <tt>:mt</tt> service. diff --git a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb index 975120212f..1d8715a8f7 100644 --- a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb +++ b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb @@ -52,9 +52,17 @@ module ActionWebService # :nodoc: invocation.protocol = request.protocol invocation.service_name = request.service_name if web_service_dispatching_mode == :layered - if request.method_name =~ /^([^\.]+)\.(.*)$/ - public_method_name = $2 - invocation.service_name = $1 + case invocation.protocol + when Protocol::Soap::SoapProtocol + soap_action = request.protocol_options[:soap_action] + if soap_action && soap_action =~ /^\/\w+\/(\w+)\// + invocation.service_name = $1 + end + when Protocol::XmlRpc::XmlRpcProtocol + if request.method_name =~ /^([^\.]+)\.(.*)$/ + public_method_name = $2 + invocation.service_name = $1 + end end end case web_service_dispatching_mode diff --git a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb index 822939a101..a999be9b7c 100644 --- a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +++ b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb @@ -185,7 +185,7 @@ module ActionWebService # :nodoc: api = self.class.web_service_api web_service_name = controller_class_name.sub(/Controller$/, '').underscore apis[web_service_name] = [api, register_api(api, marshaler)] - when :delegated + when :delegated, :layered self.class.web_services.each do |web_service_name, info| service = web_service_object(web_service_name) api = service.class.web_service_api @@ -244,7 +244,7 @@ module ActionWebService # :nodoc: api = values[0] api.api_methods.each do |name, method| gen = lambda do |msg_name, direction| - xm.message('name' => msg_name) do + xm.message('name' => message_name_for(api_name, msg_name)) do sym = nil if direction == :out returns = method.returns @@ -271,8 +271,8 @@ module ActionWebService # :nodoc: xm.portType('name' => port_name) do api.api_methods.each do |name, method| xm.operation('name' => method.public_name) do - xm.input('message' => "typens:#{method.public_name}") - xm.output('message' => "typens:#{method.public_name}Response") + xm.input('message' => "typens:" + message_name_for(api_name, method.public_name)) + xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response")) end end end @@ -284,9 +284,9 @@ module ActionWebService # :nodoc: api.api_methods.each do |name, method| xm.operation('name' => method.public_name) do case web_service_dispatching_mode - when :direct, :layered + when :direct soap_action = soap_action_base + "/api/" + method.public_name - when :delegated + when :delegated, :layered soap_action = soap_action_base \ + "/" + api_name.to_s \ + "/" + method.public_name @@ -315,7 +315,7 @@ module ActionWebService # :nodoc: port_name = port_name_for(global_service_name, api_name) binding_name = binding_name_for(global_service_name, api_name) case web_service_dispatching_mode - when :direct + when :direct, :layered binding_target = 'api' when :delegated binding_target = api_name.to_s @@ -336,6 +336,15 @@ module ActionWebService # :nodoc: "#{global_service}#{service.to_s.camelize}Binding" end + def message_name_for(api_name, message_name) + mode = web_service_dispatching_mode + if mode == :layered || mode == :delegated + api_name.to_s + '-' + message_name + else + message_name + end + end + def register_api(api, marshaler) bindings = {} traverse_custom_types(api, marshaler) do |binding| diff --git a/actionwebservice/lib/action_web_service/protocol/abstract.rb b/actionwebservice/lib/action_web_service/protocol/abstract.rb index 70b922ce73..d8830968d0 100644 --- a/actionwebservice/lib/action_web_service/protocol/abstract.rb +++ b/actionwebservice/lib/action_web_service/protocol/abstract.rb @@ -17,7 +17,7 @@ module ActionWebService # :nodoc: request end - def decode_request(raw_request, service_name) + def decode_request(raw_request, service_name, protocol_options=nil) end def encode_request(method_name, params, param_types) @@ -43,14 +43,16 @@ module ActionWebService # :nodoc: attr :service_name attr_accessor :api attr_accessor :api_method + attr :protocol_options - def initialize(protocol, method_name, method_params, service_name, api=nil, api_method=nil) + def initialize(protocol, method_name, method_params, service_name, api=nil, api_method=nil, protocol_options=nil) @protocol = protocol @method_name = method_name @method_params = method_params @service_name = service_name @api = api @api_method = api_method + @protocol_options = protocol_options || {} end end diff --git a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb index 4bc9d2806e..fde992bf9a 100644 --- a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb +++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb @@ -14,9 +14,10 @@ module ActionWebService # :nodoc: end def decode_action_pack_request(action_pack_request) - return nil unless has_valid_soap_action?(action_pack_request) + return nil unless soap_action = has_valid_soap_action?(action_pack_request) service_name = action_pack_request.parameters['action'] - decode_request(action_pack_request.raw_post, service_name) + protocol_options = { :soap_action => soap_action } + decode_request(action_pack_request.raw_post, service_name, protocol_options) end def encode_action_pack_request(service_name, public_method_name, raw_body, options={}) @@ -25,7 +26,7 @@ module ActionWebService # :nodoc: request end - def decode_request(raw_request, service_name) + def decode_request(raw_request, service_name, protocol_options=nil) envelope = SOAP::Processor.unmarshal(raw_request) unless envelope raise ProtocolError, "Failed to parse SOAP request message" @@ -33,7 +34,7 @@ module ActionWebService # :nodoc: 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) + Request.new(self, method_name, params, service_name, nil, nil, protocol_options) end def encode_request(method_name, params, param_types) diff --git a/actionwebservice/test/abstract_dispatcher.rb b/actionwebservice/test/abstract_dispatcher.rb index 4784180518..c3d256d71a 100644 --- a/actionwebservice/test/abstract_dispatcher.rb +++ b/actionwebservice/test/abstract_dispatcher.rb @@ -371,24 +371,33 @@ module DispatcherCommonTests end def do_method_call(container, public_method_name, *params) + request_env = {} mode = container.web_service_dispatching_mode case mode when :direct service_name = service_name(container) api = container.class.web_service_api + method = api.public_api_method_instance(public_method_name) when :delegated service_name = service_name(container) api = container.web_service_object(service_name).class.web_service_api + method = api.public_api_method_instance(public_method_name) when :layered service_name = nil + real_method_name = nil if public_method_name =~ /^([^\.]+)\.(.*)$/ service_name = $1 + real_method_name = $2 + end + if @protocol.is_a? ActionWebService::Protocol::Soap::SoapProtocol + public_method_name = real_method_name + request_env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{real_method_name}" end api = container.web_service_object(service_name.to_sym).class.web_service_api + method = api.public_api_method_instance(real_method_name) service_name = self.service_name(container) end @protocol.register_api(api) - method = api.public_api_method_instance(public_method_name) virtual = false unless method virtual = true @@ -397,6 +406,7 @@ module DispatcherCommonTests body = @protocol.encode_request(public_method_name, params.dup, method.expects) # puts body ap_request = @protocol.encode_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest) + ap_request.env.update(request_env) ap_response = ActionController::TestResponse.new container.process(ap_request, ap_response) # puts ap_response.body diff --git a/actionwebservice/test/dispatcher_action_controller_soap_test.rb b/actionwebservice/test/dispatcher_action_controller_soap_test.rb index 3d7327be02..731185f398 100644 --- a/actionwebservice/test/dispatcher_action_controller_soap_test.rb +++ b/actionwebservice/test/dispatcher_action_controller_soap_test.rb @@ -26,6 +26,7 @@ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase @direct_controller = DirectController.new @delegated_controller = DelegatedController.new @virtual_controller = VirtualController.new + @layered_controller = LayeredController.new @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new end @@ -59,6 +60,13 @@ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase assert(BrokenAutoLoadController.web_service_api.nil?) end + def test_layered_dispatching + mt_cats = do_method_call(@layered_controller, 'mt.getCategories') + assert_equal(["mtCat1", "mtCat2"], mt_cats) + blogger_cats = do_method_call(@layered_controller, 'blogger.getCategories') + assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats) + end + protected def exception_message(soap_fault_exception) soap_fault_exception.detail.cause.message |