
     
   An XML-RPC API for Allegro Common Lisp


Contents:

** XML-RPC CLIENT API
** XML-RPC DATA API
** XML-RPC SERVER API
** EXAMPLE
** NOTES


This module implements classes and functions to support the XML-RPC
protocol for remote function calls through HTTP connections.  The
protocol is described in detail on the XML-RPC Home Page at
http://xmlrpc.com/.  This page also lists public XML-RPC servers and
many community links.

All symbols in this module are exported from the :net.xml-rpc package.
This module requires the AllegroServe (:aserve) and the XML Utilities
(:xmlutils) modules.

This implementation of XML-RPC is separate and independent from the
Lisp RPC implememtation in the aclrpc module.  The Lisp RPC module is
more appropriate for closely coupled applications on one processor or
on a local area network.  XML-RPC is more appropriate for occasional
contact between applications separated by large distances and by
firewalls.

The key features (both positive and negative) of the XML-RPC protocol
are:

    + It is a published protocol implemented in a variety of languages
      and operating systems.

    + It allows communication between applications implemented in
      different languages.

    + It allows communication with established public servers.

    + A Lisp application can be setup as a public server.

    + It allows communication over the internet and through firewalls.

    - It is not intended for time-critical communications, or for the
      transmission of large volumes of data.

    - It is an asymetrical protocol allowing calls from the client to
      the server but not callbacks from the server to the client.  (It
      is however possible for an application to implement both client
      and server functions in one program to allow some two-way
      communication.)



*xml-rpc-version*                                  Variable

   A list of three integers that describe the XML-RPC version.

     (2 9 5) convert time values in time-zone 0 (UTC)
     (2 9 4) Allow additional args to pass on to do-http-request
     (2 9 3) use case-sensitive test in xml-rpc-slot-value, add error-p arg
     (2 9 2) allow class initargs in make-xml-rpc-server 
     (2 9 1) decode xml-rpc-fault instance signalled by method body


xml-rpc-version &optional stream                   Function

   If stream is nil, return a string with a formatted version message.

   If stream is a stream, write the formatted version message to the stream.

   If stream is the keyword :number, return an integer of the form aabbcc
   where aa bb and cc are the version number components.

   Otherwise, return the value of *xml-rpc-version*, a list of three
   version numbers.


*xml-rpc-time-zone*				Variable

   When nil, convert time values in local time zone.  This was the
   behavior in previous version of the XML-RPC module.

   The default value is 0 to specify UTC time values.


*xml-rpc-base64*                                Variable

   The default value is :string to implement behavior compatible with 
   previous versions.

   A value :array specifies that base64 values are decoded into
   USB8 arrays.  A Lisp value to be encoded as <base64> must be 
   specified as a USB8 array.


xml-rpc-condition                                        Condition

xml-rpc-fault                                            Condition

   Instances are created with :fault-code and :fault-string initargs.

   If a user-defined server method signals this condition during its
   execution, the result sent to the client is a fault message where
   the faultCode element is taken from the :fault-code initarg and 
   the faultString element is taken from the :fault-string initarg.


xml-rpc-error                                            Condition

xml-rpc-response-error                                   Condition

xml-rpc-argument-error                                   Condition

xml-rpc-fault-code                                    Reader Method
xml-rpc-fault-string                                  Reader Method
xml-rpc-error-place                                   Reader Method
xml-rpc-error-data                                    Reader Method

** XML-RPC CLIENT API

The Client API allows a Lisp application to call any XML-RPC server.

In a client call, 
 
 - Lisp arguments are converted and encoded to satisfy 
   the requirements of the protocol,  
 - The remote method is called by sending the encoded message
   to the server.
 - The result of the call is received from the server, decoded and 
   mapped to a Lisp value.



encode-xml-rpc-call name &rest args               Function

   The purpose of this function is to encode a client call into
   a string ready to be transmitted to a server.

   The name argument is a symbol or string that names a method
   available at the server.

   The remaining arguments are Lisp values that are encoded into
   suitable protocol items.  Default encoding rules are defined
   for many Lisp data types.  Some arguments must be explicitly
   encoded by calling make-xml-rpc-encoding described later.

   If the same call needs to be made several times, there is some
   efficiency gained in encoding the call once, and reusing the
   string.

   The XML-RPC protocol requires that each http request includes
   a length and that the length is accurate.  



