ToC DocOverview CGDoc RelNotes Index PermutedIndex
Allegro CL version 6.2
New since 6.2 release.

A SOAP 1.1 API for Allegro CL

This document contains the following sections:

1.0 Preface
2.0 Introduction
3.0 A Simple Client Example
4.0 Components of the API
5.0 Element Definition
6.0 Type Definition
7.0 Making a Client Call
8.0 SOAP Server Components
   8.1 The SOAP Network Server
   8.2 Exporting Methods
   8.3 Controlling Access to Methods
   8.4 Defining SOAP Methods
9.0 Programming Notes
   9.1 Multiple Threads
   9.2 Connector Class Hierarchy
10.0 WSDL Support
   10.1 Limitations in WSDL support
   10.2 WSDL Functions and Variables
   10.3 Namespaces and Packages
      10.3.1 Some important namespaces and packages
      10.3.2 A namespace example
      10.3.3 Deducing the namespaces used in a WSDL file
      10.3.4 Namespace variables
   10.4 When things go wrong - debugging SOAP interfaces
11.0 Headers
12.0 Faults and Errors
13.0 Index



1.0 Preface

This document describes an implementation of the Allegro CL SOAP API. There are still pieces of the Allegro CL/SOAP implementation to be completed. These will be released when they are ready.

The Implementation Plan for the Allegro/SOAP API is as follows. Note that dates in the future are tentative.

Changes since the last update

Users may have used the earlier releases of Allegro CL/SOAP. In this release, the following things have been added or changed:

New features

Enhancements and corrections

Miscellaneous



2.0 Introduction

The Allegro CL SOAP Server needs AllegroServe version 1.2.30 (or later) to work. Be sure you have that version of AllegroServe. Both the Client and the Server need PXML version 7.0.1. The PXML version is returned by the function net.xml.parser:pxml-version and is the value of the variable net.xml.parser::*pxml-version*.

You load the SOAP API into a running lisp with the following call to require:

(require :soap)

All the symbols in the SOAP API are exported from the net.xmp.soap package.

There is a SOAP client example in examples/soap/soapex.cl. There is a SOAP server example in examples/soap/soapval1.cl.

The letters xmp stand for XML Message Protocol. The XMP component implements a separately documented API that is used as a basis for the SOAP implementation and for other XML-based message protocols such as XMLRPC.

Users may find it more convenient to try the SOAP examples in a Modern (case-sensitive) Allegro CL image. Since case in SOAP symbols is significant, SOAP symbols typically have mixed case print names. Modern mode handles mixed case names without special effort. If you use an ANSI (case-insensitive) Allegro CL image, SOAP symbols need to be wrapped in vertical bar escapes (as is done in the Simple Example just below) in order to preserve their mixed-case print names.



3.0 A Simple Client Example

This simple example shows how to access a public SOAP server that returns currency conversion rates. (See also the file examples/soap/soapex.cl.)

The symbols in the "urn:xmethods-CurrencyExchange" namespace are exported from a Lisp package created for this purpose.


(require :soap)
(use-package :net.xmp.soap)

;;  This form ensures that XSD is a nickname of the NET.XMP.SCHEMA
;;  package:
(defpackage :net.xmp.schema (:use) (:nicknames :xs :xsd))

(defpackage :conv (:use) (:export "getRate"))

We define a function to send the message and decode the reply:

(defun convert (&optional (country1 "Canada") (country2 "USA"))
  (let ((conn (soap-message-client 
         :lisp-package :keyword
                :url "http://services.xmethods.net:80/soap")))
    (call-soap-method
     conn
     '(:element
       conv:|getRate|
       (:complex (:seq (:element "country1" xsd:|string|)
                       (:element "country2" xsd:|string|)
                       )
                :action ""
                :namespaces
                (nil (:conv "tns" "urn:xmethods-CurrencyExchange"))
                ))
     :|country1| country1 :|country2| country2
     )))

The main element of the message is defined (in line) as a complex type composed of a sequence of two elements "country1" and "country2". The content of each of these elements is declared to be a string. The information needed to create the element definitions must be obtained from the server documentation, often in the form of a WSDL file.

We try the function:

cl-user(4): (convert)
;SOAP Warning: Undefined element conv::getRateResponse
;SOAP Warning: Undefined element :Result
(conv::getRateResponse (:Result 0.7212))
nil

The warning indicates that we failed to specify the data type of the main element in the reply. A strict interpretation of the SOAP specification would require us to reject the message.

The result message is returned as a nested list of association lists where element name is the key and element content is the value.

We can muffle the warning by declaring the type of the element:

cl-user(5): (defpackage :conv (:use) (:export "getRateResponse"))
#<The conv package>
cl-user(6): (define-soap-element nil
  'conv:|getRateResponse|
  '(:complex (:seq (:element "Result" xsd:|float|))))
(:complex (:seq (:element ("Result") net.xmp.schema:float)))

We try again:

cl-user(7): (convert)
(conv:getRateResponse (:Result 0.7212))
nil
cl-user(8): 


4.0 Components of the API

The client API encodes Lisp data into a SOAP message and transmits the encoded HTTP message to the server. The reply from the server is another HTTP message that is decoded into Lisp data returned to the caller.

The server API defines Lisp functions that are called when specified messages are sent to the server. The messages arrive as encoded HTTP text and the value returned by the function is sent as an encoded HTTP reply message.

The XML elements in both outgoing and incoming messages must be defined in order to specify the required encoding and decoding behaviors.



5.0 Element Definition

An element definition specifies how an element should be encoded in a message to a server and how it can be decoded in a reply message.

An element definition can appear as a component in a Lisp list structure that describes a compound XML element:

element-def -> (:element elt-name-spec type-spec)

An element definition can also be created with a call to define-soap-element:


define-soap-element

Generic Function

Package: net.xmp.soap

Arguments: conn elt-name-spec type-spec &rest def-options &key (redef :warn)

After a call to define-soap-element, any of the names listed in the elt-name-spec may be used to denote the defined element.

The conn argument may be nil but can also be used to define behavior specific to a particular class of connections.

The elt-name-spec argument specifies one or more names by which the element can be identified. It is described below.

The type-spec argument may be the name of a separately defined SOAP type, the name of a built-in SOAP type or an anonymous type definition as defined in the next section.

The redef option controls the behavior when a definition already exists. The possible values are:


An elt-name-spec is defined as follows:

elt-name-spec -> symbol | string 
              -> ( { symbol | string | (:any-case string) }... )

When a SOAP message is created, the first (or only) name in elt-name-spec determines the name included in the message. The components of an elt-name-spec are:

string --> unqualified QName
symbol --> 1. If the symbol-package of the symbol has been 
                 associated with a namespace
	        AND
	         the namespace is included in the current context,
	        THEN
	         the qualified QName is included in the message.
	  2. OTHERWISE the symbol name is included as an unqualified QName.
(:any-case string) --> treated like string above

When a SOAP message is decoded, any one of the names in the elt-name-spec is accepted as a name for this element.

string --> accept any string= QName in any namespace
symbol --> accept the EQ symbol
(:any-case string) --> accept any string-equal QName in any namespace


6.0 Type Definition

A type definition specifies the structure, content and attributes of an XML element. A type definition also specifies the encoding from Lisp to XML and the decoding from XML to Lisp.

A type definition can appear as a component in a Lisp list structure that describes a compound XML element:

type-def -> (:simple simple-type-spec simple-option... )
         -> (:array type-spec array-option... )
         -> (:complex complex-def complex-option... )

A type definition can also be created with a call to define-soap-type:


define-soap-type

Function

Package: net.xmp.soap

Arguments: conn name type-def &key (redef :warn)

Once defined, a type name may be used in other element or type definitions.


simple-type-spec -> nil | type-name
       type-spec -> type-name | type-def 

 complex-def -> (collector complex-part ...)
   collector -> :seq    ;; zero or one of each part in specified sequence
             -> :seq*   ;; zero or more of each part in specified sequence
             -> :seq+   ;; one or more of each part in specified sequence
             -> :seq1   ;; exactly one of each part in specified sequence
             -> :set    ;; zero or one of each part in any sequence
             -> :set*  
             -> :set+  
             -> :set1  
             -> :or     ;; exactly one of the parts

The components of :seq :seq* :seq1 and :seq+ must be ordered as specified.

The components of :set :set* :set1 and :set+ may appear in any order.

When a complex element is encoded, the sub-elements are always encoded in the order listed in the definition.

complex-part -> element-spec | complex-def
element-spec -> element-name | (:any} | element-def

When a complex-part denotes a sequence of elements the sequence is spliced into the sequence containing the complex-part.

Sub-element definitions enter only through an element-def with a :complex or :array type-def.

Options on :complex type-def:

Options on :array type-def:

Options on any type-def:

Built-in Types:

The package qualifier xsd is a nickname for the net.xml.schema package. You must have evaluated (defpackage :net.xmp.schema (:use) (:nicknames :xs :xsd)) in order for the nickname to be valid. Otherwise, replace xsd with net.xmp.schema in the lists below.

The package qualifier enc is a nickname for the net.xml.soap.encoding package. You must have evaluated (defpackage :net.xmp.soap.encoding (:use) (:nicknames :enc)) in order for the nickname to be valid. Otherwise, replace enc with net.xmp.soap.encoding in the lists below.

     package enc corresponds to namespace http://schemas.xmlsoap.org/soap/encoding/
     package xsd corresponds to namespace http://www.w3.org/2001/XMLSchema

     Lisp Name of
     SOAP Type            Lisp Type

     enc:|QName|          symbol in package corresponding to namespace
     xsd:|string|         string
     enc:|int|            integer
     xsd:|int|            integer
     enc:|boolean|        boolean
     xsd:|boolean|        boolean
     enc:|float|          single-float
     xsd:|float|          single-float
     enc:|double|         double-float
     xsd:|double|         double-float
     enc:|base64|         base64 data decoded to Lisp string
     enc:|base64Binary|   base64 data decoded to Lisp string
     xsd:|base64Binary|   base64 data decoded to Lisp string

     other                string


7.0 Making a Client Call

To make a client call, an application must create a connection instance with a call to soap-message-client.

A SOAP service available via HTTP is located with a URI that has several components:

Within the HTTP request that carries the SOAP message there are HTTP headers that can be treated as attributes of the HTTP request. The soapAction header may be used by a specific SOAP server to recognize or to dispatch a message.

The entire pattern used to identify a SOAP method to be called consists of these components:


soap-message-client

Function

Package: net.xmp.soap

Arguments: &rest options

The options (keywords) and their values are (note that a value must be supplied for :url):



call-soap-method

Generic Function

Package: net.xmp.soap

Arguments: conn method &rest args

The conn argument is an instance of soap-client-connector.

The method argument is a symbol defined as a SOAP element or a list containing an element-def as described above.

The args argument is an alternating list of element names and element values. The element names are matched with the element names defined as arguments in the method definition. The argument values must conform to the element types in the method definition. The following table shows the suitable values given a Method argument defintion:

Method argument def

Suitable Lisp Value

:simple A Lisp value that can be coerced to the required simple type.
:complex An alternating list of element names and element values. The element names match the sub-elements of the complex type.
:array A list of values that can be encoded as the array element type. or a list of items described by the :argument property in an :array-item option. If an element in the list is an instance of soap-element, then it is transmitted as the encoding specified in the instance. (Note: In the future, we should allow a Lisp array as well but the current implementation only accepts a list.)

The outgoing message includes any headers that have been added to the connector with soap-add-header (described below).

The function returns two values, the main body element in the reply and a list of header elements.

Examples

In this example, we call a method with one argument declared as a simple element containing a string value. We use strings for all the element names because the server does not expect qualified XML names.

(define-soap-element nil "simpleStructReturnTest"
  '(:complex (:seq (:element "myNumber" (:simple enc:|int|)))))

(call-soap-method client "simpleStructReturnTest" "myNumber" 123)

In this example, the SOAP method expects one argument declared as a complex element with 3 sub-elements.

(define-soap-element nil "easyStructTest"
  '(:complex
    (:seq
     (:element
      "stooges"
      (:complex
       (:set
	(:element "moe" enc:|int|)
	(:element "larry" enc:|int|)
	(:element "curly" enc:|int|)))))))

(call-soap-method client "easyStructTest" "stooges" (list "moe" 1 "larry" 2 "curly" 3))

In this example, the SOAP method expects one argument declared as an array of elements. The Lisp argument corresponding to the "myArray" element is a list of strings. Each string in the list is encoded as an array element with the default element name "item".

(define-soap-element nil "moderateSizeArrayCheck"
  '(:complex (:seq (:element "myArray" (:array xsd:|string|)))))

(call-soap-method client "myArray" (list "a" "b" "c" "d"))

To specify more precisely the layout of an array we could say

(define-soap-element nil "moderateSizeArrayCheck"
  '(:complex (:seq (:element "myArray" (:array xsd:|ur-type|
                                               :array-item
                                               (:element "myArrayElement"
                                                :send-type t
                                                :argument :type-and-arg))))))

