Beispiel für einen SOAP-Server und SOAP-Client

(Auszug aus "Python & XML" von Christopher A. Jones & Fred L. Drake, Jr.)

Im Moment ist es so, daß serverseitige Implementierungen von SOAP-Diensten im Prinzip nicht existieren. Die wenigen existierenden weichen von den sich abzeichnenden Standards ab und werden sich sehr wahrscheinlich noch stark verändern, während sie allmählich herausfinden, was die Benutzer wirklich wollen.

Die stabilsten Beispielimplementierungen von Webdiensten stammen von Microsoft und IBM. In diesem Abschnitt erzeugen wir einen Python-Client, der den Rechnerdienst benutzt, der in Microsofts freiem SOAP-Toolkit 2.0 enthalten ist. Der Dienst als solcher muß entweder unter Windows NT Server 4.0 oder Windows 2000 Server laufen. Die Clients können überall dort laufen, wo COM läuft. Das Toolkit ist auf diesen Plattformen sehr leicht einzurichten und ist sofort nach Beendigung des Installationsskripts einsatzbereit.

Der in diesem Abschnitt erstellte Python-Client benutzt COM, um sich mit Objekten der MSSOAP-Typbibliothek zu verbinden, und interagiert mit dem Dienst. Die Clients können im Prinzip jede beliebige Version von Windows verwenden, solange sie Zugang zu den Diensten und den WSDL-Dateien auf dem Server haben. Beachten Sie, daß die Clients auch auf dem gleichen Rechner laufen können wie die Server (was vermutlich auch am bequemsten ist).

Anforderungen bei der Verwendung von MSSOAP

SOAP und Webdienste sind neu, und daher müssen Entwickler, die mit der Technologie experimentieren möchten, entsprechende Software installieren. Der Rest dieses Abschnitts hängt sehr von COM ab. Wenn Sie also mit der Arbeitsweise von COM und Python nicht vertraut sind, sollte dieser Abschnitt dabei helfen, das Notwendige einzurichten.

Die folgenden Schritte sind notwendig, um das in diesem Abschnitt vorkommende Beispiel eines Python-Clients ausführen zu können.

  1. Das Microsoft SOAP Toolkit 2.0 muß auf einem Server installiert sein.
  2. Die WSDL- und Dienstimplementierungen, die im SOAP-Toolkit enthalten sind, müssen durch die Installationsbeispiele im Toolkit über HTTP in Ihrem Netzwerk sichtbar sein. Das trifft auch dann zu, wenn Sie Client und Server auf dem gleichen Rechner laufen lassen.
  3. Python-Clients müssen win32all.exe (Python-Unterstützung von COM und entwickelt von Mark Hammond) installiert haben, und das Hilfsskript makepy.py muß auf der SOAP-Typbibliothek ausgeführt sein. Wenn die Clients auf einem anderen Rechner laufen sollen, müssen dort das SOAP-Toolkit oder zumindest die COM-Objektdateien mit der Endung .dll installiert sein.

Herunterladen des Microsoft SOAP Toolkit 2.0

Microsoft hat Client-DLLs und robuste Client- und Server-Beispielimplementierungen in seinem SOAP Toolkit 2.0 verfügbar gemacht.

Bei der Installation des Toolkits erhalten Sie automatisch ein aktualisiertes Paket von MSXML 3.0, das XSLT vollständig unterstützt. Arbeiten mit MSXML 3.0 behandelt das Arbeiten mit Python und dem MSXML-Parser.

Sichtbarmachen der Beispiele im Web

