Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Verteilte Kommunikation oberhalb der Socket-API

Ähnliche Präsentationen


Präsentation zum Thema: "Verteilte Kommunikation oberhalb der Socket-API"—  Präsentation transkript:

1 Verteilte Kommunikation oberhalb der Socket-API
Datencodierung, Remote Procedure Calls, Verteilte Objektkommunikation, Namensdienste und Ortstranparenz Clemens Düpmeier,

2 Zunächst mal 2 Probleme Kommunikation basiert auf Nachrichtenaustausch (über Sockets) Ein grundsätzliches Problem mit Sockets ist Wir müssen Encoding / Decoding der Nachrichten definieren, dass jeder Kommunikationspartner versteht Nachrichten sollen dabei beliebig komplex sein können (i.e. auch komplexe binäre Strukturen) 2. Problem: Wir brauchen einfache, aber universell funktionierende Mechanismen an Stelle von selbst-definierten Protokollen (Abstraktion oberhalb der Protokollebene) Höherwertige Kommunikationsmechanismen stellen Lösungen für diese beiden Probleme bereit Clemens Düpmeier,

3 Übertragung komplexer binärer Daten
Clemens Düpmeier,

4 Externe Datenrepräsentation
Höherwertige Kommunikationsmechanismen nutzen ein gemeinsames Datenformat, genannt externe Datendarstellung zur transparenten Übertragung von beliebigen (binären) Daten. Notwendig wegen der Heterogenität der Umgebungen Unterschiedliche Hardwarearchitektur Verschiedene Betriebssysteme Verschiedene Programmiersprachen Unter Marshalling versteht man den Prozess der Transformation strukturierter Datenelemente und elementarer Werte in eine (mit einer Nachricht übertragbaren) externe Datendarstellung Unter Un-Marshalling versteht man den Prozess der Erstellung elementarer Werte aus ihrer externen Datendarstellung und den Wiederaufbau der ursprünglichen Datenstrukturen. Clemens Düpmeier,

5 Formen von externen Darstellungen
Sender und Empfänger sind sich über die Reihenfolge und die Typen der Datenelemente in einer Nachricht einig ISO: ASN.1 (Abstract Syntax Notation) Sun ONC (Open Network Computing)-RPC: XDR (eXternal Data Representation) Corba: IDL und CDR (Common Data Representation): CDR bildet IDL-Datentypen in Bytefolgen ab. Vollständige Informationen über Reihenfolge und die Typen der Datenelemente sind in einer Nachricht enthalten Java: Objektserialisierung, d.h. Abflachung eines (oder mehrerer) Objektes zu einem seriellen Format inkl. Informationen über die Klassen. Deserialisierung ist die Wiederherstellung eines Objektes ohne Vorwissen über die Typen der Objekte. Clemens Düpmeier,

6 Corba CDR Format Typ Darstellung Sequence
String Array Struct Enumerated Darstellung Länge gefolgt von Elementen in der angegebenen Reihenfolge Länge gefolgt von Zeichen in der angegebenen Reihenfolge Array-Elemente in der angegebenen Reihenfolge Die Reihenfolge der Deklarationen der Komponenten Unsigned Long Reihenfolge und Typen der Elemente bei Sender und Empfänger bekannt! 0–3 4–7 8–11 12–15 16–19 20-23 24–27 5 "Smit" "h___" 6 "Lond" "on__" 1934 Index in Bytefolge 4 Byte Länge der Zeichenkette “Smith” “London” unsigned int Struct Person{ string name; string place; unsigned int year; }; Smith London 1934

7 Java Objektserialisierung: vereinfacht
public class Person implements Serializable{ private String name; private String place; private int year; public Person(String aName, String aPlace, int aYear) { name = aName; place = aPlace; year = aYear; } // gefolgt von Methoden für den Zugriff auf die Instanzvariablen } Person p = new Person(„Smith“,“London“,1934); Klassenname, Versionsnummer Person 8-Byte Versionsnummer h0 java.lang.String java.lang.String Nummer, Typ und Name der Instanzvariablen 3 int year name: place: 1934 5 Smith 6 London h1 Werte der Instanzvariablen Das echte serialisierte Format enthält zusätzliche Typkennzeichner; h0 und h1 sind Handles, also Verweise auf serialisierte Objekte

8 Fazit Zuerst die schlechte Nachricht: das sieht alles ziemlich kompliziert zu implementieren aus, und das ist es auch! Die gute Nachricht: Solche externen Datendarstellungen sind schon konzipiert und implementiert und ihre Nutzung ist (insbesondere bei objektorientierten Sprachen) einfach Clemens Düpmeier,

9 Elementare Kommunikationsmuster
Clemens Düpmeier,

10 Blockierende, synchrone Interaktion
über Anfrage-Anwort (Request-Reply) Protokoll Client schickt Anfrage-Nachricht an Server Server empfängt Nachricht und führt zugehörige Aktion durch Server sendet Antwort-Nachricht an Client zurück Ausführung auf dem Client blockiert nach Schicken der Anfrage-Nachricht so lange, bis Antwort-Nachricht erhalten wurde Beide, Client und Server, müssen zur Zeit der Interaktion verfügbar sein Wenn nicht, muss durch wiederholtes Senden von Nachrichten Fehlersituation bereinigt werden Typischer Weise über Verbindungs-orientierte Sockets implementiert Punkt-zu-Punkt Verbindung Kommunikationspartner müssen direkt verbunden sein (Keine Message-Router dazwischen) Viele mögliche Fehlersituationen Clemens Düpmeier,

11 Mögliche Fehlersituationen bei Request-Reply
Client Server 1) Verlust der Auftragsnachricht 2) Verlust der Ergebnisnachricht 3) Ausfall des Servers 4) Ausfall des Clients 1) 2) 3) 4) Clemens Düpmeier,

12 at least once Semantik at most once Semantik Client Server Client
Request Request Liste der Requests Reply Request Liste der Requests über- prüfen; Verwerfen des 2. Requests Acknowledge- ment Request löschen Reply Request Bearbeitung des Requests; Request eintragen Timeout Timeout Reply Request Bearbeitung des Requests Timeout Timeout Ergebnis kann verschieden sein! Reply Request Bearbeitung des Requests Timeout Timeout Clemens Düpmeier,

13 Fehlersemantiken und Eigenschaften
Clemens Düpmeier,

14 Weiteres zur Fehlerbehandlung
Um zu verhindern, dass ein Service vorübergehend nicht verfügbar ist, kann Replizierung des Service (Serverteils) und automatische Lastverteilung und Relokation bei Fehlern eingesetzt werden Für eine "Exactly Once"-Strategie und kompliziertere Konsistenzerhaltung von Daten benötigt man Transaktionskonzept (siehe später) Clemens Düpmeier,

15 Remote Procedure Calls (RPC)
Vorläufer der Verteilten Objektkommunikationsmechanismen Clemens Düpmeier,

16 Idee für einen entfernten Prozeduraufruf
Clemens Düpmeier,

17 Remote Procedure Calls (Sun-RPC)
Realisieren entfernten Funktionsaufruf übernehmen Funktion des Anwenderprotokolls bei Socket-orientierter Kommunikation At least once Semantik (d.h. entfernter Prozeduraufruf wird mindestens 1-mal ausgeführt) synchrone Kommunikation beliebig komplexe Argument(e) und Returnwerte werden als komplexe Datenstrukturen aufgefasst und mit XDR kodiert übertragen bzw. dekodiert. Realisierungen von Funktionsaufrufen, die über Rechnergrenzen hinweg aufgerufen werden können, bezeichnet man als Remote Procedure Calls (RPC). Sie sind eng an der Semantik eines lokalen Funktionsaufrufs orientiert. Der Client soll im wesentlichen bei einem RPC Aufruf die aufzurufende RPC Funktion und ihre Parameter angeben können und wartet anschließend auf die Rückgabe des Returnwertes des RCP Aufrufs. Die Interna des RPC Aufrufs (d.h. das Anwendungsprotokoll, mit dem die Kommunikation zwischen Serverseite und Clientseite erfolgt) sind dabei vollständig intern in der RPC Schnittstelle gekapselt. Der Benutzer der RPC Aufrufe hat damit nichts mehr zu tun. Ihm bieten RPC‘s vielmehr eine „At least once“ Semantik, d.h. sie können sicher sein, das ihr Funktionsaufruf mindestens einmal auf der Serverseite ausgeführt wurde (aber Achtung hier: RPC garantiert nicht, das er genau einmal aufgerufen wurde!) Der Client wartet dabei bis der Server mit dem RPC fertig ist und gegebenenfalls einen Returnwert zurückliefert (synchrone Kommunikation). Die Übertragung der binären Daten (Parameter der Funktion und Returnwert) erfolgt bei einem RPC mit Hilfe eines über verschiedene Rechnerarchitekturen hinweg portablen Codierungsformat (bei klassischen RPC‘s im XDR (external data representation format)). Beim Aufruf des RPC müssen hierzu die entsprechenden Codierungs- und Decodierungsfunktionen mit angegebenen werden. Clemens Düpmeier,

18 Synchrone Kommunikation in RPC‘s
Client vor Aufruf Client wartet Client nach Aufruf Client RPC Aufruf RPC Return Lokale Funktion aufrufen Server Das obige Diagramm zeigt den synchronen Ablauf eines RPC Aufrufes. Nach Aufruf des RPC Aufrufes auf der Clientseite wartet der aufrufende Code auf der Clientseite bis der Server auf seiner Seite den Aufruf decodiert, dann die zugehörige lokale Funktion ausgeführt, anschließend den Returnwert codiert und dann zurück zum Client übertragen hat. Lokale Prozedur Zeit Clemens Düpmeier,

19 Registrierung von RPC Programmen
Portmap / rpcbind Client Programm Lookup 111 Registrierung RPC Server Im Gegensatz zu socket-basierten Programmen ist bei RPC Programmen dem Client die Portnummer, an dem der RPC Server seinen Dienst anbietet, nicht mehr unmittelbar bekannt. Stattdessen ist auf jedem Rechner, der RPC basierte Dienste anbietet, ein Auskunftsdienst (der portmapper oder rpcbind Prozess) in Betrieb, der es RPC Clients erlaubt, auf Grund einer Programmnummer und Versionsangabe RPC basierte Server auf diesem Rechner zu finden. Dieser Auskunftsdienst bietet seinen Service an dem speziellen Port 111 sowohl auf Basis von UDP als auch TCP an und ist ebenfalls RPC basiert. Beim Starten des Betriebssystems eines Rechners, der RPC Dienste anbietet, wird zunächst der portmap oder rpcbind Daemon gestartet. RPC Dienste, die anschließend starten, registrieren ihre Dienste durch Angabe einer RPC Programmnummer und Versionsangabe unter dem portmap oder rpcbind Daemon, wobei die intern für den Dienst verwendete Portnummer mit registriert wird. Die Clientseite führt bei einem RPC Aufruf zunächst einen Lookup des Servers beim zugehörigen Registrierungsdaemon der Zielmaschine durch, bekommt dabei intern die Portnummer des RPC Servers mitgeteil, sodass sie sich anschließend mit dem Server zur Durchführung des eigentlichen RPC Aufrufs verbinden kann. RPC Call Client System Server System Clemens Düpmeier,

