Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented SOAP endpoint

  • Loading branch information...
commit 0f76bcc3f573e5893af40bc8d1e9807b6d57c3c5 1 parent 009c915
Mark Kremer authored
63 app/controllers/echo_service_controller.rb
View
@@ -1,11 +1,74 @@
+require 'soap_fault'
+
class EchoServiceController < ApplicationController
Mime::Type.register "application/wsdl+xml", :wsdl
+ Mime::Type.unregister :xml
+ Mime::Type.register "text/xml", :xml
+ # Service the WSDL
def wsdl
@url = ENV['BASE_URL'] || "http://localhost:#{request.port}"
respond_to :wsdl
end
+ # This is the SOAP endpoint
def endpoint
+ soap_message = Nokogiri::XML(request.body.read)
+ process_soap_headers(soap_message)
+ soap_body = extract_soap_body(soap_message)
+ validate_soap_body(soap_body)
+ # Attempt to determine the SOAP operation and process it
+ self.send(soap_operation_to_method(soap_body), soap_body)
+ rescue StandardError => e
+ # If any exception was raised generate a SOAP fault, if there is no
+ # fault_code present then default to fault_code Server (indicating the
+ # message failed due to an error on the server)
+ @fault_code = e.respond_to?(:fault_code) ? e.fault_code : "Server"
+ @fault_string = e.message
+ render :fault, :status => 500
+ end
+
+ private
+
+ def process_soap_headers(soap_message)
+ # The EchoService isn't programmed to handle particular SOAP headers,
+ # any SOAP headers with mustUnderstand="1" will result in a SOAP fault
+ # with fault_code MustUnderstand (indicating that the EchoService
+ # couldn't process a mandatory SOAP header)
+ raise(SoapFault::MustUnderstandError, "SOAP Must Understand Error", "MustUnderstand") if soap_message.root.at_xpath('//soap:Header/*[@soap:mustUnderstand="1" and not(@soap:actor)]', 'soap' => 'http://schemas.xmlsoap.org/soap/envelope/')
+ end
+
+ def extract_soap_body(soap_message)
+ # Extract the SOAP body from SOAP envelope using XSLT
+ xslt = Nokogiri::XSLT(File.read("#{Rails.root}/lib/soap_body.xslt"))
+ xslt.transform(soap_message)
+ end
+
+ def validate_soap_body(soap_body)
+ # Validate the content of the SOAP body using the XML schema that is used
+ # within the WSDL
+ xsd = Nokogiri::XML::Schema(File.read("#{Rails.root}/public/echo_service.xsd"))
+ errors = xsd.validate(soap_body).map{|e| e.message}.join(", ")
+ # If the content of the SOAP body does not validate generate a SOAP fault
+ # with fault_code Client (indicating the message failed due to a client
+ # error)
+ raise(SoapFault::ClientError, errors) unless errors == ""
+ end
+
+ # Detect the SOAP operation based on the root element in the SOAP body
+ def soap_operation_to_method(soap_body)
+ method = soap_body.root.name.sub(/Request$/, '').underscore.to_sym
+ end
+
+ # Echo operation, send back the message given
+ def echo(soap_body)
+ @message = soap_body.root.at_xpath('//echo:Message/text()', 'echo' => 'http://www.without-brains.net/echo').to_s
+ render :echo
+ end
+
+ # ReverseEcho operation, send back the message given in reverse
+ def reverse_echo(soap_body)
+ @message = soap_body.root.at_xpath('//echo:Message/text()', 'echo' => 'http://www.without-brains.net/echo').to_s.reverse!
+ render :reverse_echo
end
end
7 app/views/echo_service/echo.builder
View
@@ -0,0 +1,7 @@
+xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:echo" => "http://www.without-brains.net/echo") do
+ xml.SOAP :Body do
+ xml.echo :EchoResponse do
+ xml.echo(:Message, @message)
+ end
+ end
+end
8 app/views/echo_service/fault.builder
View
@@ -0,0 +1,8 @@
+xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/") do
+ xml.SOAP :Body do
+ xml.SOAP :Fault do
+ xml.faultcode "SOAP:#{@fault_code}"
+ xml.faultstring @fault_string
+ end
+ end
+end
7 app/views/echo_service/reverse_echo.builder
View
@@ -0,0 +1,7 @@
+xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:echo" => "http://www.without-brains.net/echo") do
+ xml.SOAP :Body do
+ xml.echo :ReverseEchoResponse do
+ xml.echo(:Message, @message)
+ end
+ end
+end
6 lib/soap_body.xslt
View
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+ <xsl:template match="/">
+ <xsl:copy-of select="//soap:Body/*[1]"/>
+ </xsl:template>
+</xsl:transform>
5 lib/soap_fault.rb
View
@@ -0,0 +1,5 @@
+module SoapFault
+end
+
+require_relative 'soap_fault/client_error'
+require_relative 'soap_fault/must_understand_error'
7 lib/soap_fault/client_error.rb
View
@@ -0,0 +1,7 @@
+module SoapFault
+ class ClientError < StandardError
+ def fault_code
+ "Client"
+ end
+ end
+end
7 lib/soap_fault/must_understand_error.rb
View
@@ -0,0 +1,7 @@
+module SoapFault
+ class MustUnderstandError < StandardError
+ def fault_code
+ "MustUnderstand"
+ end
+ end
+end
12 public/echo_service.xsd
View
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="http://www.without-brains.net/echo" xmlns="http://www.without-brains.net/echo" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified">
+ <xs:complexType name="EchoMessageType">
+ <xs:sequence>
+ <xs:element name="Message" type="xs:string" minOccurs="1" />
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="EchoRequest" type="EchoMessageType"/>
+ <xs:element name="EchoResponse" type="EchoMessageType"/>
+ <xs:element name="ReverseEchoRequest" type="EchoMessageType"/>
+ <xs:element name="ReverseEchoResponse" type="EchoMessageType"/>
+</xs:schema>
Please sign in to comment.
Something went wrong with that request. Please try again.