From 9b83e3396180d0dbcb23ec3d71adb198eae7629b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 21 Nov 2007 15:17:04 +0000 Subject: Ousted ActionWebService from Rails 2.0 git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8180 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- .../lib/action_web_service/dispatcher/abstract.rb | 207 ----------- .../dispatcher/action_controller_dispatcher.rb | 379 --------------------- 2 files changed, 586 deletions(-) delete mode 100644 actionwebservice/lib/action_web_service/dispatcher/abstract.rb delete mode 100644 actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb (limited to 'actionwebservice/lib/action_web_service/dispatcher') diff --git a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb deleted file mode 100644 index cb94d649e7..0000000000 --- a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb +++ /dev/null @@ -1,207 +0,0 @@ -require 'benchmark' - -module ActionWebService # :nodoc: - module Dispatcher # :nodoc: - class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc: - def initialize(*args) - super - set_backtrace(caller) - end - end - - def self.included(base) # :nodoc: - 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 invoke_web_service_request(protocol_request) - invocation = web_service_invocation(protocol_request) - if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol) - xmlrpc_multicall_invoke(invocation) - else - web_service_invoke(invocation) - end - end - - def web_service_direct_invoke(invocation) - @method_params = invocation.method_ordered_params - arity = method(invocation.api_method.name).arity rescue 0 - if arity < 0 || arity > 0 - params = @method_params - else - params = [] - end - web_service_filtered_invoke(invocation, params) - end - - def web_service_delegated_invoke(invocation) - web_service_filtered_invoke(invocation, invocation.method_ordered_params) - end - - def web_service_filtered_invoke(invocation, params) - cancellation_reason = nil - return_value = invocation.service.perform_invocation(invocation.api_method.name, params) do |x| - cancellation_reason = x - end - if cancellation_reason - raise(DispatcherError, "request canceled: #{cancellation_reason}") - end - return_value - end - - def web_service_invoke(invocation) - case web_service_dispatching_mode - when :direct - return_value = web_service_direct_invoke(invocation) - when :delegated, :layered - return_value = web_service_delegated_invoke(invocation) - end - web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value) - end - - def xmlrpc_multicall_invoke(invocations) - responses = [] - invocations.each do |invocation| - if invocation.is_a?(Hash) - responses << [invocation, nil] - next - end - begin - case web_service_dispatching_mode - when :direct - return_value = web_service_direct_invoke(invocation) - when :delegated, :layered - return_value = web_service_delegated_invoke(invocation) - end - api_method = invocation.api_method - if invocation.api.has_api_method?(api_method.name) - response_type = (api_method.returns ? api_method.returns[0] : nil) - return_value = api_method.cast_returns(return_value) - else - response_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0) - end - responses << [return_value, response_type] - rescue Exception => e - responses << [{ 'faultCode' => 3, 'faultString' => e.message }, nil] - end - end - invocation = invocations[0] - invocation.protocol.encode_multicall_response(responses, invocation.protocol_options) - end - - def web_service_invocation(request, level = 0) - public_method_name = request.method_name - invocation = Invocation.new - invocation.protocol = request.protocol - invocation.protocol_options = request.protocol_options - invocation.service_name = request.service_name - if web_service_dispatching_mode == :layered - case invocation.protocol - when Protocol::Soap::SoapProtocol - soap_action = request.protocol_options[:soap_action] - if soap_action && soap_action =~ /^\/\w+\/(\w+)\// - invocation.service_name = $1 - end - when Protocol::XmlRpc::XmlRpcProtocol - if request.method_name =~ /^([^\.]+)\.(.*)$/ - public_method_name = $2 - invocation.service_name = $1 - end - end - end - if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol - if public_method_name == 'multicall' && invocation.service_name == 'system' - if level > 0 - raise(DispatcherError, "Recursive system.multicall invocations not allowed") - end - multicall = request.method_params.dup - unless multicall.is_a?(Array) && multicall[0].is_a?(Array) - raise(DispatcherError, "Malformed multicall (expected array of Hash elements)") - end - multicall = multicall[0] - return multicall.map do |item| - raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash) - raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName') - method_name = item['methodName'] - params = item.has_key?('params') ? item['params'] : [] - multicall_request = request.dup - multicall_request.method_name = method_name - multicall_request.method_params = params - begin - web_service_invocation(multicall_request, level + 1) - rescue Exception => e - {'faultCode' => 4, 'faultMessage' => e.message} - end - end - end - end - case web_service_dispatching_mode - when :direct - invocation.api = self.class.web_service_api - invocation.service = self - when :delegated, :layered - invocation.service = web_service_object(invocation.service_name) - invocation.api = invocation.service.class.web_service_api - end - if invocation.api.nil? - raise(DispatcherError, "no API attached to #{invocation.service.class}") - end - invocation.protocol.register_api(invocation.api) - request.api = invocation.api - if invocation.api.has_public_api_method?(public_method_name) - invocation.api_method = invocation.api.public_api_method_instance(public_method_name) - else - if invocation.api.default_api_method.nil? - raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}") - else - invocation.api_method = invocation.api.default_api_method_instance - end - end - if invocation.service.nil? - raise(DispatcherError, "no service available for service name #{invocation.service_name}") - end - unless invocation.service.respond_to?(invocation.api_method.name) - raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})") - end - request.api_method = invocation.api_method - begin - invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup) - rescue - logger.warn "Casting of method parameters failed" unless logger.nil? - invocation.method_ordered_params = request.method_params - end - request.method_params = invocation.method_ordered_params - invocation.method_named_params = {} - invocation.api_method.param_names.inject(0) do |m, n| - invocation.method_named_params[n] = invocation.method_ordered_params[m] - m + 1 - end - invocation - end - - def web_service_create_response(protocol, protocol_options, api, api_method, return_value) - if api.has_api_method?(api_method.name) - return_type = api_method.returns ? api_method.returns[0] : nil - return_value = api_method.cast_returns(return_value) - else - return_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0) - end - protocol.encode_response(api_method.public_name + 'Response', return_value, return_type, protocol_options) - end - - class Invocation # :nodoc: - attr_accessor :protocol - attr_accessor :protocol_options - attr_accessor :service_name - attr_accessor :api - attr_accessor :api_method - attr_accessor :method_ordered_params - attr_accessor :method_named_params - attr_accessor :service - end - end - end -end diff --git a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb deleted file mode 100644 index f9995197a0..0000000000 --- a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +++ /dev/null @@ -1,379 +0,0 @@ -require 'benchmark' -require 'builder/xmlmarkup' - -module ActionWebService # :nodoc: - module Dispatcher # :nodoc: - module ActionController # :nodoc: - def self.included(base) # :nodoc: - class << base - include ClassMethods - alias_method_chain :inherited, :action_controller - end - base.class_eval do - alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke - end - base.add_web_service_api_callback do |klass, api| - if klass.web_service_dispatching_mode == :direct - klass.class_eval 'def api; dispatch_web_service_request; end' - end - end - base.add_web_service_definition_callback do |klass, name, info| - if klass.web_service_dispatching_mode == :delegated - klass.class_eval "def #{name}; dispatch_web_service_request; end" - elsif klass.web_service_dispatching_mode == :layered - klass.class_eval 'def api; dispatch_web_service_request; end' - end - end - base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods) - end - - module ClassMethods # :nodoc: - def inherited_with_action_controller(child) - inherited_without_action_controller(child) - child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction) - end - end - - module InstanceMethods # :nodoc: - private - def dispatch_web_service_request - method = request.method.to_s.upcase - allowed_methods = self.class.web_service_api ? (self.class.web_service_api.allowed_http_methods || []) : [ :post ] - allowed_methods = allowed_methods.map{|m| m.to_s.upcase } - if !allowed_methods.include?(method) - render :text => "#{method} not supported", :status=>500 - return - end - exception = nil - begin - ws_request = discover_web_service_request(request) - rescue Exception => e - exception = e - end - if ws_request - ws_response = nil - exception = nil - bm = Benchmark.measure do - begin - ws_response = invoke_web_service_request(ws_request) - rescue Exception => e - exception = e - end - end - log_request(ws_request, request.raw_post) - if exception - log_error(exception) unless logger.nil? - send_web_service_error_response(ws_request, exception) - else - send_web_service_response(ws_response, bm.real) - end - else - exception ||= DispatcherError.new("Malformed SOAP or XML-RPC protocol message") - log_error(exception) unless logger.nil? - send_web_service_error_response(ws_request, exception) - end - rescue Exception => e - log_error(e) unless logger.nil? - send_web_service_error_response(ws_request, e) - end - - def send_web_service_response(ws_response, elapsed=nil) - log_response(ws_response, elapsed) - options = { :type => ws_response.content_type, :disposition => 'inline' } - send_data(ws_response.body, options) - end - - def send_web_service_error_response(ws_request, exception) - if ws_request - unless self.class.web_service_exception_reporting - exception = DispatcherError.new("Internal server error (exception raised)") - end - api_method = ws_request.api_method - public_method_name = api_method ? api_method.public_name : ws_request.method_name - return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0) - ws_response = ws_request.protocol.encode_response(public_method_name + 'Response', exception, return_type, ws_request.protocol_options) - send_web_service_response(ws_response) - else - if self.class.web_service_exception_reporting - message = exception.message - backtrace = "\nBacktrace:\n#{exception.backtrace.join("\n")}" - else - message = "Exception raised" - backtrace = "" - end - render :text => "Internal protocol error: #{message}#{backtrace}", :status => 500 - end - end - - def web_service_direct_invoke(invocation) - invocation.method_named_params.each do |name, value| - params[name] = value - end - web_service_direct_invoke_without_controller(invocation) - end - - def log_request(ws_request, body) - unless logger.nil? - name = ws_request.method_name - api_method = ws_request.api_method - params = ws_request.method_params - if api_method && api_method.expects - params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" } - else - params = params.map{ |param| param.inspect } - end - service = ws_request.service_name - logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}") - logger.debug(indent(body)) - end - end - - def log_response(ws_response, elapsed=nil) - unless logger.nil? - elapsed = (elapsed ? " (%f):" % elapsed : ":") - logger.debug("\nWeb Service Response" + elapsed + " => #{ws_response.return_value.inspect}") - logger.debug(indent(ws_response.body)) - end - end - - def indent(body) - body.split(/\n/).map{|x| " #{x}"}.join("\n") - end - end - - module WsdlAction # :nodoc: - XsdNs = 'http://www.w3.org/2001/XMLSchema' - WsdlNs = 'http://schemas.xmlsoap.org/wsdl/' - SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/' - SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/' - SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http' - - def wsdl - case request.method - when :get - begin - options = { :type => 'text/xml', :disposition => 'inline' } - send_data(to_wsdl, options) - rescue Exception => e - log_error(e) unless logger.nil? - end - when :post - render :text => 'POST not supported', :status => 500 - end - end - - private - def base_uri - host = request.host_with_port - relative_url_root = request.relative_url_root - scheme = request.ssl? ? 'https' : 'http' - '%s://%s%s/%s/' % [scheme, host, relative_url_root, self.class.controller_path] - end - - def to_wsdl - xml = '' - dispatching_mode = web_service_dispatching_mode - global_service_name = wsdl_service_name - namespace = wsdl_namespace || 'urn:ActionWebService' - soap_action_base = "/#{controller_name}" - - marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace) - apis = {} - case dispatching_mode - when :direct - api = self.class.web_service_api - web_service_name = controller_class_name.sub(/Controller$/, '').underscore - apis[web_service_name] = [api, register_api(api, marshaler)] - when :delegated, :layered - self.class.web_services.each do |web_service_name, info| - service = web_service_object(web_service_name) - api = service.class.web_service_api - apis[web_service_name] = [api, register_api(api, marshaler)] - end - end - custom_types = [] - apis.values.each do |api, bindings| - bindings.each do |b| - custom_types << b unless custom_types.include?(b) - end - end - - xm = Builder::XmlMarkup.new(:target => xml, :indent => 2) - xm.instruct! - xm.definitions('name' => wsdl_service_name, - 'targetNamespace' => namespace, - 'xmlns:typens' => namespace, - 'xmlns:xsd' => XsdNs, - 'xmlns:soap' => SoapNs, - 'xmlns:soapenc' => SoapEncodingNs, - 'xmlns:wsdl' => WsdlNs, - 'xmlns' => WsdlNs) do - # Generate XSD - if custom_types.size > 0 - xm.types do - xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do - custom_types.each do |binding| - case - when binding.type.array? - xm.xsd(:complexType, 'name' => binding.type_name) do - xm.xsd(:complexContent) do - xm.xsd(:restriction, 'base' => 'soapenc:Array') do - xm.xsd(:attribute, 'ref' => 'soapenc:arrayType', - 'wsdl:arrayType' => binding.element_binding.qualified_type_name('typens') + '[]') - end - end - end - when binding.type.structured? - xm.xsd(:complexType, 'name' => binding.type_name) do - xm.xsd(:all) do - binding.type.each_member do |name, type| - b = marshaler.register_type(type) - xm.xsd(:element, 'name' => name, 'type' => b.qualified_type_name('typens')) - end - end - end - end - end - end - end - end - - # APIs - apis.each do |api_name, values| - api = values[0] - api.api_methods.each do |name, method| - gen = lambda do |msg_name, direction| - xm.message('name' => message_name_for(api_name, msg_name)) do - sym = nil - if direction == :out - returns = method.returns - if returns - binding = marshaler.register_type(returns[0]) - xm.part('name' => 'return', 'type' => binding.qualified_type_name('typens')) - end - else - expects = method.expects - expects.each do |type| - binding = marshaler.register_type(type) - xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens')) - end if expects - end - end - end - public_name = method.public_name - gen.call(public_name, :in) - gen.call("#{public_name}Response", :out) - end - - # Port - port_name = port_name_for(global_service_name, api_name) - xm.portType('name' => port_name) do - api.api_methods.each do |name, method| - xm.operation('name' => method.public_name) do - xm.input('message' => "typens:" + message_name_for(api_name, method.public_name)) - xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response")) - end - end - end - - # Bind it - binding_name = binding_name_for(global_service_name, api_name) - xm.binding('name' => binding_name, 'type' => "typens:#{port_name}") do - xm.soap(:binding, 'style' => 'rpc', 'transport' => SoapHttpTransport) - api.api_methods.each do |name, method| - xm.operation('name' => method.public_name) do - case web_service_dispatching_mode - when :direct - soap_action = soap_action_base + "/api/" + method.public_name - when :delegated, :layered - soap_action = soap_action_base \ - + "/" + api_name.to_s \ - + "/" + method.public_name - end - xm.soap(:operation, 'soapAction' => soap_action) - xm.input do - xm.soap(:body, - 'use' => 'encoded', - 'namespace' => namespace, - 'encodingStyle' => SoapEncodingNs) - end - xm.output do - xm.soap(:body, - 'use' => 'encoded', - 'namespace' => namespace, - 'encodingStyle' => SoapEncodingNs) - end - end - end - end - end - - # Define it - xm.service('name' => "#{global_service_name}Service") do - apis.each do |api_name, values| - port_name = port_name_for(global_service_name, api_name) - binding_name = binding_name_for(global_service_name, api_name) - case web_service_dispatching_mode - when :direct, :layered - binding_target = 'api' - when :delegated - binding_target = api_name.to_s - end - xm.port('name' => port_name, 'binding' => "typens:#{binding_name}") do - xm.soap(:address, 'location' => "#{base_uri}#{binding_target}") - end - end - end - end - end - - def port_name_for(global_service, service) - "#{global_service}#{service.to_s.camelize}Port" - end - - def binding_name_for(global_service, service) - "#{global_service}#{service.to_s.camelize}Binding" - end - - def message_name_for(api_name, message_name) - mode = web_service_dispatching_mode - if mode == :layered || mode == :delegated - api_name.to_s + '-' + message_name - else - message_name - end - end - - def register_api(api, marshaler) - bindings = {} - traverse_custom_types(api, marshaler, bindings) do |binding| - bindings[binding] = nil unless bindings.has_key?(binding) - element_binding = binding.element_binding - bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding) - end - bindings.keys - end - - def traverse_custom_types(api, marshaler, bindings, &block) - api.api_methods.each do |name, method| - expects, returns = method.expects, method.returns - expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects - returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns - end - end - - def traverse_type(marshaler, type, bindings, &block) - binding = marshaler.register_type(type) - return if bindings.has_key?(binding) - bindings[binding] = nil - yield binding - if type.array? - yield marshaler.register_type(type.element_type) - type = type.element_type - end - type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured? - end - end - end - end -end -- cgit v1.2.3