20 Beispiel für RPC Server (Low Level)
#include <stdio.h> #include <rpc/rpc.h> #include <rpcsvc/rusers.h> /* lokale Funktion, die Anzahl Benutzer feststellt */ void *rusers(); main() { if (rpc_reg(RUSERSPROG,RUSERSVERS,RUSERSPROCNUM,rusers, xdr_void, xdr_u_int, /* Welche Argument hat RPC Prozedur, * was wird zurückgegeben */ "visible") == -1) /* Tranportwege = hier alle */ fprintf(stderr, "Couldn't register myself as RPC program\n"); exit(1); } svc_run(); /* Endlosschleife, * nur return, wenn durch Signal abgebrochen */ fprintf(stderr, "Programm wurde beendet\n"); Registrierung einer lokalen Prozedur im Laufzeitsystem des Servers unter Angabe von Programmnummer, Version Prozedurnummer Lokaler Funktion Parameterdecodierung Returnwertdecodierung Starten der Laufzeitinfrastruktur des Servers Laufzeitinfrastruktur registriert Programme und Prozeduren im Namensdienst Server des RUSERSPROG RPC Programms. Dieses Programm stellt eine RPC Prozedur bereit, die die Anzahl der Benutzer auf dem Rechner zurueckgibt. durch Aufruf der lokalen Funktion rusers() zurückgibt. Wir muessen dem RPC Laufzeitsystem mitteilen, welche Prozeduren wir bereitstellen. Hierzu geben wir Programmname, Version, Prozedurnummer und dann den Zeiger auf die implementierende Funktion sowie Filter zur Konvertierung nach bzw. vom XDR Format für die Argumentdaten bzw. Returnwertdaten und die Transportart in einem Aufruf von rpc_reg an. rpc_reg kann mehrfach aufgerufen werden, wenn mehr als eine Prozedur im Laufzeitsystem registriert werden soll. OK, wir können nun das Laufzeitsystem starten. Es wählt sich einen freien Serverport und registriert sich dann mit den im Laufzeitsystem registrierten Funktionen beim rpcbind (bzw. portmap). Dann wartet es auf Anfragen und ruft die registrierten Funktionen auf. Es benutzt die angegebenen Datenfilter der Funktionen, um den Datenstrom für die reinkommende Argumentstruktur bzw. für den rausgehenden Returnwert von XDR zu decodieren bzw. nach XDR zu codieren. Clemens Düpmeier,

