
Using WSDL
**********

*WSDL* (Web Service Definition Language) is an *XML* based document
which described a set of Web Services either based on *SOAP* or
*XML/RPC*. By using a *WSDL* document it is possible to describe, in a
formal way, the interface to any Web Services. The *WSDL* document
contains the end-point (URL to the server offering the service), the
*SOAPAction* (needed to call the right routine), the procedure names
and a description of the input and output parameters.

*AWS* provides two tools to work with *WSDL* documents:

*ada2wsdl*

   which creates a *WSDL* document from an Ada package spec.

*wsdl2aws*

   which create the interfaces to use a Web Service or to implement
   Web Services. With this tool the *SOAP* interface is completely
   abstracted out, users will deal only with *Ada* API. All the *SOAP*
   marshaling will be created automatically.


Creating WSDL documents
=======================

Note that this tool is based on *ASIS*.


Using ada2wsdl
--------------

*ada2wsdl* can be used on any Ada spec file to generated a *WSDL*
document. The Ada spec is parsed using *ASIS*.

The simplest way to use it is:

   $ ada2wsdl simple.ads

Given the following Ada spec file:

   package Simple is
      function Plus (Value : in Natural) return Natural;
   end Simple;

It will generate the following *WSDL* document:

   <?xml version="1.0" encoding="UTF-8"?>
   <definitions name="Simple"
    targetNamespace="urn:aws:Simple"
    xmlns:tns="urn:aws:Simple"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <message name="Plus_Request">
      <part name="Value" type="xsd:int"/>
    </message>

    <message name="Plus_Response">
      <part name="Result" type="xsd:int"/>
    </message>

    <portType name="Simple_PortType">
      <operation name="Plus">
      <input message="tns:Plus_Request"/>
      <output message="tns:Plus_Response"/>
      </operation>
    </portType>

    <binding name="Simple_Binding" type="tns:Simple_PortType">
      <soap:binding style="rpc"
       transport="http://schemas.xmlsoap.org/soap/http"/>

      <operation name="Plus">
        <soap:operation soapAction="Plus"/>
          <input>
            <soap:body
             encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             namespace="urn:aws:Simple"
             use="encoded"/>
         </input>
         <output>
           <soap:body
            encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
            namespace="urn:aws:Simple"
            use="encoded"/>
         </output>
       </operation>
    </binding>

    <service name="Simple_Service">
      <port name="Simple_Port" binding="tns:Simple_Binding">
        <soap:address location="http://.../"/>
      </port>
    </service>
   </definitions>

The value of the *name* attribute in the *description* node is the
name of the *WSDL* document (the name of the Ada spec package). On the
*portType* section we have the description of the Ada **Plus**
function. Something important to note is that in Ada a function does
not have a named return parameter, "ada2wsdl" use **Result** for the
response. Both the input and output parameter are mapped to *SOAP*
*xsd:int* type.

Note that the *SOAP* address generated by default (http://.../) must
be edited manually or specified using "ada2wsdl"'s -a option.

This is of course a very simple example. *ada2wsdl* does support lot
more complex specs and will map Ada records, arrays, enumerations,
derived types to a corresponding *XML* schema definition. See section
below for a description of the mapping.


Ada mapping to WSDL
-------------------

*ada2wsdl* parse Ada records, arrays, derived types, enumerations,
procedures and functions and generate the corresponding *WSDL*
document. In this section we describe the mapping between Ada and
*WSDL*.

*Integer*
   Mapped to **xsd:int**.

*Float*
   Mapped to **xsd:float**.

*Long_Float*
   Mapped to **xsd:double**

*Long_Long_Float*
   Mapped to **xsd:double**, not supported by SOAP, mapped for
   convenience but precision cannot be guaranteed.

*Boolean*
   Mapped to **xsd:boolean**

*String*
   Mapped to **xsd:string**

*Unbounded_String*
   Mapped to **xsd:string**, note that Unbounded_String should be used
   only inside a record for full interoperability. This is a current
   limitation.

*Character*
   Mapped to a Character schema definition:

      <simpleType name="Character">
        <restriction base="xsd:string">
          <length value="1"/>
        </restriction>
      </simpleType>}

