Example SOAP Server and Client

As of this writing, server-side implementations of SOAP services are virtually nonexistent. The few that do exist stray from the emerging standards and are likely to continue to morph as they discover what the users really want.

The most stable web service sample implementations come from Microsoft and IBM. In this section, we create a Python client that utilizes the calculator service that ships with Microsoft’s free SOAP Toolkit 2.0, available from http://msdn.microsoft.com. As such, the service must run on either Windows NT Server 4.0 or Windows 2000 Server. The clients may run anywhere COM runs. The toolkit sets up very easily on these platforms, and is ready to go after the install script is finished.

The Python client created in this section uses COM to connect with the MSSOAP type library objects, and interacts with the service. The clients can run on virtually all flavors of Windows, provided they have access to the services and WSDL files residing on the server. Note that the clients can easily (and probably most conveniently) run on the same machine as the servers.

Requirements for Using MSSOAP

SOAP and web services are new, and as such require the installation of software for developers who wish to experiment the technology. The rest of this chapter relies on COM; therefore, if you are not familiar with the workings of COM and Python, this section helps to get things set up.

The following steps are required in order to run the Python client example in this section.

  1. The Microsoft SOAP Toolkit 2.0 must be installed on a server.

  2. The WSDL and service implementations that ship with the SOAP Toolkit must be visible via HTTP on your network, per the installation examples that ship with the toolkit. This is true even if you are running the client and server on the same machine.

  3. Python clients must have win32all.exe (Python COM Support available from http://aspn.activestate.com and developed by Mark Hammond) installed, and the utility script makepy.py must be applied against the SOAP Type Library. Additionally, if running the clients on a different machine, the SOAP Toolkit, or at least the COM object .dll files, must be installed.

Getting Microsoft SOAP Toolkit 2.0

Microsoft has made available client DLLs and robust client and server example implementations in their SOAP Toolkit 2.0. This is a free download, fully supported as well as available from http://msdn.microsoft.com/downloads/default.asp.

When installing the toolkit, you automatically receive an updated MSXML 3.0 package, which fully supports XSLT. Appendix E covers working with Python and the MSXML parser.

Making the samples web-visible

When you install the samples, you need to follow the instructions for creating a virtual directory in IIS (Internet Information Server, the default HTTP implementation on Windows servers) that can point to the samples. The instructions call for putting an entry for MSSOAPSampleServer in your hosts file (c:winntsystem32hosts), but this step is optional, and is only required if you intend to run the Microsoft sample clients. For the purpose of this chapter, you are writing a Python client from scratch; therefore, your existing hostname is fine. You need to be able to see the samples directory via HTTP, as the instructions indicate.

If you plan on running the Python client from the same machine that hosts the samples, you won’t need to install anything else (except perhaps Python COM support) to proceed.

Getting Python COM support

If you have not used COM from Python (and we haven’t yet in this book), you need to download and install Python COM support. Start by retrieving the appropriate installer from the Web available at http://aspn.activestate.com/ASPN/Downloads/ActivePython/Extensions/Win32all.

There are links and instructions to download win32all.exe for your version of Python; read the information on this web page carefully to be sure you get the right version. This installer provides full support for COM from your Python programs, and allows you to implement COM servers from other languages to use.

Fixing MSSOAP with makepy.py

Even if you already have Python COM support (or just installed it), you need to tweak Python’s access to the SOAP Type Library. Unfortunately, the authors of the SOAP Toolkit objects rely on Visual Basic’s and Windows Scripting’s ability to set object properties like this:

Object.Property("PropertyName") = NewPropertyValue

That’s not even legal syntax in Python! Visual C++ uses a slightly different syntax, allowing an overloaded operator to provide syntax that matches Python’s dictionary assignment syntax:

Object.Property["PropertyName"] = NewPropertyValue

Great! This syntax works just fine in Python if you are assigning a value to an element of a member dictionary. Unfortunately, the COM API does not automatically convert this COM construct to Python member dictionaries. For this specific object, Property is a method, and there is no way to assign a value in Python to an object method. Typically, components implement access methods, or at the minimum, implement SetProperty and GetProperty type constructs. Thankfully, the makepy.py script that ships with win32all.exe wraps another Python interface on top of the COM objects and uses a lower-level API to access them correctly, allowing you to overcome this aspect.

To run makepy.py, launch it from within the win32comclient directory of your Python installation (typically, C:Python20win32comclient):

C:Python20win32comclient>python makepy.py

A dialog GUI pops up that displays all of the different type libraries registered on your system. Find Microsoft SOAP Type Library (1.0) and click Ok. The script suddenly produces a flurry of activity (evidenced by frequent text output) and writes a .py file with a monstrously long name inside the folder C:Python20win32comgen_py. You probably will not need to see that file again, as you can use a standard call to win32com.client.Dispatch to invoke the object and it will seek out the updated Python-friendly interface that makepy.py created. Figure 9-1 shows the dialog in action with Microsoft SOAP Type Library (1.0) highlighted.

Selecting the SOAP Type Library with makepy.py
Figure 9-1. Selecting the SOAP Type Library with makepy.py

Once you’ve created the Python interface for the object by selecting Ok, you may go about instantiating the object normally, but now you can call constructs such as:

Object.SetProperty("PropertyName", "NewValue")

The makepy.py accomplishes more than just correcting property assignments for Python syntax, as it can also be used to smooth out parameter types and properties for all sorts of COM objects. See the makepy documentation for more information.

Server Setup

Before we get into developing the client, it’s important to understand the server setup. SOAP and web services are inherently cross-platform. While you are running services implemented on Windows, clients can conceivably be written on any platform, provided they can either create the correct kind of SOAP packet to invoke the services, or interpret the published WSDL to wrap the services with a local stub object.

The Python client implemented here uses COM access to a SOAP connector and serializer; however any SOAP implementation should be able to connect to these services and utilize them.

The server setup that ships with the toolkit is merely a collection of WSDL files describing services, as well as service end-points that implement them. The end-points are in a variety of languages and techniques, ranging from Active Server Pages to ISAPI plug-ins. The interface to these services is purely SOAP.

A Python SOAP Client

The SOAP Toolkit ships with a Calculator service. This service offers four different operations that it performs on two supplied parameters, much like a basic calculator. This example is similar in functionality to the VBScript sample client that ships with the Toolkit. The most significant difference between the two is that your client is implemented entirely in Python from scratch, not in VBScript.

The calculator operations are add, subtract, multiply, and divide. If your SOAP Toolkit is freshly installed, it’s a good idea to verify that the calculator service is running properly by testing it with one of the sample clients that ships with the toolkit—it certainly aids in the debugging phase of things (if you need to debug!) In other words, knowing that your web server and SOAP implementations are working helps to isolate any problems or errors that may occur when running your Python client.

Defining reusable basics

To properly build the SOAP packet, define a portion of the SOAP Action URI, allowing for the appending of different method names. You also want to reuse the namespace URI between method invocations. These two reused items, along with the service end-point, are defined up front as global variables:

import win32com.client

# SOAP Action URI
BaseSoapActionUri = "http://tempuri.org/action/Calc."

# Namespace
WrapperElementNamespace = "http://tempuri.org/message/"

# Service End Point
EndPointUrl = 
  "http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp"

You can take calculator functionality and embed it within a method, allowing the method to take a string representing the operation you wish to perform, along with the parameters. This method can then repeatedly be called to generate answers:

def Calculate(Op, Val1, Val2):
  """Return a result based on the operator 'Op' and two input values."""
  # Instantiate HttpConnector
  connector = win32com.client.Dispatch("MSSOAP.HttpConnector")

Immediately as the function begins, the HTTP SOAP connector is created as shown in the preceding code. The connector is then handed some critical information regarding the location of the service:

# Set properties (will fail if makepy.py wasn't run
#                 on SOAP type library)
connector.SetProperty("EndPointURL", EndPointUrl)
connector.SetProperty("SoapAction", BaseSoapActionUri + Op)

# Start SOAP message
connector.BeginMessage(  )

What’s critical in this code snippet is the SetProperty call to change the value of SoapAction. If you note, the BaseSoapActionUri is concatenated with the desired operation Op. If using the add method, create a SoapAction string similar to:

http://tempuri.org/action/Calc.Add

Now the task turns to actually creating the SOAP envelope.

# Create a serialization object
serializer = win32com.client.Dispatch("MSSOAP.SoapSerializer")

# Attach it to the connector created earlier
serializer.Init(connector.InputStream)

The serializer is bound to the connector’s input stream, so that the SOAP packet actually finds its way to the service end-point. Creating the rest of the packet follows the same pattern shown earlier, with methods representing the starting and ending of elements:

# Create SOAP Envelope
serializer.startEnvelope(  )
serializer.startBody(  )
serializer.startElement(Op, WrapperElementNamespace, '', "m")
serializer.startElement("A")
serializer.writeString(Val1)
serializer.endElement(  )
serializer.startElement("B")
serializer.writeString(Val2)
serializer.endElement(  )
serializer.endElement(  )
serializer.endBody(  )
serializer.endEnvelope(  )

# Finish SOAP message
connector.EndMessage(  )

The reader is brought in to read and interpret the result of the call to the service. As discussed earlier, in Section 9.2, the reader is attached to the connector’s output stream, and digests the information as it is returned:

# Create SOAP reader object
reader = win32com.client.Dispatch("MSSOAP.SoapReader")
reader.Load(connector.OutputStream)

# check for errors
if reader.Fault:
  print "Error: ", reader.faultstring.Text

# Return calculation value
return reader.RPCResult.Text

If there has been an error, it is reflected in the reader.Fault property. When a SOAP call fails, the SOAP server sends a fault entry back to the client. SOAP uses many of the same semantics as HTTP regarding propagating error conditions back to the caller. In fact, when using SOAP over HTTP, SOAP is bound to some of the same exact error conditions—SOAP must send back an HTTP 500 Internal Server Error, even if the web server behaves as expected but the code handling the SOAP request fails. (This is required to ensure that knowledge of the implementation details of the server is not needed by the client; it is not a failing of the SOAP or HTTP protocols.)

Example 9-1 shows the complete listing of PyCalcSerial.py.

Example 9-1. PyCalcSerial.py
"""
Python MSSOAP Serializer Example
"""
# import support for COM
import win32com.client

# SOAP Action URI
BaseSoapActionUri = "http://tempuri.org/action/Calc."

# Namespace
WrapperElementNamespace = "http://tempuri.org/message/"

# Service End Point
EndPointUrl = 
  "http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp"

# Calculate(operation, value1, value2)
#   Takes an operator (as a word like "Add") along
#   with two values and returns the result
def Calculate(Op, Val1, Val2): 
  # Instantiate HttpConnector
  connector = win32com.client.Dispatch("MSSOAP.HttpConnector")

  # Set properties (will fail if makepy.py wasn't run
  #                 on SOAP type library)
  connector.SetProperty("EndPointURL", EndPointUrl)
  connector.SetProperty("SoapAction", BaseSoapActionUri + Op)

  # Start SOAP message
  connector.BeginMessage(  )

  # Create a serialization object
  serializer = win32com.client.Dispatch("MSSOAP.SoapSerializer")

  # Attach it to the connector created earlier
  serializer.Init(connector.InputStream)

  # Create SOAP Envelope
  serializer.startEnvelope(  )
  serializer.startBody(  )
  serializer.startElement(Op, WrapperElementNamespace, '', "m")
  serializer.startElement("A")
  serializer.writeString(Val1)
  serializer.endElement(  )
  serializer.startElement("B")
  serializer.writeString(Val2)
  serializer.endElement(  )
  serializer.endElement(  )
  serializer.endBody(  )
  serializer.endEnvelope(  )

  # Finish SOAP message
  connector.EndMessage(  )

  # Create SOAP reader object
  reader = win32com.client.Dispatch("MSSOAP.SoapReader")
  reader.Load(connector.OutputStream)

  # check for errors
  if reader.Fault:
    print "Error: ", reader.faultstring.Text

  # Return calculation value
  return reader.RPCResult.Text

# Main line-- do some calculations
print "Using Service:", EndPointUrl
print "Calculate 3 * 4: 	", 
print Calculate("Multiply", 3, 4)

print "Calculate 4 - 3: 	", 
print Calculate("Subtract", 4, 3)

print "Calculate 345 + 1004: 	", 
print Calculate("Add", 345, 1004)

print "Calculate 115 / 5: 	", 
print Calculate("Divide", 115, 5)

To run the example, just launch it from your command line. You should then see output similar to the following:

C:my-dir> python PyCalcSerial.py
Using Service: http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp
Calculate 3 * 4:        12
Calculate 4 - 3:        1
Calculate 345 + 1004:   1349
Calculate 115 / 5:      23

SOAP is the heart of web services, at least as they are being described by most of the big players. WSDL, if implemented correctly, is seldom even seen by developers as it can be automatically generated from object source files. When support for WSDL matures, most languages (most likely including Python) will have WSDL generators that generate WSDL directly from class code. Of course, these tools can also be provided by SOAP server implementations, or by Python object servers such as Zope.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.107.229