Wenn Sie die Beispiele installieren, müssen Sie den Anweisungen zur Erstellung eines virtuellen Verzeichnisses in IIS (Internet Information Server, die Standard-HTTP-Implementierung auf Windows-Servern) folgen, das auf die Beispiele zeigen kann. In den Anweisungen wird verlangt, daß Sie einen Eintrag für MSSOAPSampleServer in Ihrer hosts-Datei (c:\winnt\system32\hosts) anlegen, aber dieser Schritt ist optional und nur dann notwendig, wenn Sie beabsichtigen, Microsofts eigene Beispiel-Clients auszuführen. In diesem Abschnitt schreiben Sie jedoch einen von Grund auf neuen Python-Client, daher ist Ihr existierender Rechnername ausreichend. Sie müssen in der Lage sein, das Beispielverzeichnis über HTTP zu sehen, wie in den Anweisungen angegeben.

Wenn Sie vorhaben, den Python-Client auf demselben Rechner laufen zu lassen, auf dem auch die Beispiele liegen, müssen Sie nichts weiter installieren (außer vielleicht die Python-Unterstützung für COM), um weitermachen zu können.

Herunterladen der COM-Unterstützung für Python

Falls Sie COM aus Python noch nicht benutzt haben (in diesem Buch haben wir das noch nicht), müssen Sie die Python-Unterstützung für COM herunterladen und installieren. Beginnen Sie damit, sich den passenden Installer aus dem Web zu besorgen.

Dort gibt es Links und Anweisungen zum Herunterladen von win32all.exe für Ihre Version von Python; lesen Sie die Informationen auf dieser Webseite sorgfältig, um sicher zu sein, daß Sie die richtige Version bekommen. Dieser Installer bietet vollständige COM-Unterstützung für Ihre Python-Programme und ermöglicht es Ihnen, COM-Server zu implementieren, die aus anderen Sprachen heraus benutzt werden können.

Reparieren von MSSOAP mit makepy.py

Selbst wenn Sie bereits Python-Unterstützung für COM haben (oder sie gerade installiert haben), müssen Sie Pythons Zugriff auf die SOAP-Typbibliothek noch zurechtrücken. Leider verlassen sich die Autoren der SOAP-Toolkit-Objekte auf die Skriptfähigkeiten von Visual Basic und Windows, um Objekteigenschaften folgendermaßen zu setzen:

 Object.Property("PropertyName") = NewPropertyValue 

In Python ist diese Syntax noch nicht einmal erlaubt! Visual C++ benutzt eine etwas andere Syntax, was es einem überladenen Operator ermöglicht, eine Syntax bereitzustellen, die mit Pythons Syntax zur Dictionary-Zuweisung übereinstimmt:

 Object.Property["PropertyName"] = NewPropertyValue 

Großartig! Diese Syntax funktioniert prima in Python, wenn Sie einen Wert an ein Element eines Instanz-Dictionary zuweisen. Leider konvertiert die COM-API jedoch dieses COM-Konstrukt nicht automatisch in Instanz-Dictionaries in Python. Bei diesem speziellen Objekt ist Property eine Methode, und es gibt keine Möglichkeit, in Python einen Wert an eine Methode eines Objekts zuzuweisen. Üblicherweise implementieren Komponenten Zugriffsmethoden oder zumindest SetProperty- und GetProperty-Typkonstrukte. Zum Glück kapselt das Skript makepy.py in win32all.exe COM-Objekte mit einer weiteren Python-Schnittstelle und verwendet eine primitivere API, um korrekt auf sie zuzugreifen, womit dieses Problem für Sie gelöst ist.

Um makepy.py auszuführen, starten Sie es im Verzeichnis win32com\client Ihrer Python-Installation (meistens C:\Python20\win32com\client):

 C:\Python20\win32com\client>python makepy.py 