*SOAP.Utils.SOAP_Base64*
   Mapped to **xsd:base64Binary**. *SOAP.Utils.SOAP_Base64* is a
   subtype of string which is is recognized by *ada2wsdl* to generate
   the proper SOAP type.

*SOAP.Types.Byte*
   Mapped to **xsd:byte**. *SOAP.Types.Byte* is a type which is
   recognized by *ada2wsdl* to generate the proper SOAP type.

*SOAP.Types.Short*
   Mapped to **xsd:short**. *SOAP.Types.Short* is a type which is
   recognized by *ada2wsdl* to generate the proper SOAP type.

*SOAP.Types.Long*
   Mapped to **xsd:long**. *SOAP.Types.Long* is a type which is
   recognized by *ada2wsdl* to generate the proper SOAP type.

*SOAP.Types.Unsigned_Byte*
   Mapped to **xsd:unsignedByte**. *SOAP.Types.Unsigned_Byte* is a
   type which is recognized by *ada2wsdl* to generate the proper SOAP
   type.

*SOAP.Types.Unsigned_Short*
   Mapped to **xsd:unsignedShort**. *SOAP.Types.Unsigned_Short* is a
   type which is recognized by *ada2wsdl* to generate the proper SOAP
   type.

*SOAP.Types.Unsigned_Int*
   Mapped to **xsd:unsignedInt**. *SOAP.Types.Unsigned_Int* is a type
   which is recognized by *ada2wsdl* to generate the proper SOAP type.

*SOAP.Types.Unsigned_Long*
   Mapped to **xsd:unsignedLong**. *SOAP.Types.Unsigned_Long* is a
   type which is recognized by *ada2wsdl* to generate the proper SOAP
   type.

*Derived types*
   Mapped to a type schema definition:

      type Number is new Integer;

   is defined as:

      <simpleType name="Number" targetNamespace="http://soapaws/WSDL_C_pkg/">
        <restriction base="xsd:int"/>
      </simpleType>

*User's types*
   Mapped to a type schema definition:

      type Small is range 1 .. 10;

   is defined as:

      <simpleType name="Small" targetNamespace="http://soapaws/WSDL_C_pkg/">
        <restriction base="xsd:byte"/>
      </simpleType>}

*Enumerations*
   Mapped to an enumeration schema definition. For example:

      type Color is (Red, Green, Blue);

   is defined as:

      <simpleType name="Color">
        <restriction base="xsd:string">
          <enumeration value="Red"/>
          <enumeration value="Green"/>
          <enumeration value="Blue"/>
        </restriction>
      </simpleType>

*Records*
   Mapped to a struct schema definition. For example:

      type Rec is record
         A : Integer;
         B : Float;
         C : Long_Float;
         D : Character;
         E : Unbounded_String;
         F : Boolean;
      end record;

   is defined as:

      <complexType name="Rec">
        <all>
          <element name="A" type="xsd:int"/>
          <element name="B" type="xsd:float"/>
          <element name="C" type="xsd:double"/>
          <element name="D" type="tns:Character"/>
          <element name="E" type="xsd:string"/>
          <element name="F" type="xsd:boolean"/>
        </all>
      </complexType>

*Arrays*
   Mapped to an array schema definition. For example:

      type Set_Of_Rec is array (Positive range <>) of Rec;

   is defined as:

      <complexType name="Set_Of_Rec">
        <complexContent>
          <restriction base="soap-enc:Array">
            <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:Rec[]"/>
          </restriction>
        </complexContent>
      </complexType>