21 Beispiel für RPC Client (Low Level)
/* einige includes */ main(argc, argv) int argc; char **argv; { unsigned int nusers; enum clnt_stat cs; if (argc != 2) { fprintf(stderr,"usage: rusers hostname\n"); exit(1); } if (cs= rpc_call(argv[1], RUSERSPROG, /* Programmnummer */ RUSERSVERS, RUSERSPROC_NUM,/* Version, Prozedur */ xdr_void, (char *)0, /* Argumente */ xdr_u_int, (char *)&nusers, /* Returnwert */ "visible") != RPC_SUCCESS) { clnt_perrno(cs); /* Gebe RPC Fehlercode auf Console aus */ fprintf(stdout, "%d users on %s\n", nusers, argv[1]); Aufruf der Prozedur unter Angabe von Hostname, Programmnr., Version Prozedurnummer Codierer + Parameter Decodierer, Variable für Returnwert Ausgabe des Wertes auf Standardausgabe Clemens Düpmeier,

22 Low Level RPC sieht wirklich hässlich aus
Problem: sieht noch nicht wirklich wie lokaler Prozeduraufruf aus Lösung hierfür ist Stub- und Skeleton Generierung Führe RPC Sprache ein, mit der RPC Aufrufe bzgl. Parameter (welche XDR Typen gehören dazu, etc.) spezifiziert werden RPC-Compiler generiert daraus lokale Funktionen XDR-Kodierungs- und Dekodierungsfunktionen Stubs für die Clientseite (sehen wie lokale Funktionen aus) Anwendungsprogrammierer benutzt nur die Stubs Skeleton für die Serverseite (Skeleton ruft normale Anwenderprozedur auf) Anwendungsprogrammierer programmiert nur Anwendungsprozeduren Stubs und Skeleton kommunizieren dann miteinander über die bereits vorgestellte Low Level RPC Schnittstelle Ähnliches Prinzip sehen wir gleich auch bei RMI und CORBA Clemens Düpmeier,

23 Bedeutung von Stubs Aufruf von Stub Stub- oder Proxy
/* einige includes */ main(argc, argv) int argc; char **argv; { unsigned int nusers; if (argc != 2) { fprintf(stderr,"usage: rusers hostname\n"); exit(1); } nusers=rusers(argv[1]); // Aufruf Stub fprintf(stdout, "%d users on %s\n", nusers, argv[1]); Bedeutung von Stubs Aufruf von Stub int rusers(char *hostnname) { if (cs= rpc_call(hostname, RUSERSPROG, /* Programmnummer */ RUSERSVERS, RUSERSPROC_NUM,/* Version, Prozedur */ xdr_void, (char *)0, /* Argumente */ xdr_u_int, (char *)&nusers, /* Returnwert */ "visible") != RPC_SUCCESS) return -1; else return cs; } Stub- oder Proxy Clemens Düpmeier,

24 Wo wird RPC eingesetzt? RPC Einsatz findet sich an vielen Stellen bei Linux und Windows Betriebssystemen Beispiele Unix / Linux NFS - Network File Sytem YP - YP / NIS Verzeichnisdienst Mount Daemon für das Mounten von Netzwerklaufwerken ... Windows - alles an Diensten, was abhängig vom RPC Dienst ist COM+ Ereignissystem (COM+ Kommunikation allgemein) Dateireplikation Distributed Transaction Dienst Druckerdienst RPC Schnittstellen stellen oftmals unbekannte Sicherheitslücken im Netz dar Clemens Düpmeier,

25 Verteilte Objektkommunikation
Remote Method Invocation ist die objektorientierte Form der RPC Technologie, die speziell für die Sprache Java entwickelt wurde. Bei dieser Technologie kann man in Java Serverobjekte mit dedizierten Interfaces (Remote Interfaces) implementieren, die ein Client dann über Rechnergrenzen hinweg benutzen kann. Clemens Düpmeier,

26 Entfernte und lokale Methodenaufrufe
entfernter Aufruf lokaler Jeder Prozess hat Objekte, einige, die entfernte Aufrufe erhalten können - entfernte Objekte genannt -, einige, die nur lokale Aufrufe erhalten können Objekte müssen die entfernte Objektreferenz eines Objektes in einem anderen Prozess kennen, um dessen Methoden aufrufen zu können. Wo bekommen sie diese Referenz her ? Die entfernte Schnittstelle spezifiziert, welche Methoden entfernt aufgerufen werden können Clemens Düpmeier,

27 Eigenschaften Verteilter Objekte
Interagierende Objekte sind auf mehr als einen Prozess verteilt Wichtige Begriffe (Auswahl, vereinfacht): Entfernte Objektreferenz: die „Adresse“/eindeutige Identität eines Objekts im ganzen verteilten System Entfernte Schnittstellen: die Schnittstelle eines entfernten Objekts (interface definition language, IDL) Ereignisse/Aktionen: Ereignisse/Aktionen von Objekten können Prozessgrenzen überschreiten Exceptions/Ausnahmen: verteilte Ausführung des Systems erweitert das Spektrum möglicher Fehler Garbage Collection: Freigabe nicht mehr benutzten Speichers wird im verteilten System schwieriger Clemens Düpmeier,

28 Entfernte Objektreferenzen
Über Raum und Zeit garantiert eindeutig! Bestehen aus Internetadresse: gibt den Rechner an Port-Nummer und Zeit: Identifizieren eindeutig den Prozess Objektnummer: Identifiziert das Objekt Schnittstelle: beschreibt die entfernte Schnittstelle des Objekts Werden erzeugt von einem speziellen Modul - dem entfernten Referenzmodul - wenn eine lokale Referenz als Argument an einen anderen Prozess übergeben wird und in dem korrespondierenden Proxy gespeichert. Achtung: Diese Art der Referenz erlaubt kein Verschieben des Objektes in einen anderen Prozess zur Laufzeit! Internetadresse Port-Nummer Zeit Objektnummer Schnittstelle des entfernten Objektes 32 bits

29 Entfernte Schnittstellen
Die entfernte Schnittstelle gibt an, wie auf entfernte Objekte zugegriffen wird (Signatur der Methodenmenge). Ihre Beschreibung enthält Den Namen der Schnittstelle Möglicherweise Datentypdefinitionen Die Signatur aller entfernt verfügbaren Methoden, bestehend aus Dem Methodennamen Ihrer Ein- und Ausgabeparameter Ihrem Rückgabewert Jede Verteilte Objektkommunikationstechnologie besitzt eine eigene Sprache, um solche Schnittstellen zu beschreiben. Clemens Düpmeier,

30 Enternte Schnittstelle: Beispiel CORBA IDL
struct Person { string name; string place; long year; } ; interface PersonList { readonly attribute string listname; void addPerson(in Person p) ; void getPerson(in string name, out Person p); long number(); }; Parameter sind in, out oder inout Signatur: Definition der Methoden CORBA hat Strukturen, Java hat Klassen entfernte Schnittstelle entfernte Schnittstelle lokaler Aufruf m1 m2 m3 m4 m5 m6 Daten Implementierung der Methoden entfernter

31 <<interface>>
Proxy Design Pattern +request() <<interface>> Subject +request() RealSubject +request() Proxy Bei Verwendung des Proxy Design Patterns bietet man einem Objekt, das ein anderes mit einer bestimmten Funktionalität (d.h. mit bestimmten Methoden, die man aufrufen kann = einem bestimmten Interface, oben Subject genannt) verwenden möchte, statt der realen Implementierung (RealSubject) ein Proxy-Objekt (Proxy) zur Verwendung an, das die gleiche Schnittstelle (interface, d.h. von Namen und Parametern und Returnwert her, die gleichen Methoden) implementiert, wie ein Objekt der realen Implementierung. Das Proxy Objekt selbst benutzt dann eine wie auch immer geartete Kommunikation mit dem realen Objekt, um mit dessen Hilfe die entsprechende Funktionalität umzusetzen, die der Client bei ihm abruft. Der Vorteil dieses Proxy Konzeptes liegt nun darin, das das Proxy Objekt bei gleichbleibender Schnittstelle für das Clientobjekt intern eine Reihe weiterer Aktionen durchführen kann (z.B. eine Protokollierung der Aufrufe, also logging, Statistikdienste, etc.). Im Fall von RMI erledigt der Proxy mit Hilfe der RMI Implementierungsklassen einen für den Client unsichtbaren und völlig transparenten Aufruf des realen Objektes über Rechnergrenzen hinweg. realSubject Clemens Düpmeier,

32 Bedeutung von Schnittstellen
Client Server Implementierung im Server Gewünschte Schnittstelle im Client Proxy Object (Stub) Skeleton Das Proxy Objekt (im Fall von RMI / Corba auch Stub Objekt genannt) kommuniziert mit der Serverseite über eine Schicht von Protokollen (im Bild gelb) mit einem Skeleton Objekt (bei älteren Implementierungen 1.1.x Java Versionen) bzw. einer Softwareschicht, die die Java Reflection API benutzt, um die vom Proxy-Objekt angeforderten Methodenaufrufe durch Aufrufe der entsprechenden serverseitigen Implementierung umzusetzen (orange dargestellt). Bei der Implementierung werden nach dem Kompilieren der Server- und Clientklassen mit dem Java Compiler durch ein spezielles RMI Tool (rmic = rmi compiler) Skeleton und Stub-Klassen erzeugt, die die Aufrufe des Serverobjektes kapseln und auf die darunterliegenden Protokollschicht abbilden. Neuere Implementierungen (rmic Compiler Option –v1.2 für Java 1.2 kompatible Stubs) nutzen die Möglichkeiten der Reflection API, um dynamisch Methodenaufrufe der Serverobjekte aus den einzelnen Informationen, die über die Protokollklassen übertragen werden, zusammenzubasteln und dann die so zusammengefügte Methode dynamisch aufzurufen (dies leistet gerade die Reflection API). Hierbei entfällt dann die Erzeugung der Skeletonklassen. Kommunikationsschnittstelle Netzwerk Clemens Düpmeier,

33 Teile einer Implementierung
Kommunikationsschnittstelle: zuständig für das Request-/Reply (Anfrage-Antwort) Protokoll Entferntes Referenzmodul: Übersetzt zwischen entfernten und lokalen Objektreferenzen; besitzt meist eine entfernte Objekt-Tabelle, in der diese Zuordnung eingetragen wird. Beim ersten Aufruf wird die entfernte Objektreferenz von diesem Modul erzeugt. Proxies und Skeletons Proxies (auch Stubs) genannt stellen Client Schnittstelle zur Verfügung Skeletons rufen serverseitige Objektimplementierung auf Clemens Düpmeier,

34 Rolle von Proxy und Skeleton
Proxy: schafft Transparenz für Client. Proxy implementiert entfernte Schnittstelle. Marshals Request und unmarshals Reply. Leitet Request weiter. Ausführung des Request/Reply Protokolls Dispatcher: wählt Methode im Skeleton aus. Objekt A Entferntes Referenzmodul Kommunikations- schnittstelle Client Proxy B Server Objekt B Dispatcher B Skeleton B Request Reply Skeleton: implementiert Methoden der entfernten Schnittstelle. Unmarshals Request und Marshals Reply. Ruft Methode in entferntem Objekt auf. Übersetzung zwischen lokalen und entfernten Objektreferenzen

35 Parameterübergabe: Referenz- und Kopiersemantik
Entfernte Methodenaufrufe sollten Parameterübergabe-Semantik der verwendeten Programmiersprache respektieren: In Java Übergabe von Werten per Kopie, Übergabe von Objekten per Referenz In C++ freie Wahl der Übergabeart Probleme: Entfernte Referenzen auf Werte prinzipiell nicht möglich Entfernte Referenzen auf Objekte nur möglich, wenn entsprechende Stubs und Skeletons existieren Empfänger benötigt Implementierungsklasse für erhaltenes Objekt (Kopiersemantik) bzw. Stub (Referenzsemantik) Clemens Düpmeier,

36 Beispiel für Parameterübergabe
Betrachte folgende Objektklasse: import B; public interface A extends Remote { public void setB(B b) throws Throwable; public B getB() throws Throwable;}} public class AServant extends UnicastRemoteObject implements A { private B b; public void setB(B b) { this.b = b; } public B getB() { return this.b; }} AServant B ASkeleton

37 Parameterübergabe: Kopiersemantik (1)
1. Clientobjekt hält Referenz auf Instanz von A, ruft darauf Methode getB() auf. 2. Stub übermittelt Methodenaufruf an Skeleton 3. Skeleton delegiert Methodenaufruf an Servant 4. Servant übergibt Referenz auf Instanz von B an Skeleton Adressraum 1 Klienten- objekt AStub Adressraum 2 AServant B ASkeleton "getB" Clemens Düpmeier,

38 Parameterübergabe: Kopiersemantik (2)
8. Stub übergibt Verweis auf neue Instanz an Aufrufer 7. Stub lädt Klasse B, dekodiert Zustand und erzeugt damit neue Instanz von B 6. Kodierter Zustand wird an Stub übertragen 5. Skeleton kodiert Zustand von Instanz gemäß Wire Protocol Adressraum 1 AStub Klienten- objekt Adressraum 2 AServant B ASkeleton codierter Zustand von B B B.jar Clemens Düpmeier,

39 Parameterübergabe: Referenzsemantik (1)
1. Clientobjekt hält Referenz auf Instanz von A, ruft darauf Methode getB() auf. 2. Stub übermittelt Methodenaufruf an Skeleton 3. Skeleton delegiert Methodenaufruf an Servant 4. Servant übergibt Referenz auf Instanz von B an Skeleton Adressraum 1 Klienten- objekt AStub Adressraum 2 AServant ASkeleton B "getB" Clemens Düpmeier,

40 Parameterübergabe: Referenzsemantik (2)
8. A-Stub übergibt Verweis auf B-Stub an Aufrufer 7. A-Stub erzeugt neuen B-Stub, der Netzwerkadresse von B-Skeleton enthält 6. A-Skeleton sendet Netzwerkadresse von B-Skeleton an A-Stub 5. A-Skeleton erzeugt neues Skeleton für B, falls nicht bereits vorhanden Adressraum 2 AServant B ASkeleton Adressraum 1 AStub Klienten- objekt (hostname, port) BStub BSkeleton B.jar Clemens Düpmeier,

41 Weitere Aspekte der Objektübergabe
Festlegung der Übergabesemantik i.A. durch Typ des formalen Parameters: Referenzen und keine Referenzen sind zunächst alles Werte! Die Übergabesemantik regelt die Art der Interpretation. Referenzübergabe, wenn formaler Parameter bestimmtes Interface (in Java RMI z.B. java.rmi.Remote) implementiert Wertübergabe sonst Bei Wertübergabe Komplikationen möglich: Wenn übergebenes Objekt direkt oder indirekt andere Objekte referenziert, müssen diese ebenfalls übergeben werden (mit welcher Übergabesemantik?) Sharing von Objekten muss auf der Clientseite rekonstruiert werden Wenn übergebenes Objekt echter Untertyp des formalen Parameters ist, ist u.U. Upcast erforderlich Was ist mit Garbage Collection von Serverobjekt, wenn Client Referenz darauf hat (siehe nächste Folie)? Clemens Düpmeier,

42 Weitere Implementierungsaspekte
Namensdienst, der Clients Objektreferenzen zunächst unabhängig von ihrer Lage vermitteln kann Parallele Abarbeitung: Um zu verhindern, dass ein entfernter Aufruf einen anderen Aufruf verzögert, weisen Server der Ausführung jeden entfernten Aufrufs einen eigenen Thread zu! Aktivierung: Automatische Erzeugung einer Instanz und Initialisierung der Instanzvariablen. Persistenter Objektspeicher: Verwaltet persistente Objekte, also Objekte, die zwischen Aktivierungen weiterbestehen. Verteiltes garbage collection: Stellt sicher, dass in einem verteilten System garbage collection durchgeführt wird. Problem: Referenzen, die nur in Nachrichten vorhanden sind. Clemens Düpmeier,

43 Fallbeispiel(e) Am Beispiel von Java Clemens Düpmeier,

44 Beispiel RMI Clemens Düpmeier,

45 RMI – Remote Method Invocation
Definiert Verteilte Objektkommunikation von Java-Objekten unabhängig von ihrem Ort Eine reine Java-Lösung Callback Funktionalität und dynamisches Laden von Code Alle entfernten Objekte müssen eine entfernte Schnittstelle definiert als Java Interface abgeleitet von java.rmi.Remote besitzen Es sind Werkzeuge für die Generierung von Stubs und Skeletons vorhanden. JDK stellt eine Implementierung eines Naming-Service zur Verfügung: die RMIregistry. Ein RMI-Dämon erlaubt eine flexible (on-demand)-Instanziierung (Aktivierung) von Objekten. Clemens Düpmeier,

46 Remote Reference Layer Remote Reference Layer
RMI Architektur Server Client Server Programm Gemeinsames Client Programm Interface Skeleton/Reflection Stubs Remote Reference Layer RMI Komponenten Remote Reference Layer Transport Layer Transport Layer Diese Folie verdeutlicht die unter der Stub-Skeleton/Reflection Schicht liegenden Protokollschichten bei RMI. Sie ist in zwei separate Schichten zerlegt: Im Remote Reference Layer, über den Stubs und Server-objekte in Beziehung zueinander gesetzt sind und Stubs Methoden auf der Serverseite aufrufen Transport Layer, der die Verbindung zwischen den virtuellen Maschinen auf Server- und Clientseite herstellt, pflegt und den Transport der Informationen (Methoden, Parameter und Returnwertinformationen übernimmt). Netzwerk Clemens Düpmeier,

47 Remote Reference Layer (RRL)
Stub benutzt RRL-API, um Methodenaufrufe auf die Serverseite zu übertragen RRL auf Serverseite benutzt Reflection oder Skeleton Objekte, um auf Serverobjekt zuzugreifen RRL unterstützt unicast Punkt-zu-Punkt Objektverbindungen und aktivierbare Objekte Andere Formen (Multicast) sind denkbar Der Stub benutzt den RRL Layer, um Methodenaufrufe auf die Serverseite zu übertragen. Der RRL Layer auf der Serverseite benutzt die Reflection API oder Skeleton Objekte, um auf das zugehörige Serverobjekt zuzugreifen. RRL unterstützt dabei unicast Punkt zu Punkt Verbindungen und aktivierbare Objekte durch seine Implementierung innerhalb der UniCastRemoteObject oder Activable Serverimplementierungsklassen. Andere Formen, wie Multicast Semantik, ist durch andere Implementierungsklassen denkbar. Clemens Düpmeier,

48 Transportlayer Stellt eigentliche Verbindung zwischen JVM's her
spricht JRMP (Java Remote Method Protocol) als stream-basiertes Protokoll oberhalb von TCP/IP RMI ab JDK 1.3 spricht zusätzlich das RMI-IIOP Transportprotokoll basierend auf IIOP (Internet Inter-ORB Protocol) ermöglicht Kommunikation zwischen CORBA und RMI Objekten enthält Fähigkeiten, RMI Verkehr über andere Verbindungen zu tunneln (z.B. über HTTP) Der Transportlayer stellt die Verbindung zwischen den JVM‘s auf der Client- und Serverseite her. Es benutzt dabei standardmäßig das JRMP (Java Remote Method Protocol) als ein stream-basiertes (also TCP basiertes) Protokoll oberhalb von TCP/IP. Ab JDK 1.3 kann man auch das RMI-IIOP (ein zwischen RMI und CORBA kompatibles) Übertragungsprotokoll verwenden. Hierzu muss man eine entsprechende Option dem rmic Compiler bei der Erzeugung von Skeleton (in diesem Fall tie Objekte) und Stubs mitteilen (rmic –iiop). Letzteres ermöglicht dann eine Kommunikation zwischen CORBA und RMI Objekten. Mit der zusätzlichen Option -poa des rmic Compilers bekommt man Portable Objekt Adapter (siehe CORBA) kompatible RMI Serverobjekte (d.h. von PortableServer.Servant abgeleitete Klassen) und kann deren zusätzliche Funktionalität für Serverimplementierungen nutzen. Das JRMP Protokoll enthält automatische Fähigkeiten, den RMI Verkehr über HTTP zu tunneln. Falls ein Client keine direkte Verbindung zu einem Serversocket aufbauen kann, versucht er zunächst den Serversocket über Tunneln des RMI Verkehrs über das HTTP Protokoll zu erreichen. Dies funktioniert nur, wenn Firewalls HTTP Protokollverkehr zu beliebigen Ports (nicht nur Port 80) erlauben. Funktioniert dies auch nicht, versucht der Client ein HTTP-RMI CGI Programm unter Port 80 auf dem Zielrechner mit Adresse /cgi-bin/rmi-cgi zu erreichen. Dieses Programm sollte dann den Verkehr an den RMI Server weiterleiten. Ein Beispielimplementierung eines solchen Programms liegt dem JDK unter Beispiele bei. Clemens Düpmeier,

49 Beispiel: Interfacebeschreibung eines RMI Objektes (entfernten Objektes)
public interface Compute extends Remote { <T> T executeTask(Task<T> t) throws RemoteException; } Interface von Remote ableiten Jeder Methode throws java.rmi.RemoteException hinzufügen Objekte, die so ein "Remote" Interface implementieren, sind entfernte Objekte Jedes Interface, dass entfernte Objekte definiert, muss von dem Interface Remote abgeleitet sein. Alle Methoden des Interface, die von entfernt aufgerufen werden können sollen, müssen die Ausnahme RemoteException (throws RemoteException) werfen. Parameter oder Returnwerte, die wiederum Remote Objekte darstellen, müssen in Form einer Remote Interface Angabe und nicht durch die Angabe einer Implementierungsklasse beschrieben werden. Clemens Düpmeier,

50 Verwendet "normales" Objekt mit Interface Task
import java.io.Serializable; public interface Task<T> { T execute(); } Nicht-Remote Objektparameter von entfernten Methoden müssen serialisierbar sein Implementierungen müssen also sagen: implements Serializable Ein Task ist für uns ein beliebiges Objekt, dass eine execute() Methode zur Ausführung einer Berechnung besitzt und irgendein Ergebnis zurückgibt Objekte, die Task implementieren, sind lokale Objekte Objekte, die nicht vom Typ Remote sind und als Parameter an Remote-Prozeduren übergeben werden, müssen serialisierbar sein (damit sie von einer Virtuellen Maschine in eine anderen übertragen werden können). Unsere Remote-Methode executeTask() der ComputeEngine verlangt nach einem Task Objekt, dass bestimmt, was berechnet werden soll. Dieses Task Objekt muss das obige Interface erfüllen, damit die ComputeEngine die Berechnung durch Ausführung der Interface-Methode execute() ausführen kann. Der Ergebniswert der Berechnung wird in Form eines beliebigen Objekttyps als Returnwert zurückgegeben. Der Returnwert von execute() ist daher ein Objekt eines beliebigen Typs T. Clemens Düpmeier,

51 RMI Parameterübergabe
Entfernte Objekte werden als Proxy (Stub) an den Client übergeben (Referenzsemantik) Bei Benutzung sind sowohl Methoden wie auch Daten des Objektes entfernt Andere (lokale Objekte) werden Call by Value (Kopiersemantik) übergeben Beim Kommunikationspartner wird dabei eine Kopie des Objektes angelegt Die Objekte müssen hierfür serialisierbar sein, um übertragen werden zu können Der Code muss beim Kommunikationspartner verfügbar sein oder dynamisch geladen werden Bei der Parameterübergabe an Methoden von Remote Objekten muss man zwei Fälle unterscheiden. Ist der übergebende Parameter wieder ein Remote Objekt, dann wird statt einer Kopie des Objektes der Stub des Remote Objektes (also ein Proxy) übertragen. Nach der Übertragung sind also sowohl dessen Daten als auch dessen Methoden auf den Empfängerrechner bezogen entfernt. Andere Objekte (sogenannte lokale Objekte) werden Call by Value (also als Kopie) übertragen. D.h. der Empfänger arbeitet nach der Übertragung mit einer privaten, lokalen Kopie des Objektes und Änderungen dieses Objektes beeinfluss nicht das Orginal des Objektes beim Absender. An solche lokalen Objekte als Argumente oder Returnwerte von Remote Objektmethoden ist eine einzige Bedingung geknüpft: sie müssen serialisierbar sein, d.h. sie müssen das Serializable Interface implementieren (da Serializable nur ein sogenanntes Marker Interface ist, bei dem man keine Methoden oder so was implementieren muss reicht hier die Angabe implements Serializable). Nicht alle Klasse für Objekte werden als serialisierbar deklariert, da z.B. Objekte, die an lokale Ressourcen gebunden sind (z.B. ein Drucker, Font oder ähnliches) nicht so ohne weiteres als Kopie von einem Rechner auf einen anderen übertragen werden können. Clemens Düpmeier,

52 Implementierung des entfernten Objektes
public class ComputeEngine extends UnicastRemoteObject implements Compute { public ComputeEngine() throws RemoteException() { super(); } public <T> T executeTask(Task<T> t) { return t.execute(); } } Eine einfache Möglichkeit eine Implementierung für Remote Objekt bereitzustellen, ist es die Implementierungsklasse des Remote Interfaces von der Klasse UnicastRemoteObject abzuleiten. Hierbei erledigt die UnicastRemoteObject einiges, was man ansonsten selbst realisieren muss. Zunächst stellt UnicastRemoteObject einige auf Remote Objekte angepasste Implementierungen von Methoden der Objekt Klasse bereit (equals(), hasCode(), toString()). Dies müsste man ansonsten selbst bereitstellen. Im Konstruktor der UnicastRemoteObject Klass (immer direkt vom Konstruktor unserer eigenen Klasse aufgerufen) wird weiterhin ein erzeugtes Remote Objekt in der RMI Laufzeitinfrastruktur registriert (d.h. dadurch wird es von aussen zugreifbar). Realisiert man die eigene Implementierungsklasse eines Remote Objektes nicht durch Ableitung von UnicastRemoteObjekt, so muss man diese Registrierung von Objekten in der RMI Laufzeitinfrastruktur von Hand für jedes erzeugt Remote Objekt durchführen. Hierzu verwendet man dann die statische Methode UnicastRemoteObject.exportObject() und übergibt dieser dass das Remote Interface implementierende Objekt. Implementierungsklasse wurde von UnicastRemoteObject abgeleitet; dies macht aus Objekt in Konstruktor von UnicastRemoteObject einen Server Konstruktor registriert Remote Objekt gleichzeitig in RMI Laufzeitinfrastruktur und macht Objekt so von aussen referenzierbar Clemens Düpmeier,

53 Alternative Implementierung
public class ComputeEngine implements Compute { public <T> T executeTask(Task<T> t) { return t.execute(); } } // und später bei Instanzierung ComputeEngine engine = new ComputeEngine(); Compute engineStub =(Compute)UnicastRemoteObject.exportObject(engine,0); Eine weitere Möglichkeit, das entfernte Objekt zu implementieren, ist nur das Compute Interface zu implementieren und nicht von UnicastRemoteObjecdt abzuleiten. Dann muss man allerdings später sein Implementierungsobjekt manuell in der RMI-Laufzeitstruktur registrieren. Dies gescheiht mit einem Aufruf der Methode exportObject der UnicastRemoteObject-Klasse. Die exportObject-Methode registriert dann das übergebende implementierende Objekt in der Laufzeitinfrastruktur und gibt ein Stub (Proxyobjekt) zurück, dass den Zugriff auf die Implementierung kapselt. Der Stub enthält dann bereits die entfernte Objektreferenz, etc. Manuelles Registrieren des engine-Objektes in der RMI-Laufzeitinfrastruktur Laufzeitinfrastruktur liefert dabei Stub (Proxyobjekt) zurück Clemens Düpmeier,

54 RMI Compiler Basierend auf der Implementierung des Objekts mit seinen Methoden kann man nun automatisch Stub- und Skeletonklassen generieren. JDK stellt ein Werkzeug namens rmic für diesen Zweck zur Verfügung. Folgender Aufruf > rmic ComputeEngine Erzeugt zwei Dateien: ComputeEngine_Stub.class (Proxy-Objekt für Client) ComputeEngine_Skel.class (Skeleton für Server) Dieser Schritt ist nur noch in bestimmten Anwendungssituationen notwendig Clemens Düpmeier,

55 Neuerungen in JDK 1.4 und 1.5 Bei JDK >= 1.4 Nutzung auf Serverseite kann Erzeugung von Skeleton entfallen RMI Implementierung kann Reflection API statt Skeletons auf Serverseite zum Aufruf von Methoden nutzen Bei Nutzung von JDK >= 1.5 kann Generierung von Stubs entfallen da 1.5 Möglichkeiten zu dynamischen Erzeugung von Proxyobjekten enthält und RMI in JDK 1.5 diese zur automatischen Erzeugung des Stubobjektes nutzen kann Clemens Düpmeier,

56 Namensauflösung bei RMI
registry.lookup (liefert Stub) rmiregistry Client Programm 1099 registry.rebind(...) RMI Server rufe remote Methode durch Stub auf Wie bei RPC‘s benötigt man auch für RMI und aller weiteren Formen der Objektkommunikation eine Instanz zum Lookup (Namensauflösung) der Serverobjekte. Bei RMI wird dieser Dienst durch das rmiregistry bereitgestellt. Hierzu wird ein Java basierter Serverdaemon mit Namen rmiregistry (auf dem Serverrechner) gestartet, der normaler Weise auf Port 1099 zu erreichen ist, sofern man den Port nicht bei Aufruf des Daemon ändert. Ruft man anschließend ein RMI Serverprogramm auf, so kann sich dieses durch einen Naming.rebind() Aufruf im rmiregistry Daemon unter einem angegebenen RMI-Remote Objektnamen registrieren (siehe eine der folgenden Folien). Ein Client kann sich im Anschluss daran mit einem Aufruf von Naming.lookup() an das RMI Registry wenden, um ein Stub-Objekt zum Zugriff auf das gewollte Serverobjekt zu bekommen. Dabei gibt der Client den Namen des gewünschten Serverobjektes an. Durch Aufruf der Remote Interface Methoden auf dem zurückgelieferten Stub-Objekt kommuniziert im Anschluss der Client direkt mit der Objektimplementierung im RMI-Server. Stub Client System Server System Clemens Düpmeier,

57 Registry Klasse Wie sieht RMI Name aus? //hostname[:port]/Objektname
java.rmi.Registry static void rebind(String name, Remote obj) // registriere // obj im Namensdienst // mit Name name ... static Remote lookup(String name) // hole Stub zu Name // unter Anfrage beim // Namensdienst Die InetSocketAddress Klasse enkapsuliert in Java Adressen, die Sockets zugeordnet werden, d.h. sie enthalten sowohl IP-Adressangaben als auch zugehörige Ports. Angelegt werden Sie über Konstruktoren, bei denen am den Hostnamen entweder als String oder bereits als ein InetAdress und die Portnummer als normale Integer angibt. Weiter gibt es einen Konstruktor für Wildcard IP-Adressen, d.h. bei Erzeugen einer lokalen Adressen gibt man keine IP-Adresse an und dies heisst, dass ein accept() auf allen Interface (falls also der Rechner mehr als eine IP-Adresse hat) erfolgen soll. Die Klasse besitzt weiter Methoden zur Abfrage der einzelnen Teile eines InetSocketAddress Objektes (also Portnummer, InetAddress und/oder Hostname). Wie sieht RMI Name aus? //hostname[:port]/Objektname Clemens Düpmeier,

58 Basisstruktur RMI Server (1. Version)
if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); String name="//hostname/Compute"; try { Compute engineStub=new ComputeEngine(); Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, engineStub); } catch (Exception e) { } Security Manager setzen = Schutz vor Clientcode Namen für das Serverobjekt definieren Serverobjekt erzeugen; hier Version mit extends UnicastRemoteObject Mit Namen im rmiregistry registrieren Diese Folie verdeutlicht die Basisfunktionsweise eines RMI Serverrumpfes (d.h. Teil der Main-Methode). Zunächst setzt der Server, sofern dies noch nicht erfolgt ist, einen Security Manager ein, der als Schutzwall die Möglichkeiten von Objekten, die eventuell vom entfernten Client auf den Server geladen und dort ausgeführt werden, begrenzt. Der oben verwendete RMISecurityManager bietet hier dem Server die gleichen Schutzbedingungen, wie sie im Fall von Applets durch den SecurityManager im Java Plugin (Java-Implementierung im Browser) bereitgestellt werden, d.h. Objekte, die vom Client geladen werden, dürfen keine lokalen Fileoperationen machen, oder hier betriebssystemspezifische Dinge aufrufen. Sie dürfen sich weiter zur Kommunikation nur auf den Rechner verbinden, von dem sie herkommen. Als erster Schritt zum Remote Serverobjekt wird ein Name für das Serverobjekt definiert (in der Form //hostname/Servicname) und dann ein Serverobjekt als Objekt der zugehörigen Implementierungsklasse instanziiert. Bei dieser Version des Servers gehen wir davon aus, dass die Objektimplementierung von UnicastRemoteObject ableitet und daher bereits durch den Konstruktor in der RMI-Laufzeitinfrastruktur registriert wird. Nun muss nur noch das Objekt unter dem gewählten Namen im rmiregistry durch Aufruf der Methode registry.rebind() Methode registriert werden (registry.rebind(name, remoteObj). Eine Referenz auf dem Server gestartete Registry bekommt man dabei durch LocateRegistry.getRegistry(). Clemens Düpmeier,

59 Basisstruktur RMI Server (2. Version)
if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); String name="//hostname/Compute"; try { ComputeEngine engine=new ComputeEngine(); Compute engineStub = UnicastRemoteObject.exportObject(engine,0) Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, engineStub); } catch (Exception e) { } Diese Folie verdeutlicht die zweite Form, wie man eine Implementierung des Serverobjektes in der RMI-Laufzeitinfrastruktur registrieren kann. Dies geschieht über den Aufruf der exportObject() Methode. Der zweite Parameter gibt dabei eine Portnummer an, unter der das exportierte Objekt verfügbar sein soll. Wenn 0 angegeben wird, wird irgendeine Portnummer verwendet. Man beachte weiter, dass bei der Registrierung zurückgegebende Stub (Proxyobjekt) und nicht engine in diesem Fall beim Namensdient registriert werden muss. Manuelle Registrierung in der Laufzeitinfrastruktur mit exportObject() Man beachte: das zurückgegebene Stubobjekt und nicht engine wird im Namensdienst registriert Clemens Düpmeier,

