PZR420 - ćw - temat C
Obiekty rozproszone CORBA.
CORBA = Common ORB Architecture
literatura i inne materiały ...
- http://www.omg.org - główna
strona organizacji OMG która zajmuje się tworzeniem specyfikacji CORBA
- "Overview of CORBA" - rozdział z pewnej
książki
- "Distributed Object Computing with CORBA"
- ogólne wprowadzenie
- "CORBA: Integrating Diverse Applications
Within Distributed Heterogeneous Environments"- ogólne wprowadzenie
- "Introduction to OMG IDL" - opis języka
IDL pozwalającego definiować interfejsy obiektów CORBA
- "Chapter 11. The Portable Object Adapter"
- rozdz. 11 specyfikacji CORBA
- "An Overview of the CORBA Portable Object
Adapter" - opis POA czyli środowiska w którym "siedzą" obiekty CORBA
- "The
POA interface" - inny opis POA (rozdział książki "GNOME
& CORBA")
- "New Features for CORBA 3.0"- nowe cechy
CORBA wprowadzone w wersji 3.0 specyfikacji
- http://www.fpx.de/Combat
-
broker języka skryptowego Tcl (tu znajdziesz oprogramowanie i
dokumentacje Combat-a)
- http://java.sun.com/j2se/1.4.2/docs/guide/corba/index.html
- Java IDL, czyli broker wbudowany w język Java
- Orfali, Harkey "Client/Server Programming with Java & CORBA"
- książka
- McHale "CORBA EXPLAINED SIMPLY" książka (chyba dobra...)
krótkie przykłady użycia obiektów
CORBA ...
- przykład
używania obiektów CORBA z poziomu Combat-a
(broker CORBA języka Tcl)
- przyklad
z poziomu Java IDL (broker
"wbudowany" w język Java); uwaga: w tych przykładach nie uzywa sie POA!
- przyklad
z poziomu ORBit-a (bardzo
"lekki" broker języka C)
wyjaśnienie "skrotów" ...
- OMG = Object Management
Group; organizacja która stworzyła CORBA
- ORB = Object Request
Broker; inaczej "broker CORBA" - oprogramowanie które pozwala na dostęp
do obiektów CORBA; ORB istnieje zarówno po stronie klienta
(=użytkownika
obiektów), jak i po stronie serwera (=implementatora obiektów)
- IDL = Interface
Definition
Language - język opisu interfejsów udostępnianych przez obiekty CORBA
- IOR = Interoperable
Object Reference - string zawierający referencje do obiektu CORBA
(zawiera m.in. adres IP serwera udostępniającego ten obiekt)
- OA = Object Adapter
- środowisko w którym przebywają obiekty CORBA (zestaw procedur dzięki
którym obiekt CORBA może się "zarejestrować" w ORB)
- POA = Portable Object
Adapter - przenośne OA (BOA =
Basic Object Adapter - to przestarzała wersja OA)
- IIOP / GIOP = Internet
Inter-ORB Protocol / General Inter-ORB Protocol; protokół przy pomocy
którego rozmawiają ORB na różnych maszynach; IIOP - oparty na Tcp/Ip;
GIOP - protokół nie związany z konkretnym transportem
- COS = Common Object
Services - usługi CORBA: COSNaming/NameService,
COSProperty/PropertyService, itp
- DSI = Dynamic Skeleton
Interface - implementacja obiektu CORBA bez statycznego szkieletu
(ang. skeleton)
- DII = Dynamic Invocation
Interface - umożliwia używanie obiektów CORBA bez statycznego pieńka
(ang.
stub) i pliku IDL
- IR (lub IFR) = Interface Repository - baza
danych z opisem interfejsów obiektów CORBA; zawiera te same informacje
co pliki IDL, ale w postaci czytelnej dla maszyny; IR jest
używane przez DII/DSI
Podstawowe pojęcia CORBA.
- CORBA pozwala używać
obiektów zdalnych (rezydujących na innej maszynie - to są własnie obiekty CORBA) tak jakby to były
zwykłe, lokalne obiekty ...
- (klient i serwer, ORB); klient to program który używa
obiektu CORBA, serwer to
program który zawiera implementację obiektu CORBA; między klientem a
serwerem pośredniczą ORB (ORB musi być zainstalowane zarówno na
maszynie
klienta jak i serwera); ORB rozmawiają przy pomocy protokołu IIOP;
oprogramowanie ORB jest potocznie nazywane "brokerem" ...
Rys 1. ORB pośredniczy między
klientem i serwerem:
Rys 2. klient używa obiektu na
tej samej oraz na zdalnej maszynie:
- (interfejs, język IDL);
każdy obiekt CORBA
posiada interfejs czyli zbiór
funkcji (metod) które można wywoływać na rzecz tego obiektu; interfejs
obiektu jest opisany w języku ID; przykład:
module HelloApp
{
interface Hello
{
string sayHello();
string przetworzString(in string parametr);
long podajLiczbe();
typedef long tab[10];
void wektorRazyDwa(in tab tab1, out tab tab2);
};
};
- (typ interfejsowy/ typ valuetype)
obiekt CORBA to formalnie instancja typu interfejsowego; parametr/wynik
metody może być typu interfejsowego - oznacza to przekazywanie obiektu przez referencję; w CORBA istnieje
drugi rodzaj obiektów: valuetype
- parametry typu valuetype są przekazywane przez wartość (ObjectByValue)
- (stub/skeleton); mając
plik IDL możemy przy pomocy specjalnego kompilatora wygenerować stub oraz skeleton; są to moduły programowe;
stub (pieniek) jest po
stronie
klienta i pozwala używać obiektu CORBA jakby to był zwkły lokalny
obiekt; skeleton (szkielet)
jest po stronie serwera i umożliwia implementacje obiektu; stub i
skeleton zajmują się m.in. przesyłaniem przez sieć parametrów metod
wywoływanych na rzecz obiektu CORBA oraz przesyłaniem wyników tych metod
Rys 3. składniki CORBA nieco
dokładniej:
- (referencja do
obiektu CORBA; IOR); obiekty CORBA mają identyfikatory; mogą być
one przechowywane jako string, w postaci IOR; można zamienić IOR na odniesienie (ang. reference) do
obiektu CORBA przy pomocy funkcji string_to_object;
w drugą stronę przy pomocy object_to_string
Rys 4. co zawiera IOR:
- (usługi/serwisy CORBA);
COS =
Common Object Services czyli usługi
CORBA - są to pewne standardowe usługi przydatne obiektom CORBA;
przykład takiej usługi: NamingService,
czyli usługa nazewnicza, pozwala nadawać obiektom CORBA nazwy widoczne
w
sieci, nazwy te tworza hierarchię (drzewo kataogów);
UWAGA:
usługi są
"zwykłymi" obiektami CORBA i ich formalna definicja to plik IDL;
oznacza to, że każdy broker potrafi skorzystać z usługi
zaimplementowanej dla innego brokera ...
- skąd klient bierze odniesienie
do pierwszego obiektu CORBA?
1. wystarczy ze klient otrzyma w dowolny sposób IOR pierwszego obiektu;
2. klient może użyć usługi NamingService, powienien wtedy podać nazwę
obiektu (właściwie ścieżkę podobną do "ścieżki do pliku") i otrzyma od
usługi odniesienie do odpowiedniego obiektu; Uwaga: odniesienia do
pozostałych obiektów mogą być zwracane przez metody uruchamiane na
rzecz
pierwszego obiektu.
- (POA, servant, oid);
- implementację obiektu CORBA nazywamy servant-em (może to być obiekt
danego języka programowania lub "coś" innego ...)
- POA (=Portable Object Adapter) jest pośrednikiem między ORB a
servantem
- "Portable" - można przenosić kod serwera między brokerami
różych producentów
- POA jest (pseudo)obiektem CORBA; obiekty POA tworzą drzewo (dla
nowo tworzonego obiektu można ustalić tzw politykę); obiekty POA maja
identyfikatory "poa id"
- odniesienie do obiektu CORBA zawiera m.in. "poa id" i "object
id" (=oid); gdy klient uruchamia metodę obiektu CORBA, wtedy żądanie
dociera do odpowiedniego POA (na podstawie "poa id"), a następnie POA
przekazuje je do odpowiedniego servanta (na podstawie oid)
- zadania POA - podsumowanie (patrz też tutaj):
- generowanie odniesień (=referencji) do obiektów CORBA
- aktywowanie i
deaktywowanie serwantów - aktywowanie servanta w praktyce oznacza
zarejestrowanie go w ORB
- demultipleksowanie żądań do servantów (kierowanie żądania do
odp serwanta)
- wywoływanie metod servantów
- minimalny kod używający POA w języku Java i Tcl:
// założenie: orb to odnośnik do obiektu ORB; serv to odnośnik do servanta
//
// Java -------------------------------------------------------------
//
// uzyskujemy ref do pseudo-obiektu RootPOA oraz aktywujemy POAManager
POA rootpoa= POAHelper.narrow(
orb.resolve_initial_references("RootPOA"));
rootpoa.the_POAManager().activate();
// aktywujemy servanta i tworzymy ref do obiektu CORBA
org.omg.CORBA.Object ref= rootpoa.servant_to_reference(serv);
#
# Tcl ---------------------------------------------------------------
#
set rootpoa [corba::resolve_initial_references "RootPOA"]
[$rootpoa the_POAManager] activate
set ref [$rootpoa servant_to_reference $serv]
- czym się CORBA różni od RMI ?
- RMI jest
nierozerwalnie związane z językiem Java, CORBA jest niezależna od
języka
programowania; interfejs obiektu RMI opisuje się w języku Java
(interfejsy samoistne języka Java); interfejs obiektu CORBA opisuje się
w języku
IDL
- RMI posiada niewiele "serwisów systemowych" (tylko rejestr
rmi); CORBA posiada bardzo wiele takich serwisów (patrz spis
specyfikacji serwisów CORBA: corbaservices_spec_catalog
- CORBA umożliwia w większym stopniu "zarządzanie" obiektami na
serwerze (poprzez POA)
- używanie CORBA bez statycznego
stub/skeleton
Służy do tego DII; DII wymaga obiektu pomocniczego IR (=Interface
Repository), który pamięta definicje interfejsów w postaci czytelnej
dla
programów; DII+ IR pełnią zasadniczo tę samą funkcję co stub. Po
stronie
serwera można użyć DSI +IR, które pełnią tę samą funkcję co skeleton. W
brokerze Combat używa się wyłącznie DII + DSI + lokalny IR (nie ma
pienka/szkieletu).
- obiekty CORBA vs pseudoobiekty
ORB i POA to pseudoobiektów; IR oraz COS to "prawdziwe" obiekty CORBA
POA - więcej szczegółów.
Co to znaczy "aktywować serwant-a" ?
- POA zawiera tablicę Active Object Map, która kojarzy oid z
serwantem
- aktywowanie serwanta to własnie ustalenie związku oid-u i serwanta
- jest możliwe że jeden serwant ma przypisanych wiele różnych
oid-ów; tak więc nie należy
utożsamiać obiektu CORBA i serwanta bedącego jego implementacją !
- możemy przyjąć
że
obiekty CORBA są "wirtualne" i powstają w momencie aktywowania
serwanta;
serwant moze być aktywowany /deaktywowany wielokrotnie; obiekt CORBA
jest
jednoznacznie wyznaczony przez poa_id+oid
- szczegółowy opis POA jest w specyfikacji CORBA (specyfikacja CORBA v2.3): rozdz 11
Inne pojęcia POA:
- słowniczek pojęć POA ze specyfikacji CORBA (rozdz. 11) (wstaw
link)
- (Object ID); w referencji
do obiektu CORBA jest zawarty oid (=Object ID); oid jest ukryty przed
klientem, widoczny jedynie na serwerze, w obiekcie POA; każdy POA ma
własną przestrzeń nazw oid; fizycznie oid może być napisem
- (polityka POA); definiuje
sposób zachowania się POA; przykłady polityk:
- Thread Policy: ORB_CTRL_MODEL lub SINGLE_THREAD_MODEL
druga stała oznacza że wszystkie żądania klientów są obsługiwane na 1
wątku
- ID Assignment Policy: SYSTEM_ID lub USER_ID
kto tworzy nowe oid-y, system czy użytkownik
- RootPOA ma ustawioną politykę
IMPLICIT_ACTIVATION ("niejawne aktywowanie")
dlatego nie trzeba aktywować obiektów bezpośrednio - przez
activate_object
- (drzewo obiektów POA); na
serwerze istnieje drzewo obiektów POA, jego korzeń nazywa się "RootPOA"
(ten napis to właśnie poa_id); podczas tworzenia nowego liścia drzewa
określa się jego politykę
- (POAManager); jest
odpowiedzialny za przekazywanie żadań do POA i do ich serwantów; można
go aktywować (metoda activate), spowodować że będzie wstrzymywał
żądania
(hold_request), lub odrzucał (discard_requests)
- (ServantManager); jest to
"procedura" uruchamiana podczas pierwszego odwołania do obiektu CORBA
oraz podczas deaktywowania tego obiektu; procedura ta składa się z
dwóch
podprocedur: incarnate i etherealize; ten mechanizm wymaga plityki
USE_SERVANT_MANAGER
Jakie efekty można uzyskać przy pomocy
POA ?
- 1 servant obsługuje wiele obiektów CORBA; servant odczytuje oid
bieżącego obiektu i w ten sposób je rozróżnia;
- można tworzyć servanta i obiekt CORBA automatycznie przy
pierwszym odwołaniu do tego obietku; do tego celu służy ServantManager
...
- ???
ORB dla różnych języków programowania.
Pokazemy miniaturową aplikcję używającą obiektu CORBA z takim
interfejsem:
Plik Hello2.idl ...
module HelloApp2
{
interface Hello
{
string sayHello();
string sayHello2(in string we);
long podajLiczbe();
Hello sayHello_nowyObiekt();
typedef long tab[10];
void wektorRazy2(in tab tab1, out tab tab2);
};
};
Java IDL - broker języka
Java.
Wszystkie potrzebne pliki Java są tutaj.
Trzeba skompilować plik IDL przy pomocy kompilatora idlj
idlj -fall Hello2.idl
Kod serwera ...
import HelloApp2.*;
import org.omg.CORBA.*;
// na użytek POA
import org.omg.PortableServer.*;
// na użytek NameService
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import java.io.*;
// klasa servant-a
class HelloServant2 extends HelloPOA
{
private int licz;
private String str;
private ORB orb;
HelloServant2(ORB _orb)
{
super();
System.out.println("HelloServant2()");
licz=0; str=""; orb=_orb;
}
public String sayHello()
{
System.out.println("sayHello()"); // napis pojawi sie na serwerze
return "Hello world !!!";
}
public int podajLiczbe()
{
System.out.println("podajLiczbe(), "+licz);
return licz++;
}
public String sayHello2(String _str)
{
String s= _str + "[" + str+ "]";
str= s;
return s;
}
// nie zaimplementowane ...
public Hello sayHello_nowyObiekt()
{
return null;
}
// metoda o bardziej skomplikowanych parametrach ...
public void wektorRazy2(int[] tab1, HelloApp2.HelloPackage.tabHolder tab2)
{
System.out.println("wektorRazy2()");
tab2.value= new int[10];
for(int i=0; i<10; i++) tab2.value[i]=tab1[i]*2;
}
}
// glowna klasa serwera
public class HelloServer2 {
public static void main(String args[])
{
try{
// tworzymi i inicjujemy ORB
ORB orb = ORB.init(args, null);
// tworzymy serwanta
HelloServant2 serv= new HelloServant2(orb);
POA rootpoa= POAHelper.narrow(
orb.resolve_initial_references("RootPOA"));
rootpoa.the_POAManager().activate();
// aktywujemy servanta i tworzymy ref
// (w tym momencie powstaje obiekt CORBA !!!)
org.omg.CORBA.Object ref= rootpoa.servant_to_reference(serv);
// zapisujemy IOR w pliku
String IOR= orb.object_to_string(ref);
System.out.println("IOR="+IOR);
PrintWriter out= new PrintWriter(new BufferedWriter(new FileWriter("Hello.IOR")));
out.println(IOR); out.close();
/* // tworzenie wpisu w NameService
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent("Hello2", "");
NameComponent path[] = {nc};
ncRef.rebind(path, serv);
*/
// czekamy na żądania klientow ...
orb.run();
} catch (Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
}
}
Kod klienta ...
import HelloApp2.*;
import org.omg.CORBA.*;
import java.io.*;
public class HelloClient2
{
public static void main(String args[])
{
try{
// tworzymi i inicjujemy ORB
ORB orb = ORB.init(args, null);
// odczytujemy IOR
BufferedReader in= new BufferedReader(new FileReader("Hello.IOR"));
String IOR=in.readLine(); in.close();
// zamieniamy IOR na odniesienie do obiektu CORBA
org.omg.CORBA.Object obj= orb.string_to_object(IOR);
// "zawężamy" typ obiektu:
// org.omg.CORBA.Object -> HelloApp2.Hello
// teraz bedzie można wywolywac metody na rzecz tego obiektu
Hello helloRef= HelloHelper.narrow(obj);
System.out.println("podajLiczbe="+helloRef.podajLiczbe());
System.out.println("sayHello="+helloRef.sayHello());
} catch (Exception e) {
System.out.println("ERROR : " + e) ;
e.printStackTrace(System.out);
}
}
}
Combat - broker języka Tcl.
Interpreter tcl 8.4 z wbudowanym Itcl-em: tclkit
(linux), tclkit.exe (win)
dokumentacja Tcl:
tcl8.4
docs, Itcl
docs
konsola do eksperymentow: konsola2c.tcl
sposob uzycia konsoli: tclkit
konsola2c.tcl skrypt.tcl &
Strona brokera Combat: http://www.fpx.de/Combat/
Pakiet Combat combat.tar.gz (wersja z
poprawkami!!)
nalezy wypakowac katalog
combat-tcl-0.7.4
dodac sciezke do tego katalogu do
zm. auto_path !!!
Przykładowy klient i serwer pod Combat-em znajdziesz tutaj
Plik IDL kompilujemy tak: itcl2tcl Hello3.idl; idl2tcl.zip
(win), idl2tcl.tar.gz (lin)
(lin: najpierw ". e_idl2tcl"-trzeba
uaktualnić ten skrypt!; potem "tclsh idl2tcl.tcl Hello3.idl"
Uwaga:
ta wersja zawiera całego
brokera mico2.3.12 oraz combat/cpp !!!)
Program idl2tcl tłumaczy plik Hello3.idl na specjalny string, który
można potem
załadować do (lokalnego) IR
Informacje z IR są używane gdy uruchamiamy metody obiektu CORBA (sa
używane po stronie klienta jak i serwera):
set m [corba::string_to_object $ior]
$m podajLiczbe
Wynik "corba::string_to_object $ior" to uchwyt (ang. handle) wg
terminologii Combat-a; zawiera on ref do obiektu ORAZ procedurę
sprawdzającą poprawność metody i jej parametrów na podstawie danych z
IR; uchwyt jest procedurą Tcl, gdy nie jest już potrzebny musi być
jawnie zniszczony przy pomocy corba::release; IOR zawiera(?) Repo_ID,
który określa jakiego interfejsu opisanego w IR używa nasz obiekt;
zawartość IOR można odczytać przy pomocy skrptu iordump.tcl
(Uwaga
- uruchamianie iordump.tcl: tam gdzie jest tclsh "tclsh
iordump.tcl plik_IOR",
w przypadku używania "tclkit" pod Windows trzeba
zastąpić "exit" w
ostatniej linii pliku iordump.tcl przez "console show"
i uruchamiać z konsoli przez "tclkit iordump.tcl
plik_IOR").
UWAGA:
zasadnicza różnica między Combat-em i JavaIDL ...
Combat zawsze używa
DII (dynamicznej CORBY); plik IDL jest mu tylko i wyłącznie potrzebny
do "karmienia" lokalnego IR, z którego sa pobierane dane o
metodach i typach param/wyniku;
można także używać zdalnego IR i wtedy plik IDL nie jest w
ogóle potrzebny!
JavaIDL używa pliku IDL do utworzenia statycznego pieńka
DII też jest w Javie możliwe, ale bardziej skomplikowane!
UWAGA 2
: serwer CORBA pod Combatem jest jednowątkowy/ zdarzeniowy
tj nadaje się do użytku tylko jeśli metody są krótkotrwałe
(mimo to na jednym wish-u można utworzyć dowolną liczbę
ob, Corba)
Kod serwera ...
lappend auto_path ./combat-tcl-0.7.4
package require Itcl
package require combat
# definiujemy serwant-a jako klasę itcl ...
# klasa posiada definicje wiekszości metod Hello3.idl
#
itcl::class HelloWorld {
inherit PortableServer::ServantBase
public method _Interface {} {
return "IDL:HelloApp2/Hello:1.0"
# mozna to wyciagnac z pliku Hello3.tcl
# to jest Repo_ID interfejsu
}
public method sayHello {} {
return "Jak sie masz ???"
}
public method sayHello2 {_str} {
return "sayHello2: _str=$_str"
}
public method podajLiczbe {} {
set x $liczba; incr liczba
return $x
}
private variable str ""
private variable liczba 0
}
source Hello3.tcl
combat::ir add $_ir_Hello3
# ladujemy do IR definicje interfejsu
set obj [HelloWorld #auto]
# tworzymy serwanta
# parametr #auto oznacza ze itcl sam wybierze nazwe obiektu itcl
### POA -------------------------------------------------------
set poa [corba::resolve_initial_references "RootPOA"]
# uzyskujemy ref do RootPOA
set mgr [$poa the_POAManager]
# uzyskujemy ref do POAMgr-a
$mgr activate
# aktywujemy POAManager
set ref [$poa servant_to_reference $obj]
# w tym momencie:
# - aktywowaliśmy serwanta (<=> utworzyliśmy obiekt CORBA)
# - utworzyliśmy referencję do obiektu CORBA
set ior [corba::object_to_string $ref]
# zamieniamy ref na IOR
set f [open "Hello.IOR" "w"]; puts $f $ior; close $f
# zapisujemy IOR w pliku
### -----------------------------------------------------------
#vwait nieskonczenie
# to jest niezbedne spod tclsh; jeśli używamy wish to można pominąć
Kod klienta ...
lappend auto_path ./combat-tcl-0.7.4
package require combat
source Hello3.tcl
combat::ir add $_ir_Hello3
# dodajemy wpis do (local) Interface Repository
set f [open "Hello.IOR" "r"]; set ior [read $f]; close $f
# plik Hello.IOR zawiera IOR do obiektu CORBA
# plik ten został utworzony przez serwer
set m [corba::string_to_object $ior]
# zamieniamy IOR na referencję do obiektu CORBA (zmienna "m")
# teraz można wydawać komendy
# $m metoda parametr1 parametr2 ...
$m podajLiczbe
$m podajLiczbe
# powinno zwrócic dwie kolejne liczby
$m sayHello2 "A ku ku !!!"
Zadania.
Zadanie 20
(wypróbować gotowe przykłady +
proste eksperymenty)
Spróbuj skompilować i uruchomić przykłady zawarte w plikach przykład
Java i przykład
Tcl. W tym zadaniu uruchamiaj jedynie prostą metodę sayHello().
Wypróbuj działanie klienta/serwera CORBA w nastepujących konfiguracjach:
klient serwer
1. java java
2.
tcl tcl
3. java
tcl
4.
tcl java
Przekazywanie ref do obiektu CORBA zrealizuj poprzez IOR zapisany w
pliku.
Wykonaj też inne podobne eksperymenty (bez programowania) i opisz je w
sprawozdaniu ...
Zadanie 21
(nie tak proste eksperymenty)
Korzystając z przykładowego kodu z zadania 20 wypróbuj następujace
możliwości:
- obiekt CORBA posiada metodę która tworzy nowy obiekt CORBA i
zwraca referencje do tego obiektu; wypróbuj działanie tak tworzonych
obiektów przy pomocy metody podajLiczbe() której kolejne wywołania
zwracają
kolejne liczby całkowite (oczywiście o ile to są wywołania na rzecz
tego
samego obiektu CORBA)
- obiekt CORBA posiada metodę która się długo wykonuje i wyświetla
okresowo napisy w okienku serwera; sprawdź co się stanie gdy kilku
klientów równocześnie uruchomi taką metodę (czy rzeczywiście będą się
wykonywać na osobnych wątkach ?)
- klient CORBA jest równocześnie serwerem i uruchamia metode na
rzecz zdalnego obiektu, która uruchamia metode lokalnego obiektu (czyli
uzyskujemy efekt "callback")
Zadanie 22
(przekazywanie złożonych str
danych - znajomość języka IDL)
- Zaprogramuj ob. CORBA który posiada metodę "pomnoz" mnożącą przez
podaną stałą wektory dowolnej
długości i zwracającą wynik wektorowy (typ "sequence"); broker dowolny.
Dodaj metodę "pomnoz10" mnożąca wyłącznie wektory długości 10 (typ
"zwykła tablica"); zbadaj czy Combat przestrzega tego ograniczenia.
- Zaprogramuj ob. CORBA który potrafi obliczać
wyznacznik macierzy (albo sume elementów macierzy) o dowolnych
wymiarach. Klient ma być zaprogramowany
w języku Java lub Tcl, serwer w języku Java.
Zadanie
23
(eksperymenty z POA w języku
Java)
Spróbuj "przetłumaczyć" na język Java poniższy kod w Tcl/Combat;
potem sprawdz jak to działa.
#
# jeden serwant obsługuje dwa obiekty CORBA (ma przypisane 2 różne oid-y)
#
#
# serwer ...
#
package require combat
class HelloWorld {
inherit PortableServer::ServantBase
public method _Interface {} {
return "IDL:HelloApp2/Hello:1.0"
}
public method sayHello {} {
# serwant odczytuje oid swojego obiektu CORBA ...
#
set poa [corba::resolve_initial_references "POACurrent"]
set oid [$poa get_object_id]
puts "get_object_id=$oid"
# komunikat diagnostyczny po stronie serwera
return "get_object_id=$oid"
}
public method podajLiczbe {} {
}
private variable liczba 0
}
source Hello3.tcl
combat::ir add $_ir_Hello3
set obj [HelloWorld #auto]
### POA -------------------------------------------------------
set poa [corba::resolve_initial_references "RootPOA"]
set mgr [$poa the_POAManager]
$mgr activate
set mypoa [$poa create_POA "MyPOA" $mgr {USER_ID MULTIPLE_ID}]
# włączyliśmy polityki które pozwalaja na:
# - oid-y generuje użytkownik
# - 1 serwant może mieć wiele skojarzonych oid-ow
$mypoa activate_object_with_id "HelloWorld_A" $obj
$mypoa activate_object_with_id "HelloWorld_B" $obj
# tworzymy 2 obiekty CORBA z tym samym servantem
# obiekty te maja oid-y "HelloWorld_A" i "HelloWorld_B"
set ref_A [$mypoa id_to_reference "HelloWorld_A"]
set ref_B [$mypoa id_to_reference "HelloWorld_B"]
# tworzymy odniesienia do obiektow CORBA
set ior [corba::object_to_string $ref_A]
set f [open "Hello_A.IOR" "w"]; puts $f $ior; close $f
set ior [corba::object_to_string $ref_B]
set f [open "Hello_B.IOR" "w"]; puts $f $ior; close $f
# tworzymy i zapisujemy IORy do plików
### -----------------------------------------------------------
vwait nieskonczenie
#
# klient ...
#
package require combat
source Hello3.tcl
combat::ir add $_ir_Hello3
set f [open "Hello_A.IOR" "r"]; set ior_A [read $f]; close $f
set f [open "Hello_B.IOR" "r"]; set ior_B [read $f]; close $f
set m_A [corba::string_to_object $ior_A]
set m_B [corba::string_to_object $ior_B]
$m_A podajLiczbe
$m_B podajLiczbe
$m_B podajLiczbe
Zadanie 24
(eksperymenty z POA w języku
Java)
Spróbuj "przetłumaczyć" na język Java poniższy kod w Tcl/Combat;
potem sprawdz jak to działa.
#
# obiekt CORBA i serwant sa tu tworzone przy pierwszym odwolaniu do ref
#
#
# serwer ...
#
package require combat
class HelloWorld {
inherit PortableServer::ServantBase
public method _Interface {} {
return "IDL:HelloApp2/Hello:1.0"
}
public method sayHello {} {
return "Jak sie masz ???"
}
public method sayHello2 {_str} {
}
public method podajLiczbe {} {
}
private variable str ""
private variable liczba 0
# sprawdzamy kiedy obiekt jest tworzony/ niszczony
constructor {} {puts "HelloWorld: constructor"}
destructor {puts "HelloWorld: destructor"}
}
source Hello3.tcl
combat::ir add $_ir_Hello3
### POA -------------------------------------------------------
set poa [corba::resolve_initial_references "RootPOA"]
set mgr [$poa the_POAManager]
$mgr activate
set mypoa [$poa create_POA "MyPOA" $mgr {USE_SERVANT_MANAGER}]
# wlaczamy polityke USE_SERVANT_MANAGER
# rejestrujemy ServantManager
# - mojSM tworzy servanta przy pierwszym odwolaniu do obiektu CORBA
# - bledy w mojSM sa bardzo trudne do zlapania!!!
# - musi byc parametr "args" gdyz etherealize ma inne argumenty niz incarnate
# (w przeciwnym wypadku wystapi niewidzialny blad !!!)
#
$mypoa set_servant_manager mojSM
proc mojSM {komenda oid poa args} {
puts "mojSM: $komenda $oid $poa $args"
# komunikat diagnostyczny
if {$komenda=="incarnate"} then {
# podkomenda wywoływana przy pierwszym odwołaniu przez klienta do ref
set obj [HelloWorld #auto]
puts "mojSM: obj=$obj"
return $obj
}
if {$komenda=="etherealize"} then {
# deaktywaca obiektu CORBA powoduje zniszczenie serwanta
set serv [lindex $args 0]
puts "mojSM: serv=$serv"
delete object $serv
}
}
set ref [$mypoa create_reference "IDL:HelloApp2/Hello:1.0"]
puts "ref=$ref"
# tworzymy ref do obiektu CORBA bez aktywowania tego obiektu
set oid [$mypoa reference_to_id $ref]
# zeby mozna bylo deaktywowac obiekt z konsoli poleceniem:
# $mypoa deactivate_object $oid
# wtedy powinien sie uruchomic destruktor serwanta !!!
set ior [corba::object_to_string $ref]
puts "HelloWorld IOR = $ior"; set f [open {Hello.IOR} "w"]; puts $f $ior; close $f
### -----------------------------------------------------------
vwait qqq
#
# klient ...
#
package require combat
source Hello3.tcl
combat::ir add $_ir_Hello3
set f [open {Hello.IOR} "r"]; set ior [read $f]; close $f
set m [corba::string_to_object $ior]
# można uruchamiać metody ...
$m sayHello
$m sayHello
$m sayHello
# przy pierwszym odwołaniu się do obiektu CORBA
# oraz przy pierwszym odwolaniu po deaktywacji
# w okienku serwera powinien się odezwać konstruktor serwanta !!!
#UWAGA terminologiczna:
aktywacja (obiektu,serwanta, oid-u) <=> utworzenie obiektu Corby
deaktywacja <=> usuniecie obiektu Corby
Zadanie 25
(podstawowy przykład użycia
COSNaming)
Zakładam że posiadamy IOR pewnego serwera Corba ...
Napisz dwa klienty Corby (kli1 i kli2) pod dowolnym brokerem:
- niech kli1 umieszcza ref do pewnego obiektu Corby w NamingService
- niech kli2 odczytuje tę ref z NamingService (a NIE z pliku IOR) i
wywołuje pewną metodę.
Wskazówki do zad 25:
Przypominam że NamingService to zwykły obiekt Corba, którego interf
(NamingContext) opisano w specyfikacji OMG
(katalog
specyfikacji OMG - tu znajdziesz specyfikacje NamingService !!!)
Serwerem NamingService może być program "tnameserv" z JDK; program ten
wyswietla swoj IOR na stdout...
Uwaga: czasem trzeba podac opcje:
tnameserv -ORBInitialPort 10000
-ORBServerHost 1.2.3.4 > NS.IOR &
aby byl używany właściwy nr portu oraz adres
hosta!!! (sprawdzic przy pomocy iordump.tcl)
dodatkowo
trzeba przeedytowac recznie plik NS.IOR aby pozbyć sie niepotrzebnych
linii tekstu!!!
(tak aby NS.IOR zawierał wyłącznie IOR
...)
Podstawowe operacje interfejsu NamingContext: bind, resolve,
bind_context, new_context;
"context" pełni analogiczną rolę jak katalog w systemie plików...
Broker JavaIDL:
http://java.sun.com/j2se/1.4.2/docs/guide/idl/index.html
http://java.sun.com/j2se/1.4.2/docs/api/org/omg/CosNaming/package-summary.html
Broker Combat:
trzeba nakarmic lokalny IR opisem interfejsow NamingService (COS_ns.idl, COS_ns.tcl
- juz skompilowany przez idl2tcl !);
trzeba się dostać do NS poprzez jego IOR (tymczasowo skopiowac go z
ekranu po uruchomieniu tnameserv)
operacje na NS wykonuje się tak jak na każdym innym obiekcie Corba
Zadanie 26
(COSNaming - przeglądarka)
Zaprogramuj przeglądarke COSNaming pokazująca "drzewo
kontektów" graficznie ...
Aby wypróbować jej działanie musisz wypełnić serwer NS odpowiednio
obfitą treścia (muszą być jakieś konteksty)
Wskazówka/tcl: do pokazywania
drzewa pod Tcl-em możesz użyc widgetu Tree pakietu BWidget:
http://aspn.activestate.com/ASPN/docs/ActiveTcl/8.4/bwidget/Tree.html
Uwagi z dnia 5.04.2011 ........................
jak uruchomic program "ird" - mamy nastepujace opcje:
1. sciagnac binaria idl2tcl.tar.gz, wsrod ktorych znajduje sie "ird"
moze byc problem z zaleznosciami od bibliotek so...
(na maszynie atos jednak dziala!!!!!!)
2. kompilacja MICO ze zrodel, patrz strona mico.org
w katalogu bin bedzie "ird"
3. mozemy uzywac dzialajacego na atosie ird, ktorego IOR jest dostepny
przez url: http://atos.amu.edu.pl/~mhanckow/IOR/ird.IOR
jednak aby go nakarmic wlasnymi plikami IDL musimy dysponowac programem "idl"
z idl2tcl.tar.gz, ktory mozemy uruchomic z atosa...
jak uzywac idl2tcl (broker Combat):
1. mozna skorzystac ze strony www combat/idl2tcl
wpisujemy w okienku plik IDL, a strona zwraca wersje tcl (duzy string),
ktory mozemy umiescic w naszym programie Combatowym...
2. mozemy uzywac idl2.tar.gz, np. na atosie
skrypt idl2tcl.tcl wymaga aby:
(a) byly dostepne, tj daly sie uruchomic, programy: idl, ird, ...
(b) skrypt idl2tcl.tcl MUSI miec dostep do brokera Combat,
dlatego nalezy w nim dopisac na poczatku odp. linijke "lappend auto_path ..."
kolejnosc uruchamiania programow w zadaniu 27 (po stronie serwera):
1. ird --ior=ird.IOR &
nsd --ior=nsd.IOR &
# uruchamiamy repozytorium interfejsow (ird) oraz NameService (nsd)
# mozna tez uruchomic inne NameService, np. z javy
2. idl --feed-ir -ORBInitRef InterfaceRepository=file://$(pwd)/ird.IOR Hello3.idl
idl --feed-ir -ORBInitRef InterfaceRepository=file://$(pwd)/ird.IOR COS_ns.idl
# karmimy ird plikami idl... (COS_ns.idl dotyczy NameService)
3. uruchamiamy serwer Corby, skonfigurowany z "ird"
Zadanie 27
(klient Combat bez pliku IDL
(i programu idl2tcl !!!))
Skonfigurować serwer Combatowy (lub inny) tak aby klienci
Combata NIE musieli uzywac pliku IDL oraz idl2tcl;
jeśli serwer ma prawidłowo skonfigurowany IR (prawdziwy !!! nie
lokalny) to klienci Combata
automatycznie wyciagają informcję o interfejsie ob. Corby z serwera ...
mechanizm ten jest opisany w pliku combat.n w katalogu
combat-tcl-0.7.4;
będzie potrzeby serwer IR czyli program ird z brokera MICO (jest razem
z idl2tcl);
(trzeba ustawic odp zmienne srodowiska skryptem e_mico_ird)
w razie kłopotów z bibliotekami .so rozważyć ponowną kompilację brokera
MICO (www.mico.org);
Uwaga do zadania 27: omawiany tu mechanizm wykorzystuje metoda _get_interfejs zwracającą ref do ob.
InterfaceDef opisującego interfejs... nie wszystkie brokery
implementują te metodę,
np javaidl tego nie robi (otrzymamy wyjątek Corby NO_IMPLEMENT po
uruchomieniu _get_interface);
w takiej sytuacji należy skonfigurować IR bezpośrednio w kliencie!
Uwaga 2 do zadania 27:
co to znaczy skonfigurować IR? odp: tzn spowodować aby
resolve_initial_references "InterfaceRepository"
zwracało ref do IR... robi się to np przy pomocy opcji "-ORBInitRef
InterfaceRepository=ior_do_IR"
podawanej przy uruchamianiu kli/ser.
Broker Corby dla .NET - IIOP.NET
Środowisko .NET posiada brokera Corby o nazwie iiop.net (patrz link
???);
broker ten różni się od wcześniej poznanych: stanowi rozszerzenie ".NET
Remoting";
"konfiguracje" po stronie serwera które w innych brokerach robi się
przez POA tutaj robi się
poprzez klasy Remotingu ...;
obiekt Remotingu staje się obiektem Corby gdy zmienimy kanał na
"IiopChannel";
Przykład serwera ob. Corba pod iiop.net
(iiopdotnet_przyklad.zip):
/*
plik IDL:
module qqq1 {
interface Hello
{
double dajLiczbe();
};
};
kompilacja pod mono:
mono IDLToCLSCompiler.exe xxx1 Hello3.idl
# program IDLToCLSCompiler.exe zamienia plik IDL na interfejs .NET
# interfejs "Hello" będzie w złożeniu "xxx1.dll"
mcs -r:xxx1.dll -r:IIOPChannel.dll HelloServer.cs
# tworzy serwer ob. Corby HelloServer.exe
# IIOPChannel.dll zawiera impl. kanalu "IiopChannel"
uruchamianie serwera:
mono HelloServer.exe > qqq.IOR &
# serwer wypisuje IOR na stdout
*/
using ...; // pomijam dla krótkości
// to jest klasa servant-a
public class HelloImpl : MarshalByRefObject, Hello {
private double liczba=123.123;
public double dajLiczbe() {
return liczba++;
}
}
public class HelloServer {
[STAThread]
public static void Main(string[] args) {
IiopChannel chan = new IiopChannel(10000);
// serwer bedzie oczekiwał na porcie 10000
ChannelServices.RegisterChannel(chan);
// rejestruje kanal "IiopChannel"
Hello hello = new HelloImpl();
// tworze serwanta
omg.org.CORBA.OrbServices orb= omg.org.CORBA.OrbServices.GetSingleton();
String ior= orb.object_to_string(hello);
// tu sie podaje servanta a nie ref jak w innych brokerach!!!
Console.WriteLine(ior);
Thread.Sleep(Timeout.Infinite);
}
}
Przykład klienta Combatowego dla
serwera iiop.net:
package re combat
set m [corba::string_to_object file://[pwd]/qqq.IOR]
$m _is_a IDL:qqq1/Hello:1.0
# podajemy wlasciwy RepoID (ten w IOR jest niewlasciwy - blad iiop.net??)
source Hello_dotnet.tcl
combat::ir add $_ir_Hello_dotnet
$m dajLiczbe
.................................................
Zadanie 28
(Wydajnosc brokerów: JavaIDL,
IIOP.NET, Combat)
Zaprogramuj obiekty Corba z operacją
ciagRazy2(we,wy)
monożącą podany ciąg liczb double (dowolnej długości - typ sequence w
IDL !!) przez 2;
zaprogramuj taki obiekt w 3 brokerach: JavaIDL, IIOP.NET, Combat;
nastepnie zaprogramuj klienta Corby który będzie mnożył dany ciąg przy
pomocy tych 3 obiektów;
zmierz czas wykonywania operacji ... który broker jest najbardziej
wydajny???
(klienta i pomiary czasu najwygodniej (chyba?) zrobic przy pomocy
brokera Combat);
pomiar czasu należy wykonać dla ciągów rosnącej długości;
wynik przedstawić w postaci tabelki:
dlugosc |
JavaIDL
|
IIOP.NET
|
Combat
|
100
|
?
|
?
|
?
|
200
|
?
|
?
|
?
|
400
|
?
|
?
|
?
|
...
|
|
|
|
Zadanie 28a
(IIOP.NET - problem po stronie
klienta???)
Broker iiop.net dobrze się sprawuje jako serwer, natomiast pewne
problemy pojawiają się
gdy działa jako klient:
nie chce współpracować z serwerem JavaIDL i
wytworzonym przez niego
plikiem ior... (przetestowane z iiop.net 1.9.0 pod mono 1.1.13)
podobny problem pojawia się w przypadku serwera
Combatowego
W ramach tego zadania należy usunąć ten problem, być może kontaktując
się z twórcami
brokera iiop.net http://iiop-net.sourceforge.net/
Należy także odtworzyć eksperymenty ujawniające ten problem!
.................................................
Zadanie 29
(Eksperyment z polityką:
Lifespan/PERSISTENT, Id Assignment/USER_ID)
Zaprojektuj eksperyment pokazujący znaczenie ustawienia
Lifespan=PERSISTENT.
Polityka Lifespan moze przyjmować wartości TRANSIENT(default) i
PERSISTENT;
pojęcie PERSISTENT (pol. trwały) dotyczy nie samego obiektu Corby tylko
referencji do tego obiektu;
obiekty PERSISTENT mogą mieć czas
życia dłuższy niż czas życia serwera,
tj mogę wyłączyć serwer potem ponownie go włączyć a ref u klientów będa
nadal działać.
W ramach zadania prosze ten
efekt zademonstrować ...
Broker: dowolny (najłatwiej pod Combat-em)
Uwaga 1: Id
Assignment/USER_ID pozwala recznie przydzielac oid-y obiektom Corby w
POA
(oid to identyfikator obiektu w ramach jego POA, uzywany m.in w tablicy
AOM).
Uwaga 2: parametry obiektu
zawarte w IOR nie mogą sie zmienic po przeładowaniu serwera
(w razie problemów prosze zaglądać do IORa!)
Materiały: opis polityk POA
znajdziemy w specyfikacji CORBA 2.3, rozdz 11,
punkt 11.3.7.2 - Lifespan Policy, 11.3.7.4 Id Assignment Policy
RMI-over-IIOP
... czyli jak zrobic ob. Corba z ob.
RMI (nie modyfikując kodu ob. RMI)
... rmi-over-iiop jest używane przez EJB
Zadanie 30
(podstawowy eksperyment
RMI-over-IIOP)
Zaprogramować ob. RMI z następującym interfejsem:
public interface CCC1_interf extends Remote { int[] razy2(int[] x) throws RemoteException; }
następnie zamienić go na obiekt RMI-over-IIOP,
oraz sprawdzić czy jest dostępny z poziomu klienta JavaIDL oraz Combat.
Materiały:
http://java.sun.com/j2se/1.4.2/docs/guide/rmi-iiop/index.html
http://java.sun.com/j2se/1.4.2/docs/guide/rmi-iiop/tutorial.html
Wskazówki:
Główne różnice między zwykłym ob. RMI a ob. RMI-over-IIOP:
1. pieńki tworzy się komendą rmic z odp. opcjami: rmic -iiop -idl -noValueMethods CCC1
2. eksportuje się obiekt przy pomocy javax.rmi.PortableRemoteObject.exportObject()
(a nie java.rmi.UnicastRemoteObject.exportObject()
!!!)
Obiekt RMI-over-IIOP jako "name servera" nie może używac
rmiregistry, lecz usługi COSNaming Corby;
aby się wpisać do COSNaming należy użyć JNDI - jest to dodatkowa
warstwa abstrakcji nad rozmaitymi
usługami nazewniczymi w Javie; poniżej przykład użycia JNDI spod
tclBlend:
# konfiguracja JNDI:
set p1 [java::new java.util.Properties]
$p1 put java.naming.factory.initial "com.sun.jndi.cosnaming.CNCtxFactory"
set f [open "ns.ior" r]; set ior [string trim [read $f]]; close $f
$p1 put java.naming.provider.url $ior
# plik ns.ior to ior serwera COSNaming, np tnameserv z javaidl lub nsd z mico ...
#$p1 put java.naming.provider.url "iiop://localhost:9000"
# można tez podać taki url o ile znamy nr portu pod którym działa serwer!
set ctx1 [java::new javax.naming.InitialContext $p1]
$ctx1 rebind "qqq1" $rmi1
# wpisujemy obiekt $rmi1 do name serwisu pod nazwą "qqq1"
set x [java::cast CCC1_interf [$ctx1 lookup "qqq1"]]
# wyciągamy ref do obiektu o nazwie "qqq1" + konwersja na typ interfejsowy
[$x razy2 [java::new {int[]} {} {1 2 3 4 5}]] getrange
#% 2 4 6 8 10
# wywołujemy metode razy2 na rzecz ob. RMI-over-IIOP
# Uwaga: używanie JNDI nie jest konieczne w przypadku RMI-over-IIOP!!!
# można posługiwać sie tradycyjnymi ior-ami:
set q1 [java::call javax.rmi.PortableRemoteObject toStub $rmi1]
set q2 [java::cast _CCC1_interf_Stub $q1]
set args [java::new {String[]} {} {}]
set orb [java::call org.omg.CORBA.ORB init $args [java::null]]
#$q2 connect $orb; # tego wymaga JacORB (w JavaIDL niekonieczne...)
$orb object_to_string $q2
# wyswietla w konsoli ior...
Typ "any" i TypeCode
Typ any w Corbie
pozwala przekazywać/zwracać dowolne struktury danych ...
Dana typu any to para: (TypeCode, wartość),
gdzie TypeCode opisuje dowolny typ danych, którego egzemplarzem
jest
wartość ...
// plik IDL
module HelloApp2
{
interface Hello
{
any zwrocCokolwiek(in long tryb);
};
};
# implementacja na serwerze Combat-owym (tylko fragment!):
public method zwrocCokolwiek {tryb} {
return {{struct {} {a long b long}} {a 123 b 321}}
# zwraca liste: {TypeCode wartość}
# interpetacje TypeCode pod Combatem znajdziesz w pliku combat.n
# Uwaga: type any został znacząco uproszczony w brokerze Combat;
# w innych brokerach typ ten jest znacznie trudnieszy w użyciu!!
}
# sposób użycia przez klienta Combat-owego:
$m zwrocCokolwiek 1
#% {struct {} {a long b long}} {a 123 b 321}
Zadanie 31
(any i TypeCode w JavaIDL)
W tym zadaniu sprawdzamy jak typ "any" jest obsługiwany przez
brokera JavaIDL oraz Combat.
Najpierw należy przygotować serwer Combatowy i klienta JavaIDL, przy
czym
metoda zwrocCokolwiek() powinna zwracać:
tryb zwracana wartość
1 float
2 sekwencja float
3 sekwencja struktur z 3
polami typu long o nazwach: a,b,c
4 sekwencja struktur z 3
polami: a,b typu long i c typu "sekwencja float-ów"
Klient powinien wypisywać otrzymane dane na terminalu (np sekwencje
float jako ciąg liczb).
Następnie należy odwrócić role i zbudować serwer JavaIDL oraz klienta
Combatowego.
Wskazówki ---:
Aby czytać lub tworzyć dane typu "any" w JavaIDL należy utworzyć
"dynamiczne any" (DynAny);
robi się to przy pomocy pseudoobiektu "DynAnyFactory" oraz metod:
create_dyn_any
org.omg.CORBA.Any
# oglądanie istniejącego "any"
create_dyn_any_from_type_code
org.omg.CORBA.TypeCode
# tworzenie nowego dynany na
podstawie TC;
# potem trzeba wywołać to_any()
aby zamienić dynany na any...
Jeśli dynany może być zinterpretowany jako ciąg elementów, to można po
nich przebiegać przy pomocy metod:
rewind(),
seek(ind), next(), ...
można odczytać bieżący element przy pomocy get_*(), gdzie * to typ np "float";
można zmodyfikować bieżący element przy pomocy insert_*(wartość).
Aby wykonać niektóre operacje specyficzne dla pewnych struktur trzeba
dokonać
konwersji DynAny na Dyn*, gdzie *=Struct, Array, Sequence, ...
Dokumentacja i przyklady ---:
Opis klasy DynAny docs/api/org/omg/CORBA/DynAny.html
Przykład tworzenia danych "any" spod tclBlend: java_any.tcl.txt
DynAny jest opisany w 9 rozdz. specyfikacji Corba!
Przekazywanie obiektów
przez wartość: valuetype
Słowo "interface" w pliku IDL oznacza że chodzi o referencję do
(zdalnego) obiektu Corby ...
Nie zawsze jest to odpowiednie rozwiązanie, dlatego wprowadzono
możliwość przekazywania
obiektów przez wartość - służy do tego słowo "valuetype".
Valuetype to połączenie struktury(dane) i interfejsu(operacje) czyli
... obiekt.
Wartość valuetype, gdy jest przekazywana przez par lub zwracana,
zachowuje się tak:
1. jest serializowana i transportowana na miejsce przeznaczenia ...
2. tam tworzy się nowy obiekt odpowiedniej klasy, inicjalizuje się go
danymi które przybyły ...
3. implementacja tej "odpowiedniej" klasy MUSI być dostępna na miejscu
przeznaczenia obiektu
Szerzej o valuetype można przeczytać w New
Features for CORBA 3.0, rozdz 4.
// plik IDL:
module xxx1
{
interface Pojemnik {
attribute wstring wartosc;
};
valuetype Pojemnik2 {
public wstring wartosc;
private wstring wartosc2;
void nic(); // bez "public"!
};
interface FabrykaPojemnikow {
Pojemnik utworz();
Pojemnik2 utworz2(); // test przekazywania VT ser->kli
string odbierz(in Pojemnik2 par); // test przekazywania VT kli->ser
};
};
# sposób użycia spod Combata:
# serwer (fragmenty) -------------------------------------------
# IDL: Pojemnik utworz();
public method utworz {} {
global poa
set obj [namespace current]::[PojemnikImpl #auto]
set ref [$poa servant_to_reference $obj]
return $ref
}
# IDL: Pojemnik2 utworz2();
public method utworz2 {} {
return {
wartosc "a ku ku !!!"
wartosc2 "a ku ku2 !!!"
}; # trzeba podac wartosci wszystkich pol valuetype!
}
# IDL: string odbierz(in Pojemnik2 par);
public method odbierz par {
return "odbierz: par= $par"
}
# klient -----------------------------------------------------
source valuetype.tcl
combat::ir add $_ir_valuetype
set f [open FabrykaPojemnikow.IOR "r"]; set ior [read $f]; close $f
set m [corba::string_to_object $ior]
set x [$m utworz]
$x wartosc "123 321"
$x wartosc
# $x to ref do (zdalnego) obiektu Corby
# testujemy odbieranie vt ...
set x2 [$m utworz2]
#% wartosc {a ku ku !!!}
wartosc2 {a ku ku2 !!!}
_tc_ {valuetype IDL:xxx1/Pojemnik2:1.0 {public wartosc wstring private wartosc2 wstring} 0 {}}
# testujemy wysylanie vt ...
$m odbierz {
wartosc "11111111 111111111"
wartosc2 "222222222"
}
Zadanie 32
(obiekt przez wartość,
valuetype, współpraca różnych brokerów)
Zaprogramować serwer dla powyższego pliku IDL pod JavaIDL;
przetestować współpracę klienta Combatowego z serwerm JavaIDL!!!
(zarówno wysyłanie jak i odbieranie valuetype)
Wskazówki: po skompilowaniu
powyższego pliku idl pod JavaIDL jest tworzony plik "Pojemnik2.java"
plik ten zawiera klase abstrakcyjna(!) Pojemnik2;
należy zaprogramować podklasę Pojemnik2 o nazwie Pojemnik2Impl, która
już nie jest abstrakcyjna;
klasa ta jest używana w Pojemnik2DefaultFactory.java;
nazwa Pojemnik2Impl jest standardowa;
gdy przychodzi wartość valuetype tworzony jest obiekt klasy
Pojemnik2Impl
i jest on inicjalizowany danymi z valuetype ...
Dostęp programowy do
InterfaceRepository (IR)
IR może zawierać opis interfejsów obiektów Corby oraz inne
informacje ...
Jest możliwy programowy dostęp do IR w celu zapoznania się z
interfejsem danego obiektu
np w celu wywoływania metod przez DII.
Każdy obiekt Corby posiada metode _get_interface która zwraca ref do
obiektu z zinterfejsem InterfaceDef
który znajduje sie w IR ...
Opis IR znajdziemy w specyfikacji Corby, rozdz 10, (opis ten jest
jednak dość trudny ... jednak trzeba tam zaglądać)
Skrócony opis IR:
metoda _get_interface zwraca ref do InterfaceDef;
interfejs ten zawiera 2 istotne metody odziedziczone po interf
"Contained" i "Container"
Contained zawiera metody/atrybuty: describe, name, id (=RepoId)
Container zawiera metody/atrybuty: contents (zwraca liste obiektów)
- describe
zwraca ref do ob. z interf Description zawierajacym 2 atrybuty kind i
value; value jest typu any i można z niego wyczytać wiele ogolnych
informacji o interfejsie ...
- contents dk_Operation 1
z takimi parametrami zwraca listę ob. z interfejsem OperationDef, które
też zawiera metodę describe();
describe() zwraca strukturę zawierająca m.in. pole parameters - jest to
lista obiektów które mają metody name i type, z których można odczytać
nazwę i typ parametru metody ...
Uwaga 1: operacje IR bardzo często zwracają złożone struktury danych,
zawierające wiele ref do obiektów Corby na serwerze IR
Uwaga 2: aby to wszystko
działalo po stronie serwera musi być włączony "ird", trzeba go
"nakarmić" odpowiednimi plikami IDL, musi też być odpowiednio połączony
z serwerem naszego obiektu Corby, czyli:
# bash:
ird --ior=ird.IOR
idl --feed-ir -ORBInitRef
InterfaceRepository=file://E:/Corba/tcl/idl2tcl/ird.ior Hello3.idl
# kod serwera:
corba::init -ORBInitRef
InterfaceRepository=file://E:/Corba/tcl/idl2tcl/ird.ior
Uwaga 3: serwer ird z brokera MICO zdaje się nie implementować w 100%
interf opisanych w corba_ir.idl (poniżej) ...
ale na szczeście te metody które są dostępne w zupełności wystarczą do
naszych celów ...
.................................
Przykład klienta Combatowego używającego IR (plik idl/tcl dla IR: corba_ir.idl, corba_ir.tcl):
package require combat
set f [open "Hello.IOR" "r"]; set ior [read $f]; close $f
set m [corba::string_to_object $ior]
$m podajLiczbe
source corba_ir.tcl
combat::ir add $_ir_corba_ir; # MUSIMY załadować opis IR do lokalnego IR !
set ir [$m _get_interface]
$ir _is_a IDL:omg.org/CORBA/InterfaceDef:1.0; # to jest NIEZBEDNE !
$ir describe
#% kind dk_Interface
value {
{struct IDL:omg.org/CORBA/InterfaceDescription:1.0
{name string id string defined_in string version string base_interfaces {sequence string}}
}
{name Hello
id IDL:HelloApp2/Hello:1.0
defined_in IDL:HelloApp2:1.0
version 1.0
base_interfaces {}
}
}
# jak widac pole value zawiera wartosc typu any (TypeCode, wartosć)
# jeśli interesuje nas tylko value/wartosc to mozna to odczytac przez:
lindex [$ir describe] 3 1
name Hello
id IDL:HelloApp2/Hello:1.0
defined_in IDL:HelloApp2:1.0
version 1.0
base_interfaces {}
Zadanie 33
(InterfaceRepository -
przeglądarka)
Zaprogramowac program lub procedurę, która pokazuje krótki opis
metod i ich parametrów dla podanej ref do ob. Corby.
Wydruk powinien wyglądać tak (Combat):
set m [corba::string_to_object $ior]
interf_info $m
# wydruk:
sayHello
result: string
sayHello2
we: string (IN)
result: string
podajLiczbe
result: long
sayHello_nowyObiekt
result: Object IDL:HelloApp2/Hello:1.0
wektorRazy2
tab1: array long 10 (IN)
tab2: array long 10 (OUT)
result: void
uruchomZwrotnaMet
ref: Object IDL:HelloApp2/WywZwrotne:1.0 (IN)
result: void
pomnozRazy2
x: sequence long (IN)
result: sequence long
zwrocCokolwiek
arg: any (IN)
result: any
Uwaga: jesli powyższe
zadanie wykonujemy w języku Tcl to przydatna będzie konstrukcja
ułatwiająca wyciąganie danych ze słowniko-podobnej listy elementow:
set lista {a 111 b 222 c 333}
# chcemy wyciagnac wartość elementu o kluczu b (czyli 222)
# niezaleznie od tego gdzie sie ten element w liscie znajduje ...
array set q1 $lista
# tworzy tablice asocjacyjna na podstawie listy!
puts $q1(a)
# wypisuje na terminalu 222
## w przypadku zagniezdzonych slownikow, np set lista {a {a1 111 a2 222} b 333}
## trzeba uzyc polecenia dict (w tcl8.4 trzeba uzyc pakietu "dict" dict.zip (
## to jest wersja dla lin, dla win nie mam pod ręką...))
## dict get $lista a a1
## zwraca 111
## docs polecenia dict:ActiveTcl/8.4/dict/dict.html
Zadanie 33a (*)
(broker Combat: idl2tcl bez
MICO)
Jak wiemy idl2tcl.tcl zamienia plik idl na równoważny string tcl-owy,
który można załadować
do lokalnego ir (Interface Repository) brokera Combat;
skrypt ten używa serwera ird z brokera mico w charakterze
parsera idl...
W ramach tego zadania należy napisać "lekki" program (<50KB)
spełniający to samo zadanie jednak bez zależności od zewnętrznego
brokera ...
COS = Corba Object Services
PSS = Persistent State Service
Jest to serwis zapewniajacy "persystencje" czyli trwałość obiektów Corby
(odporność na zniszczenie procesu serwera).
W zasadzie serwis ten nie ma wiele wspólnego z Corba,
a polega na zapewnieniu trwałości serwantów ...
Przykład jak zapewnić trwałość serwantów pod brokerem Combat języka Tcl:
Założenia tego przykładu:
1. dysponujemy lokalną bazą danych metakit/wiki, metakit, która wspiera transakcje (płaskie!) oraz posiada kursory;
interpretery Tcl-a typu "tclkit" maja wbudowaną standardowo tę
bazę...
2. stan serwantów jest przechowywany w tej bazie (1 serwantowi
odpowiada 1 wiersz odpowiedniej tabeli);
w serwancie jest przechowywany kursor wskazujący na odp. wiersz tabeli,
co przyspiesza dostęp do danych
3. metody serwanta (ob. Corby) są transakcjami bazodanowymi (jeśli
istnieją związki między serwantami
to przydatne stają się transakcje zagnieżdżone, jednak baza metakit ich
nie posiada...)
4. poa ma polityki USER_ID oraz PERSISTENT, dzięki czemu przy ponownym
uruchomieniu
serwera referencje u klientów ciągle działają (i sa takie same jak
poprzednio!)
5. serwer używa zawsze tego samego nr portu (opcja -ORBServerPort)
Kod klienta i serwera: combat_pss.txt , (potrzebne pliki: COS_ns.idl, COS_ns.tcl).
Zadanie 34 (PSS w JavaIDL)
Prosze "zaimplementować" PSS w JavaIDL używając nadającej się do
tego bazy danych,
w podobny sposób jak w przykładzie Combatowym.
Dodatkowo proszę przygotować przykład demonstrujący trwałość obiektów.
Property Service
Ten serwis pozwala dynamicznie definiować zbiory właściwości
(w przeciwieństwie do atrybutów
ob. Corby, które są statyczne!).
Właściwość definiuje się metodą define_property
interfejsu PropertySet
podając nazwę i wartość (typ any)
...
Precyzyjny opis serwisu COSProperty znajdziemy oczywiście w
specyfikacjach OMG...
Przykładowy klient pod brokerem Combat:
combat_property.txt (potrzebne pliki:
COS_Prop.tcl).
Zadanie 35 (COSProperty w JavaIDL)
Proszę przygotować przykład pokazujący działanie serwisu
Property pod brokerem JavaIDL.
W szczególności proszę pokazać jak dwaj klienci mogą współdzielić jeden
ob. PropertySet
i wymieniać się informacjami za jego pośrednictwem.
Uwaga 1: to zadanie wymaga
umiejętności posługiwania się typem "any" pod JavaIDL!
Uwaga 2: trzeba skompletować
pliki idl opisujace COSProperty w celu utworzenia pieńka!!!
(zbiorczy plik idl z interfejsami większości serwisów: COSidl.idl)
Uwaga 3: w ramach tego zadania
proszę także zademonstrować, jak dwaj klienci używający
różnych brokerów (JavaIDL i Combat) mogą wymieniać dane poprzez
COSProperty.
Event Service
COSEvent jest opisany w specyfikacji oraz w artykule pod tytułem
"Using Value Types to Improve Access to CORBA Objects" ...
Pojęcia:
Supplier
- dostawca komunikatów
Consumer - odbiorca komunikatów
model push i pull - push
("popychać", aktywny dostawca), pull ("ciągnąć", aktywny odbiorca)
event channel - kanał
zdarzeniowy, do którego podłączają się dostawcy i odbiorcy,
proxy - ob. pośredniczący
między klientem a kanałem;
np: "proxy push supplier" pośredniczy między "push consumer" a
"event channel"
Przykładowy klient pod brokerem Combat:
combat_event.txt (potrzebne pliki: COS_Event.tcl).
Zadanie 36 (COSEvents w JavaIDL)
Proszę przygotować przykład pokazujący działanie serwisu Events
pod brokerem JavaIDL.
Przykład powinien być utrzymany w podobnym duchu co przykład
Combatowy...
Uwaga: trzeba skompletować
pliki idl opisujace COSEvents w celu utworzenia pieńka!!!
(zbiorczy plik idl z interfejsami większości serwisów: COSidl.idl)
Transaction Service
OTS = Object Transaction Service.
Implementacja tzw "rozproszonych transakcji" ...
Jest tu używany protokół o nazwie 2PC =
"2 phase commit".
Opis: odpowiednia specyfikacja OMG;
ciekawy artykuł: "Distributed transactions and two-phase commit", A.
Wilson
Implementacja OTS jest dostępna w brokerze openorb (openorb.sourceforge.net).
Co trzeba zainstalować: OpenORB, tools, NamingService,
TransactionService, to jest ok 60MB!
Transakcje rozproszone są potrzebne, gdy np używamy równocześnie 2 baz
danych B1 i B2,
i chcemy aby modyfikacje danych w B1 i B2 dokonały się "atomowo" (tj
albo w obu bazach albo w żadnej),
niezależnie od możliwości awarii w dowolnym miejscu i czasie...
Uproszczony opis transakcji
rozproszonej modyfikującej dane w bazach B1 i B2:
- Uczestnicy: klient, zasób1, zasób2.
- Klient tworzy ob. kontrolny transakcji, wykonuje operacje na
bazach
oraz kończy transakcje (commit lub rollback z interfejsu terminatora).
- Zasób1 i zasób2 są to ob. Corby reprezentujące bazy B1 i B2;
obiekty te posiadają metody prepare,
commit i rollback;
w metodzie prepare zasoby głosują jaką operację mogą wykonać (commit
czy rollback);
metody commit i rollback kończą indywidualne transakcje bazodanowe (tak
jak wskazuje nazwa metody);
aby zarejestrować się w OTS zasoby muszą uzyskać dostęp do ob.
kontrolnego transakcji
i użyć metody register_resource z interfejsu koordynatora.
- Gdy klient zakończy transakcje przez commit to:
- wywołuje się prepare dla wszystkich zasobów
- jeśli wszystkie zasoby głosują na commit to wywołuję się metodę
commit dla wszystkich zasobów
- jeśli choć jeden zasób głosuje na rollback lub "został
wykillowany" to wywołuje się metodę rollback
dla wszystkich "żywych" zasobów.
- Jeśli klient zakończył transakcję przez commit lecz ta operacja
się nie powiodła, zostaje zgłoszony wyjątek;
aby rozpocząć nową transakcję trzeba utworzyć nowy ob. kontrolny
transakcji (?).
Przykład pokazujący użycie OTS spod brokera Tcl/Combat: combat_trans.txt (potrzebny plik COS_trans.tcl).
Zadanie 37 (COSTransactions w JavaIDL)
Proszę przygotować przykład pokazujący działanie serwisu
Transactions
pod brokerem JavaIDL.
Przykład powinien być utrzymany w podobnym duchu co przykład
Combatowy...