What is SOAP?
Simple Object Access ProtocolA protocol specification for exchanging sturctured information in theimplementation of WebServices that uses XML format and usuallyuses HTTP or SMTP for message negotiation.Allows for namespacingFlexibility
Parts of SOAPEnvelope - Required
Identifies the XML document as a SOAP message.Header - Optional
Passes along application level info that is processed by SOAPnodes along the way
Body - RequiredThe information on the message that you are trying to send
Fault - OptionalError and Status information
Example SOAP Request<?xml version="1.0"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <o: Security>... </o:Security> </soap:Header> <soap:Body> <m:GetStockPrice xmlns:m="http://www.example.org/stock"> <m:StockName>IBM</m:StockName> </m:GetStockPrice> </soap:Body></soap:Envelope>
WSDL & XSDWSDL
Describes the service and operations available for that service.Its about the functionality of the service
XSDDescribes the structure of the complex datatypes of the serviceIts about the sturcture of the objects (types, fields, restrictions likemax leghth)
They work together to give you a contract for the service
What Can We Use
Roll Your OwnPros:
You control all the details.Cons:
You control all the details.You are forced to think about lower level details.
JAXBJava Architecture for XML Binding
Java standard for binding XML schemas to Java classes. Allowsconverting Java objects to XML documents, and vice versa, basedon JAXB annotations on the corresponding Java classes.Pros:
It handles all the crufty work for you.Well tested
Cons:Doesnt generate the code from the wsdl for you.Annotations clutter up your code.
https://netbeans.org/kb/docs/websvc/jaxb.html
Apache CXF
CXF helps you build and develop services using frontendprogramming APIs, like JAX-WS and JAX-RS. These services canspeak a variety of protocols such as SOAP, XML/HTTP, RESTfulHTTP, or CORBA and work over a variety of transports such asHTTP, JMS or JBI.Pros:
Its an apache project!Wraps JAXBHides away the annotations for you in generated code.
Cons:Generates java
http://cxf.apache.org
ScalaXB
Eugene Yokota - @eed3si9nPros:
For the most part handles receiving faults pretty wellGenerates Scala that uses the cake pattern for implementationdetailsYou end up with case classes to use for the messages created
Cons:Not as active as some other open source projects.
http://scalaxb.org
ScalaXB and How it Works
Setting Up A Simple ProjectHas options for mvn, ivy, cli, and sbt
Pluginplugins.sbt
addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % "1.1.2")
build.sbtscalaxbSettings
sourceGenerators in Compile <+= scalaxb in Compile
packageName in scalaxb in Compile := "io.trent.periodic.soap"
dispatchVersion in scalaxb in Compile := "0.10.1"
libraryDependencies <+= (dispatchVersion in scalaxb in Compile){ dv => "net.databinder.dispatch" %% "dispatch-core" % dv}
File structurePlace your wsdl/xsdfiles
project/plugins.sbtbuild.sbtsrc/main/xsdsrc/main/wsdlsrc/main/scala
Using the callstrait PeriodicLookupServiceV1 { val service = (new PeriodictableSoap12Bindings with scalaxb.SoapClients with scalaxb.DispatchHttpClients {}).service}
Generated Methods// from target/src_managed// Generated by <a href="http://scalaxb.org/">scalaxb</a>.package io.trent.periodic
trait PeriodictableSoap { def getAtoms(): Either[scalaxb.Fault[Any], io.trent.periodic.GetAtomsResponse]
def getAtomicWeight(elementName: Option[String]): Either[scalaxb.Fault[Any], io.trent.periodic.GetAtomicWeightResponse]
def getAtomicNumber(elementName: Option[String]): Either[scalaxb.Fault[Any], io.trent.periodic.GetAtomicNumberResponse]
def getElementSymbol(elementName: Option[String]): Either[scalaxb.Fault[Any], io.trent.periodic.GetElementSymbolResponse]}
Clean it up a bittrait PeriodicLookupServiceV2 { private[this] val service = (new PeriodictableSoap12Bindings with scalaxb.SoapClients with scalaxb.DispatchHttpClients {}).service
def getAtoms() = { val faultOrAtoms = service.getAtoms() faultOrAtoms.right.map(faultToPeriodicTableFault) .left.map(atomResponseToElement) }
private[this] def faultToPeriodicTableFault(fault: Fault[Any]) = <mapping to our models> private[this] def atomResponseToElement(atoms: GetAtomsResponse) = <mapping to our models>}
Security Headertrait OurSoapClients extends SoapClients11 { httpClient: HttpClients => override lazy val soapClient = new WssSoapClient {}
trait OurSoapClient extends Soap11Client { override def requestResponse(body: NodeSeq, headers: NodeSeq, scope: NamespaceBinding, address: URI, webMethod: String, action: Option[URI]): Either[Soap11Fault[Detail], (NodeSeq, NodeSeq)] = { super.requestResponse(xmlWithHoistedNamespace, headers ++ securityHeader, ... ) }} lazy val securityHeader = <"xml for header">}
Security Header (cont.)trait PeriodicLookupServiceV3 { private[this] val service = (new PeriodictableSoap12Bindings with OuSoapClients with scalaxb.DispatchHttpClients {}).service
def getAtoms() = { // the request will contain our header now val faultOrAtoms = service.getAtoms() faultOrAtoms.right.map(faultToPeriodicTableFault) .left.map(atomResponseToElement) }
private[this] def faultToPeriodicTableFault(fault: Fault[Any]) = <mapping to our models> private[this] def atomResponseToElement(atoms: GetAtomsResponse) = <mapping to our models>}
Pitfalls We Have EncounteredSax Parsing Errors
Happens when the service you are connected to does not adhereto the wsdl that you are using
TimeoutsWe ended up writing a nice little wrapper around API requests tocatch the timeoutErrors and handle them appropriately
We're HiringTalk to one of the guys here from bannobanno.com/jobs