Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 18 Verteilte Programmierung mit RMI und SOAP
gp 18.1 Entfernte Methoden
gp 18.1.1 Wie entfernte Methoden arbeiten
gp 18.1.2 Stellvertreter (Proxy)
gp 18.1.3 RMI
gp 18.1.4 Wie die Stellvertreter die Daten übertragen
gp 18.1.5 Probleme mit entfernten Methoden
gp 18.2 Nutzen von RMI bei Middleware-Lösungen
gp 18.3 Die Lösung für Java ist RMI
gp 18.3.1 Entfernte Objekte programmieren
gp 18.3.2 Entfernte und lokale Objekte im Vergleich
gp 18.4 Definition einer entfernten Schnittstelle
gp 18.5 Das entfernte Objekt
gp 18.5.1 Der Bauplan für entfernte Objekte
gp 18.5.2 Der Konstruktor
gp 18.5.3 Implementierung der entfernten Methoden
gp 18.6 Stellvertreterobjekte erzeugen
gp 18.6.1 Das Dienstprogramm rmic
gp 18.7 Der Namensdienst (Registry)
gp 18.7.1 Der Port
gp 18.8 Der Server: entfernte Objekte beim Namensdienst anmelden
gp 18.8.1 Automatisches Anmelden bei Bedarf
gp 18.9 Einen Client programmieren
gp 18.9.1 Einfaches Logging
gp 18.10 Aufräumen mit dem DGC
gp 18.11 Entfernte Objekte übergeben und laden
gp 18.11.1 Klassen vom RMI-Klassenlader nachladen
gp 18.11.2 Sicherheitsmanager
gp 18.12 Registry wird vom Server gestartet
gp 18.13 RMI über die Firewall
gp 18.13.1 RMI über HTTP getunnelt
gp 18.14 RMI und CORBA
gp 18.15 UnicastRemoteObject, RemoteServer und RemoteObject
gp 18.16 Daily Soap
gp 18.16.1 SOAP-Implementierung der Apache-Gruppe
gp 18.16.2 Einen Client mit der Apache-Bibliothek implementieren
gp 18.16.3 Der Seifen-Server
gp 18.17 Java-API für XML Messaging (JAXM)
gp 18.18 Java Message Service (JMS)
gp 18.18.1 OpenJMS
gp 18.18.2 Beispiel mit Konsument und Produzent im Publish-Subscribe-Modell


Galileo Computing

18.16 Daily Soapdowntop

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.


Galileo Computing

18.16.1 SOAP-Implementierung der Apache-Gruppedowntop

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.


Galileo Computing

18.16.2 Einen Client mit der Apache-Bibliothek implementierendowntop

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.

Galileo Computing

18.16.3 Der Seifen-Servertoptop

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.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> 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.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de