In this case each array element in Lisp must be specified as a list where the first element is the SOAP type of the encoding and the second is the Lisp value to be encoded. Each array element will be encoded as an element named "myArrayElement" and the type will be encoded as a xsd:|type| attribute. (xsd is a nickname for the net.xml.schema package. You must have evaluated (defpackage :net.xml.schema (:use) (:nicknames :xsd :xs)) for the mickname to be valid. Otherwise replace xsd with net.xml.schema in the example below.)

(call-soap-method client 
  "myArray" '((:xsd:|string| "a") (xsd:|int| 17)))



8.0 SOAP Server Components

A SOAP server exports methods that may be called from remote clients through a network interface. The network interface in this implementation is an AllegroServe HTTP server. A method is exported by specifying a SOAP element pattern and a Lisp function. When the specified message is received by the network server, the Lisp function is called. The arguments to the Lisp function are the decoded sub-elements of the message. The result returned by the Lisp function is encoded and sent as the reply message.


8.1 The SOAP Network Server

A SOAP network interface is established with a call to soap-message-server.


soap-message-server

Function

Package: net.xmp.soap

Arguments: &key start enable publish class name service-name url port-name binding-name action lisp-package message-dns must-understand decode-flag encoding actor &allow-other-keys

The function returns an instance of soap-server-connector. This instance is an argument to most of the other API functions.

The arguments are:

All other arguments are passed as initargs in a call to make-instance. Arguments recognized for the class soap-aserve-server-string-in-out-connector include:



enable-soap-server

Generic Function

Package: net.xmp.soap

Arguments: server &key &allow-other-keys

This method enables the server to respond to SOAP method calls. The HTTP server is not affected by this call.



disable-soap-server

Generic Function

Package: net.xmp.soap

Arguments: server &key &allow-other-keys

This method disables the server for SOAP method calls. The HTTP server is not affected by this call.



start-soap-server

Function

Package: net.xmp.soap

Arguments: server &key new start enable &allow-other-keys

Start the HTTP server for this SOAP server. If new is non-nil, create a new HTTP server If start argument is specified, it overrides the start argument in call to soap-message-server If enable is non-nil, enable the soap server



stop-soap-server

Function

Package: net.xmp.soap

Arguments: server &key disable &allow-other-keys

Stop the HTTP server for this SOAP server. If disable is non-nil disable the SOAP server as well.



8.2 Exporting Methods

A method must be exported to make it available to remote clients through the network server.


soap-export-method

Generic Function

Package: net.xmp.soap

Arguments: conn name signature &key lisp-name (enable t) return help action ordered exact &allow-other-keys

This function defines how a Lisp function will be invoked when a SOAP message arrives at the server. The arguments to the Lisp function are the names and content of the sub-elements in the message.

The arguments to soap-export-method are:



8.3 Controlling Access to Methods

The Lisp function associated with a SOAP message is called with the soap-invoke-method generic function. The SOAP API includes a method specialized on soap-server-connector. This method simply calls apply. Applications can add additional restrictions on how and when the function is called by implementing a more specific method on a sub-class of soap-server-connector.


soap-invoke-method

Generic Function

Package: net.xmp.soap

Arguments: server name arg &key headers

This function is called to invoke the Lisp function associated with a SOAP message. The default primary method simply calls apply. User methods can be defined for sub-classes of soap-server-connector to enforce more restrictive access rules.

The headers argument is a list of SOAP header elements that were included in the incoming message. The default method ignores these.

This function normally returns one value which is encoded as the content of the reply message. If zero values are returned, then a SOAP client fault with fault string "Call refused" is returned as the reply. Values othere than the first are ignored.

An :around method specialized on soap-server-connector binds the variable *soap-server*. If more specific :around methods are defined, the body of these methods will not see this binding.



8.4 Defining SOAP Methods

The Lisp function defined as the SOAP method body is called with an &rest argument that consists of an alternating list of element names and element content values.

If the element names are Lisp keywords, the function may be defined with keyword arguments, otherwise the function must extract argument values by some other means such as getf.

Named element content in message:

Lisp argument to method:

simple type corresponding Lisp value
complex type an association lists in which the keys are sub-element names. The function soap-sub-element-content should be used to extract the content of a sub-element.
array type a Lisp array of t, each array element is the element content of the array elements in the message

*soap-server*

Variable

Package: net.xmp.soap

During the execution of a SOAP method call, this variable is bound to a copy of the server instance that received the message with the method call.


Some convenience functions for writing method bodies:


soap-sub-element-content

Function

Package: net.xmp.soap

Arguments: element-item sub-element-name

This function is used to extract the sub-element content from an argument to a SOAP method. The sub-element-name must be the name of an immediate sub-element of the argument.

If the sub-element is a simple element, the value is a Lisp atom that represents the value of the element. If the sub-element is a complex element, the value is a Lisp association list that can be decomposed with additional calls to soap-sub-element-content.



soap-alist-to-plist

Function

Package: net.xmp.soap

Arguments: element-alist &optional recursive

Translate an association list into a property list. This is useful when turning an argument into a reply.



soap-encode-object

Generic Function

Package: net.xmp.soap

Arguments: name type-spec data

This function returns an instance of soap-element that contains an encoded form of the data argument using the type-spec to control the encoding.

Once a value is encoded as a soap-element instance, it is not affected by other element or type specifications that may be applied to the value. This function may be used to specify the encoding of SOAP array elements when a uniform encoding rule cannot be specified.



soap-version

Function

Package: net.xmp.soap

Arguments: &optional v1 v2 v3 error-p

In its simplest form, with no arguments, this function returns a string containing the current version information.

If the first argument is t or a stream, the version string is written to the stream (t indicating *terminal-io*).

If the first argument is an integer, the function acts as a predicate that compares the integer arguments to the current version. If v2 or v3 are omitted, they default to zero.




9.0 Programming Notes


9.1 Multiple Threads

A client connector instance should be used serially only. Only one thread should access the connector for the entire duration of a message round-trip.

When a server responds to an incoming message, a copy of the server connector instance is cloned for the duration of the message. The variable *soap-server* is bound in the thread that calls the Lisp function exported to handle the message. Message handling programs called by the server must take care to deal with shared resources with appropriate interlocks.


9.2 Connector Class Hierarchy

The complete class hierarchy for sub-classes of soap-connector includes all the following classes:

   soap-connector

   soap-client-connector
   soap-server-connector

   soap-string-out-connector
   soap-string-in-connector
   soap-string-in-out-connector
   
   soap-client-string-out-connector
   soap-client-string-in-connector
   soap-client-string-in-out-connector

   soap-server-string-out-connector
   soap-server-string-in-connector
   soap-server-string-in-out-connector

   soap-aserve-connector

   soap-aserve-client-connector
   soap-aserve-server-connector

   soap-aserve-string-out-connector
   soap-aserve-string-in-connector
   soap-aserve-string-in-out-connector
   
   soap-aserve-client-string-out-connector
   soap-aserve-client-string-in-connector
   soap-aserve-client-string-in-out-connector

   soap-aserve-server-string-out-connector
   soap-aserve-server-string-in-connector
   soap-aserve-server-string-in-out-connector

Methods in the API and internals methods are specialized on the least-specific method in this hierarchy, but only the classes

  soap-aserve-client-string-in-out-connector
  soap-aserve-server-string-in-out-connector

are actually instantiated in an application using this API. Thus, in order to provide behavior specific to a given application the programmer must create a sub-class of one or both of the above classes.

The following are accessors for soap-connector. Values are used by encode-wsdl-file.


soap-port-name

Generic Function

Package: net.xmp.soap

Arguments: soap-connector

Returns the port name.



soap-binding-name

Generic Function

Package: net.xmp.soap

Arguments: soap-connector

Returns the binding name.



soap-service-name

Generic Function

Package: net.xmp.soap

Arguments: soap-connector

Returns the service name.




10.0 WSDL Support

Many web services are defined in an XML dialect known as WSDL. The WSDL definition specifies the element content and data types in the SOAP messages received and sent by the service.

Given a web service WSDL definition, we can generate the Lisp functions and definitions needed to send messages to the service and to receive and decode the replies.

We can also generate the server interface and skeleton definitions for the server methods. The only additional programming needed is to supply the body of the server functions.


10.1 Limitations in WSDL support

This early release of WSDL support implements most of the WSDL 1.1 specification. Any omissions are the result of oversight or for the benefit of an earlier release. We plan to correct omissions and add support for the WSDL 1.2 specification in a future release.

The known omissions include:


10.2 WSDL Functions and Variables

The packages net.xmp.wsdl and net.xmp.wsdl.soap hold the symbols in the WSDL namespaces.


wsdl-file-connector

Class

Package: net.xmp.soap

An instance of this class is created when a WSDL file is decoded.



decode-wsdl-file

Function

Package: net.xmp.soap

Arguments: file &key namespaces lisp-package

This function parses a file containing a WSDL specification and returns wsdl-file-connector instance containing the parsed data.

The lisp-package argument is a package specifier. Unqualified WSDL names will be interned in this package.

The value of the namespaces argument should be an extended-namespace-spec, defined recursively here:

namespaces -> extended-namespace-spec

  extended-namespace-spec 
     -> ex-ns-tail | (ns-default ex-ns-part ... . ex-ns-tail)
	  ex-ns-tail -> :none | :wsdl-1.1 | :wsdl-1.2 | nil | :guess
             :wsdl-1.1: include the value of *wsdl-1.1-namespaces*
             :wsdl-1.2: include the value of *wsdl-1.2-namespaces*
             nil: include the value of *wsdl-default-namespaces*
             :none: do not add any namespaces - use only the ones 
                    explicitly included in the namespaces argument.
             :guess: call decode-wsdl-namespace to determine the 
                     namespace configuration
	  ex-ns-part -> package-name
	             -> (:prefix symbol-or-string)
                     -> namespace-def -> (package prefix uri)

If a package-name occurs as an ex-ns-part, any unknown namespaces in the file are mapped to this package. Only one package-name should occur in the extended-namespace-spec.

If the form (:prefix symbol-or-string) occurs as an ex-ns-part, each unknown namespace is mapped to a different package named "prefixNN". Only one such form should occur in the extended-namespace-spec.

The ex-ns-tail component specifies how the standard namespaces should be identified in the file. If the package-name or :prefix forms occur as an ex-ns-part, or if the tail is :guess, then decode-wsdl-namespaces is called.



decode-wsdl-string

Function

Package: net.xmp.soap

Arguments: string &key namespaces lisp-package

This function is like decode-wsdl-file but the input is from the string argument instead of a file.



decode-wsdl-at-uri

Function

Package: net.xmp.soap

Arguments: uri &key namespaces lisp-package

This function is like decode-wsdl-file but the input is from the specified uri argument instead of a file.



decode-wsdl-source

Function

Package: net.xmp.soap

Arguments: &key uri string file namespaces lisp-package

This is the most general form of decode-wsdl-* functions. Only one of the keyword arguments uri, string, and file should be specified. The other keyword arguments are like decode-wsdl-file.



encode-wsdl-file

Function

Package: net.xmp.soap

Arguments: &key namespaces servers target name (if-exists :supersede)

Create a file with WSDL definitions of the specified servers. The definitions include exported methods and associated data types.

The arguments are:



wsdl-service-names

Generic Function

Package: net.xmp.soap

Arguments: conn &optional and-ports

Returns a list of the names of all the services defined in the wsdl file. The order of the names is the order of the defininitions in the file. If more than one service is defined, the index in the list may be used as the service argument to make-client-interface.

The optional and-ports argument determines the level of detail included in the returned value. If it is omitted or nil, the result will look like (service-name ... ). If it is t, the result will look like ((service-name port-name ...) ... ). If it is :verbose, the result will look like ((service-name (port-name binding url) ...) ... ).



make-client-interface

Generic Function

Package: net.xmp.soap

Arguments: conn service destination &key eval (lisp-package :keyword) (file-package :user) empty-element null-element expand-singleton prefix suffix port if-missing-package

This method analyzes the data in the WSDL definition to generate type definitions and client call functions.

The service argument can be

The destination argument can be

The lisp-package, empty-element, and null-element arguments apply to the client connection that is created in the client call functions.

The file-package argument denotes the package for the source file that is generated by this function.

When the expand-singleton argument is nil, each generated client function expects as many keyword arguments as there are immediate components in the SOAP message.

When the expand-singleton argument is non-nil, and the SOAP message consists of exactly one sub-element, the generated client function expects as many keyword arguments as there are immediate components in this singleton sub-element. SOAP messages are often designed to contain this structure, and this feature simplifies the client message function arguments.

The prefix argument is the leading component of the generated names of client functions. The argument must be a string or a symbol. The default is :client-.

The suffix argument should be one of the keywords :index or :message. The keyword :index denotes names like prefix-17. The keyword :message denotes names like prefix-SoapMessageName.

The port argument specifies the port binding within a service. The value is a name string or an index. The default is 0.

The if-missing-package argument specifies the behavior if a namespace cannot be mapped to a package. The value can be :error or :warn or a string or a symbol.

If the value of if-missing-package is :error or :warn (the default), and error or a warning is signaled. When the :warn option is chosen, if no warnings are printed, the generated interface is complete and correct. If warnings are printed, the generated interface file must be hand modified to make it complete and functional. It is usually easier to adjust the namespaces argument and generate a new interface file.

If the value of if-missing-package is a string or some other symbol, then a package with name "net.xmpns.SSSNN" where SSS is the string (or symbol-name) and NN is an index is created and used.

If no Lisp package has been defined for a namespace, the warning "There is no Lisp package defined for namespace ~S" is printed. If a Lisp package is not pre-defined in the application, the symbols will be interned in a new package for each new incoming message.



make-server-interface

Generic Function

Package: net.xmp.soap

Arguments: conn service destination &key eval (lisp-package :keyword) (file-package :user) empty-element null-element expand-singleton prefix suffix action message-dns port if-missing-package

This method analyzes the data in the WSDL file to generate type definitions and and server function skeletons.

Most of the arguments are as for make-client-interface.

The prefix argument is the leading component of the generated names of server functions. The argument must be a string or a symbol. The default is :server-.

The action argument is the default soapAction expected for all incoming messages.

The message-dns argument is used to initialize the namespace definitions of the server instance.



10.3 Namespaces and Packages

The meaning of XML, SOAP, and WSDL texts depends in part on the correct identification of various namespaces.

XML namespaces are identified by a URI and URIs are considered distinct if they differ in any character position. The SOAP module considers two URIs equivalent if they only differ in a final slash character.


10.3.1 Some important namespaces and packages

XML Schema definition namespace

XML Schema instance namespace

SOAP message envelope namespace:

SOAP message encoding namespace

WSDL definition namespace

WSDL SOAP binding namespace


10.3.2 A namespace example

In order to decode a WSDL definition correctly, all six of the above namespaces must be identified correctly. The WSDL definition file must be inspected to identify the URI used in a given instance.

If the pattern matches the one in *wsdl-1.1-namespaces* or *wsdl-1.2-namespaces* then a simple assignment to *wsdl-default-namespaces* is sufficient. If the pattern used differs only in one or two of the namespaces, the incorrect defaults can be overriden with the :namespaces argument to decode-wsdl-file. If most of the namespaces must be redfined, it is usually best to make a new setting for *wsdl-default-namespaces*.

For example, in the snowboarder example at http://www-106.ibm.com/developerworks/webservices/library/ws-soap/?dwzone=ws the WSDL definition specified the namespaces:

 <wsdl:definitions name="EndorsementSearch"
   targetNamespace="http://namespaces.snowboard-info.com"
   xmlns:es="http://www.snowboard-info.com/EndorsementSearch.wsdl"
   xmlns:esxsd="http://schemas.snowboard-info.com/EndorsementSearch.xsd"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

 <xsd:schema
   targetNamespace="http://namespaces.snowboard-info.com"
   xmlns:xsd="http://www.w3.org/1999/XMLSchema">

The following package configuration can be used to decode the file correctly.

(defpackage :tns (:use))

(defparameter *wsdl-default-namespaces*
  '(nil
    (:tns "tns"   "http://namespaces.snowboard-info.com")
    (:tns "es"    "http://www.snowboard-info.com/EndorsementSearch.wsdl")
    (:tns "esxsd" "http://schemas.snowboard-info.com/EndorsementSearch.xsd")
    (:net.xmp.wsdl "wsdl" "http://schemas.xmlsoap.org/wsdl/")
    (:net.xmp.wsdl.soap "soap" "http://schemas.xmlsoap.org/wsdl/soap/")
    (:net.xmp.soap.encoding "soapenc" "http://schemas.xmlsoap.org/soap/encoding/")
    (:net.xmp.soap.envelope "soapenv" "http://schemas.xmlsoap.org/soap/envelope/")
    (:net.xmp.schema "xsd" "http://www.w3.org/1999/XMLSchema")
    ))

