vs7.1.5

Werbung
7.1.5 Java RMI – Remote Method Invocation
(http://java.sun.com/products/jdk/rmi )
(http://java.sun.com/j2se/1.3/docs/guide/rmi )
(http://java.sun.com/docs/books/tutorial/rmi )
(http://java.sun.com/developer/onlineTraining/rmi/RMI.html )
Unterstützung von Fernaufrufen durch Bibliothekspakete
java.rmi
java.rmi.server
java.rmi.registry
und weitere . . .
RMI bietet leider nur begrenzte Verteilungsabstraktion.
vs7.1.5
1
7.1.5.1 Grundzüge der Fernaufruf-Programmierung in Java

interface Remote
Für fernaufrufbares Objekt und sein Vertreterobjekt muß
gemeinsame Schnittstelle definiert werden, die von
java.rmi.Remote erben muß, z.B.
import java.rmi.*;
interface RemoteService extends Remote {
String echo(String s) throws RemoteException;
}
Spätere Vertretererzeugung gelingt nur dann, wenn die Ausnahme
java.rmi.RemoteException vereinbart wird.
vs7.1.5
2

class UnicastRemoteObject
Klasse eines fernaufrufbaren Objekts muß von
java.rmi.server.UnicastRemoteObject erben, z.B.
import java.rmi.*;
import java.rmi.server.*;
class
Server extends UnicastRemoteObject
implements RemoteService {
public Server() throws RemoteException { } nötig!
private String memo = "";
public String echo(String s) // throws entbehrlich!
{ return memo += s; }
}
UnicastRemoteObject redefiniert die Operationen von Object
und registriert das fernaufrufbare Objekt bei der RMI-Verwaltung.
Achtung: Ein Server-Objekt kann durchaus auch lokal benutzt werden.
vs7.1.5
3

class Naming:
Namensdienst ist über statische Operationen der Klasse
java.rmi.Naming erreichbar:
public static void rebind(String name, Remote object)
throws RemoteException,
MalformedURLException // java.net
public static Remote lookup(String name)
throws NotBoundException,
RemoteException,
MalformedURLException
(weitere Operationen: bind, unbind, list )
vs7.1.5
4
Der Parameter String name ist im URL-Format anzugeben –
er identifiziert den Station und Port des Namensdienstes und
Enthält den eigentlichen Objektnamen:
[ // host [ : port ] / ] name
Adresse des Namensdienstes
Standard-Host = lokale Station
Standard-Port = 1099
Ein Namensdienst wird (unter Unix) gestartet mit
rmiregistry [ port ] &
(und sollte – wenn nicht mehr benötigt – mit kill beendet werden)
Achtung: Inhalt verändern nur lokal, Inhalt befragen auch entfernt !
vs7.1.5
5
Anbieterseitig:
Server -Objekt erzeugen und beim (lokalen) Namensdienst registrieren:
Naming.rebind("Service", new Server());
Klientenseitig:
Klient erfragt Objekt beim Namensdienst:
RemoteService s =
(RemoteService)Naming.lookup("//obelix/Service");
System.out.println(s.echo("bla");
Casting erforderlich! Es wird geprüft, ob das von lookup gelieferte
Vertreterobjekt tatsächlich die benötigte Schnittstelle implementiert.
vs7.1.5
6
7.1.5.2 Vertretererzeugung und -installation
Vertretergenerator heißt RMI Compiler und wird aufgerufen mit
rmic <ServerClass>
also z.B.
rmic Server
( - nicht mit Schnittstelle RemoteService !)
und generiert Stubs – bereits als .class -Dateien
Eingabe
Server.class
Ausgabe
Server_Stub.class (Vertreter)
Server_Skel.class (Treiber)
vs7.1.5
7
Installation der .class-Dateien:
CLASSPATH geeignet setzen!
 Beim Erzeugen des fernaufrufbaren Objekts
muss der zugehörige Treiber-Code greifbar sein.
 Beim Registrieren des fernaufrufbaren Objekts beim Namensdienst
muss auch der zugehörige Vertreter-Code greifbar sein
- denn Vertreter-Objekt samt Code (s.u. )
wird zum Namensdienst geschickt.
 Beim Erzeugen des Vertreter-Objekts beim Klienten
– als Folge der Anfrage beim Namensdienst –
muss dort der Vertreter-Code greifbar sein.
(Alternative: Namensdienst liefert Vertreter-Objekt samt Code (s.o.)
– sofern Security Manager das Herunterladen erlaubt; vgl. 7.2.4)
vs7.1.5
8
7.1.5.3 Von der Programmierung bis zur verteilten Ausführung
// Anbieter-Code Server.java
// Start mit java Server &
import java.rmi.*;
import java.rmi.server.*;
interface RemoteService extends Remote {
String echo(String s) throws RemoteException;
}
class Server extends UnicastRemoteObject
implements RemoteService {
public Server() throws RemoteException { }
private String memo = "";
public String echo(String s) { return memo += s+" "; }
public static void main(String[] arg) throws Exception {
Naming.rebind("Service", new Server());
}
} // Programm stoppt hier nicht – wegen verborgener RMI Threads
vs7.1.5
9
Übersetzen auf Server-Maschine obelix:
liefert RemoteService.class
Server.class
javac Server.java
Erzeugung der Stubs:
liefert Server_Stub.class
Server_Skel.class
rmic Server
Namensdienst einrichten (falls nicht schon vorhanden):
rmiregistry &
Server starten (er registriert sich selbst beim Namensdienst):
java Server &
vs7.1.5
10
… und hier ein Beispiel-Klient:
import java.rmi.*;
import java.io.*;
// Klienten-Code Client.java
// Start mit java Client host text
interface RemoteService extends Remote {
String echo(String s) throws RemoteException;
}
class Client {
public static void main(String[] arg) throws Exception {
RemoteService s =
(RemoteService)Naming.lookup("//"+arg[0]+"/Service");
System.out.println(s.echo(arg[1])+"\n");
System.exit(0);
}
}
Damit das Programm nicht
Fernaufrufe
wegen der RMI Threads hängenbleibt
vs7.1.5
11
Übersetzen auf irgendeiner Klienten-Maschine:
javac Client.java
Vertreter-Code bereitstellen,
Server_Stub.class ,
über Netzdateisystem oder
Dateiübertragung von Server-Maschine obelix
Klient z.B. wiederholt starten:
> java Client obelix hallo
hallo
> java Client obelix hallo
hallo hallo
> java Client obelix hallo
hallo hallo hallo
vs7.1.5
12
Alternatives Szenario mit separater Entwickler-Station:
Entwickler-Station
Klienten-Station
Anbieter-Station
> javac Server.java
> javac Client.java
> rmic Server
RemoteService.class RemoteService.class RemoteService.class
Server.class
Server.class
Client.class
Client.class
Server_Stub.class
Server_Stub.class
Server_Stub.class
Server_Skel.class
Server_Skel.class
> rmiregistry &
> java Server &
> java Client elfe bla
bla
>
vs7.1.5
13
7.1.5.4 Verweise in Fernaufruf-Parametern
Übergeben wird entweder Vertreter oder Kopie des Objekts:
 Schnittstelle des formalen Parameters erbt von Remote:
aktueller Parameter muß
(statisch) gleiche Schnittstelle implementieren,
(dynamisch) von UnicastRemoteObject erben,
andernfalls MarshalingException
 Netzverweis/Vertreterobjekt wird übergeben
vs7.1.5
14
 Schnittstelle des formalen Parameters erbt nicht von Remote:
aktueller Parameter muß
(statisch) gleiche Schnittstelle implementieren,
(dynamisch) Schnittstelle java.io.Serializable
implementieren, andernfalls MarshalingException
 Objektkopie wird übergeben
In Objekte eingebettete Verweise werden entsprechend behandelt !
Felder (arrays) und Zeichenketten (strings) sind serializable !
vs7.1.5
15
Achtung!
Wenn ein formaler Parameter einen Schnittstellentyp hat, kennt man
vom aktuellen Parameter nur diese Schnittstelle (unabhängig davon,
ob es sich um einem lokalen oder einen Fernaufruf handelt).
Wird ein fernaufrufbares UnicastRemoteObject übergeben, so weiß
man nicht, ob das Objekt tatsächlich entfernt oder aber lokal vorliegt.
Handelt es sich um ein serialisierbares Objekt, so wird in Abhängigkeit
von seiner Lage entweder eine Kopie oder das Objekt selbst geliefert!
 Die Semantik des Aufrufs ist nicht eindeutig bestimmt !
(siehe dazu auch Brose/Löhr/Spiegel: Java resists transparent distribution)
vs7.1.5
16
7.1.5.5 Aktivierbare Objekte
werden erst bei Bedarf erzeugt – allerdings nach vorangegangener
Registrierung über den RMI Daemon rmid
import java.rmi.activation.*;
class
Server extends Activatable
implements RemoteService {............
public Server(ActivationID id, MarshalledObject data)
throws RemoteException {
super(id, 0); }
}
Server.class muss bei rmid, die zugehörige Vertreterklasse beim
Namensdienst registriert werden – dafür muss ein setup-Programm
geschrieben werden.
http://java.sun.com/j2se/1.3/docs/guide/rmi/activation.html
vs7.1.5
17
Herunterladen