call-xml-rpc-server server name &rest args               Function

   The purpose of this function is to call the remote method and to
   decode the result.

   The first argument is a list of keyword value pairs describing
   the desired XML-RPC server.

   The second argument is the name of a remote method and the remaining
   arguments are arguments passed to the remote method.
   
   The value returned by the function is the decoded value returned
   by the remote method.

   If the call results in an XML-RPC Fault, then a Lisp error 
   of type xml-rpc-fault is signalled.

   The keyword arguments that may appear in the server list
   are :url, :agent, and :host.

   The url argument specifies the URL of the remote server.  The
   default value is taken from the variable *xml-rpc-url*.

   The agent argument may be a string that is passed to the server
   as the :user-agent header element.  The default value is :aserve;
   this value sends the AllegroServe version string.

   The host argument may be a string that is passed to the server
   as the :host header element.  When this argument is nil, the
   :host header element is omitted.



xml-rpc-call encoded &rest more			    Function
         &key url agent host headers 

   The purpose of this function is to call the remote method and to
   decode the result.

   The first argument is a string produced by the encode-xml-rpc-call
   function.  It is the encoded version of the method name and argument
   values.
   
   The value returned by the function is the decoded value returned
   by the remote method.

   If the call results in an XML-RPC Fault, then a Lisp error 
   of type xml-rpc-fault is signalled.

   The url argument specifies the URL of the remote server.  The
   default value is taken from the variable *xml-rpc-url*.

   The agent argument may be a string that is passed to the server
   as the :user-agent header element.  The default value is :aserve;
   this value sends the AllegroServe version string.

   The host argument may be a string that is passed to the server
   as the :host header element.  When this argument is nil, the
   :host header element is omitted.

   The headers argument is combined with the :host header element
   and passed on to AllegroServe.

   Any other arguments are passed on to the AllegroServe
   do-http-request function.  Since the xml-rpc-call function
   passes its own version of the :method :protocol :content-type
   :content :user-agent arguments, these should not be specified.


*xml-rpc-url*                                     Variable

   The value of this variable is the default URL used to make
   a client call.  If many calls to the same server are made in some 
   context, the setting of this variable may be used to provide the
   correct default URL.




** XML-RPC DATA API

We provide classes and functions that give the programmer control over 
the encoding and decoding of Lisp values.

   Lisp Data Type           Default Encoding    Default Decoding
   --------------           ----------------    ----------------
   integer                  <int> or <i4>       integer
   float                    <double>            float
   string                   <string>            string
   list                     <array>             list
   xml-rpc-struct           <struct>            xml-rpc-struct
                            <boolean>           t  or  nil
                            <base64>            string or USB8 array

Some XML-RPC data types must be explicitly created by the application
since it is not possible to infer them from the Lisp data type.


xml-rpc-struct                                      Class

   The purpose of this class is to represent the XML-RPC <struct>
   data type.


xml-rpc-struct-members xml-rpc-struct               Reader Method

   This function returns a list of members defined in the <struct>.
   Each item in the list is an instance of the xml-rpc-member class.


xml-rpc-member                                      Class

   The purpose of this class is to represent the members defined
   in a <struct>.


xml-rpc-member-name xml-rpc-member                  Reader Method

   This function returns a string that represents the name of the
   <struct> member.


xml-rpc-member-value xml-rpc-member                 Accessor Method

   This function returns the Lisp value of the <struct> member.


xml-rpc-encoding                                    Class

   The purpose of this class is to represent an explicit encoding
   of a Lisp value into an XML-RPC protocol value.  Instances of 
   this class are created when a default encoding cannot be used to
   create the desired encoding.


