File: using_soap.rst

package info (click to toggle)
libaws 20.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 16,656 kB
  • sloc: ada: 95,505; python: 2,270; ansic: 1,017; makefile: 829; xml: 235; javascript: 202; java: 112; sh: 106
file content (273 lines) | stat: -rw-r--r-- 8,644 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
.. _Using_SOAP:

**********
Using SOAP
**********

.. index:: SOAP
.. index:: Simple Object Access Protocol

`SOAP` can be used to implements Web Services. The `SOAP`
implementation uses `AWS HTTP` as the transport layer. `SOAP` is
platforms and languages independent, to ensure a good
inter-operability, `AWS/SOAP` implementation has been validated through
`http://validator.soapware.org/ <http://validator.soapware.org/>`_, the version number listed on
this server corresponds to the AWS version string
(`AWS.Version`) catenated with the `SOAP` version string
(`SOAP.Version`).

This `SOAP` implementation is certainly one with the higher level
of abstraction. No need to mess with a serializer, to know what is a
payload or be an `XML` expert. All the low level stuffs are
completely hidden as the `SOAP` type system has been binded as
much as possible to the Ada type system.

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

The `SOAP` type system has been relaxed to be compatible with
`WSDL` based `SOAP` implementation. In these implementations, types
are generally (as in the Microsoft implementation) not part of the
payload and should be taken from the `WSDL` (Web Services Description
Language). `AWS/SOAP` is not `WSDL` compliant at this stage, all
such types are binded into the Ada type system as strings. It is up to
the programer to convert such strings to the desired type.

.. _SOAP_Client:

SOAP Client
===========

.. index:: SOAP Client

.. highlight:: ada

The `SOAP` client interface is quite simple. Here are the step-by-step
instructions to call a `SOAP` Web Service:

* Build the `SOAP` parameters

  As for the `SOAP` servers, the `SOAP` parameters are built using a
  `SOAP.Parameters.List` object::

   Params : constant Parameters.List := +I (10, "v1") & I (32, "v2");

* Build the `SOAP` Payload

  The Payload object is the procedure name and the associated parameters::

   declare
      Payload : Message.Payload.Object;
   begin
      Payload := Message.Payload.Build ("Add", Params);

* Call the `SOAP` Web Service

  Here we send the above Payload to the Web Server which handles the Web
  Service. Let's say that this server is named `myserver`, it is
  listening on port `8082` and the `SOAPAction` is `soapdemo`::

   Resp : constant Message.Response.Object'Class :=
            SOAP.Client.Call ("http://myserver:8082/soapdemo", Payload);

* Retrieve the result

  Let's say that the answer is sent back into the parameter named
  "myres", to get it::

   My_Res : constant Integer := SOAP.Parameters.Get (Params, "myres");

In the above example we have called a Web Service whose spec could be
described in Ada as follow::

 function Add (V1, V2 : in Integer) return Integer;
 --  Add V1 and V2 and returns the result. In SOAP the result is named "myres"

.. _SOAP_Server:

SOAP Server
===========

.. index:: SOAP Server
.. index:: SOAPAction

A `SOAP` server implementation must provides a callback procedure as for
standard Web server :ref:`Callback_procedure`. This callback must
checks for the `SOAP` Action URI to handle both standard Web requests
and `SOAP` ones. The `SOAPAction` is sent with the HTTP headers and
can be retrieved using `AWS.Status.SOAPAction`.

.. _Step_by_step_instructions:

Step by step instructions
-------------------------

Here are the step-by-step instructions to be followed in the `SOAP`
callback procedure:

* Retrieve the `SOAP` Payload

  .. index:: Payload

  The `SOAP` Payload is the `XML` message, it contains the
  procedure name to be called and the associated parameters::

   function SOAP_CB (Request : in AWS.Status.Data) return AWS.Response.Data is
      use SOAP.Types;
      use SOAP.Parameters;

      Payload : constant SOAP.Message.Payload.Object :=
                  SOAP.Message.XML.Load_Payload (AWS.Status.Payload (Request));

  `AWS.Status.Payload` returns the `XML` Payload as sent by
  the `SOAP` Client. This `XML` Payload is then parsed using
  `SOAP.Message.XML.Load_Payload` which returns a
  `SOAP.Message.Payload.Object` object.