In this example, it makes sense to map the namespaces with prefixes "tns" "es" "esxsd" to the same package. Other applications might require a separate package for each namespace.


10.3.3 Deducing the namespaces used in a WSDL file

The function decode-wsdl-namespaces returns information about the namespaces mentioned in a WSDL definition and it can generate a namespace specification based on some heuristic rules.


decode-wsdl-namespaces

Function

Package: net.xmp.soap

Arguments: &key file string uri other-pk base-ns

This function returns 4 values:

  1. A namespace specification acceptable as the :namespaces argument
  2. A list of unrecognized URIs
  3. A list of missing namespaces
  4. A list of ambiguous namespaces

file should be a string containing the path to a file. string should be a string containing a WSDL definition. uri should be the uri where a WSDL definition may be found. Only one of the above arguments should appear.

other-pk should be the name of a package or a list of the form (:prefix string-or-symbol) This argument specifies how unknown namespaces should be resolved. If a package name is specified, then all unknown namespaces are mapped to this package. If the :prefix form is specified, then each unknown namespace is mapped to a different package.

base-ns should be a namespace specification of the form (default namespace-def ...) that specifies additional known namespaces.

When decode-wsdl-file is called with :guess in the final cdr of the :namespaces argument, the function decode-wsdl-namespaces is called and if values 2 3 and 4 are nil the decode operation proceeds with the resulting namespace specification. If any of the values 2 3 or 4 are non-nil, the function signals an error.



