diff options
Diffstat (limited to 'actionwebservice/lib')
14 files changed, 274 insertions, 333 deletions
diff --git a/actionwebservice/lib/action_web_service.rb b/actionwebservice/lib/action_web_service.rb index a55afc2244..5cf988a0f8 100644 --- a/actionwebservice/lib/action_web_service.rb +++ b/actionwebservice/lib/action_web_service.rb @@ -41,7 +41,7 @@ require 'action_web_service/api' require 'action_web_service/struct' require 'action_web_service/container' require 'action_web_service/protocol' -require 'action_web_service/router' +require 'action_web_service/dispatcher' ActionWebService::Base.class_eval do include ActionWebService::API @@ -55,6 +55,6 @@ ActionController::Base.class_eval do include ActionWebService::Protocol::XmlRpc include ActionWebService::API include ActionWebService::API::ActionController - include ActionWebService::Router::ActionController - include ActionWebService::Router::Wsdl + include ActionWebService::Dispatcher + include ActionWebService::Dispatcher::ActionController end diff --git a/actionwebservice/lib/action_web_service/client.rb b/actionwebservice/lib/action_web_service/client.rb index 77f934882c..2a1e33054d 100644 --- a/actionwebservice/lib/action_web_service/client.rb +++ b/actionwebservice/lib/action_web_service/client.rb @@ -1,3 +1,3 @@ require 'action_web_service/client/base' -require 'action_web_service/client/soap' -require 'action_web_service/client/xmlrpc' +require 'action_web_service/client/soap_client' +require 'action_web_service/client/xmlrpc_client' diff --git a/actionwebservice/lib/action_web_service/client/soap.rb b/actionwebservice/lib/action_web_service/client/soap_client.rb index 3557f88594..3557f88594 100644 --- a/actionwebservice/lib/action_web_service/client/soap.rb +++ b/actionwebservice/lib/action_web_service/client/soap_client.rb diff --git a/actionwebservice/lib/action_web_service/client/xmlrpc.rb b/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb index df51230b81..df51230b81 100644 --- a/actionwebservice/lib/action_web_service/client/xmlrpc.rb +++ b/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb diff --git a/actionwebservice/lib/action_web_service/container.rb b/actionwebservice/lib/action_web_service/container.rb index 6fa14def56..f02717579e 100644 --- a/actionwebservice/lib/action_web_service/container.rb +++ b/actionwebservice/lib/action_web_service/container.rb @@ -5,8 +5,6 @@ module ActionWebService # :nodoc: 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.extend(ClassMethods) base.send(:include, ActionWebService::Container::InstanceMethods) end @@ -82,151 +80,6 @@ module ActionWebService # :nodoc: service = info[:block] service ? instance_eval(&service) : info[:object] end - - private - def dispatch_web_service_request(protocol_request) - case web_service_dispatching_mode - when :direct - dispatch_direct_web_service_request(protocol_request) - when :delegated - dispatch_delegated_web_service_request(protocol_request) - else - raise(ContainerError, "unsupported dispatching mode :#{web_service_dispatching_mode}") - end - end - - def dispatch_direct_web_service_request(protocol_request) - public_method_name = protocol_request.public_method_name - api = self.class.web_service_api - method_name = api.api_method_name(public_method_name) - block = nil - expects = nil - if method_name - signature = api.api_methods[method_name] - expects = signature[:expects] - protocol_request.type = Protocol::CheckedMessage - protocol_request.signature = expects - protocol_request.return_signature = signature[:returns] - else - protocol_request.type = Protocol::UncheckedMessage - system_methods = self.class.read_inheritable_attribute('default_system_methods') || {} - protocol = protocol_request.protocol - block = system_methods[protocol.class] - unless block - method_name = api.default_api_method - unless method_name && respond_to?(method_name) - raise(ContainerError, "no such method ##{public_method_name}") - end - end - end - - @method_params = protocol_request.unmarshal - @params ||= {} - if expects - (1..@method_params.size).each do |i| - i -= 1 - if expects[i].is_a?(Hash) - @params[expects[i].keys.shift.to_s] = @method_params[i] - else - @params["param#{i}"] = @method_params[i] - end - end - end - - if respond_to?(:before_action) - @params['action'] = method_name.to_s - return protocol_request.marshal(nil) if before_action == false - end - - perform_invoke = lambda do - if block - block.call(public_method_name, self.class, *@method_params) - else - send(method_name) - end - end - try_default = true - result = nil - catch(:try_default) do - result = perform_invoke.call - try_default = false - end - if try_default - method_name = api.default_api_method - if method_name - protocol_request.type = Protocol::UncheckedMessage - else - raise(ContainerError, "no such method ##{public_method_name}") - end - result = perform_invoke.call - end - after_action if respond_to?(:after_action) - protocol_request.marshal(result) - end - - def dispatch_delegated_web_service_request(protocol_request) - web_service_name = protocol_request.web_service_name - service = web_service_object(web_service_name) - api = service.class.web_service_api - public_method_name = protocol_request.public_method_name - method_name = api.api_method_name(public_method_name) - - invocation = ActionWebService::Invocation::InvocationRequest.new( - ActionWebService::Invocation::ConcreteInvocation, - public_method_name, - method_name) - - if method_name - protocol_request.type = Protocol::CheckedMessage - signature = api.api_methods[method_name] - protocol_request.signature = signature[:expects] - protocol_request.return_signature = signature[:returns] - invocation.params = protocol_request.unmarshal - else - protocol_request.type = Protocol::UncheckedMessage - invocation.type = ActionWebService::Invocation::VirtualInvocation - system_methods = self.class.read_inheritable_attribute('default_system_methods') || {} - protocol = protocol_request.protocol - block = system_methods[protocol.class] - if block - invocation.block = block - invocation.block_params << service.class - else - method_name = api.default_api_method - if method_name && service.respond_to?(method_name) - invocation.params = protocol_request.unmarshal - invocation.method_name = method_name.to_sym - else - raise(ContainerError, "no such method /#{web_service_name}##{public_method_name}") - end - end - end - - canceled_reason = nil - canceled_block = lambda{|r| canceled_reason = r} - perform_invoke = lambda do - service.perform_invocation(invocation, &canceled_block) - end - try_default = true - result = nil - catch(:try_default) do - result = perform_invoke.call - try_default = false - end - if try_default - method_name = api.default_api_method - if method_name - protocol_request.type = Protocol::UncheckedMessage - invocation.params = protocol_request.unmarshal - invocation.method_name = method_name.to_sym - invocation.type = ActionWebService::Invocation::UnpublishedConcreteInvocation - else - raise(ContainerError, "no such method /#{web_service_name}##{public_method_name}") - end - result = perform_invoke.call - end - protocol_request.marshal(result) - end end end end diff --git a/actionwebservice/lib/action_web_service/dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher.rb new file mode 100644 index 0000000000..601d831373 --- /dev/null +++ b/actionwebservice/lib/action_web_service/dispatcher.rb @@ -0,0 +1,2 @@ +require 'action_web_service/dispatcher/abstract' +require 'action_web_service/dispatcher/action_controller_dispatcher' 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 diff --git a/actionwebservice/lib/action_web_service/router/wsdl.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb index 6963334818..68c0f4ffb3 100644 --- a/actionwebservice/lib/action_web_service/router/wsdl.rb +++ b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb @@ -1,23 +1,114 @@ module ActionWebService # :nodoc: - module Router # :nodoc: - module Wsdl # :nodoc: + module Dispatcher # :nodoc: + module ActionController # :nodoc: def self.append_features(base) # :nodoc: - base.class_eval do + super + base.class_eval do class << self - alias_method :inherited_without_wsdl, :inherited + alias_method :inherited_without_action_controller, :inherited + end + end + base.class_eval do + alias_method :before_direct_invoke_without_action_controller, :before_direct_invoke + alias_method :after_direct_invoke_without_action_controller, :after_direct_invoke + end + base.add_web_service_api_callback do |klass, api| + if klass.web_service_dispatching_mode == :direct + klass.class_eval <<-EOS + def api + controller_dispatch_web_service_request + end + EOS + end + end + base.add_web_service_definition_callback do |klass, name, info| + if klass.web_service_dispatching_mode == :delegated + klass.class_eval <<-EOS + def #{name} + controller_dispatch_web_service_request + end + EOS end end base.extend(ClassMethods) + base.send(:include, ActionWebService::Dispatcher::ActionController::Invocation) end - module ClassMethods + module ClassMethods # :nodoc: def inherited(child) - inherited_without_wsdl(child) - child.send(:include, ActionWebService::Router::Wsdl::InstanceMethods) + inherited_without_action_controller(child) + child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlGeneration) end end - module InstanceMethods # :nodoc: + module Invocation # :nodoc: + private + def controller_dispatch_web_service_request + request, response, elapsed, exception = dispatch_web_service_request(@request) + if response + begin + log_request(request) + log_error(exception) if exception && logger + log_response(response, elapsed) + response_options = { :type => response.content_type, :disposition => 'inline' } + send_data(response.raw_body, response_options) + rescue Exception => e + log_error(e) unless logger.nil? + render_text("Internal protocol error", "500 Internal Server Error") + end + else + logger.error("No response available") unless logger.nil? + render_text("Internal protocol error", "500 Internal Server Error") + end + end + + def before_direct_invoke(request) + before_direct_invoke_without_action_controller(request) + @params ||= {} + signature = request.signature + if signature && (expects = request.signature[:expects]) + (0..(@method_params.size-1)).each do |i| + if expects[i].is_a?(Hash) + @params[expects[i].keys[0].to_s] = @method_params[i] + else + @params['param%d' % i] = @method_params[i] + end + end + end + @params['action'] = request.method_name.to_s + @session ||= {} + @assigns ||= {} + return nil if before_action == false + true + end + + def after_direct_invoke(request) + after_direct_invoke_without_action_controller(request) + after_action + end + + def log_request(request) + unless logger.nil? || request.nil? + logger.debug("\nWeb Service Request:") + indented = request.raw_body.split(/\n/).map{|x| " #{x}"}.join("\n") + logger.debug(indented) + end + end + + def log_response(response, elapsed) + unless logger.nil? || response.nil? + logger.debug("\nWeb Service Response (%f):" % elapsed) + indented = response.raw_body.split(/\n/).map{|x| " #{x}"}.join("\n") + logger.debug(indented) + end + end + + unless method_defined?(:logger) + def logger; @logger; end + end + end + + module WsdlGeneration # :nodoc: XsdNs = 'http://www.w3.org/2001/XMLSchema' WsdlNs = 'http://schemas.xmlsoap.org/wsdl/' SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/' @@ -28,7 +119,7 @@ module ActionWebService # :nodoc: case @request.method when :get begin - host_name = @request.env['HTTP_HOST']||@request.env['SERVER_NAME'] + host_name = @request.env['HTTP_HOST'] || @request.env['SERVER_NAME'] uri = "http://#{host_name}/#{controller_name}/" soap_action_base = "/#{controller_name}" xml = to_wsdl(self, uri, soap_action_base) diff --git a/actionwebservice/lib/action_web_service/invocation.rb b/actionwebservice/lib/action_web_service/invocation.rb index 64d3e8d524..62f38b8ecd 100644 --- a/actionwebservice/lib/action_web_service/invocation.rb +++ b/actionwebservice/lib/action_web_service/invocation.rb @@ -1,9 +1,5 @@ module ActionWebService # :nodoc: module Invocation # :nodoc: - ConcreteInvocation = :concrete - VirtualInvocation = :virtual - UnpublishedConcreteInvocation = :unpublished_concrete - class InvocationError < ActionWebService::ActionWebServiceError # :nodoc: end @@ -137,31 +133,15 @@ module ActionWebService # :nodoc: end end - def perform_invocation_with_interception(invocation, &block) - return if before_invocation(invocation.method_name, invocation.params, &block) == false - result = perform_invocation_without_interception(invocation) - after_invocation(invocation.method_name, invocation.params, result) - result + def perform_invocation_with_interception(method_name, params, &block) + return if before_invocation(method_name, params, &block) == false + return_value = perform_invocation_without_interception(method_name, params) + after_invocation(method_name, params, return_value) + return_value end - def perform_invocation(invocation) - if invocation.concrete? - unless self.respond_to?(invocation.method_name) && \ - self.class.web_service_api.has_api_method?(invocation.method_name) - raise InvocationError, "no such web service method '#{invocation.method_name}' on service object" - end - end - params = invocation.params - if invocation.concrete? || invocation.unpublished_concrete? - self.send(invocation.method_name, *params) - else - if invocation.block - params = invocation.block_params + params - invocation.block.call(invocation.public_method_name, *params) - else - self.send(invocation.method_name, *params) - end - end + def perform_invocation(method_name, params) + send(method_name, *params) end def before_invocation(name, args, &block) @@ -221,32 +201,5 @@ module ActionWebService # :nodoc: end end end - - class InvocationRequest # :nodoc: - attr_accessor :type - attr :public_method_name - attr_accessor :method_name - attr_accessor :params - attr_accessor :block - attr :block_params - - def initialize(type, public_method_name, method_name, params=nil) - @type = type - @public_method_name = public_method_name - @method_name = method_name - @params = params || [] - @block = nil - @block_params = [] - end - - def concrete? - @type == ConcreteInvocation ? true : false - end - - def unpublished_concrete? - @type == UnpublishedConcreteInvocation ? true : false - end - end - end end diff --git a/actionwebservice/lib/action_web_service/protocol.rb b/actionwebservice/lib/action_web_service/protocol.rb index 733787136a..b15e850676 100644 --- a/actionwebservice/lib/action_web_service/protocol.rb +++ b/actionwebservice/lib/action_web_service/protocol.rb @@ -1,4 +1,4 @@ require 'action_web_service/protocol/abstract' require 'action_web_service/protocol/registry' -require 'action_web_service/protocol/soap' -require 'action_web_service/protocol/xmlrpc' +require 'action_web_service/protocol/soap_protocol' +require 'action_web_service/protocol/xmlrpc_protocol' diff --git a/actionwebservice/lib/action_web_service/protocol/soap.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb index 3c527fea93..3c527fea93 100644 --- a/actionwebservice/lib/action_web_service/protocol/soap.rb +++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb diff --git a/actionwebservice/lib/action_web_service/protocol/xmlrpc.rb b/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb index 414bcfdbf7..1addccba56 100644 --- a/actionwebservice/lib/action_web_service/protocol/xmlrpc.rb +++ b/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb @@ -54,7 +54,6 @@ module ActionWebService # :nodoc: def initialize(container_class) super(container_class) - container_class.write_inheritable_hash('default_system_methods', XmlRpcProtocol => method(:xmlrpc_default_system_handler)) end def unmarshal_request(protocol_request) @@ -153,20 +152,6 @@ module ActionWebService # :nodoc: end private - def xmlrpc_default_system_handler(name, service_class, *args) - case name - when 'system.listMethods' - methods = [] - api = service_class.web_service_api - api.api_methods.each do |name, info| - methods << api.public_api_method_name(name) - end - methods.sort - else - throw :try_default - end - end - def check_array_types(signature) signature.map{|x| x.is_a?(Array) ? Array : x} end diff --git a/actionwebservice/lib/action_web_service/router.rb b/actionwebservice/lib/action_web_service/router.rb deleted file mode 100644 index 4bfb0bc8b7..0000000000 --- a/actionwebservice/lib/action_web_service/router.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'action_web_service/router/action_controller' -require 'action_web_service/router/wsdl' diff --git a/actionwebservice/lib/action_web_service/router/action_controller.rb b/actionwebservice/lib/action_web_service/router/action_controller.rb deleted file mode 100644 index 591fe4e232..0000000000 --- a/actionwebservice/lib/action_web_service/router/action_controller.rb +++ /dev/null @@ -1,99 +0,0 @@ -module ActionWebService # :nodoc: - module Router # :nodoc: - module ActionController # :nodoc: - def self.append_features(base) # :nodoc: - base.add_web_service_api_callback do |container_class, api| - if container_class.web_service_dispatching_mode == :direct - container_class.class_eval <<-EOS - def api - process_action_service_request - end - EOS - end - end - base.add_web_service_definition_callback do |klass, name, info| - if klass.web_service_dispatching_mode == :delegated - klass.class_eval <<-EOS - def #{name} - process_action_service_request - end - EOS - end - end - base.send(:include, ActionWebService::Router::ActionController::InstanceMethods) - end - - module InstanceMethods # :nodoc: - private - def process_action_service_request - protocol_request = nil - begin - begin - protocol_request = probe_request_protocol(self.request) - rescue Exception => e - unless logger.nil? - logger.error "Invalid request: #{e.message}" - logger.error self.request.raw_post - end - raise - end - if protocol_request - log_request(protocol_request) - protocol_response = dispatch_web_service_request(protocol_request) - log_response(protocol_response) - response_options = { - :type => protocol_response.content_type, - :disposition => 'inline' - } - send_data(protocol_response.raw_body, response_options) - else - logger.fatal "Invalid Action Web Service service or method requested" unless logger.nil? - render_text 'Internal protocol error', "500 Invalid service/method" - end - rescue Exception => e - log_error e unless logger.nil? - exc_response = nil - case web_service_dispatching_mode - when :direct - if self.class.web_service_exception_reporting - exc_response = protocol_request.protocol.marshal_exception(e) - end - when :delegated - web_service = web_service_object(protocol_request.service_name) rescue nil - if web_service && web_service.class.web_service_exception_reporting - exc_response = protocol_request.protocol.marshal_exception(e) rescue nil - end - end - if exc_response - response_options = { - :type => exc_response.content_type, - :disposition => 'inline' - } - log_response exc_response - send_data(exc_response.raw_body, response_options) - else - render_text 'Internal protocol error', "500 #{e.message}" - end - end - end - - def log_request(protocol_request) - unless logger.nil? - web_service_name = protocol_request.web_service_name - method_name = protocol_request.public_method_name - logger.info "\nProcessing Action Web Service Request: #{web_service_name}##{method_name}" - logger.info "Raw Request Body:" - logger.info protocol_request.raw_body - end - end - - def log_response(protocol_response) - unless logger.nil? - logger.info "\nRaw Response Body:" - logger.info protocol_response.raw_body - end - end - end - end - end -end |