Systemy rozproszone W. Bartkiewicz Wykład 6. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej – zdalne obiekty
Obiekty rozproszone W miarę stopniowego stawania się mechanizmów RPC standardami de facto komunikacji w systemach rozproszonych, zdano sobie sprawę z tego, że zasadę zdalnych wywołań procedur można z równym powodzeniem zastosować do obiektów. Wywołania zdalnych obiektów stanowią generalnie proste rozszerzenie koncepcji RPC. Przez obiekt rozproszony (distributed object) rozumiemy konstrukcję w której interfejs obiektu i sam obiekt znajdują się w różnych procesach i często na różnych maszynach. W obiekcie rozproszonym stan może być fizycznie rozproszony w wielu procesach (i również maszynach), ale rozproszenie to jest skrywane przed klientami za interfejsami obiektu. Często jednak stan obiektu ma charakter skupiony – pozostaje w jednym procesie. W innych procesach dostępne są tylko realizowane przez obiekt interfejsy. Obiekty rozproszone tego typu nazywane są również często obiektami zdalnymi (remote objects).
Wiązanie w obiektach rozproszonych Podczas wiązania klienta z obiektem do przestrzeni adresowej klienta załadowana zostaje implementacja interfejsu obiektu, nazywana pośrednikiem (proxy). Pośrednik jest odpowiednikiem namiastki klienta w systemach RPC. Jedyną rzeczą jest przetaczanie wywołań metod do komunikatów i odwrotne przetaczanie odpowiedzi do klienta. Rzeczywisty obiekt rezyduje w procesie serwera, w którym udostępnia ten sam interfejs co w pośrednik procesie klienta. Nadchodzące zamówienia wywołań są najpierw przekazywane do namiastki serwera, często nazywanej szkieletem (skeleton), która dokonuje ich odwrotnego przetoczenia, nadając im postać poprawnych wywołań metod obiektu. Namiastka serwera odpowiada również za przetaczanie odpowiedzi i przekazywanie komunikatów z odpowiedziami do pośrednika po stronie klienta.
Wiązanie w obiektach rozproszonych Maszyna klientaMaszyna serwera Sieć SO klientaSO serwera PośrednikSzkielet Klient Klient wywołuje metodę Interfejs ten sam co obiektu Szkielet wywołuje taką samą metodę w obiekcie Serwer Obiekt Stan Metoda Interfejs Przetoczone wywołanie jest przekazywane siecią
Obiekty rozproszone fazy kompilacji i wykonania Obiekty rozproszone mogą mieć postać bezpośrednio związaną z obiektami poziomu językowego, takimi jak spotykane np. w C++, Javie, określane również jako obiekty fazy kompilacji. Wadą takiego rozwiązania jest zależność od danego języka programowania. Alternatywą jest budowa obiektów rozproszonych wprost w fazie wykonania programu. Obiekty fazy wykonania nie zależą od struktury żadnego konkretnego języka, co umożliwia tworzenie aplikacji z wykorzystaniem różnych narzędzi programistycznych. Obiekty czasu wykonania nie muszą być nawet realizowane w sposób obiektowy. Może być to np. grupa funkcji języka C, działająca na wspólnym zestawie danych. Powszechnie korzysta się wówczas z mechanizmu nazywanego adapterem obiektu (object adapter) lub opakowaniem obiektu (object wrapper), który działa jako opakowanie implementacji, nadając jej wygląd obiektu.
Adapter obiektu Serwer z trzema obiektami Lokalny SO serwera Szkielet Demultiplekser zamówień Adapter obiektu
Adaptery mogą realizować różne polityki uaktywnień obiektów, np.: –Przekazywać zamówienia klientów do obiektów istniejących przez cały czas lub tworzyć i likwidować obiekty przy nawiązaniu i zakończeniu kontaktu przez klienta. –Zarządzać uruchomieniami współbieżnymi obiektów, poprzez ich umieszczanie w różnych wątkach. –Uaktywniać obiektów w oddzielnych lub wspólnych segmentach danych. Adapter obiektu jest często ukryty w zbiorze narzędzi do budowy serwerów obiektowych. Są one tworzone zazwyczaj w postaci ogólnych komponentów, które mają pomagać budowniczym obiektów rozproszonych. Adaptery niekoniecznie muszą znać konkretne interfejsy kontrolowanych przez siebie obiektów. Ich zadaniem jest przekazywanie zamówień do szkieletów obiektów utworzonych zgodnie z daną polityką uaktywnienia.
Obiekty trwałe i tymczasowe Obiekt trwały (persistent object) istnieje nawet wówczas, gdy nie ma go w przestrzeni adresowej procesu usługodawczego. Inaczej mówiąc, nie zależy on od swojego aktualnego serwera. W praktyce oznacza to, że serwer, który aktualnie zarządza obiektem trwałym, może przechować stan obiektu w pamięci zewnętrznej i zakończyć swoje działanie. Nowo uruchomiony serwer może załadować zmagazynowany stan obiektu do swojej przestrzeni adresowej i obsługiwać zamówienia wywołań. Obiekt tymczasowy (transient object) istnieje dopóty, dopóki działa serwer, który nim zarządza. Z chwilą zakończenia pracy serwera, obiekt również przestaje istnieć.
Realizacja odniesień obiektowych W środowiskach obiektów rozproszonych znacznie częściej niż w przypadku RPC stosuje globalne usługi wiązania, pozwalające na realizację wywołań zdalnych metod obiektu. Obejmują one zazwyczaj globalną usługę nazewniczą, polegającą na implementacji przez środowisko systemu jednoznacznych identyfikatorów obiektów oraz ich interfejsów, a także realizację wiązania za pośrednictwem globalnego serwera położenia (location server), przechowującego dane o maszynie z aktualnie działającym serwerem obiektu, oraz punkcie końcowym do komunikacji z danym obiektem.
Wywołania statyczne i dynamiczne metod zdalnych Podejście oparte na użyciu wcześniej zdefiniowanych opisów interfejsów określane jest jako wywołanie statyczne (static invocation). Wymaga ono znajomości interfejsu obiektu podczas kompilacji aplikacji klienta. Zmiana w interfejsie pociąga za sobą konieczność rekompilacji klienta. Wywołania metod mogą być opracowywane podczas wykonania aplikacji. Mówimy wówczas o wywołaniu dynamicznym (dynamic invocation). Nazwa lub identyfikator metody przezywane są przez klienta obiektowi w postaci danych czasu wykonania, a nie identyfikatorów czasu kompilacji. Podczas kompilacji klient nie musi znać specyfikacji merytorycznego interfejsu obiektu, a jedynie sposób (interfejs) wywołania dynamicznego. Usługi udostępniane przez obiekt i formę ich wywołania (parametry, wartość powrotną) mogą zostać określone podczas wykonania.
Wywołania statyczne i dynamiczne metod zdalnych Wywołanie dynamiczne jednak jest nieco mniej efektywne. Pojawiają się dodatkowe narzuty związane z koniecznością sprawdzenia interfejsów podczas wykonania programu, a nie jego kompilacji. Ponadto podejście to uniemożliwia kompilatorowi sygnalizacji niezgodności interfejsu w ramach kontroli typów podczas kompilacji. Ewentualne błędy wykrywane podczas wykonania sygnalizowane być muszą poprzez mechanizmy obsługi błędów (np. z wykorzystaniem wyjątków). W celu umożliwienia klientom konstruowania zamówień dla obiektów podczas fazy wykonania, interfejsy wywołania dynamicznego oferują zazwyczaj również mechanizmy odpytywania obiektu o rodzaj i sposób wywołania danej usługi.
Java RMI Charakterystyka Obiekty rozproszone w infrastrukturze Javy RMI mają charakter obiektów zdalnych. Są one typowymi obiektami czasu kompilacji. Definicja obiektu tworzona jest jako klasa języka Java, a obiekty rozproszone zintegrowane zostały z językiem. Ważnym celem było zachowanie jak najwięcej z semantyki obiektów zwykłych, nierozproszonych. W sytuacjach jednak gdy przezroczystość rozproszenia pogarsza efektywność, powoduje nadmierne trudności lub jest niemożliwa do realizacji, rozproszenie obiektów jest uwidaczniane. Między obiektami zdalnymi i lokalnymi Javy istnieje zaledwie kilka subtelnych różnic: –Obiekt zdalny może być klonowany wyłącznie przez aplikację serwera. –Aby uniknąć skomplikowanej synchronizacji rozproszonej, metody synchronizowane obiektu zdalnego blokowane są na poziomie pośrednika (czyli w obrębie pojedynczej aplikacji klienta).
Java RMI Przetaczanie parametrów Poprzez parametry metod w środowisku RMI przekazywane mogą być dowolne typy proste lub obiekty serializowalne. Obiekty lokalne przekazywane są przez wartość. Ich stan serializowany jest do strumienia bajtów, przetaczany do serwera i tam wykorzystywany do odbudowy obiektu. Serializacji, a więc i przetaczaniu nie podlegają obiekty zależne od platformy, a więc zawierające deskryptory plików, uchwyty gniazd, itp. Podczas wywołania RMI parametrem może być także obiekt zdalny. Obiekty tego typu przekazywane są przez odniesienie.
Java RMI Definiowanie interfejsów Ponieważ RMI jest środowiskiem związanym wyłącznie z językiem Java, interfejsy dla obiektów rozproszonych definiowane są w postaci interfejsów Javy. Interfejs obiektu zdalnego musi dziedziczyć z interfejsu java.rmi.Remote. Interfejs ten nie dostarcza żadnych metod, służy jedynie jako oznaczenie zdalnych obiektów dla systemu RMI. Wszystkie metody interfejsu obiektu zdalnego muszą być zadeklarowane jako zgłaszające wyjątek java.rmi.RemoteException. Jest to klasa podstawowa dla wszystkich wyjątków zgłaszanych przez RMI podczas zdalnych wywołań.
Interfejsy dla obiektów zdalnych RMI import java.rmi.*; import java.io.OutputStream; public interface RMISolver extends java.rmi.Remote { public boolean solve(RMIProblemSet s) throws RemoteException; } import java.rmi.*; public interface RMIProblemSet extends Remote { public double getValue() throws RemoteException; public double getSolution() throws RemoteException; public void setValue(double v) throws RemoteException; public void setSolution(double s) throws RemoteException; }
Java RMI Implementacja serwera Serwer stanowi po prostu implementację w języku Java zadeklarowanego interfejsu (interfejsów). Obok implementacji interfejsu klasa obiektu serwerowego zazwyczaj dziedziczy z klasy java.rmi.server.UnicastRemoteObject. UnicastRemoteObject dziedziczy z RemoteServer, która jest klasą podstawową dla wszystkich obiektów zdalnych w RMI. Podklasy RemoteServer mają w zamierzeniu interpretować różne typy obiektów zdalnych (obiekty powielane, rozgłaszanie, komunikacja typu punktowego), standard RMI 1.1 wspiera jedynie komunikację typu punktowego. Tak więc UnicastRemoteObject jest jedyną klasą pochodną od RemoteServer. Dziedziczenie z UnicastRemoteObject nie jest wymagane, ale w ten sposób klasa obiektu zdanego otrzymuje kilka istotnych funkcji, które w przeciwnym przypadku musiałby być zaimplementowane przez programistę.
Implementacja obiektu zdalnego RMI import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class RMIProblemSetImpl extends UnicastRemoteObject implements RMIProblemSet { protected double value; protected double solution; public RMIProblemSetImpl() throws RemoteException { value = 0.0; solution = 0.0; } public double getValue() throws RemoteException { return value; } public double getSolution() throws RemoteException { return solution; } public void setValue(double v) throws RemoteException { value = v; } public void setSolution(double s) throws RemoteException { solution = s; }
Implementacja serwera RMI java.rmi.*; import java.rmi.server.UnicastRemoteObject; import java.io.*; public class RMISolverImpl extends UnicastRemoteObject implements RMISolver { // Konstruktor public RMISolverImpl() throws RemoteException { super(); } public boolean solve(RMIProblemSet s) throws RemoteException { boolean success = true; if (s == null) { System.out.println("No problem to solve."); return false; } System.out.println("Problem value = " + s.getValue()); try {// Solve problem here... s.setSolution(Math.sqrt(s.getValue())); } catch (ArithmeticException e) { System.out.println("Badly-formed problem."); success = false; } System.out.println("Problem solution = " + s.getSolution()); return success; }... }
Java RMI Rejestracja serwera W środowisku RMI rolę menedżera obiektów i usługi nazewniczej stanowi tzw. rejestr. Ma on charakter lokalny, tzn. uruchamiany jest na maszynie na której znajduje się zdalny obiekt. Klienci mogą wykorzystywać rejestr do pobierania uchwytów obiektów zdalnych z serwera, za pośrednictwem określonych identyfikatorów. Rejestr RMI powinien zostać uruchomiony na maszynie serwera przed uruchomieniem jego procesu, z wykorzystaniem polecenia JDK rmiregistry. Rejestr defaultowo nasłuchuje na porcie 1099, ale może zostać polecenie rmiregistry może specyfikować inny port. Proces serwera tworzy obiekt zdalny, a następnie rejestruje go w usłudze nazewniczej z wykorzystaniem funkcji Naming.rebind.
Implementacja serwera RMI java.rmi.*; import java.rmi.server.UnicastRemoteObject; import java.io.*; public class RMISolverImpl extends UnicastRemoteObject implements RMISolver {... public static void main(String argv[]) { try { // Register an instance of RMISolverImpl with the // RMI Naming service String name = "TheSolver"; System.out.println("Registering RMISolverImpl as \"" + name + "\""); RMISolverImpl solver = new RMISolverImpl(); Naming.rebind(name, solver); System.out.println("Remote Solver ready..."); } catch (Exception e) { System.out.println("Caught exception while registering: " + e); }
Java RMI Generowanie namiastki i szkieletu Aplikacja serwera, tj. interfejsy i implementacje obiektów zdalnych kompilowane są następnie w normalny sposób do kodu pośredniego Javy. Następnie kod pośredni interfejsów i klas serwera przetwarzany jest z wykorzystaniem kompilatora rmic. Kompilator ten generuje namiastki klienta i szkielety serwerowe obiektów zdalnych. Namiastka serwera pobierana będzie przez klienta po zgłoszeniu odpowiedniego żądania do rejestru RMI, szkielet natomiast służyć będzie jako interfejs między rejestrem RMI i instancjami obiektów zdalnych: myhost% rmic pakiet.RMIProblemSetImpl myhost% rmic pakiet.RMISolverImpl
Java RMI Tworzenie aplikacji klienta Jeśli serwer zarejestrował obiekt po określoną nazwą: MyObjectImpl obj = new MyObjectImpl(); Naming.rebind("Object1", obj); klient pobiera namiastkę obiektu, wykorzystując tę nazwę oraz składnię zbliżoną do URL: System.setSecurityManager(new java.rmi.RMISecurityManager()); MyObject objStub = (MyObject)Naming.lookup("rmi://objhost/Object1"); Przed pobraniem namiastki obiektu, klient instaluje specjalny menedżer bezpieczeństwa RMI, zabezpieczający przed dostępem przez obiekty zdalne do lokalnego środowiska klienta. Jeśli klient nie zainstaluje menedżera bezpieczeństwa RMI, może pobierać wyłącznie namiastki obiektów z lokalnego systemu plików.
Implementacja klienta RMI import java.rmi.*; import java.rmi.server.*; public class RMISolverClient { public static void main(String argv[]) { // Install a security manager that can handle remote stubs System.setSecurityManager(new RMISecurityManager()); // Get a remote reference to the RMISolver class String name = "rmi://objhost.myorg.com/TheSolver"; System.out.println("Looking up " + name + "..."); RMISolver solver = null; try { solver = (RMISolver)Naming.lookup(name); } catch (Exception e) { System.out.println("Caught an exception looking up Solver."); System.exit(1); }
Implementacja klienta RMI RMIProblemSetImpl s = null; try { s = new RMIProblemSetImpl(); s.setValue(Double.valueOf(argv[0]).doubleValue()); } catch (Exception e) { System.out.println("Caught exception initializing problem."); e.printStackTrace(); } try { if (solver.solve(s, 1)) { System.out.println(Wynik: " + s.getSolution()); } else { System.out.println( Blad serwera, wartosc = " + s.getValue()); } catch (RemoteException e) { System.out.println("Caught remote exception."); System.exit(1); }
Java RMI Tworzenie aplikacji klienta Zauważmy, że obiekt RMIProblemSetImpl tworzony przez klienta jest również obiektem zdalnym. Tak więc na serwer jako parametr metody solve przekazywane jest jego odniesienie, namiastka. Serwer za pośrednictwem tej namiastki odwołuje się zdalnie do obiektu RMIProblemSetImpl działającego na kliencie. Jeśli więc namiastka zdalnego obiektu przesyłana jest w sposób jawny np. jako parametr metody, nie ma potrzeby korzystania z rejestru RMI. Parametrami zdalnych obiektów mogą być również obiekty lokalne. Muszą być one przetaczane na serwer poprzez mechanizm serializacji. Obiekty serializowalne implementować muszą interfejs Serializable. Jest to interfejs znacznikowy, tzn. nie ma żadnych metod. Obiekt serializowany jest w zasadzie automatycznie, poprzez mechanizmy Javy. Istnieje jednak możliwość kustomizacji tego procesu.
CORBA Wprowadzenie Powszechna architektura pośrednika zamówień obiektowych CORBA (Common Object Request Broker Architecture) stanowi specyfikację architektury aplikacji rozproszonych opartych na obiektach, opracowaną przez konsorcjum Object Management Group (OMG), niedochodową organizację skupiającą ponad 800 członków, głównie z przemysłu. Globalna architektura CORBA składa się z czterech grup elementów, połączonych z tzw. pośrednikiem zamówień obiektowych (ORB – Object Request Broker). Pośrednik ORB tworzy trzon każdego systemu rozproszonego CORBA. Odpowiada on za komunikację między obiektami i ich klientami, ukrywając aspekty dotyczące rozproszenia oraz heterogeniczności. W wielu systemach ORB realizowany jest w postaci bibliotek oferujących podstawowe usługi komunikacyjne, które łączy się z aplikacjami klienta i serwera.
CORBA Wprowadzenie Udogodnienia CORBA (CORBA facilities) zbudowane sa na zasadzie zestawów usług obiektowych (CORBA srvices) i obejmują: –Udogodnienia poziome (horizontal facilities) – wysoko-poziomowe usługi usługi ogólnego przeznaczenia, niezależne od dziedziny zastosowań (obsługa interfejsów użytkownika, zarządzanie informacją, zarządzanie systemem, zarządzanie zadaniami). –Udogodnienia pionowe (vertical facilities) – usługi wysokiego poziomu, ukierunkowane na daną dziedzinę zastosowań, jak handel elektroniczny, bankowość, produkcja, itd.). Obiekty aplikacji Udogodnienia pionowe (dziedzinowe) Udogodnienia poziome (ogólne) Wspólne usługi obiektowe Pośrednik zamówień obiektowych (ORB)
CORBA Model obiektowy W architekturze CORBA przyjęto model obiektu zdalnego. Specyfikacje CORBY nie precyzują nigdzie co prawda, że obiekty muszą być realizowane jako obiekty zdalne, ale praktycznie niemal wszystkie implementacje tego standardu udostępniają tylko ten model. Obiekty i usługi specyfikowane są w języku opisu interfejsu CORBA IDL. Dostarcza on szczegółowej składni dla opisu metod i ich parametrów. Standard CORBA nie definiuje standardu binarnego interfejsu, a określa reguły odwzorowania specyfikacji IDL na określone języki programowania. Obecnie sformułowano takie reguły dla kilku języków, w tym dla C, C++, Javy, Smalltalku, Ady i Cobolu.
CORBA Ogólna organizacja Sieć Maszyna klienta Lokalny SO Statyczny pośrednik IDL Interfejs ORB Interfejs wywołań dynamicznych ORB Klienta Maszyna serwera Lokalny SO Interfejs ORB ORB Serwera Adapter obiektu Szkielet Interfejs szkieletów dynamicznych Realizacja obiektuAplikacja klienta
CORBA Ogólna organizacja Pośrednik ORB jest systemem wykonawczym, odpowiadającym za obsługę podstawowej komunikacji między klientem a serwerem. Gwarantuje on, że wywołanie jest przekazywane do serwera i odpowiedź jest przekazywana z powrotem do klienta. Podstawowe usługi ORB: –Manipulowanie odniesieniami obiektowymi. Szczegółowa implementacja zależy od konkretnego ORB. ORB oferuje operacje przetaczania i odwrotnego przetaczania odniesień obiektowych, tak aby można je było wymieniać między procesami. Ponadto oferuje operacje porównywania odniesień. –Uzyskiwanie początkowych odniesień do obiektów realizujących konkretną usługę CORBY, takich jak np. usługi nazewnicze. Klienci i serwery znają jedynie interfejs pośrednika ORB. Aplikacja klienta ma ponadto pośrednika, który realizuje taki sam interfejs jak obiekt, przetaczając i wysyłając zamówienia dla serwera, oraz odbierając i przetaczając odwrotnie jego odpowiedzi.
CORBA Ogólna organizacja Interfejs między pośrednikiem klienta i pośrednikiem ORB nie musi być standardowy. Generuje go kompilator IDL związany z daną implementacją środowiska CORBA. W niektórych sytuacjach klient nie zna statycznie zdefiniowanych interfejsów obiektu. Zamiast tego musi określać dynamicznie jak powinien wyglądać interfejs do konkretnego obiektu i w jaki sposób zestawić zamówienie wywołania danej usługi obiektu. W tym celu CORBA udostępnia interfejs wywołań dynamicznych (DII – Dynamic Invocation Interface), umożliwiający budowanie zamówienia w fazie wykonania. Interfejs DII udostępnia operację invoke, która przyjmuje jako parametry odniesienie obiektowe, identyfikator metody, wartości wejściowe. Wyniki zwracane są za pośrednictwem parametrów wyjściowych.
CORBA Ogólna organizacja Serwer w środowisku CORBA dostarcza adaptera obiektu, który zajmuje się przekazywaniem nadchodzących wywołań do właściwego obiektu. Rzeczywiste odwrotne przetaczanie po stronie serwera wykonywane jest przez szkielety obiektów, ale możliwe jest również aby pieczę nad nim sprawowała sama implementacja obiektu. Szkielety kompilowane są statycznie na podstawie specyfikacji IDL. Obiekt, który używa szkieletu dynamicznego musi dostarczyć właściwą implementację funkcji invoke, realizującą określone usługi dla klienta.
CORBA Magazyn interfejsów i implementacji Dla wspomagania konstruowania zamówień w fazie wykonania, CORBA oferuje magazyn interfejsów (interface repository), przechowujący definicje wszystkich interfejsów. Zazwyczaj w implementacjach standardu realizowany jest on poprzez oddzielny proces ze standardowym interfejsem dla przechowywania i odzyskiwania definicji interfejsów. Standardowy charakter mają również operacje poruszania się pośród definicji interfejsu i same definicje interfejsu. Odpowiadać one muszą regułom składni IDL. System CORBA dostarcza również z reguły magazyn implementacji. Zawiera on wszystko, co jest potrzebne do realizacji i uaktywnienia obiektów (np. serwer i port nasłuchowy, nazwa pliku wykonalnego lub biblioteki obiektu, itp.). Funkcjonalność taka jest blisko związana z pośrednikiem ORB i bazowym system operacyjnym i zależy od konkretnej implementacji środowiska.
CORBA Usługi CORBA Zbiór usług obiektowych CORBA stanowi ważną część tego standardu. Mają one charakter niezależny od aplikacji, w dużym stopniu przypominając usługi świadczone powszechnie przez systemu operacyjne. W standardzie CORBA zdefiniowana jest lista usług, nie zawsze jednak można przeprowadzić wyraźną linię rozgraniczającą poszczególne usługi. Często zachodzą one na siebie funkcjonalnie. Usługi zaprojektowane zostały na bazie modelu obiektowego CORBA. Są one więc wyspecyfikowane w języku IDL, oraz dokonano rozdziału miedzy specyfikacją interfejsu a realizacją.
CORBA Usługi CORBA Obsługa kolekcji (collection service) – obiekty kontenerowe, służące do grupowania obiektów w listy, zbiory, kolejki, itd. Obsługa zapytań (query service) – środki dla odpytywania zbiorów obiektów za pomocą deklaratywnego języka zapytań. Obsługa sterowania współbieżnością (concurrency control service) – usługa zapewniająca mechanizmy blokowania synchronizujące współbieżny dostęp przez klientów do obiektów dzielonych. Obsługa kolekcji (transaction service) – usługa umożliwiająca klientom definiowanie ciągów uaktywnień metod wielu obiektów w ramach jednej transakcji. Obsługiwane są transakcje płaskie i zagnieżdżone. Obsługa zdarzeń (event service) – środki komunikacji asynchronicznej z użyciem zdarzeń. Obsługa powiadomień (notification service) – zaawansowane środki komunikacji asynchronicznej opartej na zdarzeniach.
CORBA Usługi CORBA Obsługa uzewnętrzniania (externalization service) – usługa umożliwiająca przetaczanie i odwrotne przetaczanie obiektów, analogiczna do serializacji w Javie. Obsługa cyklu eksploatacyjnego (life cycle service) – usługa udostępniająca środki tworzenia, usuwania, kopiowania i przemieszczania obiektów. Praktyka wskazuje, że zazwyczaj oddzielnej usługi wymaga tylko tworzenie obiektów. Pozostałe operacje definiowane są przez nie same. Kluczową rolę w tworzeniu obiektów gra koncepcja fabryki obiektów (object factory), czyli obiektu używanego do tworzenia innych obiektów. Obsługa licencjonowania (licensing service) – usługa umożliwiająca dołączanie do obiektów i egzekwowanie konkretnych zasad licencjonowania, określających prawa klientów do używania obiektu. Mogą one limitować liczbę jednocześnie obsługiwanych klientów, okres dostępności obiektu, itp. Usługi nazewnicze – pozwalające nadawać obiektom nazwy czytelne dla człowieka, odwzorowywane na identyfikatory obiektów.
CORBA Usługi CORBA Obsługa właściwości (property service) – usługa dzięki której klienci mogą kojarzyć z obiektami pary (atrybut, wartość). Nie są one częścią stanu obiektu, dostarczają one jedynie informacji o obiekcie. Obsługa wymiany handlowej (trading service) – usługa dostarczająca środków publikowania i znajdywania usług oferowanych przez obiekt. Obsługa trwałości (persistence service) – usługa oferująca udogodnienia trwałego przechowywania obiektów na dysku w postaci obiektów zmagazynowanych. Obsługa zależności (relationship service) – usługa tworząca zaplecze tworzenia związków między dwoma lub więcej obiektami. Usługi bezpieczeństwa – dostarczają środków realizacji uwierzytelniania, upoważniania, kontrolowania, bezpiecznej komunikacji, niezaprzeczalności i administrowania. Obsługa czasu (time service) – uzyskiwanie aktualnego czasu z określonymi marginesami błędu.
CORBA Modele wywołań obiektów Wywołanie synchroniczne. –Klient wywołujący obiekt wysyła zamówienie do odpowiedniego serwera i blokuje się do czasu otrzymania odpowiedzi. –W przypadku awarii klientowi w końcu zostanie zgłoszony wyjątek, informujący że wywołanie nie doszło do skutku. –Semantyka wywołania co najwyżej jednokrotnego (raz albo wcale). Zamówienie jednokierunkowe. –Metoda może mieć charakter zamówienia jednokierunkowego jeżeli wyspecyfikowano, że nie zwraca ona żadnych wyników. –Wywołanie ma charakter asynchroniczny. Klient wznawia działalność natychmiast, nie czekając na odpowiedź serwera. –W zamówieniach jednokierunkowych CORBA oferowana jest tylko usługa dostarczania na zasadach dołożenia wszelkich starań aby się powiodła. Klient nie ma żadnych gwarancji, że wywołanie dojdzie do skutku.
CORBA Modele wywołań obiektów Odroczone zamówienie synchroniczne. –Metoda może mieć charakter zamówienia jednokierunkowego jeżeli wyspecyfikowano, że nie zwraca ona żadnych wyników. –Wywołanie ma charakter kombinacji zamówienia jednokierunkowego i zgody na to, by serwer odesłał wynik w trybie asynchronicznym. Klient wznawia działalność natychmiast, a ewentualnie później może być powiadomiony o dostarczeniu odpowiedzi. –Semantyka wywołania jest co najwyżej jednokrotna.
CORBA Obsługa zdarzeń W przypadkach gdy interakcja między klientem a serwerem obiektu zdalnego jest bardziej złożona, podstawowy model komunikacyjny, oparty na wywołaniach metod może okazać się niewystarczający. Zdarzenia są usługą pozwalającą na poinformowanie przez obiekt zdalny o pewnych wypadkach, tak by implementujący ten mechanizm klient mógł podjąć odpowiednie działania. Podstawowy model zdarzeń w CORBA jest prosty: –Każde zdarzenie kojarzy się z pojedynczą jednostką danych, na ogół z odniesieniem obiektowym albo wartością specyficzną dla aplikacji. –Zdarzenie powstaje u dostawcy (supplier) i jest odbierane przez konsumenta (consumer). –Zdarzenia dostarczane są przez kanał zdarzeń (event channel), występujący logicznie między dostawcami i konsumentami. –Dwa podstawowe modele: pchany i ciągniony.
CORBA Obsługa zdarzeń – Model pchany W modelu pchanym (push model) po wystąpieniu każdego zdarzenia jego dostawca (i zarazem twórca) wypycha je przez kanał komunikacyjny, który przekazuje zdarzenie do klientów. Model pchany najbliższy jest zachowaniu asynchronicznemu. Konsumenci czekają pasywnie na nadchodzące zdarzenia, spodziewając się w formie takiego lub innego przerwania. Kanał zdarzeń Dostawca Konsument Wypchnij zdarzenie do konsumentów
CORBA Obsługa zdarzeń – Model ciągniony W modelu ciągnionym (pull model) konsumenci dowiadują się aktywnie czy wystąpiło zdarzenie, odpytując o nie kanał. W reakcji na to kanał odpytuje różnych dostawców. Kanał zdarzeń Dostawca Konsument Poproś o nowe zdarzenie
CORBA Obsługa powiadomień Ten prosty i oczywisty model propagacji zdarzeń ma kilka poważnych wad: –Do rozchodzenia się zdarzeń niezbędne jest aby dostawcy i konsumenci byli podłączeni do kanału zdarzeń. Oznacza to również, że jeśli konsument połączy się z kanałem po wystąpieniu zdarzenia, to ulegnie ono zagubieniu. –Brak jest niemal zupełnie środków dla filtrowania zdarzeń przez konsumentów. W zasadzie każde zdarzenie przekazywane jest do każdego konsumenta. Jeśli zachodzi potrzeba wyodrębniania różnych typów zdarzeń, to konieczne staje się utworzenie odrębnego kanału dla każdego typu. Możliwości filtrowania dodano do rozszerzenia, zwanego obsługą powiadomień. Usługa ta oferuje ponadto środki zapobiegające rozchodzeniu się danego zdarzenia, jeśli żaden z konsumentów nie jest nim zainteresowany.
CORBA Protokoły Do komunikacji między obiektami klienta i serwera pośrednicy ORB wykorzystują protokół zgodny ze ogólnym protokołem pośredników ORB (GIOP – General Inter-ORB Protocol). Protokół GIOP jest elementem standardu CORBA, który może być implementowany na bazie różnych protokołów transportowych. Realizacja na bazie protokołu TCP nazywana jest internetowym protokołem wymiany między pośrednikami ORB (IIOP – Internet Inter-ORB Protocol). Protokół GIOP i dowolna jego realizacja rozpoznają osiem różnych typów komunikatów.
CORBA Komunikaty GIOP Zamówienie (Request) – komunikat ten zawiera kompletne przetoczone zamówienie, składające się z odniesienia obiektowego, nazwy uaktywnianej metody i wszystkich niezbędnych parametrów wejściowych. Odniesienie obiektowe i nazwa metody są częścią nagłówka. Każdy komunikat zamówienie ma także własny identyfikator zamówienia, używany później do dopasowania właściwej z nadchodzących odpowiedzi. Odpowiedź (Reply) – zawiera przetoczone wartości zwracane i parametry wyjściowe skojarzone z uprzednio wywołaną metodą. Metody obiektu nie trzeba jawnie określać – wystarczy zwrócenie odpowiedniego identyfikatora zamówienia. Zamówienie lokalizacji (Locate Request) – wysyłane przez klienta do magazynu implementacji, z prośbą o podanie szczegółów dotyczących dotarcia do konkretnego obiektu.
CORBA Komunikaty GIOP Odpowiedź z lokalizacją (Locate Reply) – odpowiedź magazynu implementacji. Zazwyczaj identyfikuje aktualny serwer obiektu do którego możemy wysyłać zamówienia wywołań. Zamówienie kasowania (Cancel Request) – wysyłane przez klienta, który chce anulować poprzednio wysłany komunikat Zamówienie lub Zamówienie lokalizacji. Anulowanie zamówienia oznacza, że klient nie jest już gotów czekać na odpowiedź serwera. Z anulowania zamówienia nie wynika jednak, że nie zostanie ono wykonane. Z tym problemem musi poradzić sobie aplikacja klienta. Zamknij połączenie (Close Connection) – Połączenie z serwerem w protokole GIOP zawsze nawiązuje klient. Od serwerów oczekujemy przyjmowania lub odrzucania zamówień, a nie ustanawiania przez nie z własnej inicjatywy połączeń z klientem. Do zamknięcia połączenia uprawnieni są zarówno klient jak i serwer, w związku z tym wysyłają drugiej stronie powyższy komunikat.
CORBA Komunikaty GIOP Błąd komunikatu (Message Error) – służy do powiadomienia drugiej strony o wystąpieniu błędu. Wysyłany może być zarówno przez serwer jak i przez klienta. Jest to metoda podobna do komunikatów ICMP w protokole internetowym, używanych do zwracania informacji o błędzie, gdy stanie się coś złego. Fragment (Fragment) – Protokół GIOS umożliwia dzielenie poszczególnych komunikatów zamówienia i odpowiedzi na części. W ten sposób łatwo można zrealizować wywołania wymagające przesyłu między klientem a serwerem dużych ilości danych. Części są specjalnymi komunikatami Fragment, w których identyfikowany jest komunikat oryginalny, umożliwiającymi jego ponowne zestawienie u odbiorcy. Wysyłany może być zarówno przez serwer jak i przez klienta.
CORBA (Java) Interfejsy IDL module DCJ { module examples { interface ProblemSet { double getValue(); void setValue(in double v); double getSolution(); void setSolution(in double s); }; interface Solver { boolean solve(inout ProblemSet s); };
CORBA (Java) Wygenerowane interfejsy Javy package DCJ.examples; public interface ProblemSet extends org.omg.CORBA.Object { double getValue(); void setValue(double v); double getSolution(); void setSolution(double s); } package DCJ.examples; public interface Solver extends org.omg.CORBA.Object { boolean solve(DCJ.examples.ProblemSetHolder s); }
CORBA (Java) Wygenerowane interfejsy Javy Do kompilacji interfejsów IDL CORBA w Javie wykorzystywany jest kompilator idltojava. Zazwyczaj jego wywołanie wygląda następująco: myhost% idltojava -fclient Solver.idl Dla każdego zadeklarowanego interfejsu generowany jest (zazwyczaj w odrębnym pliku) odrębny interfejs w języku Java. Generowana jest również klasa namiastki klienta (pośrednika), o mniej więcej następującej strukturze: public class _SolverStub extends org.omg.CORBA.portable.ObjectImpl implements dcj.examples.Solver {...
CORBA (Java) Wygenerowane szkielety Kompilator idltojava generuje również szkielety obiektów serwerowych: myhost% idltojava -fserver Solver.idl Wygenerowane zostaną ponownie interfejsy klas w Javie, a także szkielety o następującej strukturze: public abstract class _SolverImplBase extends org.omg.CORBA.portable.ObjectImpl implements DCJ.examples.Solver, org.omg.CORBA.portable.Skeleton {...
CORBA (Java) Implementacja obiektów serwerowych package DCJ.examples; public class ProblemSetImpl extends _ProblemSetImplBase { protected double value; protected double solution; public double getValue() { return value; } public void setValue(double v) { value = v; } public double getSolution() { return solution; } public void setSolution(double s) { solution = s; } }
CORBA (Java) Implementacja obiektów serwerowych import java.lang.*; import java.io.*; import org.omg.CORBA.*; import org.omg.CosNaming.*; public class CORBASolverImpl extends _SolverImplBase { // Constructors public CORBASolverImpl() { super(); } public boolean solve(ProblemSetHolder sh) { ProblemSet s = sh.value; boolean success = true; if (s == null) { System.out.println(Error"); return false; } System.out.println("Problem value = " + s.getValue()); // Solve problem here... try { s.setSolution(Math.sqrt(s.getValue())); } catch (ArithmeticException e){ System.out.println("Err"); success = false; } System.out.println("Problem solution = " + s.getSolution()); return success; }...
CORBA (Java) Implementacja obiektów serwerowych public static void main(String argv[]) { try { // create and initialize the ORB System.out.println("Initializing ORB..."); ORB orb = ORB.init(argv, null); // Create a Solver and register it with the ORB System.out.println("Connecting solver to ORB..."); CORBASolverImpl solver = new CORBASolverImpl(); orb.connect(solver); // Get the naming service from the ORB System.out.println("Getting reference to Naming Service..."); org.omg.CORBA.Object ncObj = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(ncObj); // Bind the Solver object to a name System.out.println("Registering Solver with Naming Service..."); NameComponent comp = new NameComponent("Solver", ""); NameComponent path[] = {comp}; ncRef.rebind(path, solver);...
CORBA (Java) Implementacja obiektów serwerowych public static void main(String argv[]) {... // Wait for client requests System.out.println("Waiting for clients..."); java.lang.Object dummySync = new java.lang.Object(); synchronized (dummySync) { dummySync.wait(); } catch (Exception e) { System.err.println(e); e.printStackTrace(System.out); }
CORBA (Java) Implementacja klienta import org.omg.CORBA.*; import org.omg.CosNaming.*; public class CORBASolverClient { public static void main(String argv[]) { try { // Create an ORB ORB orb = ORB.init(argv, null); // Get a reference to the Naming Service org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService"); NamingContext nc = NamingContextHelper.narrow(obj); // Get a reference to the Solver on the remote host NameComponent comp = new NameComponent("Solver", ""); NameComponent path[] = {comp}; org.omg.CORBA.Object sobj = nc.resolve(path); Solver solver = SolverHelper.narrow(sobj);...
CORBA (Java) Implementacja klienta import org.omg.CORBA.*; import org.omg.CosNaming.*; public class CORBASolverClient { public static void main(String argv[]) { try {... // Make a problem and ask the solver to solve it ProblemSet s = new ProblemSetImpl(); s.setValue(173.39); solver.solve(new ProblemSetHolder(s), 1); // Print out solution System.out.println("Problem = " + s.getValue()); System.out.println("Solution = " + s.getSolution()); } catch (Exception e) { System.out.println(e) ; e.printStackTrace(System.out); }