Joshua Boverhof,
jrboverhof@lbl.gov
Charles Moad
Release 2.0.0
February 01, 2007
Copyright © 2001, Zolera Systems, Inc.
All Rights Reserved.
Copyright © 2002-2003, Rich Salz.
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.
Copyright © (c) 2003, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
(1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. (2) 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. (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory, U.S. Dept. of Energy 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 COPYRIGHT OWNER 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.
You are under no obligation whatsoever to provide any bug fixes, patches, or upgrades to the features, functionality or performance of the source code ("Enhancements") to anyone; however, if you choose to make your Enhancements available either publicly, or directly to Lawrence Berkeley National Laboratory, without imposing a separate written license agreement for such Enhancements, then you hereby grant the following license: a non-exclusive, royalty-free perpetual license to install, use, modify, prepare derivative works, incorporate into other computer software, distribute, and sublicense such Enhancements or derivative works thereof, in binary and source code form.
ZSI, the Zolera SOAP Infrastructure, is a Python package that provides an implementation of the SOAP specification, as described in SOAP 1.1 Specification.
This guide demonstrates how to use ZSI to develop Web Service applications from a Web Services Description Language document.
This document is primarily concerned with demonstrating and documenting how to use a Web Service by creating and accessing Python data for the purposes of sending and receiving SOAP messages. Typecodes are used to marshall Python datatypes into XML, which can be included in a SOAP Envelope. The typecodes are generated from information provided in the WSDL document, and generally describe SOAP and XML Schema data types. For a low-level treatment of typecodes, and a description of SOAP-based processing see the ZSI manual.
The wsdl2py script is the primary tool. It will generate all the code needed to access a Web Service through an exposed WSDL document, usually this description is available at a URL which is provided to the script.
wsdl2py generates a "stub" module from the WSDL SOAP Bindings. It contains various classes, including a Locator which represents the bindings to the actual Web Service, and several port classes that are used to remotely invoke operations on the Web Service, as well as various Message classes that represent the SOAP and XML Schema data types. A Message instance is serialized as a XML instance. A Message passed as an argument to a port method is then serialized into a SOAP Envelope and transported to the Web Service, the client will then wait for an expected response, and finally the SOAP response is marshalled back into the Message returned to the user.
A second module the "types", contains typecodes representing all the components
of each schema specified by the target WSDL Document (not including built-in
types). Each schema component declared at the top-level, the immediate children
of the schema tag, are global in scope and by importing the "types" module
an application has access to the GEDs and global type definitions either
directly by reference or through the convenience functions GED
and
GTD
, respectively.
**keywords) |
These four items are represented by three abstractions, consisting of a Locator class, PortType class, and several Message classes. The Locator will have two methods for each service port declared in the WSDL definition. One method returns the address specified in the binding, and the other is a factory method for returning a PortType instance. Each Message class represents the aspects of the binding at the operation level and below, and any type information specified by message part items.
The module level class defintions each represent a unique namespace, they are simply wrappers for the contents of individual namespaces. The inner classes are the typecode representations of global type definitions (suffix _Def), and element declarations (suffix _Dec).
From Namespaces in XML NCName ::= (Letter | '_') (NCNameChar)* NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender From Python Reference Manual (2.3 Identifiers and keywords) identifier ::= (letter|"_") (letter | digit | "_")* Default set of anames ANAME ::= ("_") (letter | digit | "_")*
|
digit |
"_") change to "_"
(namespace,name)
tuples, the value of each key represents the value of
the attribute.
__metaclass__
attribute will be set on all generated
pyclasses. The metaclass will introspect the typecode attribute of
pyclass, and create a set of helper methods for each element
and attribute declared in the complexType definition. This option simply
adds wrappers for dealing with content, it doesn't modify the generation scheme.
get_element_ANAME
and
set_element_ANAME
respectively. In this example, variable wsreq
has functions named get_element_Options
and set_element_Options
.
In addition to elements, getters and setters are generated for the attributes
of a complex type. For attributes, just the name of the attribute is used in
determining the method names, so get_attribute_NAME and set_attribute_NAME are
created.
newANAME
, so wsreq has
a factory method, new_Options
.
PNAME
, where the first letter of the type's pname
attribute is capitalized. In our running example, wsreq has class
property, Options
, which calls functions get_element_Options
and
set_element_Options
under the hood.
<xsd:complexType name='WolframSearchOptions'> <xsd:sequence> <xsd:element name='Query' minOccurs='0' maxOccurs='1' type='xsd:string'/> <xsd:element name='Limit' minOccurs='0' maxOccurs='1' type='xsd:int'/> </xsd:sequence> <xsd:attribute name='timeout' type='xsd:double' /> </xsd:complexType> <xsd:element name='WolframSearch'> <xsd:complexType> <xsd:sequence> <xsd:element name='Options' minOccurs='0' maxOccurs='1' type='ns1:WolframSearchOptions'/> </xsd:sequence> </xsd:complexType> </xsd:element>
# Create a request object to operation WolframSearch # to be used as an example below from WolframSearchService_services import * port = WolframSearchServiceLocator().getWolframSearchmyPortType() wsreq = WolframSearchRequest()
# sample usage of the generated code # get an instance of a Options holder class using factory method opts = wsreq.new_Options() wsreq.Options = opts # assign values using the properties or methods opts.Query = 'Newton' opts.set_element_Limit(10) # don't forget the attribute opts.set_attribute_timeout(1.0) # At this point the serialized wsreq object would resemble this: # <WolframSearch> # <Options timeout="1.0" xsi:type="tns:WolframSearchOptions"> # <Query xsi:type="xsd:string">Newton</Query> # <Limit xsi:type="xsd:double">10.0</Limit> # </Options> # </WolframSearch> # ready call the remote operation wsresp = port.WolframSearch(wsreq) # returned WolframSearchResponse type holder also has conveniences print 'SearchTime:', wsresp.Result.SearchTime
This section covers wsdl2py, the second way ZSI provides to access WSDL services. Given the path to a WSDL service, two files are generated, a 'service' file and a 'types' file, that one can then use to access the service. As an example, we will use the search service provided by Wolfram Research Inc.©, http://webservices.wolfram.com/wolframsearch/, which provides a service for searching the popular MathWorld site, http://mathworld.wolfram.com/, among others.
wsdl2py -bu http://webservices.wolfram.com/services/SearchServices/WolframSearch2.wsdl
Run the above command to generate the service and type files. wsdl2py uses the name attribute of the wsdl:service element to name the resulting files. In this example, the service name is WolframSearchService. Therefore the files WolframSearchService_services.py and WolframSearchService_services_types.py should be generated.
The 'service' file contains locator, portType, and message classes. A locator instance is used to get an instance of a portType class, which is a remote proxy object. Message instances are sent and received through the methods of the portType instance.
The 'types' file contains class representations of the definitions and declarations defined by all schema instances imported by the WSDL definition. XML Schema attributes, wildcards, and derived types are not fully handled.
The following shows how to call a proxy method for WolframSearch. It assumes wsdl2py has already been run as shown in the section above. The example will be explained in greater detail below.
# import the generated class stubs from WolframSearchService_services import * # get a port proxy instance loc = WolframSearchServiceLocator() port = loc.getWolframSearchmyPortType() # create a new request req = WolframSearchRequest() req.Options = req.new_Options() req.Options.Query = 'newton' # call the remote method resp = port.WolframSearch(req) # print results print 'Search Time:', resp.Result.SearchTime print 'Total Matches:', resp.Result.TotalMatches for hit in resp.Result.Matches.Item: print '--', hit.Title
Now each section of the code above will be explained.
from WolframSearchService_services import *
We are primarily interested in the service locator that is imported. The binding proxy and classes for all the messages are additionally imported. Look at the WolframSearchService_services.py file for more information.
loc = WolframSearchServiceLocator() port = loc.getWolframSearchmyPortType()
Using an instance of the locator, we fetch an instance of the port proxy which is used for invoking the remote methods provided by the service. In this case the default location specified in the wsdlsoap:address element is used. You can optionally pass a url to the port getter method to specify an alternate location to be used. The portType - name attribute is used to determine the method name to fetch a port proxy instance. In this example, the port name is WolframSearchmyPortType, hence the method of the locator for fetching the proxy is getWolframSearchmyPortType.
The first step in calling WolframSearch is to create a request object corresponding to the input message of the method. In this case, the name of the message is WolframSearchRequest. A class representing this message was imported from the service module.
req = WolframSearchRequest() req.Options = req.new_Options() req.Options.Query = 'newton'
Once a request object is created we need to populate the instance with the information we want to use in our request. This is where the -complexType option we passed to wsdl2py will come in handy. This caused the creation of functions for getting and setting elements and attributes of the type, class properties for each element, and convenience functions for creating new instances of elements of complex types. This functionality is explained in detail in subsection A.1.2.
Once the request instance is populated, calling the remote service is easy. Using the port proxy we call the method we are interested in. An instance of the python class representing the return type is returned by this call. The resp object can be used to introspect the result of the remote call.
resp = port.WolframSearch(req)
Here we see that the response message, resp, represents type WolframSearchReturn. This object has one element, Result which contains the search results for our search of the keyword, newton.
print 'Search Time:', resp.Result.SearchTime ...
Refer to the wsdl for WolframSearchService for more details on the returned information.
wsdl2dispatch -u http://webservices.wolfram.com/services/SearchServices/WolframSearch2.wsdl
class ServiceInterface: '''Defines the interface for use with ServiceContainer Handlers. ''' def __init__(self, post): self.post = post
# WolframSearchService_services_server.py class WolframSearchService(ServiceSOAPBinding): ... def soap_WolframSearch(self, ps): self.request = ps.Parse(WolframSearchRequest.typecode) return WolframSearchResponse() ...
#!/usr/bin/env python import sys from ZSI.ServiceContainer import AsServer from WolframSearchService_services_server import * class Service(WolframSearchService): def soap_WolframSearch(self, ps): rsp = WolframSearchService.soap_WolframSearch(self, ps) msg = self.request t1 = time.time() opts = msg.Options rsp.Result = result = rsp.new_Result() if opts.Query == 'Newton': result.TotalMatches = 1 result.Matches = match = result.new_Matches() item = match.new_Item() item.Title = "Fig Newtons" item.Score = 10 item.URL = 'http://www.nabiscoworld.com/newtons/' match.Item = [item] result.SearchTime = time.time() - t1 return rsp if __name__ == "__main__" : port = 8080 AsServer(port, (Service('test'),))
The ZSI.ServiceContainer.AsServer function is a convenient way to start a HTTP server that will dispatch to your various services. In a container all services should have unique paths, here the service is available at "test". A URL to contact this service at port 8080 would be http://localhost:8080/test
>=
2.4, Twisted>=
2.0.0, TwistedWeb>=
0.5.0
usage: wsdl2dispatch [options]
This document was generated using the LaTeX2HTML translator.
LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.
The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.