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.

Podobne dokumenty