* Retrieve the `SOAP` Parameters

  The `SOAP` procedure's parameters::

   Params : constant SOAP.Parameters.List :=
              SOAP.Message.Parameters (Payload);

  `SOAP.Parameters.List` is a structure which holds the `SOAP`
  parameters. Each parameter can be retrieved using a
  `SOAP.Parameters` API, :ref:`SOAP.Parameters`. For example to
  get the parameter named `myStruc` which is a `SOAP` struct::

   My_Struct : constant SOAP_Record :=
                 SOAP.Parameters.Get (Params, "myStruct");

  Another example, to get the parameter named `myInt` which is a
  `SOAP` integer::

   My_Int : constant Integer := SOAP.Parameters.Get (Params, "myInt");

* Implements the Web Service

  This is the real job, as for any procedure you can do whatever is
  needed to compute the result.

* Build the `SOAP` answer

  This is the procedure answer. A `SOAP` answer is built from the
  `SOAP` Payload and by setting the returned parameters::

   declare
      Resp        : SOAP.Message.Response.Object;
      Resp_Params : SOAP.Parameters.List;
   begin
      Resp := SOAP.Message.Response.From (Payload);

      Resp_Params := +I (My_Int * 2, "answer");

      SOAP.Message.Set_Parameters (Resp, Resp_Params);

  This build a response which is a single integer value named
  `answer` with the value `My_Int * 2`.

* Returns the answer back to the client

  This last step will encode the response object in `XML` and will
  returns it as the body of an `HTTP` message::

   return SOAP.Message.Response.Build (Resp);

.. _SOAP_helpers:

SOAP helpers
------------

There is two ways to help building the `SOAP`
callbacks. `AWS` provides a `SOAP` specific callback, the spec is::

 function SOAP_Callback
   (SOAPAction : in String;
    Payload    : in Message.Payload.Object;
    Request    : in AWS.Status.Data) return AWS.Response.Data;

With both solutions exposed below, `AWS` retrieve the
`SOAPAction` and the Payload from the `SOAP` request. This
is transparent to the user.

* Using Utils.SOAP_Wrapper

  .. index:: Utils.SOAP_Wrapper

  It is possible to dispatch to such callback by using the
  `SOAP.Utils.SOAP_Wrapper` generic routine::

   generic
      with function SOAP_CB
             (SOAPAction : in String;
              Payload    : in Message.Payload.Object;
              Request    : in AWS.Status.Data) return AWS.Response.Data;
   function SOAP_Wrapper
     (Request : in AWS.Status.Data) return AWS.Response.Data;
   --  From a standard HTTP callback call the SOAP callback passed as generic
   --  formal procedure. Raise Constraint_Error if Request is not a SOAP
   --  request.

  For example, from the standard HTTP callback `CB` we want to call
  `SOAP_CB` for all `SOAP` requests::

   function SOAP_CB
     (SOAPAction : in String;
      Payload    : in Message.Payload.Object;
      Request    : in AWS.Status.Data) return AWS.Response.Data is
   begin
      --  Code here
   end SOAP_CB;

   procedure SOAP_Wrapper is new SOAP.Utils.SOAP_Wrapper (SOAP_CB);

   function CB (Request : in AWS.Status.Data) return AWS.Response.Data is
      SOAPAction : constant String := Status.SOAPAction (Request);
   begin
      if SOAPAction /= "" then
         SOAP_Wrapper (Request);
      else
         ...

* Using a SOAP Dispatcher

  .. index:: SOAP Dispatcher

  `AWS` provides also a `SOAP` specific dispatcher. This
  dispatcher will automatically calls a standard `HTTP` or
  `SOAP` callback depending on the request. If `SOAPAction` is
  specified (i.e. it is a `SOAP` request), the dispatcher will call
  the `SOAP` callback otherwise it will call the standard `HTTP`
  callback. This is by far the easiest integration procedure. Using
  dispatcher the above code will be written::

   function SOAP_CB
     (SOAPAction : in String;
      Payload    : in Message.Payload.Object;
      Request    : in AWS.Status.Data) return AWS.Response.Data is
   begin
      --  Code here
   end SOAP_CB;

   function CB (Request : in AWS.Status.Data) return AWS.Response.Data is
      SOAPAction : constant String := Status.SOAPAction (Request);
   begin
      --  Code here
   end CB;

   --  In the main procedure

   begin
      AWS.Server.Start
        (WS,
         Dispatcher =>
           SOAP.Dispatchers.Callback.Create (CB'Access, SOAP_CB'Access),
         Config     =>
           AWS.Config.Default_Config);

  .. index:: SOAP.Dispatchers.Callback

  The dispacther is created using `SOAP.Dispatchers.Callback.Create`.
  This routine takes two parameters, one is the standard HTTP
  callback procedure and the other is the `SOAP` callback procedure.