60 Basisstruktur RMI Client
if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); String name="//hostname/Compute"; try { Registry registry = LocateRegistry.getRegistry(args[0]); Compute engine=(Compute)registry.lookup(name); // Methoden des Remote Objektes verwenden } catch .... Entsprechend einfach ist der Code eines RMI client. Auch dieser schützt sich bei Bedarf zunächst einmal durch Einsetzen eines Security Managers vor böswilligen Objekten, die vom RMI Server durch Aufruf von Remote Objektmethoden heruntergeladen werden. Mit dem Namen, der für ein Remote Objekt auf Serverseite definiert wurde, führt er dann ein Lookup des Objektes im rmiregistry durch (registry.lookup(name)). Als Returnwert erhält er dabei ein Objektreferenz auf ein zugehöriges Stubobjekt. Auf diesem kann er anschließend alle Methoden des Remote Interfaces aufrufen. Eine Referenz auf das Registry auf dem Serverrechner bekommt man dabei durch LocateRegistry.getRegistry("hostname"). In unserem Beispiel wird der Hostname als Argument auf der Kommandozeile übergeben. Security Manager setzen = Schutz vor Servercode Lookup des Serverobjektes im Registry Verwendung der Methoden des Remote Objektes Clemens Düpmeier,

61 Basisstruktur RMI Client (2)
... try { Registry registry = LocateRegistry.getRegistry(args[0]); Compute engine=(Compute)registry.lookup(name); Pi task = new Pi(Integer.parseInt(args[1])); BigDecimal pi = engine.executeTask(task); System.out.println(pi); } catch .... Entsprechend einfach ist der Code eines RMI client. Auch dieser schützt sich bei Bedarf zunächst einmal durch Einsetzen eines Security Managers vor böswilligen Objekten, die vom RMI Server durch Aufruf von Remote Objektmethoden heruntergeladen werden. Mit dem Namen, der für ein Remote Objekt auf Serverseite definiert wurde, führt er dann ein Lookup des Objektes im rmiregistry durch (registry.lookup(name)). Als Returnwert erhält er dabei ein Objektreferenz auf ein zugehöriges Stubobjekt. Auf diesem kann er anschließend alle Methoden des Remote Interfaces aufrufen. Eine Referenz auf das Registry auf dem Serverrechner bekommt man dabei durch LocateRegistry.getRegistry("hostname"). In unserem Beispiel wird der Hostname als Argument auf der Kommandozeile übergeben. Client berechnet die Zahl PI über den Server Hierzu muss es eine Implementierung des Task-Interfaces geben, die innerhalb ihrer execute()-Methode PI berechnet und den Wert als BigDecimal zurückgibt Clemens Düpmeier,

62 Implementierung der PI-Berechnungsklasse
zu lang für Folie siehe aber Java Tutorial enthält die komplette Implementierung des Beispiels unter Clemens Düpmeier,

63 Wie kommt der Server zum Code der Klasse PI?
Der jar-File mit dem Code des Servers muss nicht notwendigerweise die Klasse PI enthalten Wie kommt dann aber der Klassencode der Klasse PI zum Server, wenn das PI-Berechnungsobjekt zum Server übertragen und dort ausgeführt wird? Java kann Code dynamisch über Netz laden! Hierfür muss der Code von PI irgendwo zum Download für den Server bereitgestellt werden Und die Infrastruktur so aufgesetzt werden, dass sie weiss, woher der Code geladen werden soll Clemens Düpmeier,

64 Zusammenfassung: RMI Anwendung schreiben
1. Definiere die entfernte Schnittstelle 2. Implementiere die entfernte Schnittstelle durch eine Klasse (z.B. abgeleitet von UnicastRemoteObject) 3. Generiere Stubs und Skeletons mit rmic 4. Schreibe einen Server und Client 5. Starte den Namensdienst mit rmiregistry 6. Starte den Server auf der Maschine, wo das rmiregistry läuft 7. Starte den Client Clemens Düpmeier,

65 RMI-Beispiel ablaufen lassen
Vollständiger Code und Beschreibung im Java Tutorial von Sun Achtung: Beim Starten der Applikation (Client + Server) muss der Klassenlader richtig aufgesetzt werden (siehe Beschreibung im Tutorial), z.B. java -Djava.rmi.server.codebase=http://myhost/Compute/classes/ \ -Djava.rmi.server.hostname=zaphod.east.sun.com \ -Djava.security.policy=java.policy \ ComputeEngine da sonst die Klassen, die über Netz gehen (z.B. das Stubobjekt vom Server, die Interfaces oder die Client Task Klasse), nicht geladen werden können Außerdem muss die Security-Policy Datei (wir schützen unsere Programme von fremder Code durch SecurityManger) richtig aufgesetzt werden Clemens Düpmeier,

66 Verteilte Objekttechnologien Common Object Request Broker Architecture (CORBA)
CORBA ist eine portable Implementierung für verteilte Objekte, die die Realisierung von entfernten Objekten auf verschiedenen Maschinen unter Nutzung verschiedener Programmiersprachen (C, C++, Java, etc.) ermöglicht. Clemens Düpmeier,

67 Object Management Group (OMG)
Gründung: April 1989 Ziele: Interoperabilität Anwendungsintegration Portabilität Mitglieder: über 800 Mitglieder darunter: Apple, AT&T, DEC, HP, IBM, Microsoft, SUN,... Entwicklungsprozeß: Request for Proposal (RFP) in heterogenen Umgebungen auf der Basis eines Objektmodells Distributed Component Object Model (DCOM) Clemens Düpmeier,

68 Object Management Architecture (OMA)
Application Objects spezifische Anwendungsgebiete gehören nicht zur Infrastruktur Common Facilities allgemein nützliche Dienste (Drucken, , Datenbanken) nicht notw. Teil aller Infrastrukturen Object Request Broker (Objektbus) Infrastruktur für Kommunikation garantiert Interoperabilität Common Object Services allg. Funktionen zum Erstellen u. Unterhalten von Objekten Application Objects Common Facilities Common Object Services ORB Clemens Düpmeier,

69 ORB Aufgabe Einbettung von Objekt-Implementationen ("Server-Objekte")
Application Objects Common Facilities Common Object Services ORB Einbettung von Objekt-Implementationen ("Server-Objekte") Vergabe von Objektreferenzen Entgegennehmen von Aufrufen vom Client Transport der Aufrufe zum Server ggf. Aktivierung eines Server-Objektes Übergabe des Aufrufs zum Server-Objekt Entgegennehmen von Ergebnissen und Transport / Rückgabe zum Client Unterstützung von Sicherheits- und Abrechnungsfunktionen Clemens Düpmeier,

70 Object Services Object Services Naming Event Security Transactions
Application Objects Common Facilities Common Object Services ORB Object Services Naming Event Security Transactions Trading Lifecycle Time (= Systemfunktionen) Licensing Properties Relationships Notification Persistence Concurrency Control Externalisation Nur Spezifikation der Schnittstellen und grundlegender Funktionsprinzipien! Clemens Düpmeier,

71 Common Facilities Application Objects Common Facilities Common Object Services ORB Höherwertige Dienste für ein breites Spektrum an Anwendungsbereichen Bereitstellung allgemein interessanter Funktionalität (analog zu großen Klassenbibliotheken) Horizontale Common Facilities (Basisfunktionalität allgemein) User Interface Information Management (Speicherung komplexer Strukturen, Formatkonvertierung) Task Management (Workflow, lange Transaktionen) Internationalisierung („Sprachenübersetzung“) Vertikale Common Facilities (Basisfunktionalität speziell) für Marktsegemente, z.B. Banken, Gesundheitswesen, Finanzdienste vgl. „application frameworks“, „business objects“ Clemens Düpmeier,

72 Application Objects (Business Objekte)
Common Facilities Common Object Services ORB Application Objects (Business Objekte) Andere Schnittstellen Business-Objekte (M, Server) kapseln Speicher, Metadaten, Parallelität u. Regeln einer aktiven Business-Einheit legt fest, wie auf Änderungen in View/Modell reagiert wird Business-Prozeßobjekte (C, Server) kapseln Business-Logik Verwaltung vorwiegend langlebiger Prozesse (Workflow, Transaktion) Präsentationsobjekte (V, Client) grafische Darstellung des Objektes unterschiedliche Präsentationen möglich Komponenten eines Business- Objektes Präsentations- Objekt MVC Business- Prozeß- Objekt Business- Objekt Andere Business-Objekte Dokument Server

73 IDL (Interface Definition Language)
Ada Basismechanismus zur Definition von Schnittstellen (Standard) Unabhängig von spezieller Sprache (dekla-rativ, d.h. ohne algorithmische Teile, d.h. ohne Implementierungsdetails) Sprachbindung für verschiedene Sprachen IDL-Grammatik ist Teilmenge von C++; zusätzlich Mittel für Verteilungskonzepte Beinhaltet Mehrfachvererbung Schnittstellenverzeichnis (Interface Repository), damit selbstbeschreibend IDL ist Kontrakt, der alle und alles zusammenbringt IDL C IDL C++ IDL ORB COBOL IDL Java IDL Smalltalk IDL Clemens Düpmeier,

74 Beispiel für eine IDL Datei (1)
module Bank { typedef sequence<string> StringArray; struct Person { string name; string vorname; }; // hier fehlt noch exception Definition interface Konto { readonly attribute float kontostand; readonly attribute long geheimzahl; readonly attribute long kontonummer; void einzahlen(in float betrag); void abheben(in float betrag); void unlock(); // Sperre freigeben }; // hier geht es weiter mit dem KontoManager }; Das obige Beispiel zeigt eine typische IDL Beschreibung. Innerhalb einer IDL Moduldeklaration können Datentypen, Strukturen und Objektinterfaces (IDL interface Konstrukt) definiert werden. Mit den typedef Konstrukten werden in Analogie zu C und C++ Namen (im obigen Beispiel StringArray) für zusammengesetzte Datentypen definiert. Ebenfalls in Analogie zu C bzw. C++ lässt sich die Struktur von Structs mit einem Namen verbinden. Solche Strukturdeklarationen lassen sich auch wieder in typedef Definitionen einbeziehen. Das interface Konstrukt der IDL erlaubt die Definition der Schnittstellen von (entfernten) Objekten. In einem Interface können Attribute und Methoden eines Interfaces definiert werden. Attribute sind in so fern spezielle Methodendeklarationen, als dass sie in Zielsprachen für gewöhnlich auf zwei Methoden (einer getter-Methode attribute_name() ohne Parameter und einer Setter Methode attribute_name(wert) umgesetzt werden. Attribute vom Typ readonly werden nur auf die getter Methode abgebildet. Bei der Angabe der Parameter von Methoden muss man mit den Schlüsselwörtern in, out bzw. inout angeben, ob der Parameter einen Werte in die Methoden hineingibt, ein Wert aus der Methode heraus an das aufrufende Programm zurückgegeben werden soll oder der Parameter Werte in beide Richtungen transportieren soll. Diese Angabe ist ungewöhnlich, da Computersprachen so eine Angabe in der Regel nicht besitzen. Wir werden noch sehen, das spezielle Hilfsklassen bzw. Hilfsfunktionen (oft Holder genannt) nötig sind, um als Container für die Werte von out bzw. inout Parametern zu dienen, die Werte an den Aufrufe zurückgeben sollen. Für die Typangabe der Parameter und Returnwerte von Methoden können gängige Standardtypbezeichnungen (wie float, long, void, int) usw. verwendet werden. Weiter werden von der IDL komplexere Typen bereitgestellt und bereits definierte interfaces sind auch erlaubt, wie wir auf den nächsten Folien noch darlegen werden. Clemens Düpmeier,

75 Beispiel IDL Datei (2) module Bank { typedef sequence<string> StringArray; struct Person { string name; string vorname; }; exception KontoException { string begruendung; }; // hier war interface Konto definiert interface KontoManager { Konto anmelden(in long kontonr, in long geheimzahl) raises (KontoException); Konto oeffnen(in Person daten); void aufloesen(in Konto konto); StringArray holeKontenInfos(); }; }; Dies ist der zweite Teil unserer Beispiel IDL Datei. Hier wird das Interface KontoManager definiert. Es verwendet das Interface Konto, das auf der vorhergehenden Folie definiert wurde sowohl für Parameter von Methoden als auch als Returnwert von Methoden. Es zeigt weiter, dass Fehler bei entfernten Methodenaufrufen durch Senden eines Exception Objektes (Hier KontoException) über das Netzwerk übertragen werden können. Ein eigenes Exception Objekt kann mit einer exception Definition in der IDL Datei zu definiert werden. Clemens Düpmeier,

76 Feature der IDL (1) Mehrere Interface Beschreibungen können in einer Modulbeschreibung zusammengefasst werden Es gibt die von anderen Sprachen bekannten Standardtypen (Gleitkomma, Integer, Zeichen-, bool, Byte und deren Subtypen) Es gibt Konstrukte zum Aufbau von struct's und union's Template Typen sequence und string sowie Arrays Neue Typen können mit typedef deklariert werden interface Definitionen entsprechen neu definierten Objekttypen (Klassen) Es gibt den Begriff Attribut mit name() und name(value) Zugriffsfunktionen Wie wir bereits angedeutet haben, sind die von anderen gängigen Sprachen her bekannten Standarddatentypen auch in der IDL verwendbar (float, int, long, short, char usw.). Weiter gibt es Standarddatentypen für Zeichenketten string und Bytefolgen byte und einen booleschen Typ (bool). Auch Konstrukte zum Aufbau von structs und union sind wie gewohnt vorhanden. Auch Arrays sind in IDL definierbar. Neu ist der Template Typ sequence, wie in unserem Beispiel sequence<string>. Interface Definitionen entsprechen Objektdefinitionen und die spezielle Bedeutung von Attributen haben wir bereits an Hand der vorhergehenden Folie erläutert. Clemens Düpmeier,

77 Feature der IDL (2) Es gibt Enumerations (Aufzählungstypen)
Man kann Konstanten deklarieren Weiter gibt es Exception Deklarationen für Ausnahmezustände Parameter von Methoden lassen sich als in, out oder inout Parameter definieren Weiter gibt es die Möglichkeit Methoden als vom Typ oneway (d.h. kein Returnwert erwartet) zu deklarieren, was eine nicht-blockierende Bearbeitung bedeutet (der Client wartet hier nicht auf den Server) Auch enumeration (also Aufzählungstypen wie in C++) lassen sich definieren und Konstanten deklarieren. Weiter lassen sich Ausnahmen für die Fehlerbehandlung mit dem exception Konstrukt definieren. Die Bedeutung der Schlüsselwörter in, out oder inout haben wir bereits erklärt. In Bezug auf die Synchronisierung eines entfernten Methodenaufrufes ist es interessant, dass man Methoden als vom Typ oneway deklarieren kann. D.h.: der Client wartet nach Aufruf der Methode nicht auf einen Returnwert oder auf eine Rückmeldung vom Server. Clemens Düpmeier,

78 andere Server- Objekte
Funktion des IDL Compiler Client Source Code Client Client Stub javac IDL interface IDL compiler Hilfs- klassen Server javac Skeleton Diese Folie verdeutlicht die Funktion des IDL Compilers. Ausgehend von einem IDL Interface erzeugt er Stubs, Skeletons und verschiedene Hilfsfunktionen in der jeweiligen Zielsprache (hier für Java). Die Hilfsfunktionen (in Java spezielle Hilfsklassen, die für Typcastings und als Speicher für out Parameter, die in der IDL definiert sind) werden vom Anwendungsprogrammierer innerhalb der Serverobjektimplementierung verwendet, um Objekte auf den richtigen Typ zu casten oder auf spezielle Parameter (die out/inout Parameter) zuzugreifen. Bei der Compilierung des Servers werden das Server Main Programm (Server Source), die Server Objektimplementierungen, andere vom Server benötigte lokale Objekte und die Skeletonklassen mit dem Zielsprachencompiler übersetzt (hier javac) und zum Serverprogramm zusammengebunden. Auf der Clientseite werden die Hilfsfunktionen ebenfalls innerhalb des Clientsourcecodes für Castings und Zugriff auf die speziellen out/inout Parameter genutzt. Zur Erzeugung des Clients werden Client Source Code und Client Stubcode mit dem Zielsprachencompiler übersetzt und zusammengebunden. andere Server- Objekte Server Ojekt- Impl. Server Source Clemens Düpmeier,

79 Ablauf eines Methodenaufrufs
Client Objekt Anwendung Implementierung 1) Aufruf 5) Auspacken und 4b) Aktivieren Aufruf IDL Stub IDL Skeletton Implementation Repository 4) Weiterleiten an 2) Parameter einpacken Schnittstelle und Aufruf weiterleiten Object Adapter 4a) Ermitteln der Implementierung Object Request Broker Core 3) Transport über den ORB mit GIOP (IIOP) Clemens Düpmeier,

