Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 800

Show
Ignore:
Timestamp:
02/25/05 23:39:39 (4 years ago)
Author:
bitserf
Message:

merged the changes for the upcoming 0.6.0:

seperate out protocol marshaling into a small 'ws' library in vendor, so that
AWS itself only does integration with ActionPack, and so we can keep protocol
specific code in AWS proper to a minimum. refactor unit tests to get 95%
code coverage (for a baseline).

be far more relaxed about the types given to us by the remote side, don't do
any poor man's type checking, just try to cast and marshal to the correct types if
possible, and if not, return what they gave us anyway. this should make interoperating
with fuzzy XML-RPC clients easier.

if exception reporting is turned on, do best-effort error responses, so that
we can avoid "Internal protocol error" with no details if there is a bug in
AWS itself.

also perform extensive cleanups on AWS proper.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionwebservice/ChangeLog

    r796 r800  
     1*0.6.0* (Unreleased) 
     2 
     3        * lib/*, test/*: refactored SOAP and XML-RPC protocol specifics into 
     4          a small seperate library named 'ws', and drop it in vendor. be 
     5          more relaxed about the type of received parameters, perform casting 
     6          for XML-RPC if possible, but fallback to the received parameters. 
     7          performed extensive cleanup of the way we use SOAP, so that marshaling 
     8          of custom and array types should somewhat faster. 
     9 
    110*0.5.0* (24th February, 2005) 
    211 
  • trunk/actionwebservice/lib/action_web_service.rb

    r679 r800  
    3333end 
    3434 
    35 $:.unshift(File.dirname(__FILE__)) 
     35$:.unshift(File.dirname(__FILE__) + "/action_web_service/vendor/") 
     36 
     37require 'action_web_service/support/class_inheritable_options' 
     38require 'action_web_service/vendor/ws' 
    3639 
    3740require 'action_web_service/base' 
     
    4245require 'action_web_service/container' 
    4346require 'action_web_service/protocol' 
     47require 'action_web_service/struct' 
    4448require 'action_web_service/dispatcher' 
    4549 
    4650ActionWebService::Base.class_eval do 
    47   include ActionWebService::API 
     51  include ActionWebService::Container::Direct 
    4852  include ActionWebService::Invocation 
    4953end 
    5054 
    5155ActionController::Base.class_eval do 
    52   include ActionWebService::Container 
    53   include ActionWebService::Protocol::Registry 
     56  include ActionWebService::Protocol::Discovery 
    5457  include ActionWebService::Protocol::Soap 
    5558  include ActionWebService::Protocol::XmlRpc 
    56   include ActionWebService::API 
    57   include ActionWebService::API::ActionController 
     59  include ActionWebService::Container::Direct 
     60  include ActionWebService::Container::Delegated 
     61  include ActionWebService::Container::ActionController 
    5862  include ActionWebService::Dispatcher 
    5963  include ActionWebService::Dispatcher::ActionController 
  • trunk/actionwebservice/lib/action_web_service/api.rb

    r672 r800  
    1 require 'action_web_service/api/abstract' 
    2 require 'action_web_service/api/action_controller' 
     1require 'action_web_service/api/base' 
  • trunk/actionwebservice/lib/action_web_service/api/base.rb

    r672 r800  
    11module ActionWebService # :nodoc: 
    22  module API # :nodoc: 
    3     class APIError < ActionWebService::ActionWebServiceError # :nodoc: 
    4     end 
    5  
    6     def self.append_features(base) # :nodoc: 
    7       super 
    8       base.extend(ClassMethods) 
    9     end 
    10  
    11     module ClassMethods 
    12       # Attaches ActionWebService API +definition+ to the calling class. 
    13       # 
    14       # Action Controllers can have a default associated API, removing the need 
    15       # to call this method if you follow the Action Web Service naming conventions. 
    16       # 
    17       # A controller with a class name of GoogleSearchController will 
    18       # implicitly load <tt>app/apis/google_search_api.rb</tt>, and expect the 
    19       # API definition class to be named <tt>GoogleSearchAPI</tt> or 
    20       # <tt>GoogleSearchApi</tt>. 
    21       # 
    22       # ==== Service class example 
    23       # 
    24       #   class MyService < ActionWebService::Base 
    25       #     web_service_api MyAPI 
    26       #   end 
    27       # 
    28       #   class MyAPI < ActionWebService::API::Base 
    29       #     ... 
    30       #   end 
    31       # 
    32       # ==== Controller class example 
    33       # 
    34       #   class MyController < ActionController::Base 
    35       #     web_service_api MyAPI 
    36       #   end 
    37       # 
    38       #   class MyAPI < ActionWebService::API::Base 
    39       #     ... 
    40       #   end 
    41       def web_service_api(definition=nil) 
    42         if definition.nil? 
    43           read_inheritable_attribute("web_service_api") 
    44         else 
    45           if definition.is_a?(Symbol) 
    46             raise(APIError, "symbols can only be used for #web_service_api inside of a controller") 
    47           end 
    48           unless definition.respond_to?(:ancestors) && definition.ancestors.include?(Base) 
    49             raise(APIError, "#{definition.to_s} is not a valid API definition") 
    50           end 
    51           write_inheritable_attribute("web_service_api", definition) 
    52           call_web_service_api_callbacks(self, definition) 
    53         end 
    54       end 
    55  
    56       def add_web_service_api_callback(&block) # :nodoc: 
    57         write_inheritable_array("web_service_api_callbacks", [block]) 
    58       end 
    59  
    60       private 
    61         def call_web_service_api_callbacks(container_class, definition) 
    62           (read_inheritable_attribute("web_service_api_callbacks") || []).each do |block| 
    63             block.call(container_class, definition) 
    64           end 
    65         end 
    66     end 
    67  
    683    # A web service API class specifies the methods that will be available for 
    694    # invocation for an API. It also contains metadata such as the method type 
     
    8823       
    8924      class << self 
    90         include ActionWebService::Signature 
    91  
    9225        # API methods have a +name+, which must be the Ruby method name to use when 
    9326        # performing the invocation on the web service object. 
     
    12659            returns = options[:returns] 
    12760          end 
    128           expects = canonical_signature(expects) if expects 
    129           returns = canonical_signature(returns) if returns 
     61          expects = canonical_signature(expects) 
     62          returns = canonical_signature(returns) 
    13063          if expects 
    13164            expects.each do |param| 
    132               klass = signature_parameter_class(param) 
     65              klass = WS::BaseTypes.canonical_param_type_class(param) 
    13366              klass = klass[0] if klass.is_a?(Array) 
    13467              if klass.ancestors.include?(ActiveRecord::Base) 
     
    187120          end 
    188121 
     122          def canonical_signature(signature) 
     123            return nil if signature.nil? 
     124            signature.map{|spec| WS::BaseTypes.canonical_param_type_spec(spec)} 
     125          end 
    189126      end 
    190127    end 
  • trunk/actionwebservice/lib/action_web_service/base.rb

    r672 r800  
    1 require 'action_web_service/support/class_inheritable_options' 
    2 require 'action_web_service/support/signature' 
    3  
    41module ActionWebService # :nodoc: 
    52  class ActionWebServiceError < StandardError # :nodoc: 
  • trunk/actionwebservice/lib/action_web_service/client/base.rb

    r680 r800  
    1313        call_name = method_name(name) 
    1414        return super(name, *args) if call_name.nil? 
    15         perform_invocation(call_name, args) 
     15        self.perform_invocation(call_name, args) 
    1616      end 
    17  
    18       protected 
    19         def perform_invocation(method_name, args) # :nodoc: 
    20           raise NotImplementedError, "use a protocol-specific client" 
    21         end 
    2217 
    2318      private 
     
    2722          elsif @api.has_public_api_method?(name.to_s) 
    2823            @api.api_method_name(name.to_s).to_s 
    29           else 
    30             nil 
    3124          end 
    32         end 
    33  
    34         def lookup_class(klass) 
    35           klass.is_a?(Hash) ?  klass.values[0] : klass 
    3625        end 
    3726    end 
  • trunk/actionwebservice/lib/action_web_service/client/soap_client.rb

    r680 r800  
    2929      def initialize(api, endpoint_uri, options={}) 
    3030        super(api, endpoint_uri) 
    31         @service_name = options[:service_name] || 'ActionWebService' 
    32         @namespace = "urn:#{@service_name}"  
    33         @mapper = ActionWebService::Protocol::Soap::SoapMapper.new(@namespace) 
    34         @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new(@mapper) 
     31        @service_name = options[:service_name] 
     32        @namespace = @service_name ? '' : "urn:#{@service_name}" 
     33        @marshaler = WS::Marshaling::SoapMarshaler.new 
     34        @encoder = WS::Encoding::SoapRpcEncoding.new 
    3535        @soap_action_base = options[:soap_action_base] 
    3636        @soap_action_base ||= URI.parse(endpoint_uri).path 
     
    4949      private 
    5050        def create_soap_rpc_driver(api, endpoint_uri) 
    51           @mapper.map_api(api) 
     51          register_api(@marshaler, api) 
    5252          driver = SoapDriver.new(endpoint_uri, nil) 
    53           driver.mapping_registry = @mapper.registry 
     53          driver.mapping_registry = @marshaler.registry 
    5454          api.api_methods.each do |name, info| 
    5555            public_name = api.public_api_method_name(name) 
     
    5959            returns = info[:returns] 
    6060            param_def = [] 
    61             i = 1 
     61            i = 0 
    6262            if expects 
    63               expects.each do |klass| 
    64                 param_name = klass.is_a?(Hash) ? klass.keys[0] : "param#{i}" 
    65                 param_klass = lookup_class(klass) 
    66                 mapping = @mapper.lookup(param_klass) 
    67                 param_def << ['in', param_name, mapping.registry_mapping] 
     63              expects.each do |spec| 
     64                param_name = spec.is_a?(Hash) ? spec.keys[0].to_s : "param#{i}" 
     65                type_binding = @marshaler.register_type(spec) 
     66                param_def << ['in', param_name, type_binding.mapping] 
    6867                i += 1 
    6968              end 
    7069            end 
    7170            if returns 
    72               mapping = @mapper.lookup(lookup_class(returns[0])
    73               param_def << ['retval', 'return', mapping.registry_mapping] 
     71              type_binding = @marshaler.register_type(returns[0]
     72              param_def << ['retval', 'return', type_binding.mapping] 
    7473            end 
    7574            driver.add_method(qname, action, name.to_s, param_def) 
    7675          end 
    7776          driver 
     77        end 
     78 
     79        def register_api(marshaler, api) 
     80          type_bindings = [] 
     81          api.api_methods.each do |name, info| 
     82            expects, returns = info[:expects], info[:returns] 
     83            if expects 
     84              expects.each{|type| type_bindings << marshaler.register_type(type)} 
     85            end 
     86            if returns 
     87              returns.each{|type| type_bindings << marshaler.register_type(type)} 
     88            end 
     89          end 
     90          type_bindings 
    7891        end 
    7992 
  • trunk/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb

    r680 r800  
    3232        @handler_name = options[:handler_name] 
    3333        @client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout]) 
     34        @marshaler = WS::Marshaling::XmlRpcMarshaler.new 
    3435      end 
    3536 
     
    4445        def transform_outgoing_method_params(method_name, params) 
    4546          info = @api.api_methods[method_name.to_sym] 
    46           signature = info[:expects] 
    47           signature_length = signature.nil?? 0 : signature.length 
    48           if signature_length != params.length 
    49             raise(ProtocolError, "API declares #{public_name(method_name)} to accept " + 
    50                                  "#{signature_length} parameters, but #{params.length} parameters " +  
    51                                  "were supplied") 
     47          expects = info[:expects] 
     48          expects_length = expects.nil?? 0 : expects.length 
     49          if expects_length != params.length 
     50            raise(ClientError, "API declares #{public_name(method_name)} to accept " + 
     51                               "#{expects_length} parameters, but #{params.length} parameters " +  
     52                               "were supplied") 
    5253          end 
    53           if signature_length > 0 
    54             signature = Protocol::XmlRpc::XmlRpcProtocol.transform_array_types(signature) 
    55             (1..signature.size).each do |i| 
    56               i -= 1 
    57               params[i] = Protocol::XmlRpc::XmlRpcProtocol.ruby_to_xmlrpc(params[i], lookup_class(signature[i])) 
     54          params = params.dup 
     55          if expects_length > 0 
     56            i = 0 
     57            expects.each do |spec| 
     58              type_binding = @marshaler.register_type(spec) 
     59              info = WS::ParamInfo.create(spec, i, type_binding) 
     60              params[i] = @marshaler.marshal(WS::Param.new(params[i], info)) 
     61              i += 1 
    5862            end 
    5963          end 
     
    6367        def transform_return_value(method_name, return_value) 
    6468          info = @api.api_methods[method_name.to_sym] 
    65           return true unless signature = info[:returns] 
    66           param_klass = lookup_class(signature[0]) 
    67           signature = Protocol::XmlRpc::XmlRpcProtocol.transform_array_types([param_klass]) 
    68           Protocol::XmlRpc::XmlRpcProtocol.xmlrpc_to_ruby(return_value, signature[0]) 
     69          return true unless returns = info[:returns] 
     70          type_binding = @marshaler.register_type(returns[0]) 
     71          info = WS::ParamInfo.create(returns[0], 0, type_binding) 
     72          info.name = 'return' 
     73          @marshaler.transform_inbound(WS::Param.new(return_value, info)) 
    6974        end 
    7075 
  • trunk/actionwebservice/lib/action_web_service/container.rb

    r679 r800  
    1 module ActionWebService # :nodoc: 
    2   module Container # :nodoc: 
    3     class ContainerError < ActionWebService::ActionWebServiceError # :nodoc: 
    4     end 
    5  
    6     def self.append_features(base) # :nodoc: 
    7       super 
    8       base.extend(ClassMethods) 
    9       base.send(:include, ActionWebService::Container::InstanceMethods) 
    10     end 
    11  
    12     module ClassMethods 
    13       # Declares a web service that will provides access to the API of the given 
    14       # +object+. +object+ must be an ActionWebService::Base derivative. 
    15       # 
    16       # Web service object creation can either be _immediate_, where the object 
    17       # instance is given at class definition time, or _deferred_, where 
    18       # object instantiation is delayed until request time. 
    19       # 
    20       # ==== Immediate web service object example 
    21       # 
    22       #   class ApiController < ApplicationController 
    23       #     web_service_dispatching_mode :delegated 
    24       # 
    25       #     web_service :person, PersonService.new 
    26       #   end 
    27       # 
    28       # For deferred instantiation, a block should be given instead of an 
    29       # object instance. This block will be executed in controller instance 
    30       # context, so it can rely on controller instance variables being present. 
    31       # 
    32       # ==== Deferred web service object example 
    33       # 
    34       #   class ApiController < ApplicationController 
    35       #     web_service_dispatching_mode :delegated 
    36       # 
    37       #     web_service(:person) { PersonService.new(@request.env) } 
    38       #   end 
    39       def web_service(name, object=nil, &block) 
    40         if (object && block_given?) || (object.nil? && block.nil?) 
    41           raise(ContainerError, "either service, or a block must be given") 
    42         end 
    43         name = name.to_sym 
    44         if block_given? 
    45           info = { name => { :block => block } } 
    46         else 
    47           info = { name => { :object => object } } 
    48         end 
    49         write_inheritable_hash("web_services", info) 
    50         call_web_service_definition_callbacks(self, name, info) 
    51       end 
    52  
    53       # Whether this service contains a service with the given +name+ 
    54       def has_web_service?(name) 
    55         web_services.has_key?(name.to_sym) 
    56       end 
    57  
    58       def web_services # :nodoc: 
    59         read_inheritable_attribute("web_services") || {} 
    60       end 
    61  
    62       def add_web_service_definition_callback(&block) # :nodoc: 
    63         write_inheritable_array("web_service_definition_callbacks", [block]) 
    64       end 
    65  
    66       private 
    67         def call_web_service_definition_callbacks(container_class, web_service_name, service_info) 
    68           (read_inheritable_attribute("web_service_definition_callbacks") || []).each do |block| 
    69             block.call(container_class, web_service_name, service_info) 
    70           end 
    71         end 
    72     end 
    73  
    74     module InstanceMethods # :nodoc: 
    75       def web_service_object(web_service_name) 
    76         info = self.class.web_services[web_service_name.to_sym] 
    77         unless info 
    78           raise(ContainerError, "no such web service '#{web_service_name}'") 
    79         end 
    80         service = info[:block] 
    81         service ? instance_eval(&service) : info[:object] 
    82       end 
    83     end 
    84   end 
    85 end 
     1require 'action_web_service/container/direct_container' 
     2require 'action_web_service/container/delegated_container' 
     3require 'action_web_service/container/action_controller_container' 
  • trunk/actionwebservice/lib/action_web_service/container/action_controller_container.rb

    r672 r800  
    11module ActionWebService # :nodoc: 
    2   module API # :nodoc: 
     2  module Container # :nodoc: 
    33    module ActionController # :nodoc: 
    44      def self.append_features(base) # :nodoc: 
     
    3737            class_eval do 
    3838              define_method(name) do 
    39                 probe_protocol_client(api_klass, protocol, endpoint_uri, options) 
     39                create_web_service_client(api_klass, protocol, endpoint_uri, options) 
    4040              end 
    4141              protected name 
  • trunk/actionwebservice/lib/action_web_service/dispatcher/abstract.rb

    r708 r800  
    1515    module InstanceMethods # :nodoc: 
    1616      private 
    17         def dispatch_web_service_request(action_pack_request) 
    18           protocol_request = protocol_response = nil 
    19           bm = Benchmark.measure do 
    20             protocol_request = probe_request_protocol(action_pack_request) 
    21             protocol_response = dispatch_protocol_request(protocol_request) 
     17        def invoke_web_service_request(protocol_request) 
     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 
     23            web_service_delegated_invoke(invocation) 
    2224          end 
    23           [protocol_request, protocol_response, bm.real, nil] 
    24         rescue Exception => e 
    25           protocol_response = prepare_exception_response(protocol_request, e)  
    26           [protocol_request, prepare_exception_response(protocol_request, e), nil, e] 
    2725        end 
    2826       
    29         def dispatch_protocol_request(protocol_request) 
    30           case web_service_dispatching_mode 
    31           when :direct 
    32             dispatch_direct_request(protocol_request) 
    33           when :delegated 
    34             dispatch_delegated_request(protocol_request) 
    35           else 
    36             raise(ContainerError, "unsupported dispatching mode :#{web_service_dispatching_mode}") 
    37           end 
     27        def web_service_direct_invoke(invocation) 
     28          @method_params = invocation.method_ordered_params 
     29          return_value = self.__send__(invocation.api_method_name) 
     30          returns = invocation.returns ? invocation.returns[0] : nil 
     31          invocation.protocol.marshal_response(invocation.public_method_name, return_value, returns) 
    3832        end 
    3933 
    40         def dispatch_direct_request(protocol_request) 
    41           request = prepare_dispatch_request(protocol_request) 
    42           return_value = direct_invoke(request) 
    43           protocol_request.marshal(return_value) 
    44         end 
    45  
    46         def dispatch_delegated_request(protocol_request) 
    47           request = prepare_dispatch_request(protocol_request) 
    48           return_value = delegated_invoke(request) 
    49           protocol_request.marshal(return_value) 
    50         end 
    51  
    52         def direct_invoke(request) 
    53           return nil unless before_direct_invoke(request) 
    54           return_value = send(request.method_name) 
    55           after_direct_invoke(request) 
    56           return_value 
    57         end 
    58  
    59         def before_direct_invoke(request) 
    60           @method_params = request.params 
    61         end 
    62  
    63         def after_direct_invoke(request) 
    64         end 
    65  
    66         def delegated_invoke(request) 
     34        def web_service_delegated_invoke(invocation) 
    6735          cancellation_reason = nil 
    68           web_service = request.web_service 
    69           return_value = web_service.perform_invocation(request.method_name, request.params) do |x| 
     36          return_value = invocation.service.perform_invocation(invocation.api_method_name, invocation.method_ordered_params) do |x| 
    7037            cancellation_reason = x 
    7138          end 
     
    7340            raise(DispatcherError, "request canceled: #{cancellation_reason}") 
    7441          end 
    75           return_value 
     42          returns = invocation.returns ? invocation.returns[0] : nil 
     43          invocation.protocol.marshal_response(invocation.public_method_name, return_value, returns) 
    7644        end 
    7745 
    78         def prepare_dispatch_request(protocol_request) 
    79           api = method_name = web_service_name = web_service = params = nil 
    80           public_method_name = protocol_request.public_method_name 
     46        def web_service_invocation(request) 
     47          invocation = Invocation.new 
     48          invocation.protocol = request.protocol 
     49          invocation.service_name = request.service_name 
    8150          case web_service_dispatching_mode 
    8251          when :direct 
    83             api = self.class.web_service_api 
     52            invocation.api = self.class.web_service_api 
     53            invocation.service = self 
    8454          when :delegated 
    85             web_service_name = protocol_request.web_service_name 
    86             web_service = web_service_object(web_service_name) 
    87             api = web_service.class.web_service_api 
     55            invocation.service = web_service_object(request.service_name) rescue nil 
     56            unless invocation.service 
     57              raise(DispatcherError, "failed to instantiate service #{invocation.service_name}") 
     58            end 
     59            invocation.api = invocation.service.class.web_service_api 
    8860          end 
    89           method_name  = api.api_method_name(public_method_name) 
    90           signature = nil 
    91           if method_name 
    92             signature = api.api_methods[method_name] 
    93             protocol_request.type = Protocol::CheckedMessage 
    94             protocol_request.signature = signature[:expects] 
    95             protocol_request.return_signature = signature[:returns] 
     61          public_method_name = request.method_name 
     62          unless invocation.api.has_public_api_method?(public_method_name) 
     63            raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}") 
     64          end 
     65          invocation.public_method_name = public_method_name 
     66          invocation.api_method_name = invocation.api.api_method_name(public_method_name) 
     67          info = invocation.api.api_methods[invocation.api_method_name] 
     68          invocation.expects = info[:expects] 
     69          invocation.returns = info[:returns] 
     70          if invocation.expects 
     71            i = 0 
     72            invocation.method_ordered_params = request.method_params.map do |param| 
     73              if invocation.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol) 
     74                marshaler = invocation.protocol.marshaler 
     75                decoded_param = WS::Encoding::XmlRpcDecodedParam.new(param.info.name, param.value) 
     76                marshaled_param = marshaler.typed_unmarshal(decoded_param, invocation.expects[i]) rescue nil 
     77                param = marshaled_param ? marshaled_param : param 
     78              end 
     79              i += 1 
     80              param.value 
     81            end 
     82            i = 0 
     83            params = [] 
     84            invocation.expects.each do |spec| 
     85              type_binding = invocation.protocol.register_signature_type(spec) 
     86              info = WS::ParamInfo.create(spec, i, type_binding) 
     87              params << WS::Param.new(invocation.method_ordered_params[i], info) 
     88              i += 1 
     89            end 
     90            invocation.method_ws_params = params 
     91            invocation.method_named_params = {} 
     92            invocation.method_ws_params.each do |param| 
     93              invocation.method_named_params[param.info.name] = param.value 
     94            end 
    9695          else 
    97             method_name = api.default_api_method 
    98             if method_name 
    99               protocol_request.type = Protocol::UncheckedMessage 
    100             else 
    101               raise(DispatcherError, "no such method #{web_service_name}##{public_method_name}") 
    102             end 
     96            invocation.method_ordered_params = [] 
     97            invocation.method_named_params = {} 
    10398          end 
    104           params = protocol_request.unmarshal 
    105           DispatchRequest.new( 
    106             :api                => api, 
    107             :public_method_name => public_method_name, 
    108             :method_name        => method_name, 
    109             :signature          => signature, 
    110             :web_service_name   => web_service_name, 
    111             :web_service        => web_service, 
    112             :params             => params) 
     99          invocation 
    113100        end 
    114101 
    115         def prepare_exception_response(protocol_request, exception) 
    116           if protocol_request && exception 
    117             case web_service_dispatching_mode 
    118             when :direct 
    119               if web_service_exception_reporting 
    120                 return protocol_request.protocol.marshal_exception(exception) 
    121               end 
    122             when :delegated 
    123               web_service = web_service_object(protocol_request.web_service_name) 
    124               if web_service && web_service.class.web_service_exception_reporting 
    125                 return protocol_request.protocol.marshal_exception(exception) 
    126               end 
    127             end 
    128           else 
    129             protocol_request.protocol.marshal_exception(RuntimeError.new("missing protocol request or exception")) 
    130           end 
    131         rescue Exception 
    132           nil 
    133         end 
    134  
    135         class DispatchRequest 
    136           attr :api 
    137           attr :public_method_name 
    138           attr :method_name 
    139           attr :signature 
    140           attr :web_service_name 
    141           attr :web_service 
    142           attr :params 
    143  
    144           def initialize(values={}) 
    145             values.each{|k,v| instance_variable_set("@#{k.to_s}", v)} 
    146           end 
     102        class Invocation 
     103          attr_accessor :protocol 
     104          attr_accessor :service_name 
     105          attr_accessor :api 
     106          attr_accessor :public_method_name 
     107          attr_accessor :api_method_name 
     108          attr_accessor :method_ordered_params 
     109          attr_accessor :method_named_params 
     110          attr_accessor :method_ws_params 
     111          attr_accessor :expects 
     112          attr_accessor :returns 
     113          attr_accessor :service 
    147114        end 
    148115    end 
  • trunk/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb

    r798 r800  
     1require 'benchmark' 
     2require 'builder/xmlmarkup' 
     3 
    14module ActionWebService # :nodoc: 
    25  module Dispatcher # :nodoc: 
     
    811            alias_method :inherited_without_action_controller, :inherited 
    912          end 
    10           alias_method :before_direct_invoke_without_action_controller, :before_direct_invoke 
    11           alias_method :after_direct_invoke_without_action_controller, :after_direct_invoke 
     13          alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke 
    1214        end 
    1315        base.add_web_service_api_callback do |klass, api| 
    1416          if klass.web_service_dispatching_mode == :direct 
    15             klass.class_eval <<-EOS 
    16               def api 
    17                 controller_dispatch_web_service_request 
    18               end 
    19             EOS 
     17            klass.class_eval 'def api; dispatch_web_service_request; end' 
    2018          end 
    2119        end 
    2220        base.add_web_service_definition_callback do |klass, name, info| 
    2321          if klass.web_service_dispatching_mode == :delegated 
    24             klass.class_eval <<-EOS 
    25               def #{name} 
    26                 controller_dispatch_web_service_request 
    27               end 
    28             EOS 
     22            klass.class_eval "def #{name}; dispatch_web_service_request; end" 
    2923          end 
    3024        end 
    3125        base.extend(ClassMethods) 
    32         base.send(:include, ActionWebService::Dispatcher::ActionController::Invocation
     26        base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods
    3327      end 
    3428 
    35       module ClassMethods # :nodoc: 
     29      module ClassMethods 
    3630        def inherited(child) 
    3731          inherited_without_action_controller(child) 
    38           child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlGeneration) 
     32          child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction) 
    3933        end 
    4034      end 
    4135 
    42       module Invocation # :nodoc: 
     36      module InstanceMethods 
    4337        private 
    44           def controller_dispatch_web_service_request 
    45             request, response, elapsed, exception = dispatch_web_service_request(@request) 
    46             if response 
    47               begin 
    48                 log_request(request) 
    49                 log_error(exception) if exception && logger 
    50                 log_response(response, elapsed) 
    51                 response_options = { :type => response.content_type, :disposition => 'inline' } 
    52                 send_data(response.raw_body, response_options) 
    53               rescue Exception => e 
    54                 log_error(e) unless logger.nil? 
    55                 render_text("Internal protocol error", "500 Internal Server Error") 
     38          def dispatch_web_service_request 
     39            request = discover_web_service_request(@request) 
     40            if request 
     41              log_request(request, @request.raw_post) 
     42              response = nil 
     43              exception = nil 
     44              bm = Benchmark.measure do 
     45                begin 
     46                  response = invoke_web_service_request(request) 
     47                rescue Exception => e 
     48                  exception = e 
     49                end 
     50              end 
     51              if exception 
     52                log_error(exception) unless logger.nil? 
     53                send_web_service_error_response(request, exception) 
     54              else 
     55                send_web_service_response(response, bm.real) 
    5656              end 
    5757            else 
    58               logger.error("No response available") unless logger.nil? 
    59               render_text("Internal protocol error", "500 Internal Server Error") 
    60             end 
    61           end 
    62  
    63           def before_direct_invoke(request) 
    64             before_direct_invoke_without_action_controller(request) 
     58              exception = DispatcherError.new("Malformed SOAP or XML-RPC protocol message") 
     59              send_web_service_error_response(request, exception) 
     60            end 
     61          rescue Exception => e 
     62            log_error(e) unless logger.nil? 
     63            send_web_service_error_response(request, e) 
     64          end 
     65 
     66          def send_web_service_response(response, elapsed=nil) 
     67            log_response(response, elapsed) 
     68            options = { :type => response.content_type, :disposition => 'inline' } 
     69            send_data(response.body, options) 
     70          end 
     71