Ein GUI-Dialog erscheint, der all die verschiedenen Typbibliotheken anzeigt, die auf Ihrem System registriert sind. Finden Sie Microsoft SOAP Type Library (1.0) und klicken Sie auf OK. Das Skript erzeugt einen plötzlichen Aktivitätsschub (zu erkennen an häufiger Textausgabe) und schreibt eine .py-Datei mit einem monströs langen Namen in das Verzeichnis C:\Python20\win32com\gen_py. Sie werden diese Datei vermutlich nicht mehr anschauen müssen, da Sie einen Standardaufruf von win32com.client.Dispatch benutzen können, um das Objekt anzustoßen, so daß es die aktualisierte Python-freundliche Schnittstelle finden wird, die makepy.py erzeugt hat. Die folgende Abbildung zeigt diesen Dialog in Aktion, wobei Microsoft SOAP Type Library (1.0) hervorgehoben ist.

Auswählen der SOAP-Typbibliothek mit makepy.py

Abbildung: Auswählen der SOAP-Typbibliothek mit makepy.py

Nachdem Sie die Python-Schnittstelle für das Objekt erzeugt haben, können Sie das Objekt ganz normal instanziieren, aber nun können Sie Konstrukte wie diese aufrufen:

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

Aber makepy.py vollbringt mehr, als nur Zuweisungen von Eigenschaften mit der Python-Syntax zu korrigieren, da es auch dazu benutzt werden kann, Parametertypen und Eigenschaften für alle möglichen COM-Objekte auszubügeln. Siehe die Dokumentation zu makepy für weitere Informationen.

Einrichten des Servers

Bevor wir zur Entwicklung des Clients kommen, ist es wichtig, das Einrichten des Servers zu verstehen. SOAP und Webdienste sind inhärent plattformübergreifend. Obwohl Sie unter Windows implementierte Dienste ausführen, ist es denkbar, daß Clients auf einer beliebigen Plattform laufen, vorausgesetzt, daß sie entweder ein korrektes SOAP-Paket erzeugen können, um die Dienste anzusprechen, oder die veröffentlichte WSDL interpretieren können, um die Dienste mit einem lokalen Stellvertreterobjekt zu kapseln.

Der hier implementierte Python-Client benutzt einen COM-Zugang auf einen SOAP- Connector und -Serialisierer. Es sollte jedoch jede SOAP-Implementierung in der Lage sein, sich mit diesen Diensten zu verbinden und sie zu benutzen.

Die Server-Einrichtung, die mit dem Toolkit geliefert wird, ist lediglich eine Sammlung von WSDL-Dateien, die Dienste beschreiben, sowie Dienst-Endpunkte, die sie implementieren. Die Endpunkte sind mit einer Vielzahl von Sprachen und Techniken implementiert, von Active Server Pages bis ISAPI-Plug-ins. Die Schnittstelle zu diesen Diensten ist pures SOAP.

Ein SOAP-Client in Python

Das SOAP Toolkit enthält einen Rechendienst. Dieser Dienst bietet vier verschiedene Operationen, die er auf zwei übergebenen Parametern ausführt, ähnlich einem einfachen Taschenrechner. In seiner Funktionalität ist dieses Beispiel vergleichbar mit dem Beispiel-Client in VBScript, der auch im Toolkit mitgeliefert wird. Der wichtigste Unterschied zwischen den beiden ist, daß Ihr Client vollständig und von Grund auf in Python und nicht in VBScript implementiert ist.

Die Rechenoperationen sind die vier Grundrechenarten (add, subtract, multiply und divide). Wenn Ihr SOAP Toolkit frisch installiert ist, ist es eine gute Idee nachzuprüfen, ob der Rechendienst korrekt läuft, indem er mit einem der Beispiel-Clients getestet wird, die mit dem Toolkit geliefert werden – es ist ganz bestimmt bei der Fehlersuche hilfreich (wenn Sie Fehler suchen!). Mit anderen Worten: Es hilft, Probleme und Fehler zu isolieren, die beim Ausführen Ihres Python-Client auftreten könnten, wenn Sie wissen, daß Ihr Webserver und Ihre SOAP-Implementierung funktionieren.

Wiederverwendbare Grundlagen schaffen