80 Aufbau eines CORBA Servers
POA (Portable Objekt Adapter) dient als zentrale Zugriffsschnittstelle auf Objektimplementierungen erzeugt eindeutige Objektreferenzen hat Objekt Map nimmt Requests für Objekte vom ORB entgegen Applikationscode aktive Servants main (String args[]) { ORB orb = ORB.init(args); orb.connect ( new AServant() ); orb.connect( new BServant() ); orb.run(); } Haupt- programm Servant Activator i Default Servant statisch (mit Skeleton) dynamisch (ohne Skeleton) ... ORB- Schnittstelle Portable Object Adapter Fabrik für Objektreferenzen 1 2 ... n Active Object Map Servant Activator Default Servant ORB-Kern Event Loop Marshalling Engine Request Interceptors für verschiedene Services (optional) Netzwerk Clemens Düpmeier,

81 Ablauf einer CORBA Entwicklung
Schnittstellendesigner Programmierer interfaces.idl Anwendungsentwickler IDL-Java Compiler IDL-C++ Compiler Client Server client.jar stubs.jar types.hh stubs.cc skels.cc servants.cc

82 CORBA Protokolle: GIOP und IIOP
Mit CORBA 2.0 wurde GIOP = General Inter-Orb Protocol als netzwerkunabhängiges Wire Protocol spezifiziert Die (meist verwendete) TCP/IP-Variante heißt IIOP = Internet Inter-Orb Protocol GIOP spezifiziert Nachrichtentypen (Requests, Resultate, Ping, ...) Datenaustauschformat ("Common Data Representation") Interoperable Objektreferenzen (IORs) Service-Kontexte (Request-Anhängsel, mit denen Dienste transparent Informationen übermitteln können) Clemens Düpmeier,

