module WashOut::Dispatcher
The WashOut::Dispatcher
module should be included in a controller acting as a SOAP
endpoint. It includes actions for generating WSDL and handling SOAP
requests.
Public Class Methods
deep_replace_href(hash, replace)
click to toggle source
# File lib/wash_out/dispatcher.rb, line 186 def self.deep_replace_href(hash, replace) return replace[hash[:@href]] if hash.has_key?(:@href) hash.keys.each do |key, value| hash[key] = deep_replace_href(hash[key], replace) if hash[key].is_a?(Hash) end hash end
deep_select(hash, result=[], &blk)
click to toggle source
# File lib/wash_out/dispatcher.rb, line 176 def self.deep_select(hash, result=[], &blk) result += Hash[hash.select(&blk)].values hash.each do |key, value| result = deep_select(value, result, &blk) if value.is_a? Hash end result end
included(controller)
click to toggle source
# File lib/wash_out/dispatcher.rb, line 160 def self.included(controller) entity = if defined?(Rails::VERSION::MAJOR) && (Rails::VERSION::MAJOR >= 4) 'action' else 'filter' end controller.send :"around_#{entity}", :_catch_soap_errors controller.send :helper, :wash_out controller.send :"before_#{entity}", :_authenticate_wsse, :except => [ :_generate_wsdl, :_invalid_action ] controller.send :"before_#{entity}", :_map_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ] controller.send :"skip_before_#{entity}", :verify_authenticity_token end
Public Instance Methods
_authenticate_wsse()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 18 def _authenticate_wsse begin xml_security = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first xml_security = xml_security.values_at(:header, :Header).compact.first xml_security = xml_security.values_at(:security, :Security).compact.first username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first rescue username_token = nil end WashOut::Wsse.authenticate soap_config, username_token request.env['WSSE_TOKEN'] = username_token.with_indifferent_access unless username_token.blank? end
_catch_soap_errors() { || ... }
click to toggle source
# File lib/wash_out/dispatcher.rb, line 143 def _catch_soap_errors yield rescue SOAPError => error render_soap_error(error.message, error.code) end
_generate_wsdl()
click to toggle source
This action generates the WSDL for defined SOAP
methods.
# File lib/wash_out/dispatcher.rb, line 71 def _generate_wsdl @map = self.class.soap_actions @namespace = soap_config.namespace @name = controller_path.gsub('/', '_') render :template => "wash_out/#{soap_config.wsdl_style}/wsdl", :layout => false, :content_type => 'text/xml' end
_invalid_action()
click to toggle source
This action is a fallback for all undefined SOAP
actions.
# File lib/wash_out/dispatcher.rb, line 139 def _invalid_action render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}") end
_load_params(spec, xml_data)
click to toggle source
Creates the final parameter hash based on the request spec and xml_data
from the request
# File lib/wash_out/dispatcher.rb, line 59 def _load_params(spec, xml_data) params = HashWithIndifferentAccess.new spec.each do |param| key = param.raw_name.to_sym if xml_data.has_key? key params[param.raw_name] = param.load(xml_data, key) end end params end
_map_soap_parameters()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 34 def _map_soap_parameters @_params = _load_params action_spec[:in], _strip_empty_nodes(action_spec[:in], xml_data) end
_render_soap(result, options)
click to toggle source
Render a SOAP
response.
# File lib/wash_out/dispatcher.rb, line 82 def _render_soap(result, options) @namespace = soap_config.namespace @operation = soap_action = request.env['wash_out.soap_action'] @action_spec = self.class.soap_actions[soap_action] result = { 'value' => result } unless result.is_a? Hash result = HashWithIndifferentAccess.new(result) inject = lambda {|data, map| result_spec = [] return result_spec if data.nil? map.each_with_index do |param, i| result_spec[i] = param.flat_copy unless data.is_a?(Hash) raise ProgrammerError, "SOAP response used #{data.inspect} (which is #{data.class.name}), " + "in the context where a Hash with key of '#{param.raw_name}' " + "was expected." end value = data[param.raw_name] unless value.nil? if param.multiplied && !value.is_a?(Array) raise ProgrammerError, "SOAP response tried to use '#{value.inspect}' " + "(which is of type #{value.class.name}), as the value for " + "'#{param.raw_name}' (which expects an Array)." end # Inline complex structure {:foo => {bar: ...}} if param.struct? && !param.multiplied result_spec[i].map = inject.call(value, param.map) # Inline array of complex structures {:foo => [{bar: ...}]} elsif param.struct? && param.multiplied result_spec[i].map = value.map{|e| inject.call(e, param.map)} # Inline scalar {:foo => :string} else result_spec[i].value = value end end end return result_spec } render :template => "wash_out/#{soap_config.wsdl_style}/response", :layout => false, :locals => { :result => inject.call(result, @action_spec[:out]) }, :content_type => 'text/xml' end
_strip_empty_nodes(params, hash)
click to toggle source
# File lib/wash_out/dispatcher.rb, line 39 def _strip_empty_nodes(params, hash) hash.keys.each do |key| param = params.detect { |a| a.raw_name.to_s == key.to_s } next if !(param && hash[key].is_a?(Hash)) value = hash[key].delete_if do |k, _| k.to_s[0] == '@' && !param.map.detect { |a| a.raw_name.to_s == k.to_s } end if value.length > 0 hash[key] = _strip_empty_nodes param.map, value else hash[key] = nil end end hash end
render_soap_error(message, code=nil)
click to toggle source
Render a SOAP
error response.
Rails do not support sequental rescue_from handling, that is, rescuing an exception from a rescue_from handler. Hence this function is a public API.
# File lib/wash_out/dispatcher.rb, line 153 def render_soap_error(message, code=nil) render :template => "wash_out/#{soap_config.wsdl_style}/error", :status => 500, :layout => false, :locals => { :error_message => message, :error_code => (code || 'Server') }, :content_type => 'text/xml' end
Private Instance Methods
action_spec()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 198 def action_spec self.class.soap_actions[soap_action] end
request_input_tag()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 202 def request_input_tag action_spec[:request_tag] end
soap_action()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 206 def soap_action request.env['wash_out.soap_action'] end
xml_data()
click to toggle source
# File lib/wash_out/dispatcher.rb, line 210 def xml_data xml_data = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first xml_data = xml_data.values_at(:body, :Body).compact.first || {} return xml_data if soap_config.wsdl_style == "document" xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym, request_input_tag.to_sym).compact.first || {} end