10.3.4 Namespace variables

The value of each of these variables is a namespaces specification of the form

   (default-namespace-uri-or-nil  namespace-def ... )

   namespace-def -> (package-name prefix uri)

*soap-namespaces*

Variable

Package: net.xmp.soap

The value of this variable is the default used by soap-message-client The initial setting is the value of *soap-namespaces-a*.



*wsdl-default-namespaces*

Variable

Package: net.xmp.soap

The value of this variable is the default used by decode-wsdl-file and friends. The initial setting is the value of *wsdl-1.1-namespaces*.



*application-namespaces*

Variable

Package: net.xmp.soap

This variable is defined in source files generated by make-client-interface and make-server-interface. The initial value is nil.



*soap-namespaces-a*

Variable

Package: net.xmp.soap

The value of this variable is one configuration of namespaces that we have seen.

      (nil
	(:net.xmp.schema-instance   "xsi"
	 "http://www.w3.org/2001/XMLSchema-instance")
	(:net.xmp.schema            "xsd"
	 "http://www.w3.org/2001/XMLSchema")
	(:net.xmp.soap.envelope     "soap"
	 "http://schemas.xmlsoap.org/soap/envelope/")
	(:net.xmp.soap.encoding     "SOAP-ENC"
	 "http://schemas.xmlsoap.org/soap/encoding/")
	)