xml-rpc-slot-value                                  Generic Function
   xml-rpc-struct slot-name &key (error-p t)

   The purpose of this function is to access the value of a member
   in a <struct> instance.

   The slot-name argument can be a string or a symbol.  If specified
   as a string it must match the member name exactly.  If specified as
   a symbol, the symbol name must match.  In a Modern image use equal;
   in an ANSI image, use string-equal for a more sloppy but convenient
   match.

   The value returned is the current Lisp value of the member.
   If the error-p argument is nil, return nil if the member is not found.


(setf xml-rpc-slot-value)     	   	      	     Generic Function
   new-value xml-rpc-struct slot-name &key (error-p t) 

   This function may be used to store a new value as the Lisp value of
   the member.

   The slot-name argument can be a string or a symbol.  If specified
   as a string it must match the member name exactly.  If specified as
   a symbol, the symbol name must match.  In a Modern image use equal;
   in an ANSI image, use string-equal for a more sloppy but convenient
   match.

   If the error-p argument is nil, the call is ignored and the returned
   value is nil.
   

make-xml-rpc-struct &rest name-value-sequence          Function

   This function creates an object from which an XML-RPC <struct> 
   instance can be encoded.  The arguemnts are an alternating 
   sequence of name and value arguments.  The name argument names
   a member of the <struct>, the value argument is a Lisp value to
   be encoded as the value component of the member.

   Each name argument may be a string or symbol or a list.
   A name or symbol specifies the name of the member and a default
   encoding for the Lisp value.  A list consists of a name for the
   member and a keyword that specifies the desired XML-RPC 
   encoding.  All the encoding keywords are described with the
   encode-xml-rpc-value function.  A third element in the list may
   be t or nil to specify whether the encoding for the Lisp value 
   should be cached in the member object.


make-xml-rpc-encoding data &optional type &rest more   Function

   The purpose of this function is to make an explicit encoding of
   a Lisp value to create an encoded value that cannot be obtained
   from a default encoding.

   If the type argument is omitted or nil, then the data argument
   value is encoded by default rules:

                   integer           <i4>
                   float             <double>
                   string            <string>
                   sequence          <array>
                   xml-rpc-encoding  the encoding stored in the object
                   xml-rpc-struct    <struct>

   The type argument may be a keyword to insure a specific encoding:

       :int        The data argument is truncated to an integer.   <i4>
       :truncate   The data argument is truncated to an integer.   <i4>
       :round      The data argument is rounded to an integer.     <i4>
       :string     The data argument is converted to a string      <string>
                    with a ~A format directive.
       :double     The data argument is coerced to a doubl-float.  <double>
       :boolean    The data argument may be nil(false) or          <boolean>
                    non-nil(true).
       :date       The data argument may be an integer treated     <dateTime.iso8601>
                    as a CL universal time number or a list
                    of (second minute hour day month year).
                   In the second form, the year is treated 
                    literally - not as in the CL definition,
                    to allow dates before 1900.
       :base64     The encoding is always a string of base64       <base64>
                    characters.  The expected data and the conversion 
		    depends on the value of *xml-rpc-base64*:

                    :string  - this default value implements the 
                      behavior in previous versions. If the data is
		      not a string, it is converted to a string with
		      the ~A format directive.  The string is then
		      encoded as base64 characters.

		    :array  - this value implements new behavior in version (2 9 6).
      		      The data must be of type (array (unsigned-byte 8) (*)).
		      The bytes in the array are encoded as base64 characters.

       :struct     If the data argument is an xml-rpc-struct        <struct>
                    instance, then the data argument is encoded
                    as in the default case.
                   Otherwise, the data argument is ignored and the 
                    more argument must be a list of items of the
                    form (name value [type] ...) where name denotes 
                    a member name, value is the Lisp value of the
                    member and the remainder of the list is used
                    in a recursive call to encode the Lisp value.
                   This second form allows a <struct> argument to be
                    encoded without creating an xml-rpc-struct
                    instance.
       :encoded    The data argument must be a string that contains
                    a correct XML-RPC value encoding.

   If an encoded value cannot be created, a Lisp error of type
   xml-rpc-argument-error is signalled.