83 RMI-IIOP Corba Objekte mit RMI Clemens Düpmeier,

84 Beispiel-Interface Ganz normales RMI Interface //HelloInterface.java
import java.rmi.Remote; public interface HelloInterface extends java.rmi.Remote { public void sayHello( String from ) throws java.rmi.RemoteException; } Ganz normales RMI Interface Clemens Düpmeier,

85 Implementierung des Interfaces
//HelloImpl.java import javax.rmi.PortableRemoteObject; public class HelloImpl extends PortableRemoteObject implements HelloInterface { public HelloImpl() throws java.rmi.RemoteException { super(); // invoke rmi linking and remote object initialization } public void sayHello( String from ) throws java.rmi.RemoteException { System.out.println( "Hello from " + from + "!!" ); System.out.flush(); Diese Folie zeigt den Rumpf eines CORBA Clients. Dieser muss sich ebenfalls zunächst einmal einen Zugriff auf das CORBA Laufzeitenvironment verschaffen und die Laufzeitstruktur des ORB initialisieren (Aufruf von ORB.init()). Damit sich der Client Zugriff auf das gewollte Serverobjekt verschaffen kann, benötigt er zunächst Zugriff auf den Namensdienst. Auch er verwendet wie der Server hierzu die Methode resolve_initial_references() der orb Objektes und castet die so gewonnene Objektreferenz vomTyp CORBA.Object in das richtige Interface NamingContext des Namensdienstobjektes mit der narrow() Methode der zugehörigen Hilfsklasse NamingContextHelper. Dann bildet der Client den Namen des gewollten CORBA Serverobjekts als Namenskomponentenarray und verschafft sich durch einen Aufruf von der resolve() Methode der NamingContext Klasse vom Namensdienstobjekt ncRef ein Objektreferenz auf das gewollte Serverobjekt. Man beachte, dass die zurückgegebene Objektreferenz wiederum vom generischen Typ CORBA.Object ist und erst in den spezifischen Interfacetyp Hello durch Aufruf der narrow() Methode der zugehörigen Hilfsklasse (HelloHelper) gecastet werden muss. Anschließend kann das Serverobjekt gemäß seinem Interface vom Client verwendet werden (helloRef.sayHello()). Leitet von PortableRemoteObject ab! Clemens Düpmeier,

