Entfernter Methodenaufruf mit RMI 7.1 Remote Method Invocation

Werbung
7
Entfernter Methodenaufruf mit RMI
In diesem Kapitel stellen wir ein System vor, das die Kommunikation zwischen Objekten, die auf verschiedenen Rechnern
erzeugt sind, ermöglicht Im Gegensatz zur XML-RPC-Spezifikation aus Kapitel 6 sind die Datentypen der Methodenaufrufparameter nicht eingeschränkt Neben (fast) beliebigen Objekten
kann auch das Verhalten (Bytecode) übertragen werden, so dass
flexible Anwendungen realisiert werden können. Allerdings muss
sowohl der Client als auch der Server in Java programmiert sein.
7.1
Remote Method Invocation
Das Protokoll Remote Method Invocation (RMI) setzt auf TCP/IP
auf und verbirgt die Details einer Netzverbindung. RMI hat folgende Eigenschaften,
•
Mit RMI können Methoden für Objekte aufgerufen werden, Eigenschaften
die von einer anderen virtuellen Maschine QVM) erzeugt und von RMI
verwaltet werden - in der Regel auf einem anderen Rechner.
•
Für den Entwickler sieht der entfernte Methodenaufruf wie
ein ganz normaler lokaler Aufruf aus .
•
Entfernt aufrufbare Methoden werden in einem Interface
deklariert. Nur hierüber kann der Client mit einem entfernten
Objekt kommunizieren. Das Interface stellt einen so genannten Vertrag zwischen Client und Server dar.
•
Netzspezifischer Code, der die Codierung und übertragung
von Aufrufparametern und Rückgabewerten ermöglicht, wird
ab Java SE 5 dynamisch zur Laufzeit generiert
•
Um für den ersten Aufruf einer entfernten Methode eine "Referenz" auf das entfernte Objekt, das diese Methode anbietet,
zu erhalten, kann der Client einen so genannten Namensdienst (Registry) nutzen,
•
RMI bietet Mechanismen sowohl für die Übertragung von
Objekten als auch für die Übertragung und das Laden des
Bytecodes der zugehörigen Klassen, falls diese lokal nicht
vorhanden sind.
•
RMI ist eine rein Java-basierte Lösung, d. h. Client und Server
müssen in Java programmiert sein.
Mit Hilfe eines Namensdienstes können Dienste zentral veröffent- Begriffserklätung
licht werden, sodass Clients diese über ein Netz finden und nut- Namensdienst
zen können. Namensdienste ordnen den Adressen von Ressourcen (beispielsweise entfernten Objekten) eindeutige Namen zu.
7
250
Entfernter Methodenaufruf mit RMI
Die Adresse einer Ressource enthält alle Informationen, die ein
Client braucht, um mit der Ressource zu kommunizieren. Um
eine "Referenz" auf die gewünschte Ressource zu erhalten, übergibt der Client dem Namensdienst den Namen, unter dem die
Ressource angemeldet ist. Als Ergebnis erhält er die Referenz, mit
der nun eine Verbindung zur Ressource aufgebaut werden kann.
Bild 7.1 zeigt den allgemeinen Fall einer mit RMI realisierten
Client-Server-Anwendung.
Bild 7.1·
Rechner B
RMI-Anwendung
J
Rechner A
Client
~~
Registry
I
~r
0
0
0 Server
0
-,
Der Client erhält über die Registry eine "Referenz" auf ein entferntes Objekt. das der Server vorher dort registriert hat. Für
dieses Objekt ruft der Client eine Methode auf. Gegebenenfalls
kann das RMI-System auch einen Webserver nutzen, um Bytecode für Objekte vom Server zum Client bzw. umgekehrt zu übertragen.
Die Zusammenhänge. Begriffe und die erforderlichen Klassen
und Methoden zur Entwicklung einer RMI-Anwendung werden
nun im Folgenden anhand eines ersten Beispiels schrittweise
erläutert.
Programm 7.1
Programm 7.1 zeigt die Implementierung eines Echo-Dienstes.
Remote Interface
Das Remote Interface definiert die Sicht des Client auf das entfernte Objekl. Dieses Interface enthält die Methoden. die für
dieses Objekt entfernt aufgerufen werden können.
Ein Remote Interface ist von dem Interface
ja va. rrri , RelTDte
abgeleitet: RelTDte dient dazu, Interfaces zu kennzeichnen, deren
Methoden entfernt aufgerufen werden sollen. Remot e muss von
allen Interfaces erweitert werden, die entfernte Methoden deklarieren.
7.1
Remote Method Invocation
251
java. rmi . RemoteExceptl on ist von java.l o. IO Exceptlon abgeleitet RemoteException
und ist Superklasse einer Reihe von Ausnahmen, die beim Aufruf
einer entfernten Methode bei Netz- bzw. ProtokoIIfehlern ausgelöst werden können. Jede Methode eines von Remote abgeleiteten
Interfaces (Remote Interface) muss diese Klasse in der throwsKlausel aufführen.
lmport java.rmi.Re mote;
import java.rm i.Re mote Exception;
Remote Interface
Echo
public interface Echo extends Remote (
String get Echo(String s) throws RemoteException;
Jedes Objekt, dessen Klasse ein Remote Interface implementiert, Remote Object
ist ein so genanntes entferntes Objekt (Remote Objeci), d.h. es
implementiert die vorgeschriebenen entfernt aufrufbaren Methoden. Diese Methoden und die Konstruktoren müssen RemoteExcept i on in der throws-Klausel enthalten.
Damit eine Verbindung zwischen Client und Server aufge- Exportieren
nommen werden kann und Methoden des Objekts entfernt aufgerufen werden können, muss das entfernte Objekt exportiert
und damit remote-fäbig gemacht werden.
Dies geschieht durch Ableiten von der Klasse
ja va. rmi .server. UnlcastRemoteObject.
Bei Erzeugung des entfernten Objekts wird der Konstruktor dieser Superklasse aufgerufen. der das Objekt exportiert. Das exportierte Objekt kann nun über TCP/IP eingehende Nachrichten
erhalten.
Es hat sich die Konvention durchgesetzt, dass die Implementie- Implementierung
rung des Interface Xxx in der Klasse Xxx lmp 1 erfolgt.
des Remote
Interface. EchoImpl
lmport java.rmi.Re moteExceptlon;
lmport java.rm i.server.UnlcastRemoteObject;
public class Echol mpl extends UnicastRemoteObject
implements Echo (
public Echol mpl ( ) throws RemoteException (
)
7
252
Entfemter Methodenaufruf mit RMI
public String getEcho(String s) throws RemoteException {
return 5;
Stub und Skeleton
Die Codierung bzw. Decodierung der Aufrufparameter und
Rückgabewerte von Methodenaufrufen und die Übermittlung der
Daten zwischen Client und Server wird vom RMI-System und
von generierten Klassen, beim Client Stub und beim Server Skeleton genannt, geregelt (siehe Bild 7.2).
Bild 72·
Aufruf einer
entfernten Methode
Server
Client
Server-Programm
Client-Programm
Ergebnisrückgabe
Ergebnis-
Methodenaufruf
rückgabe
Skeleton
Stub
Aufrufcodierung
Ergeb nisdecodierung
RMI-System
Ergebnisempfang
Ergebniscodierung
Aufrufdecodierung
Netzwerkeode
Netzwerkeode
Aufrufübertragung
Methodenaufruf
(
Netz
'I
Ergebnisübertragung
Aufrufempfang
Java Remote Method Protocol (JRMP)
Ein Stub-Objekt fungiert als lokaler Stellvertreter (Proxy) des
entfemten Objekts. Ein Stub implementiert dasselbe Remote
Interface, das auch die Klasse des entfemten Objekts implementiert.
Remote Reference
Ein Client erhält Zugriff auf ein entfemtes Objekt durch eine so
genannte enifernte Referenz (Remote Reference). Diese wird
beim Erzeugen des lokalen Stub-Objekts bereitgestellt. Sie kapseIt Informationen, die für den Zugriff auf das entfernte Objekt
benötigt werden. Der Client ruft eine Methode des Stub-Objekts
auf, die dann für den Methodenaufruf des entfemten Objekts auf
der Serverseite sorgt (siehe Bild 7.3). Kurz gesagt wird eine entfernte Referenz durch eine Referenz auf ein entsprechendes
Stub-Objekt realisiert.
7.1
Remote Method Invocation
253
Client
Bild 73·
Remote Reference
St ring st r =
p.getEcho (s);
Aufrufparameter
verpacken
Rückgabewert
auspacken
Server
Skeleton
Stub
Remote
Reference
Aufrufparameier
auspacken
Rückgebewert
verpacken
public s t r i no ge t Echo(Stdng s )
t. h rows RemoteException {
r e tu r n :3;
Das Java Remote Method Protocol ORMP) wird vom Stub genutzt. Generierung von
um mit dem Server zu kommunizieren. Es liegt in zwei Versio- Stub und Skeleton
nen vor, 1.1 und 1.2.
•
Version 1.1 kommuniziert mit einem Skeleton (wird genutzt
für Clients, die unter ]DK 1.1 laufen),
•
Version 1.2 benötigt keine Skeleton-Klasse.
Das Tool rmic erzeugt Stubs und Skeletons aus den kompilierten
Klassen, die die Implementierung des Remote Interface enthalten.
•
rmic -vl.l
erzeugt Stubs und Skeletons für JRMP 1.1,
•
rmic -vl.2
erzeugt nur Stubs für JRMP 1.2.
Ab Java SE 5 werden Stubs zur Laufzeit dynamisch generiert,
sodass rmic nicht mehr gebraucht wird. rmic steht aber weiterhin zur Verfügung, um Clients unter früheren Java-Versionen zu
unterstützen. Der Aufruf von rmic ohne weitere Option verhält
Um Stubs und Skeletons, die mit JRMP
sich wie rmic -vl.2 .
1.1 und 1.2 kompatibel sein sollen, zu generieren, muss
rmic -vcompat .. . genutzt werden.
Die Klasse EchoServer (siehe unten) erzeugt ein entferntes Objekt
vom Typ EchoImpl und registriert dieses bei einem Namensdienst
(Registry).
Das vom JDK bereitgestellte Programm rmiregistry stellt einen Registry
einfachen Dienst zur Verfügung, der es dem Client erlaubt, eine
erste Referenz auf ein entferntes Objekt als Einstiegspunkt zu
7
254
Entfemter Methodenaufruf mit RMI
erhalten. Weitere Referenzen auf andere entfernte Objekte können von hier aus dann anwendungsspezifisch, z. B. als Rückgabewerte von entfernten Methodenaufrufen, geliefert werden.
Jeder Eintrag in der Registry besteht aus einem Namen und einer
Objektrejerenz.
Der Name hat die Form eines URL:
//host:port/ Dienstname
Bis auf Dienstname können alle Bestandteile entfallen. Der Rechnemame ist in diesem Falllocalhost und die Fortnummer 1099.
Soll für die Registry eine andere als die standardmäßig vorgesehene Portnummer 1099 benutzt werden, so muss sie als Aufrufparameter beim Start von rmiregistry angegeben werden.
Naming
Die Klasse java . rmi . Naml ng wird von Clients und Servern benutzt,
um mit der Registry zu kommunizieren.
bind
static voi d bind(String name. Remote obj)
throws ja va. rmi .Alrea dyBJund Exceptl cn,
java.net.MalformedU RL Exceptlon, java.rml.Re moteExceptlon
registriert einen Eintrag für ein entferntes Objekt. name wird an
obj gebunden. Alr eadyBJundExceptl on wird ausgelöst, wenn narre
bereits eingetragen ist. Ha1formedURL Exceptl on wird ausgelöst,
wenn der Aufbau von narre nicht korrekt ist.
rebind
statlc vOl d reblnd(Strlng name, Remot e obj)
throws ja va.net.MalformedURLException.
java.rml.RemoteExceptlon
registriert einen Eintrag für ein entferntes Objekt. name wird an
obj gebunden. Besteht bereits ein Eintrag zu diesem Namen, so
wird der bestehende Eintrag überschrieben. Mal formedURLExcept l on wird ausgelöst, wenn der Aufbau von narre nicht korrekt ist.
unbind
statlc vOld unblnd(Strlng name)
throws ja va.rml . NotBJund Exceptlon ,
java.net.HalforrredU RL Exceptlon, java.rml.RemoteExceptlon
entfernt den Eintrag zu name. Not BJundExceptlon wird ausgelöst,
wenn zu name kein Eintrag vorhanden ist. Ha lforrredURL Exceptl on
wird ausgelöst, wenn der Aufbau von narre nicht korrekt ist.
Diese drei Naml ng-Methoden können nur auf dem Rechner ausgeführt werden. auf dem auch der Namensdienst läuft.
7.1
255
Rernote Method Invocation
lmport java.rml .Namlng;
lmport java.rmi.Re mote;
Der Server:
EchoServer
public class EchoSer ver (
public static void main(String args[]) throws Except i on (
Remote remote ~ new Echo lmpl ();
Nami ng. rebi nd( "echo", re mJte);
System.out.print ln("EchoSer ver gestartet ... ");
Das RMI-Systern sorgt dafür. dass der Server läuft. auch wenn die
Ausführung der ma in-Methode beendet ist.
import java.rm i.Naming;
public class EchoCl i ent (
public static voi d main(String args[]) throws Exception
if (args.length !~ 2) (
Der Client:
EchoClient
System.err.println("java EchoClient <hast> <text>");
System. exi t (1)
;
String host
String text
args[O];
args[l];
Echo remote
(Echo) Naming.lookup("11" + host + "Iecho");
String received
=
remote.getEcho(text);
System.out.println (recei ved);
Mittels der Nami ng-Methode lookup erhält der Client das Stub- lookup
Objekt zum entfernten Objekt, das unter dem Namen "echo" in
der Registry eingetragen ist.
static Remot e lookup(String name)
throws java.rmi . NotBound Exception,
java. net .Mal formedURL Excepti cn, java. rmi . RemoteExcepti on
liefert die Referenz auf das Stub-Objekt für das unter name eingetragene entfernte Objekt. Ma lformedURL Excepti on wird ausgelöst.
wenn der Aufbau von name nicht korrekt ist. NotBoundException
wird ausgelöst, wenn zu name kein Eintrag vorhanden ist.
7
256
Test
Entfemter Methodenaufruf mit RMI
Aufruf der Registry:
start /0 bln rmlreglstry
oder
start /0 bi n rmlreglstry
-J ~Djava.rml.server. logCalls=true
(Dies bewirkt, dass der Kommunikationsfluss zwischen Client
und Server protokolliert wird.)
Aufruf des Servers,
start java -cp bln EchoServer
Mit der Systemeigenschaft ja va.rml.server.hostnarre kann der
Hostname bzw. die IP-Adresse des Servers explizit festgelegt
werden.
Beispiel (in einer Zeile einzugeben}
start java - Dj ava .rmi
EchoServer
.server.hostna me~ 169
254.53. 192 -cp bin
Aufruf des Client:
java -cp bi n EchoCl i ent localhost Hal l o
Um sich gegen Einschleusen schädlichen Codes in den Client zu
schützen, kann die Ausführung von einem Security Manager
kontrolliert werden. Hierzu muss eine Policy-Datei mit beispielsweise folgendem Inhalt angelegt werden,
policy.txt
grant {
perml ss l on java. net .SocketPermlss l on "* : 1024-". "connect";
};
Der Client ist dann wie folgt aufzurufen (in einer Zeile einzugeben}
java -Djava.securlty .manager -Djava securlty.pollcy=pollcy.txt
-cp bin EchoCl ie nt localhost Hal l o
Client und Server können natürlich auch auf unterschiedlichen
Rechnern installiert und getestet werden.
LocateRegistry
rmiregistry startet die Registry auf einem Rechner, die dann für
mehrere RMI-Server genutzt werden kann. Eine individuelle Registry kann aber auch innerhalb des Servers gestartet werden.
7.1 Remote Method Invocation
Dazu steht
die
Klasse
LocateReglstry im Paket
257
ja va.rml.
regi st ry zur Verfügung.
Die Methode
statlc Reglstry createRegistrY(lnt port)
throws java.rml . RemoteExceptlon
erzeugt eine Registry die auf dem Port port Anfragen akzeptiert.
Programm 7.2 demonstriert den Einsatz von Locat eRegls try und Programm 7.2
zeigt, wie die Nummer des Ports, an dem das entfernte Objekt
Methodenaufrufe empfängt. vorgegeben werden kann. Hierzu
wird der folgende Konstruktor der Klasse UnicastRemoteObject
genutzt:
protected UnicastRemoteObject(lnt port) throws Remote Exceptlon
Gegenüber Programm 7.1 werden Echolmpl . EchoServer und EchoCl i ent wie folgt angepasst
lmport java.rmi.Re moteExcept ion;
import java.rm i.server.UnicastRe moteObject;
Echolmpl
public class Echolmpl extends UnicastRemoteObject
i mpl ement s Echo (
public Echolmpl (i nt port) throws RemoteException (
super(port) ;
public Str ing getEcho(String s) throws RemoteException {
return 5;
import java.rmi.Naming;
import java.rm i.Re mote;
import java.rm i.registry LocateRegistry;
public class EchoServer (
public static void main(String args[]) throws Except i on
int registryPort ~ Integer .parselnt (args [ O]) ;
int port ~ Int eger .parsel nt (args [l ] ) ;
LocateRegistry.createRegistry(registryPort);
Remote remote ~ new Echolmpl (port);
Nami ng .rebi nd(" /I;" + regi stryPort + "Iecho". remote);
System .out.println("EchoServer gestart et ... ");
EchoServer
7
258
EchoClient
Entfemter Methodenaufruf mit RMI
lmport ja va.rml.Namlng;
publ ic class EchoCl i ent (
public stat ic voi d main(String args[J) throws Except i on {
if (args.length !- 3) (
System. err.println(
"ja va EchoCl l ent <hast> <port> <text>");
System.exit(l);
String host - args[OJ;
int port - Int eger . parsel nt (args [ l J ) ;
Str ing text
args[2J ;
Echo relTDte
(Echo) Naming.lookup(
"lI" + host + '"." + port + "Iecho");
Strlng recelved
=
remote.getEcho(text);
Syst em.out.println(received);
Bei Einsatz des Security Managers müssen dann nur die Portnummer für die Registry und die Portnummer für das Remote
Object freigegeben werden.
Beispiel (policy. txi).
grant {
perml ss l on java net SocketPermlss l on "*: 40000", "connect";
perml ss l on java net SocketPermlss l on "*: 50000", "connect";
};
Aufrufparameter
und Rückgabewert
Die Aufrufparameter und der Rückgabewert einer entfernten
Methode können von einem einfachen Datentyp, Referenzen auf
"normale" lokale Objekte oder Referenzen auf entfernte Objekte
sein.
Übenragungsregeln
Für entfernte Methoden gelten die folgenden Übertragungsregeln
Werte von einfachem Datentyp (z.B. i nt, doubl e) werden wie bei
lokalen Methodenaufrufen hy value übertragen.
Lokale Objekte werden serialisiert, übertragen und vom
Server deserialisiert. Dafür sorgen Stub und Skeleton. Lokale
Objekte werden, anders als beim lokalen Methodenaufruf, als
Kopie hy value übertragen. Diese Objekte müssen also das Interface java.lo.Serlallzable implementieren.
7.2
Dienstauskunft
259
Exportierte entfernte Objekte werden by reference übertragen. d.
h. es werden die Stub-Objekte, nicht Kopien der Originale übertragen.
Die folgende Tabelle fasst die Regeln zusammen,
Typ
lokale Methode
entfernte Methode
einfacher Typ
by value
by value
Objekt
by reference
by value
CSerialisierung)
entferntes Objekt
by reference
by remote reference
(Stub-Objekt)
7.2
Dienstauskunfl
Das folgende Programm gibt eine Liste aller in der Registry gebundenen Namen aus.
Die Nami ng-Methode
static Str ing[J list(Str ing name)
throws java.rml . Remote Exceptlon,
ja va.net.MalformedURLException
liefert ein Array von Namen, die an entfernte Objekte gebunden
sind. name spezifiziert die Registry in der Form / /host: port.
lmport java. rml. Naming;
Programm 73
public class ListRegistry (
public static void main(String args[J) throws Except i on (
String registryNam e ~ args[OJ;
String list[J ~ Naming .list (registryName);
for (String name
list) (
System.out.println (name);
java -cp bin ListRegistry //localhost: 40000
Die Ausgabe hat die Form
//host:port/Djenstname
Test
7
260
7.3
Entfernter Methodenaufruf mit RMI
Transport by reference
Beim Aufruf entfernter Methoden werden lokale Objekte als
Kopie in serialisierter Form übertragen. Das folgende Beispiel
zeigt eine entfernte Methode, die als Rückgabewert eine enifernte Referenz liefert, mit deren Hilfe eine entfernte Methode eines
weiteren entfernten Objekts vom Client aufgerufen werden kann.
Programm 7.4
Der RMI-Server soll Konten mit den Attributen Kontonummer
Gd), PIN und Saldo verwalten, Der Client kann ein neues Konto
mit Angabe von Kontonummer und PIN anlegen oder ein bereits
unter seiner Kontonummer eingerichtetes Konto öffnen. Für
dieses Konto kann er dann einen Betrag einzahlen oder abheben
sowie sich seinen Kontostand anzeigen lassen.
Für dieses Beispiel nutzen wir eine eigene Except l on-Klasse :
KontoException
publlc class Konto Exceptlon extends Except l on {
public Konto Exception() {
}
public Konto Exception (Str ing msg)
super(msg) ;
Remote Interface
Konto
l mpor t ja va rmi .Remote;
lmport ja va rml.RemoteExceptlon;
publ ic interface Konto extends Remote (
int getSaldo () throws Remote Excep t ion;
vOld add(lnt betrag) thro ws RemoteExceptlon, Konto Exceptlon;
Remote Interface
KontoManager
l mport ja va rmi .Remote;
lmport ja va rml.RemoteExceptlon;
publ l c l nt erface KontoManager extends Remote {
Kont o getKonto(lnt ld, l nt pl n) throws Remote Exceptlon,
Konto Exceptlon;
Die entfernte Methode getKonto gibt eine entfernte Referenz auf
ein Konto-Objekt zurück
7.3 Transport by reference
261
Wird versucht, das Konto zu überziehen, so wird eine Ausnahme Kontolmpl
vom Typ KontoExcepti on ausgelöst.
import java.rmi . RemoteException;
import java.rmi .server.UnicastRemoteObject;
public class Kontolmpl extends UnicastRemoteObject
implements Konto {
private int pin;
private int saldo;
public Konto lmpl (int pin) throws RemoteException (
this.pin = pin;
public int getSaldo() throws RemoteException (
return saldo;
public void add (int betrag) throws RemoteException,
KontoException {
if (saldo + betrag< 0) (
throw new KontoException(
"Das Konto kann nicht ueberzogen werden. ");
}
saldo
+~
betrag;
public int getPin()
return pi n:
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.ut i l .Hashtab.e:
public class KontoManagerImpl extends UnicastRemoteObject
implements KontoManager {
pri vate Hashtable<Integer, Kontolmpl> hashtable;
public KontoManagerlmpl() throws RemoteException (
hashtable ~ new Hashtable<Integer, Kontolmpl>();
public Konto getKonto(int id, int pin)
throws RemoteException, KontoException
KontoManagerlmpl
7
262
Entfernter Methodenaufruf mit RMI
KontoImpl konto ~ hashtable.get(id);
i f (konto ~~ null) (
konto ~ new KontoImpl(pin);
hashtable.put(id. konto);
System.out.println("Konto " + id
+ " wurde elngerlchtet. ");
return konto;
else (
if (konto.getPin() ~~ pin)
return konto;
else
throw new KontoException ( "PIN ist unguelt i 9 . " ) ;
Die Konten werden in einer Hashtable unter der jeweiligen Kontonummer gespeichert. Ist bereits unter der angegebenen Kontonummer ein Konto vorhanden, so wird geprüft, ob die angegebene PIN gültig ist. Ist die PIN nicht korrekt, wird eine Ausnahme ausgelöst. Ist die Kontonummer neu, so wird ein neues
Konto eingerichtet. Bei fehlerfreier Verarbeitung wird in beiden
Fällen die entfernte Referenz auf ein Konto-Objekt zurückgeliefert.
BankServer
lmport java rml.Namlng;
l mpor t java rmi . Remote;
public class BankServer (
public static void main(String args[]) throws Exception (
Remote remote
=
new KontoManagerImpl();
Naming. rebind("bank". remote);
System. out. pri nt1n( "BankServer gestartet ... ");
Das "Einstiegsobjekt" vom Typ KontoManagerImpl wird registriert.
Beim Aufruf des Client werden als Parameter u. a. Kontonummer
und PIN rrtitgegeben. Das Programm ermöglicht die Ausführung
verschiedener Aktionen:
get
+nnn
- nnn
q
Anzeige des Saldos
Betrag nnn einzahlen
Betrag nnn auszahlen
Beenden
7.3 Transport by reference
lmport java.io.BufferedReader;
import j ava. i 0 . I nputSt reamReader ;
import java.rmi.Naming;
publie elass BankClient (
publie statie void main(String args[J) throws Exeeption {
if (args.length !- 3) (
System.err.println("java BankClient <hast> <id> <p i n>"}:
System. exi t (1) ;
String host - args[OJ;
int id - Integer.parseInt(args[lJ);
int pin - Integer.parseInt(args[2J);
KontoManager manager - (KontoManager) Naming lookup("/ /"
+ host + "/bank");
Konto konto - manager.getKonto(id. pin);
BufferedReader in - new BufferedReader(
new InputStreamReader(System.in));
String input;
whi 1e (true) {
try {
System. out
.println("Kommando eingeben (get 1 <zahl »] q);");
input - in.readLine();
if (input -- null 11 input length() -- 0
11 input.equals("q"))
break;
if (input.equals("get")) {
System. out. pri nt 1n("Aktuell er Kontostand;
+ konto.getSaldo());
else (
int betrag - Integer parseInt(input);
konto.add(betrag);
}
eateh (NumberFormatExeeption e) {
eateh (KontoExeeption e) (
System.out.println(e.getMessage());
Mit 1ookup erhält der Client Zugriff auf das entfernte KontoManager-Objekt. Hierfür ruft er die Methode getKonto auf und
erhält als Rückgabewert eine entfernte Referenz auf ein Konto-
Objekt, für das er dann die entfernten Konto-Methoden aufruft.
263
BankClient
7
264
Test
Entfemter Methodenaufruf mit RMI
Registry und Server werden wie in Kapitel 7.1 aufgerufen.
Aufruf des Client:
java -cp bin BankCl i ent localhost 1 1234
Kommando eingeben (get
<zahl>1 q):
1000
Kommando eingeben (get <zahl>1 q):
get
Aktueller Kontostand: 1000
Kommando eingeben (get I <zahl>1 q):
-2000
Das Konto kann nlcht ueberzogen werden.
Kommando eingeben (get I <zahl>1 q):
q
7.4
Mobile Agenten
Ein (serialisierbares) Objekt kann auch dann vom Client zum
Server transportiert werden, wenn der Server den Bytecode der
zugehörigen Klasse noch nicht zur Verfügung hat. Der Code
muss dann ebenfalls zur Laufzeit ad hoc übertragen werden.
Wir nutzen hier diese Möglichkeit, um Methoden dieser Klasse
auf dem Server lokal auszuführen. Derartige Nachrichten entsprechen von ihrem Wesen her einem mobilen Agenten, der im
Auftrag eines Client bestimmte Aufgaben auf einem anderen
Rechner erledigt und danach zurückkehrt.
Programm 7.5
Wir entwickeln einen Server, der beliebige Aufgaben vom Client
entgegennimmt, diese ausführt und die Ergebnisse zurückliefert.
Das ist z. B. dann hilfreich, wenn der Server auf einer sehr
schnellen Maschine läuft und komplexe mathematische Berechnungen ausgeführt werden müssen.
Eine Aufgabe kann durch ein beliebiges Objekt repräsentiert
werden, dessen Klasse das Interface Agent implementiert:
Agent
package agent;
publlC l nt erf ace Agent ext ends java.lo.Serlallzable {
VOl d execute ( ) ;
7.4 Mobile Agenten
package agent;
lmport java.rmi.Re mote;
import java.rmi.Re moteException;
265
Remote Interface
SeroerAgent
public interface ServerAgent extends Remote {
Agent execute(Agent agent) throws Remote Exception;
Die entfernte Methode execute des Remote Interface Ser verAgent
initiiert den Transport des Agent-Objekts und ruft die AgentMethode execute auf
package server;
SeroerAgentlmpl
import java.rmi.Re moteException:
import java.rmi.server.UnicastRe moteObject;
import agent.Agent;
import agent.ServerAgent;
public class ServerAgentlmpl extends UnicastRemoteObject
implements ServerAgent {
public ServerAgentlmpl () throws Remote Exception {
}
public Agent execute (Agent agent) throws Remote Exception {
agent. execute ( ) ;
return agent;
package server;
import java.rmi.Naming;
import java.rmi.Re mote;
public class Server (
public static voi d main(String args[]) throws Exception (
Remote remote = new ServerAgent Impl();
Nami ng. rebi nd(" agent", remote);
System.out.printl n("Server gestartet ... ");
Server
266
7
Entfernter Methodenaufruf mit RMI
Die Klasse DemJÄgent implementiert das Interface Agent. Die Methode execute berechnet die Summe der Zahlen von 1 bis zu
einer vorgegebenen Zahl n. Diese Klasse soll später über das
Netz zum Server transportiert werden.
DemoAgent
package cII ent;
l mport agent.Agent ;
publ i c class DemoAgent impl ements Agent (
pr i vat e l nt n:
prlvate lnt sum;
public DemoAgent (i nt n) (
thlsn=n;
public void execute() {
for (int i ~ 1; i <~ r: i++) (
sum += i :
public int getResult()
r eturn sum:
Client
package cII ent;
lmport java.rml.Nam lng;
l mport agent.Agent ;
lmport agent.ServerAgent;
public class Cli ent (
public static void main(String args[J) throws Except i on {
String hos t ~ arg5[OJ;
ServerAgent remote ~ (ServerAgent ) Nami ng.l ookup ("/ /"
+ host + "/agent");
Agent demo ~ new DemoAgent (l OO) ;
OemoAgent result ~ (OemoAgent) remote.execute(demo);
System.out.println(result.getResult());
7.4
Mobile Agenten
267
Zum Test werden für Client und Server verschiedene Projektverzeichnisse eingerichtet. Die Klasse DemoAgent ist so für den Server
über seinen CLASSPATH nicht erreichbar.
Um den Bytecode von D2mJAgent herunterladen zu können, nutzt
der Server einen HTTP-Server. Hier kann ein beliebiger Webserver genutzt werden, z. B. der Mini-Webserver aus Kapitel 5.4.
Für den Start des Client ist der URL für den zu übertragenden
Bytecode als Wert der Property
ja va.rml.server.codebase
anzugeben. Diese Information wird zum Client übertragen, sodass dieser dann die geeignete HTTP-Anfrage stellen kann.
Der Server muss einen Security Manager nutzen, da das Laden
von Bytecode im Allgemeinen eine unsichere Aktivität ist.
Die Policy-Datei hat für unsere Zwecke den folgenden Inhalt
grant {
permission java.net.SocketPermission "*' 1024-",
policy.txt
"connect, acce pt " ;
permission java.net.SocketPermiss ion "*'8080", "connect" ;
};
Unser HTTP-Server wird an die Portnummer 8080 gebunden.
Bild 7.4 zeigt die Konfiguration. Insbesondere geht aus der Abbildung hervor. welche Klassen dem Client, welche dem Server
lokal zur Verfügung stehen.
-------------------1
HTTP-Server
1---Download
,
De moA g e n t. c L a sa
java.rmi .serve r.codebase=
h t t p : / /lo c alh os t : 8 0 8 0 /
RMI-Client
1
r erno te . execute (demo)
RMI-Server
I
Lokal veriugbare
Interfaces und Klassen:
agent.Agen t
agent.Ser:ve rAgent
c l ient. De moAg e n t
c lient .Cl ient
vom Typ DemoAg ent
Lokal verfügbare
Interfaces und Klassen:
agen t.Agent
ag ent. Se rve r Aqen t
ae rve r . se r v e r:Ag e ntl mpl
se rve r vse r v e r
Bild 7.4·
Dynamisches Laden
einer Klasse
7
268
Test
Entfemter Methodenaufruf mit RMI
Aufruf von Registry und Server (jeweils in einer Zeile einzugeben}
start /0 bin rmiregistry
start java -Dj ava .secur i t y.manager -Djava.securi ty .pol icy=
policy. txt -cp bin server .Server
Aufruf des H'I'Tl-<Servers.
start java -cp . . /Prog0504/bin Mini WebServer 8080 bin
Aufruf des Client (in einer Zeile einzugeben}
java -Ojava.rmi .server.codebase~htt p://loca lhost:8080/ -cp bin
client.Client loca lhost
7.5
Callbacks
In diesem Kapitel sehen wir, dass ein Client auch zeitweise selbst
Dienste anbieten kann. Der Server ruft eine entfernte Methode
des Client auf.
Polling oder
Callback
Eine typische Anwendungssituation ist: Der Client will Ereignisse
beobachten, die auf dem Server eintreten. Statt nun regelmäßig
in bestimmten Abständen eine Anfrage an den Server zu stellen,
ob das interessierende Ereignis eingetreten ist oder nicht
(Polling), lässt sich der Client vom Server über das Eintreten des
Ereignisses informieren (Callback).
Damit dieser Callback-Mechanismus funktioniert, muss der
Client sich beim Server registrieren (der Server speichert eine
entfernte Referenz auf ein Remote-Objekt des Clieni). Dann kann
der Server bei Eintreten des Ereignisses eine entfernte Methode
des Client aufrufen. Bei dieser Lösung fällt im Vergleich zum
PoIling unnötige Rechenzeit und Netzlast weg.
Programm 7.6
Zur Veranschaulichung dieses Mechanismus entwickeln wir eine
Anwendung (Client und Server), mit der Textnachrichten, die ein
so genannter Publisher veröffentlicht, an interessierte Abonnenten (Subscriber) gesendet werden können. Der Server hat die
Aufgabe, eine an ihn gerichtete Nachricht sofort an alle Abonnenten weiterzuleiten. Zu diesem Zweck muss er diese "kennen".
Textnachrichten werden in ein rvess age-Ob jekt verpackt, das
zusätzlich den Zeitpunkt der Veröffentlichung enthält.
7.5 Callbacks
publlC class Message implements java.io.Serializable {
private lang timestamp;
private String text;
269
Message
public void setTimestamp(long ti mestamp) (
this.timestamp = timestamp;
public long getTimestamp()
return timestamp;
public void setText(String text) (
this.text ~ text;
public String getText() {
return text;
Das entfernte Objekt des Servers (vom Typ MessageManager) hat
drei Methoden:
•
void setMessageListener(MessageListener listener)
meldet einen Subscriber an.
•
voi d removeMessageListener(MessageListener listener)
meldet einen Subscriber ab.
•
void send(Message msg)
sendet eine Nachricht.
Das entfernte Objekt des Client (vom Typ Messagelistener) hat
die Methode:
•
voi d onMessage( Message msg)
gibt die Nachricht aus.
import java.rmi . Remote;
import java.rmi . RemoteException;
public interface MessageListener extends Remote {
void onMessage(Message msg) throws RemoteException;
MessageListener
7
270
MessageManager
Entfemter Methodenaufruf mit RMI
lmport ja va.rml. Remote;
lmport ja va.rmi .RemoteException;
public interface Mess ageManager extends Remote {
voi d setMessageListener(MessageListener listener)
throws Remote Exception;
voi d remo veMessageListener( MessageListener listener)
t hrows Remote Exception;
voi d send(Message msg) throws Remote Exception;
Bild 7.5 zeigt den Zusammenhang.
Bild 7.5·
CallbackMechanismus
remote
Publisher
send (msg)
MessageManager
Li ste der entfemten Referenzen
auf die Me s s a g eListe n e r -Obje kte der
Subsenbor
MessageServer
onMessage (msg )
MessageListener
setMessage Listene r(
Li s t.ener )
Subscriber
r e mov eMe s s a g eLi s t e n er (
li s t e n er )
Wir implementieren zunächst den RMI-Server. Das Vector-Objekt
1i steners ist die Liste, die die entfernten Referenzen auf die
MessageLi stener-Objekte der Abonnenten verwaltet, Die Methode
send ruft für jede in der Liste gespeicherte Referenz die entfernte
MessageLi stener-Methode onMessage auf. Wird hierbei (z. B. aufgrund des Abbruchs eines Subscribers) eine Remote Excepti on
ausgelöst, so wird die entsprechende Referenz aus der Liste entfernt.
Ein Thread gibt alle 5 Sekunden die Anzahl der Abonnenten am
Bildschirm aus.
MessageManagerImpl
l mport java. rmi .RemoteExceptl cn:
l mport java. rmi .server. um castRemoteObj ect;
l mport java.utll .Vector;
publlC class Mess ageManagerI mpl extends UnlcastRemoteObject
lmpl ements Mess ageManager {
7.5 Callbacks
271
prl vate Vector<MessageLlstener> llsteners;
public MessageManager lmpl() throws RemoteException
llsteners = new Vector<MessageLlstener>();
new ControlThread().start();
publlC vOl d setMessageLlstener(MessageLlstener llstener)
throws Remote Exceptlon
listeners.add(listener);
publlC vOld remove MessageLlstener( MessageLlstener llstener)
throws Remote Exception (
llsteners.remove(llstener);
publlC synchronlzed vOld send( Message msg)
t hrows Remote Exception {
for (int i ~ listeners.size()
I; i >~ 0; i--) {
MessageL l stener llstener
=
II steners. get (l );
try (
llstener.onMessage(msg);
catch (RemoteException e) (
llsteners.remove(llstener);
private class ControlThread extends Thread (
public void run() {
wh i 1e (true) {
try (
Thread .s l eep(5000) ;
catch (Inter rupted Exception e ) {
System. out. pri nt 1n("Anzah1 Subscri bcrs :
+ llsteners.slze());
lmport ja va.rml .Namlng;
lmport java.rml . Remote;
publlC class MessageServer {
public static void main(String args[]) throws Except i on {
MessageSeroer
7
272
Remote remote
=
Entfernter Methodenaufruf mit RMI
new MessageManager Impl();
Naml ng. rebi nd (" rressage", re lTDte);
System. out. pri nt l n( "MessageSer ver gestartet ... ");
Nun implementieren wir Publisber und Subscriber.
Publisher
i mpor t java.rmi .Naming;
public class Publish er (
public static voi d main(String args[]) throws Except i on
i f (args.length !- 2) (
System. err .println("java Publ i s her <hast> <text>");
System.exit(l);
String host
Stri ng tex t
args[O];
args[l] ;
MessageManager manager = (MessageManager) Nami ng
.lookup("/I" + host + "/message");
Message msg = new Message();
msg.setTi mestamp(System.currentTi meMillis());
msg.setText(text);
manager .send(msg);
MessageListener-
Impl
import
import
import
import
ja va
ja va
ja va
ja va
rmi .RemoteExcepti on;
rmi .server.UnicastRemoteObject;
text.SimpleDateFormat;
util.Date;
public class Mess ageLi st enerI mpl extends UnicastRemoteObject
implements Mess ageLl st ener {
prlv at e SlmpleDateFormat formatter;
publ i c Mess ageLi st enerl mpl ( ) throws Remote Exception (
formatt er = new Slmpl eDateFormat(
" E. MMM d , yyyy HH ;mm ;ss z");
publlC vOld onMessage(Message msg) t hrows Remote Exceptlon
Strlng tl mestamp = formatter.format(new Date(msg
.getTimestamp ())) ;
7.5 Callbacks
273
System.out println (timestamp);
System.out print ln(msg.getText());
lmport ja va.rml .Namlng;
Subscriber
public class Subscriber (
public static void main(String args[J) throws Except i on {
if (args .length !- 2) (
System.err.prlntln ("ja va Subscrlber <hast> <mlllls>");
System. exi t (1) ;
String host - args[OJ;
int millis - Int eger .parsel nt (args [l J ) ;
Mess ageManager manager = (MessageManager) Namlng
.lookup("/I" + host + "/ rressage");
Mess ageL l stener llstener = new MessageLl stener Imp1( ) ;
manager.setMessageLlstener(llstener);
try (
Thread.sleep(millis) ;
catch (Interrupted Exception e) (
manager.remove MessageLlstener(llstener);
System .exi t( 0) ;
Der Subscriber wird nach einer vorgegebenen Anzahl Millisekunden beendet.
Aufruf von Registry und Server:
start /0 bin rmiregistry
start ja va -cp bin MessageServer
Aufruf zweier Abonnenten:
start java -cp bin Subscriber localhos t 30000
start java -cp bin Subscriber localhost 30000
Aufruf eines Publishers:
java -cp bin Publisher localhost "Das ist ein Test"
Test
7
274
7.6
Entfemter Methodenaufruf mit RMI
Exkurs: RMI mit 1I0P
CORBA
CORBA (Common Object Reqnest Broker Arcbitecturei, eine Spezifikation der Object Management Group (OMG), stellt eine
Kommunikations- und Dienstinfrastruktur für verteilte objektorientierte Anwendungen bereit Die Methodenaufrufe sind spracbunabbängig, d. h. Client und Server können mit unterschiedlichen Programmiersprachen implementiert werden. Schnittstellen
werden mit der speziellen Beschreibungssprache IDL (Interface
Definition Language) unabhängig von der Implementierungssprache definiert, Im Vergleich zu RMI ist CORBA jedoch komplizierter und aufwändiger in der Umsetzung.
IIOP
CORBA nutzt das Kommunikationsprotokoll IIOP (Internet InterORB Protocol) auf der Basis von TCP/IP,
Neben dem Protokoll JRMP für eine reine Java-Umgebung (siehe
Kapitel 7,1) unterstützt RMI auch IIOP (Java RMI over IIOF) und
hat damit Zugang zu anderen CORBA-Anwendungen, Enterprise
javaBeans (EjB) der Plattform Java EE kommunizieren in der
Regel über RMI!IIOP ,
Programm 7.7
Im Folgenden wird gezeigt, wie eine einfache verteilte Anwendung auf der Basis von RMI mit IIOP implementiert werden
kann, Analog zur RMI-Registry wird hier ein IIOP-fähiger Namensdienst, der vom Object Request Broker Daemon (orbd) angeboten wird, eingesetzt.
Interface
l mport ja va rmi . Remote;
lmport ja va rml.RemoteExceptlon;
LagerSeroice
publlC lnterface LagerServlce extends Remote {
Lager getLager(String id) throws RemoteException;
Zu einer Artikelnummer id liefert die Methode getLager das zugehörige Lager-Objekt Die Klasse Lager muss das Interface java.
l o. Serl al i zabl e implementieren.
Die Klasse Lager
lmport ja va lO.Ser ializabl e;
import ja va util.Date;
publ ic class Lager implements Serializable {
prlvate Strlng ld;
prlv ate lnt bestand;
prlv ate Date datum;
7.6
Exkurs, RMI mit IIOP
275
pub1i c Lager(Stri ng i d , i nt bestand. Dat e datum) (
this.id ~ i d ;
this.bestand ~ bestand;
this.datum ~ datum;
public Str ing get ld()
return l d:
public voi d set ld(String id) (
this.id~id;
pub1i c i nt get Bestand()
return bestand;
public void setBestand(int bestand)
this.bestand ~ bestand ;
publ ic Date getDatum()
return datum;
public voi d setDatum(Date datum)
this.datum ~ datum;
lmport java.rmi.RemoteException;
import java.utll.Date;
import java.util. Hashtable;
import j avax. rmi . Portabl eRemoteObj ect;
public class LagerService lmpl ext ends PortableRemoteObject
implements LagerService {
pri vate Hashtable<String . Lager> table;
public LagerService lmpl() throws RemoteException
table ~ new Hashtable<String. Lager>() ;
Date datum ~ new Date();
Lager[] list ~ new Lager[] (
newLager(" 471I". 100. dat um).
new Lager("4712". 80. datum).
new Lager("4713". 55. datum) l:
Implementierung
LagerServicelmpl
7
276
Entfernter Methodenaufruf mit RMI
f or (int i ~ 0; i < 1ist.length; i++)
tab le. put(l ist[i] .getld(). 1i st[i]);
public Lager getLager(String id) throws RemoteException (
return table.get(id);
Da Client und Server über IIOP kommunizieren sollen, muss
die Klasse von j avax. rmi . Portab1eRemoteObject abgeleitet werden.
Der Server
LagerServer
lmport javax.namlng Context;
lmport javax.namlng. InitialContext;
public class LagerSer ver (
publ i c static void ma in(String args[]) throws Except i on
LagerSer vice service = new LagerSer vice Impl ();
// Referenz im Naming Service mit JND I veröffentli chen
~ new Ini t i al Cont ext () ;
Context ctx
ctx. rebi nd( "LagerServi ce". servi ce) ;
System. out. printl n("LagerServer gestartet ... ");
Das Programm erzeugt ein Service-Objekt und meldet dieses
beim Namensdienst an. Auf den Namensdienst wird mit Hilfe des
API JNDI (Java Naming and Directory Interface) zugegriffen.
Hierzu werden das Interface Context und die Klasse
Ini t i al Context, beide aus dem Paket j avax. nami ng, genutzt. Der
Service wird unter dem Namen "LagerServl ce" eingetragen. Konkrete Angaben zum gewählten Namensdienst werden beim Aufruf des Programms über Properties eingestellt (siehe unten).
Der Client
LagetClient
lmport ja vax.namlng.Context;
lmport ja vax.namlng. InltlalContext;
lmport ja vax.rml .Portabl eRemoteObject;
public class LagerCl ient (
public static voi d main(String args[]) throws Exception
if (args.length !~ I ) (
System.err.prlntln("java LagerCllent <td>"):
System.exit(l);
7.6
Exkurs, RMI mit IIOP
String id
~
277
args[O];
// Referenz vom Namlng Service mit JNDI erfragen
Context ctx ~ new InitialContext();
Object objref ~ ctx.lookup("LagerService");
// Referenz casten
LagerService service = (LagerServlee) PortableRemoteObject
.narrow(objref, LagerService.class);
Lager lager
=
service getLager(id);
if (lager ~~ null) (
System. out. pri nt 1n("Lager ni cht vorhanden");
else (
System.out println(lager getld());
System.out println(lager getßestand());
System.out println(lager getOatum());
Der Client kontaktiert den Namensdienst und erfragt mit
lookup das als "LagerServi ce" registrierte Service-Objekt. Die gelieferte Referenz muss mit narrow auf den entsprechenden Interface-Typ "gecastet" werden.
Nach Compilierung der Sourcen mit javac müssen mit rmic ein Compiliemng
Stub und eine so genannte Tie-Klasse generiert werden:
rmic -classpath bin -d bin -iiop LagerServiceImpl
Mit Hilfe der zusätzlichen Option - i dl können nach Bedarf auch
die IDL-Beschreibungen zum Interface erzeugt werden.
Der Namensdienst wird wie folgt auf Port 50000 gestartet
start orbd -ORBlniti al Port 50000
Namensdienst
starten
start java -cp bln LagerServer
Start des Servers
Die im bin-Verzeichnis abgelegte Datei jndi.properties enthält
den Namen der JNDI-Treiberklasse für den Namensdienst sowie
dessen URL,
java. nami ng.factory. i ni t i al =com. s un .j ndi .cosnami ng.CNCtxF actory
java.naming.provider.url=iiop://localhost:50000
7
278
Statt des Client
Entfemter Methodenaufruf mit RMI
java -cp bin LagerCl ient 4711
Hier werden auch die Angaben in der Datei jndi.properties genutzt. Befinden sich Client und Server auf unterschiedlichen
Rechnern im Netz, muss beim Client l ocal hast durch den Hostnamen bzw. die IP-Adresse des Servers ersetzt werden.
Zur Ausführung werden die folgenden Bytecode-Dateien benötigt:
Lager. cl ass, LagerServl ce cl ass, LagerCll ent . cl ass und
LagerSer Vlce_Stub class.
7.7
1.
Aufgaben
Programmieren Sie einen RMI-Dienst, dessen entfernte Methode
Str ing getDayti me()
die aktuelle Systemzeit des Servers liefert.
2.
Aus einer Bücher-Datenbank sollen zu einer vorgegebenen
Buchnummer Angaben zum Buch (Autor und Titel) über
SQL abgefragt werden. Entwickeln Sie einen RMI-Dienst
(inkl, Server) mit der Methode
Buch get Buch (int id)
und einen Client, der diese entfemte Methode aufruft.
Die Klasse Buch soll die Angaben zum Buch als Attribute mit
den entsprechenden set- und get-Methoden enthalten (vgI.
auch Aufgabe 5 in Kapitel 4).
3.
Erstellen Sie für den RMI-Server aus Kapitel 7.4 einen neuen
AgenlRn. der zu einer vorgegebenen Zahl n die Fakultät n!
ermittelt. Zur Berechnung kann die Klasse java. math.
Blg Integer genutzt werden.
4.
Programmieren Sie ein Applet, das als Subscriber im Rahmen von Programm 7.6 Nachrichten in einer Textfläche
(JTextArea) anzeigt. Hierzu muss ~ s s a g e L l stener Imp laus
Programm 7.6 so angepasst werden, dass die Ausgabe in
der Textfläche erscheint.
5.
Entwickeln Sie nach der Vorlage in Kapitel 4.5 (Programm
4.3) ein auf RMI basierendes Chat-Programm RMI-Server.
RMI-Client (als eigenständige Applikation und als Applet),
Der Client soll die gleiche Anwendungsfunktionalität und
Benutzungsoberfläche haben wie das in Kapitel 4.5 entwickelte Programm. Nutzen Sie den Callback-Mechanismus.
7.7
Aufgaben
6.
Erstellen Sie einen universellen RMI-Server (Multi Ser ver).
der mehrere Dienste gleichzeitig anbieten kann. Zur Laufzeit
sollen bestehende Dienste beendet und neue Dienste hinzugefügt werden können. Ebenso soll der Server kontrolliert
beendet werden können.
279
Der Server soll das Interface Multi ServerManager mit den folgenden Methoden implementieren:
voi d shutdo wn ()
vOl d reconflgure()
Die neu hinzuzufügenden Dienste sind in einer Textdatei in
folgender Form (Beispiel) gespeichert
echo
daytime
Echol mp1
Oayti me lmpl
Jede Zeile entspricht einem Dienst. Sie enthält den Dienstnamen und den Namen der Klasse, die den Dienst erbringt.
Diese Datei ist bei der Rekonfiguration einzulesen.
Für jeden Eintrag soll mittels Reflection (Nutzung der Cl assMethoden forName und new Instance) ein neues entferntes
Objekt erzeugt und bei der Registry angemeldet werden.
Des Weiteren ist ein Client MultlServerManagerCll ent zu
erstellen. der den Aufruf der Methoden s hutdown und
reconf l gure ermöglicht.
Herunterladen