mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
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
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user