Presentation on SOAP and C++ for the January 2002 ACCU meeting
by Kimberly Nicholls, Rogue Wave Software (nicholls@roguewave.com)

SOAP and C++

•      What is SOAP?

•      Who cares about SOAP?

•      Why is SOAP useful?

•      What does SOAP look like?

•      C++ Examples

 

What is SOAP?

SOAP = Simple Object Access Protocol

 

From the spec: (http://www.w3.org/TR/SOAP/)

 

"SOAP is a lightweight protocol for exchange of information in a decentralized, distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined data types, and a convention for representing remote procedure calls and responses. "

 

What SOAP isn’t

•      The spec doesn’t say anything about

•     Language for applications

•    Use any language you want

•     Transport mechanism

•    Can be HTTP, but also SMTP, sockets…

•     Platform

•    Messages are plain text

•     Security

•     Transactions

•    Extensible through headers

 

SOAP and existing protocols

•      SOAP builds on top of existing, well-understood mechanisms

•     Don’t need to re-architect everything

•      Standard protocol any application can use to communicate with any other application

•     Can replace custom adapters with a SOAP interface

•     Analogy: a SOAP client is like a web browser for applications

 

SOAP history

•      First spec drafted in 1998 by Dave Winer, Microsoft, and DevelopMentor

•      Delayed by Microsoft internal politics, so Dave Winer released a subset, XML-RPC

•      Late 1999: first spec with SOAP name

•     Used types from XML Schema

•      July 2001: SOAP 1.2 working draft

•     XML schema is stable

 

Who cares about SOAP?

Almost everyone:

•      Microsoft

•     “Microsoft SOAP Toolkit 2.0 provides a flexible framework to build scalable Web services for various intranet and Internet solutions”

•      Sun

•     “Forte for Java IDE Adds SOAP and WSDL Support”  12/7/01

•      Oracle

•     Oracle9i Web Services, Oracle9i Jdeveloper

•      IBM

•     Application Server v.4 for zOS, OS/390 and iSeries will support Web services

•      Apache

•     Apache SOAP provides server-side infrastructure for deploying, managing and running SOAP enabled services.

 

 

Why is SOAP useful?

•      Covers some of the same functionality as

•     DCOM – Windows only

•     RMI – Java only

•     CORBA – incompatible ORBs

 

•      Consistent interface across platforms, object models, or internal protocols

•     On  top of existing applications, not replacing them

•     Can replace proprietary interfaces

 

•      Loosely coupled communication

•      Structured way to make remote procedure calls

 

Web services

•      Software components accessible via a standard interface over the web

•      Analogy: HTTP to publish data, Web services to publish applications

•      Use SOAP messages to make requests and receive responses

•      Examples:

•     Internal

•    Supply chain optimization

•    New employee workflow

•     External

•    Currency converter

•    Zip code lookup

•    Credit card validation

•     More samples at http://www.xmethods.com

 

When to use web services

•      Transfer of data between systems

•      Publish services for use by partners or clients

•      Communication across firewalls

•     Many firewalls already allow HTTP traffic

 

What SOAP looks like

•      All SOAP messages are encoded using XML

•      A message consists of

•     Mandatory envelope

•     Optional header

•     Mandatory body

 

SOAP Envelope 

•      Element name = Envelope

•      Must be associated with the SOAP envelope namespace: http://schemas.xmlsoap.org/soap/envelope/

•      May contain namespace declarations

•      May contain namespace-qualified attributes

•      May contain additional namespace-qualified sub-elements following the Body element

 

<SOAP-ENV:Envelope

   xmlns:SOAP-ENV=

   "http://schemas.xmlsoap.org/soap/envelope/">

...

</SOAP-ENV:Envelope>

 

SOAP Header

•      Element name = Header

•      If present, the header must be the first immediate child of the Envelope element

•      May contain a set of namespace-qualified immediate child entries

•      Use a header to extend SOAP functionality using metadata here

•     User credentials

•     Session information

•     Transaction id

•      SOAP defines two attributes

•     mustUnderstand

•    If set to 1, recipient must understand the element or send back a fault

•     actor

•    A message may move through a series of nodes before reaching its final destination

•    Use this to specify who should process the header element

 

SOAP Header example

<SOAP-ENV:Header>

  <rw:ServiceName SOAP-ENV:mustUnderstand="1">WebData</rw:ServiceName>

  <rw:ReloadServiceDescription

  SOAP-ENV:mustUnderstand= "1">true</rw:ReloadServiceDescription>

</SOAP-ENV:Header>

 

SOAP Body

•      Element name = Body

•      Must be an immediate child of the Envelope element

•      Must immediately follow the Header element if present

•      May contain a set of immediate child elements, optionally namespace-qualified

•      Fault element used to report error messages

•     <faultcode> -- any fully qualified name; predefined soapenv:Client, soapenv:Server

•     <faultstring> -- human readable error message

•     <detail> -- optional; put more error information as child elements

 

SOAP Body example

<SOAP-ENV:Body>

 <urn:ToEuro xmlns:urn="Euro-IEuro">

  <Currency SOAP-ENV:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/">FRF</Currency>

  <Amount SOAP-ENV:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/">100</Amount>

  </urn:ToEuro>

</SOAP-ENV:Body>

 

 

SOAP Body Fault example

<SOAP-ENV:Body>

 <SOAP-ENV:Fault>

  <SOAP-ENV:faultcode>SOAP-ENV:Server</SOAP-ENV:faultcode>

  <SOAP-ENV:faultstring>No such method XToEuro</SOAP-ENV:faultstring>

 </SOAP-ENV:Fault>

</SOAP-ENV:Body>

 

SOAP Encoding

•      SOAP encoding rules define a serialization mechanism for exchanging application-defined data types

•      Superset of XML Schema types

•      Simple types – same as XML Schema

•     Int, float, enumerations, etc.

 

 

SOAP Encoding -- structs

•      A Struct is an XML element that contains sub-elements

•      Names of elements are significant

•      Order of elements is not significant

 

<e:Book>

   <author>Henry Ford</author>

   <preface>Prefatory text</preface>

   <intro>This is a book.</intro>

</e:Book>

 

SOAP Encoding -- arrays

•      An Array is an XML element with a SOAP-ENC:arrayType attribute whose value begins with

•     type[number] (single-type array)

•     ur-type[number] (multi-type array)

•      Order of array elements is significant

•      Names of elements are not significant

•      Arrays can

•     Contain multiple types

•     Be multi-dimensional

•     Be partially transmitted

•     Be sparse

 

<myFavoriteNumbers

  SOAP-ENC:arrayType="xsd:int[2]">

   <number>3</number>

   <number>4</number>

</myFavoriteNumbers>

 

SOAP & HTTP

•      SOAP does not depend on HTTP, but HTTP is a natural fit

•     Request-response pattern

•      Must use text/xml MIME type when including SOAP in HTTP messages

•      Use SOAPAction HTTP header to indicate what to do with the request

•     If empty, send to the request URI

•     Can be used by firewalls to filter requests

•     Action determined by application

•      If request was processed

•     Return HTTP 2xx

•     Include a SOAP message with the response

•      If an error occurs

•     Return HTTP 500 Internal Server Error

•     Include a SOAP message containing a SOAP Fault

 

SOAP over HTTP

request

POST /StockQuote HTTP/1.1

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

SOAPAction: "http://electrocommerce.org/abc#MyMessage"

 

<SOAP-ENV:Envelope...

</SOAP-ENV:Envelope>

 

response

HTTP/1.1 200 OK

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

<SOAP-ENV:Envelope...

</SOAP-ENV:Envelope>

 

SOAP and RPC

•      The SOAP spec (section 7) defines a convention for remote procedure calls and responses

•      Method calls and responses are carried in the Body element

 

Calling a method

•      The method invocation is a struct named method-name containing an element for each parameter

•      Parameters must appear in the same order as the method signature

 

<urn:ToEuro xmlns:urn="Euro-IEuro">

  <Currency>FRF</Currency>

  <Amount>100</Amount>

</urn:ToEuro>

 

•      Method name is ToEuro

•      Parameters are Currency, Amount

 

Receiving a response

•      The method invocation is a struct containing an element for the return value followed by return parameters

•      Parameters must appear in the same order as the method signature

•      The name of the return value element is not significant

•     Convention: name it method-nameReponse

 

<NS1:ToEuroResponse xmlns:NS1="urn:Euro-IEuro">

<return xsi:type="xsd:double"> 15.244901723741</return>

</NS1:ToEuroResponse>

 

SOAP and RPC

•      To make a procedure call, you need to know

•     URI of the target object

•     Method namespace

•     Method name

•     Method parameters

 

Finding a web service: UDDI

•      UDDI = Universal Description, Discovery, and Integration

•      Version 1 Draft published in September 2000

•      The UDDI Business Registry is intended to serve as a global, all-inclusive listing of businesses and their services

•      Search registry node to find web services

•     Programmatic and web interfaces

•     More than just SOAP interfaces; also CORBA, Java RMI, COM+, etc.

•      A tModel and a Binding Template point to specifications that describe the web service interface.

•     UDDI does not dictate any specific technology or methodology to describe a web service interface

•     BindingTemplate – contains address and option info

•     tModel -- metadata about a specification; name, publisher, reference to specification

 

Describing a web service: WSDL

•      WSDL = Web Services Description Language

•      XML grammar for describing Web Service

•     Interfaces

•     Supported protocols

•     Location

•      Use a WSDL document to find what you need to access a web service

 

 

WSDL contents

•      A service contains one or more ports

•      Each port references a binding

•      Each binding references a portType, the portType’s operations, and the messages that make up each operation

•      Each operation has an input and an output message

•      Each message has zero or more typed parts

 

WSDL elements: service

•      A service is exposed via a port

•      The port specifies a network address and binding

•      A single service can be exposed via multiple ports

 

<service xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEuroservice">

  <port xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEuroPort" binding="targetNamespace:IEurobinding">

    <soap:address location="http://www.drbob42.co.uk/cgi-bin/Euro42/soap/IEuro"></soap:address>

  </port>

</service>

 

•      The location attribute specifies the URI of the target object

 

WSDL elements: binding

•      A binding specifies the protocol and the input/output format

•      The name attribute of the operation element specifies the  method name

•      The namespace attribute of the body element specifies the method namespace

 

WSDL elements: binding

<binding xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEurobinding" type="targetNamespace:IEuro">

 <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"></soap:binding>

 <operation xmlns="http://schemas.xmlsoap.org/wsdl/" name="FromEuro">

  <soap:operation soapAction="urn:Euro-IEuro#FromEuro"> </soap:operation>

  <input>

   <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Euro-IEuro"></soap:body>

  </input>

  <output>

   <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Euro-IEuro"></soap:body>

  </output>

 </operation>

</binding>

 

WSDL elements: portType

•      A portType is a group of operations (like an interface)

•      The name attribute of the operation element contains the method name

 

<portType xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEuro">

 <operation xmlns="http://schemas.xmlsoap.org/wsdl/" name="FromEuro">

  <input message="targetNamespace:FromEuroRequest"></input>

  <output message="targetNamespace:FromEuroResponse"></output>

 </operation>

</portType>

 

WSDL elements: message

•       The message element contains part elements describing each parameter (name and type)

 

<message xmlns="http://schemas.xmlsoap.org/wsdl/" name="FromEuroRequest">

 <part xmlns="http://schemas.xmlsoap.org/wsdl/" name="Currency" type="xs:string"></part>

 <part xmlns="http://schemas.xmlsoap.org/wsdl/" name="Amount" type="xs:double"></part>

</message>

<message xmlns="http://schemas.xmlsoap.org/wsdl/" name="FromEuroResponse">

 <part xmlns="http://schemas.xmlsoap.org/wsdl/" name="return" type="xs:double"></part>

</message>

 

Example

•      Rogue Wave Web Services module provides a set of abstractions for building and parsing SOAP messages

•      Built on top of XML Streaming module for serializing C++ classes to XML

•      Rogue Wave Internet Protocols module provides a set of classes for working with HTTP

•      Uses the Xerces parser from the Apache group

 

Example page 1: setup

int main(int argc, char *argv[])

{

  RWWinSockInfo winsock;

 

  if (argc < 2) {

    cerr << "usage: soap_simple currency amt" << endl;

    return -1;

  }

 

  RWCString paramVal = argv[1];

  long param2Val = atoi(argv[2]);

 

Example page 2: create SOAP message

  RWXmlNamespace euroNs("urn","Euro-IEuro");

 

  RWSoapBody soapBody;

  RWSoapEntry method(RWXmlName("ToEuro", euroNs));

 

  RWSoapSimpleType param =     RWSoapSimpleType::create(RWXmlName("Currency"),

      paramVal);

  RWSoapSimpleType param2 =     RWSoapSimpleType::create(RWXmlName("Amount"),

      param2Val);

 

  method.appendChild(param);

  method.appendChild(param2);

  soapBody.appendEntry(method);

  RWSoapMessage soapMsg(soapBody);

 

Example: what happened?

•      Sent this message:

 

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  <SOAP-ENV:Body>

    <urn:ToEuro xmlns:urn="Euro-IEuro">

      <Currency SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">FRF</Currency>

      <Amount SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">100</Amount>

    </urn:ToEuro>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

Example page 3: create HTTP request

  // create the HTTP client and send the message

  RWCString host = "www.drbob42.co.uk";

  long port = 80;

 

  RWHttpHeaderList headers;

 

  headers.addHeader(RWHttpGenericHeader(

      "Content-Type","text/xml; charset=utf-8"));

  headers.addHeader(RWHttpGenericHeader("SOAPAction",

      "urn:Euro-IEuro#ToEuro"));

 

  RWHttpRequestStringBody requestBody(soapMsg.asString());

 

Example page 4: send request, get response

  RWHttpRequest request(RWHttpRequest::Post,

          "/cgi-bin/Euro42/soap/IEuro",

          headers,

          requestBody);

  RWHttpClient client = RWHttpSocketClient::make();

  RWCString replyBody;

  try {

        client.connect(host, port);

      client.submit(request);

      RWHttpReply reply = client.getReply(5000);  

      if (reply.is2XX())

          replyBody = reply.getBody();

  } catch(const RWxmsg& msg) {

    cerr << "error: " << msg.why() << endl;

  } 

 

Example: what came back?

•      Received this repsonse:

 

HTTP/1.1 200 OK

Content:

Content-Length: 498

Content-Type: text/xml

Date: Fri, 04 Jan 2002 18:21:29 GMT

Server: Apache/1.3.19 (Unix) mod_bwlimited/0.8 PHP/4.0.5 mod_log_bytes/0.2 mod_frontpage/3.0.4.3 mod_ssl/2.8.1 OpenSSL/0.9.6

 

 

Example: what came back?

<?xml version="1.0"?>

 

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">

<SOAP-ENV:Body SOAP-ENC:encodingStyle="http://schemas.xmlsoap.org/soap/envelope/">

<NS1:ToEuroResponse xmlns:NS1="urn:Euro-IEuro">

<return xsi:type="xsd:double">15.244901723741</return>

</NS1:ToEuroResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

Example page 5: process the reponse

  RWSoapMessage soapRet;

  double value;

 

  soapRet.extract(replyBody.data());

  RWXmlNamespace euroNs2("NS1","urn:Euro-IEuro");

  RWSoapEntry soapMethod =     *(soapRet.getSoapBody().findEntry(

      RWXmlName("ToEuroResponse", euroNs2)));

  RWSoapSimpleType soapRetVal =

       static_cast<RWSoapSimpleType &>     (*(soapMethod.findChild(RWXmlName(("return")))));

  soapRetVal.extract(value);

  cout << "value = " << value << endl;

  return 0;

}

 

Next steps

•      SOAP messages can do more than just return a number

•      Any object can be serialized to XML and included in a SOAP message

•      Pass objects between systems

 

Sending an object: composite type

struct Contract {

  long bid;

  RWCString company;

  RWDateTime closingDate;

};

…

RWSoapEntry method(RWXmlName("RegisterBid", myNs));

RWSoapCompositeType contract(RWXmlName("Bid", myNs));

contract.appendChild(RWSoapSimpleType::create(

   RWXmlName("bid"), c.bid));

contract.appendChild(RWSoapSimpleType::create(

   RWXmlName("company"), c.company));

contract.appendChild(RWSoapSimpleType::create(

   RWXmlName("closingDate"), c.closingDate));

method.appendChild(contract);

body.appendEntry(method);

RWSoapMessage soapMsg(body);

 

Sending an object: composite type

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  <SOAP-ENV:Body>

    <app:RegisterBid xmlns:app="http:://my.app.com/ns">

      <app:Bid SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

        <bid>5000</bid>

        <company>WidgetTron</company>

        <closingDate>2002-12-31T08:00:00Z</closingDate>

      </app:Bid>

    </app:RegisterBid>

  </SOAP-ENV:Body>

 

</SOAP-ENV:Envelope>

Sending an object: set up serialization

template <class T>

   void registerXMLStreamTypeWithSoap(const T& t)

{

  // Create functors

  static RWTFunctorR1<string,T const &> outFunctor =

    rwtMakeFunctorR1((string(*)(T const &))0,

    rwtXMLObjectOutputStreamSerializer<T>);

  // Register functors

  RWXmlNamespace rwName = RWXmlNamespace(RWXmlObjectStreamCommon::rwNamespace,                                       RWXmlObjectStreamCommon::rwNamespaceValue);

  RWSoapEncodingRegistry<T>& reg = RWSoapEncodingRegistry<T>::getRegistry();

  reg.registerSerializer(outFunctor, RWXmlName(RWXmlObjectStreamCommon::rwStreamToLocalStringType(rwStreamType(t)),rwName),

       RWXmlObjectStreamCommon::rwEncodingNamespaceValue);

}

 

Sending an object: create the message

residential* real1 = new residential("1980 Main St. Corvallis, Oregon","50X100",1200);

…

// Register XMLStreams as the serializer for a listing

registerXMLStreamTypeWithSoap(real1);

 

// Create a soap simple type with type and namespace

RWSoapSimpleType listingValue = createSoapSimpleType(RWXmlName("listing",

      RWXmlNamespace()),real1);

RWSoapEntry addListing(RWXmlName("addListing", RWXmlNamespace()));

addListing.appendChild(agentName);

addListing.appendChild(listingValue);

soapBody.appendEntry(addListing);

RWSoapMessage soapMsg(soapBody);

Sending an object: message contents 1

 <addListing>

   <agent SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">George</agent>

   <listing xmlns:rw="http://www.roguewave.com/xmlstream"     xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" SOAP-ENV:encodingStyle="http://www.roguewave.com/xmlstream/encoding" xsi:type="rw:object">

  &lt;rw:object rw:class="residential" ID="I1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:rw="http://www.roguewave.com/xmlstream"&gt;

    &lt;rw:member rw:name="address" xsd:type="xsd:string"&gt;1980 Main St. Corvallis, Oregon&lt;/rw:member&gt;

    &lt;rw:member rw:name="size" xsd:type="xsd:string"&gt;50X100&lt;/rw:member&gt;

    &lt;rw:member rw:name="footage" xsd:type="xsd:long"&gt;1200&lt;/rw:member&gt;

   

Sending an object: message contents 2

   &lt;rw:member rw:name="rooms" xsd:type="rw:sequence"&gt;

      &lt;rw:sequence rw:count="3" rw:element-type="rw:nested_object"&gt;

        &lt;rw:seq-element rw:pos="0"&gt;

          &lt;rw:nested_object rw:class="residential::room"&gt;

            &lt;rw:member rw:name="type" xsd:type="xsd:string"&gt;living&lt;/rw:member&gt;

            &lt;rw:member rw:name="size" xsd:type="xsd:string"&gt;18x20&lt;/rw:member&gt;

          &lt;/rw:nested_object&gt;

        &lt;/rw:seq-element&gt;

        &lt;rw:seq-element rw:pos="1"&gt;

          &lt;rw:nested_object rw:class="residential::room"&gt;

            &lt;rw:member rw:name="type" xsd:type="xsd:string"&gt;bedroom&lt;/rw:member&gt;

            &lt;rw:member rw:name="size" xsd:type="xsd:string"&gt;14x16&lt;/rw:member&gt;

          &lt;/rw:nested_object&gt;

        &lt;/rw:seq-element&gt;

      &lt;/rw:sequence&gt;

   &lt;/rw:member&gt;

  &lt;/rw:object&gt;

  </listing>

</addListing>

       

URLs

SOAP spec http://www.w3.org/TR/SOAP/
UDDI http://www.uddi.org
WSDL spec http://www.w3.org/TR/wsdl
Xerces http://xml.apache.org/xerces-c/index.html
public web services http://www.xmethods.com/
SOAPWare.org http://www.soapware.org/
Rogue Wave white paper http://www.roguewave.com/products/whitepapers.cfm?paper=spsoap
Rogue Wave webcast: "Extending C++ Applications to the Internet"
  Tuesday, January 15, 8:00am PST
  http://www.roguewave.com/corp/events/learnonline/index.cfm?event=extend2