Changeset 800
- Timestamp:
- 02/25/05 23:39:39 (4 years ago)
- Files:
-
- trunk/actionwebservice/ChangeLog (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service.rb (modified) (2 diffs)
- trunk/actionwebservice/lib/action_web_service/api.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/api/base.rb (moved) (moved from trunk/actionwebservice/lib/action_web_service/api/abstract.rb) (4 diffs)
- trunk/actionwebservice/lib/action_web_service/base.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/client/base.rb (modified) (2 diffs)
- trunk/actionwebservice/lib/action_web_service/client/soap_client.rb (modified) (3 diffs)
- trunk/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb (modified) (3 diffs)
- trunk/actionwebservice/lib/action_web_service/container (added)
- trunk/actionwebservice/lib/action_web_service/container.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/container/action_controller_container.rb (moved) (moved from trunk/actionwebservice/lib/action_web_service/api/action_controller.rb) (2 diffs)
- trunk/actionwebservice/lib/action_web_service/container/delegated_container.rb (added)
- trunk/actionwebservice/lib/action_web_service/container/direct_container.rb (added)
- trunk/actionwebservice/lib/action_web_service/dispatcher/abstract.rb (modified) (2 diffs)
- trunk/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb (modified) (8 diffs)
- trunk/actionwebservice/lib/action_web_service/protocol.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/protocol/abstract.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/protocol/discovery.rb (added)
- trunk/actionwebservice/lib/action_web_service/protocol/registry.rb (deleted)
- trunk/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb (modified) (2 diffs)
- trunk/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/struct.rb (modified) (1 diff)
- trunk/actionwebservice/lib/action_web_service/support/signature.rb (deleted)
- trunk/actionwebservice/lib/action_web_service/vendor (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/common.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/encoding (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/marshaling (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb (added)
- trunk/actionwebservice/lib/action_web_service/vendor/ws/types.rb (added)
- trunk/actionwebservice/Rakefile (modified) (5 diffs)
- trunk/actionwebservice/test/abstract_client.rb (modified) (3 diffs)
- trunk/actionwebservice/test/abstract_dispatcher.rb (added)
- trunk/actionwebservice/test/abstract_soap.rb (deleted)
- trunk/actionwebservice/test/abstract_unit.rb (modified) (1 diff)
- trunk/actionwebservice/test/api_test.rb (modified) (2 diffs)
- trunk/actionwebservice/test/apis (added)
- trunk/actionwebservice/test/apis/auto_load_api.rb (added)
- trunk/actionwebservice/test/apis/broken_auto_load_api.rb (added)
- trunk/actionwebservice/test/client_soap_test.rb (modified) (4 diffs)
- trunk/actionwebservice/test/client_xmlrpc_test.rb (modified) (2 diffs)
- trunk/actionwebservice/test/container_test.rb (modified) (3 diffs)
- trunk/actionwebservice/test/dispatcher_action_controller_soap_test.rb (added)
- trunk/actionwebservice/test/dispatcher_action_controller_test.rb (deleted)
- trunk/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb (added)
- trunk/actionwebservice/test/gencov (modified) (1 diff)
- trunk/actionwebservice/test/invocation_test.rb (modified) (7 diffs)
- trunk/actionwebservice/test/protocol_registry_test.rb (deleted)
- trunk/actionwebservice/test/protocol_soap_test.rb (deleted)
- trunk/actionwebservice/test/protocol_xmlrpc_test.rb (deleted)
- trunk/actionwebservice/test/run (modified) (1 diff)
- trunk/actionwebservice/test/ws (added)
- trunk/actionwebservice/test/ws/abstract_encoding.rb (added)
- trunk/actionwebservice/test/ws/abstract_unit.rb (added)
- trunk/actionwebservice/test/ws/gencov (added)
- trunk/actionwebservice/test/ws/run (added)
- trunk/actionwebservice/test/ws/soap_marshaling_test.rb (added)
- trunk/actionwebservice/test/ws/soap_rpc_encoding_test.rb (added)
- trunk/actionwebservice/test/ws/types_test.rb (added)
- trunk/actionwebservice/test/ws/xmlrpc_encoding_test.rb (added)
- trunk/actionwebservice/TODO (modified) (1 diff)
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 1 10 *0.5.0* (24th February, 2005) 2 11 trunk/actionwebservice/lib/action_web_service.rb
r679 r800 33 33 end 34 34 35 $:.unshift(File.dirname(__FILE__)) 35 $:.unshift(File.dirname(__FILE__) + "/action_web_service/vendor/") 36 37 require 'action_web_service/support/class_inheritable_options' 38 require 'action_web_service/vendor/ws' 36 39 37 40 require 'action_web_service/base' … … 42 45 require 'action_web_service/container' 43 46 require 'action_web_service/protocol' 47 require 'action_web_service/struct' 44 48 require 'action_web_service/dispatcher' 45 49 46 50 ActionWebService::Base.class_eval do 47 include ActionWebService:: API51 include ActionWebService::Container::Direct 48 52 include ActionWebService::Invocation 49 53 end 50 54 51 55 ActionController::Base.class_eval do 52 include ActionWebService::Container 53 include ActionWebService::Protocol::Registry 56 include ActionWebService::Protocol::Discovery 54 57 include ActionWebService::Protocol::Soap 55 58 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 58 62 include ActionWebService::Dispatcher 59 63 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' 1 require 'action_web_service/api/base' trunk/actionwebservice/lib/action_web_service/api/base.rb
r672 r800 1 1 module ActionWebService # :nodoc: 2 2 module API # :nodoc: 3 class APIError < ActionWebService::ActionWebServiceError # :nodoc:4 end5 6 def self.append_features(base) # :nodoc:7 super8 base.extend(ClassMethods)9 end10 11 module ClassMethods12 # Attaches ActionWebService API +definition+ to the calling class.13 #14 # Action Controllers can have a default associated API, removing the need15 # to call this method if you follow the Action Web Service naming conventions.16 #17 # A controller with a class name of GoogleSearchController will18 # implicitly load <tt>app/apis/google_search_api.rb</tt>, and expect the19 # API definition class to be named <tt>GoogleSearchAPI</tt> or20 # <tt>GoogleSearchApi</tt>.21 #22 # ==== Service class example23 #24 # class MyService < ActionWebService::Base25 # web_service_api MyAPI26 # end27 #28 # class MyAPI < ActionWebService::API::Base29 # ...30 # end31 #32 # ==== Controller class example33 #34 # class MyController < ActionController::Base35 # web_service_api MyAPI36 # end37 #38 # class MyAPI < ActionWebService::API::Base39 # ...40 # end41 def web_service_api(definition=nil)42 if definition.nil?43 read_inheritable_attribute("web_service_api")44 else45 if definition.is_a?(Symbol)46 raise(APIError, "symbols can only be used for #web_service_api inside of a controller")47 end48 unless definition.respond_to?(:ancestors) && definition.ancestors.include?(Base)49 raise(APIError, "#{definition.to_s} is not a valid API definition")50 end51 write_inheritable_attribute("web_service_api", definition)52 call_web_service_api_callbacks(self, definition)53 end54 end55 56 def add_web_service_api_callback(&block) # :nodoc:57 write_inheritable_array("web_service_api_callbacks", [block])58 end59 60 private61 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 end65 end66 end67 68 3 # A web service API class specifies the methods that will be available for 69 4 # invocation for an API. It also contains metadata such as the method type … … 88 23 89 24 class << self 90 include ActionWebService::Signature91 92 25 # API methods have a +name+, which must be the Ruby method name to use when 93 26 # performing the invocation on the web service object. … … 126 59 returns = options[:returns] 127 60 end 128 expects = canonical_signature(expects) if expects129 returns = canonical_signature(returns) if returns61 expects = canonical_signature(expects) 62 returns = canonical_signature(returns) 130 63 if expects 131 64 expects.each do |param| 132 klass = signature_parameter_class(param)65 klass = WS::BaseTypes.canonical_param_type_class(param) 133 66 klass = klass[0] if klass.is_a?(Array) 134 67 if klass.ancestors.include?(ActiveRecord::Base) … … 187 120 end 188 121 122 def canonical_signature(signature) 123 return nil if signature.nil? 124 signature.map{|spec| WS::BaseTypes.canonical_param_type_spec(spec)} 125 end 189 126 end 190 127 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 4 1 module ActionWebService # :nodoc: 5 2 class ActionWebServiceError < StandardError # :nodoc: trunk/actionwebservice/lib/action_web_service/client/base.rb
r680 r800 13 13 call_name = method_name(name) 14 14 return super(name, *args) if call_name.nil? 15 perform_invocation(call_name, args)15 self.perform_invocation(call_name, args) 16 16 end 17 18 protected19 def perform_invocation(method_name, args) # :nodoc:20 raise NotImplementedError, "use a protocol-specific client"21 end22 17 23 18 private … … 27 22 elsif @api.has_public_api_method?(name.to_s) 28 23 @api.api_method_name(name.to_s).to_s 29 else30 nil31 24 end 32 end33 34 def lookup_class(klass)35 klass.is_a?(Hash) ? klass.values[0] : klass36 25 end 37 26 end trunk/actionwebservice/lib/action_web_service/client/soap_client.rb
r680 r800 29 29 def initialize(api, endpoint_uri, options={}) 30 30 super(api, endpoint_uri) 31 @service_name = options[:service_name] || 'ActionWebService'32 @namespace = "urn:#{@service_name}"33 @ma pper = 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 35 35 @soap_action_base = options[:soap_action_base] 36 36 @soap_action_base ||= URI.parse(endpoint_uri).path … … 49 49 private 50 50 def create_soap_rpc_driver(api, endpoint_uri) 51 @mapper.map_api(api)51 register_api(@marshaler, api) 52 52 driver = SoapDriver.new(endpoint_uri, nil) 53 driver.mapping_registry = @ma pper.registry53 driver.mapping_registry = @marshaler.registry 54 54 api.api_methods.each do |name, info| 55 55 public_name = api.public_api_method_name(name) … … 59 59 returns = info[:returns] 60 60 param_def = [] 61 i = 161 i = 0 62 62 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] 68 67 i += 1 69 68 end 70 69 end 71 70 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] 74 73 end 75 74 driver.add_method(qname, action, name.to_s, param_def) 76 75 end 77 76 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 78 91 end 79 92 trunk/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
r680 r800 32 32 @handler_name = options[:handler_name] 33 33 @client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout]) 34 @marshaler = WS::Marshaling::XmlRpcMarshaler.new 34 35 end 35 36 … … 44 45 def transform_outgoing_method_params(method_name, params) 45 46 info = @api.api_methods[method_name.to_sym] 46 signature= info[:expects]47 signature_length = signature.nil?? 0 : signature.length48 if signature_length != params.length49 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") 52 53 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 58 62 end 59 63 end … … 63 67 def transform_return_value(method_name, return_value) 64 68 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)) 69 74 end 70 75 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 1 require 'action_web_service/container/direct_container' 2 require 'action_web_service/container/delegated_container' 3 require 'action_web_service/container/action_controller_container' trunk/actionwebservice/lib/action_web_service/container/action_controller_container.rb
r672 r800 1 1 module ActionWebService # :nodoc: 2 module API# :nodoc:2 module Container # :nodoc: 3 3 module ActionController # :nodoc: 4 4 def self.append_features(base) # :nodoc: … … 37 37 class_eval do 38 38 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) 40 40 end 41 41 protected name trunk/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
r708 r800 15 15 module InstanceMethods # :nodoc: 16 16 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) 22 24 end 23 [protocol_request, protocol_response, bm.real, nil]24 rescue Exception => e25 protocol_response = prepare_exception_response(protocol_request, e)26 [protocol_request, prepare_exception_response(protocol_request, e), nil, e]27 25 end 28 26 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) 38 32 end 39 33 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) 67 35 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| 70 37 cancellation_reason = x 71 38 end … … 73 40 raise(DispatcherError, "request canceled: #{cancellation_reason}") 74 41 end 75 return_value 42 returns = invocation.returns ? invocation.returns[0] : nil 43 invocation.protocol.marshal_response(invocation.public_method_name, return_value, returns) 76 44 end 77 45 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 81 50 case web_service_dispatching_mode 82 51 when :direct 83 api = self.class.web_service_api 52 invocation.api = self.class.web_service_api 53 invocation.service = self 84 54 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 88 60 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 96 95 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 = {} 103 98 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 113 100 end 114 101 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 147 114 end 148 115 end trunk/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
r798 r800 1 require 'benchmark' 2 require 'builder/xmlmarkup' 3 1 4 module ActionWebService # :nodoc: 2 5 module Dispatcher # :nodoc: … … 8 11 alias_method :inherited_without_action_controller, :inherited 9 12 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 12 14 end 13 15 base.add_web_service_api_callback do |klass, api| 14 16 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' 20 18 end 21 19 end 22 20 base.add_web_service_definition_callback do |klass, name, info| 23 21 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" 29 23 end 30 24 end 31 25 base.extend(ClassMethods) 32 base.send(:include, ActionWebService::Dispatcher::ActionController::In vocation)26 base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods) 33 27 end 34 28 35 module ClassMethods # :nodoc:29 module ClassMethods 36 30 def inherited(child) 37 31 inherited_without_action_controller(child) 38 child.send(:include, ActionWebService::Dispatcher::ActionController::Wsdl Generation)32 child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction) 39 33 end 40 34 end 41 35 42 module In vocation # :nodoc:36 module InstanceMethods 43 37 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) 56 56 end 57 57 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