*soap-namespaces-b*

Variable

Package: net.xmp.soap

The value of this variable is one configuration of namespaces that we have seen.

      (nil
	(:net.xmp.soap.envelope      "SOAP-ENV"
         "http://schemas.xmlsoap.org/soap/envelope/")
	(:net.xmp.soap.encoding      "SOAP-ENC"
	"http://schemas.xmlsoap.org/soap/encoding/")
	(:net.xmp.schema             "xsd"
	 "http://www.w3.org/1999/XMLSchema")
	(:net.xmp.schema-instance     "xsi"
	 "http://www.w3.org/1999/XMLSchema-instance")
	)


*wsdl-1.1-namespaces*

Variable

Package: net.xmp.soap

The value of this variable is one configuration of namespaces that we have seen.

  (nil
    (:net.xmp.wsdl
     "wsdl"
     "http://schemas.xmlsoap.org/wsdl/"
     ;; WSDL namespace for WSDL framework.
     )
    (:net.xmp.wsdl.soap
     "soap"
     "http://schemas.xmlsoap.org/wsdl/soap/"
     ;; WSDL namespace for WSDL SOAP binding.
     )
    ;; http http://schemas.xmlsoap.org/wsdl/http/ 
    ;;      WSDL namespace for WSDL HTTP GET & POST binding.
    ;; mime http://schemas.xmlsoap.org/wsdl/mime/
    ;;      WSDL namespace for WSDL MIME binding.
    (:net.xmp.soap.encoding
     "soapenc"
     "http://schemas.xmlsoap.org/soap/encoding/"
     ;; Encoding namespace as defined by SOAP 1.1 [8].
     )
    (:net.xmp.soap.envelope
     "soapenv"
     "http://schemas.xmlsoap.org/soap/envelope/"
     ;; Envelope namespace as defined by SOAP 1.1 [8].
     )
    (:net.xmp.schema-instance
     "xsi"
     "http://www.w3.org/2000/10/XMLSchema-instance"
     ;; Instance namespace as defined by XSD [10].
     )
    (:net.xmp.schema
     "xsd"
     "http://www.w3.org/2000/10/XMLSchema"
     ;; Schema namespace as defined by XSD [10].
     )
    ;; tns (various)
    ;; The 'this namespace' (tns) prefix is used as a convention
    ;;     to refer to the current document.
    ;; (other) (various)
    ;; All other namespace prefixes are samples only. 
    ;;     In particular, URIs starting with 'http://example.com'
    ;;     represent some application- dependent or context-dependent URI [4].
    )


