Class: Handsoap::Service
- Inherits:
-
Object
- Object
- Handsoap::Service
- Defined in:
- lib/handsoap/service.rb,
lib/handsoap/service.rb
Constant Summary collapse
- @@logger =
nil- @@instance =
{}
Class Method Summary collapse
-
.endpoint(args = {}) ⇒ Object
Sets the endpoint for the service.
- .envelope_namespace ⇒ Object
- .fire_on_create_document(doc) ⇒ Object
- .get_mapping(name) ⇒ Object
- .instance ⇒ Object
- .logger=(io) ⇒ Object
-
.map_method(mapping) ⇒ Object
Registers a simple method mapping without any arguments and no parsing of response.
- .method_missing(method, *args) ⇒ Object
-
.on_create_document(&block) ⇒ Object
Registers a block to call when a request document is created.
- .request_content_type ⇒ Object
- .uri ⇒ Object
Instance Method Summary collapse
-
#debug(message = nil) ⇒ Object
:nodoc:.
-
#dispatch(doc, action) ⇒ Object
Send document and parses the response into a
XmlQueryFront::XmlElement(XmlDocument). -
#invoke(action, options = { :soap_action => :auto }, &block) ⇒ Object
Creates an XML document and sends it over HTTP.
-
#make_envelope ⇒ Object
Creates a standard SOAP envelope and yields the
Bodyelement. - #method_missing(method, *args) ⇒ Object
-
#on_after_create_http_request(http_request) ⇒ Object
Hook that is called after the http_client is created.
-
#on_before_dispatch ⇒ Object
Hook that is called before the message is dispatched.
-
#on_create_document(doc) ⇒ Object
Hook that is called when a new request document is created.
-
#on_fault(fault) ⇒ Object
Hook that is called if the dispatch returns a
Fault. -
#on_http_error(response) ⇒ Object
Hook that is called if there is a HTTP level error.
-
#on_missing_document(response) ⇒ Object
Hook that is called if the response does not contain a valid SOAP enevlope.
-
#on_response_document(doc) ⇒ Object
Hook that is called when there is a response.
-
#parse_soap_fault(document) ⇒ Object
XmlDocument -> [Fault | nil].
-
#parse_soap_response_document(http_body) ⇒ Object
String -> [XmlDocument | nil].
-
#send_http_request(uri, post_body, headers) ⇒ Object
Does the actual HTTP level interaction.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
318 319 320 321 322 323 324 325 |
# File 'lib/handsoap/service.rb', line 318 def method_missing(method, *args) action = self.class.get_mapping(method) if action invoke(action, *args) else super end end |
Class Method Details
.endpoint(args = {}) ⇒ Object
Sets the endpoint for the service. Arguments:
:uri => endpoint uri of the service. Required.
:version => 1 | 2
:envelope_namespace => Namespace of SOAP-envelope
:request_content_type => Content-Type of HTTP request.
You must supply either :version or both :envelope_namspace and :request_content_type. :version is simply a shortcut for default values.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/handsoap/service.rb', line 91 def self.endpoint(args = {}) @uri = args[:uri] || raise("Missing option :uri") if args[:version] soap_namespace = { 1 => 'http://schemas.xmlsoap.org/soap/envelope/', 2 => 'http://www.w3.org/2003/05/soap-envelope' } raise("Unknown protocol version '#{@protocol_version.inspect}'") if soap_namespace[args[:version]].nil? @envelope_namespace = soap_namespace[args[:version]] @request_content_type = args[:version] == 1 ? "text/xml" : "application/soap+xml" end @envelope_namespace = args[:envelope_namespace] unless args[:envelope_namespace].nil? @request_content_type = args[:request_content_type] unless args[:request_content_type].nil? if @envelope_namespace.nil? || @request_content_type.nil? raise("Missing option :envelope_namespace, :request_content_type or :version") end end |
.envelope_namespace ⇒ Object
105 106 107 |
# File 'lib/handsoap/service.rb', line 105 def self.envelope_namespace @envelope_namespace end |
.fire_on_create_document(doc) ⇒ Object
332 333 334 335 336 |
# File 'lib/handsoap/service.rb', line 332 def self.fire_on_create_document(doc) if @create_document_callback @create_document_callback.call doc end end |
.get_mapping(name) ⇒ Object
315 316 317 |
# File 'lib/handsoap/service.rb', line 315 def self.get_mapping(name) @mapping[name] if @mapping end |
.instance ⇒ Object
115 116 117 |
# File 'lib/handsoap/service.rb', line 115 def self.instance @@instance[self.to_s] ||= self.new end |
.logger=(io) ⇒ Object
80 81 82 |
# File 'lib/handsoap/service.rb', line 80 def self.logger=(io) @@logger = io end |
.map_method(mapping) ⇒ Object
Registers a simple method mapping without any arguments and no parsing of response.
This is deprecated
309 310 311 312 313 314 |
# File 'lib/handsoap/service.rb', line 309 def self.map_method(mapping) if @mapping.nil? @mapping = {} end @mapping.merge! mapping end |
.method_missing(method, *args) ⇒ Object
118 119 120 121 122 123 124 |
# File 'lib/handsoap/service.rb', line 118 def self.method_missing(method, *args) if instance.respond_to?(method) instance.__send__ method, *args else super end end |
.on_create_document(&block) ⇒ Object
Registers a block to call when a request document is created.
This is deprecated, in favour of #on_create_document
329 330 331 |
# File 'lib/handsoap/service.rb', line 329 def self.on_create_document(&block) @create_document_callback = block end |
.request_content_type ⇒ Object
108 109 110 |
# File 'lib/handsoap/service.rb', line 108 def self.request_content_type @request_content_type end |
.uri ⇒ Object
111 112 113 |
# File 'lib/handsoap/service.rb', line 111 def self.uri @uri end |
Instance Method Details
#debug(message = nil) ⇒ Object
:nodoc:
198 199 200 201 202 203 204 205 206 207 |
# File 'lib/handsoap/service.rb', line 198 def debug( = nil) #:nodoc: if @@logger if @@logger.puts() end if block_given? yield @@logger end end end |
#dispatch(doc, action) ⇒ Object
Send document and parses the response into a XmlQueryFront::XmlElement (XmlDocument)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/handsoap/service.rb', line 229 def dispatch(doc, action) on_before_dispatch headers = { "Content-Type" => "#{self.class.request_content_type};charset=UTF-8" } headers["SOAPAction"] = action unless action.nil? response = send_http_request(self.class.uri, doc.to_s, headers) # Start the parsing pipe-line. # There are various stages and hooks for each, so that you can override those in your service classes. xml_document = parse_soap_response_document(response.primary_part.body) soap_fault = parse_soap_fault(xml_document) # Is the response a soap-fault? unless soap_fault.nil? return on_fault(soap_fault) end # Does the http-status indicate an error? if response.status >= 400 return on_http_error(response) end # Does the response contain a valid xml-document? if xml_document.nil? return on_missing_document(response) end # Everything seems in order. on_response_document(xml_document) return SoapResponse.new(xml_document, response) end |
#invoke(action, options = { :soap_action => :auto }, &block) ⇒ Object
Creates an XML document and sends it over HTTP.
action is the QName of the rootnode of the envelope.
options currently takes one option :soap_action, which can be one of:
:auto sends a SOAPAction http header, deduced from the action name. (This is the default)
String sends a SOAPAction http header.
nil sends no SOAPAction http header.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/handsoap/service.rb', line 136 def invoke(action, = { :soap_action => :auto }, &block) # :yields: Handsoap::XmlMason::Element if action if .kind_of? String = { :soap_action => } end if [:soap_action] == :auto [:soap_action] = action.gsub(/^.+:/, "") elsif [:soap_action] == :none [:soap_action] = nil end doc = make_envelope do |body| body.add action end if block_given? yield doc.find(action) end dispatch(doc, [:soap_action]) end end |
#make_envelope ⇒ Object
Creates a standard SOAP envelope and yields the Body element.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/handsoap/service.rb', line 257 def make_envelope # :yields: Handsoap::XmlMason::Element doc = XmlMason::Document.new do |doc| doc.alias 'env', self.class.envelope_namespace doc.add "env:Envelope" do |env| env.add "*:Header" env.add "*:Body" end end self.class.fire_on_create_document doc # deprecated .. use instance method on_create_document(doc) if block_given? yield doc.find("Body") end return doc end |
#on_after_create_http_request(http_request) ⇒ Object
Hook that is called after the http_client is created.
You can override this to customize the http_client
168 169 |
# File 'lib/handsoap/service.rb', line 168 def on_after_create_http_request(http_request) end |
#on_before_dispatch ⇒ Object
Hook that is called before the message is dispatched.
You can override this to provide filtering and logging.
163 164 |
# File 'lib/handsoap/service.rb', line 163 def on_before_dispatch end |
#on_create_document(doc) ⇒ Object
Hook that is called when a new request document is created.
You can override this to add namespaces and other elements that are common to all requests (Such as authentication).
158 159 |
# File 'lib/handsoap/service.rb', line 158 def on_create_document(doc) end |
#on_fault(fault) ⇒ Object
Hook that is called if the dispatch returns a Fault.
Default behaviour is to raise the Fault, but you can override this to provide logging and more fine-grained handling faults.
See also: parse_soap_fault
186 187 188 |
# File 'lib/handsoap/service.rb', line 186 def on_fault(fault) raise fault end |
#on_http_error(response) ⇒ Object
Hook that is called if there is a HTTP level error.
Default behaviour is to raise an error.
178 179 180 |
# File 'lib/handsoap/service.rb', line 178 def on_http_error(response) raise HttpError, response end |
#on_missing_document(response) ⇒ Object
Hook that is called if the response does not contain a valid SOAP enevlope.
Default behaviour is to raise an error
Note that if your service has operations that are one-way, you shouldn’t raise an error here. This is however a fairly exotic case, so that is why the default behaviour is to raise an error.
195 196 197 |
# File 'lib/handsoap/service.rb', line 195 def on_missing_document(response) raise "The response is not a valid SOAP envelope" end |
#on_response_document(doc) ⇒ Object
Hook that is called when there is a response.
You can override this to register common namespaces, useful for parsing the document.
173 174 |
# File 'lib/handsoap/service.rb', line 173 def on_response_document(doc) end |
#parse_soap_fault(document) ⇒ Object
XmlDocument -> [Fault | nil]
281 282 283 284 285 286 |
# File 'lib/handsoap/service.rb', line 281 def parse_soap_fault(document) unless document.nil? node = document.xpath('/env:Envelope/env:Body/descendant-or-self::env:Fault', { 'env' => self.class.envelope_namespace }).first Fault.from_xml(node, :namespace => self.class.envelope_namespace) unless node.nil? end end |
#parse_soap_response_document(http_body) ⇒ Object
String -> [XmlDocument | nil]
273 274 275 276 277 278 279 |
# File 'lib/handsoap/service.rb', line 273 def parse_soap_response_document(http_body) begin Handsoap::XmlQueryFront.parse_string(http_body, Handsoap.xml_query_driver) rescue Handsoap::XmlQueryFront::ParseError => ex nil end end |
#send_http_request(uri, post_body, headers) ⇒ Object
Does the actual HTTP level interaction.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/handsoap/service.rb', line 209 def send_http_request(uri, post_body, headers) request = Handsoap::Http::Request.new(uri, :post) headers.each do |key, value| request.add_header(key, value) end request.body = post_body debug do |logger| logger.puts request.inspect end on_after_create_http_request(request) http = Handsoap::Http.drivers[Handsoap.http_driver] response = http.send_http_request(request) debug do |logger| logger.puts(response.inspect do |body| Handsoap.pretty_format_envelope(body).chomp end) end return response end |