Skip to content
This repository
Browse code

add 'system.multicall' support to XML-RPC. boxcarred methods must sti…

…ll exist

on the target service(s), value casting will still be performed, and recursive
'system.multicall' calls are not allowed.


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2021 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 9d79880e81a035c96ca70d7e342549236ed1f242 1 parent 2eba713
Leon Breedt bitserf authored
2  actionwebservice/CHANGELOG
... ... @@ -1,5 +1,7 @@
1 1 *SVN*
2 2
  3 +* Add XML-RPC 'system.multicall' support #1941 [jbonnar]
  4 +
3 5 * Fix duplicate XSD entries for custom types shared across delegated/layered services #1729 [Tyler Kovacs]
4 6
5 7 * Allow multiple invocations in the same test method #1720 [dkhawk]
66 actionwebservice/lib/action_web_service/dispatcher/abstract.rb
@@ -16,11 +16,10 @@ module InstanceMethods # :nodoc:
16 16 private
17 17 def invoke_web_service_request(protocol_request)
18 18 invocation = web_service_invocation(protocol_request)
19   - case web_service_dispatching_mode
20   - when :direct
21   - web_service_direct_invoke(invocation)
22   - when :delegated, :layered
23   - web_service_delegated_invoke(invocation)
  19 + if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
  20 + xmlrpc_multicall_invoke(invocation)
  21 + else
  22 + web_service_invoke(invocation)
24 23 end
25 24 end
26 25
@@ -47,10 +46,43 @@ def web_service_filtered_invoke(invocation, params)
47 46 if cancellation_reason
48 47 raise(DispatcherError, "request canceled: #{cancellation_reason}")
49 48 end
  49 + return_value
  50 + end
  51 +
  52 + def web_service_invoke(invocation)
  53 + case web_service_dispatching_mode
  54 + when :direct
  55 + return_value = web_service_direct_invoke(invocation)
  56 + when :delegated, :layered
  57 + return_value = web_service_delegated_invoke(invocation)
  58 + end
50 59 web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
51 60 end
  61 +
  62 + def xmlrpc_multicall_invoke(invocations)
  63 + responses = []
  64 + invocations.each do |invocation|
  65 + begin
  66 + case web_service_dispatching_mode
  67 + when :direct
  68 + return_value = web_service_direct_invoke(invocation)
  69 + when :delegated, :layered
  70 + return_value = web_service_delegated_invoke(invocation)
  71 + end
  72 + api_method = invocation.api_method
  73 + if invocation.api.has_api_method?(api_method.name)
  74 + return_value = api_method.cast_returns(return_value)
  75 + end
  76 + responses << [return_value]
  77 + rescue Exception => e
  78 + responses << { 'faultCode' => 3, 'faultString' => e.message }
  79 + end
  80 + end
  81 + invocation = invocations[0]
  82 + invocation.protocol.encode_response('system.multicall', responses, nil, invocation.protocol_options)
  83 + end
52 84
53   - def web_service_invocation(request)
  85 + def web_service_invocation(request, level = 0)
54 86 public_method_name = request.method_name
55 87 invocation = Invocation.new
56 88 invocation.protocol = request.protocol
@@ -70,6 +102,28 @@ def web_service_invocation(request)
70 102 end
71 103 end
72 104 end
  105 + if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
  106 + if public_method_name == 'multicall' && invocation.service_name == 'system'
  107 + if level > 0
  108 + raise(DispatcherError, "Recursive system.multicall invocations not allowed")
  109 + end
  110 + multicall = request.method_params.dup
  111 + unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
  112 + raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
  113 + end
  114 + multicall = multicall[0]
  115 + return multicall.map do |item|
  116 + raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
  117 + raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
  118 + method_name = item['methodName']
  119 + params = item.has_key?('params') ? item['params'] : []
  120 + multicall_request = request.dup
  121 + multicall_request.method_name = method_name
  122 + multicall_request.method_params = params
  123 + web_service_invocation(multicall_request, level + 1)
  124 + end
  125 + end
  126 + end
