.. _Using_WSDL:

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

.. index:: WSDL
.. index:: Web Service Definition Language

`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*

  .. index:: ada2wsdl

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

*wsdl2aws*

  .. index:: 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:

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

.. index:: ada2wsdl

Note that this tool is based on `ASIS`.

.. _Using_ada2wsdl:

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

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

.. highlight:: sh

The simplest way to use it is::

 $ ada2wsdl simple.ads

.. highlight:: ada

Given the following Ada spec file::

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

.. highlight:: xml

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,
:file:`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 :file:`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:

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.

.. highlight:: xml

*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.

.. highlight:: ada

*Derived types*
  Mapped to a type schema definition::

   type Number is new Integer;

  .. highlight:: xml

  is defined as::

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

.. highlight:: ada

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

   type Small is range 1 .. 10;

  .. highlight:: xml

  is defined as::

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

.. highlight:: ada

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

   type Color is (Red, Green, Blue);

  .. highlight:: xml

  is defined as::

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

.. highlight:: ada

*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;

  .. highlight:: xml

  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>

.. highlight:: ada

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

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

  .. highlight:: xml

  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>

.. highlight:: ada

*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 :file:`ada2wsdl`) to achieve
  interoperability with :file:`wsdl2aws`. :ref:`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)`.

  .. highlight:: xml

  These Ada definitions are fully recognized by :file:`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:

.. highlight:: ada

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. :ref:`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.

.. _:file:`ada2wsdl`_limitations:

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

.. index:: 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:

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

.. _Client_side_(stub):

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

.. index:: WSDL, Client

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 <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
:file:`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):

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

.. index:: WSDL, Server

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
:file:`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:

wsdl2aws
--------

.. index:: wsdl2aws

::

  Usage: wsdl2aws [options] <file|URL>

It is possible to pass a `WSDL` file or direct :file:`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 :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:

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:

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

.. index:: 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 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 :file:`server.adb`,

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