86 RMI-IIOP Serverprogramm
//HelloServer.java import javax.naming.InitialContext; import javax.naming.Context; public class HelloServer { public static void main(String[] args) { try { HelloImpl helloRef = new HelloImpl(); // Step 2: Publish the reference using JNDI API Context initialNamingContext = new InitialContext(); initialNamingContext.rebind("HelloService", helloRef ); } catch (Exception e) { e.printStackTrace(); } Diese Folie zeigt den Rumpf eines CORBA Clients. Dieser muss sich ebenfalls zunächst einmal einen Zugriff auf das CORBA Laufzeitenvironment verschaffen und die Laufzeitstruktur des ORB initialisieren (Aufruf von ORB.init()). Damit sich der Client Zugriff auf das gewollte Serverobjekt verschaffen kann, benötigt er zunächst Zugriff auf den Namensdienst. Auch er verwendet wie der Server hierzu die Methode resolve_initial_references() der orb Objektes und castet die so gewonnene Objektreferenz vomTyp CORBA.Object in das richtige Interface NamingContext des Namensdienstobjektes mit der narrow() Methode der zugehörigen Hilfsklasse NamingContextHelper. Dann bildet der Client den Namen des gewollten CORBA Serverobjekts als Namenskomponentenarray und verschafft sich durch einen Aufruf von der resolve() Methode der NamingContext Klasse vom Namensdienstobjekt ncRef ein Objektreferenz auf das gewollte Serverobjekt. Man beachte, dass die zurückgegebene Objektreferenz wiederum vom generischen Typ CORBA.Object ist und erst in den spezifischen Interfacetyp Hello durch Aufruf der narrow() Methode der zugehörigen Hilfsklasse (HelloHelper) gecastet werden muss. Anschließend kann das Serverobjekt gemäß seinem Interface vom Client verwendet werden (helloRef.sayHello()). Clemens Düpmeier,