Um das SOAP-Paket korrekt zu erstellen, definieren Sie einen Teil des SOAP-Action-URIs so, daß Sie verschiedene Methodennamen anhängen können. Sie werden auch den Namensraum-URI zwischen Methodenaufrufen wiederverwenden wollen. Diese beiden wiederverwendeten Dinge werden zusammen mit dem Dienst-Endpunkt zu Beginn als globale Variablen definiert:

import win32com.client

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

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

# Dienst-Endpunkt
EndPointUrl = \
   "http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp"

Sie können die Rechenfunktionalität nehmen und in eine Methode einbetten, damit diese Methode einen String mit der gewünschten Operation plus ihren Parametern annehmen kann. Diese Methode kann dann wiederholt aufgerufen werden, um Antworten zu erzeugen:

def Calculate(Op, Val1, Val2):
   """Nimmt Operator (als Wort, z.B. "Add") plus zwei
       ganzzahlige Werte und gibt Ergebnis zurück."""
   # Instanziiere HttpConnector
   connector = win32com.client.Dispatch("MSSOAP.HttpConnector")

Sobald die Funktion beginnt, wird der HTTP-SOAP-Connector erzeugt, wie der vorangehende Code zeigt. Dem Connector wird dann einiges an kritischer Information bezüglich des Ortes des Dienstes übergeben:

# Setze Eigenschaften (schlägt fehl, falls makepy.py
# nicht auf der SOAP-Typbibliothek ausgeführt wurde)
connector.SetProperty("EndPointURL", EndPointUrl)
connector.SetProperty("SoapAction", BaseSoapActionUri + Op)

# Beginne SOAP-Nachricht
connector.BeginMessage( )

Der kritische Teil dieses Codestücks ist der Aufruf von SetProperty, um den Wert von SoapAction zu ändern. Wie Sie sehen, wird BaseSoapActionUri mit der gewünschten Operation Op verkettet. Wenn Sie die Methode add verwenden, erzeugen Sie einen SoapAction-String ähnlich zu:

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

Nun geht es darum, tatsächlich den SOAP-Umschlag zu erzeugen.

# Erzeuge Serialisierungsobjekt
serializer = win32com.client.Dispatch("MSSOAP.SoapSerializer")

# Füge es an vorher erzeugten Connector an
serializer.Init(connector.InputStream)

Der serializer ist mit dem Eingabestrom des connectors verbunden, damit das SOAP-Paket auch seinen Weg zum Dienst-Endpunkt finden kann. Der Rest des Pakets wird ähnlich wie vorhin erzeugt, wobei die Methoden Anfang und Ende der Elemente darstellen:

# Erzeuge SOAP-Umschlag
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( )

# Beende SOAP-Nachricht
connector.EndMessage( )

Der reader kommt ins Spiel, um das Ergebnis nach dem Aufruf des Dienstes zu lesen und zu interpretieren. Wie zuvor in Der entstehende SOAP-Standard erläutert wurde, hängt der reader am Ausgabestrom des connectors und verarbeitet die Information dann, wenn sie zurückgegeben wird:

# Erzeuge SOAP-reader-Objekt
reader = win32com.client.Dispatch("MSSOAP.SoapReader")
reader.Load(connector.OutputStream)

# Prüfe auf Fehler
if reader.Fault:
print "Fehler: ", reader.faultstring.Text

# Liefere berechneten Wert
return reader.RPCResult.Text

Falls ein Fehler aufgetreten ist, wird dieser im Attribut reader.Fault wiedergegeben. Wenn ein SOAP-Aufruf fehlschlägt, sendet der SOAP-Server einen Fehlereintrag zurück an den Client. SOAP verwendet einen Großteil der gleichen Semantik wie HTTP, was die Weitergabe von Fehlerbedingungen zurück an den Aufrufer angeht. Wenn SOAP über HTTP benutzt wird, ist SOAP an einige exakt gleiche Fehlerbedingungen gebunden – SOAP muß einen HTTP 500 Internal Server Error zurückschicken, selbst wenn der Webserver sich wie erwartet benimmt, aber der Code fehlschlägt, der die SOAP-Anfrage behandelt. (Dies ist notwendig, um zu gewährleisten, daß vom Client kein Wissen über Implementierungsdetails des Servers benötigt wird; es ist kein Fehler in den SOAP- oder HTTP-Protokollen.)

