Stand 11-2005 Institut für Systemarchitektur Lehrstuhl Rechnernetze (Komplex-)Praktikum Rechnernetze Komplex II Programmierung verteilter Anwendungen Praktikumsversuch CORBA - Standardplattformen für verteilte Anwendungen – Praktikumsdokumentation -1- Stand 11-2005 1 2 3 Der CORBA Standard .................................................................................................- 3 1.1 OMG ...................................................................................................................... - 3 - 1.2 Objektmodell ........................................................................................................- 3 - 1.3 Referenzmodell .....................................................................................................- 4 - 1.4 CORBA-Spezifikation .......................................................................................... - 5 - 1.4.1 CORBA-Objektmodell ...................................................................................- 6 - 1.4.2 Interface Definition Language (IDL) ............................................................. - 6 - 1.4.3 Object Request Broker (ORB) .......................................................................- 8 - 1.4.4 Ablauf einer Anforderung (Request) .............................................................. - 9 - 1.4.5 Objektadapter ............................................................................................... - 12 - CORBA-Beispiel in Java ............................................................................................... 16 2.1 Vorgehen bei der Implementierung ...................................................................... 16 2.2 Schnittstellenbeschreibung mit IDL ..................................................................... 16 2.3 Implementierung der Schnittstelle ....................................................................... 17 2.4 Implementierung des Servers ................................................................................ 18 2.5 Implementierung des Clients................................................................................. 19 2.6 Starten des Beispiels ............................................................................................... 20 Der Versuch .................................................................................................................... 21 3.1 4 Versuchsbeschreibung ........................................................................................... 22 3.1.1 bereitgestellte Programmkomponenten ............................................................ 22 3.1.2 erforderliche Erweiterungen/Implementierungen ............................................ 22 3.2 Starten des Versuchs .............................................................................................. 23 3.3 Sicherung der Versuchsergebnisse ....................................................................... 23 Literatur .......................................................................................................................... 24 -2- Stand 11-2005 1 Der CORBA Standard Die Common Object Request Broker Architecture (CORBA) ist ein Standard für eine objektorientierte Middleware zur Realisierung von verteilten Anwendungen. Zentraler Bestandteil von CORBA ist der Object Request Broker (ORB), eine Softwarekomponente, die Aufrufe von Clientobjekten erhält und diese an die entsprechenden Zielobjekte übermittelt. Befinden sich diese Objekte auf unterschiedlichen Rechnern, werden zwei ORB’s in die Aktion einbezogen. Der ORB des Clients sendet den Aufruf über das Netzwerk zum ORB des Zielobjektes, welcher den Aufruf an das Zielobjekt selbst übermittelt. Die Funktionalität der Netzwerkzugriffe ist vollständig im ORB enthalten. Zugriffe auf entfernte Objekte unterscheiden sich nicht von lokalen Objektzugriffen (Verteilungstransparenz). Dies ist die grundlegende Idee der Common Object Request Broker Architecture. In der Folge wird ausgehend von dem Modell der Objektorientierung CORBA beschrieben und in seinen Eigenschaften dargestellt. 1.1 OMG Der Standard der Common Object Request Broker Architecture -Spezifikation wurde durch die OMG (Open Management Group) [1] definiert. Unter den Mitgliedern dieser Organisation befinden sich nicht nur namhafte Softwarehersteller (IBM, Hewlett-Packart, Philips Telecommunications, Microsoft, Sun Microsystems, Digital Equipment u.a.), sondern auch Anwender, Forschungsinstitutionen und staatliche Einrichtungen. Die OMG verfolgt das Ziel der Erstellung und Verbreitung eines akzeptierten objektorientierten Standards, der auf kommerzieller oder freier Software basiert und die Wiederverwendbarkeit von Komponenten sowie die Interoperabilität und Portabilität von Anwendungen garantieren soll. Die erste Arbeit der OMG war die Spezifikation der Object Management Architecture (OMA) [2]. In der OMA wurden als Grundlage für alle weiteren Standardisierungen der Integration von Anwendungen das Objektmodell und das Referenzmodell definiert. 1.2 Objektmodell Das Objekt bildet die Grundlage des Kernmodells. Ein Objekt kann ein Konzept oder ein Gegenstand sein. Jedes Objekt ist einmalig. Diese Einmaligkeit wird durch die Objektidentität erreicht, die das Objekt charakterisiert. Diese Identität ist unabhängig von den Eigenschaften des Objektes und bleibt über die gesamte Lebenszeit des Objektes unverändert. An jedes Objekt sind Operationen (methods) gebunden. Eine Operation beschreibt häufig eine parametergesteuerte Aktion und besitzt eine Signatur. Die Signatur besteht aus Operationsnamen, Parameterliste und Resultatliste. Der Operationsaufruf (Request, Anforderung) wird von einem Client gestartet und auf Serverseite ausgeführt. Auf das Objekt anwendbare Objektklassen typisieren das Objekt. Die so entstandenen Objekttypen können vererbt werden. Um Vererbung handelt es sich, wenn ein Typ X alle Operationen von einem Typ Y erhält und für seinen Bedarf erweitert. Dabei muß eine Beziehung zwischen Typ X und Y bestehen. Die Besonderheit der Vererbung des KernModells gegenüber der aus vielen Programmiersprachen bekannten Vererbung besteht darin, -3- Stand 11-2005 daß alle Operationen exportiert (vererbt) werden. Es entfällt somit die Möglichkeit der Unterscheidung in public (exportierbare) Operationen und private (nicht exportierbare) Operationen. Ebenfalls ist kein Überlagern (Überschreiben) von geerbten Operationen möglich. Alle Operationen werden an der Schnittstelle (Interface) in der Interface Definition Language (IDL) deklariert. 1.3 Referenzmodell Das Referenzmodell stellt die Gesamtarchitektur des verteilten Systems von Objekten dar [2]. Diese Gesamtarchitektur wird als Grundlage für die Entwicklung der einzelnen Spezifikationen genutzt. Im Gegensatz zu allen bisherigen Client-/Server-Architekturen geht die OMG bei der OMA nicht von einer direkten Verbindung von Client und Server aus, sondern führt für die Client-Server-Kommunikation eine eigene Ebene, den ORB (Object Request Broker) ein. Das in Abbildung 1.1 dargestellten Referenzmodell der OMA zeigt die Ebenenstruktur. Die abgebildete Architektur ist eine Busarchitektur, die das System in einzelnen Komponenten zerlegt. Common Facilities CIM Accounting Mapping Vertical Facilities Applications Objects Horizontal Facilities Task Systems Information Management Management User Management Buisiness Interface Objects ORB (Object Request Broker ) CORBA-Services Abbildung 1.1: Die Object Management Architecture (OMA) Der ORB bildet die Hauptkomponente des Referenzmodells [3]. Aus der Busstruktur resultiert, daß die Kommunikation zwischen Objekten ausschließlich über den ORB erfolgt. Die kommunizierenden Objekte verhalten sich dabei wie Client und Server. Ziel des ORB ist eine vollständige Zugriffstransparenz aus Sicht des Clients, lokaler und entfernter Aufruf sollen für diesen keinen Unterschied aufweisen. -4- Stand 11-2005 Die weiteren vier im Referenzmodell dargestellten Komponenten sind die CORBAServices die horizontalen und vertikalen CORBAFacilities sowie die Application Objects [3]. Alle Dienste, die in diesen Komponenten enthalten sind, sind in Objekten gekapselt und die Nutzung der Dienste erfolgt über den Aufruf ihrer Objektmethoden. Komponente Beschreibung Bestandteile Application Objects Alle Anwendungsspezifischen Objekte (nicht Gegenstand der Standardisierung) Horizontal Facilities Generische Dienste, die in einer Vielzahl von Anwendungen genutzt werden User Interface, Information Management, Systems Management, Task Management Verticale Facilities Dienste, die in speziellen Anwendungsbereichen verwendet werden Imagery, Information Superhighways, Manifacturing, Distributed Simulation, Oil and Gas Industry Exploitation and Production, Accounting, Application Development, Mapping Object Request Broker Kommunikationskanal zur Interaktion der Komponenten Objektmodell, IDL, Language Mapping, Client Stubs, Dynamic Invocation Interface, Implementation Skeleton, Dynamic Skeleton Interface, Object Adapters, ORB-Interface, Interface Repository, Implementation Repository CORBA-Services Basisdienste Bestandteil jeder ORBImplementierung Naming Service, Event Service, LifeCycle Service, Persistent Object Service, Transaction Service, Concurrency Control Service, Relationsship Service, Externalization Service, Query Service, Licensing Service Property Service, Time Service, Security Service, Object Trader Service, Object Collections Service Tabelle 1.1: Komponenten des OMA-Referenzmodells Die Spezifikation beinhaltet nur die Schnittstellen und Protokolle zur Objektkommunikation, keine Implementierungsdetails. Es erfolgt somit eine Trennung von Schnittstelle und Implementierung, die für alle Objekte einer CORBA-Umgebung gilt. 1.4 CORBA-Spezifikation Die CORBA-Spezifikation bildet den Hauptteil des Referenzmodells der Object Management Architecture. Dies gilt besonders für die Festlegung des ORB (Object Request Broker). Weitere in der CORBA-Spezifikation enthaltene Definitionen sind das erweiterte Objektmodell (CORBA-Modell), die IDL (Interface Definition Language), die unterschiedlichen Sprachanbindungen (Language Mapping) und die Möglichkeiten der Interoperabilität sowie die zugehörigen Protokolle. -5- Stand 11-2005 1.4.1 CORBA-Objektmodell Dieser Teil der Spezifikation beschreibt das konkrete Objektmodell auf dem die CORBAArchitektur basiert. Es wurde vom abstrakten Kernmodell (Core Object Model) abgeleitet, das im Object Management Architecture Guide der OMG definiert ist. Konzepte, die von CORBA unterstützt werden, sind in diesem Modell spezifiziert. Das CORBA-Objektmodell ist ein Client-/Server-Modell, deshalb bezeichnet es die einschlägige Literatur als „klassisches Objektmodell“. Dabei wird von folgendem Szenario ausgegangen: 1. Der Client sendet eine Nachricht an ein Objekt. 2. Das betroffene Objekt empfängt die Nachricht. 3. Es interpretiert die Nachricht und handelt entsprechend (führt Aktionen aus). 4. (Sendet eventuell Antwort zurück.). Durch die klare Rollenvergabe und Trennung der Anwendungsbestandteile ist es möglich, den Dienstanbieter (Server, Provider) vom Dienstnutzer (Client) durch eine Schnittstelle abzukapseln. Das CORBA-Objektmodell erbt zur Erfüllung dieser Kapselung vom KernModell die Konzepte für Objekte, Operationen, Operationsnamen, Signaturen, Parameter, Parametertypen, Typen, Anforderungen, Resultate und Vererbung. 1.4.2 Interface Definition Language (IDL) Damit ein Client in die Lage versetzt wird, eine entfernte Funktionalität nutzen zu können, muss er die Aufrufsemantik einer Funktion oder Methode eines entfernten Objektes kennen. Im Beispiel von Java-RMI wird zur Beschreibung dieser Semantik der Javaeigene Mechanismus der Interfaces verwendet. Da die OMG mit CORBA allerdings ein verteiltes System schaffen wollte, das sprachunabhängig ist, musste ebenso eine sprachunabhängige Möglichkeit der Beschreibung von Schnittstellen gefunden werden. Zu diesem Zweck wird die OMG Interface Definition Language (IDL) eingesetzt. Dabei handelt es sich um eine beschreibende Sprache, die keinerlei Konstrukte für die Implementierung von Algorithmen enthält. Die in dieser Sprache gemachte Spezifikation der Schnittstelle wird durch einen IDLCompiler in die bei der Implementierung verwendete Sprache übersetzt. Es ist dabei sogar möglich, dass Client und Server in unterschiedlichen Sprachen programmiert werden und dennoch die gleiche IDL-Repräsentation des Interfaces zu den verteilten Objekten nutzen. Jede Sprache, für die Sprachanbindungen standardisiert wurde, erhält ein Language Mapping Dokument. In der Version 3.0 enthält die CORBA-Spezifikation Standard-Mappings zu den Sprachen C, C++, Java, Smalltalk, COBOL, Ada, Lisp, PL/1, Python und IDLscript. Spezifikationen für eine Reihe weiterer Sprachen sind außerhalb der Standardisierung verfügbar. Zudem existieren einige standardisierte Mappings von einer Programmier- oder Beschreibungssprache auf OMG IDL, wie beispielsweise ausgehen von Java, XML oder MOF 2.0. Die jeweilige Sprachanbindung enthält Definitionen für alle Elemente, die für die Nutzung des ORB nötig sind. Es sind somit folgende Definitionen im Language Mapping enthalten: - Konstanten der IDL Basistypen der IDL Strukturierte Datentypen Ausnahmebehandlungen Zugriffe auf Attribute -6- Stand 11-2005 - Objektreferenzen Aufrufe von Operationen und deren Parameter Abbildung 1.2: Übersetzung der IDL Bei der Übersetzung kann es vorkommen, dass Umgehungslösungen geschaffen werden müssen, da ein spezielles Element aus der IDL nicht direkt in die entsprechende Programmiersprache abgebildet werden kann. Beispiele dafür stellen bestimmte primitive Datentypen oder die Angabe von Referenzparametern als Methodenattribute dar. Zur Beschreibung einer Schnittstelle dient das IDL-Konstrukt „interface“, in dessen Rumpf die zugehörigen Methoden deklariert werden. Bei der Angabe der Parameter existieren die Möglichkeit Eingabeparameter mit dem Schlüsselwort in, Ausgabeparameter mit dem Schlüsselwort out oder beide Übergaberichtungen mit dem Schlüsselwort inout anzugeben. Ein Eingabeparameter ist dabei ein ganz normaler Parameter, der beim Methodenaufruf vom Client zum Server übergeben wird. Ein Ausgabeparameter bietet dem Client die Möglichkeit, vom Server Daten in einer bestimmten Speicherposition abzulegen. Ein Beispiel für die Definition einer Schnittstelle ist: interface Beispiel{ string Methode1(in short param1); long Methode2(in string param2); }; -7- Stand 11-2005 Dadurch wird ein Interface Beispiel angelegt, das zwei Methoden bereitstellt. Methode1 muss dabei ein short-Wert übergeben werden und sie liefert einen String als Rückgabe. Methode2 hingegen bekommt einen String als Parameter und liefert als Rückgabe einen long-Wert. Nach der Deklaration wird die IDL-Datei wie bereits erwähnt mit einem IDL-Compiler auf die jeweiligen Sprachen abgebildet, in denen Client und Server implementiert werden sollen. Bei den Typangaben ist darauf zu achten, auf welchen Datentyp der Programmiersprache diese jeweils abgebildet werden. Beispielsweise wird ein IDL-long-Wert auf einen int-Wert in der Sprache Java gemappt. Meistens allerdings liegen gleichnamige Typabbildungen vor. Mit Hilfe der IDL kann neben der Beschreibung der Schnittstelle auch die Beschreibung von Objekten erfolgen, die als Methodenparameter und Rückgabewerte fungieren sollen. Dieses geschieht in IDL Syntax mit dem Bezeichner „struct“, in dessen Rumpf die Attribute des Objekts angegeben werden. struct ObjectParameter{ string attribute1; short attribute2; }; Aus dem Beispiel würde bei der Übersetzung auf eine Programmiersprache eine Klasse namens „ObjectParameter“ entstehen, die zwei Attribute, einen String und einen short-Wert aufweist. Sie kann in der Folge als Parameter oder Rückgabewerte von Methoden einer Schnittstelle verwendet werden. 1.4.3 Object Request Broker (ORB) Der ORB bildet das Kernstück des Referenzmodells. Seine Aufgabe besteht darin, die Verteilung für den Client transparent zu gestalten. Dazu kapselt er jegliche Kommunikation zwischen Client und Server. Um das zu realisieren, muß er folgende Punkte organisieren: Erzeugung und Vernichtung von Objektreferenzen, Vermittlung zwischen verteilten Objekten und Organisation der Kommunikation vom Client zum Server und zurück. Dadurch wird der Client von allen die Kommunikation betreffenden Fragen, wie zum Beispiel Lokation von Servern und Auswahl eines Übertragungsprotokolls, entbunden. CORBA ist die für alle Mitglieder der OMG verbindliche Definition des ORB, welcher in der OMA bereits abstrakt beschrieben wurde. Jedes CORBA-System läßt sich in drei abstrakte Teile zerlegen (Abbildung 1.3). Diese drei Teile sind der Client, die Objektimplementierung und der ORB. Client Object Implementation ORB (Object Request Broker) -8- Stand 11-2005 Abbildung 1.3: Objektaufruf über den ORB Dabei wird der ORB nochmals in: den Kern (ORB Core), die dynamische Aufrufschnittstelle (DII, Dynamic Invocation Interface), den statischen IDL Stub (Client Stub), die ORB-Schnittstelle (ORB Interface), das statische Implementierungsskelett (SIS, Skeleton) des Servers, das dynamische Implementierungsskelett (DSI, Dynamic Skeleton Interface) und den Objektadapter (OA, Object Adapter) aufgeteilt. Diese Teile sind in Abbildung 1.4 dargestellt. Im Konzept der OMG fällt den Schnittstellen eine große Bedeutung zu, denn nur sie und das Dienstverhalten werden standardisiert. Client DII statischer IDLStub Objektimplementierung ORB Schnittstelle DSI SIS Objekt Adapter ORB Kern Schnittstelle (ORB-unabhängig) Schnittstelle pro Objektmethode Schnittstelle pro Objekt Adapter ORB abhängige Schnittstelle Abbildung 1.4: Struktur der Schnittstellen für Objektaufrufe 1.4.4 Ablauf einer Anforderung (Request) Beim Betrachten des Ablaufs einer Anforderung empfiehlt es sich, von zwei verschiedenen Sichtweisen auszugehen. Das ist zum einen die Sichtweise des Client und zum anderen die der Objektimplementierung. Die Beschreibung beginnt mit dem Client, der die Aufrufe absetzt. Sichtweise des Clients: Um eine Anforderung zu starten, kann der Client das DII (Dynamic Invocation Interface) oder einen vom Compiler für eine IDL-Schnittstellenbeschreibung generierten Stub nutzen -9- Stand 11-2005 (Abbildung 1.5). Dabei ist zu beachten, daß für die Objektimplementierung beide Aufrufarten identisch sind, da sie sich nur in der Art ihrer Erzeugung unterscheiden. Ein Client benötigt zum Aufrufen eines Dienstes dessen Objektreferenz, den Methodennamen und die Parameterliste. Diese drei Elemente werden als Signatur bezeichnet. Um die für Anwendungsprogrammierer einfacher zu bedienende Version der Anforderung den Stub - nutzen zu können, muß bereits zur Übersetzungszeit das Interface des gewünschten Objekts bekannt sein. Eine nachträgliche Stubgenerierung ist nicht möglich. Diese Einschränkung macht das System weniger flexibel, denn Änderungen erfordern eine erneute Übersetzung des Client. Nutzt der Client jedoch das DII, so kann er auch zur Laufzeit Anforderungen an neue Objektimplementationen erzeugen. Dabei stehen ihm zwei Aufrufmechanismen zur Verfügung: der synchrone Aufruf und der aufgeschoben synchrone Aufruf. Bei letzterem besteht die Möglichkeit, die Ergebnisse des Aufrufs zu untersuchen. Die zur Erzeugung benötigten Informationen entnimmt der Client dabei dem Interface Repository. Dieses Interface enthält Informationen über die Schnittstellenbeschreibung von Objekten. Im Gegensatz dazu befinden sich im Implementation Repository Informationen für die Lokalisierung und Aktivierung von Objektimplementationen. Client Request DII statischer IDLStub ORB Schnittstelle ORB Kern Abbildung 1.5: Objektaufruf aus Client-Sicht Die Erzeugung eines dynamischen Aufrufs erfolgt in folgenden Schritten (siehe auch Abbildung 1.6): 1. Ermitteln des Zielobjekts 2. Ermitteln der Objektschnittstellen, insbesondere des Methodennamens 3. Erstellen der dynamischen Anfrage 4. Absetzen der dynamischen Anfrage an das DII 5. Weiterleiten der Anfrage durch das DII an den ORB 6. Empfangen des Ergebnisses nach Bearbeitung durch die Implementierung über den DII. - 10 - Stand 11-2005 Client ORB create_request invoke_send get_response DII add_arg Abbildung 1.6: Erstellung von Aufrufstrukturen mittels DII Der Client hat ebenfalls die Möglichkeit, direkt über die ORB-Schnittstelle mit dem ORB zu kommunizieren. Dies ist jedoch nur für bestimmte Sonderfälle (z.B. Konvertierungen von Objektreferenzen in Zeichenketten und zurück) sinnvoll. Sichtweise der Objektimplementierung: Um eine Anforderung erfüllen zu können, muß der ORB die entsprechende Objektimplementierung der gewünschten Objektmethode finden. Wenn die Implementierung auf dem Server noch nicht existiert, muß ein Server mit der betroffenen Objektimplementierung gestartet und das Objekt aktiviert werden. Diese Aufgabe und die Deaktivierung des Servers übernimmt der Objekt Adapter. Zur Suche nach der Implementierung nutzt der ORB das Implementation Repository, in dem die Startdaten des Servers verwaltet werden. Ist ein aktiver Server mit dem gesuchten Objekt vorhanden, werden die Anforderung und die zugehörige Parameterliste an die Objektimplementation übermittelt und dort die Methode ausgeführt. Wie auch beim Client bestehen hier zwei Möglichkeiten der Aufrufweiterleitung (Abbildung 1.7). Die erste - der IDL-Skeleton - ist das direkte Gegenstück zum IDL-Stub. Die andere Möglichkeit führt über das DSI, eine standardisierte Schnittstelle, die zum Beispiel für die Entwicklung von Interoperabilitätsbridges genutzt werden kann. Natürlich kann die Objektimplementierung auch direkt auf den ORB zugreifen. Objektimplementierung Request ORB Schnittstelle DSI SIS Objekt Adapter ORB Kern Abbildung 1.7: Objektimplementierungssicht Das ORB Interface enthält eine Reihe von Definitionen von Operationen, die für alle Objekte gültig sind, und Definitionen von allgemeinen Operationen. Beispiele dafür sind die Konvertierung von Objektreferenzen in Zeichenketten und zurück. - 11 - Stand 11-2005 Die auf alle Objekte anwendbaren Operationen sind im Interface Object enthalten. In diesem Interface befinden sich unter anderem Operationen, die zur Überprüfung von Objekten und ihren Referenzen dienen. Übertragung von Daten Der Weg zwischen den beteiligten ORBs auf Client- und auf Serverseite wurde bis hierhin ausgelassen. Die Kommunikation zwischen ihnen setzt ein für beide bekanntes Protokoll voraus, damit zum einen der Server die Information erhält, welche Operation auf welchem Objekt mit welchen Parametern aufgerufen wurde und der Client die erhaltene Rückgabe interpretieren kann. Zu diesem Zweck hat die OMG das auf TCP/IP aufsetzende Internet Inter ORB Protocol (IIOP) mit der CORBA-Version 2.0 standardisiert, über das somit auch ORBs unterschiedlicher Hersteller kommunizieren können. Zwar verwenden manche ORBImplementierungen nach wie vor proprietäre Protokolle, allerdings muss das IIOP von jedem standardkonformen ORB unterstützt werden. Abbildung 1.8: Internet Inter ORB Protocol 1.4.5 Objektadapter Der Objektadapter ist für jede Objektimplementation zugänglich und bietet ihr grundlegende Dienste, wie zum Beispiel die Erzeugung und Interpretation von Objektreferenzen. Ebenfalls der Objektadapter realisiert das Aktivieren und Deaktivieren von Servern (Prozessen) sowie die Registrierung von Objektimplementationen. Eine weitere Aufgabe besteht in der Sicherung von Interaktionen. Der Objektadapter ist ein spezialisierter Baustein, der bei der Erstellung der Objektimplementation zum ORB hinzugefügt werden kann, wenn dies erforderlich ist. Da das von ihm betreute Gebiet sehr komplex ist - es gibt viele Mechanismen zur Realisierung der Aufgaben des Adapters - können unmöglich alle Funktionen in einer Schnittstelle spezifiziert werden. Deshalb läßt die OMG mehrere Objekt Adapter zu, aus denen der günstigste gewählt werden kann. Es wird jedoch davon ausgegangen, daß es nur eine beschränkte Anzahl geben wird. Bis jetzt wurden von der OMG zwei Objekt Adapter standardisiert. Zum einen der BOA (Basic Object Adapter) und zum anderen der POA (Portable Object Adapter). Beim BOA handelt es sich um den ursprünglichen Standard Objekt Adapter, der in jedem ORB vorhanden sein mußte. Da er für einige verteilten Anwendungen nicht ausreichend ist, wurde der POA standardisiert, der zusätzliche Funktionen anbietet. BOA (Basic Object Adapter): Abbildung 1.9 verdeutlicht den Aufruf einer Methode unter Benutzung des BOA (BasicObjektadapters): - 12 - Stand 11-2005 Objektimplementierung 1 2 3 Methoden 5 4 Skeleton Basis Object Adapter ORB Core Abbildung 1.9: Funktion des BOA Erreicht den ORB-Kern ein Methodenaufruf, so wird dieser an den dafür zuständigen BOA weitergeleitet. Daraufhin werden folgende Schritte durchgeführt: 1. Der BOA testet, ob die Objektimplementierung, deren Methode ausgeführt werden soll, bereits aktiviert ist. Ist dies nicht der Fall, wird die Methode zuerst mit Hilfe der vom Server bereitgestellten factory aufgerufen und dadurch aktiviert. 2. Die aktivierte Methode wird für die weitere Verwendung im BOA registriert. 3. Sollte das gewünschte Objekt, das die bereits registrierte Methode anbietet nicht im Speicher vorhanden sein, so wird es importiert (z.B. aus einer Datenbank). 4. Daraufhin kann die Methode über das Skeleton aufgerufen werden. 5. Die Implementierung der Methode greift bei der Abarbeitung einer Anfrage auf weitere Methoden und Objekte zu, die vom BOA angeboten werden (z.B. zu Authentisierungs-Zwecken) Die Kommunikationsmechanismen zwischen BOA und Objektimplementierung sind nicht in der CORBA-Spezifikation enthalten, da sie sehr stark vom verwendeten Betriebssystem abhängen. Der BOA unterstützt eine oder mehrere Formen der Methodenaktivierung (Activation Policy). Es wurden vier Formen der Methodenaktivierung festgelegt (Abbildung 1.10): 1. Zunächst besteht die Möglichkeit, jede Methode in einem eigenen Prozeß zu realisieren, welcher bei der Methodenaktivierung gestartet wird (Server per Method Activation Policy), so z.B. verwendbar für Anzeige- und Transportdienste, aber ungeeignet für zustandsbehaftete Objekte. Nach Ausführung der Methode wird der Server wieder gestoppt. 2. Als zweite Variante ist vorgesehen, jedes Objekt in einem eigenen Server zu realisieren (Unshared Server Activation Policy). Die Serverlebenszeit ist gleich der Objektlebensdauer, das heißt, der Server wird mit der Aktivierung des Objekts gestartet und mit der Deaktivierung gestoppt. Ein Beispiel hierfür ist die Einbindung externer Anwendungen. 3. Die dritte Möglichkeit besteht darin, mehrere Objekte in einem Programm zu verwalten (Shared Server Activation Policy). Hierbei handelt es sich um die gebräuchlichste Strategie. Der Server wird aktiviert, wenn eine in ihm enthaltene Objektimplementierung benötigt wird. Es erfolgt jedoch keine Aktivierung, wenn ein anderer bereits aktiver Server diese Implementierung ebenfalls anbietet. - 13 - Stand 11-2005 4. Die letzte Möglichkeit ist die Persistent Server Activation Policy. Diese wird nicht vom BOA sondern von einer externen Instanz aktiviert. Nach der Aktivierung meldet er sich beim BOA an. Erfolgt eine Anforderung an einen nicht aktivierten persistenten Server, so erhält der Client eine Fehlermeldung. 1 2 3 4 BOA (Basis Object Adapter) Objekt Register Implementation Prozeß Start Prozeß Abbildung 1.10: Aktivierungsarten Die folgenden Funktionalitäten werden vom BOA unterstützt: Authentisierung des Aufrufenden, Generierung und Interpretation von Objektreferenzen, Aktivierung und Deaktivierung von Objektimplementierungen, Objektinformationen bereitstellen, Methodenaufrufe durch den Skeleton. Der Portable Object Adapter Auch wenn der BOA eine maßgebliche Entwicklung war, reichte sein Funktionsangebot dennoch für einige Anwendungsfälle nicht aus. Viele Entwickler sorgten aus diesem Grunde für eine nicht standardkonforme Erweiterung des BOA und somit entstand eine Vielzahl proprietärer Implementierungen. Als Reaktion darauf ergänzte die OMG mit der CORBASpezifikation 2.2. den Portable Object Adapter (POA), der den BOA durch seinen grossen Funktionsumfang ersetzte. Beispiele für die zusätzlichen Funktionen des POA sind dabei vor allem die Möglichkeiten, Objekte wahlweise mit transienter oder persistenter Identität realisieren zu können und flexiblere Aktivierung bzw. Deaktivierung von Objekten. Zudem war, wie der Name vermuten lässt, die Nutzung des POA in unterschiedlichen ORBImplementierungen, ohne den Adapter zu modifizieren, Ziel der Spezifikation. Der Ablauf einer Anfrage durch Clients ist analog zu dem im Vorfeld für den BOA dargestellten und ist noch einmal in Abbildung 1.11. zusammengefasst: - 14 - Stand 11-2005 Abbildung 1.11: Portable Object Adapter Bei der Verwendung des POA in einer Anwendung ist es möglich mit Hilfe von PolicyEinstellungen den Umgang mit den verwalteten Objekten genau zu spezifizieren. Dabei können detaillierte Informationen zum Zustand, zur Identität, zur Persistenz oder über den Lebenszyklus der Objekte angegeben werden. Für den weiter unten beschriebenen Praktikumsversuch genügen allerdings die Standard-Einstellungen, die beispielsweise nicht persistente Objekte mit automatischer Aktivierung durch den POA vorsehen. Nähere Ausführungen über den Policy-Mechanismus finden sich unter http://www.omg.org/gettingstarted/orb_basics.htm#j:POAPolicies und in der von dort verlinkten CORBA-Spezifikation. - 15 - 2 CORBA-Beispiel in Java In diesem Abschnitt wird anhand eines kleinen Beispiels das Vorgehen bei der Programmierung einer CORBA-Anwendung in Java dargestellt. Bei dem Beispiel handelt es sich um eine Client-Anwendung, die auf einem entfernten Objekt eine Methode zur Multiplikation zweier short-Zahlen aufruft und das Ergebnis ausgibt. Um das Beispiel testen zu können ist ein Java SDK ab der Version 1.4 notwendig, das alle erforderlichen Werkzeuge (IDL-Compiler, ORB, Namensdienst) anbietet. Zwar unterstützen auch ältere SDK-Versionen CORBA, allerdings ebenso einen älteren CORBA-Standard, in dem z.B. das Konzept des POA noch nicht verfügbar ist. 2.1 Vorgehen bei der Implementierung Bei der Implementierung einer vollständigen Anwendung auf Basis von CORBA sind grundlegend folgende Schritt durchzuführen: 1. Spezifikation der Aufrufsemantik der Methoden eines entfernten Objektes (Schnittstelle) in IDL 2. Implementierung der Schnittstelle 3. Entwicklung einer Server-Anwendung 4. Entwicklung einer Client-Anwendung 2.2 Schnittstellenbeschreibung mit IDL Die Beschreibung des Interfaces des Objektes, das die entfernte Methode anbieten soll ist in folgendem Quellcode in IDL-Syntax dargestellt: //Multiply.idl module Beispiel // entspricht Package-Begriff in Java { interface Multiply // Interface wie in Java { short mult(in short x,in short y); }; }; In dieser IDL-Datei wird ein Interface Multiply beschrieben, das als einzige Methode mult aufweist, die wiederum 2 short-Parameter besitzt und als Rückgabewert ebenfalls einen short Parameter liefert. Die Übersetzung dieser Datei in die notwendigen Programmkomponenten erfolgt mit Hilfe des Java-IDL-Compilers idlj durch folgenden Aufruf im Quellverzeichnis: $ idlj –fall Multiply.idl Die Kompilierung mit der Option –fall dient dazu, sowohl Client-Komponenten, als auch den 16 Server-Stub zu erzeugen. Wird die Option nicht verwendet, so werden ausschließlich die vom Client benötigten Komponenten erzeugt. Durch den Aufruf des Compilers wird im aktuellen Ordner ein Verzeichnis mit dem Namen „Beispiel“ angelegt, das wichtige Klassen für die Arbeit mit CORBA enthält. Die folgende Tabelle gibt Auskunft über die erzeugten Dateien samt ihrer Aufgabe: Datei Aufgabe Multiply.java Repräsentiert das Interface Multiply MultiplyHelper.java Unterstützt die Namensauflösung Aufruf der entfernten Methode MultiplyHolder.java Falls benötigt bietet diese Klasse Konvertierungsmöglichkeiten für IDLSprachkonstrukte, die in Java kein Äquivalent besitzen (inout- und out-Parameter für primitive Datentypen) MultiplyOperations.java Definiert die Methoden der Schnittstelle _MultiplyStub.java Für das entfernte Objekt spezifischer Skeleton, der vom Server verwendet wird MultiplyPOA Abstrakte Klasse, von der die Implementierung des entfernten Dienstes erben muss beim Die für das Beispiel angegebene Schnittstelle verwendet nur Sprachkonstrukte, die unmittelbar in Java übersetzt werden können. Deshalb wird eine Holder-Klasse nicht benötigt. 2.3 Implementierung der Schnittstelle Nachdem die Schnittstelle abstrakt beschrieben wurde kann sie nun implementiert werden. //MultiplyImpl.java import Beispiel.MultiplyPOA; public class MultiplyImpl extends MultiplyPOA { public short mult(short x, short y){ return (short)(x*y); } } Wichtig bei der Implementierung ist, dass diese Klasse MultiplyPOA erweitert, um von CORBA als entferntes Objekt eingesetzt werden zu können. Ansonsten handelt es sich um eine normale Java-Klasse, die ebenso im lokalen Einsatz ihre Funktion erfüllen könnte. Eine Instanz dieser Klasse auf Server-Seite wird in der CORBA-Terminologie als „Servant“ bezeichnet. 17 2.4 Implementierung des Servers Im nächsten Schritt soll der Server implementiert werden. Er hat folgende Aufgaben: 1. Erzeugen und Initialisieren eines ORB 2. Erzeugen eines entfernten Objektes (MultiplyImpl) 3. Registrieren des Objektes beim Nameserver 4. Warten auf Aufrufe durch Clients Prinzipiell gibt es für die Erledigungen dieser Aufgaben mehrere Vorgehensweisen. Eine davon ist im folgenden Progammcode dargestellt: //Server.java import org.omg.CORBA.*; import org.omg.CosNaming.*; import Beispiel.*; import org.omg.PortableServer.*; public class Server { public static void main(String[] args) { try{ ORB orb = ORB.init(args, null); POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); rootpoa.the_POAManager().activate(); MultiplyImpl multiplyImpl = new MultiplyImpl(); org.omg.CORBA.Object ref = rootpoa.servant_to_reference(multiplyImpl); Multiply href = MultiplyHelper.narrow(ref); org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); NameComponent path[] = ncRef.to_name("Multiply"); ncRef.rebind(path, href); orb.run(); } catch (Exception e) { System.err.println("ERROR: " + e); } System.out.println("Exiting ..."); } } Zuerst wird dabei ein ORB-Objekt erzeugt, das die gesamte Kommunikation zwischen Server und Client durchführen wird. Daraufhin wird für diesen ORB ein Portable Object Adapter (POA) erzeugt, bei dem eine Instanz der Klasse MultiplyImpl hinterlegt wird. Der POA ist dafür zuständig, Anfragen an diese Instanz zu verwalten und sorgt dabei für Skalierbarkeit, 18 falls mehrere Client-Anfragen auftreten. Im dritten Schritt wird unter Verwendung des ORBs der Namensdienst ermittelt. Als Parameter bekommt die entsprechende Methode den String „NameService“ übergeben, der in allen CORBA ORBs für das Ansprechen dieses Services definiert ist. Mit Hilfe des ermittelten Objektes, das den Namenskontext repräsentiert, kann nun ein Eintrag „Multiply“ erzeugt werden, hinter dem sich eine indirekte Referenz auf das MultiplyImpl-Objekt verbirgt. Es handelt sich um eine indirekte Referenz, da ein Objekt vom Typ Multiply registriert wird, das wiederum eine Referenz auf das MultiplyImpl-Objekt darstellt. Der Eintrag wird unter Verwendung der Methode rebind(…) erzeugt. Im letzten Schritt wird mit orb.run() dafür gesorgt, dass der erzeugte und initialisierte ORB auf Client-Anfragen wartet. Eine kleine Besonderheit innerhalb der Server-Klasse bildet das zweimalige Auftauchen der narrow-Methode. Diese dient dazu, eine Konvertierung von CORBA-Objekten (org.omg.CORBA.Object) auf andere Objekte oder umgekehrt zu realisieren, damit diese ihre bestimmungsgemäßen Aufgaben erfüllen können. 2.5 Implementierung des Clients Als letzter Bestandteil der verteilten Anwendung fehlt noch der Client. Er muss zum einen den Namensdienst des Servers ansprechen und über diesen das gewünschte Objekt lokalisieren und zum anderen die gewünschte Methode auf diesem Objekt aufrufen. 19 //Client.java import Beispiel.*; import org.omg.CORBA.*; import org.omg.CosNaming.*; public class Client{ static Multiply MultiplyOb; public static void main(String[] args){ try{ ORB orb = ORB.init(args, null); org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); MultiplyOb = MultiplyHelper.narrow(ncRef.resolve_str("Multiply")); short result = MultiplyOb.mult((short)3,(short)4); System.out.println("Ergebnis:"+result); } catch(Exception e){ System.out.println("ERROR : " + e) ; } } } Die Ermittlung des Namensdienstes erfolgt vollkommen analog zum Vorgehen beim Server. Interessant dabei ist, dass CORBA automatisch über die übergebenen Argumente beim Starten des Clients prüft, auf welchem Rechner der Namensdienst zu ermitteln ist. Wird hierbei eine IP als Argument angegeben, so ermittelt CORBA eine Referenz auf den Namensdienst des entfernten, ansonsten auf den des lokalen Rechners. Mit Hilfe des ermittelten Nameservices kann anschließend eine Referenz auf das entfernte Objekt, das sich unter dem Namen „Multiply“ eingetragen hat, erfragt werden. Auch beim Client kommt die narrow-Methode zum Einsatz, die wie oben beschrieben für Objektumwandlungen sorgt. In diesem Fall muss das Objekt MultiplyOb, das zunächst ein einfaches CORBA-Objekt ist mit Hilfe der MultiplyHelper-Klasse auf den Typ Multiply angepasst werden, so dass daraufhin die gewünschte Methode aufgerufen werden kann. 2.6 Starten des Beispiels Zum Starten des Versuchs sind zunächst die einzelnen Klassen zu kompilieren: $ javac *.java Daraufhin kann auf dem Server-Rechner der im SDK enthaltene orbd gestartet werden, der unter anderem einen Namensdienst anbietet: 20 $ orbd –ORBInitialPort 1050 Der optionale Parameter –ORBInitialPort spezifiziert den Port, auf dem der Dienst lauscht. Im Anschluss können Server und Client gestartet werden: $ java Server –ORBInitialPort 1050 $ java Client –ORBInitialPort 1050 // -ORBInitialHost IP Ergebnis: 12 Sollten Client und Server auf unterschiedlichen Rechnern gestartet werden, muss beim Aufruf des Clients die IP-Adresse des Servers mit Hilfe des Parameters –ORBInitialHost angegeben werden. Der beim Methoden-Aufruf ablaufende Vorgang ist in der Abbildung 2.1 zusammenfassen dargestellt: Abbildung 2.1: Ablauf des Beispiels 3 Der Versuch Die zunächst theoretisch vorgestellten und im letzten Abschnitt an einem kleinen Beispiel praktisch erarbeiteten Grundlagen sollen nun für die Lösung des Versuchs eingesetzt werden. Bei dem Versuch handelt es sich um das bereits bekannte Szenario eines einfachen, verteilten Flugbuchungssystems. Bei diesem existiert ein Server, der mit Hilfe eines entfernt nutzbaren Objektes verschiedene Dienste für einen Client nutzbar macht. Ein Client kann dabei Flüge buchen, stornieren, sich gebuchte Flüge anzeigen lassen, eine Anfrage nach dem Raucherabteil starten und sich Sitzplatznummern für Fensterplätze ausgeben lassen. Der Server initialisiert zunächst 20 Flüge, die unter den Flugnummern 1-20 verfügbar sind. Jeder Flug verfügt über 300 Sitzplätze mit den Platznummern 1-300. Es besteht die Möglichkeit anzugeben, ob man einen Raucher- und Fensterplatz buchen will. Ist dieses der Fall wird durch den Server ausgewertet, ob der angegebene Sitzplatz den Kriterien entspricht und je nach Resultat wird er gebucht oder eine Fehlermeldung ausgegeben. Der Client hat ebenso die Möglichkeit, beim Server anzufragen, welche Plätze sich im Raucherabteil befinden und welche freien Plätze Fensterplätze sind, wobei jeweils 5 Platznummern im Raucherbereich und 5 im Nichtraucherbereich angezeigt werden, sofern genügend freie Plätze vorhanden sind. 21 3.1 Versuchsbeschreibung 3.1.1 bereitgestellte Programmkomponenten Nach dem Download der Sourcen von den Seiten des Lehrstuhls und dem Entpacken des Archivs liegen im Zielverzeichnis folgende Dateien vor: Datei Aufgabe(n) ClientApplication.java das eigentliche Client-Programm, das dem Nutzer eine grafische Oberfläche bereitstellt Client.java die Klasse, die auf Clientseite für die Kommunikation über CORBA sorgt und alle notwendigen Aufgaben in diesem Bereich durchführt ServerApplication.java PlatzbuchungImpl.java das Server-Programm, das eine grafische Oberfläche auf Serverseite zur Verfügung stellt und Client-Anfragen mitprotokolliert die Klasse, die auf Serverseite für die Kommunikation über CORBA sorgt und alle notwendigen Aufgaben in diesem Bereich durchführt die Implementierung des entfernten Objektes Flight.java eine Klasse zur Datenhaltung der Flüge Platzbuchung.idl die Beschreibung der Schnittstelle zum entfernten Objekt Server.java An folgenden Dateien sind keine Änderungen erforderlich: PlatzbuchungImpl.java Flight.java ClientApplication.java ServerApplication.java 3.1.2 erforderliche Erweiterungen/Implementierungen I. II. Die Schnittstelle Platzbuchung ist innerhalb der Datei Platzbuchung.idl um die Beschreibung der fünf Methoden book, bookedSeats, storn, freeWindowSeats und smokerArea zu erweitern. Alle Methoden haben dabei zum einen den Rückgabeparameter string und zum anderen den Parameter „FlightRequest request“, der vom Client zum Server übergeben wird. Zudem muss die Klasse FlightRequest definiert werden, die wie soeben erwähnt nicht als entferntes Objekt fungiert, sondern zur Kapselung der übergebenen Parameter dient. Sie hat folgende Attribute: flight (short), seat (short), name (string), smoker (short), window (short). Die Klasse client.java ist zu implementieren. Alle dort notwendigen Ergänzungen sind durch Kommentare gekennzeichnet. 22 III. Die Klasse server.java ist zu implementieren. Alle dort notwendigen Ergänzungen sind durch Kommentare gekennzeichnet. Da durch die IDL-Datei die Komponenten beschrieben werden, die vom Client und Server benötigt werden, sollten diese, sobald die Ergänzungen in der Datei Platzbuchung.idl durchgeführt wurden unter Verwendung des Compilers idlj erzeugt werden. Dadurch wird im Arbeitsverzeichnis der Unterordner PlatzbuchungApp erzeugt, in dem sich alle generierten Klassen befinden. Die Ergänzungen in den beiden Klassen Server und Client sind ohne Kenntnisse der zu verwendeten Objekte und Methoden auf diesen Objekten selbstverständlich nicht implementierbar. Aus diesem Grunde sollte das einfache Beispiel, das im vorherigen Abschnitt durchgenommen wurde tatsächlich einmal selbst durchgeführt werden, da das dort vorgestellte Prinzip des Ablaufs grundlegend für alle CORBA-Anwendungen gleich ist. 3.2 Starten des Versuchs Nachdem alle Implementierungen durchgeführt und die Klassen kompiliert wurden, kann der Versuch getestet werden. Dazu ist zunächst auf dem Rechner, auf dem die Server-Applikation gestartet werden soll der orbd durch den Aufruf: $ orbd –ORBInitialPort 1050 zu starten. Daraufhin kann zunächst die Server-Application und dann die Client-Application gestartet werden: $ java ServerApplication –ORBInitialPort 1050 $ java ClientApplication –ORBInitialPort 1050 Wird die Client-Application zuerst gestartet kommt es selbstverständlich zu einem Fehler, da der entfernte Dienst nicht ermittelt werden kann. Auch hier noch einmal der Hinweis darauf, dass falls Client und Server auf unterschiedlichen Rechnern ausgeführt werden, die Client-Applikation mit der Option –ORBInitialHost „Server-IP“ gestartet werden muss. 3.3 Sicherung der Versuchsergebnisse Nachdem die richtige Funktionsweise des Versuchsergebnisses ausreichend getestet wurde, sind folgende Dinge zu tun: 1. Anlegen des Ordners „LösungenCORBA“ im Unterverzeichnis „Lösungen“ des eigenen Verzeichnisses auf dem Praktikumsrechner 2. Speicherung der veränderten Dateien (Client.java, Server.java, Platzbuchung.idl) in diesem Verzeichnis 3. Mail mit dem Betreff „Versuch-CORBA“ an [email protected] unter Angabe des Namens, Vornamens, der Matrikelnummer und des Logins verschicken 4. Kopie der Versuchsergebnisse bis zur Ausgabe der Scheine sichern 23 4 Literatur [1] OMG: Home Page; http://www.omg.com Dokumente und Spezifikationen der OMG: http://www.omg.org/technology/documents/index.htm OMG-Spezifikationen: http://www.omg.org/technology/documents/spec_catalog.htm ORB-Einführung: http://www.omg.org/gettingstarted/orb_basics.htm [2] Liste mit freien ORBs: http://adams.patriot.net/~tvalesky/freecorba.html [3] Text über IDL und Java: http://www-128.ibm.com/developerworks/library/co-cjct5.html Text über IDL und C++: http://www.ispras.ru/~dkv/superstr.html [4] Sean Baker: CORBA Distributed Objects; Addison Wesley, ISBN 0-201-92475-7, 1997 [5] CORBA Java-Doc: http://java.sun.com/j2se/1.4.2/docs/api/org/omg/CORBA/package-summary.html 24