Übung zur Vorlesung "Einführung in Verteilte Systeme" Wintersemester 2004/05 Ulf Rerrer Thema: Java RMI Institut für Informatik Universität Paderborn Inhalt Java Remote Method Invocation RMI-Architektur! Interface-Konzept! Schichtenmodell! Registry/Naming! Anwendung! Sicherheitskonzept RMI-Programmbeispiel BankSimulation Hinweise zur Übung Zusammenfassung U. Rerrer Übung zu Verteilte Systeme 2 Java Remote Method Invocation Das RMI-Schichtenmodell RMI unterstützt verteilte Berechnungen (Objekte) in Java: Client Server Mit Hilfe von RMI kann eine virtuelle Maschine A Methoden einer anderen virtuellen Maschine B aufrufen. RMI ermöglicht das Verteilen von Objekten (und somit Funktionalitäten) zur Laufzeit. Entfernte Objekte werden entweder über eine Registrierungsstelle oder eine Referenz adressiert. Mittels Serialisierung können Objekte verschickt werden. U. Rerrer Übung zu Verteilte Systeme 3 RMI System Stub und Skeleton Schicht Remote Reference Schicht Transport Schicht Stub und Skeleton Schicht Remote Reference Schicht Die Stub und Skeleton Schicht fängt die Methodenaufrufe auf das Proxy-Objekt ab und leitet sie an das entfernte implementierte Objekt um. Die Remote Reference Schicht erzeugt die Verbindung zum Server aufgrund der Referenzen, die ein Client auf ein entferntes Objekt macht. Die Transport Schicht basiert auf der TCP/IP Schicht. U. Rerrer Übung zu Verteilte Systeme 4
Vorteile von RMI gegenüber Sockets Verwaltet Dienste Kümmert sich um Verbindungen Kein eigenes Protokoll notwendig Daten werden (fast) automatisch in transferierbare Form gebracht Strukturen der zu übertragenden Daten bleibt erhalten Code kann verschickt werden Integriert sich einfach in das von Java bekannte Objektmodell (verteilte Objekte) RMI Workflow Ein Server erstellt die verteilten Objekte. Die Clients greifen auf die Methoden dieser Objekte zu. RMI kümmert sich um die Aufrufe und die Rückgabe der Ergebnisse (z.b. auch Exceptions). Damit ein Client einen Server finden kann, wird eine Registrierungsstelle (rmiregistry) eingesetzt. Ein Server registriert sich dort. Ein Client fragt dort nach dem Objekt. Der Client bekommt das Objekt und arbeitet darauf. U. Rerrer Übung zu Verteilte Systeme 5 U. Rerrer Übung zu Verteilte Systeme 6 Registry Server implementiert Objekt und exportiert es an RMI RMI registriert dieses unter offiziellem Namen Client erhält Zugang zur Registry via Naming-Klasse! bind(), rebind(): registriert Objekt in Registry! unbind(): entfernt Eintrag in Registry! lookup(): sucht Eintrag in Registry lookup() benötigt Namen und IP-Adresse des Objektes und bekommt eine Referenz auf das Objekt zurück. Die rmiregistry ist "flach" " keine Hierarchie! Registrierte Namen sind eindeutig, Mehrfachvergebung nicht gestattet. Standardport ist 1099 Naming Klasse java.rmi.naming Stellt Zugriff auf entfernte RMI-Registry mittels URL-Form bereit. Zugriff: [rmi:][//][host][port:]/name! rmi: Protokoll! host: Host auf dem dir Registry läuft! port: Standard ist 1099! name: Name des Objektes in der Registry Beispiel: Naming.bind("Name", RemoteObject); U. Rerrer Übung zu Verteilte Systeme 7 U. Rerrer Übung zu Verteilte Systeme 8
Interface-Konzept Ist Basis der entfernten Objektaufrufe. Client muss das Verhalten bzw. die Fähigkeiten des entfernten Objektes kennen. Benutzung der Interfaces im Java-Konzept zur Trennung von Definition und Implementierung. Aufruf des real instanzierten Objektes mittels Stellvertreterklasse (proxy Klasse) " Stub-Klasse Client Programm Interface RMI Server Programm Implementation U. Rerrer Übung zu Verteilte Systeme 9 RMI Verteilte Objekte Verteilte Objekte werden in Interface Klassen beschrieben. Ein Objekt ist ein verteiltes Objekt, wenn! Es java.rmi.remote erweitert (extends).! Jede Methode wirft (throws) eine RemoteException! Die Implementierung erweitert UnicastRemoteObject Ein nicht verteiltes Objekt wird kopiert, wenn es zwischen JVMs verschickt wird. Um es zu verschicken, muss es serialisierbar sein. Ein verteiltes Objekt wird nicht kopiert, sondern nur durch einen Stummel (stub, proxy) repräsentiert. Dieser gibt vor, das Objekt (laut Definition im Interface) zu sein und leitet alle Aufrufe an das wirkliche Objekt weiter. Auf der Serverseite sorgen skeleton/dispatcher für das Empfangen der Nachrichten und die Ausführung des eigentlichen Aufrufs. U. Rerrer Übung zu Verteilte Systeme 10 RMI Rahmen Um eine RMI Anwendung zu erstellen und verteilte Objekte zu nutzen muss man: Ein Interface, welches die Funktionalitäten der verteilten Objekte beschreibt erstellen. Die Funktionalitäten implementieren. Die stubs/skeletons erzeugen. Einen Server schreiben, der das verteilte Objekt erzeugt, es registriert und verwaltet. Einen Client schreiben, der das verteilte Objekt bei der Registrierung anfordert und dann benutzt. Die Registrierstelle, den Server und den Client starten. Sicherheitskonzept Seit Java2 existiert ein umfangreiches policy-basiertes Sicherheitskonzept (näheres in JavaDoku [6]) Ermöglicht sehr fein einstellbare Zugriffssteuerung Von außen konfigurierbar Sicherheitsmodell aktiviert durch Installation eines security managers System.setSecurityManager(new RMISecurityManager()); Policy ist Datei mit Zugriffsrechten, die bei bei Ausführung angegeben wird: grant permission java.net.socketpermission "*:1024-65535", "connect,accept"; permission java.net.socketpermission "*:80", "connect"; ; U. Rerrer Übung zu Verteilte Systeme 11 U. Rerrer Übung zu Verteilte Systeme 12
Compilieren und Ausführen 1. Erzeugung und Kompilierung eines Interfaces: javac Hello.java 2. Erzeugung und Kompilierung eines Servers: javac HelloImpl.java 3. Erzeugung der Stubs und Skeletons der Interface-Implementierung: rmic HelloImpl 4. Setzen des CLASSPATHs: set CLASSPATH=C:\Source\VS\rmi;%CLASSPATH% bzw. export CLASSPATH=~/source/vs/rmi;$CLASSPATH 5. Starten der RMI-Registry: rmiregistry & 6. Erzeugung einer Policy: java.policy 7. Starten des Servers: java Djava.security.policy=java.policy HelloImpl & 8. Erzeugung und Kompilierung eines Clients: javac HelloClient.java 9. Starten des Clients: java Djava.security.policy=java.policy HelloClient RMI-Beispiel: Bank-Simulation (1) anhand eines großen Beispiels soll die Funktionsweise von RMI näher erläutert werden wir programmieren eine Bank-Anwendung die! ein Interface bereitstellt! deren Implementierung ein RemoteObjekt bietet mit Funktionen: # ein Konto öffnen # ein Konto schließen # Geld verbuchen # Geld abbuchen # Kontostand anzeigen # vergangene Transaktionen anzeigen! ein Server der dieses Objekt bereitstellt! ein Client der das entfernt Objekt benutzt U. Rerrer Übung zu Verteilte Systeme 13 U. Rerrer Übung zu Verteilte Systeme 14 import java.util.*; Bank-Simulation (2) Interface: RemoteBank.java public interface RemoteBank extends Remote //öffnet ein neues Konto, mit angegebenen Namen und Passwort public void openaccount(string name, String password) throws RemoteException, BankingException; //Schliesst das angegebene Konto public Money closeaccount(string name, String password) throws RemoteException, BankingException; //... Objekte von RemoteBank sollen verteilt sein, also Remote erweitern. Alle Methoden eines verteilten Objektes müssen RemoteException werfen können (falls Kommunikationsfehler auftreten). Alle Rückgabewerte und Parameter müssen serialisiertbar sein (erweitern java.io.serializable) U. Rerrer Übung zu Verteilte Systeme 15 Bank-Simulation (3) Impl.: RemoteBankService.java import java.rmi.server.*; import java.util.*; //diese Klasse implementiert das RemoteBank-Interface public class RemoteBankService extends UnicastRemoteObject implements RemoteBank //eine verschachtelte Klasse, die das Bankkonto repräsentiert class Account String password; //Passwort int balance; //Kontostand Vector transactions = new Vector(); //Konto Transaktionen Account(String password) this.password = password; transactions.addelement("account opened at " + new Date()); Fortsetzung siehe nächste Folie Da RemoteBankService ein verteiltes Objekt ist, muss es UnicastRemoteObject erweitern und die Struktur aus RemoteBank realisieren (um entfernte Aufrufe annehmen zu können). U. Rerrer Übung zu Verteilte Systeme 16
Bank-Simulation (4) Impl.: RemoteBankService.java Fortsetzung... //dieser Hashtable verwaltet alle Konten. Hashtable accounts = new Hashtable(); //trivialer Konstruktor (notwendig wegen Exceptions) public RemoteBankService() throws RemoteException super(); //öffnet ein Bankkonto mit Namen und Passwort. (thread-safe!) public synchronized void openaccount(string name, String password) throws RemoteException, BankingException //prüfen, ob Konto bereits existiert... if (accounts.get(name)!= null) throw new BankingException("Account already exists."); //wenn nicht... erzeugen Account acct = new Account(password); //... und es registrieren accounts.put(name, acct); //... Bank-Simulation (5) Objekte: Money.java public class Money implements java.io.serializable public int amount; public Money(int amount) this.amount = amount; Da Money ein zu übertragendes Objekt ist, muss es serialisierbar sein, also java.io.serializable erweitern. U. Rerrer Übung zu Verteilte Systeme 17 U. Rerrer Übung zu Verteilte Systeme 18 Bank-Simulation (6) Server: Server.java public class Server public static void main(string[] args) try //Erzeugung eines Objekts des implementierten Service RemoteBankService bank = new RemoteBankService(); //das Objekt an einen offiziellen Namen binden Naming.rebind("RemoteBank", bank); System.out.println("Bankserver is open for customers."); catch (Exception e) System.err.println(e); System.err.println("Usage: java Server"); System.exit(1); Das verteilte Objekt wird erzeugt und unter "RemoteBank" registriert. U. Rerrer Übung zu Verteilte Systeme 19 import java.util.*; Bank-Simulation (7) Client: Client.java public class Client public static void main(string[] args) try RemoteBank bank = (RemoteBank) Naming.lookup("rmi:///RemoteBank"); String cmd = args[0].tolowercase(); //die Benutzereingabe interpretieren if (cmd.equals("open")) //Konto eröffnen bank.openaccount(args[1], args[2]); System.out.println("Account opened."); else if (cmd.equals("close")) //Konto auflösen Money money = bank.closeaccount(args[1], args[2]); //die Einheit von Money ist money items System.out.println(money.amount + " money items returned!"); System.out.println("Thanks for banking with us."); //... Der Client holt und bearbeitet das verteilte Objekt "RemoteBank". U. Rerrer Übung zu Verteilte Systeme 20
Hinweise zur Übung Es ist ein zusammenhängendes Java-Programm zu erstellen Es ist sinnvoll Gruppen zu bilden Es sollte versucht werden die Programme außerhalb der Übung zu erstellen Die Programme werden in der Übung abgegeben! dazu werden die Programme vor Ort ausgeführt! der Quelltext ist zu zeigen! Fragen zur Funktionsweise des Programms oder Auswirkung einzelner Befehle müssen von jedem der Gruppe beantwortet werden können Literatur [1] Dokumentation zu Java: http://java.sun.com/j2se/1.4.2/docs/api/index.html [2] Guido Krüger: Javabuch, Addison-Wesley 2001, 3. Auflage http://www.javabuch.de [3] Esmond Pitt, Kathleen McNiff: java.rmi The Remote Method Invocation Guide Addison-Wesley 2001 [4] Java's Tutorial zu RMI: http://java.sun.com/docs/books/tutorial/rmi/index.html [5] JGuru RMI Tutorial: http://java.sun.com/developer/onlinetraining/rmi/ [6] Java's Security Model Guide: http://java.sun.com/docs/guide/security/index.html U. Rerrer Übung zu Verteilte Systeme 21 U. Rerrer Übung zu Verteilte Systeme 22