ORB
Transkrypt
ORB
Plan wykładu 1. CORBA (Common Object Request Broker Architecture) ● wprowadzenie, ● rodzaje obiektów, ● typy i interfejsy, ● model operacji, ● struktura ORB, ● język IDL. 2. Przykład aplikacji rozproszonej CORBA. Wprowadzenie CORBA (Common Object Request Broker Architecture) – specyfikacja określająca funkcjonalność ORB. Opiekę nad standardem sprawuje OMG (Object Managment Group). ORB (Object Request Broker) – magistrala dla komunikatów zawierających żądania wywołań oraz ich wyniki, wymienianych pomiędzy obiektami CORBA i klientami. Specyfikacja dostarcza interfejsów dla komponentów ORB nie określając ich implementacji. CORBA - podstawowe cechy: ● jednolity dostęp do obiektów niezależnie od ich fizycznej lokalizacji, ● niezależność od języka programowania – IDL (Interface Definition Language), Wprowadzenie program klienta Stub Object Request Broker Skeleton implementacja obiektu Klient za pośrednictwem ORB kontaktuje się z implementacją obiektu. Przekaz danych jest realizowany za pośrednictwem procedur łącznikowych Stub i Skeleton. Rodzaje obiektów Rozróżnia się dwa podstawowe rodzaje obiektów: ● obiekty udostępniające usługi (servants) – fragment programu zawierający kod operacji zdefiniowanej przez interfejs IDL. Obiekty udostępniające usługi mogą być wywoływane za pośrednictwem dowolnego mechanizmu, jednak w praktyce korzysta się głównie z kodu zawartego w klasie łącznikowej (Skeleton) wygenerowanego przez kompilator IDL. Pojedynczy obiekt CORBA może być realizowany lub wcielany (incarnate) przez różne obiekty usługowe. Rodzaje obiektów ● obiekty referencyjne (references object) – identyfikator (uchwyt) obiektu używany przez klienta aby wywołać odpowiednią operację. Identyfikator zawsze określa pojedynczy obiekt, choć kilka różnych identyfikatorów może wskazywać na ten sam obiekt. Obiekty referencyjne mogą być przekazywane jako argumenty i wyniki operacji. Obiekty referencyjne są nieprzezroczyste dla użytkownika, tzn. informacja w nich zawarta jest wystarczająca do zidentyfikowania obiektu przez ORB, natomiast jest bezużyteczna dla klienta. Typy i interfejsy Typy obiektów są związane poprzez relację dziedziczenia. Wszystkie typy wywodzą się od typu Object. Istnieją ponadto typy nieobiektowe. Typy podstawowe mogą służyć do budowy typów złożonych takich jak tablice, struktury, sekwencje, unie. Interfejs to opis operacji udostępnianej przez obiekt. Interfejsy są związane relacją dziedziczenia. Istnieje wzajemnie jednoznaczne odwzorowanie typów obiektów i typów interfejsów. Głównym (principal) interfejsem obiektu jest ten, który go najlepiej opisuje (każdy z jego potomków nie opisuje tego obiektu). CORBA dopuszcza istnienie tzw. komponentów – obiektów posiadających wiele interfejsów. Typy i interfejsy Valuetype podobnie jak interfejs opisuje zbiór operacji. Ponadto zawiera też dostępną dla klienta informację o stanie. Instancje valuetypes są implementowane lokalnie i w przeciwieństwie do obiektów są przekazywane przez wartość. Abstrakcyjny interfejs opisuje wielkość, która w trakcie działania programu może być obiektem lub instancją valuetype. Model operacji Istnieją dwa rodzaje wywołań operacji: ● At-Most-Once. Operacja jest wywoływana dokładnie raz. Program klienta zostaje wstrzymany do momentu zakończenia operacji i zwrócenia wyników lub zgłoszenia wyjątku. ● Best-Effort. Program klienta nie czeka na zakończenie wywołanej operacji. Istnieje też możliwość wywołania operacji w taki sposób, aby program klienta nie był blokowany, natomiast wyniki działania operacji zostaną odebrane później (Deferred-Synchronous). Model operacji Sygnatura operacji zapisana w języku IDL zawiera: ● identyfikator operacji (nazwę), ● typ zwracanej wartości, ● listę parametrów wywołania – każdy parametr jest określony przez typ i tzw. kierunek (direction): in, out, inout określający sposób przekazywania parametru, np. in – przekazanie parametru przez klienta do obiektu . Sygnatura może ponadto zawierać: ● listę zwracanych wyjątków (raises), ● rodzaj wywołania (best-effort), ● zmienne środowiskowe, które muszą być przesłane wraz z żądaniem wykonania operacji. Wyjątki Wyjątki (exceptions) stanowią specjalizowany nieobiektowy typ w języku IDL. Wyjątek posiada nazwę i opcjonalne atrybuty udostępniające dalsze, szczegółowe informacje. CORBA zawiera deklaracje 31 wyjątków odnoszących się do problemów z siecią, ORB lub systemem operacyjnym. Każdy z tych wyjątków zawiera dwa zbiory danych określających: ● status wykonania operacji: COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE, określający czy wywołana operacja została wykonana, ● liczę całkowitą określającą kod błędu – liczba ta może być zależna od implementacji ORB. Dodatkowe wyjątki mogą być definiowane przez programistę Struktura ORB implementacja obiektu klient Dynamic Invocation Interface Stub IDL Interfejs ORB Skeleton IDL Dynamic Skeleton Interface Adapter obiektu Rdzeń ORB Interfejs standardowy Interfejs generowany dla typu obiektu Adaptery obiektu, może ich być wiele. Interfejs zależny od implementacji ORB. Sruktura ORB Typowo komunikacja między klientem i obiektem odbywa się z wykorzystaniem procedur łącznikowych (stub, skeleton) generowanych na podstawie specyfikacji napisanej w języku IDL. DII (Dynamic Invocation Interface) oraz DSI (Dynamic Skeleton Interface) – umożliwia komunikację z obiektem z pominięciem procedur łącznikowych. Jest to wykorzystywane np. przy wywołaniach rodzaju Deferred-Synchronous. Adapter obiektu (Object Adapter) jest komponentem łączącym implementację obiektu i ORB. ORB używa go do zarządzania środowiskiem, w którym działa obiekt. Wykorzystanie adapterów zamiast rozszerzania interfejsu ORB umożliwia zastosowanie wielu adapterów dla różnych implementacji obiektów. Język IDL Interface Definition Language służy do definiowania interfejsów dla obiektów działających na platformie CORBA. Specyfikacja zapiana w języku IDL pozwala wygenerować kod łączący klienta i obiekt z ORB. Składnia IDL wywodzi sie z C ++. Do budowy interfejsów wykorzystuje: ● stałe, ● deklaracje typów danych, ● atrybuty, ● operacje, ● interfejsy, ● valuetypy, ● moduły. Język IDL Przykłady: module Hotel{ interface Room{}; }; module Inheritance{ interface A{ typedef unsigned short ushort; ushort operacja1(); } interface B:A{ boolean operacja2(ushort n); }; }; Interfejs B udostępnia dwie operacje: operacja1() i operacja2(). Interfejs może dziedziczyć po kilku interfejsach z różnych modułów. Język IDL Podstawowe typy danych: [unsigned] short – 16 bitowa liczba całkowita, [unsigned] long – 32 bitowa liczba całkowita, [unsigned] long long – 64 bitowa liczba całkowita, float – 16 bitowa liczba rzeczywista, double – 32 bitowa liczba rzeczywista, long double – 64 bitowa liczba rzeczywista, fixed – liczba dziesiętna do 31 cyfr, char – znak (ISO Latin-1), wchar – znak z innego zestawu wspierającego internacjonalizację, boolean – TRUE lub FALSE, string – ciąg znaków char wstring – ciąg znaków wchar octet – 8 bitów enum – typ enumeracyjny, any – dowolny typ w języku IDL, native – typ zależny od języku programowania. Program w technologii CORBA Aplikację kliencką korzystającą z technologii CORBA buduje się w następujących krokach: 1. Napisanie i kompilacja interfejsów w języku IDL. 2. Identyfikacja wygenerowanych interfejsów i klas do późniejszego wykorzystania lub implementacji. 3. Napisanie kodu klienta obiektów CORBA. 4. Implementacja interfejsu IDL w docelowym języku programowania 5. Napisanie programu serwera 6. Uruchomienie programu. Krok 1: interfejs IDL Plik Hello.idl module HelloApp{ interface Hello{ string sayHello(); oneway void shutdown(); }; }; // definicje operacji Kompilacji dokonuje się za pomocą kompilatora IDL dostosowanego do używanego języka programowania. Obecnie istnieją kompilatory dla następujących języków: Ada, C, C++, COBOL, Java, Lisp, PL/1, Pyton, Smalltalk. Krok 2: identyfikacja wygenerowanych plików Standardowo dostępny kompilator dla języka Java uruchamia się poleceniem: idlj -fall Hello.idl Można też używać innych kompilatorów. Najpopularniejsze z nich to idltojava oraz idl2java. W wyniku kompilacji zostanie utworzony katalog HelloApp, w którym pojawią się pliki: ● HelloOperations.java zawiera definicję interfejsu w Javie opisującego dostępne operacje. package HelloApp; public interface HelloOperations{ String sayHello (); void shutdown (); } // interface HelloOperations Krok 2: identyfikacja wygenerowanych plików ● Hello.java interfejs w Javie reprezentujący interfejs IDL. package HelloApp; public interface Hello extends HelloOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {} ● HelloHolder.java dostarcza operacji dla parametrów out i inout. package HelloApp; public final class HelloHolder implements org.omg.CORBA.portable.Streamable{ public HelloApp.Hello value = null; public HelloHolder(){} public HelloHolder (HelloApp.Hello initialValue){ value = initialValue; } public void _read (org.omg.CORBA.portable.InputStream i){ value = HelloApp.HelloHelper.read (i); } public void _write (org.omg.CORBA.portable.OutputStream o){ HelloApp.HelloHelper.write (o, value); } public org.omg.CORBA.TypeCode _type (){ return HelloApp.HelloHelper.type (); } } Krok 2: identyfikacja wygenerowanych plików ● HelloHelper.java jest odpowiedzialny za odczytywanie i zapisywanie strumieniów CORBA, obsługi typów Any. Wykorzystywany przez Holder do odczytu i zapisu informacji. Zawiera też metodę do rzutowania obiektów CORBA. public static HelloApp.Hello narrow (org.omg.CORBA.Object obj){ if (obj == null) return null; else if (obj instanceof HelloApp.Hello) return (HelloApp.Hello)obj; else if (!obj._is_a (id ())) throw new org.omg.CORBA.BAD_PARAM (); else{ org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate (); HelloApp._HelloStub stub = new HelloApp._HelloStub (); stub._set_delegate(delegate); return stub; } } Krok 2: identyfikacja wygenerowanych plików ● _HelloStub.java klasa łącznikowa klienta (stub) rozszerzająca org.omg.CORBA.portable.ObjectImpl i implementująca HelloApp.Hello . ... public String sayHello (){ org.omg.CORBA.portable.InputStream $in = null; try { org.omg.CORBA.portable.OutputStream $out = _request("sayHello", true); $in = _invoke ($out); String $result = $in.read_string(); return $result; } catch (org.omg.CORBA.portable.ApplicationException $ex) { $in = $ex.getInputStream(); String _id = $ex.getId(); throw new org.omg.CORBA.MARSHAL(_id); } catch (org.omg.CORBA.portable.RemarshalException $rm) { return sayHello(); } finally { _releaseReply ($in); } } // sayHello ... Krok 2: identyfikacja wygenerowanych plików ● HelloPOA.java klasa łącznikowa serwera (skeleton). ... switch (__method.intValue ()){ case 0:{ // HelloApp/Hello/sayHello String $result = null; $result = this.sayHello (); out = $rh.createReply(); out.write_string ($result); break; } case 1:{ // HelloApp/Hello/shutdown this.shutdown (); out = $rh.createReply(); break; } default: throw new org.omg.CORBA.BAD_OPERATION (0,org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE); } return out; } // _invoke ... Krok 3: Kod klienta CORBA Plik HelloClient.java import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; public class HelloClient{ static Hello helloImpl; public static void main(String args[]){ try{ ORB orb = ORB.init(args, null); // utworzenie i inicjalizacja ORB org.omg.CORBA.Object objRef = orb.resolve_initial_references ("NameService"); // pobranie kontekstu nazw NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); String name = "Hello"; // wyszukanie obiektu w kontekscie helloImpl = HelloHelper.narrow(ncRef.resolve_str(name)); System.out.println("otrzymano uchwyt: " + helloImpl); System.out.println(helloImpl.sayHello()); helloImpl.shutdown(); } catch (Exception e) { System.out.println("ERROR : " + e) ; } } } Krok 4: Implementacja interfejsu Plik HelloImpl.java zawiera implementację interfejsu HelloApp.Hello import HelloApp.*; import org.omg.CORBA.*; public class HelloImpl extends HelloPOA { private ORB orb; public void setORB(ORB orb_val) { orb = orb_val; } public String sayHello() { return "\nHello world !!\n"; } } public void shutdown() { orb.shutdown(false); } Krok 5: Kod serwera Plik HelloServer.java zawiera kod serwera import import import import import HelloApp.*; org.omg.CosNaming.*; org.omg.CosNaming.NamingContextPackage.*; org.omg.CORBA.*; org.omg.PortableServer.*; public class HelloServer { public static void main(String args[]){ try{ ORB orb = ORB.init(args, null); // utworzenie i inicjalizacja ORB POA rootpoa = POAHelper.narrow(orb.resolve_initial_references "RootPOA")); // referencja do POA (Skeletonu) rootpoa.the_POAManager().activate(); Krok 5: Kod serwera HelloImpl helloImpl = new HelloImpl();// stworzenie obiektu usługowego helloImpl.setORB(orb); // i rejestracja w ORB org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl); Hello href = HelloHelper.narrow(ref); // odebranie referencji do obiektu org.omg.CORBA.Object objRef = orb.resolve_initial_references ("NameService"); // uzyskanie kontekstu nazw NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); String name = "Hello"; // związanie obiektu z nazwą NameComponent path[] = ncRef.to_name(name); ncRef.rebind(path, href); System.out.println("HelloServer gotowy..."); } } orb.run(); // czeka na zgłoszenia klientów }catch (Exception e) { System.err.println("ERROR: " + e); } System.out.println("HelloServer Exiting ..."); Odwołania do ORB W przypadku prostych aplikacji „lokalnych” nie wymagających używania kontekstu nazw operacje związane ze zdalnym obiektem można wykonywać nieco łatwiej używając metod dla instancji org.omg.CORBA.ORB. Do połączenia obiekty z ORB można użyć metody void connect(org.omg.CORBA.Object obj) orb.connect(href); //połączenie obiektu z ORB Każdy przyłączony obiekt posiada swoją reprezentację tekstową. Konwersja pomiędzy obiekten a odpowiadającym mu tekstem jest dokonywana przez metody: String object_to_string(org.omg.CORBA.Object obj) oraz org.omg.CORBA.Object string_to_object(String name) np: String name = orb.object_to_string(href); // uzyskanie nazwy obiektu Object obj = orb.string_to_object(name); // uzyskanie obiektu Krok 6: Kompilacja i uruchomienie Kompilujemy pliki: javac HelloServer.java HelloApp/*.java javac HelloClient.java HelloApp/*.java Uruchomienie aplikacji rozproszonej: 1. uruchomienie orbd: orbd -ORBInitialPort 1050 -ORBInitialHost localhost& 2. uruchomienie serwera java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost& 3. uruchomienie programu klienta: java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost Serwer typu persistant Przykładowy serwer udostępnia obiekty typu transient, tzn. czas życia takich obiektów jest ściśle związany z czasem życia procesu serwera, który je stworzył. W momencie zakończenia pracy serwera wszystkie referencje utrzymywane przez klientów do takiego obiektu stają się nieaktualne. Odmienne zachowanie jest cechą obiektów typu persistant. Referencje nich są niezależne od czasu życia procesu serwera. Jeżeli nadejdzie zgłoszenie do takiego obiektu, ORB automatycznie uruchomi odpowiedni serwer. Obiekty persistant żyją dopóki nie zostaną w sposób jawny usunięte (zniszczone). Począwszy od wersji J2SE 1.4 można operować na takich obiektach. Podsumowanie CORBA jest platformą służącą do tworzenia programów rozproszonych. W porównaniu do wcześniej omówionych rozwiązań (RPC, RMI) CORBA nie jest związana z żadnym konkretnym językiem programowania. Jej działanie opiera się na udostępnianiu rozproszonych obiektów, których własności definiuje się za pomocą specjalnego języka - IDL. Implementacje tych obiektów mogą być tworzone w jednym z wielu popularnych języków programowania.