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.11 Entfernte Objekte übergeben und ladendowntop

In unserem bisherigen Beispiel haben wir zwei Ganzzahlwerte übergeben. Die Implementierung der Stellvertreter ist nun so, dass eine Socket-Verbindung die Daten überträgt. Da keine Objekte transportiert werden, muss keine Serialisierung die Daten in Reihe liefern. Wir wollen jetzt nun damit beschäftigen, was mit Objekten passiert, die übertragen werden. Wir können verschiedene Klassen unterscheiden:

gp Klassen, die auf beiden Seiten vorliegen, weil es zum Beispiel Klassen aus dem Standard-API sind
gp Klassen, die nur auf der Server-Seite vorliegen und dem Client nicht bekannt sind
gp Klassen, die selbst wieder Remote implementieren

Liegt die Klasse auf beiden Seiten als Klassenbeschreibung vor, da sie etwa eine Standardklasse ist oder in beiden Pfaden eingetragen ist, müssen wir nicht mit Problemen rechnen. Die übertragenen Daten müssen jedoch von Klassen stammen, die serialisierbar sind.

Wann ist eine Klassenbeschreibung nötig?

Schwierig wird die Lage erst dann, wenn der Server Klassen benötigt, die beim Client liegen. Es könnte etwa eine entfernte Methode

int max( Vector v );

geben, die das Maximum der Elemente aus dem Vektor bildet. Die Elemente sind jedoch Objekte, die der Server vorher nicht gesehen hat, etwa Unterklassen von Konto im Vector, und der Server kennt nur Konto und die Methoden davon, bindet aber dynamisch an die Methode der Unterklasse.


Galileo Computing

18.11.1 Klassen vom RMI-Klassenlader nachladendowntop

Wir kommen also dazu, dass der Klassenlader Klassen nachladen muss, die für den verteilten Aufruf auf der Client- und Server-Seite nötig sind. Das erinnert an einen Applet-Klassenlader, der Gleiches machen muss. Für RMI-Aufrufe kommt der RMI-Klassenlader java.rmi.RMIClassLoader zum Zuge. Dieser Lader lädt jetzt die Stellvertreter (die Stubs) sowie weitere benötigte Klassen in die lokale virtuelle Maschine. Woher die Klassen kommen, ist dem Lader egal. Sie können in CLASSPATH stehen, im aktuellen Verzeichnis oder auf einem Web-Server. Im letzten Fall steuert die Eigenschaft java.rmi.server.codebase den Ort.


Beispiel Setzen der Codebase auf einen Web-Server, damit das RMI-Programm die benötigten Klassen aus http://server/classimlp laden kann
java -Djava.rmi.codebase=http://server/classimlp

Wenn ein Client einen entfernten Aufruf startet, sucht er die Stub-Klasse. Findet er die Klasse nicht in dem eigenen Namensraum, wird die Codebase hinzugezogen. Der Client wird dann die Stub-Klasse von der angegebenen URL anfordern. Der Server überträgt anschließend die Klassendatei zum RMI-Client. Die Stub-Klasse muss also dem Server bekannt sein, da er sie ja übertragen muss.

Sollten die Klassen nur vom Server geladen werden und aus anderen, vielleicht dunklen Stellen des Dateisystems nicht, so ist die Eigenschaft java.rmi.useCodebaseOnly auf true zu setzen.


Galileo Computing

18.11.2 Sicherheitsmanagertoptop

Damit die Klassen nicht auf dem Client oder Server liegen müssen, können sie nachträglich über den RMI-Klassenlader geladen werden. Doch das Laden von Klassen muss erst vom Sicherheitsmanager abgesegnet werden. Die Erlaubnis, ob Klassen übertragen werden dürfen, regelt ein spezieller Sicherheitsmanager. Die Klasse RMISecurityManager definiert eine Sicherheitsrichtlinie, dass serialisierbare Klassen von einem Rechner auf den anderen übertragen werden können. Wenn wir mit primitiven Werten arbeiten, wie in unserem ersten Beispiel, oder mit Standardklassen, ist dieser RMISecurityManager nicht nötig. Da wir aber serialisierbare Klassen übertragen müssen, ist der Sicherheitsmanager vorgeschrieben. Da Applets schon vom Applet-Sicherheitsmanager überwacht werden, können sie keinen zusätzlichen RMISecurityManager installieren.


Beispiel Ein RMISecurityManager ist nichts anderes als ein SecurityManager. Sun könnte jedoch jederzeit die Implementierung ändern und spezielle Einschränkungen vorsehen.
public class RMISecurityManager extends SecurityManager {
  public RMISecurityManager() {
  }
}

Wenn wir folgende Zeile in unseren Servercode aufnehmen, wird RMI vom Klassenlader die Klassen laden können:

System.setSecurityManager( new RMISecurityManager() );

Erst der Sicherheitsmanager gibt uns das Recht zur Übertragung. Tragen wir ihn nicht ein, führt das zu einer Fehlermeldung der folgenden Art:

java.security.AccessControlException: access denied
(java.net.SocketPermission 127.0.0.1:1099 connect,resolve)

Die Meldung zeigt an, dass die aktuellen Sicherheitsrichtlinien die Übertragung nicht zulassen. Häufig ist es so, dass die Java-Installationen Sicherheitsrichtlinien vorgeben, die sehr eingeschränkt sind.

Policy-Dateien

Um die Richtlinien zu lockern, müssen wir eine Policy-Datei anlegen, die uns die Rechte zum Laden von Klassen gibt.


Beispiel Die folgende Datei rmi.policy vergibt alle Rechte.
grant
{
  permission java.security.AllPermission;
};

Der Sicherheitsmanager bindet nun eine Reihe dieser Policy-Dateien ein. Wollen wir zusätzliche Policies einbinden, so geben wir sie auf der Kommandozeile für den Java-Interpreter an.

$ java -Djava.security.manager -Djava.security.policy=rmi.policy MyClass

Die Option -D setzt Systemeigenschaften. Die Anweisung -Djava.security.manager hat den gleichen Effekt wie

System.setSecurityManager( new SecurityManager() );

Dies installiert einen Sicherheitsmanager, der dann die nachfolgende Policy behandelt. Sie ist als URL angegeben und in unserem Fall eine Datei im aktuellen Verzeichnis.


Beispiel In einem Verzeichnis befinden sich die Policy-Datei rmi.policy und die Klassen für RMI. Über die Systemeigenschaften lassen sich codebase und policy setzen.
String codebase = ">http://server/verzeichnis/RMI/";;
System.setProperty( "java.rmi.server.codebase", codebase );
System.setProperty( "java.security.policy", codebase+"rmi.policy" );
System.setSecurityManager( new RMISecurityManager() );


Tipp Die Sicherheitsrichtlinie sollte wohl überlegt erfolgen. Lädt der Server jeden Stub beziehungsweise Skeleton oder jede Klasse vom Client, hat er es natürlich leicht, Server-Funktionalität auszuführen. Schmuggelt er miesen Programmcode ein, kann dies großen Schaden anrichten, da der Server häufig über mehr Rechte als der Client verfügt.





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