RMI−Server und −Client
RMI−Server
Remote−Objekt(e) bereitstellen
Wurzel−Objekt in Verzeichnisdienst anmelden
RMI−Client
Wurzel−Objekt in entfernter JVM mittels
Verzeichnisdienst finden
Methoden von Remote−Objekten aufrufen
Ein Java−Programm kann gleichzeitig RMI−Client und
RMI−Server sein.
Web−Anwendungen mit Java
551
Beispiel: E−Shop
Was passiert, wenn Kunde Artikel kauft?
Lieferung der Ware zum Kunden (Logistik)
Bezahlen (Rechnung, Lastschrift, Kreditkarte usw.)
Typische Aufgaben eines Warenwirtschaftssystems
Im E−Shop das Rad nicht neu erfinden, sondern
Anbindung an WWS schaffen
WWS präsentiert sich als Remote−Objekt.
E−Shop faßt Bestelldaten zu einem Objekt zusammen.
E−Shop schickt Bestelldaten−Objekt per RMI an WWS.
Lieferstatus vom WWS holen
Web−Anwendungen mit Java
552
Lösungsidee
Remote−
Interface
E−Shop
WWS
Stub
Remote−
Objekt
Kasse
Bestellung
Web−Anwendungen mit Java
Bestellung
553
Lösungsskizze: Remote−Interface
E−Shop »sieht« WWS als Remote−Interface
de.rainer_klute.rmi.WWS.
Interface erbt von java.rmi.Remote.
Spezifiziert die Methoden des WWS, die ein RMI−Client
aufrufen kann.
Alle Methoden eines Remote−Objekts können eine
RemoteException werfen.
Netzprobleme
Server−Probleme
Web−Anwendungen mit Java
554
Lösungsskizze: Remote−Objekt
Remote−Objekt implementiert Remote−Interface.
Hier: WWSImpl implementiert WWS.
Klasse von UnicastRemoteObject ableiten (oder
weitere Möglichkeiten nutzen)
Beispiel:
import java.rmi.*;
import java.rmi.server.*;
public class WWSImpl extends
UnicastRemoteObject implements WWS
Konstruktor des Remote−Objekts macht es im
Netz erreichbar.
Web−Anwendungen mit Java
555
Lösungsskizze: RMI−Server
Erzeugt Instanz des Remote−Objekts
Remote−Objekt wird im Netz erreichbar.
Meldet Instanz bei RMI−Registrierung an
Ordnet Remote−Objekt einen Namen zu.
Remote−Objekt wird im Netz adressierbar.
RMI−Server oft als main()−Methode des Remote−
Objekts realisiert.
Web−Anwendungen mit Java
556
Lösungsskizze: RMI−Client
Fordert Remote−Objekt von RMI−Registrierung an.
Adressierung über den vom RMI−Server festgelegten
Namen
Ruft Methoden des Remote−Objekts auf.
Web−Anwendungen mit Java
557
Beispiel: Remote−Interface
package de.rainer_klute.rmi;
import java.rmi.*;
public interface WWS extends Remote
{
/** <p>Liefert den Status des WWS.</p> */
public String getStatus()
throws RemoteException;
/** <p>Übermittelt eine Bestellung an das
* Warenwirtschaftssystem.</p> */
public String bestellen(Bestellung bestellung)
throws RemoteException;
}
Web−Anwendungen mit Java
558
Beispiel: Remote−Objekt
package de.rainer_klute.rmi.server;
import
import
import
import
java.net.*;
java.rmi.*;
java.rmi.server.*;
de.rainer_klute.rmi.*;
public class WWSImpl extends UnicastRemoteObject
implements WWS
{
/**
* <p>Konstruktor hier nur zur Illustration:
* Konstruktor der Oberklasse
* {@link UnicastRemoteObject} macht Objekt netzweit
* erreichbar.</p>
*/
public WWSImpl() throws RemoteException
{
super();
}
Web−Anwendungen mit Java
559
Beispiel: Remote−Objekt
/**
* <p>Liefert den Status des WWS.</p>
*/
public String getStatus() throws RemoteException
{
System.out.println("getStatus()");
return "All subsystems running.";
}
/**
* <p>Übermittelt eine Bestellung an das
* Warenwirtschaftssystem.</p>
*/
public String bestellen(Bestellung bestellung)
throws RemoteException
{
String s = "Order received: " + bestellung;
System.out.println(s);
return s;
}
Web−Anwendungen mit Java
560
Beispiel: RMI−Server
/**
* <p>Startet den RMI−Server.</p>
*/
public static void main(String args[])
{
/* Security−Manager installieren */
if (System.getSecurityManager() == null)
System.setSecurityManager
(new RMISecurityManager());
try
{
/* Remote−Objekt erzeugen */
WWS wws = new WWSImpl();
Web−Anwendungen mit Java
561
Beispiel: RMI−Server
/* Remote−Objekt in RMI−Registry anmelden.
* Format des Namens: "//host/name" */
String wwsName = "//" +
InetAddress.getLocalHost().
getHostAddress() + "/WWS";
System.out.println
("Versuche, WWS als \"" + wwsName +
"\" zu registrieren.");
Naming.rebind(wwsName, wws);
System.out.println("Okay.");
}
}
}
catch (Exception e)
{
System.out.println
("Fehler: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
Web−Anwendungen mit Java
562
Beispiel: RMI−Client
package de.rainer_klute.rmi.client;
import java.net.*;
import java.rmi.*;
import de.rainer_klute.rmi.WWS;
public class WWSClient
{
public static void main(String args[])
{
/* Security−Manager installieren */
if (System.getSecurityManager() == null)
System.setSecurityManager
(new RMISecurityManager());
String remoteName = args[0];
Web−Anwendungen mit Java
563
Beispiel: RMI−Client
try
{
}
WWS wws = (WWS) Naming.lookup(remoteName);
String status = wws.getStatus();
System.out.println("WWS−Status: " + status);
Bestellung b = new BestellungImpl();
b.setKunde(1234);
Posten p = new PostenImpl();
p.setArtikel(4711);
p.setAnzahl(2);
b.addPosten(p);
p = new PostenImpl();
p.setArtikel(1000);
p.setAnzahl(1);
b.addPosten(p);
String s = wws.bestellen(b);
System.out.println("WWS−Nachricht: " + s);
Web−Anwendungen mit Java
564
Beispiel: RMI−Client
}
catch (Exception e)
{
System.out.println("Fehler: " +
e.getMessage());
e.printStackTrace();
}
}
Web−Anwendungen mit Java
565
RMI−Registrierung
Einfacher Verzeichnisdienst für RMI
Verwaltet Zuordnungen von Namen (Strings) zu
Remote−Objekten.
Notiert zu jedem Remote−Objekt, woher die Klasse
dieses Objekts stammt.
Namensformat:
//{hostname|ipaddress}[:port]/objectname
//rmi.rainer−klute.de/WWS
//127.0.0.1:1234/WWS
Web−Anwendungen mit Java
566
RMI−Registrierung
Starten der RMI−Registrierung:
CLASSPATH darf Anwendungsklassen nicht enthalten.
bash: (unset CLASSPATH; rmiregistry &)
csh: (unsetenv CLASSPATH; rmiregistry &)
Web−Anwendungen mit Java
567
Getrennte Entwicklung
RMI ermöglicht Trennung der Entwicklung von
Server und Client.
Beispiel: Web−Anwendung für Kunden einer
Versicherung
Kunde kann persönliche Daten aktualisieren.
Jeder Interessent kann »seinen« persönlichen Berater anhand
seiner eigenen Adresse ermitteln und kontaktieren.
Entwicklung der Web−Anwendung durch Internet−
Agentur
Versicherung macht Kundendaten und Vertriebsdaten der
Internet−Agentur nicht zugänglich.
Datenschutz, Betriebsgeheimnis
Host
Web−Anwendungen mit Java
568
Getrennte Entwicklung
Remote−
Interface
Host−
Daten
RMI−
Server
RMI−
Client
Web−
Oberfläche
Versicherung entwickelt RMI−Server mit Zugriff auf die
Host−Daten.
Internet−Agentur entwickelt RMI−Client und Web−
Oberfläche (HTML−Generierung mit JSP).
Klassen übersetzen
Gemeinsam genutzte Interfaces
de.rainer_klute.rmi.WWS
de.rainer_klute.rmi.Bestellung
de.rainer_klute.rmi.Posten
Server−Klasse:
de/rainer_klute/rmi/server/WWSImpl
Client−Klasse:
de/rainer_klute/rmi/client/WWSClient
de/rainer_klute/rmi/client/BestellungImpl
de/rainer_klute/rmi/client/PostenImpl
Web−Anwendungen mit Java
570
Klassen übersetzen
Übersetzung durchführen:
mkdir classes
javac −d classes src/de/rainer_klute/rmi/WWS.java
src/de/rainer_klute/rmi/Bestellung.java
src/de/rainer_klute/rmi/Posten.java
javac −d classes
src/de/rainer_klute/rmi/server/WWSImpl.java
javac −d classes
src/de/rainer_klute/rmi/client/WWSClient.java
src/de/rainer_klute/rmi/client/BestellungImpl.java
src/de/rainer_klute/rmi/client/PostenImpl.java
Web−Anwendungen mit Java
571
Stubs und Skeletons generieren
RMI−Server
RMI−Client
Stub
Stub
Skeleton
Repräsentiert das Remote−Objekt im Client.
Skeleton
Netzfähiges Gegenstück im Server
Leitet Zugriffe an Remote−Objekt weiter
Web−Anwendungen mit Java
572
Remote−
Objekt
Stubs und Skeletons generieren
RMI−Compiler rmic generiert Stubs und Skeletons
aus Remote−Klassen.
Beispiel:
rmic −classpath classes −d classes
de.rainer_klute.rmi.server.WWSImpl
Ergebnis: Klassen
de.rainer_klute.rmi.server.WWSImpl_Stub
de.rainer_klute.rmi.server.WWSImpl_Skel
Web−Anwendungen mit Java
573
JAR−Dateien erzeugen
RMI−Client und RMI−Server dürfen nicht den selben
Classpath nutzen.
Entspräche nicht dem Konzept der getrennten
Entwicklung.
Unterschiedliche JAR−Dateien mit Klassen für Client
und Server erzeugen
rmicommon.jar mit gemeinsam genutzten Interfaces:
WWS, Bestellung, Posten
rmiserver.jar mit Server−Klassen: WWSImpl,
WWSImpl_Stub, WWSImpl_Skel
rmiclient.jar mit Client−Klasse: WWSClient,
BestellungImpl, PostenImpl
Web−Anwendungen mit Java
574
Programme starten
RMI−Server:
java −cp dist/lib/rmicommon.jar:dist/lib/rmiserver.jar
−Djava.rmi.server.codebase=file:///home/.../classes/
−Djava.rmi.server.hostname=mark
−Djava.security.policy=rmiPolicy
de.rainer_klute.rmi.server.WWSImpl
Versuche, WWS als "//192.168.10.1/WWS" zu registrieren.
Okay.
RMI−Client:
java −cp dist/lib/rmicommon.jar:dist/lib/rmiclient.jar
−Djava.security.policy=rmiPolicy
de.rainer_klute.rmi.client.WWSClient //mark/WWS
WWS−Status: All subsystems running.
Server: getStatus()
Web−Anwendungen mit Java
575
Klassen laden mit RMI
Wesentlich für das korrekte Funktionieren von RMI ist
das Übertragen von Klassen.
RMI−Client benötigt die Stub−Klasse(n).
RMI−Server benötigt die Klassen der Objekte, die ihm der
RMI−Client überträgt.
Klassen sollten nicht im Classpath enthalten sein.
Getrennte Entwicklung von Client und Server
Anbieter des RMI−Servers muß Stub−Klasse(n) zum
Herunterladen verfügbar machen.
Property java.rmi.server.codebase teilt
mit, wo die Klassen liegen.
Web−Anwendungen mit Java
576
Risiken bei fremdem Code
Das Ausführen heruntergeladener Klassen ist ein
Sicherheitsrisiko.
Code kann beliebige Aktionen ausführen, zu denen
der Benutzer berechtigt ist.
Daten ausspionieren
Daten verändern
System schädigen
Web−Anwendungen mit Java
577
Sandkastenmodell
Java 1.0 und 1.1 unterstützen das Sandkasten−
Modell:
Java−Applets dürfen nichts nur Anzeige im Browser.
Java−Applikationen dürfen alles.
Sandkasten−Modell unzureichend:
Applets benötigen ggf. Zugriff auf Systemressourcen.
Beispiel: Texteditor−Applet speichert Text in lokaler Datei.
Einschränkungen für Applikationen erforderlich
Beispiel: Vom RMI−Server geladene Klassen dürfen nur in das
Verzeichnis /tmp schreiben.
Web−Anwendungen mit Java
578
Sicherheit
Java 2 ermöglicht fein granulierte
Zugriffsberechtigungen.
Welche Klasse darf welche Aktion ausführen?
Von welchem Ort stammt diese Klasse (Codebase)?
Von welchem Hersteller stammt diese Klasse
(digitale Signatur)?
Policy−Datei legt Zugriffsberechtigungen fest.
Beispiel: Klassen von http://rmi.rainer−klute.de:1111/
dürfen in /tmp lesen und schreiben.
Security−Manager führt Zugriffskontrollen durch.
Beispiel: Berechtigungsprüfung beim Öffnen
der Datei /tmp/foo
Web−Anwendungen mit Java
579
Beispiel: Policy−Datei
keystore "${user.home}/.keystore", "JKS";
grant {
permission java.net.SocketPermission "*", "resolve";
permission java.net.SocketPermission "for.bar.de:1024−2000",
"connect, accept";
};
grant codeBase "http://rmi:1111/" {
permission java.io.FilePermission "<<ALL FILES>>", "read";
permission java.io.FilePermission "/tmp/−", "read, write";
};
grant signedBy "RainerKlute" {
permission java.security.AllPermission;
};
Erzeugen der Policy−Datei: Texteditor oder policytool
Verwenden der Policy−Datei mit
−Djava.security.policy=url
Web−Anwendungen mit Java
580
Sicherheitsprüfungen aktivieren
Java−Programme laufen normalerweise ohne
Security−Manager.
Alles ist erlaubt. Kompatibilität zu Java 1.0 und 1.1 ist
gewährleistet.
Standard−Security−Manager aktivieren
Beim Start des Java−Programms:
java −Djava.security.manager
−Djava.security.policy=policy−url MeineKlasse
Programmgesteuert:
if (System.getSecurityManager() == null)
Sicherheitsprüfungen durchführen
Viele Methoden der Java−Standardklassen führen
Sicherheitsprüfungen durch.
Vor einer potentiell gefährlichen Operation
Beispiel: Datei zum Lesen öffnen
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkRead(filename);
Klasse SecurityManager besitzt zahlreiche
checkXXX−Methoden:
checkAccept, checkAccess, checkAwtEventQueueAccess, checkConnect,
Sicherheitsgrundeinstellungen
JDK−Installation gibt Sicherheitsgrundeinstellungen
vor.
Dateien in ${java.home}/jre/lib/security,
z.B. /opt/local/jdk1.3/jre/lib/security
Hauptdatei java.security
Hier nur einige Einstellungen zum Thema Policy
# URLs von Policy−Dateien:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
# −Djava.security.policy=someURL erlaubt?
policy.allowSystemProperty=true
Web−Anwendungen mit Java
583
Einstellungen in java.policy
Standarderweiterungen dürfen alles.
grant codeBase "file:${java.home}/lib/ext/*" {
permission java.security.AllPermission;
};
Jeder Code darf den aktuellen Thread stoppen, auf
nichtprivilegierten Ports lauschen und Standard−
Properties lesen.
grant {
permission java.lang.RuntimePermission "stopThread";
permission java.net.SocketPermission "localhost:1024−",
"listen";
permission java.util.PropertyPermission "java.version",
};
Klassen laden mit RMI
RMI−Classloader lädt Klassen nur dann, wenn ein
Security−Manager installiert ist.
RMI−Security−Manager in Client und Server installieren
if (System.getSecurityManager() == null)
System.setSecurityManager
(new RMISecurityManager());
Web−Anwendungen mit Java
585
RMI−Server starten
RMI−Server starten (1. Versuch)
java −cp dist/lib/rmiserver.jar:dist/lib/rmicommon.jar
de.rainer_klute.rmi.server.WWSImpl
Fehler:
java.security.AccessControlException: access denied
(java.net.SocketPermission 127.0.0.1:1099
connect,resolve)
Security−Manager verbietet Verbindungsaufbau.
Web−Anwendungen mit Java
586
RMI−Server starten
RMI−Server registriert Wurzel−Objekt bei einer
RMI−Registrierung.
Naming.rebind("//localhost/WWS", new WWSImpl());
Verbindung zur RMI−Registrierung aufbauen
Hier: localhost, Port 1099 (Voreinstellung)
Alternativer Port möglich: "//localhost:1234/WWS"
Alternativer Rechner möglich: "//other.host.de/WWS"
AccessControlException, weil RMI−Server keine
Netzverbindung zur RMI−Registrierung aufbauen kann
Web−Anwendungen mit Java
587
RMI−Server starten
Policy−Datei mit der benötigten Berechtigung erstellen
Mit Texteditor oder policytool
grant {
permission java.net.SocketPermission
"localhost:1099", "connect";
};
RMI−Server starten (2. Versuch mit Policy−Datei)
java −cp dist/lib/rmiserver.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiServerPolicy
de.rainer_klute.rmi.server.WWSImpl
Fehler:
RMI−Server starten
RMI−Registrierung starten
(unset CLASSPATH; rmiregistry &)
RMI−Server starten (3. Versuch mit laufender RMI−
Registrierung)
java −cp dist/lib/rmiserver.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiServerPolicy
de.rainer_klute.rmi.server.WWSImpl
Fehler
java.rmi.ServerException: RemoteException occurred in
server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling
arguments; nested exception is:
java.lang.ClassNotFoundException:
de.rainer_klute.rmi.server.WWSImpl_Stub
Web−Anwendungen mit Java
589
RMI−Server starten
Fehlerursache finden
java.rmi.ServerException: RemoteException occurred in
server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling
arguments; nested exception is:
java.lang.ClassNotFoundException:
de.rainer_klute.rmi.server.WWSImpl_Stub
...
at java.rmi.Naming.rebind
at de.rainer_klute.rmi.server.WWSImpl.main
RemoteException: Fehler nicht im RMI−Server,
sondern in einer Remote−Methode
ClassNotFoundException: Kommunikationspartner
kennt Klasse WWSImpl_Stub nicht.
Naming.rebind: Kommunikationspartner ist die
RMI−Registrierung.
Web−Anwendungen mit Java
590
Sag mir, wo die Klassen sind
RMI−Registrierung soll Instanz von WWSImpl_Stub
speichern und auf Anforderung an Clients ausliefern.
RMI−Registrierung benötigt die Klasse des Objekts.
Klasse nicht im Classpath enthalten.
RMI−Registrierung bewußt ohne Classpath gestartet
RMI−Server muß der Registrierung verraten, wo die
Klassen sind.
Property java.rmi.server.codebase
URL, z.B. file:///home/klute/classes/ oder
http://classes.rainer−klute.de:1111/
RMI−Partner muß Ort der Klassen verraten.
Web−Anwendungen mit Java
591
RMI−Registrierung
Name:
WWS
...
RMI−Registrierung
Objekt: Codebase: Server:
Stub http://cserver/dir/ rserver
...
...
...
RMI−Client
RMI−Server
Stub
Stub
http://cserver/dir/
java.rmi.server.codebase=
http://cserver/dir/
rserver
Class−Server
cserver
Web−Anwendungen mit Java
592
RMI−Server starten
RMI−Server starten (4. Versuch mit Codebase)
java −cp dist/lib/rmiserver.jar:dist/lib/rmicommon.jar
−Djava.rmi.server.codebase=file:///home/klute/classes/
−Djava.security.policy=rmiServerPolicy
de.rainer_klute.rmi.server.WWSImpl
Ausgabe:
Versuche, WWS als "//127.0.0.1/WWS" zu registrieren.
Okay.
Endlich Erfolg!
Für’s erste jedenfalls...
Web−Anwendungen mit Java
593
RMI−Client starten
RMI−Client starten (1. Versuch)
java −cp dist/lib/rmiclient.jar:dist/lib/rmicommon.jar
de.rainer_klute.rmi.client.WWSClient //mark/WWS
java.security.AccessControlException: access denied
(java.net.SocketPermission mark resolve)
Client benötigt das Recht, Host−Namen per DNS
aufzulösen, sprich: die IP−Adresse zu ermitteln.
Policy−Datei für Client anlegen
grant {
permission java.net.SocketPermission "*", "resolve";
};
Web−Anwendungen mit Java
594
RMI−Client starten
RMI−Client starten (2. Versuch mit Policy)
java −cp dist/lib/rmiclient.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiClientPolicy
de.rainer_klute.rmi.client.WWSClient //mark/WWS
java.security.AccessControlException: access denied
(java.net.SocketPermission 127.0.0.2:1099
connect,resolve)
Client benötigt das Recht, auf die RMI−Registry
zuzugreifen. Hier: Port 1099 auf beliebigem Host
grant {
};
permission java.net.SocketPermission "*", "resolve";
permission java.net.SocketPermission "*:1099", "connect";
Ggf. Hosts einschränken oder Ports erweitern
Web−Anwendungen mit Java
595
RMI−Client starten
RMI−Client starten (3. Versuch)
java −cp dist/lib/rmiclient.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiClientPolicy
de.rainer_klute.rmi.client.WWSClient //mark/WWS
java.lang.ClassNotFoundException:
java.security.AccessControlException: access denied
(java.io.FilePermission /home/klute/classes/− read)
Client lernt aus Stub, wo die zugehörige Klasse ist.
Client benötigt das Recht, auf das Klassenverzeichnis
zuzugreifen.
grant {
};
permission java.net.SocketPermission "*", "resolve";
permission java.net.SocketPermission "*:1099", "connect";
permission java.io.FilePermission
"/home/klute/classes/−", "read";
Web−Anwendungen mit Java
596
RMI−Client starten
RMI−Client starten (4. Versuch)
java −cp dist/lib/rmiclient.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiClientPolicy
de.rainer_klute.rmi.client.WWSClient //mark/WWS
java.security.AccessControlException: access denied
(java.net.SocketPermission 127.0.0.1:2833
connect,resolve)
Client benötigt das Recht, eine Verbindung zum RMI−
Server aufzubauen (genauer: zum Remote−Objekt).
Port−Nummer läßt sich im Konstruktor von
UnicastRemoteObject festlegen.
grant {
};
permission java.net.SocketPermission "*", "connect";
permission java.io.FilePermission
"/home/klute/classes/−", "read";
Web−Anwendungen mit Java
597
RMI−Client starten
RMI−Client starten (5. Versuch)
java −cp dist/lib/rmiclient.jar:dist/lib/rmicommon.jar
−Djava.security.policy=rmiClientPolicy
de.rainer_klute.rmi.client.WWSClient //mark/WWS
java.rmi.ConnectException: Connection refused to host:
127.0.0.1; nested exception is:
java.net.ConnectException: Verbindungsaufbau abgelehnt
Stub sucht Skeleton auf dem eigenen Rechner
(127.0.0.1 = localhost) statt auf der Server−Maschine.
RMI−Server hat sich bei der RMI−Registrierung als
»localhost« registriert. Diesen Rechnernamen gibt die
RMI−Registrierung mit dem Stub an den Client weiter.
Web−Anwendungen mit Java
598
RMI−Server neu starten
Property java.rmi.server.hostname legt
Hostnamen oder IP−Adresse für die Registrierung fest.
RMI−Server neu starten
java −cp dist/lib/rmiserver.jar:dist/lib/rmicommon.jar
−Djava.rmi.server.codebase=file:///home/klute/classes/
−Djava.security.policy=rmiServerPolicy
−Djava.rmi.server.hostname=rserver
de.rainer_klute.rmi.server.WWSImpl
RMI−Client neu starten
Bingo!
Web−Anwendungen mit Java
599
Objekte übertragen
Client stellt Bestellung zusammen.
Interfaces Bestellung, Posten
Implementierungen BestellungImpl, PostenImpl
Client schickt Bestellung zum Server.
Bestellung b = new BestellungImpl();
// ...
b.addPosten(p);
String s = wws.bestellen(b);
System.out.println("WWS−Nachricht: " + s);
Übertragen zweier serialisierter Objekte (Marshalling).
Klassen−Server
Problem in der Beispielanwendung:
Zugriff auf Klassen über das Dateisystem
Im allgemeinen nicht möglich
Lösung für produktive Anwendung:
Klassendateien auf FTP− oder HTTP−Server legen
Immer noch problematisch: Übertragen der Klassen
vom RMI−Client zum RMI−Server
Lösung: RMI−Client implementiert eigenen HTTP−
Server.
RMI überträgt Objekte.
HTTP−Server überträgt Klassen.
Web−Anwendungen mit Java
601
RMIClassServer
RMIClassServer: HTTP−Server für Klassen
Basiert auf Mini−Klassenserver von Sun Microsystems.
Wird in normale RMI−Client− oder RMI−Server−
Anwendung eingebaut.
RMIClassServer rcs = RMIClassServer.instance();
int port = rcs.run();
Classpath der Anwendung in System−Property
de.rainer_klute.rmi.classserver.classpath vorgeben
Ermittelt freien Port und startet Server−Thread.
RMI: Nicht behandelte Themen
RMI über Firewalls
HTTP−Tunnelling
Objekte auf festgelegtem Port exportieren
Eigene Socket−Typen
Z.B. RMI über SSL
Remote Object Activation
Remote−Objekte auf Anforderung erzeugen
Marshalling
RMI−IIOP
RMI−Programm (Java) spricht mit CORBA−
Programm.
Web−Anwendungen mit Java
603