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_client(http_client) ⇒ 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
414 415 416 417 418 419 420 421 |
# File 'lib/handsoap/service.rb', line 414 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.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/handsoap/service.rb', line 83 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
97 98 99 |
# File 'lib/handsoap/service.rb', line 97 def self.envelope_namespace @envelope_namespace end |
.fire_on_create_document(doc) ⇒ Object
428 429 430 431 432 |
# File 'lib/handsoap/service.rb', line 428 def self.fire_on_create_document(doc) if @create_document_callback @create_document_callback.call doc end end |
.get_mapping(name) ⇒ Object
411 412 413 |
# File 'lib/handsoap/service.rb', line 411 def self.get_mapping(name) @mapping[name] if @mapping end |
.instance ⇒ Object
107 108 109 |
# File 'lib/handsoap/service.rb', line 107 def self.instance @@instance[self.to_s] ||= self.new end |
.logger=(io) ⇒ Object
72 73 74 |
# File 'lib/handsoap/service.rb', line 72 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
405 406 407 408 409 410 |
# File 'lib/handsoap/service.rb', line 405 def self.map_method(mapping) if @mapping.nil? @mapping = {} end @mapping.merge! mapping end |
.method_missing(method, *args) ⇒ Object
110 111 112 113 114 115 116 |
# File 'lib/handsoap/service.rb', line 110 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
425 426 427 |
# File 'lib/handsoap/service.rb', line 425 def self.on_create_document(&block) @create_document_callback = block end |
.request_content_type ⇒ Object
100 101 102 |
# File 'lib/handsoap/service.rb', line 100 def self.request_content_type @request_content_type end |
.uri ⇒ Object
103 104 105 |
# File 'lib/handsoap/service.rb', line 103 def self.uri @uri end |
Instance Method Details
#debug(message = nil) ⇒ Object
:nodoc:
190 191 192 193 194 195 196 197 198 199 |
# File 'lib/handsoap/service.rb', line 190 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)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/handsoap/service.rb', line 219 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.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/handsoap/service.rb', line 128 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.
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/handsoap/service.rb', line 247 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_client(http_client) ⇒ Object
Hook that is called after the http_client is created.
You can override this to customize the http_client
160 161 |
# File 'lib/handsoap/service.rb', line 160 def on_after_create_http_client(http_client) end |
#on_before_dispatch ⇒ Object
Hook that is called before the message is dispatched.
You can override this to provide filtering and logging.
155 156 |
# File 'lib/handsoap/service.rb', line 155 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).
150 151 |
# File 'lib/handsoap/service.rb', line 150 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
178 179 180 |
# File 'lib/handsoap/service.rb', line 178 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.
170 171 172 |
# File 'lib/handsoap/service.rb', line 170 def on_http_error(response) raise "HTTP error #{response.status}" 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.
187 188 189 |
# File 'lib/handsoap/service.rb', line 187 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.
165 166 |
# File 'lib/handsoap/service.rb', line 165 def on_response_document(doc) end |
#parse_soap_fault(document) ⇒ Object
XmlDocument -> [Fault | nil]
271 272 273 274 275 276 |
# File 'lib/handsoap/service.rb', line 271 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]
263 264 265 266 267 268 269 |
# File 'lib/handsoap/service.rb', line 263 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.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/handsoap/service.rb', line 201 def send_http_request(uri, post_body, headers) request = Handsoap::Http::Request.new(uri) 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(&Handsoap.pretty_format_envelope) end return response end |