87 RMI-IIOP Clientprogramm
public class HelloClient { public static void main( String args[] ) { Context ic; Object objref; HelloInterface hi; try { ic = new InitialContext(); hi = (HelloInterface)ic.lookup("HelloService"); hi.sayHello( " MARS " ); } catch( Exception e ) {} } Diese Folie zeigt den Rumpf eines CORBA Clients. Dieser muss sich ebenfalls zunächst einmal einen Zugriff auf das CORBA Laufzeitenvironment verschaffen und die Laufzeitstruktur des ORB initialisieren (Aufruf von ORB.init()). Damit sich der Client Zugriff auf das gewollte Serverobjekt verschaffen kann, benötigt er zunächst Zugriff auf den Namensdienst. Auch er verwendet wie der Server hierzu die Methode resolve_initial_references() der orb Objektes und castet die so gewonnene Objektreferenz vomTyp CORBA.Object in das richtige Interface NamingContext des Namensdienstobjektes mit der narrow() Methode der zugehörigen Hilfsklasse NamingContextHelper. Dann bildet der Client den Namen des gewollten CORBA Serverobjekts als Namenskomponentenarray und verschafft sich durch einen Aufruf von der resolve() Methode der NamingContext Klasse vom Namensdienstobjekt ncRef ein Objektreferenz auf das gewollte Serverobjekt. Man beachte, dass die zurückgegebene Objektreferenz wiederum vom generischen Typ CORBA.Object ist und erst in den spezifischen Interfacetyp Hello durch Aufruf der narrow() Methode der zugehörigen Hilfsklasse (HelloHelper) gecastet werden muss. Anschließend kann das Serverobjekt gemäß seinem Interface vom Client verwendet werden (helloRef.sayHello()). Clemens Düpmeier,

88 Aufruf RMI-IIOP Beispiel
// start des Nameservers start orbd -ORBInitialPort 1050 // start des Servers java classpath . -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://localhost:1050 HelloServer // start des Clients java -classpath . -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://localhost:1050 HelloClient Clemens Düpmeier,

89 Was ist InitialContext()?
Zugriff auf einen initialen Namenskontext (Context) eines Namensdienstes über die JNDI-API Java Native Directory Interface (JNDI) Ein JNDI Namenskontext ist eine Menge von JNDI-Namen-zu-Objekt Mappings Jeder Kontext kann weitere Kontexte enthalten (Hierarchische Struktur von Kontexten möglich) Clemens Düpmeier,

90 Context Interface javax.naming.Context
void bind(Name name, Object object) void bind(String name, Object object) Context createSubContext(Name name) Context createSubContext(String name) Object lookup(Name name) Object lookup(String name) void rebind(Name name, Object object) void rebind(String name, Object object) Die InetAddress Klasse enkapsuliert in Java Internet Hostaddressen ( ), also IP-Adressen. Sie besitzt statische Methoden (z.B. getByName() und getLocalHost()), um solche Adressobjekte zu erzeugen und nicht-statische Methoden, um sich verschiedene Repräsentationsformen der Adresse von einem Adressobjekt zurückgeben zu lassen. Achtung: In getByName() kann man Hostnamen, also mailhost.iai.fzk.de, aber auch Adressen in Dotted-Form also als String angeben, um ein zugehöriges Adressobjekt zu erhalten. getHostName() liefert den Hostnamen (übrigens nicht unbedingt in kanonischer, also Langform mit allen Domain: hiefür gibt es eine weitere Methode) getHostName als String die IP-Adresse in Dotted-Form und getAddress() liefert die IP-Adresse als Array von 4-Bytewerten. Clemens Düpmeier,

91 Wie bekomme ich initialen Context?
Context ctx = new InitialContext() // falls INITIAL_CONTEXT_FACTORY und PROVIDER_URL bereits definiert // z.B. durch Setzen von java.naming.* Properties // oder Hashtable env=new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); env.put(Context.PROVIDER_URL, "iiop://localhost:1050"); Context ctx=new InitialContext(env) Die InetAddress Klasse enkapsuliert in Java Internet Hostaddressen ( ), also IP-Adressen. Sie besitzt statische Methoden (z.B. getByName() und getLocalHost()), um solche Adressobjekte zu erzeugen und nicht-statische Methoden, um sich verschiedene Repräsentationsformen der Adresse von einem Adressobjekt zurückgeben zu lassen. Achtung: In getByName() kann man Hostnamen, also mailhost.iai.fzk.de, aber auch Adressen in Dotted-Form also als String angeben, um ein zugehöriges Adressobjekt zu erhalten. getHostName() liefert den Hostnamen (übrigens nicht unbedingt in kanonischer, also Langform mit allen Domain: hiefür gibt es eine weitere Methode) getHostName als String die IP-Adresse in Dotted-Form und getAddress() liefert die IP-Adresse als Array von 4-Bytewerten. Factory-Klasse definiert "Art des Namensdienstes", auf den zugegriffen werden soll PROVIDER_URL die URL zum Zugriff Clemens Düpmeier,

92 Zugriff auf JNDI-Namensdienste
CORBA konformer Namensdienst Factory: com.sun.jndi.cosnaming.CNCtxFactory URL: iiop://localhost:1050 Context ctx = new InitialContext() LDAP Directory Server Factory: com.sun.jndi.ldap.LdapCtxFactory URL: ldap://localhost:389/o=MyOrg DirContext ctx=new InitialDirContext() Clemens Düpmeier,

93 RMI-IIOP / JNDI / EJB EJB (Enterprise Java Beans) können RMI-IIOP basierte entfernte Schnittstelle anbieten Zugriff von Clientseite erfolgt dabei typischer Weise über JNDI Context ctx = new InitialContext(); Object ref=ctx.lookup("Calculator/remote"); CalculatorRemote rechner=(CalculatorRemote)PortableRemoteObject .narrow(ref, CalculatorRemote.class); System.out.println("2 + 5 =" + rechner.add(2,5)); Clemens Düpmeier,

94 Namens- und Verzeichnisdienste
Clemens Düpmeier,

95 Namensdienst bind (Name, Zugriffsinf.) lookup("name")
Adresse / Zugriffsinform. Adresse / Zugriffsinform. P Resource Zugriff auf Resource Ein Namensdienst (Naming Service) bildet Namen auf Zugriffsinformationen (Adressen) zum Zugriff auf Ressourcen ab Den Vorgang der Zuordnung eines Namens zur Zugriffsinformation nennt man Binden (bind) Clemens Düpmeier,

96 Warum Namensdienste Entkoppelung des Zugriffs auf eine Resource von den Adressierungsdetails erhöht die Konfigurierbarkeit (Adressdetails nicht hardcodiert in Client) schafft Ortstransparenz – d.h. Resourcen können relokiert werden ermöglicht Lastverteilung Es können administrative Entscheidungen zum Resource-Management getroffen werden, ohne die Clients neu compilieren zu müssen Clemens Düpmeier,

97 Was ist ein Name Namen können verschiedene äquivalente Formen haben
Im Programmierkontext häufig strukturierte Objekte, i.e. Array von NamingComponent Objekten in Corba oder CompoundName, CompositeName in JNDI lassen sich typischer Weise äquivalent auch durch Strings beschreiben, z.B. als "cn=HomeDir,cn=John,ou=Marketing,ou=East" oder "ejb/Calculator/Remote" oder Benötigen zur Interpretation einen Kontext, in dem die Namensauflösung stattfindet Clemens Düpmeier,

98 Was ist die Adresse (Zugriffsinformation)
definiert alle für den Zugriff auf die Resource notwendigen Informationen Je nach Kontext und Anwendungssituation nahezu beliebig Kann physikalische Adresse sein: IP-Adresse Kann Name bzgl. eines anderen Namensdienstes oder Auflösungssystem sein Oder Kombination von beiden Oder Objektreferenz In objektorientierten Systemen häufig wieder in Form von Objekten gekapselt z.B. DataSource-Objekte zum Zugriff auf Datenbanken Oder entfernte Objektreferenz oder direkt serialisiertes Proxyobjekt Clemens Düpmeier,

99 Kontext Der Kontext eines Namensdienstes definiert bzw. enthält
Die Menge der erlaubten Namen (Namensraum) Die Menge der Bindings, die Namen an zugehörige Resourcen bindet Er hat typischer Weise wieder einen Namen und kann als Resource innerhalb eines übergeordneten Kontextes beschrieben sein Clemens Düpmeier,

100 Hierarchische Kontexte
Kontext "Root oder InitialContext" zugehöriger Name: Kunde/Privatkunde/"Peter Meier" Kontext "Kunde" Kontext "Privatkunde" Kontext "Geschäftskunde" Namen können hierarchisch strukturiert sein Jede Teilkomponente des Namens wird über eigenen Kontext aufgelöst Kontexte können mit gleichen Namensräumen oder vollständig unterschiedlichen Namensräumen arbeiten Clemens Düpmeier,

101 Zusammenspiel mehrerer Namensdienste (Federation)
zugehöriger Name: DNS-Service Benutzerverwaltung Nutzername Domainname Namen können als zusammengesetzte Namen Komponenten haben, die über verschiedene Namensräume definiert sind Zur Auflösung müssen verschiedene Dienste oder Kontext-Provider zusammenspielen (Federation) Clemens Düpmeier,

102 Beispiele für Namensdienste / -räume
DNS (Domain Name Service)-Dienst mailhost.iai.fzk.de User-Namen-, Gruppennamenauflösung in Rechnern typischer Weise über Verzeichnisdienste, siehe später, wie YP, NIS oder LDAP -Adressen RPC-registry, RMI-registry, CORBA-Namensdienst rmi://servername/objektname Clemens Düpmeier,

103 Verzeichnisdienste Ein Verzeichnisdienst ist ein Namensdienst, der
Resourcen neben den physikalischen Adressen weitere beschreibende Metadaten zuordnet oder auch nur beschreibende Metadaten für eine Resource bereitstellt (Metadatendienst oder Metaverzeichnis) Clemens Düpmeier,

104 Typische Verzeichnisdienste
YP (Yellow Page)-Dienst, NIS (Network Informationsdienst) für Betriebssysteme lösen Anfragen nach Rechnern, Usern, Zugriffsrechten, Druckern, Netzwerkdateisystemen, etc. auf LDAP (Leigweight Directory Service Access Protocol) Services dieselben Informationen wir bei YP, NIS darüberhinaus Organisationsdaten Organsiation, Unterorganisation, Mitarbeiter inklusiver Telefonnummer, etc. beliebige weitere Objekte, insbesondere häufig als Verzeichnisdienst für entfernte Objekte, Datenbankresourcen, etc. eingesetzt UDDI-Verzeichnisse für Web-Services Clemens Düpmeier,

105 Beispiel LDAP-Server Lightweight Directory Access Protocol (LDAP)
Spezifiziert in RFC 2251 Protokoll zum Zugriff auf Verzeichnisdienste, die auf Basis von OSI X.500 arbeiten (ASN.1 codierte Daten) Namensbeschreibung hierarchisch in der Gestalt "cn=HomeDir,cn=John,ou=Marketing,ou=East" Unter Namen können beliebige LDAP-Objekte (beschrieben durch Attributname-Value Paare) gespeichert werden flexibles Typsystem erlaubt hier beliebige Typen für Attribute eigene Erweiterungen der Schema für LDAP-Objektklassen über Schemabeschreibungssprache möglich Definiert Security-Interfaces, etc und weitere Infrastrukturdienste Clemens Düpmeier,

106 binäres Bild Clemens Düpmeier,

107 Review – Was ist JNDI? Universelle Client-seitige Java-Schnittstelle zum Zugriff auf Namensdienste unterstützt alle möglichen Arten u.a. DNS, etc. LDAP-Verzeichnisdienste Namens- und Verzeichnisdienste von Business-Obektservern besitzt eine Art von Treiberschnittstelle zum Zugriff auf konkrete Dienste siehe Folie: wie bekomme ich einen Initial-Kontext Clemens Düpmeier,

108 Zentrale Schnittstelle: Context Interface
javax.naming.Context void bind(Name name, Object object) void bind(String name, Object object) Context createSubContext(Name name) Context createSubContext(String name) Object lookup(Name name) Object lookup(String name) void rebind(Name name, Object object) void rebind(String name, Object object) Die InetAddress Klasse enkapsuliert in Java Internet Hostaddressen ( ), also IP-Adressen. Sie besitzt statische Methoden (z.B. getByName() und getLocalHost()), um solche Adressobjekte zu erzeugen und nicht-statische Methoden, um sich verschiedene Repräsentationsformen der Adresse von einem Adressobjekt zurückgeben zu lassen. Achtung: In getByName() kann man Hostnamen, also mailhost.iai.fzk.de, aber auch Adressen in Dotted-Form also als String angeben, um ein zugehöriges Adressobjekt zu erhalten. getHostName() liefert den Hostnamen (übrigens nicht unbedingt in kanonischer, also Langform mit allen Domain: hiefür gibt es eine weitere Methode) getHostName als String die IP-Adresse in Dotted-Form und getAddress() liefert die IP-Adresse als Array von 4-Bytewerten. Clemens Düpmeier,

109 Wie bekomme ich nochmal einen Root-Kontext?
Context ctx = new InitialContext() // falls INITIAL_CONTEXT_FACTORY und PROVIDER_URL bereits definiert // z.B. durch Setzen von java.naming.* Properties // oder Hashtable env=new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); env.put(Context.PROVIDER_URL, "iiop://localhost:1050"); Context ctx=new InitialContext(env) Die InetAddress Klasse enkapsuliert in Java Internet Hostaddressen ( ), also IP-Adressen. Sie besitzt statische Methoden (z.B. getByName() und getLocalHost()), um solche Adressobjekte zu erzeugen und nicht-statische Methoden, um sich verschiedene Repräsentationsformen der Adresse von einem Adressobjekt zurückgeben zu lassen. Achtung: In getByName() kann man Hostnamen, also mailhost.iai.fzk.de, aber auch Adressen in Dotted-Form also als String angeben, um ein zugehöriges Adressobjekt zu erhalten. getHostName() liefert den Hostnamen (übrigens nicht unbedingt in kanonischer, also Langform mit allen Domain: hiefür gibt es eine weitere Methode) getHostName als String die IP-Adresse in Dotted-Form und getAddress() liefert die IP-Adresse als Array von 4-Bytewerten. Factory-Klasse definiert "Art des Namensdienstes", auf den zugegriffen werden soll PROVIDER_URL die URL zum Zugriff Clemens Düpmeier,

110 Und wie frage ich eine Resource ab?
JNDI-Verzeichnisse können (je nach Art) eine Vielzahl von Resourcen zurückliefern Datenbanken stellen solche Resourcen da Man kann den Zugriff auf eine Datenbank durch DataSource-Objekte kapseln (Verbindungsdetails) Und diese in Verzeichnissen bereitstellen Context ctx = new InitialContext(); DataSource ds= (DataSource)ctx.lookup("jdbc/mondialDB"); Connection con = ds.getConnection(); Clemens Düpmeier,

111 Und wie war das nochmal mit Entfernten Objekten?
EJB (Enterprise Java Beans) können RMI-IIOP basierte entfernte Schnittstelle anbieten Zugriff von Clientseite erfolgt dabei typischer Weise über JNDI Context ctx = new InitialContext(); Object ref=ctx.lookup("Calculator/remote"); CalculatorRemote rechner= (CalculatorRemote)ctx.lookup(" Calculator/remote "); System.out.println("2 + 5 =" + rechner.add(2,5)); Clemens Düpmeier,

112 Zusammenfassung Namensdienste eignen sich herorragend dazu, um Resourcen von ihren Clients zu entkoppeln Resourcen können logisch benannt werden Applikationen werden dadurch ortstransparent Mit Namensdiensten kann man Lastverteilung / Skalierbarkeit erreichen Client muss Adressdetails nicht kennen und diese können konfigurierbar gehalten werden Der Client wird von Implementierungsdetails entkoppelt Durch Anwendung des Proxy-Design-Patterns kann man Server-seitige Resourcemanagement Funktionalitäten integrieren und rekonfigurieren, ohne die Clients neu übersetzen zu müssen Clemens Düpmeier,


Herunterladen ppt "Verteilte Kommunikation oberhalb der Socket-API"

Ähnliche Präsentationen


Google-Anzeigen