Module: WashOut::Dispatcher
- Defined in:
- lib/wash_out/dispatcher.rb
Overview
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.
Defined Under Namespace
Classes: ProgrammerError, SOAPError
Class Method Summary collapse
- .deep_replace_href(hash, replace) ⇒ Object
- .deep_select(hash, result = [], &blk) ⇒ Object
- .included(controller) ⇒ Object
Instance Method Summary collapse
- #_authenticate_wsse ⇒ Object
-
#_generate_wsdl ⇒ Object
This action generates the WSDL for defined SOAP methods.
-
#_invalid_action ⇒ Object
This action is a fallback for all undefined SOAP actions.
- #_map_soap_parameters ⇒ Object
-
#_parse_soap_parameters ⇒ Object
This filter parses the SOAP request and puts it into
params
array. -
#_render_soap(result, options) ⇒ Object
Render a SOAP response.
- #_render_soap_exception(error) ⇒ Object
-
#render_soap_error(message) ⇒ Object
Render a SOAP error response.
Class Method Details
.deep_replace_href(hash, replace) ⇒ Object
196 197 198 199 200 201 202 203 204 |
# File 'lib/wash_out/dispatcher.rb', line 196 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) ⇒ Object
186 187 188 189 190 191 192 193 194 |
# File 'lib/wash_out/dispatcher.rb', line 186 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) ⇒ Object
178 179 180 181 182 183 184 |
# File 'lib/wash_out/dispatcher.rb', line 178 def self.included(controller) controller.send :rescue_from, SOAPError, :with => :_render_soap_exception controller.send :helper, :wash_out controller.send :before_filter, :_parse_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ] controller.send :before_filter, :_authenticate_wsse, :except => [ :_generate_wsdl, :_invalid_action ] controller.send :before_filter, :_map_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ] end |
Instance Method Details
#_authenticate_wsse ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/wash_out/dispatcher.rb', line 45 def _authenticate_wsse begin xml_security = @_params.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 username_token request.env['WSSE_TOKEN'] = username_token.with_indifferent_access unless username_token.blank? end |
#_generate_wsdl ⇒ Object
This action generates the WSDL for defined SOAP methods.
97 98 99 100 101 102 103 |
# File 'lib/wash_out/dispatcher.rb', line 97 def _generate_wsdl @map = self.class.soap_actions @namespace = WashOut::Engine.namespace @name = controller_path.gsub('/', '_') render :template => 'wash_with_soap/wsdl', :layout => false end |
#_invalid_action ⇒ Object
This action is a fallback for all undefined SOAP actions.
159 160 161 |
# File 'lib/wash_out/dispatcher.rb', line 159 def _invalid_action render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}") end |
#_map_soap_parameters ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/wash_out/dispatcher.rb', line 60 def _map_soap_parameters soap_action = request.env['wash_out.soap_action'] action_spec = self.class.soap_actions[soap_action] xml_data = @_params.values_at(:envelope, :Envelope).compact.first xml_data = xml_data.values_at(:body, :Body).compact.first xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym).compact.first || {} strip_empty_nodes = lambda{|hash| hash.each do |key, value| if value.is_a? Hash value = value.delete_if{|key, value| key.to_s[0] == '@'} if value.length > 0 hash[key] = strip_empty_nodes.call(value) else hash[key] = nil end end end hash } xml_data = strip_empty_nodes.call(xml_data) @_params = HashWithIndifferentAccess.new action_spec[:in].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 end |
#_parse_soap_parameters ⇒ Object
This filter parses the SOAP request and puts it into params
array.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/wash_out/dispatcher.rb', line 14 def _parse_soap_parameters # Do not interfere with project-space Nori setup strip = Nori.strip_namespaces? convert = Nori. typecast = Nori.advanced_typecasting? Nori.strip_namespaces = true Nori.advanced_typecasting = false if WashOut::Engine.snakecase_input Nori. { |tag| tag.snakecase.to_sym } else Nori. { |tag| tag.to_sym } end request_body = request.body.read @_params = Nori.parse(request_body) references = WashOut::Dispatcher.deep_select(@_params){|k,v| v.is_a?(Hash) && v.has_key?(:@id)} unless references.blank? replaces = {}; references.each{|r| replaces['#'+r[:@id]] = r} @_params = WashOut::Dispatcher.deep_replace_href(@_params, replaces) end # Reset Nori setup to project-space Nori.strip_namespaces = strip Nori.advanced_typecasting = typecast Nori. convert end |
#_render_soap(result, options) ⇒ Object
Render a SOAP response.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/wash_out/dispatcher.rb', line 106 def _render_soap(result, ) @namespace = WashOut::Engine.namespace @operation = soap_action = request.env['wash_out.soap_action'] action_spec = self.class.soap_actions[soap_action][:out] result = { 'value' => result } unless result.is_a? Hash result = HashWithIndifferentAccess.new(result) inject = lambda {|data, map| result_spec = [] map.each_with_index do |param, i| result_spec[i] = param.flat_copy # Inline complex structure if param.struct? && !param.multiplied result_spec[i].map = inject.call(data[param.raw_name], param.map) # Inline array of complex structures elsif param.struct? && param.multiplied if data.nil? data = {} # when no data is given elsif data.is_a?(Array) raise ProgrammerError, "SOAP response used #{data.inspect} (which is an Array), " + "in the context where a Hash with key of '#{param.raw_name}' " + "was expected." end data[param.raw_name] = [] unless data[param.raw_name].is_a?(Array) result_spec[i].map = data[param.raw_name].map{|e| inject.call(e, param.map)} else val = data[param.raw_name] if param.multiplied and val and not val.is_a?(Array) raise ProgrammerError, "SOAP response tried to use '#{val.inspect}' " + "(which is of type #{val.class}), as the value for " + "'#{param.raw_name}' (which expects an Array)." end result_spec[i].value = val end end return result_spec } render :template => 'wash_with_soap/response', :layout => false, :locals => { :result => inject.call(result, action_spec) }, :content_type => 'text/xml' end |
#_render_soap_exception(error) ⇒ Object
163 164 165 |
# File 'lib/wash_out/dispatcher.rb', line 163 def _render_soap_exception(error) render_soap_error(error.) end |
#render_soap_error(message) ⇒ Object
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.
171 172 173 174 175 176 |
# File 'lib/wash_out/dispatcher.rb', line 171 def render_soap_error() render :template => 'wash_with_soap/error', :status => 500, :layout => false, :locals => { :error_message => }, :content_type => 'text/xml' end |