RMI-Doku09-05

Werbung
Stand: 09.2005
Praktikum Rechnernetze
Praktikumsversuch Remote Method Invocation (java.rmi)
- verteilter Methodenaufruf mit RMI –
Praktikumsdokumentation
-1-
Stand: 09.2005
1
Einführung .................................................................................................................... - 3 -
2
Grundlagen ................................................................................................................... - 3 2.1
2.1.1
Stub................................................................................................................. - 4 -
2.1.2
Remote Refence Layer ................................................................................... - 4 -
2.1.3
Transport Layer .............................................................................................. - 5 -
2.2
4
5
Aufbau und Ablauf einer RMI-Anwendung...................................................... - 5 -
2.2.1
Bestandteile der Anwendung ......................................................................... - 5 -
2.2.2
Ablauf von RMI ............................................................................................. - 5 -
2.3
3
RMI-Architektur .................................................................................................. - 4 -
Besonderheiten von Java-RMI ............................................................................ - 6 -
2.3.1
Parameterübergabe ......................................................................................... - 6 -
2.3.2
Dynamisches Laden von Klassen ................................................................... - 7 -
RMI-Beispiel ................................................................................................................. - 8 3.1
Interface ................................................................................................................ - 8 -
3.2
Implementierung (MultiplyImpl.java) ............................................................... - 8 -
3.3
Generierung des Stubs ......................................................................................... - 9 -
3.4
Implementierung von Server und Client ........................................................... - 9 -
3.5
Ausführen der Anwendung ............................................................................... - 11 -
Der Versuch ................................................................................................................ - 12 4.1
Versuchsbeschreibung ....................................................................................... - 12 -
4.2
Starten des Versuchs .......................................................................................... - 14 -
4.3
Sicherung der Versuchsergebnisse ................................................................... - 14 -
Literatur ...................................................................................................................... - 15 -
-2-
Stand: 09.2005
1 Einführung
Der Wunsch, Funktionalitäten und Ressourcen auf einem entfernten Rechner zu nutzen ist die
Grundmotivation für den Einsatz von Computernetzwerken. Während der letzten Jahrzehnte
wurden zahlreiche Möglichkeiten entwickelt, um diesen Wunsch auf möglichst einfache und
effiziente Art zu erfüllen. Einer der erfolgreicheren Lösungsansätze ist der Remote Procedure
Call (RPC), der es dem Anwendungsentwickler ermöglicht, einen entfernten Prozeduraufruf
ähnlich zu einem lokalen Aufruf durchzuführen. Maßgebliche Innovation war hierbei die
Abstraktion von der tatsächlichen Netzwerkübertragung, wie sie z.B. bei der SocketProgrammierung nicht erreicht wird.
Dennoch weist der RPC einige Nachteile auf, die aus seinem Wesen als prozedurales Modell
resultieren. Hervorzuheben sind hier vor allem die mangelnde Möglichkeit der Migration von
Logik zwischen verschiedenen Rechnern oder die strenge Client-/Serversemantik, die
teilweise zu einem unflexiblen System führen.
Mit der allgemein zunehmenden Bedeutung der Objektorientierung wurde das Konzept, auf
dem der RPC basiert in die Welt der Objektorientierung übertragen. Remote Method
Invocation RMI ist dabei der Java-Mechanismus, der den Aufruf einer Methode eines
entfernten Objektes ermöglicht. Somit stellt RMI die Erweiterung des klassischen
Client/Server-Modell auf ein verteiltes objektorientiertes Modell dar. Dabei beseitigt es die
angedeuteten Schwächen und bildet somit die Grundlage zum Design flexibler, verteilter
Systeme auf Basis der Objektkommunikation.
Die grundlegende Funktionsweise von RMI soll in der Folge beschrieben und an einem
Beispiel praktisch dargestellt werden.
2 Grundlagen
Abbildung 1: RMI-Architektur
-3-
Stand: 09.2005
2.1
RMI-Architektur
Das Hauptdesignziel von RMI war die Trennung der Beschreibung eines Verhaltens
(Interface) von der eigentlichen Implementierung dieses Verhaltens. Auf diese Weise ist es
möglich, Teile der Logik auf einem entfernten Rechner bzw. genauer in einer anderen Java
Virtual Machine (JVM) auszuführen. Ein Client-Programm erhält durch das Interface nur
die Information, wie eine bestimmte Methode eines Objektes zu verwenden ist. Die
eigentliche Ausführung dieser Methode bleibt ihm allerdings verborgen. Das ClientProgramm soll von dem, was wirklich bei dem Aufruf auf einem entfernten Objekt
geschieht, möglichst wenig erfahren. Aus seiner Perspektive soll der gesamte Ablauf
vielmehr wie ein Methodenaufruf eines lokalen Objektes aussehen. Um die Details der
Kommunikation kümmern sich die drei Schichten des RMI-Systems: der Stub, die Remote
Reference Layer und die Transport Layer.
2.1.1 Stub
Damit die Methodenaufrufe auf einem entfernten Objekt nicht ins Leere verlaufen, müssen
sie abgefangen und an ein reales, entferntes Objekt weitergeleitet werden. Dafür ist der
Stub verantwortlich. Er ist ein Stellvertreter (Proxy) der eigentlichen Implementierung
einer Klasse, der die genaue Aufrufsemantik beschreibt. Somit ist also eine Referenz eines
Clients auf ein entferntes Objekt zunächst nichts anderes, als eine Referenz auf einen
lokalen Stub. Ruft ein Client-Programm eine entfernte Methode auf, so leitet der Stub
diesen Aufruf weiter, indem er auf einem RemoteRef-Objekt die so genannte invokeMethode unter Angabe der entfernten Methode verwendet. Des Weiteren sorgt er für die
Umwandlung der Parameter in ein sequentielles Format (Marshalling), so dass sie
daraufhin über ein Netzwerk übertragen werden können bzw. für die Regeneration der
Objekte aus diesem Format (Unmarshalling). Nachdem die Parameter übergeben wurden,
wartet der Stub auf das Ergebnis, das er dann an den Aufrufer zurückliefert. Diese
Stellvertreter können automatisch aus der Klasse des entfernten Objektes unter
Verwendung eines Hilfsprogramms generiert werden, so dass sich ihre Implementierung
aus dem Verantwortungsbereich des Programmierers entzieht.
In der ersten Version von Java-RMI (JDK 1.1) existierte auf Server-Seite zum Stub ein
direktes Gegenstück, das Skeleton. Dieses war dazu gedacht, die Kommunikation mit dem
Stub durchzuführen. Seit dem JDK 1.2 wird allerdings eine erweiterte Version des Java
Remote Method Protocol (JRMP) verwendet, welche das Skeleton überflüssig macht.
2.1.2 Remote Refence Layer
Eine weitere wichtige Aufgabe auf dem Weg von entfernter Objektreferenz auf Clientseite
zur realen Objektimplementierung auf Serverseite ist die Verwaltung solcher Referenzen.
Wie bereits erwähnt wurde, setzt der Stub den entfernten Methoden-Aufruf auf den Aufruf
der invoke-Methode des RemoteRef-Objektes um und gibt dabei als Parameter die
Bezeichnung der entfernten Methode an. Dieses RemoteRef-Objekt wird von der
RemoteReference Layer zur Verfügung gestellt und dient der Anpassung einer lokalen
Aufrufsemantik an die Aufrufsemantik einer entfernten Methode.
Mit dem Java 2 SDK wurde die Remote Reference Layer um neue Formen des Aufrufs
erweitert. Nun ist es beispielsweise möglich, nicht nur einfache Unicast-Anfragen per RMI
zu stellen, sondern mehrere Objekte per Multicast anzusprechen oder entfernte Objekte erst
-4-
Stand: 09.2005
bei Bedarf zu aktivieren.
2.1.3 Transport Layer
Die unterste Schicht der RMI-Architektur, die Transport Layer, kümmert sich um die
eigentliche Verbindung und Datenübertragung zwischen den beteiligten JVMs. Bei der
Netzwerkverbindung handelt es sich bevorzugt um TCP/IP. Darauf aufbauend kommt
häufig das Java Remote Method Protocol zum Einsatz, das sich um die
Kommunikationsdetails kümmert. Eine Alternative dazu stellt RMI-IIOP dar, durch das
eine Integration von Java-RMI in Corba erzielt wird.
2.2
Aufbau und Ablauf einer RMI-Anwendung
Mittlerweile existiert eine Vielzahl von Optionen, wie RMI im Detail eingesetzt und an
spezifische Anforderungen angepasst werden kann. Nachfolgend werden die
grundlegenden Bestandteile einer Anwendung auf Basis von RMI beschrieben und der
Kommunikationsablauf abstrakt dargestellt. Anhand eines Beispiels erfolgt im nächsten
Abschnitt dann die Demonstration des Vorgehens bei der Anwendungsentwicklung.
2.2.1 Bestandteile der Anwendung
Durch die klare Trennung von Beschreibung eines Verhaltens und dessen Implementierung
ergibt sich geradezu intuitiv der Aufbau einer RMI-Anwendung.
Der Client, der nun mal selbst nicht über ein entferntes Objekt verfügt, muss wissen, wie er
eine bestimmte Methode dieses Objektes verwenden kann. Er muss also über eine
Beschreibung der Methode mit ihren Parametern und ihrem Rückgabewert verfügen.
Anstatt für diesen Zweck eine spezielle Beschreibungssprache wie z.B. IDL zu verwenden,
setzt RMI hierbei auf die Java-eigene Beschreibung durch ein einfaches Java-Interface.
Dieses Interface muss (direkt oder indirekt) von der Schnittstelle Remote erben und die
deklarierten Methoden müssen eine RemoteException werfen können, um Fehler während
der Übertragung oder entfernten Ausführung anzeigen zu können.
Auf Server-Seite ist natürlich die Implementierung der Methoden dieser Schnittstelle
notwendig. Sobald das geschehen ist, kann der Stub für diese Implementierung generiert
werden.
Nun existiert noch das Problem, dass ein Client-Programm eine Referenz auf ein entferntes
Objekt erhalten muss, um das entfernte Objekt über diese Referenz ansprechen zu können.
Die Suche nach dem Objekt geschieht mit Hilfe eines Namensdienstes, der somit
notwendiger Bestandteil der verteilten Anwendung ist.
2.2.2 Ablauf von RMI
Das definierte Ziel bei der Verwendung eines entfernten Objektes ist es, dieses wie ein
lokales Objekt behandeln zu können. In der Tat unterscheidet den entfernten
Methodenaufruf nur ein klein wenig Vorarbeit von der lokalen Variante. Der Ablauf ist in
der folgenden Abbildung dargestellt.
-5-
Stand: 09.2005
Abbildung 2: Ablauf von RMI
Der erste Schritt ist die Erzeugung eines entfernten Objektes und seine Anmeldung beim
Namensdienst durch das Server-Programm. Der Namensdienst kann sowohl auf dem
gleichen Rechner, wie das Server-Programm laufen oder aber sich auf einem anderen
Rechner befinden. Im einfachsten Fall handelt es sich bei diesem Dienst um einen
Assoziativspeicher, der logische Namen auf die zugehörigen Stub-Objekte abbildet.
Sobald dieser Export geschehen ist, kann ein Client eine Anfrage nach einem bestimmten
Objekt durch die Angabe des logischen Namens formulieren. Die Adresse des
Namendienstes muss dem Client dazu natürlich bekannt sein. Als Rückgabe seiner Anfrage
erhält der Client das gewünschte Stellvertreterobjekt.
Im dritten Schritt kann der Client analog zu lokalen Aufrufen nun Methoden auf dem
entfernten Objekt aufrufen. Diese Aufrufe fließen durch das RMI-System, werden über das
Netzwerk zum Server übertragen, dort entgegen genommen und ausgeführt. Im letzten
Schritt versendet der Server auf gleichem Wege die Rückgabe, die dann vom ClientProgamm entgegen genommen wird.
2.3
Besonderheiten von Java-RMI
In diesem Abschnitt soll ganz kurz auf zwei Eigenarten von RMI eingegangen werden: die
Parameterübergabe und die Möglichkeit des dynamischen (Nach-)Ladens von Klassen.
2.3.1 Parameterübergabe
Ein wichtiger Aspekt von Java-RMI wurde bis jetzt ausgelassen, der vom normalen JavaMechanismus abweicht: Die Form der Parameter- und Ergebnisübergabe. Grundlegend
unterscheidet man bei der Form der Übergabe zwischen Wertparametern (pass-by-value)
und Referenzparametern (pass-by-reference).
Bei primitiven Datentypen (boolean, byte, short, int, ...) gibt es keinerlei Unterschiede zum
lokalen Aufruf, da diese Parameter als Wertparameter übergeben werden. Sobald
allerdings Objekte ins Spiel kommen, ändert sich der Ablauf. Hierbei muss zwischen der
Übergabe lokaler Objekte und der Übergabe von entfernten Objektreferenzen differenziert
werden. Bei Java-RMI erfolgt die Übergabe eines normalen Objekts als Wertparameter,
sprich es wird eine Kopie erzeugt. Die Frage ist natürlich nun, wie eine solche Übertragung
von statten geht. Für solche Aufgaben hält Java den Mechanismus der ObjektSerialisierung bereit. Durch die Serialisierung wird ein Objekt auf ein sequenzielles
(lineares) Format abgebildet, das dann beispielsweise auf einen Datenträger gespeichert
-6-
Stand: 09.2005
oder über ein Netzwerk übertragen werden kann. Damit ein Objekt serialisierbar ist, muss
es das Interface java.io.Serializable implementieren. Leider gibt es einige
Einschränkungen, die für serialisierbare Objekte bestehen. So werden z.B. statische
Klassenvariablen nicht mit in den Datenstrom geschrieben.
Die andere Form, bei der Objekte als Parameter vorkommen, sind Referenzen auf entfernte
Objekte (Remote Objects). Diese werden grundsätzlich auch als Referenzparameter
übergeben. Dabei wird ausschließlich der Stub des entfernten Objekts übertragen.
2.3.2 Dynamisches Laden von Klassen
Bis jetzt ist davon ausgegangen worden, dass ein Objekt einer Klasse angefordert wird, die
dem Client bekannt ist. Allerdings kann auch der Fall eintreten, dass der Client plötzlich
mit Objekten zu tun bekommt, deren Klassen er nicht kennt. Man denke beispielsweise an
den einfachen Fall, dass eine entfernte Methode eine Liste zurückgibt, in der sich
unbekannte Objekte befinden. Bei einem solchen Szenario ist die Fähigkeit von RMI,
dynamisch Klasseninformationen nachzuladen notwendig. Für diesen Fall ist der
RMIClassLoader geschaffen worden, der Stellvertreter oder benötigte Klassen bei Bedarf
in die lokale JVM laden kann. Natürlich sieht diese Möglichkeit unter einem anderen Licht
betrachtet nach einem riesigen Sicherheitsloch aus, da man prinzipiell jede beliebige
Klasse übertragen könnte. Aus diesem Grund gibt es die Möglichkeit,
Sicherheitsrichtlinien zu definieren, die standardmäßig eingehalten werden und mit Hilfe
eines speziellen Sicherheitssystems (SecurityManager) angepasst werden können. Der
SecurityManager wird auch im Praktikumsversuch zum Einsatz kommen.
-7-
Stand: 09.2005
3 RMI-Beispiel
Die im vorherigen Abschnitt dargestellten theoretischen Grundlagen sollen nun anhand
eines kleinen Beispiels verdeutlicht werden. Das Ziel dieses Abschnittes ist die
Entwicklung eines verteilten Programms, bei dem ein Client mit Hilfe von RMI eine
Methode zur Multiplikation zweier Integer-Werte auf einem entfernten Objekt aufrufen
kann. Dazu ist eine Schnittstelle notwendig (Interface), die die Methode definiert, die
Implementierung dieser Methode, der Stub und natürlich ein Client- und ein ServerProgramm. Um das hier beschriebene Vorgehen wirklich zu verinnerlichen ist es das
Beste, die einzelnen Schritte selbst durchzuführen und auf einem Rechner zu testen.
3.1
Interface
Das Interface ist natürlich sehr einfach, da es im gewählten Beispiel nur eine einzige
Methode beschreibt. Wichtig ist hier, dass das Interface von Remote erbt und dass durch
die entfernte Methode eine RemoteException geworfen werden kann.
//Multiply.java
import java.rmi.*;
public interface Multiply extends Remote{
public int multiply(int a, int b) throws RemoteException;
}
3.2
Implementierung (MultiplyImpl.java)
Nachdem durch das Interface das abstrakte Verhalten der Methode beschrieben wurde,
wird das Verhalten nun implementiert. Die Implementierung muss zum einen eine
spezielle Klasse erweitern und zum anderen einen Konstruktor anbieten. Bei der hier
erweiterten Klasse handelt es sich um UnicastRemoteObject, die eine Übertragung der
Daten mittels TCP-Sockets realisiert und sich um die Anmeldung des Objektes beim RMISystem kümmert.
Hieraus entsteht ein potentielles Problem, falls aufgrund mangelnder Mehrfachvererbung
von Java eine Erweiterung von UnicastRemoteObject nicht möglich ist. In diesem Fall
muss sich ein Objekt selbst um seine Anmeldung kümmern. Das geschieht mit Hilfe der
Methode UnicastRemoteObject.exportObject(Remote).
-8-
Stand: 09.2005
//MultiplyImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class MultiplyImpl extends UnicastRemoteObject implements
Multiply{
public MultiplyImpl() throws RemoteException{}
public int multiply(int x, int y) throws RemoteException{
return x * y;
}
}
3.3
Generierung des Stubs
Wie bereits erwähnt, muss sich der Anwendungsentwickler nicht selbst um die
Generierung des Stubs kümmern. Für diese Arbeit existiert das Programm rmic (RMICompiler), das im SDK (seit Version 1.1.) enthalten ist. Es erstellt aus der bereits
übersetzten, entfernten Klasse die Datei Klassenname_Stub.class.
Falls die Anwendung für ein JDK ab Version 1.2. entwickelt werden soll muss als Option
-v1.2. angegeben werden, da hier keine Skeleton-Klasse benötigt wird. Eine weitere
interessante Option ist -keep, durch die rmic angewiesen wird, die zwischenzeitlich
erstellte Quellcodedatei des Stubs nach der Übersetzung in ein class-File nicht zu löschen.
Sich diese Datei einmal genauer anzusehen, ist sicher lohnenswert.
Somit werden im Verzeichnis, in dem sich das Projekt befindet folgende zwei Schritte
ausgeführt:
$ javac MultiplyImpl.java
$ rmic -v1.2 -keep MultiplyImpl
3.4
Implementierung von Server und Client
Im letzten Schritt hin zur fertigen Anwendung müssen nun noch ein Server- und ein ClientProgramm erstellt werden. Das Entscheidende beim Server ist, dass er den angebotenen
Dienst bei einem Namensservice unter einem bestimmten Namen anmeldet, damit dieser
von einem Client gefunden werden kann. Die Anmeldung wird durch die Methode
Naming.rebind() oder Naming.bind() erzielt. Der Unterschied der beiden Methoden liegt
darin, dass bind() im Falle eines unter dem gewählten Namen bereits vorhandenen Eintrag
eine AlreadyBoundException wirft. Will man an dieser Stelle eine Exception vermeiden,
sollte rebind() verwendet werden, was allerdings dazu führen kann, dass ein vorhandener
Eintrag überschrieben wird.
-9-
Stand: 09.2005
//Server.java
import java.rmi.*;
import java.rmi.server.*;
public class Server{
public static void main(String args[]) throws Exception{
Naming.rebind("//localhost/multiply", new MultiplyImpl());
System.out.println("MultiplyImpl wurde eingetragen.");
}
}
Soll das Objekt später wieder abgemeldet werden, so ist dies mit der Methode
Naming.unbind(String name) möglich.
Der Client ist ähnlich einfach gehalten wie der Server. Das Einzige, was an ihm vermuten
lässt, dass es sich bei dem Objekt Multiply nicht um ein lokales Objekt handelt ist, dass es
initial mit Hilfe des Namendienstes gesucht wird. Dazu dient die Methode
Naming.lookup(String name), deren Parameter im URL-Format die Lokalisierung des
Objektes ermöglicht.
//Client.java
import java.rmi.*;
public class Client{
public static void main(String args[]) throws Exception{
Multiply m=(Multiply)Naming.lookup("//localhost/multiply");
int result = m.multiply(5,2);
System.out.println(result);
}
}
Alternativ zum Aufruf von Naming.lookup() existiert die Möglichkeit, sich mittels
LocateRegistry.getRegistry(String servername) zuerst einen Verweis auf den
Namensdienst eines Servers zurückgeben zu lassen und darauf die lookup()-Methode
aufzurufen.
Der Rückgabewert der lookup()-Methode ist vom Typ Remote. Daher muss die Rückgabe
noch auf den Typ Multiply gecastet werden.
Wie man hier sieht verwendet man ein entferntes Objekt tatsächlich wie ein Lokales. Das
verdeutlicht, dass das Ziel, die Integration eines entfernten Aufrufs in die Sprache Java auf
eine sehr transparente Weise gelungen ist.
- 10 -
Stand: 09.2005
3.5
Ausführen der Anwendung
Nachdem Server und Client übersetzt wurden, soll nun die Anwendung getestet werden. Dazu
muss ein Namensdienst gestartet werden, bei dem der Server das erzeugte Objekt anmelden
kann. Ein sehr schlichter, aber für dieses Beispiel ausreichender Namensdienst ist der im SDK
enthaltene rmiregistry. Dieser läuft standardmäßig auf Port 1099, kann aber durch Angabe
eines Ports als Argument selbstverständlich auch auf anderen Ports laufen. Der Dienst kann
entweder aus dem Serverprogramm heraus mit Hilfe spezieller Methoden gestartet werden
oder aber manuell von der Kommandozeile aus.
$ start rmiregistry
$ rmiregistry &
// starten unter Windows
// starten unter Unix-Systemen
Sobald der Dienst gestartet ist kann das Programm ausgeführt werden.
$ java Server
MultiplyImpl wurde eingetragen
$ java Client
10
Wie man sieht, hat das Programm seine Aufgabe erfüllt und das richtige Ergebnis zurück
geliefert.
Soll das Beispiel auf zwei über ein Netzwerk verbundene Rechner getestet werden, so ist
anstelle des String „localhost“ in der Methode lookup() die IP-Adresse des entfernten
Rechners zu spezifizieren.
- 11 -
Stand: 09.2005
4 Der Versuch
Ausgehend von den bis hierhin geschaffenen Grundlagen soll nun der Versuch im Detail
dargestellt werden. Es handelt sich bei dem Szenario um das bereits bekannte verteilte
Flugbuchungssystem, bestehend aus einer Client- und einer Server-Anwendung. Der
Server verwaltet die vorhandenen Sitzplätze verschiedener Flüge, die von den Clients
gebucht, storniert oder angezeigt werden können. Während seiner Initialisierung legt der
Server dazu 20 Flüge (Flugnummer 1-20) an, in denen jeweils 300 Plätze (Platznummer 1300) verfügbar sind. Die Plätze 1-149 sind dabei Raucherplätze, der Rest NichtRaucherplätze.
Bei der Reservierung hat ein Client die Möglichkeit, sich entweder einen Platz frei
auszusuchen und zu reservieren, wobei hier die Angaben in Bezug auf die zusätzlichen
Wünsche (Smoker, Window) nicht berücksichtigt werden oder nach seinen
Zusatzanforderungen (Smoker, Window) zuweisen zu lassen. Für die automatische
Zuweisung wird für den gewünschten Flug als Platznummer einfach 0 angegeben.
Beim Stornieren eines Platzes muss der Name, auf den der Flug gebucht wurde mit dem
bei der Stornierung angegeben Namen übereinstimmen.
Werden Client und Server auf unterschiedlichen Rechner ausgeführt, so muss beim Aufruf
des Clients die IP-Adresse des Servers als Parameter angegeben werden.
4.1
Versuchsbeschreibung
Nach dem Entpacken der Quellcodedateien befinden sich folgende Dateien im
Zielverzeichnis:
-
-
Client-Programm: ClientApplication.java
Server-Programm: ServerApplication.java
Interface zur Definition der entfernten Methoden: Platzbuchung.java
die Klasse, die sich um die notwendige Vorarbeit des Clients für Java-RMI kümmert
und die entfernten Methoden aufruft: Platzbuchung_client.java
die Klasse, die sich um die notwendige Vorarbeit des Servers für Java-RMI kümmert
und die entfernten Methoden zur Verfügung stellt (Implementierung des Interfaces):
Platzbuchung_server.java
Klassen für den Nachrichtenaustausch, die über das Netzwerk übertragen werden
müssen: Request.java und Occupation.java
zusätzliche Klassen zur Modellierung der Datenbank: Flight.java und SeatAttr.java
Sowohl am Client-Programm, als auch am Server-Programm sind keine Änderungen
erforderlich. Beide Programme stellen eine grafische Oberfläche bereit, über die der
Nutzer die zur Verfügung stehenden Funktionalitäten verwenden kann und seinen
Eingaben entsprechende Rückmeldungen bekommt.
Ebenso sollen keine Veränderungen an den Klassen für die Datenbank (Flight.java und
SeatAttr.java) durchgeführt werden.
- 12 -
Stand: 09.2005
Folgende Erweiterungen/Implementierungen sind durchzuführen:
I. Das Interface Platzbuchung.java ist um die Beschreibung der Methoden book, storn und
bookedSeats zu erweitern. Ihre Rückgabewerte und die notwendigen Parameter können in
der (noch unvollständigen) Datei Platzbuchung_server.java nachgeschaut werden. Wichtig
ist, dass die drei Methoden die entsprechende Exception werfen können.
II. Da Objekte übergeben werden, muss ein RMISecurityManager installiert werden. Er ist
in der Methode initSever der Klasse Platzbuchung_server zu initialisieren. Seit Java 2
erwartet der RMISecurityManager die Angabe von Sicherheitsrichtlinien. Diese können
entweder systemweit angegeben werden oder aber in einer Datei spezifiziert werden, die in
z.B. das Verzeichnis abgelegt wird, in das der Versuch entpackt wurde (dieses soll im
Versuch geschehen). Eine solche Datei kann folgendermaßen aussehen:
// policy.txt
grant {
permission java.security.AllPermission;
};
Wie man anhand der Rechtevergabe vermuten kann, werden hier volle Rechte an
Jedermann vergeben. In einem Produktivsystem sollten natürlich engere Restriktionen
eingeführt werden. Für den Versuch ist die angegeben Richtlinie allerdings ausreichend.
Zur Vertiefung der Sicherheitsmechanismen des SDK ab Version 1.2 und den PolicyDateien finden sich unter [4] und [5] weiterführende Informationen.
Des Weiteren soll in der Methode initServer der Klasse Platzbuchung_server die
Registrierung des Objektes (this) beim lokalen Namensdienst durchgeführt werden. Der
Registry-Dienst wird bereits vom Server gestartet und muss somit nicht manuell gestartet
werden.
III. Die Klasse Platzbuchung_client ist um die Ermittlung des Registry-Dienstes zu
erweitern. Nachdem der Namensdienst ermittelt wurde, soll mit seiner Hilfe das entfernte
Objekt referenziert und in der Variable Server gespeichert werden.
Zudem sind in der Klasse die drei Methoden book, storn und bookedSeats zu
implemetieren. Dazu wird durch sie jeweils die Arbeit an die entsprechende Methode des
entfernten Objektes delegiert. Danach soll mit Hilfe des Aufrufs von
Application.listAnswer das Answer-Objekt (die Rückgabe der entfernten Methoden)
ausgegeben werden.
IV. Das Answer-Objekt ist zu implementieren. Das Answer-Objekt benötigt folgende
öffentliche Attribute: FlightNr (int), SeatNr (int), ErrorMsg (String), BookedSeats
(Vector), AnswerType (char). Des Weiteren werden vier statische, öffentliche Attribute
benötigt, die den angegebenen festen Wert besitzen:
- AnswOcc = 'G' (char)
- AnswOk = 'O' (char)
- 13 -
Stand: 09.2005
- AnswWarn = 'W' (char)
- AnswErr = 'E' (char)
Der Konstruktor der Klasse belegt die nicht statischen Attribute der Klasse und besitzt
folgende Parameterliste:
Answer(char answerType, int flightNr, int seatNr, String errorMsg, Vector bookedSeats).
Diese Klasse soll als Parameter übergeben werden können.
V. Die notwendigen Ergänzungen in den Klassen Request und Occupation sind
durchzuführen, damit diese als Parameter übergeben werden können.
VI. Die Stub-Klasse muss erzeugt werden. Wie bereits zuvor gesehen steht dazu das
Programm rmic zur Verfügung. Beim Aufruf von rmic sollte an die Option –v1.2 gedacht
werden.
4.2
Starten des Versuchs
Nachdem alle Dateien vervollständigt und übersetzt ($javac *.java) und die Stub-Klasse
generiert wurde ($rmic Flugbuchung_server), können Server und Client(s) gestartet
werden. Beim Server ist zu beachten, dass die angelegte Policy-Datei als Argument
angegeben wird.
Durch den Aufruf
$java -Djava.security.policy=./policy.txt ServerApplication
wird das Server-Programm gestartet.
Nun kann der/die Clients aufgerufen werden:
java ClientApplication
4.3
Sicherung der Versuchsergebnisse
Nach der vollständigen Bearbeitung des Versuchs und dem Test der richtigen Ergebnisse
sind folgende Dinge zu tun:
1. Anlegen des Ordners „LösungenRMI“ im Unterverzeichnis „Lösungen“ des eigenen
Verzeichnisses auf dem Praktikumsrechner
2. Speicherung der Dateien in diesem Verzeichnis
3. Mail mit dem Betreff „Versuch-RMI“ an [email protected] unter Angabe des
Namens, Vornamens, der Matrikelnummer und des Logins verschicken
4. Kopie der Versuchsergebnisse bis zur Ausgabe der Scheine sichern
- 14 -
Stand: 09.2005
5 Literatur
[1]
ein weiteres einführendes RMI-Programmierbeispiel:
http://java.sun.com/j2se/1.4.2/docs/guide/rmi/getstart.doc.html
[2]
Java-RMI-Spezifikation:
http://java.sun.com/j2se/1.4.2/docs/guide/rmi/spec/rmiTOC.html
[3]
umfassende Einführung:
http://java.sun.com/developer/onlineTraining/rmi/RMI.html
[4]
Erläuterungen zum SecurityManager und zu Policy-Dateien
http://java.sun.com/j2se/1.3/docs/guide/security/permissions.html
[5]
Erläuterungen zum SecurityManager und zu Policy-Dateien
http://java.sun.com/j2se/1.3/docs/guide/security/PolicyFiles.html
allgemeiner Überblick über entfernte Prozedur-/Methodenaufrufe:
Folien der Lehrveranstaltung „Distributed Systems“ zum Thema RPC und RPCErweiterungen, zu finden auf den Seiten des Lehrstuhls
- 15 -
Herunterladen