*Array inside a record*
   This part is a bit delicate. A record field must be constrained but
   a *SOAP* arrays is most of the time not constrained at all. To
   support this *AWS* use a safe access array component. Such a type
   is built using a generic runtime support package named
   *SOAP.Utils.Safe_Pointers*. This package implements a reference
   counter for the array access and will release automatically the
   memory when no more reference exists for a given object.

   For example, let's say that we have an array of integer that we
   want to put inside a record:

      type Set_Of_Int is array (Positive range <>) of Integer;

   The first step is to create the safe array access support:

      type Set_Of_Int_Access is access Set_Of_Int;

      package Set_Of_Int_Safe_Pointer is
        new SOAP.Utils.Safe_Pointers (Set_Of_Int, Set_Of_Int_Access);

   Note that the name *Set_Of_Int_Safe_Pointer*
   (*<type>_Safe_Pointer*) is mandatory (and checked by "ada2wsdl") to
   achieve interoperability with "wsdl2aws". Working with WSDL
   documents.

   From there the safe array access can be placed into the record:

      type Complex_Rec is record
         SI : Set_Of_Int_Safe_Pointer.Safe_Pointer;
      end record;

   To create a Safe_Pointer given a *Set_Of_Int* one must use
   *Set_Of_Int_Safe_Pointer.To_Safe_Pointer* routine. Accessing
   individual items is done with *SI.Item (K)*.

   These Ada definitions are fully recognized by "ada2wsdl" and will
   generate standard array and record *WSDL* definitions as seen
   above:

      <complexType name="Set_Of_Int">
        <complexContent>
          <restriction base="soap-enc:Array">
            <attribute ref="soap-enc:arrayType" wsdl:arrayType="xsd:int[]"/>
          </restriction>
        </complexContent>
      </complexType>

      <complexType name="Complex_Rec">
        <all>
          <element name="SI" type="tns:Set_Of_Int"/>
        </all>
      </complexType>


ada2wsdl
--------

   Usage: ada2wsdl [options] ada_spec

*ada2wsdl* options are:

*-a url*
   Specify the *URL* for the Web Server address. Web Services will be
   available at this address. A port can be specified on the *URL*,
   *http://server[:port]*. The default value is *http://.../*.

*-f*
   Force creation of the *WSDL* file. Overwrite exiting file with the
   same name.

*-I path*
   Add path option for the *ASIS* compilation step. This option can
   appear any number of time on the command line.

*-noenum*
   Do not generate *WSDL* representation for Ada enumerations, map
   them to standard string. Ada mapping to WSDL.

*-o file*
   Generate the *WSDL* document into file.

*-q*
   Quiet mode (no output)

*-s name*
   Specify the Web Service name for the *WSDL* document, by default
   the spec package's name is used.

*-v*
   Verbose mode, display the parsed spec.


ada2wsdl limitations
--------------------

* Do not handle constraint arrays into a records.

* Unbounded_String are supported with full interoperability only
  inside a record.

* Only unconstraint arrays are supported

* Arrays with multiple dimentions not supported


Working with WSDL documents
===========================


Client side (stub)
------------------

This section describe how to use a Web Service. Let's say that we want
to use the Barnes & Noble Price Quote service. The WSDL document for
this service can be found at
http://www.xmethods.net/sd/2001/BNQuoteService.wsdl. In summary this
document says that there is a service named *getPrice* taking as input
a string representing the ISBN number and returning the price as
floating point.

The first step is to generate the client interface (stub):

   $ wsdl2aws -noskel http://www.xmethods.net/sd/2001/BNQuoteService.wsdl

This will create many files, the interesting one at this point is
"bnquoteservice-client.ads", inside we have:

   function getPrice (isbn : in String) return Float;
   --  Raises SOAP.SOAP_Error if the procedure fails

Let's call this service to find out the price for *The Sword of
Shannara Trilogy* book:

   with Ada.Text_IO;
   with BNQuoteService.Client;

   procedure Price is
      use Ada;

      ISBN : constant String := "0345453751";
      --  The Sword of Shannara Trilogy ISBN

      package LFIO is new Text_IO.Float_IO (Float);

   begin
      Text_IO.Put_Line ("B&N Price for The Sword of Shannara Trilogy");
      LFIO.Put (BNQuoteService.Client.getPrice (ISBN), Aft => 2, Exp => 0);
   end Price;

That's all is needed to use this Web Service. This program is fully
functional, It is possible to build it and to run it to get the
answer.


Server side (skeleton)
----------------------

Building a Web Service can also be done from a *WSDL* document. Let's
say that you are Barnes & Noble and that you want to build Web Service
*getPrice* as described in the previous section.

You have created the *WSDL* document to specify the service spec. From
there you can create the skeleton:

   $ wsdl2aws -nostub http://www.xmethods.net/sd/2001/BNQuoteService.wsdl

This will create many files, the interesting one here is
"bnquoteservice-server.ads", inside we have:

   Port : constant := 80;

   generic
      with function getPrice (isbn : in String) return Float;
   function getPrice_CB
     (SOAPAction : in String;
      Payload    : in SOAP.Message.Payload.Object;
      Request    : in AWS.Status.Data) return AWS.Response.Data;

