330 likes | 483 Views
Innehåll Datornätverk Behov och krav CORBA Historik, principer, arkitektur och beståndsdelar Exempel i Java. CORBA: vad, varför, hur?. Distribuerad programmering med CORBA Föreläsning 16. Läs också den utmärkta och konkreta tutorialen som du hittar på följande adress:
E N D
Innehåll Datornätverk Behov och krav CORBA Historik, principer, arkitektur och beståndsdelar Exempel i Java CORBA: vad, varför, hur? Distribuerad programmering med CORBA Föreläsning 16 • Läs också den utmärkta och konkreta tutorialen som du hittar på följande adress: • http://www.javasoft.com/docs/books/tutorial/idl/index.html
Nätverk av datorer • Idag har vi ett behov av att kommunicera mellan olika datorer och annan hårdvara • Vi vill kunna använda olika sätt att lösa ett problem, tex mha olika programmeringsspråk • Vi vill ha kostnadseffektiva lösningar • Vi vill inte binda oss till en viss leverantör • Troligen finns mycket programvara, ny eller gammal, av olika slag i organisationen
CORBA (Common Object Request Broker Architecture) • Standardisering av distribution konstruerad av OMG (Object Management Group) • OMG en sammanslutning av flera hundra (>600) intressenter för att standardisera objekttekniker • Digital, HP, SUN, IBM, Oracle, Netscape, Microsoft, Ericsson mfl • Avsikt • att konstruera ett språk- och plattformsoberoende objektorienterat system för distribution • Tillåter konstruktion av applikationer som kommunicerar över både plattforms- och språkgränser • minimerar beroendet av både hårdvara och programmeringsspråk • enklare att använda mjukvara från olika leverantörer
... CORBA ... • Baserad på en server-klient-modell • en server erbjuder service • en klient utnyttjar den • på en viss plattform kan vissa objekt ta rollen av servrar medan andra tar rollen av klienter • ibland tar ”noderna” rollen av både server och klient samtidigt, dvs så kallad ”peer-to-peer” kommunikation • Finns bindningar till flera programspråk • C++, ADA, Smalltalk, Java, C, COBOL, ...
... CORBA STARTA ... • Starta namnserver • dvs starta det objekt/program som ansvarar för att hantera namngivna delade (/distribuerade) objekt • Starta server med objekt • bind objektet till namnservern • låt servern vänta på att klienter skall kommunicera med dess objekt • Starta klienter och anslut till servern • fråga namnservern om referens till visst objekt • skicka meddelanden till objektet
... CORBA ... • Meddelanden mellan klient och server förmedlas av en mäklare, Object Request Broker (ORB) • dom går aldrig direkt utan alltid via ORBen • Både klient och server ”isolerar” implementationen av klasser med hjälp av IDLer (Interface Description Language) Objektets implementation Klient IDL ”Stubbe” IDL ”Skelett” Meddelande (Request) Object Request Broker
... • På serversidan definierar ett så kallat skelett API:et för ett serverobjekt • På klientsidan beskrivs serverns objekt med en så kallad stubbe • Ett protokoll som heter IIOP (Internet Inter-ORB Protocol) definierar hur transport av objekt och meddelanden mellan server och klienter på binär nivå sker • IIOP specificerades i CORBA 2.0, tidigare var inte denna del standardiserad vilket gjorde att olika implementationer gjorde på sina egna sätt.
CORBA innehåller flera ”services” • Några viktiga är • Lifscykel, grundläggande mekanismer för att skapa, initiera, ta bort objekt mm • Relations, hanterar relationer mellan objekt • Namn, namnger delade objekt så att flera klienter unikt kan referera dem • Persistens, hanterar persistenta objekt, dvs objekt som är långlivade • Extern lagring, kan flytta objekt mellan intern och externa lagringsformer • Transaktion, ger en infrastruktur för att hantera transaktioner • Händelse, låter objekt kommunicera mha händelser • Parallellkontroll, koordinerar objekt och access till delade resurser • Några andra (ett urval) • Trader, erbjuder sätt att "hitta" objekt utgående önskad service • Säkerhet, erbjuder säkerhetsmekanismer som identifiering och auktorisering • Time, för synkronisering av händelser, hantering av alarm och liknande
Kommunikationen mellan klienter och servrar • Lös koppling till plattform, programspråk och detaljer mha • Adaptorer • som döljer skillnader • Brokers • förmedlar meddelanden • Bryggor mellan protokoll • det finns bryggor mellan olika protokoll
CORBA och API-beskrivningar • I CORBA beskrivs gränssnitten (API:erna) för objekten med så kallade IDL:er, dvs grässnittsbeskrivningar. • En IDL påminner till stor del om Java:s gränssnittsbeskrivningar (dvs Java:s interface). • En IDL kan dock innehålla konstruktioner som har sitt ursprung i C/C++, som tex typedef, struct och sequence • Vidare deklareras parametrar till metoder som antingen • in, parameterns värde skickas med som argument till metoden, dvs den typ av parameteröverföring Java använder sig av • out, parameterns värde sätts i metoden och anropande variabel förändras • inout, parametern används som både in och out samtidigt • Gränssnitt organiseras så att ett eller flera gränssnitt definieras i en modul (eng. module)
Exempel: Steg 1) Gör gränssnittsbeskrivning modulenamnet blir ett package i Java då vi "kör" idltojava module MyApp { interface MyInterface { string myMethod(); }; }; och IDL-interfacet blir ett vanligt Java-interface CORBAs string blir sedan String i Java då vi implementerar motsvarande Java-interface (via idltojava)
Steg 2) På serversidan ... • I koden på serversidan kontaktar vi först aktuell ORB • Därefter skapar vi en referens till namnservern • Vi skapar ett serverobjekt (dvs en vanlig instans i Java) och "registrerar" det hos namnservern • Till slut låter vi servern vänta på att serva anslutande klienter • (Vi kan självklart registrera flera objekt på servern om vi vill)
... så här ser det ut i Java ... • Skapa referens till ORB (args innehåller adress för namnservern) ORB orb = ORB.init(args, null); • Fråga ORB om namnserver org.omg.CORBA.Object nameServiceRef = orb.resolve_initial_references("NameService"); • Gör om referensen till ett namnkontextobjekt NamingContext ncRef = NamingContextHelper.narrow(nameServiceRef); • Skapa ett en instans av ett objekt som implementerar MyInterface och registrera det i ORBen MyServerClass objectRef = new MyServerClass(); orb.connect(objectRef);
... serversidan ... • Konstruera ett namnkomponentobjekt med ett namn för objektreferensen som vi vill dela NameComponent nc = new NameComponent("MittObjektNamn", ""); NameComponent path[] = {nc}; • Bind objektet objectRef till namnet path i namnservern, så att klienter kan referera till det. Dvs om någon klient sedan ber namnservern om ett objekt med detta namn så får den en referens till objectRef. ncRef.rebind(path, objectRef); • Vänta på att klienter skall ansluta java.lang.Object sync = new java.lang.Object(); synchronized (sync) {sync.wait();}
Steg 3) Konstruera klient På klientsidan refererar vi ORBen på samma sätt som påserversidan, dvs • Vi kontaktar namnservern • Vi ber namnservern om referens till namngivet objekt • Vi skickar meddelanden till objektet • (självklart kan vi be namnservern om flera objekt och hantera alla dessa parallellt på klienten)
... så här ser klientens kod ut i Java ... • Skapa referens till ORB (args anger adress för namnservern även här) ORB orb = ORB.init(args, null); • Fråga ORB om namnserver org.omg.CORBA.Object nameServiceRef = orb.resolve_initial_references("NameService"); • Gör om referensen till ett namnkontextobjekt NamingContext ncRef = NamingContextHelper.narrow(nameServiceRef); • Konstruera ett namnkomponentobjekt med samma namn som det objekt som skapades på serversidan (som synes på exakt samma sätt också) NameComponent nc = new NameComponent("MittObjektNamn", ""); NameComponent path[] = {nc};
... klientsidan ... • Be namnservern om en referens till det objekt som har samma namn som namnkomponentobjektet MyInterface objectRef = MyInterfaceHelper.narrow(ncRef.resolve(path)); • Skicka meddelande till serverobjektet (på exakt samma sätt som ett meddelande till ett icke distribuerat objekt) String result = objectRef.myMethod(); System.out.println("Serverobjektet svarade: " + result); Omvandla referensen till ett Java-objekt som implementerar interfacet Be namnservern om generiskt CORBA- objekt med givet namn
Konstruera klass och IDL • Konstruera en IDL-beskrivning av gränssnittet mot klassen som konstrueras • server och klient kan ha olika definitioner (fast ofta används likadan IDL för både server och klienter) • Generera hjälpklasser • i JDK1.2 används kommandot idltojava • Skriv server med klassbeskrivning och instans för objektet som klienter skall kunna kommunicera med • Registrera objektet i ORBen och associera det med globalt namn (så att den unikt kan identifieras hos server och alla klienter). Vanligen används namnserver. • Skriv klienter som via ORB och (vanligen) namnserver refererar serverobjektet och sedan skickar meddelanden till det
IDL (Interface Description Language) • Ett programspråksneutralt sätt att beskriva en klass • Några huvuddelar: • statiskt typat • "fördefinierade" primitiva typer • med long, float, boolean, char, void, any osv • metoder och argument deklareras med typ • moduler som innehåller gränssnittsbeskrivningar • gränssnitt (Interface) • Kan användas som typ • Kan ärva från andra interface • Javas Interface har stora likheter med CORBAs interface • datatyper, konstanter, operationer, fält, parametrar • parametrar deklareras med typ och som in, out eller inout • undantagshantering (exceptions) • undantag som skall kastas av metoder i klass deklareras i interfaces any motsvarar Javas Object
... IDL exempel, modul med fyra gränssnitt ... module CosEventComm { exception Disconnected {}; interface PushConsumer { void push (in any event_data) raises (Disconnected); void disconnect_push_consumer ();}; interface PushSupplier { void disconnect_push_supplier ();}; interface PullConsumer { void disconnect_pull_consumer ();}; interface PullSupplier { any pull () raises (Disconnected); any try_pull (out boolean has_event) raises (Disconnected); void disconnect_pull_supplier ();}; }; Undantag deklareras på detta sätt event_data:s värde skickas med som argument Kan kasta undantag has_event ges värde i metoden try_pull
Java IDL • I Java IDL gör vi först gränssnittsbeskrivningen • INTERFACE.idl • Med kommandot idltojava genereras filer som vi kan utnyttja vid skrivandet av server och klienter idltojava INTERFACE.idl • En katalog med samma namn som modulen skapas och en Java-interface-beskrivning motsvarande IDL-beskrivningen skapas. • En del hjälpklasser som gör det enkelt att skriva servrar och klienter konstrueras • Alla dessa klasser definieras automatiskt tillhöra ett package med samma namn som modulen (och därmed också den nyskapade katalogens)
... • Följande fem filer skapas: INTERFACE.java • Javaversionen av interfacet _INTERFACEImplBase.java • serverskellett som implementerar interfacet _INTERFACEStub.java • klientstubbe som implementerar interfacet INTERFACEHelper.java • en klass med statiska hjälpmetoder (tex narrow() som behövs för att ovandla CORBA-objektet till INTERFACE-typen) INTERFACEHolder.java • "Håller" en instans av INTERFACE och hjälper till att hantera out och inout variabler som ju inte egentligen finns i Java
Exempel: Hello World • Ett enkelt CORBA-exempel där vi konstruerar ett objekt på en server som returnerar en sträng till den klient som ansluter • Illustrerar hur IDL-beskrivning görs, hur skelett och stubbar samt andra hjälpklasser automatiskt konstrueras, hur en server respektive klient konstrueras, hur namnserver samt server och klient startas
1) Hello World Interface module HelloApp{ interface Hello { string sayHello(); }; }; • Filen heter HelloApp.idl Gränssnittet definierar endasten metod, sayHello, varsresultat (returvärde) är en sträng (string)
2) Skapa hjälpklasser idltojava -fno-cpp HelloApp.idl • Katalogen HelloApp och följande filer i denna katalog/package skapas: Hello.java _HelloImplBase.java _HelloStub.java HelloHelper.java HelloHolder.java om vi inte vill använda C-preprocessor (som inte säkert finns)
3) Hello World Server import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; class HelloServant extends _HelloImplBase { int i = 0; public String sayHello() {return "\nHello world !! (no: " + ++i + ")\n";} } _HelloImplBase implementerar interfacet Hello.java och är ett serverskelett, dvs en brygga mot ORBen här följer en beskrivning av den klass vars instans vi vill distribuera
... public class HelloServer { public static void main(String args[]) { try{ORB orb = ORB.init(args, null); org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); HelloServant helloRef = new HelloServant(); orb.connect(helloRef); NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; ncRef.rebind(path, helloRef); kontakta ORB skapa referens till namnserver instansiera server- objekt och regi- strera det i ORBen konstruera namnobjekt och bind serverobjektet till detta namn i namnservern
... // vänta på att klienter skall ta kontakt java.lang.Object sync = new java.lang.Object(); synchronized (sync) { sync.wait(); } } catch (Exception e) { System.err.println("ERROR: " + e); e.printStackTrace(System.out); } }}
4) Hello World Klient import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CORBA.*; public class HelloClient { public static void main(String args[]) {try{ORB orb = ORB.init(args, null); org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; Hello helloRef = HelloHelper.narrow(ncRef.resolve(path)); skapa referens till serverns "Hello"- objekt
... skicka ett meddelande till serverobjektet String hello = helloRef.sayHello(); System.out.println(hello); } catch (Exception e) { System.out.println("ERROR : " + e); e.printStackTrace(System.out); } }}
5) Kompilera och Kör Kompilera javac *.java HelloApp/*.java Kör a) starta namnserver tnameserv -ORBInitialPort 1050 b) Starta HelloServer java HelloServer -ORBInitialPort 1050 c) Kör klient java HelloClient -ORBInitialPort 1050
Sammanfattning starta och anslut till namnserver starta namnserver tnameserv -ORBInitialPort PORTNUMMER Starta SERVER java SERVER -ORBInitialHost IPADRESS -ORBInitialPort PORTNUMMER Kör KLIENT java KLIENT -ORBInitialHost IPADRESS -ORBInitialPort PORTNUMMER
Exempel: på att bla definiera metod i klienten som anropas av servern • I IDL-gränssnittet definierar vi ett gränssnitt för ett objekt som skickas med som parameter från klienten till servern • Innan klienten anropar servern skapar klienten en instans av detta "callback-objekt" och registrerar det i ORBen • Från servern skickar vi ett meddelande till detta objekt som resulterar att en metod på klientsidan utförs • Kodexempel i callback-, kylanläggnings-, respektive meddelandecentralexempel i (också som appendix till utdelade materialet): http://www.nada.kth.se/kurser/kth/2D4334/99-00/contents/exempel.html