*wsdl-1.2-namespaces*

Variable

Package: net.xmp.soap

The value of this variable is one configuration of namespaces that we have seen.

  (nil
    (:net.xmp.wsdl
     "wsdl"
     "http://www.w3.org/2003/06/wsdl"
     ;; A normative XML Schema [XML Schema: Structures], 
     ;;   [XML Schema: Datatypes] document for the
     ;;   "http://www.w3.org/2003/06/wsdl" namespace can be 
     ;;   found at http://www.w3.org/2003/06/wsdl.
     ;;   WSDL documents that do NOT conform to this schema are
     ;;   not valid WSDL documents. WSDL documents that DO conform to
     ;;   this schema and also conform to the other constraints defined
     ;;   in this specification are valid WSDL documents.
     )
    (:net.xmp.wsdl.soap
     "soap12"
     "http://www.w3.org/2003/06/wsdl/soap12"
     ;; Defined by WSDL 1.2: Bindings [WSDL 1.2 Bindings].
     )
    ;; http "http://www.w3.org/2003/06/wsdl/http"
    ;; mime "http://www.w3.org/2003/06/wsdl/mime"
    (:net.xmp.schema
     "xs"
     "http://www.w3.org/2001/XMLSchema"
     ;; Defined in the W3C XML Schema specification
     ;;   [XML Schema: Structures], [XML Schema: Datatypes].
     )
    (:net.xmp.schema-instance
     "xsi"
     "http://www.w3.org/2001/XMLSchema- instance"
     )
    )


