CORBA – Common Object Request Broker Architecture
Transcription
CORBA – Common Object Request Broker Architecture
Vortrag: CORBA Jörg Bogenrieder CORBA – Common Object Request Broker Architecture 1. Einleitung Moderne Programmiersprachen haben den objektorientierten Ansatz in die strukturierte Berechnung in einem einzigen Betriebssystemprozess eingeführt. Der nächste logische Schritt ist, die Verteilung der Berechnung über mehrere Prozesse auf eine oder auf mehrere CPU´s. Da die Objektorientiertheit eine passende Methode zur Entwicklung und zum Betrieb großer skalierbarer Applikationen liefert, liegt es auf der Hand, diesen Ansatz auch zum Entwickeln von verteilten Anwendungen zu benutzen. Die Objekte sind auf vielen Computern verteilt, die mit einem Netzwerk miteinander verbunden sind. Leider ist es eine Tatsache, daß sich in einem Netzwerk, die Hardware, die Architektur und die Betriebssysteme der einzelnene Systeme voneinander unterscheiden. Auch die Programmiersprachen, in denen die Objekte implementiert wurden, sind verschieden. Diese heterogenen verteilten Systeme benötigen für die Kommunikation der Objekte eine sogenannte Middelware. Die Common Object Request Broker Architecture ist eine Spezifikation einer solchen Middelware. CORBA ist ein offener Standard der von der Object Management Group (OMG) betreut und stetig weiter entwickelt wird. CORBA beinhaltet folgende Punkte: Objektorientiertheit Objekte sind die Grundbausteine von CORBA-Applikationen Ortstransparenz Ein Objekt wird immer mit den gleichen Mechanismen aufgerufen, egal ob es sich im gleichen Adressbereich, im gleichen Computer oder in einem entfernten Computer befindet. Hardware-, Betriebssystem- und Sprachunabhängigkeit CORBA Komponenten können in verschiedenen Programmiersprachen auf verschiedenen Architekturen mit unterschiedlichen Betriebssystemen implementiert werden. Herstellerunabhängigkeit Man ist nicht an ein Hersteller gebunden, da der CORBA Standard die Kommunikation der Objekte festlegt. Daher können unterschiedliche ORB´s eingesetzt werden. 2. IDL Interface Definition Language Die Interface Definition Language dient zur Beschreibung der Schnittstellen (ähnlich einer Headerdatei in C oder Schnittstellendefinition in C++), sie trennt die Implementierung und die Schnittstellen eines Objektes. Der IDL-Code ist sehr stark an die C++ Syntax angelehnt. Um aus der IDL-Datei nun den Code für die eigentliche Implementierung zu erhalten, muss diese mittels eines IDL-Compilers in die jeweilige Sprache überführt werden. Der Compiler erzeugt eine Anzahl von Dateien, die Stub und Hilfsklassen. Diese Dateien dienen als Gerüst für die Verbindung zwischen den Objekten. Seite 1 von 11 Vortrag: CORBA Jörg Bogenrieder 3. Die CORBA Dienste Bei CORBA hat die OMG 15 Objektdienst-Spezifikationen veröffentlicht. Diese Dienste (CORBA-Services) dienen als Erweiterung und Ergänzung der Funktionalität eines ORBs. Hiermit kann eine Komponente erzeugt, benannt und in die Umgebung eingebaut werden. Life-Cycle-Service definiert die Operationen für das Erzeugen, Kopieren, Verschieben und Löschen von Komponenten. Persistence-Service bietet eine einheitliche Schnittstelle für das langfristige Speichern von Komponenten auf einer Vielzahl von Speicher-Servern wie z.B. Objektdatenbanken, relationale Datenbanken oder Dateien. Naming-Service ermöglicht den Komponenten andere Komponenten über ihren Namen zu finden; er unterstützt auch einen verteilten Namens-Dienst, also Namenskontexte, die sich in unterschiedlichen ORB-Domänen befinden. Mit Hilfe dieses Dienstes lassen sich Objekte in vorhandene Netzwerkverzeichnisse oder Namenskontexte einbinden, z.B. NIS+ (Sun), NDS (Novell) oder LDAP (Internet). Event-Service ermöglicht den Komponenten ihr Interesse an bestimmten Ereignissen dynamisch registrieren und deregistrieren zu lassen. Der Dienst definiert ein permanentes Objekt, den Event Channel, der Ereignisse sammelt und an Komponenten verteilt, die nichts voneinander wissen. Concurrent-Control-Service bietet einen Lock-Manager, der im Auftrag von Transaktionen oder Threads Sperrungen vornehmen kann. Transaction-Service sorgt für die Koordinierung eines zweiphasigen Bestätigungsprotokolls (two-phase commit) zwischen wiederherstellbaren Komponenten, die flach oder verschachtelte Transaktionen verwenden. Relationship-Service bietet die Möglichkeit, dynamische Assoziationen (oder Verknüpfungen) zwischen Komponenten zu erzeugen, die voneinander nichts wissen. Er stellt ach Mechanismen zum Durchqueren dieser Verknüpfungen zur Verfügung, die die Komponenten gruppieren. Mit Hilfe diese Dienstes können Bedingungen für referentielle Integrität erzwungen werden, Beziehungen zwischen den Inhalten verfolgt und beliebige Arten von Verknüpfungen zwischen den Komponenten vorgenommen werden. Externalisation-Service ist eine Standardmethode, über einen Stream-Mechanismus Daten in eine Komponente hinein zu importieren und aus ihr heraus zu exportieren. Query-Service stellt Abfrageoperationen für Objekte bereit. Er bildet eine Erweiterung von SQL auf Basis der SQL3-Spezifikation und der Object Query Language (OQL) der Object Database Management Group (ODMG). Seite 2 von 11 Vortrag: CORBA Jörg Bogenrieder Licensing-Service bietet Operationen, um für eine faire Abrechnung die Nutzungsdauer von Komponenten zu messen. Der Dienst unterstützt beliebige Modelle der Nutzungkontrolle zu jedem Zeitpunkt im Lebenszyklus einer Komponente, z.B. Berechnung pro Sitzung, pro Knoten, pro Instanz oder pro Site. Properties-Service bietet Operationen, um Namen/Werte-Paare mit beliebigen Komponenten zu assoziieren. Mit Hilfe dieses Dienstes lassen sich dynamisch einer Komponente Eigenschaften zuweisen, z.B. ein Titel oder ein Datum. Time-Service stellt eine Schnittstelle zur Uhrzeitsynchronisation in einer verteilten Objektumgebung zur Verfügung. Er bietet auch Operationen für die Definition und Verwaltung von zeitgetriggerten Ereignissen. Security-Service liefert ein komplettes Framework für die Sicherheit bei verteilten Objekten. Er unterstützt Identifizierung, Zugriffskontrollisten, Vertraulichkeit und Unwiderlegbarkeit. Er verwaltet auch die Delegierung von „Ausweisen“ zwischen Objekten. Trader-Service stellt die „gelben Seiten“ für Objekte bereit. Er erlaubt Objekten ihre Dienste anzubieten, oder nach bestimmten Diensten zu suchen. Collection-Service ermöglicht es CORBA-Schnittstellen, allgemeine Collections zu erzeugen und zu manipulieren. 4. Wie initialisiert der Client die Server Objekte? Da es bei CORBA keine explizite Methode für einen Client gibt, die ein Server-Objekt aktiviert, muss dies von der Serverseite aus bewerkstelligt werden. Natürlich werden nicht alle Objekte beim Start des Servers explizit gestartet, sondern es wird nur der Eindruck erweckt, daß das Server-Objekt geladen und aktiv ist. Diese Aufgabe übernimmt auf der Serverseite der Basic Object Adapter (BOA). Er wird verwendet um Objektreferenzen zu erzeugen oder zu löschen und um Informationen der Objektreferenz abzufragen und zu ändern. Der BOA verwaltet ein Verzeichnis aller aktiven Objekte und Implementierungen. Die BOA-Schnittstelle wird dazu verwendet um mit diesem Verzeichnis zu kommunizieren und dem ORB von den Objekten zu berichten. Es lässt sich als Zusammenarbeit zwischen dem Server-Objekt und dem ORB vorstellen, um so für die Illusion zu sorgen, daß alle Server-Objekte immer aktiv sind. 5. Erste Schritte mit CORBA oder wie erreiche ich meinen ORB? Ein ORB ist eigentlich nichts anderes als eine Objektbibliothek, die je nach Sprachbindung des ORBs in den jeweiligen Sprachen vorhanden sind und in das CORBA-Programm eingebunden werden (ähnlich wie bei RPC). Die CORBA-Spezifikation legt fest, wie die einzelnen Objekte aufgerufen werden und welche Methoden sie zu Verfügung stellen. Um ein ORB einzusetzen genügt es, in seinem Programm eine Referenz auf des ORB-Objekt anzulegen, nun läßt sich der ORB ansprechen. Seite 3 von 11 Vortrag: CORBA Jörg Bogenrieder org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init( args, null ); liefert die Referenz auf das ORB-Objekt. Mit orb.list_initial_services(); lassen sich alle Dienste auflisten, die der ORB zu bieten hat. Mit org.omg.CORBA.Object objPoa = null; objPoa = orb.resolve_initial_references("<Name des Dienstes>"); wird der Name des Dienstes in eine Objektreferenz umgewandelt und kann nun angesprochen werden. 6. Jetzt wird’s ernst! Um die Mechanismen genauer zu beleuchten wird es Zeit für unser allseits beliebtes HelloWorld Beispiel. Als ORB dient uns JavaORB, ein frei verfügbarer ORB mit Java als Sprachbindung, in der Version 2.2.7. Dazu benötigen wir unsere IDL Datei. Sie beinhaltet folgenden Code: interface HelloWorld { string sayHello(); }; Bei IDL ist darauf zu achten, daß nach der letzten geschweiften Klammer ebenfalls ein Strichpunkt sein muss. Nun wird mit Hilfe des IDL-Compilers unsere Stub und Hilfsklassen erzeugt. Der Aufruf lautet: idl2java <IDL-Datei> [-Options] Der IDL-Compiler erzeugt nun folgende Dateien: HelloWorld.java HelloWorldHelper.java HelloWorldHolder.java HelloWorldOperations.java _HelloWorldImplBase.java _HelloWorldStub.java Diese Dateien befinden sich nun in dem Verzeichnis ./corba_pkg/ . Nun muss nur noch der Clientcode, der Servercode und die Implementierung der Schnittstelle HelloWorld geschrieben werden. 7. Implementierung der Schnittstelle: Hierzu muss eine Klasse von der Klasse _HelloWorldImpleBase abgeleitet werden und die Funktionalität des Programms implementiert werden. Bei uns soll mittels getLocalHost() der Name und die IP-Adresse des Host zurückgegeben werden, auf dem sich das Objekt befindet. 8. Implementierung des Client: Zuerst brauchen wir eine Referenz auf unsern ORB, diese wird mittels org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init( args, null ); hergestellt. Seite 4 von 11 Vortrag: CORBA Jörg Bogenrieder Um den ORB zu befragen wo sich das Serverobjekt befindet, bedienen wir uns des Name-Service, hierzu benötigen wir eine Objektreferenz zu einem Name-ServiceObjektes - dies wird hiermit hergestellt. org.omg.CORBA.Object obj = null; org.omg.CosNaming.NamingContext naming = null; try { obj = orb.resolve_initial_references( "NameService" ); naming = org.omg.CosNaming.NamingContextHelper.narrow( obj ); } mit der Methode narrow() wird ein Downcast eines CORBA.Object zu NaimingContext durchgeführt. Nun sind wir mit dem Name-Service unseres ORB verbunden. Um den Pfad zu unserem Objekt zu finden wird zuerst eine Anfrage an den Name-Service zusammengestellt. org.omg.CosNaming.NameComponent[] name = new org.omg.CosNaming.NameComponent[1]; name[0] = new org.omg.CosNaming.NameComponent(); name[0].id = "HelloWorld"; name[0].kind = "Example"; und mit obj = naming.resolve(name); an den Name-Service geschickt. Mittels HelloWorld hello = HelloWorldHelper.narrow( obj ); wird unsere Objektreferenz wieder Downgecastet. Und über hello.sayHello(); wird unser Objekt angesprochen. 9. Nun geht’s an den Server: Auch unsere Serverklasse benötigt zuerst eine Referenz auf den ORB dies wird genau wie beim Client erledigt. Danach wird eine Referenz auf den BOA hergestellt. org.omg.CORBA.BOA boa = org.omg.CORBA.BOA.init(orb,args); Danach wird eine Instanz unserer Schnittstellenimplementierung HelloWorldImpl gebildet und beim BOA registriert und aktiviert (nochmals zur Erinnerung, das Objekt wird nicht wirklich gestartet, sondern erst wenn eine Anfrage vom Client kommt) HelloWorldImpl hello = new HelloWorldImpl(); boa.connect(hello); boa.obj_is_ready(hello); Danach benötigen wir wieder eine Objektreferenz auf ein Name-Service Objekt dies wird genauso hergestellt wie beim Client. Wenn wir diese Objektreferenz haben, wird unser Objekt in den Name-Service eingetragen org.omg.CosNaming.NameComponent [] name = new org.omg.CosNaming.NameComponent[1]; name[0] = new org.omg.CosNaming.NameComponent(); name[0].id = "HelloWorld"; name[0].kind = "Example"; naming.bind(name,hello); Seite 5 von 11 Vortrag: CORBA Jörg Bogenrieder Was nun noch übrig bleibt ist, daß wir unser Serverobjekt beim BOA anmelden und auf eingehende Anfragen warten. Wir starten den Name-Service und unser Serverobjekt durch naming java <Name des Serverprogramms> Nun beantwortet der Server die Anfrage des Clients. Seite 6 von 11 Vortrag: CORBA Jörg Bogenrieder Quellenangabe: Instant CORBA: Führung durch die CORBA-Welt Robert Orfali, Dan Harky, Jeri Edwards; Bonn: Addison Wesly Longman GmbH ISBN 3-8273-1325-2 Java Programming with CORBA Andreas Vogel, Keith Duddy; New York: Wiley Computer Publishing ISBN 0-471-17986-8 CORE Java 2 - Expertenwissen Cay S. Horstmann, Gary Cornell; München: Markt + Technik Verlag ISBN 3-8272-9566-1 Internet: Object Management Groupe: www.omg.org JavaOrb: www.multimania.com/dogweb, dog.exoffice.com Quelltexte: /******************************************************************/ /* */ /* The Server of Hello World Program */ /* using the NamingService */ /* */ /* @author Joerg Bogenrieder */ /* @version 0.0.1 */ /* */ /******************************************************************/ public class Server_name { public static void main( String args[] ) { // 1. // Initialize the ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null); // 2. // Initialize the BOA org.omg.CORBA.BOA boa = org.omg.CORBA.BOA.init(orb,args); // 3. // Instanciate Calculator object HelloWorldImpl hello = new HelloWorldImpl(); // 4. // Connect the instance to BOA boa.connect(hello); // 5. // Activate the instance boa.obj_is_ready(hello); Seite 7 von 11 Vortrag: CORBA Jörg Bogenrieder // 6. // Resolve the NameService org.omg.CORBA.Object obj = null; org.omg.CosNaming.NamingContextExt naming = null; try { obj = orb.resolve_initial_references("NameService"); naming = org.omg.CosNaming.NamingContextExtHelper.narrow(obj); } catch ( org.omg.CORBA.ORBPackage.InvalidName name ) { System.out.println("Enable to resolve NameService"); System.exit(0); } if ( naming == null ) { System.out.println("The NameService was not found"); System.exit(0); } // 7. // Build HelloWorld path org.omg.CosNaming.NameComponent [] name = new org.omg.CosNaming.NameComponent[1]; name[0] = new org.omg.CosNaming.NameComponent(); name[0].id = "HelloWorld"; name[0].kind = "Example"; // 8. // Bind Calculator into NameService try { naming.bind(name,hello); } catch( org.omg.CosNaming.NamingContextPackage.NotFound ex ) { System.out.println("Object not found"); System.exit(0); } catch( org.omg.CosNaming.NamingContextPackage.AlreadyBound ex ) { System.out.println("Already bound"); System.exit(0); } catch( org.omg.CosNaming.NamingContextPackage.InvalidName ex ) { System.out.println("Invalid name"); System.exit(0); } catch( org.omg.CosNaming.NamingContextPackage.CannotProceed ex ) { System.out.println("Cannot proceed"); Seite 8 von 11 Vortrag: CORBA Jörg Bogenrieder System.exit(0); } // 9. // Wait for invocations try { System.out.println("The server is ready..."); boa.impl_is_ready(); } catch( java.lang.Exception ex ) { System.out.println("An exception has been intercepted."); } } // main } // class /******************************************************************/ /* */ /* The Implementation of Hello World Program */ /* */ /* @author Joerg Bogenrieder */ /* @version 0.0.1 */ /* */ /******************************************************************/ public class HelloWorldImpl extends _HelloWorldImplBase { private String str; public String sayHello() { try { java.net.InetAddress InetAddr = java.net.InetAddress.getLocalHost(); str = InetAddr.toString(); } catch( java.net.UnknownHostException exc ) { System.out.println( exc.getMessage() ); } str = str + " say: HelloWorld! to you"; return str; } // sayHello } // class Seite 9 von 11 Vortrag: CORBA Jörg Bogenrieder /******************************************************************/ /* */ /* The Client of Hello World Program */ /* using the NamingService */ /* */ /* @author Joerg Bogenrieder */ /* @version 0.0.1 */ /* */ /******************************************************************/ public class Client_name { public static void main( String args[] ) { // 1. // Initialize the ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init( args, null ); // 2. // Resolve the NamingService org.omg.CORBA.Object obj = null; org.omg.CosNaming.NamingContext naming = null; try { obj = orb.resolve_initial_references( "NameService" ); naming = org.omg.CosNaming.NamingContextHelper.narrow( obj ); } catch( org.omg.CORBA.ORBPackage.InvalidName name ) { System.out.println( "Enable to resolve NameService" ); System.exit( 0 ); } // 3. // Build HelloWorld path org.omg.CosNaming.NameComponent[] name = new org.omg.CosNaming.NameComponent[1]; name[0] = new org.omg.CosNaming.NameComponent(); name[0].id = "HelloWorld"; name[0].kind = "Example"; // 4. // Resolve Calculator reference from NamingService try { obj = naming.resolve(name); } catch( org.omg.CosNaming.NamingContextPackage.NotFound ex ) { System.out.println("Object not found"); System.exit(0); } catch(org.omg.CosNaming.NamingContextPackage.CannotProceed ex) Seite 10 von 11 Vortrag: CORBA Jörg Bogenrieder { System.out.println("Cannot proceed"); System.exit(0); } catch( org.omg.CosNaming.NamingContextPackage.InvalidName ex ) { System.out.println("Invalid name"); System.exit(0); } // 5. // Narrow the Object referece HelloWorld hello = HelloWorldHelper.narrow( obj ); // 6. // Use the Hello World Object try { String tmp = hello.sayHello(); System.out.println( "Host: " + tmp ); } catch( org.omg.CORBA.SystemException exc ) { System.out.println( "A CORBA System exception?" ); System.out.println( exc.getMessage() ); } } // main } // class Seite 11 von 11