This is a *SOAP AWS*'s callback routine that can be instantiated with
the right routine to retrieve the price of a book given its ISBN
number. A possible implementation of such routine could be:

   function getPrice (isbn : in String) return Float is
   begin
      if isbn = "0987654321" then
         return 45.0;
      elsif ...
   end getPrice;

   function SOAP_getPrice is new BNQuoteService.Server.getPrice_CB (getPrice);

*SOAP_getPrice* is a *SOAP AWS*'s callback routine (i.e. it is not a
standard callback). To use it there is different solutions:

*Using SOAP.Utils.SOAP_Wrapper*
   This generic function can be used to translate a standard callback
   based on *AWS.Status.Data* into a *SOAP* callback routine:

      function getPrice_Wrapper is new SOAP.Utils.SOAP_Wrapper (SOAP_getPrice);

   The routine *getPrice_Wrapper* can be used as any other AWS's
   callback routines. Note that inside this wrapper the *XML* payload
   is parsed to check the routine name and to retrieve the *SOAP*
   parameters. To call this routine the payload needs to be parsed (we
   need to know which routine has be invoked). In this case we have
   parsed the *XML* payload twice, this is not efficient.

*Building the wrapper yourself*
   This solution is more efficient if there is many *SOAP* procedures
   as the payload is parsed only once:

      function CB (Request : in Status.Data) return Response.Data is
         SOAPAction : constant String := Status.SOAPAction (Request);
         Payload    : constant SOAP.Message.Payload.Object :=
           SOAP.Message.XML.Load_Payload (AWS.Status.Payload (Request));
         Proc       : constant String :=
           SOAP.Message.Payload.Procedure_Name (Payload);
      begin
         if SOAPAction = "..." then

            if Proc = "getPrice" then
               return SOAP_getPrice (SOAPAction, Payload, Request);
            elsif ...
               ...
            end if;

         else
            ...
         end if;

Note that the port to be used by the AWS server is described into the
server spec.


wsdl2aws
--------

   Usage: wsdl2aws [options] <file|URL>

It is possible to pass a *WSDL* file or direct "wsdl2aws" to a *WSDL*
document on the Web by passing it's *URL*.

*wsdl2aws* options are:

*-q*
   Quiet mode (no output)

*-d*
   Generate debug code. Will output some information about the payload
   to help debug a Web Service.

*-a*
   Generate using Ada style names. For example *getPrice* will be
   converted to *Get_Price*. This formatting is done for packages,
   routines and formal parameters.

*-f*
   Force creation of the file. Overwrite any exiting files with the
   same name.

*-e*
   Specify the default endpoint to use instead of the one found in the
   WSDL document.

*-s*
   Skip non supported *SOAP* routines. If *-s* is not used, *wsdl2aws*
   will exit with an error when a problem is found while parsing the
   *WSDL* document. This option is useful to skip routines using non
   supported types and still be able to compile the generated files.

*-o name*
   Specify the name of the local *WSDL* document. This option can be
   used only when using a Web *WSDL* document (i.e. passing an URL to
   *wsdl2aws*).

*-doc*
   Handle document style binding as RPC ones. This is sometimes needed
   because some *WSDL* document specify a document style binding even
   though it is really an RPC one.

*-v*
   Verbose mode, display the parsed spec.

*-v -v*
   Verbose mode, display the parsed spec and lot of information while
   parsing the *WSDL* document tree.

*-wsdl*
   Add *WSDL* document as comment into the generated root unit.

*-cvs*
   Add CVS Id tag in every generated file.

*-nostub*
   Do not generated stubs, only skeletons are generated.

*-noskel*
   Do not generated skeletons, only stubs are generated.

*-cb*
   Generate a *SOAP* dispatcher callback routine for the server. This
   dispatcher routine contains the code to handle all the operations
   as described in the *WSDL* document. You need also to specify the
   *-spec* and/or *-types* options, see below.

*-x operation*
   Add *operation* to the list of *SOAP* operations to skip during the
   code generation. It is possible to specify multiple *-x* options on
   the command line.

