18.16 Daily Soap
Für die Nutzung entfernter Ressourcen und zum Aufruf entfernter Methoden gibt es mehrere klassische Ansätze. Ein einfaches Verfahren ist die Anfrage mit Parametern an einen Web-Server, der den Inhalt zurückliefert. Zur Verteilung von Programmen haben sich CORBA, RPC, aber auch RMI bewährt. Der Weg über HTML hat den Vorteil, dass das Protokoll HTTP verbreitet ist, aber den Nachteil, dass kaum Möglichkeiten zur verteilten Programmierung gegeben sind. CORBA und RMI haftet der Nachteil an, dass ihre Kommunikation einen offenen Port erfordert, den Sicherheitsbeauftragte nicht unbedingt tolerieren. Zudem sind CORBA/RMI-Lösungen nicht wirklich einfach zu implementieren. Idealerweise verheiratet eine Technik beide Vorteile: HTTP-Kommunikation und objektorientierte Konzepte.
Bei den Firmen DevelopMentor, IBM, Lotus Development Corp., Microsoft und UserLand Software entstand das XML-basierte SOAP-Protokoll. Es wird seit 1998 entwickelt und bietet einen einfachen Zugriff auf Server-Ressourcen mit den etablierten Web-Standards HTTP und XML. SOAP selbst beschreibt die Art und Weise, wie Inhalte (Serialisierung) und die XML-Daten übertragen werden. Die Übertragung selbst hat mit SOAP aber eigentlich nichts zu tun, denn dafür sind andere Protokolle definiert. HTTP ist ein ideales Transportprotokoll, denn für Web-Seiten gibt es in der Regel keine Beschränkungen von Firewalls. Die beiden Kommunikationsparteien regeln mit SOAP so einen entfernten Methodenaufruf, der die Parameter und Ergebnisse in XML kodiert und überträgt. Durch die unabhängigen und anerkannten Web-Standards bietet SOAP gegenüber RMI oder CORBA und auch sonstigen Protokollen den Vorteil, nicht an eine Programmiersprache gebunden zu sein. Da Microsoft federführend bei der Spezifikation ist und das .NET-Framework seine Kommunikation vollständig auf SOAP aufbaut, wird es in der Zukunft eine Reihe von Java-Clients geben, die auf SOAP-Dienste von anderen Anbietern wie Microsoft aufbauen. Die Übertragung kommt auch Sun mit ihrem Ziel einer betriebssystem- und plattformunabhängigen Schnittstelle entgegen.
Den Vorteilen stehen allerdings auch einige Nachteile gegenüber. Die XML-Repräsentation der Dokumente macht die Daten groß, und ein Parsen der Parameter und Ergebnisse auf beiden Seiten ist erforderlich. In Umgebungen, die performante Übertragung fordern - etwa bei der Kommunikation mobiles Endgerät und Server -, wird sich SOAP nicht so schnell durchsetzen. Des Weiteren ist auch die Sicherheit von SOAP-Verbindungen noch nicht hinreichend gelöst. Ein Client könnte sich mit einem Server verbinden und einen Aufruf starten, obwohl die Berechtigung fehlt. Sicherheitseigenschaften müssten erst auf der Server-Seite implementiert werden. Die in Klartext übertragenen Nachrichten bilden ein weiteres Problem, was jedoch durch SSL verhindert wird.
Die technische Realisierung
Ein Client-Programm besorgt sich, wie bei entfernten Programmen üblich, eine Referenz auf das entfernte Objekt. Das ist eine URL auf einen RPC-Router. Dieser Router wird mittels einer normalen HTTP- POST-Anfrage aktiviert. Er bekommt über den Client eine XML-kodierte Nachricht (Content-Typ ist einfach text/hmtl), in der die aufzurufende Methode und ihre Parameter kodiert sind. Der RPC-Router nimmt diese Nachricht entgegen, parst das empfangene XML-Dokument und leitet die Anfrage an die Methode weiter. Diese produziert die Ausgabe, die wiederum als XML-Dokument über die Antwort vom Server zum Client geschickt wird. Der Client nimmt das Ergebnis entgegen, und die Kommunikation ist beendet.
SOAP bietet für entfernte Methodenaufrufe einige Standarddatentypen an. Zu diesen gehören einfache Datentypen wie Ganzzahlen, Fließkommazahlen, Zeit- und Datumsangaben und Binärdaten. Weiterhin unterstützt SOAP zusammengesetzte Datentypen wie Strukturen und Arrays. Wie diese Daten nun tatsächlich in eine XML-Nachricht umgesetzt werden, braucht man glücklicherweise nicht zu wissen. Als Endanwender kommen wir mit der Nachricht nicht in Kontakt.
18.16.1 SOAP-Implementierung der Apache-Gruppe
Für unsere Zwecke wollen wir die Datei soap-bin-2.3.1.zip vom Indianer-Server http://xml.apache.org/dist/soap/version-2.3.1/ beziehen und auspacken. Im Archiv findet sich ein soap.jar, welches für die Client-Seite zur Kommunikation lebensnotwendig ist. Zusätzlich müssen sich mail.jar und activation.jar im Pfad befinden.
18.16.2 Einen Client mit der Apache-Bibliothek implementieren
Bevor wir uns der Arbeitsweise des Servers nähern, wollen wir uns zunächst einen existierenden Dienst zunutze machen. Viele freie Dienste sind unter http://www.xmethods.com/ aufgelistet. Den Dienst, den wir in unserem ersten Beispiel nutzen wollen, ist besonders hilfreich zu Weihnachten. Seine Aufgabe ist es, zu einem Tannenbaum gegebener Größe und gegebenem Radius eine Anzahl von Glühbirnen zu berechnen, die der Tannenbaum tragen kann. Unter http://soap.fmui.de/webservices.php#ChristmasTree ist der Dienst näher beschrieben. Als zusätzliche Größe muss der Abstand der Kerzen angegeben werden. Die Parameter tragen die Namen h (Höhe), r (Radius), l (Lichtabstand).
Unser SOAP-Programm muss zunächst die entsprechenden Klassen einbinden. Bei Apache-SOAP befinden diese sich im Pfad org.apache.soap und org.apache.soap.rpc.
Listing 18.6 soap/HowManyLamps.java
package soap;
import java.net.*;
import java.util.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
public class HowManyLamps
{
public static void main( String args[] ) throws Exception
{
Jeder der Dienste ist durch mehrere Parameter gekennzeichnet. Einer davon ist die URL des Servers, ein andere ist der Name des Dienstes. Beginnen wir mit dem Aufbau der Methoden- und Parameterbeschreibung. Einem Objekt der Klasse Call werden dabei die Informationen übergeben. Später wird dieses Call-Objekt auch die invoke()-Methode anbieten, die den Aufruf tatsächlich durchführt.
Call call = new Call();
call.setTargetObjectURI( "urn:christmas" );
call.setMethodName( "ChristmasTree" );
call.setEncodingStyleURI( Constants.NS_URI_SOAP_ENC );
Der Dienst trägt den Namen christmas. Die aufzurufende Methode heißt ChristmasTree. Der Encoding-Style definiert die Art und Weise, wie die XML-Datei aussehen soll. Die Konstante im Methodenaufruf setEncodingStyleURI() steht für die Zeichenkette http:// schemas.xmlsoap.org/soap/encoding/.
Da der Methode Parameter übergeben werden müssen (h, r und l), ist eine Liste mit den Parametern und den Typen aufzubauen.
Vector p = new Vector();
p.addElement( new Parameter("h", double.class, new Double(200), null ) );
p.addElement( new Parameter("r", double.class, new Double(100), null ) );
p.addElement( new Parameter("l", double.class, new Double(10), null ) );
call.setParams( p );
Die Parameter werden in einem Vektor gesetzt (schade, ein Objekt der Schnittstelle List hätte es auch getan) und dann mit der setParams()-Methode dem Call-Objekt zugewiesen. Jeder Parameter ist vom Typ Parameter. Im Konstruktor werden der Name des Parameters, der Typ, der Wert und optional die Kodierung angegeben. Da der Parameter eine Fließkommazahl ist, geben wir dem Parameter-Objekt den Typ durch double.class mit. Damit kennzeichnen wir das Class-Objekt für Double-Werte. Wollen wir zum Beispiel Strings übertragen, würden wir String.class für den Klassentyp schreiben. Die Lösung ist flexibel, da nicht viele Konstruktoren für jeden Typ eingeführt werden, sondern nur einer, der angibt, wie der dritte Parameter zu interpretieren ist. Den letzten setzen wir auf null, da wir die Standardkodierung aus dem Call-Objekt nutzen wollen. Die Reihenfolge der Parameter ist bei einigen Servern wichtig.
Der nächste Schritt ist der Aufruf der Methode. Die Rückgabe wird ein Response-Objekt sein, aus dem die Ergebnisse ausgelesen werden können.
Response resp = null;
try
{
URL url = null;
try {
url = new URL( ">http://213.23.125.181:8080/RPC" );
} catch ( MalformedURLException e ) {}
resp = call.invoke( url, "" );
}
catch( SOAPException e )
{
System.err.println( "SOAPException (" + e.getFaultCode() + "): " +
e.getMessage() );
return;
}
Während des Aufrufs können Fehler auftauchen, die durch das Auffangen einer SOAPException gesichert werden müssen. Eine fehlerhafte URL liefert zum Beispiel die Meldung:
SOAPException (SOAP-ENV:Client): Error opening socket: Connection timed out: connect
Nicht alle Fehler werden durch eine SOAPException angezeigt. Nicht existierende Methoden führen zu nicht zu einer Ausnahme. Vielmehr entscheidet die Methode generatedFault(), ob Fehler auftreten. Gab es keine Fehler und ging alles glatt, haben wir in der Variablen resp das Ergebnis der Operation.
if( !resp.generatedFault() )
{
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();
System.out.println( value );
}
else
{
Fault fault = resp.getFault();
System.err.println( "Fehler bei der Ausführung: " );
System.out.println( " Fault-Code = " + fault.getFaultCode() );
System.out.println( " Fault-String = " + fault.getFaultString() );
}
}
}
Damit ist das Programm beendet und mit getReturnValue().getValue() das Ergebnis geholt. Fehlerhafte Methoden führen zu Meldungen der folgenden Art:
Fehler bei der Ausführung:
Fault-Code = SOAP-ENV:Server
Fault-String = Method 'HatChristianAuchEinenBaum(double, double, double)'
is not supported.
18.16.3 Der Seifen-Server
Ein SOAP-Server muss die Anfragen entgegennehmen und eine Methode aufrufen. Von der Apache-Gruppe gibt es einen entsprechenden Server, der als Servlet realisiert ist unter http://xml.apache.org/dist/soap/. Das Servlet übernimmt dabei die Aufgabe des Routers, der die XML-Anfragen entgegennimmt und auswertet. Die Installation ist einfach. In dem schon erwähnten soap-bin-2.2.zip-Archiv befindet sich ein War-Archiv mit dem Namen soap.war. Dieses War-Archiv wollen wir in das webapps-Verzeichnis unseres Tomcat-Servers legen. Wenn wir Tomcat anschließend starten, entpackt er automatisch das War-Archiv in ein soap-Verzeichnis. Jetzt können wir den Server testen, indem wir einen Browser aufrufen und in die URL-Zeile http://localhost:8080/soap/index.html eingeben. Eine gültige Web-Seite verkündet den Erfolg. Weitergehende Installationshinweise gibt die Web-Seite http://xml.apache.org/soap/docs/install/index.html. Ein weiterer im C++-Quellcode verfügbarer Server ist der White-Mesa-Server unter http://www.whitemesa.com.
Wir wollen hier nicht näher auf die Implementierung auf Server-Seite eingehen. Im Prinzip ist noch eine Beschreibungsdatei für den Dienst anzulegen, beim Server einzutragen und die Java-Klassen für den Server-Dienst sind zu implementieren.
|