From 418d487020d24e69b528fdbedfecb20a87f99fcb Mon Sep 17 00:00:00 2001 From: Leon Breedt Date: Sat, 19 Feb 2005 08:29:42 +0000 Subject: refactoring: * move dispatching out of the Container into Dispatcher, it makes more sense for Container to only contain the list of web services defined in it. * collapse Wsdl and ActionController "routers" into an ActionController-specific module, no advantage to having them seperate as they were quite tightly coupled. rename to Dispatcher, to avoi confusion with Routing. * add a "_thing" suffix to concept-specific filenames. this is so that we don't end up with many soap.rb files, for example. * remove "virtual invocation" support. adds complexity, and it doesn't seem to add any value. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@679 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- .../lib/action_web_service/dispatcher/abstract.rb | 158 +++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 actionwebservice/lib/action_web_service/dispatcher/abstract.rb (limited to 'actionwebservice/lib/action_web_service/dispatcher/abstract.rb') diff --git a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb new file mode 100644 index 0000000000..e03446924a --- /dev/null +++ b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb @@ -0,0 +1,158 @@ +require 'benchmark' + +module ActionWebService # :nodoc: + module Dispatcher # :nodoc: + class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc: + end + + def self.append_features(base) # :nodoc: + super + base.class_inheritable_option(:web_service_dispatching_mode, :direct) + base.class_inheritable_option(:web_service_exception_reporting, true) + base.send(:include, ActionWebService::Dispatcher::InstanceMethods) + end + + module InstanceMethods # :nodoc: + private + def dispatch_web_service_request(action_pack_request) + protocol_request = protocol_response = nil + bm = Benchmark.measure do + protocol_request = probe_request_protocol(action_pack_request) + protocol_response = dispatch_protocol_request(protocol_request) + end + [protocol_request, protocol_response, bm.real, nil] + rescue Exception => e + protocol_response = prepare_exception_response(protocol_request, e) + [protocol_request, prepare_exception_response(protocol_request, e), nil, e] + end + + def dispatch_protocol_request(protocol_request) + case web_service_dispatching_mode + when :direct + dispatch_direct_request(protocol_request) + when :delegated + dispatch_delegated_request(protocol_request) + else + raise(ContainerError, "unsupported dispatching mode :#{web_service_dispatching_mode}") + end + end + + def dispatch_direct_request(protocol_request) + request = prepare_dispatch_request(protocol_request) + return_value = direct_invoke(request) + protocol_request.marshal(return_value) + end + + def dispatch_delegated_request(protocol_request) + request = prepare_dispatch_request(protocol_request) + return_value = delegated_invoke(request) + protocol_request.marshal(return_value) + end + + def direct_invoke(request) + return nil unless before_direct_invoke(request) + return_value = send(request.method_name) + after_direct_invoke(request) + return_value + end + + def before_direct_invoke(request) + @method_params = request.params + end + + def after_direct_invoke(request) + end + + def delegated_invoke(request) + cancellation_reason = nil + web_service = request.web_service + return_value = web_service.perform_invocation(request.method_name, request.params) do |x| + cancellation_reason = x + end + if cancellation_reason + raise(DispatcherError, "request canceled: #{cancellation_reason}") + end + return_value + end + + def fallback_invoke(dispatch_request) + raise NotImplementedError + end + + def prepare_dispatch_request(protocol_request) + api = method_name = web_service_name = web_service = params = nil + public_method_name = protocol_request.public_method_name + case web_service_dispatching_mode + when :direct + api = self.class.web_service_api + when :delegated + web_service_name = protocol_request.web_service_name + web_service = web_service_object(web_service_name) + api = web_service.class.web_service_api + end + method_name = api.api_method_name(public_method_name) + signature = nil + if method_name + signature = api.api_methods[method_name] + protocol_request.type = Protocol::CheckedMessage + protocol_request.signature = signature[:expects] + protocol_request.return_signature = signature[:returns] + else + method_name = api.default_api_method + if method_name + protocol_request.type = Protocol::UncheckedMessage + else + raise(DispatcherError, "no such method #{web_service_name}##{public_method_name}") + end + end + params = protocol_request.unmarshal + DispatchRequest.new( + :api => api, + :public_method_name => public_method_name, + :method_name => method_name, + :signature => signature, + :web_service_name => web_service_name, + :web_service => web_service, + :params => params) + end + + def prepare_exception_response(protocol_request, exception) + if protocol_request && exception + case web_service_dispatching_mode + when :direct + if web_service_exception_reporting + return protocol_request.protocol.marshal_exception(exception) + else + raise exception + end + when :delegated + web_service = web_service_object(protocol_request.web_service_name) + if web_service && web_service.class.web_service_exception_reporting + return protocol_request.protocol.marshal_exception(exception) + else + raise exception + end + end + else + protocol_request.protocol.marshal_exception(RuntimeError.new("missing protocol request or exception")) + end + rescue Exception + nil + end + + class DispatchRequest + attr :api + attr :public_method_name + attr :method_name + attr :signature + attr :web_service_name + attr :web_service + attr :params + + def initialize(values={}) + values.each{|k,v| instance_variable_set("@#{k.to_s}", v)} + end + end + end + end +end -- cgit v1.2.3