*-spec spec*
   Specify the name of the spec containing the Ada implementation of
   the *SOAP* routines. This is used for example by the *-cb* option
   above to instantiate all the server side *SOAP* callbacks used by
   the main *SOAP* dispatcher routine. If *-types* is not specified,
   the type definitions are also used from this spec.

*-types spec*
   Specify the name of the spec containing the Ada types (record,
   array) used by *SOAP* routines specified with option *-spec*. If
   *-spec* is not specified, the spec definitions are also used from
   this spec.

*-main filename*
   Specify the name of the server's procedure main to generate. If
   file "<filename>.amt" (Ada Main Template) is present, it uses this
   template file to generate the main procedure. The template can
   reference the following variable tags:

   *SOAP_SERVICE*
      The name of the service as described into the *WSDL* document.
      This tag can be used to include the right units:

         with @_SOAP_SERVICE_@.Client;
         with @_SOAP_SERVICE_@.CB;

   *SOAP_VERSION*
      The AWS's SOAP version.

   *AWS_VERSION*
      The AWS's version.

   *UNIT_NAME*
      The name of the generated unit. This is the name of the
      procedure that will be created:

         procedure @_UNIT_NAME_@ is
         begin
            ...

*-proxy name|IP*
   Use this proxy to access the *WSDL* document and generate code to
   access to these Web Services via this proxy. The proxy can be
   specified by its DNS name or IP address.

*-pu name*
   User name for the proxy if proxy authentication required.

*-pp password*
   User password for the proxy if proxy authentication required.

*-timeouts [timeouts | connect_timeout,send_timeout,receive_timeout ]*
   Set the timeouts for the SOAP connection. The timeouts is either a
   single value used for the connect, send and receive timeouts or
   three values separated by a colon to set each timeout
   independently.


wsdl2aws behind the scene
-------------------------

The *wsdl2aws* tool read a *WSDL* document and creates a root package
and a set of child packages as described below:

*<root>*
   This is the main package, it contains eventually the full *WSDL* in
   comment and the description of the services as read from the *WSDL*
   document.

*<root>.Types*
   This package contains the definitions of the types which are not
   *SOAP* base types. We find here the definitions of the *SOAP*
   structs and arrays with routines to convert them between the Ada
   and *SOAP* type model. A subtype definition is also created for
   every routine's returned type. In fact, all definitions here are
   only alias or renaming of types and/or routines generated in other
   packages. The real definitions for structs, arrays, enumerations
   and derived types are generated into a package whose name depends
   on the name space used for these entities. This package act as a
   container for all definitions and it is the only one used in the
   other generated packages.

*<root>.Client*
   All spec to call Web Services.

*<root>.Server*
   All spec to build Web Services. These specs are all generic and
   must be instantiated with the right routine to create the web
   services.

*<root>.CB*
   The *SOAP* dispatcher callback routine.


wsdl2aws limitations
--------------------

It is hard to know all current limitations as the *WSDL* and *SOAP*
world is quite complex. We list there all known limitations:

* Some *SOAP* base types are not supported : *date, time,
  xsd:hexBinary, decimal*. All these are easy to add (except decimal),
  it is just not supported with the current version.

* Multi-dimension arrays are not supported.

* abstract types are not supported.

* SOAP MIME attachments are not supported.

* WSDL type inheritance not supported.

* Only the RPC/Encoded SOAP messages' style is supported (the
  Document/Literal is not)


Using ada2wsdl and wsdl2aws together
====================================

Using both tools together is an effective way to build rapidely a
*SOAP* server. It can be said that doing so is quite trivial in fact.
Let's take the following spec:

   package Graphics is

      type Point is record
         X, Y : Float;
      end record;

      function Distance (P1, P2 : in Point) return Float;
      --  Returns the distance between points P1 and P2

   end Graphics;

We do not show the body here but we suppose it is implemented. To
build a server for this service it is as easy as:

   $ ada2wsdl -a http://localhost:8787 -o graphics.wsdl graphics.ads

The server will be available on localhost at port 8787:

   $ wsdl2aws -cb -main server -types graphics graphics.wsdl
   $ gnatmake server -largs ...}

Options

*-cb*
   is to create the *SOAP* dispatcher callback routine,

*-main server*
   to generate the main server procedure in "server.adb",

*-types graphics*
   to use "graphics.ads" to get references from user's spec (reference
   to *Graphics.Point* for example).