encode-xml-rpc-value data &optional type &rest more    Function

   This function is very similar to make-xml-rpc-encoding, but the
   value returned is a string that contains an XML-RPC value encoding.
   Since the resulting string must be stored in an xml-rpc-encoding
   instance to be recognized in an argument conversion, this function
   is only useful in some circumstances where creating the xml-rpc-encoding
   instance must be delayed.  An instance is created with the form

      (make-xml-rpc-encoding (encode-xml-rpc-value ...) :encoded)



** XML-RPC SERVER API

The server API allows a Lisp application to act as an XML-RPC server
on the internet.  Other application, possibly written in other languages 
such as Java and Perl, may then call the methods exported by the server.



xml-rpc-server                                  Class

xml-rpc-export                                  Class

xml-rpc-server-name                             Accessor Method

*xml-rpc-server*                                        Variable

make-xml-rpc-server &key start enable publish          Function
                           class name introspect

   This function creates an instance of the xml-rpc-server class to
   hold the definitions of a set of exported functions.

   The publish argument defines how the server is seen from the client 
   side.  It is the list of arguments passed to the aserve:publish
   function.  If the :path argument is missing, the value "/RPC2"
   is supplied.  If :function or :content-type are specified, an
   error is signalled.

   If the start argument is non-nil, then the function aserve:start is
   called.  If the start argument is a list, this list is used as the
   argument list to aserve:start, otherwise aserve:start is called with
   all default arguments.

   If the enable argument is non-nil, then the server is enabled.
   If the enable argument is non-nil, but the start argument is nil, then
   AllegroServe must already be running when make-xml-rpc-server is
   called.

   PROGRAMMING NOTE: The XMLRPC module uses AllegroServe as the web
   interface.  The :start and :enable arguments are provided as convenient
   ways of interacting with AllegroServe in typical situations.  In
   some situations, such as when two web servers may be running in the 
   same Lisp image, the AllegroServe documentation should be consulted
   to make sure that AllegroServe and XMLRPC interact correctly.
   It is also typically undesirable to call aserve:start twice for
   the same server instance.

   The name argument is returned to clients as the :server header entry.
   The default name is "AllegroServe/x.x.x(Allegro Common Lisp)".

   The class argument can specify the name of a sub-class of xml-rpc-server.
   If the class is specified as a list, the car is the class name, the
   cdr is a list of initargs to make-instance.  Note that the initargs
   :parameters publish :name name  are always included. 
   This feature allows applications to add slots or methods to the
   server object.  This object is bound to *xml-rpc-server* when an
   exported function is called.

   If the introspect argument is non-nil, the standard introspection methods 
   are exported automatically (see export-standard-xml-rpc-methods).


enable-xml-rpc-server server &optional enable-exports   Generic Function

   This function enables a server and optionally enables any
   exported methods.

   A method is available to a client only if all three conditions are met:

     - AllegroServe is running
     - the XML-RPC server is enabled
     - the particular method is enabled

   If many methods need to be exporteded, the normal sequence of events is
   to make a disabled server, define and enable all the methods, and
   finally enable the server.  In this way all the methods become available
   simultaneously.


disable-xml-rpc-server server                              Generic Function

   This function disables the server and makes all the methods unavailable.


export-xml-rpc-method                                      Generic Function
   server name-spec result-spec &rest arg-specs

   This function makes a method available to XML-RPC client applications.

   The server argument must be an xml-rpc-server instance.

   The name-spec argument may be a symbol or a list.
   When name-spec is a list, the first element must be a string or symbol
   that names the exported method - this is the name that a client uses to
   call the remote method.  The second element of the list is the name of 
   the Lisp function that will be called as the exported method.  If the second
   element in the list is omitted or nil, then the first element must be a
   symbol that is also the name of the Lisp function to be called.
   The third element in the list is nil or non-nil; non-nil specifies that the 
   method is enabled immediately;  if nil is specified, then the method must be
   enabled explicitly by calling enable-xml-rpc-method;  if the third element is
   omitted, t is assumed and the method is enabled.  The fourth element in the
   list may be a string containing a description of the method.
   When name-spec is a symbol, it is equivalent to (symbol nil t).

   The result-spec argument must be one of the keywords that represent
   XML-RPC data types.  It is the type of the result returned to the caller.
   The available keywords are :int, :double, :string, :array, :struct, 
   and :base64.

   The remaining arguments are a list of XML-RPC data type keywords that
   describe the method signature.

   Several methods, with different arguemnt signatures, may be exported under
   the same method name.

   The Lisp function is called with the decoded arguments of the remote call.
   The value returned by the Lisp function is encoded using the data type of
   the value and the result-spec.  If the function returns an explicit
   xml-rpc-encoding then the result-spec is ignored.  If the function
   signals an instance of xml-rpc-fault, the reply is a fault message 
   where the faultCode element is taken from the :fault-code initarg and
   the faultString element is taken from the :fault-string initarg.
   If the function signals any other error, the reply is a fault message
   where the faultCode is 2 and the faultString is a representation of
   the Lisp error.