10.4 When things go wrong - debugging SOAP interfaces

Sometimes, when a connection does not seem to be working, it is useful to see the actual XML message strings passed between client and server.

To see the message string sent by a client call, trace net.aserve.client:do-http-request. If other parts of the application also call do-http-request, it may help to restrict the trace to calls inside net.xmp:xmp-call-method.

To see the message string returned by the server, trace net.xml.parser:parse-xml. If other parts of the application also call parse-xml, it may help to restrict the trace to calls inside net.xmp:xmp-call-method.

To see the message string arriving at a SOAP server, and the reply string returned by the SOAP server, it is sufficient to trace net.xmp:xmp-server-implementation. The second argument to this function is the incoming message. The function returns three values: the name of the method, the element definition of the result, and the reply string.



11.0 Headers


make-soap-header

Generic Function

Package: net.xmp.soap

Arguments: conn element-spec &rest args

The arguments are as for call-soap-method, but instead of sending a message, this method returns an object of class soap-header which contains an encoded representation of the header element.

If the header element must have a "mustUnderstand" attribute, the attribute may be specified as a :must-understand option or included in the :attributes option of the element definition.



soap-add-header

Generic Function

Package: net.xmp.soap

Arguments: conn header &key after before reset

The header argument must be an instance of the class soap-header. The method adds the header to the list of headers that will be sent with the next message.

The before and after arguments may be nil or headers previously added.

If reset is non-nil, then any previously added headers are discarded.



soap-must-understand

Generic Function

Package: net.xmp.soap

Arguments: conn element-name

When a reply message is decoded, and a "mustUnderstand" attribute with value "1" is present, then this method is called.

The default method behavior depends on the setting of the :must-understand flag in the connection instance. The following settings produce the indicated behavior:




12.0 Faults and Errors

In this implementation, "Fault" results are returned like other reply messages.

Errors detected by the implementation in the Lisp code are signaled as instances of soap-error.



13.0 Index


Copyright (c) 1998-2004, Franz Inc. Oakland, CA., USA. All rights reserved.
Documentation for Allegro CL version 6.2.
Created 2002.2.26.

ToC DocOverview CGDoc RelNotes Index PermutedIndex
Allegro CL version 6.2
New since 6.2 release.