PZR420 - ćw - temat C

Obiekty rozproszone CORBA.
CORBA = Common ORB Architecture

literatura i inne materiały ...

  1. http://www.omg.org - główna strona organizacji OMG która zajmuje się tworzeniem specyfikacji CORBA
  2. "Overview of CORBA" - rozdział z pewnej książki
  3. "Distributed Object Computing with CORBA" - ogólne wprowadzenie
  4. "CORBA: Integrating Diverse Applications Within Distributed Heterogeneous Environments"- ogólne wprowadzenie
  5. "Introduction to OMG IDL" - opis języka IDL pozwalającego definiować interfejsy obiektów CORBA
  6. "Chapter 11. The Portable Object Adapter" - rozdz. 11 specyfikacji CORBA
  7. "An Overview of the CORBA Portable Object Adapter" - opis POA czyli środowiska w którym "siedzą" obiekty CORBA
  8. "The POA interface" - inny opis POA (rozdział książki "GNOME & CORBA")
  9. "New Features for CORBA 3.0"- nowe cechy CORBA wprowadzone w wersji 3.0 specyfikacji
  10. http://www.fpx.de/Combat - broker języka skryptowego Tcl (tu znajdziesz oprogramowanie i dokumentacje Combat-a)
  11. http://java.sun.com/j2se/1.4.2/docs/guide/corba/index.html - Java IDL, czyli broker wbudowany w język Java
  12. Orfali, Harkey "Client/Server Programming with Java & CORBA" - książka
  13. McHale "CORBA EXPLAINED SIMPLY" książka (chyba dobra...)

krótkie przykłady użycia obiektów CORBA ...

wyjaśnienie "skrotów" ...

Podstawowe pojęcia CORBA.

  1. 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 ...
  2. (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:

  3. (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);
    };
    };
  4. (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)
  5. (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:

  6. (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:

  7. (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 ...
  8. 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.
  9. (POA, servant, oid);
    1. implementację obiektu CORBA nazywamy servant-em (może to być obiekt danego języka programowania lub "coś" innego ...)
    2. POA (=Portable Object Adapter) jest pośrednikiem między ORB a servantem
    3. "Portable" - można przenosić kod serwera między brokerami różych producentów
    4. POA jest (pseudo)obiektem CORBA; obiekty POA tworzą drzewo (dla nowo tworzonego obiektu można ustalić tzw politykę); obiekty POA maja identyfikatory "poa id"
    5. 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)
    6. zadania POA - podsumowanie (patrz też tutaj):
    7. 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]
  10. czym się CORBA różni od RMI ?
  11. 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).
  12. 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" ?

  1. POA zawiera tablicę Active Object Map, która kojarzy oid z serwantem
  2. aktywowanie serwanta to własnie ustalenie związku oid-u i serwanta
  3. 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ą !
  4. 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
  5. szczegółowy opis POA jest w specyfikacji CORBA (specyfikacja CORBA v2.3): rozdz 11

Inne pojęcia POA:

  1. słowniczek pojęć POA ze specyfikacji CORBA (rozdz. 11) (wstaw link)
  2. (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
  3. (polityka POA); definiuje sposób zachowania się POA; przykłady polityk:
  4. (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ę
  5. (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)
  6. (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. 1 servant obsługuje wiele obiektów CORBA; servant odczytuje oid bieżącego obiektu i w ten sposób je rozróżnia;
  2. można tworzyć servanta i obiekt CORBA automatycznie przy pierwszym odwołaniu do tego obietku; do tego celu służy ServantManager ...
  3. ???

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:
  1. 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)
  2. 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 ?)
  3. 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)
  1. 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.
  2. 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)
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:
  1. Uczestnicy: klient, zasób1, zasób2.
  2. Klient tworzy ob. kontrolny transakcji, wykonuje operacje na bazach
    oraz kończy transakcje (commit lub rollback z interfejsu terminatora).
  3. 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.
  4. Gdy klient zakończy transakcje przez commit to:
  5. 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...