xml-rpc-method-help server name                            Generic Function

   This function returns the help string associated with an
   exported method name.  All the methods with one name share the same
   help string.


(setf xml-rpc-method-help) new-string server name               Generic Function

   This function may be used to store a new help string.



export-standard-xml-rpc-methods server &optional enable    Generic Function

   This function exports three introspection methods frequently provided
   by XML-RPC servers.  The enable argument may be nil to suppress
   automatic enabling of these methods.

   The methods are:

       system.listMethods()               returns <array>
       system.methodSignature(<string>)   returns <array>
       system.methodHelp(<string>)        returns <string>


enable-xml-rpc-method server name &rest arg-specs          Generic Function

   This function enables an individual exported method, or all the methods
   with the same name.

   If the arg-specs argument is a list of the single keyword :all, then all
   the methods with the specified name are enabled.

   Otherwise, arg-specs must be a list of keywords that represent
   XML-RPC data types.  The method with the matching argument signature
   is enabled.   


disable-xml-rpc-method server name &rest arg-specs         Generic Function 

   This function disables an individual exported method, or all the methods
   with the same name.

   If the arg-specs argument is a list of the single keyword :all, then all
   the methods with the specified name are disabled.

   Otherwise, arg-specs must be a list of keywords that represent
   XML-RPC data types.  The method with the matching argument signature
   is disabled.   





** EXAMPLE

   A simple client call:

            (xml-rpc-call 
	      (encode-xml-rpc-call "currentTime.getCurrentTime")
	      :url "http://time.xmlrpc.com:80/RPC2"
	      )


   A client call with an arguemnt:

            (xml-rpc-call 
	      (encode-xml-rpc-call "system.methodSignature" "meerkat.getCategories")
	      :url "http://www.oreillynet.com/meerkat/xml-rpc/server.php"
	      )

  
   The validation server:

            (defun make-validator1-server (&optional (port 8080))
              (let ((s (make-xml-rpc-server 
	                  :start nil :enable t
	                  :publish '(:path "/ACL-XML-RPC2"))))

                  (export-xml-rpc-method s 
                     '("validator1.arrayOfStructsTest" validator1-array-of-struct)
                     :int :array)

                  (export-xml-rpc-method s 
                     '("validator1.countTheEntities" validator1-count)
                     :struct :string)

                  ...
    
                  (start :port port)
                  (enable-xml-rpc-server s)
                  s))
  

   and one of the validator functions:

              (defun validator1-count (string)
                 ;; validator1.countTheEntities   -- returns :struct
                 ;; 
                 ;; This handler takes a single parameter, a string, 
                 ;;  that contains any number of predefined entities,
                 ;;  namely <, >, &, ' and ".
                 ;; Your handler must return a struct that contains five fields, 
                 ;;  all numbers: ctLeftAngleBrackets,  ctRightAngleBrackets, 
                 ;;               ctAmpersands, ctApostrophes, ctQuotes. 

                (make-xml-rpc-struct
                     "ctLeftAngleBrackets"  (count #\< string)
                     "ctRightAngleBrackets" (count #\> string)
                     "ctAmpersands"         (count #\& string)
                     "ctApostrophes"        (count #\' string)
                     "ctQuotes"             (count #\" string)))


** NOTES

;;; TO DO:
;;; <dateTime.iso8601> what to do with negative year???