Das folgende Beispiel zeigt das komplette Listing von PyCalcSerial.py.

Beispiel: PyCalcSerial.py

"""
Python-MSSOAP-Serialisierungsbeispiel
"""

# Importiere COM-Unterstützung
import win32com.client

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

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

# Dienst-Endpunkt
EndPointUrl = \
"http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp"

def Calculate(Op, Val1, Val2)   
   """Nimmt Operator (als Wort, z.B. "Add") plus zwei
   ganzzahlige Werte und gibt Ergebnis zurück."""
   # Instanziiere HttpConnector
   connector = win32com.client.Dispatch("MSSOAP.HttpConnector")
   
   # Setze Eigenschaften (schlägt fehl, falls makepy.py
   # nicht auf der SOAP-Typbibliothek ausgeführt wurde)
   connector.SetProperty("EndPointURL", EndPointUrl)
   connector.SetProperty("SoapAction", BaseSoapActionUri + Op)
   
   # Beginne SOAP-Nachricht
   connector.BeginMessage( )
   
   # Erzeuge Serialisierungsobjekt
   serializer = win32com.client.Dispatch("MSSOAP.SoapSerializer")
   
   # Füge es an vorher erzeugten Connector an
   serializer.Init(connector.InputStream)
   
   # Erzeuge SOAP-Umschlag
   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( )
   
   # Beende SOAP-Nachricht
   connector.EndMessage( )
   
   # Erzeuge SOAP-reader-Objekt
   reader = win32com.client.Dispatch("MSSOAP.SoapReader")
   reader.Load(connector.OutputStream)
   
   # Prüfe auf Fehler
   if reader.Fault:
   print "Fehler: ", reader.faultstring.Text
   
   # Liefere berechneten Wert
   return reader.RPCResult.Text

# Hauptzeile -- führe einige Berechnungen durch
print "Benutzter Dienst-Endpunkt:", EndPointUrl
print "Berechne 3 * 4: \t",
print Calculate("Multiply", 3, 4)
print "Berechne 4 - 3: \t",
print Calculate("Subtract", 4, 3)
print "Berechne 345 + 1004: \t",
print Calculate("Add", 345, 1004)
print "Berechne 115 / 5: \t",
print Calculate("Divide", 115, 5)

Um das Beispiel auszuführen, starten Sie es einfach von Ihrer Kommandozeile. Dann sollten Sie eine Ausgabe ähnlich zu folgender sehen:

C:\mein-dir> python PyCalcSerial.py
Benutzter Dienst-Endpunkt:
http://centauri/MSSoapSamples/Calc/Service/SrSz/AspVbs/Calc.asp
Berechne 3 * 4: 12
Berechne 4 - 3: 1
Berechne 345 + 1004: 1349
Berechne 115 / 5: 23

SOAP ist das Herz von Webdiensten, jedenfalls so, wie sie von den meisten der Big Players beschrieben werden. WSDL wird, wenn korrekt implementiert, von Entwicklern nur selten wahrgenommen, da es automatisch von Objekt-Quelldateien erzeugt werden kann. Sobald eine ausgereiftere Unterstützung von WSDL existieren wird, werden die meisten Sprachen (sehr wahrscheinlich auch Python) WSDL-Generatoren haben, die WSDL direkt aus dem Quellcode für Klassen erzeugen. Natürlich können diese Werkzeuge auch von SOAP-Server-Implementierungen oder von Python-Objekt-Servern wie Zope angeboten werden.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Python & XML bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2002 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Python & XML" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de