Copyright (c) 2001, actzero, inc.

SOAP.py 0.9.5 - Cayce Ullman   (cayce@actzero.com)
                Brian Matthews (blm@actzero.com)

MANIFEST:
quickstart.txt
../SOAP.py       the library
../SOAPtest.py   tests the builder and parser
../echoClient.py an example client
../echoServer.py an example server
../speedTest.py  benchmarks the various parsers, compares speed to DOM
../TCtest.py     experimental type coercion system tests
../tests/*       examples
../validate/*    interop client and servers
../bid/*	      N+I interop client and server


HOWTO:

The easiest way to understand use of data types is look at and run the examples
already written (in tests/, validate/ and bid/) , and to write your own 
clients, looking at the xml as it is sent (by setting SOAP.Config.debug=1).  


As far as the built-in types are concerned, SOAP.py will preserve type
as expected.  That is: python integer will be of type integer, and 
equivalently for string and float.  To access more than just these types, 
there are  classes in SOAP.py.  These allow invoking a certain type by making
an instance of the corresponding class.  

The SOAPBuilder in SOAP.py will automatically convert python lists to Arrays
and python dictionaries to Structs- these are two of the most frequently used
data types.



CLIENT EXAMPLES:

## CODE
import SOAP
server = SOAP.SOAPProxy("http://localhost:8080/")
print server.echo("Hello world")
## /CODE

This example (taken from quickstart.txt) sends an ordered parameter of type 
string.

## CODE
import SOAP
import time
#SOAP.Config.debug = 1
test = time.gmtime (time.time ())
server = SOAP.SOAPProxy("http://localhost:8080/")
print server.echoDate (inputDate = SOAP.DateTime(test))
## /CODE

This test calls echoDate with the named parameter inputDate, which is a 
TimeInstant.  It prints the the result.
**Note: The reason that it is a TimeInstant and not a DateTime
is that SOAP.py uses the 1999 schema intead of the 2001 schema.  To make it
a DateTime, one would just use SOAP.dateTimeType() in place of SOAP.DateTime().
**


## CODE
import SOAP
server = SOAP.SOAPProxy("http://localhost:8080/")
test = [0, 1, -1, 3853]
print server.echoIntegerArray (inputIntegerArray = test)
## /CODE

This calls echoIntegerArray with the named parameter inputIntegerArray, which
is a four-member array of type int.  It prints the result.

## CODE
import SOAP
test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'}
server = SOAP.SOAPProxy("http://localhost:8080/")
print server.echoStruct (inputStruct = test)
## /CODE

This code calls the method echoStruct with the named parameter inputStruct, 
which is of type Struct.  It then prints the result.


## CODE
import SOAP   
item1 = SOAP.Struct( data = {"name":"widget","quantity":200,"price":SOAP.decimalType(45.99), "_typename":"LineItem"})
items = SOAP.Array ( data = [item1] )
items._ns = "http://www.soapinterop.org/Bid"
server = SOAP.SOAPProxy("http://localhost:8080")
server = server._sa ("http://www.soapinterop.org/Buy")
server = server._ns ("http://www.soapinterop.org/Bid")
po = SOAP.Struct( data = {"poID":"Order 1234", "createDate": SOAP.dateTimeType(), "items": items} )
print server.Buy(PurchaseOrder = po)
## /CODE

A few new things here.  
-First, we are creating an Array, 'items', with components of (made up) type
 'LineItem'.  (Notice the use of "_typename" to specify type).
-This code associates a namespace with the Array, rather than use the default.
-SOAP.dateTimeType() is called directly to get a dateTime instead of SOAP.py's
 default, 'timeInstant'.
-Note that when creating a Struct or Array, the data must be passed in as a 
 named 'data' param (as the first param, by order, is 'name').
-The proxy is instantiated and then the values for its namespace (_ns) and
 soapaction (_sa) are assigned.
-This call will work for a server expecting a parameter with the same 
 components as those in the variable 'po' above.  It will work whether the
 server has a named param 'PurchaseOrder' or has an unnamed param, but will
 not work if the server expects a named param with a name of anything but 
 'PurchaseOrder'.



SERVER EXAMPLES:

## CODE
import SOAP
def echo(s):
    return s + s # repeats a string twice

server = SOAP.SOAPServer(("localhost", 8080))
server.registerFunction(echo)
server.serve_forever()
## /CODE

This server example, from quickstart.txt, echoes (as type string) the 
string that is passed in, s.


## CODE
import SOAP

def echoDate (inputDate):
    return SOAP.DateTime(inputDate)

server = SOAP.SOAPServer(("localhost", 8080))
server.registerKWFunction(echoDate )
server.serve_forever()
## /CODE

This code accepts an inputDate and returns the same date, ensuring that it
is of type TimeInstant by returning an instance of DateTime instead of 
simply returning the value.


## CODE
import SOAP
def echoIntegerArray (inputIntegerArray): 
    if type(inputIntegerArray) != type([]) or len(inputIntegerArray) != 4:
        for elem in inputIntegerArray:
            if type(elem) != type(1):
                raise TypeError, "expected 4-member Array of ints"
    return inputIntegerArray
server = SOAP.SOAPServer(("localhost", 8080))
server.registerKWFunction(echoIntegerArray )
server.serve_forever()
## /CODE

This server supports the method echoIntegerArray, requiring the named parameter
inputIntegerArray, which must be a four-member array of type int.


## CODE
import SOAP

def echoStruct (inputStruct):
    myfloat = inputStruct["varFloat"]
    mystr = inputStruct["varString"]
    myint = inputStruct["varInt"]
    return inputStruct

server = SOAP.SOAPServer(("localhost", 8080))
server.registerKWFunction(echoStruct )
server.serve_forever()
## /CODE

This code creates a server with a method echoStruct, which requires that the 
incoming Struct have elements named varFloat, varString, and varInt.  That is,
the server will fault if the incoming Struct does not have any of those 
elements.  **Note, this server code does NOT require that these be the only
elements in the struct- just that they be present**.  This method simply 
returns the Struct passed in.


## CODE 
import sys
import SOAP 
serverstring = "SOAP.py (actzero.com) running "+sys.platform
def Buy(**kw):
    try:
        PurchaseOrder = kw["PurchaseOrder"]
    except:
        PurchaseOrder = kw["PO"]

    POkeys = PurchaseOrder['_keyord']
    POkeys.sort()
    POkeys_expected = ["items","poID","createDate"]
    POkeys_expected.sort()
    if POkeys != POkeys_expected:
        raise ValueError, "struct 'PurchaseOrder' needs %s, %s, and %s" % tuple(POkeys_expected)

    items =  PurchaseOrder["items"].__dict__
    data = items["data"]
    retstring = ""
    for item in data:
        itemdict = item["_asdict"]
        q = itemdict["quantity"]
        p = itemdict["price"]
        name = itemdict["name"]
        if retstring != "":
            retstring += ", "
        else:
            retstring = "bought "
        retstring += "%d %s(s) for %.2f" % (q,name,p)
    retstring += " from "+serverstring 
    return retstring

server = SOAP.SOAPServer(("localhost", 8080))
namespace = "http://www.soapinterop.org/Bid"
server.registerKWFunction(Buy, namespace )
server.serve_forever()
## /CODE

This example creates a server to implement 'Buy', which takes a parameter 
named either PurchaseOrder or PO.  (Notice the use of **kw as the input 
parameter to the method for this functionality). 
The server gets the names of the Struct's members by using the '_keyord' 
key of the Struct-as-dictionary.  It checks these names against what it 
expects from the client, and raises a fault if the two are not the same.
By using the __dict__ attribute, the server gets the 'items' (an elemnent of
the PurchaseOrder Struct) as a dictionary.  Then it checks that 'items' is 
formatted as expected.  Finally, it returns a confirmation of what was bought.



Copyright (c) 2001, actzero, inc.
Copyright (c) 2001, Cayce Ullman.

All rights reserved.

LICENSE:
--------------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

Neither the name of actzero, inc. nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