73 127 case web_service_dispatching_mode
74 128 when :direct
75 129 invocation.api = self.class.web_service_api
2  actionwebservice/lib/action_web_service/protocol/abstract.rb
@@ -41,7 +41,7 @@ def register_api(api)
41 41
42 42 class Request # :nodoc:
43 43 attr :protocol
44   - attr :method_name
  44 + attr_accessor :method_name
45 45 attr_accessor :method_params
46 46 attr :service_name
47 47 attr_accessor :api
27 actionwebservice/test/abstract_dispatcher.rb
@@ -107,11 +107,15 @@ def do_intercept(name, args)
107 107 class MTAPI < ActionWebService::API::Base
108 108 inflect_names false
109 109 api_method :getCategories, :returns => [[:string]]
  110 + api_method :bool, :returns => [:bool]
  111 + api_method :alwaysFail
110 112 end
111 113
112 114 class BloggerAPI < ActionWebService::API::Base
113 115 inflect_names false
114 116 api_method :getCategories, :returns => [[:string]]
  117 + api_method :str, :expects => [:int], :returns => [:string]
  118 + api_method :alwaysFail
115 119 end
116 120
117 121 class MTService < ActionWebService::Base
@@ -120,6 +124,14 @@ class MTService < ActionWebService::Base
120 124 def getCategories
121 125 ["mtCat1", "mtCat2"]
122 126 end
  127 +
  128 + def bool
  129 + 'y'
  130 + end
  131 +
  132 + def alwaysFail
  133 + raise "MT AlwaysFail"
  134 + end
123 135 end
124 136
125 137 class BloggerService < ActionWebService::Base
@@ -128,6 +140,17 @@ class BloggerService < ActionWebService::Base
128 140 def getCategories
129 141 ["bloggerCat1", "bloggerCat2"]
130 142 end
  143 +
  144 + def str(int)
  145 + unless int.is_a?(Integer)
  146 + raise "Not an integer!"
  147 + end
  148 + 500 + int
  149 + end
  150 +
  151 + def alwaysFail
  152 + raise "Blogger AlwaysFail"
  153 + end
131 154 end
132 155
133 156 class AbstractController < ActionController::Base
@@ -439,8 +462,8 @@ def do_method_call(container, public_method_name, *params)
439 462 public_method_name = real_method_name
440 463 request_env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{real_method_name}"
441 464 end
442   - api = container.web_service_object(service_name.to_sym).class.web_service_api
443   - method = api.public_api_method_instance(real_method_name)
  465 + api = container.web_service_object(service_name.to_sym).class.web_service_api rescue nil
  466 + method = api.public_api_method_instance(real_method_name) rescue nil
444 467 service_name = self.service_name(container)
445 468 end
446 469 protocol.register_api(api)
19 actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
@@ -19,6 +19,25 @@ def test_layered_dispatching
19 19 assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
20 20 end
21 21
  22 + def test_multicall
  23 + response = do_method_call(@layered_controller, 'system.multicall', [
  24 + {'methodName' => 'mt.getCategories'},
  25 + {'methodName' => 'blogger.getCategories'},
  26 + {'methodName' => 'mt.bool'},
  27 + {'methodName' => 'blogger.str', 'params' => ['2000']},
  28 + {'methodName' => 'mt.alwaysFail'},
  29 + {'methodName' => 'blogger.alwaysFail'}
  30 + ])
  31 + assert_equal [
  32 + [["mtCat1", "mtCat2"]],
  33 + [["bloggerCat1", "bloggerCat2"]],
  34 + [true],
  35 + ["2500"],
  36 + {"faultCode" => 3, "faultString" => "MT AlwaysFail"},
  37 + {"faultCode" => 3, "faultString" => "Blogger AlwaysFail"}
  38 + ], response
  39 + end
  40 +
22 41 protected
23 42 def exception_message(xmlrpc_fault_exception)
24 43 xmlrpc_fault_exception.faultString

0 comments on commit 9d79880

Please sign in to comment.
Something went wrong with that request. Please try again.