CORBA a IIOP

Ing. Petr Lampa, lampa@dcse.fee.vutbr.cz
Ústav informatiky a výpočetní techniky,
Fakulta elektrotechniky a informatiky, VUT v Brně, Božetěchova 2, 612 66 Brno

1. Úvod

Prostředí CORBA (Common Object Request Broker Architecture) tvoří ucelenou architekturu pro podporu tvorby distribuovaných objektově orientovaných aplikací. Standard CORBA je postupně vyvíjen od počátku 90. let společnostmi soustředěnými ve sdružení OMG (Object Management Group). Mezi hlavní nositele vývoje patří přední počítačové firmy, jako jsou IBM, Sun, HP, ale také softwarové firmy (IONA, ExperSoft), věnující se převážně vývoji prostředí CORBA. Významným mezníkem ve vývoji byla dohoda na standardu CORBA verze 2.0 v roce 1995. Tento standard přinesl společně s dalšími novinkami definici protokolu komunikace mezi implementacemi různých výrobců. Takovýto protokol předtím scházel a byla to jedna z překážek bránící šíření architektury CORBA. Další impuls k rozšíření architektury CORBA pak přichází ze strany jazyka Java. Objevuje se řada volně dostupných implementací architektury CORBA pro prostředí Java a prostředí CORBA/IIOP bude dokonce součástí nové verze prohlížeče Netscape Communicator.

2. Prostředí CORBA

Základní funkcí architektury CORBA je podpora jazykově neutrálního transparentního použití distribuovaných objektů. Klient může používat dostupné objekty bez ohledu na to, v jakém jazyce jsou implementovány, kde a na jakém počítači běží a jakým komunikačním protokolem jsou dostupné. Objektem se přitom rozumí identifikovatelná, zapouzdřená entita, která poskytuje nějaké služby. Klient přistupuje k těmto službám zasíláním požadavků. Forma generování požadavků závisí na jazyce, ve kterém je klient napsán. V objektově orientovaném jazyce to může být volání metod zástupného objektu, zatímco v klasických programovacích jazycích volání vygenerovaných funkcí (stubs).

Plná implementace prostředí CORBA se skládá z prostředí klientského, z prostředí na straně serveru a objektově orientovaných služeb. Hlavní komponenty architektury jsou znázorněny na obrázku. Jednotlivé komponenty mají tyto funkce:

2.1 Tvorba aplikací v prostředí CORBA

Pro ilustraci funkce jednotlivých komponent architektury CORBA použijeme příklad distribuovaného systému pro sledování externích odkazů na WWW stránky. Systém se bude skládat ze serveru, který bude zaznamenávat odkazy dle cílových stránek, a klientů, kteří budou zasílat serveru URL stránek, na které se chtějí odkázat. Server bude realizován jako objekt s metodami pro zaregistrování odkazu na WWW stránku reference(), zrušení odkazu release() a získání seznamu odkazů get_references(). Jednotlivé kroky při tvorbě aplikace jsou:
  1. Zápis rozhraní objektu v jazyce IDL
  2. Vygenerování spojek a kostry kompilátorem jazyka IDL
  3. Návrh klienta v implementačním jazyce
  4. Implementace objektu a hlavního programu serveru

2.2 Jazyk IDL

Jazyk IDL je deklarační jazyk určený pro definici rozhraní objektů. Vychází z jazyka C++ a proto je také vazba na jazyk C++ nejpřirozenější. Základními typy jsou short, long (není zde typ int), float, double, char, boolean, octet a any. Typ char je definován jako typ reprezentující znaky textu, jejichž binární hodnoty mohou být při přenosu mezi různými ORB transformovány, ale při zachování významu znaku. Proto je doplněn typ octet, který reprezentuje binární 8 bitové hodnoty. Typ any může reprezentovat kterýkoli typ.

Odvozené typy enum, struct, union, exception a typedef jsou definovány podobně jako v jazyce C, pouze typ union má doplněnu deklaraci rozlišující složky. Navíc jsou zavedeny typy array a sequence, které reprezentují pole o pevné velikosti a dynamické pole. Specializovaný typ string je definován jako sequence<char>. Nejdůležitější součástí jazyka je ovšem deklarace rozhraní (interface), která má formálně stejný tvar jako deklarace třídy v jazyce C++. Rozhraní objektu naší ukázkové aplikace může být definováno v jazyce IDL takto:

module WWW {				// deklarace modulu
   typedef string URL;			// adresa stránky
   typedef sequence<URL> URL_list;	// seznam odkazů na stránku
   exception not_found {};		// deklarace výjimky

   interface Server {			// definice rozhraní objektu
	boolean reference(in URL url, in string host) raises(not_found);
	boolean release(in URL url, in string host) raises(not_found);
	URL_list get_references(in URL url) raises(not_found);
   };
};
Metody definované v rozhraní (interface) reprezentují služby, které objekt poskytuje. Parametry metod musí mít definovány atribut způsobu předávání parametru:
in parametr je předáván od klienta do implementace objektu
out parametr je předáván z implementace objektu klientovi
inout parametr je předáván v obou směrech
Výsledek metody je předáván jako parametr out. Při volání metody může nastat celá řada chybových stavů, které jsou standardně signalizovány výjimkami (exception). Standardní výjimky, které může generovat ORB, jsou definovány ve standardu CORBA. V definici rozhraní pak mohou být navíc definovány uživatelské výjimky, které generuje implementace objektu (v uvedeném příkladu not_found).

Doposud naznačené vlastnosti jazyka IDL nepřináší vcelku nic zásadně nového oproti jiným architekturám volání vzdálených podprogramů (RPC, DCE). Výrazným rozdílem je však princip dědičnosti při definici rozhraní. Podobně jako v jazyce C++ lze definovat nové rozhraní odvozením z existujícího a to i s využitím vícenásobné dědičnosti. Strom dědičnosti definovaný v rozhraní objektu je navíc nezávislý na stromu dědičnosti implementace objektu, takže rozhraní objektu s vícenásobnou dědičností může být implementováno bázovou třídou a naopak.

2.3 Mapování do jazyka C++

Definice rozhraní v jazyce IDL pouze definuje služby objektu. Vlastní realizace objektu nebo klienta probíhá v implementačním jazyce. Vztah mezi definicí rozhraní objektu v jazyce IDL a odpovídající realizací v implementačním jazyce je definován mapováním. Mapování specifikuje, jakými typy implementačního jazyka jsou reprezentovány typy jazyka IDL a konvence, které musí být dodrženy při manipulaci s nimi. Standard CORBA 2.0 definuje mapování pro jazyky C, C++ a SmallTalk. V současné době jsou dále připravovány mapování pro jazyk Java a COBOL. Správné mapování definice rozhraní objektu zajistí kompilátor jazyka IDL, který vygeneruje jednak zástupnou třídu (nebo spojky, stubs) pro použití v klientském kódu, jednak kostru objektu pro použití při implementaci objektu. Další kód ovšem musí navrhnout programátor sám a musí přitom dbát na dodržení konvencí daných mapováním.

Definice rozhraní objektu vystupuje v jazyce C++ jako třída. Metody definované v rozhraní jsou pak virtuálními metodami této třídy. Práce s jednoduchými datovými typy je celkem bezproblémová. Jsou mapovány přímo na datové typy jazyka C++ definované jako typedef v modulu CORBA. Například typ boolean jazyka IDL je reprezentován typem CORBA::Boolean. Typ string je přímo mapován na řetězec jazyka C.

Složitější je ovšem mapování složených datových typů. Primární příčinou komplikací je předávání parametrů typu inout a out v metodách objektu. Pokud je parametr výstupní, musí implementační kód alokovat paměť pro uložení hodnoty parametru a tuto paměť pak musí agent ORB bezpečně uvolnit. Všechny složené typy musí proto být mapovány tak, aby bylo zajištěno správné kopírování složek při přiřazování a byla zaručeno uvolnění paměti při vyvolání destruktoru. Pro reprezentaci složených typů union a sequence vygeneruje kompilátor IDL definici třídy, která obsahuje implementaci konstruktoru, přiřazovacího operátoru a destruktoru, resp. další metody pro přístup k prvkům sequence. Mapování struktur a polí závisí na typu prvků a jeho popis se vymyká rozsahu tohoto příspěvku.

Pro bezpečnou manipulaci s ukazateli na složené typy generuje překladač IDL pro každý typ T třídu T_var a T_ptr. Třída T_var zabaluje ukazatel T * a zajišťuje správné chování při přiřazování (zrušení staré hodnoty) a opuštění rozsahu platnosti (uvolnění hodnoty na kterou ukazuje). Přímé použití T * (T_ptr) není omezeno, ale programátor musí sám zajistit explicitně rušení instancí.

Pokud použitý překladač C++ nepodporuje prostory jmen (namespace), je jméno modulu z definice rozhraní v jazyce IDL použito jako předpona mapovaných jmen. Pokud jsou prostory jmen podporovány, odpovídá jméno modulu deklaraci namespace. Pro uvedený příklad by překlad rozhraní do jazyka C++ bez namespace mohl mít tvar:

class WWW_Server: public virtual CORBA_Object {
public:
   virtual CORBA_Boolean reference(const char *url, const char *host,
			CORBA_Environment& env = _environment) const;
   virtual CORBA_Boolean release(const char* url, const char *host,
			CORBA_Environment& env = _environment) const;
   virtual WWW_URL_list *get_references(const char* url,
		 	CORBA_Environment& env = _environment) const;
  
   static WWW_Server_ptr _nil() { return &coNilObject; }
   static WWW_Server_ptr _duplicate(const WWW_Server_ptr obj);
   static WWW_Server_ptr _narrow(const CORBA_Object_ptr obj);
};
Skrytou bázovou třídou všech rozhraní je rozhraní objektu CORBA::Object. Operace definované v tomto rozhraní jsou definovány ve standardu CORBA a díky dědičnosti jsou dostupné pro všechna další rozhraní. Jsou to metody pro práci s referencemi na objekty _is_nil() (test platnosti reference) a _release() (uvolnění reference). V příkladu vyznačené statické metody musí být deklarovány znovu pro každou vygenerovanou třídu. Metoda _nil() poskytuje prázdnou referenci odpovídajícího typu, metoda _duplicate() vytváří novou referenci na objekt (inkrementuje počet odkazů) a _narrow() zajišťuje bezpečné přetypování. Další standardní metody pro přístup ke skladu rozhraní (interface repository), skladu implementací (implementation repository) a generování dynamických požadavků již přesahují téma tohoto článku.

Rozhraní objektu CORBA::Object není ve skutečnosti rozhraním vzdáleného objektu, protože objekt je součástí implementace ORB. Podobná jsou rozhraní standardních objektů ORB, BOA, Request, NVList, apod. Tyto objekty jsou proto nazývány ve standardu CORBA pseudo-objekty a jejich rozhraní je definováno v jazyce pseudo-IDL (PIDL). Mapování pseudo-objektů je samozřejmě silně závislé na implementačním jazyku. Nejpřirozenější je pro jazyk C++, kde vystupují pseudo-objekty jako třídy a lze s nimi pracovat podobně jako se vzdálenými objekty.

Na operace s typy mapovanými z jazyka IDL a PIDL jsou vztažena některá omezení. Nejvíce omezení je kladeno na třídy, které reprezentují rozhraní objektu. V programu nesmí být vytvářeny instance, odkazy, ani reference těchto objektů a nesmí být z nich odvozovány nové třídy. Použití rozhraní objektu v jazyce IDL reprezentuje odkaz na objekt (object reference). Odkazy na objekty mohou být předávány v parametrech metod a mohou být také výsledkem. Mezi klientem a serverem je předávána pouze identifikace objektu, vlastní objekt se nepřenáší. Pro práci s odkazy na objekt s rozhraním A v jazyce C++ jsou vygenerovány třídy A_var a A_ptr (obvykle odpovídá A *). Tyto typy jsou podobné typům T_var a T_ptr pro práci s ukazateli na složené typy, liší se ale způsobem vytváření a kopírování objektů:

typedef WWW_Server *WWW_Server_ptr;			// A *
class WWW_Server_var {					// A_var
	WWW_Server_ptr ptr_;				// zabalený ukazatel
public:
	WWW_Server_var(): WWW_Server::_nil()) { }	// prázný odkaz
	WWW_Server_var(WWW_Server *ptr): ptr_(ptr) { }
	WWW_Server_var(const WWW_Server_var &var):	// kopie odkazu
 				ptr_(WWW_Server::_duplicate(var.ptr_)) { }
	~WWW_Server_var() { CORBA_release(ptr_); }	// uvolnění odkazu
	WWW_Server_var &operator =(WWW_Server_var &var) {	
		if (ptr_ != var.ptr_) { 			// identita?
			CORBA_release(ptr_);		// uvolnění odkazu
			ptr_ = WWW_Server::_duplicate(var.ptr_); // kopie
		}
		return *this;
	}
	...
	operator WWW_Server_ptr() const { return ptr_; }
	WWW_Server_ptr operator-> const { return ptr_; }
};
V implementaci konstruktoru objektu a přiřazení lze vidět, jak jsou vytvářeny a rušeny reference na vzdálený objekt. Operace CORBA_release() a CORBA_duplicate() jsou standardními operacemi modulu CORBA pro zrušení reference na objekt a získání nové reference.

2.4 GIOP a IIOP

Protokol IIOP je definován jako implementace obecného protokolu GIOP nad protokolem TCP/IP. Obecný protokol komunikace mezi různými ORB (GIOP) definuje formát požadavků a odpovědí nad libovolným spojovaným transportním protokolem. Klient iniciuje spojení, server je pasivní a čeká na otevření spojení klientem. Jedno spojení mezi klientem a serverem může být sdíleno a požadavky na různé objekty se mohou překrývat. Mezi klientem a serverem je definováno celkem 7 typů zpráv:
Typ zprávy zdroj popis
Požadavek (Request) klient vyvolání metody vzdáleného objektu
Odpověď (Reply) server výsledek vyvolání
Zrušení požadavku (CancelRequest) klient zrušení předcházejícího požadavku
Vyhledání (LocateRequest) klient zjištění umístění vzdáleného objektu
Odpověď na vyhledání (LocateReply) server indikuje, zda server implementuje objekt, nebo předá volání dále
Uzavření spojení (CloseConnection) server uzavření spojení
Chyba (MessageError) oba reakce na předchozí zprávu
Formát zpráv je definován na úrovni jazyka IDL. Pro transformaci dat na úroveň přenosu je definována společná reprezentace dat (CDR, Common Data Representation). Pro jednoduché typy jazyka IDL je definována přímá binární reprezentace v tom pořadí slabik ve slově, které používá hostitelský systém. Protější strana musí být vždy schopna pořadí slabik upravit podle svých potřeb. Díky tomu není třeba při komunikaci mezi stejnými architekturami zbytečně převádět data na síťový formát a naopak, jak je tomu u Sun RPC.

Pro reprezentaci složených typů jazyka IDL jsou stanovena přesná pravidla, například posloupnost začíná vždy délkou typu long a pak následují prvky posloupnosti. Při odesílání parametrů požadavku na straně klienta a dekódování parametrů na straně serveru je využito znalosti typů přenášených dat z definice rozhraní objektu v jazyce IDL. Vlastní vkládání a dekódování řeší vygenerované metody v zástupné třídě u klienta nebo kostře na straně serveru. Například vygenerovaná metoda reference() by mohla mít tvar:

CORBA_Boolean WWW_Server::reference(const char* url, const char *host,
						 CORBA_Environment& _env)
{
	CORBA_Boolean _returnValue = 0;
	Request _req(this, operations, 1); 	// inicializace zprávy
	size_t _inSize = _req.size_string(url); // délka hodnoty 1. par.
	_inSize += _req.size_string(host); 	// délka 2. parametru
	_req.initialize(_inSize, 0, _env) != C_OK) {
		return _returnValue;		// není místo pro parametry
	}
	_req.put_string(url);			// uložení 1. parametru
	_req.put_string(host);			// uložení 2. parametru
	if (_req.invoke(_env) != C_OK) return _returnValue; // aktivace
	return _req.get_boolean();		// dekódování výsledku
}
Složitější je ovšem přenos hodnot typu Any. Skutečná hodnota může být libovolného typu a proto musí být jednak dostupné typové informace k předávané hodnotě na straně odesílatele, jednak musí být tyto informace přeneseny v požadavku nebo odpovědi na stranu příjemce. K tomuto účelu je použito identifikace typu (TypeCode). Protože hodnota identifikace typu je opět předem neznámým typem, je pro přenos identifikace typu využito zapouzdřeného CDR. Takto přenášené hodnota musí v sobě obsahovat dostatečné informace pro správné dekódování. Reprezentace spočívá v posloupnosti oktetů, je tedy stejná jako pro standardní typ IDL sequence<octet>. Navíc je před začátkem posloupnosti indikace formátu slabik ve slově.

2.5 IOR

V rámci jedné implementace prostředí CORBA může být formát adresy objektů libovolný. Při předávání odkazů na objekty mezi různými systémy už musí být adresa objektu v přenositelném tvaru. Standard CORBA 2.0 zavedl přenositelný odkaz na objekt (IOR, Interoperable Object Reference). Odkaz je možno chápat jako absolutní adresu objektu, jejíž součástí je adresa na úrovni komunikačního protokolu. Aby nebyl tento formát omezen pouze na prostředí jednoho konkrétního protokolu, může jeden odkaz IOR obsahovat několik různých adres ve formě posloupnosti profilů:
typedef unsigned long ProfileId;
const ProfileId TAG_INTERNET_IOP = 0;
struct TaggedProfile {				// profil
	ProfileId tag;				// typ profilu
	sequence <octet> profile_data;		// vlastní adresa
};
struct IOR {
	string type_id;				// typ rozhraní objektu
	sequence <TaggedProfile> profiles;	// seznam profilů (adres)
};
První složka type_id obsahuje identifikaci rozhraní zpřístupňovaného objektu. Obsah profilu je obecně závislý na protokolu komunikace mezi ORB. Obecný protokol GIOP doporučuje, aby profil obsahoval alespoň číslo verze protokolu, adresu na úrovni komunikačního protokolu a klíč (object_datum) pro identifikaci objektu. Profil pro odkaz na úrovni protokolu IIOP je definován takto:
struct Version {
	char major;			// '1'
	char minor;			// '0'
};
struct ProfileBody {
	Version iiop_version;
	string host;			// doménové jméno nebo IP adresa
	unsigned short port;		// číslo portu
	sequence <octet>object_key;	// závisí na OA a ORB
};
Pro manipulaci s odkazy jsou v rozhraní objektu ORB definovány operace pro převod IOR na řetězec ORB::object_to_string() a opačně ORB::string_to_object(). Převod na řetězec využívá zapouzdřenou reprezentaci CDR se zápisem oktetů v hexadecimálním kódu. Pro identifikaci je navíc na začátku prefix IOR.
IOR:010000002800000049444C3A6F6D672E6F72672F436F734E616D696E672F4E616D
696E67436F6E746578743A312E30000100000000000000540000000101000012000000
626F636F2E6665652E76757462722E637A008913340000004F422F49442B4E554D0049
444C3A6F6D672E6F72672F436F734E616D696E672F4E616D696E67436F6E746578743A
312E30003000

2.6 Klient

Prvním krokem při návrhu klienta je vygenerování potřebných definic v implementačním jazyce z definice rozhraní objektu v jazyce IDL. Při použití mapování do jazyka C++ vygeneruje obvykle překladač IDL jeden hlavičkový soubor obsahující deklaraci mapovaných datových typů a zástupnou třídu reprezentující rozhraní objektu. V hlavním programu klienta musí být nejprve inicializováno prostředí CORBA ORB funkcí CORBA_ORB_init():
#include "WWW.h"		// vložení vygenerovaného hlavičkového souboru
int main(int argc, char **argv)
{
	CORBA_Environment env;

	CORBA_ORB_ptr orb = CORBA_ORB_init(argc, argv, 0, env);
	if (env.exception()) {
		cerr << "Cannot initialize ORB\n"; 
		return 1;
	}
Výsledkem funkce ORB_init() je odkaz na pseudo-objekt reprezentující rozhraní ORB. V  příkladu je použito nejjednodušší možné implementace ORB v jazyce C++ bez namespace a výjimek. Chybové stavy jsou v tomto případě signalizovány vv prostředí, které je předáváno v posledním parametru funkcí modulu CORBA.

Dalším krokem je získání odkazu na objekt, který chce klient využívat. Nejjednodušší možný postup je získání reference ze standardního vstupu programu:

	cin.getline(sior, sizeof(sior));	// přečíst řádek ze vstupu
	CORBA_Object_var obj = orb->string_to_object(sior);
	if (CORBA_is_nil(obj)) { 		// je adresa platná?
		cerr << "Bad IOR\n"; 
		return 1;
	}
	WWW_Server_var server = WWW_Server::_narrow(obj);// přetypování
	if (CORBA_is_nil(server)) {			 // je typ objektu OK?
		cerr << "bad interface imported\n"; 
		return 1;
	}
// použití vzdáleného objektu
	server->reference("/index.html", hostname, &env);
	if (env.exception()) { 
		...			// chyba při volání
	}
Po získání reference na objekt následuje přetypování na požadovaný typ metodou _narrow(). Tato metoda ověří, zda je získaná reference skutečně odkazem na objekt požadovaného rozhraní. Získaná proměnná server je ukazatelem na objekt zástupné třídy. Prostřednictvím metod tohoto objektu může klient transparentně používat služby vzdáleného objektu.

2.7 Služba pojmenování objektů

Zadávání adresy objektu při každém spuštění aplikace je samozřejmě nepraktické. Běžnější asi bude použít objektovou službu registrace objektů Naming Service. Ovšem tato služba je opět zprostředkována rozhraním CORBA, takže pro její použití je třeba znát její adresu ve formě IOR. Dá se ale očekávat, že adresa této služby (a některých dalších služeb) bude v dané implementaci konstantní. Pro získání odkazů na standardní objekty je určena funkce resolve_initial_references(). V následujícím příkladu je současně demonstrována implementace, která využívá výjimek jazyka C++:
	CORBA_Object_ptr ns_obj;
 	try {						// získání objektu NS
		ns_obj = orb->resolve_initial_references("NameService");
	} catch(...) {
		cerr << "cannot resolve NameService" << endl;return 1;
	}
	CosNaming_NamingContext_var nc;	// přetypování na kontext
	nc = CosNaming_NamingContext::_narrow(ns_obj)

	CosNaming_Name name;			// jméno hledaného objektu
	name.length(1);				// nastavení délky posloupnosti
	name[0].id = CORBA_string_dup("WWW_Server");
	name[0].kind = CORBA_string_dup("");
	CORBA_Object_var obj;
	try {
		obj = nc->resolve(name);	// vyhledání objektu a 
	} catch(...) {				// získání reference
		cerr << "cannot resolve WWW_Server" << endl; return 1;
	}
Po získání adresy rozhraní objektu NameService následuje vytvoření pseudo-objektu CosNaming::Name, který popisuje hledaný objekt. Hledání může probíhat v různých kontextech určených objektem CosNaming::NamingContext. V tomto případě je pro jednoduchost použit základní kořenový kontext. Výsledkem vyhledání objektu metodou resolve() je opět reference na hledaný objekt, kterou dále přetypujeme a používáme stejně jako v předchozím příkladu.

2.8 Implementace objektu

Implementovat objekt v jazyce C++ znamená navrhnout třídu, jejíž metody odpovídají mapovaným metodám rozhraní objektu v jazyce IDL. Jméno, ani hierarchie dědičnosti této třídy, nezávisí na rozhraní implementovaného objektu. Rovněž složky této třídy mohou být libovolné, jediné požadované jsou ty, které jsou metodami implementovaného objektu. Pro vazbu implementační třídy na kostru objektu jsou používány dvě metody. První využívá dědičnosti a požaduje, aby implementační třída byla odvozena od vygenerované kostry a implementované metody byly virtuálními metodami této třídy. Vazba je pak pevná a inicializace serveru je o něco jednodušší. Na druhé straně může být požadavek dědění z kostry omezujícím, protože přidává do implementační třídy další složky a metody.

Druhá metoda spočívá v delegování metod z kostry objektu do implementačního objektu. V tomto případě je závislost opačná, kostra objektu částečně závisí na implementační třídě (ve skutečnosti pouze na jejím jménu). Implementační třída pak nemá žádné omezení z hlediska dědičnosti. Příkladem může být implementace COOL ORB firmy Chorus. Implementační třída našeho příkladu je v obou případech podobná, u druhé metody by pouze nebyla odvozena od vygenerované třídy WWW_Server_skel (název kostry se samozřejmě u každé implementace liší):

class ServerImpl: WWW_Server_impl {
	struct sless {				// operátor less<const char *>
		bool operator() (const char *s1, const char *s2) const {
			return strcmp(s1, s2) < 0;
		}
	};
	typedef list<const char *> ref_list;	// seznam STL
	typedef map<const char *, ref_list, sless> ref_map; // asociativní pole
	ref_map references;			// seznam odkazů
public:
	virtual CORBA_Boolean reference(const char *url, 
				const char *host, CORBA_Environment &env);
	virtual CORBA_Boolean release(const char *url, const char *host,
						CORBA_Environment &env);
	virtual WWW_URL_list *get_references(const char *url, 
						CORBA_Environment &env);
};
Privátní část třídy obsahuje deklarace potřebné pro implementaci objektu, v daném případě seznam a pole ze standardní knihovny šablon (STL) jazyka C++. Deklarace metod odpovídá vygenerované kostře objektu. Dalším krokem je implementace metod, například reference() :
CORBA_Boolean ServerImpl::reference(const char *url, const char *host,
							 CORBA_Environment&)
{
	host = CORBA_string_dup(host);		// kopie hodnoty 
	if (references.find(url) == references.end()) {	// není zde
		references[CORBA_string_dup(url)].push_back(host);
		return CORBA_TRUE;
	}
	references[url].push_back(host);	// přidat další odkaz
	return CORBA_FALSE;
}
Vstupní parametry jsou vždy předávány jako const a jejich hodnoty jsou zaručeny pouze po dobu volání metody. Pokud má být hodnota parametru uchována, je třeba ji okopírovat (v tomto případě CORBA_string_dup()). Naopak hodnoty výstupních parametrů a výsledek musí implementace alokovat příkazem new nebo funkcí CORBA_string_alloc() pro řetězce a ORB je po odeslání uvolní příkazem delete, resp. CORBA_string_free().

Kostra objektu dekóduje přicházející požadavky inverzním postupem oproti zástupné třídě u klienta a volá metody implementační třídy:

case id_reference: 			// příklad zpracování volání metody reference
	WWW_URL url = 0;
	char *host = 0;
	_req.get_string(url);		// dekódování 1. parametru
	_req.get_string(host);		// dekódování 2. parametru
	CORBA_Boolean _rValue;		
	_rValue = reference(url, host, _env); // vyvolání implementace
// inicializace odpovědi
	if (_req.initialize(1, _env) != C_OK) return C_ENOMEM;
	_req.put_Boolean(_returnValue);	// uložení výsledku
	CORBA_string_free(url);		// uvolnění alokované hodnoty
	CORBA_string_free(host);
	return C_OK;			// návrat a odeslání odpovědi

2.9 Hlavní program serveru

Hlavní program implementující objekt musí Nejprve inicializovat ORB podobně jako u klientského programu. Pak následuje inicializace objektového adaptéru a případně navázání implementace objektu na kostru objektu a objektový adaptér. V případě metody pevné vazby je inicializace objektu a vazba na objektový adaptér často skryta v konstruktoru kostry bázového pseudo-objektu CORBA::Object. Protože jsou všechna rozhraní skrytě odvozena od tohoto rozhraní, jsou i všechny implementační třídy odvozeny od třídy CORBA_Object_skel. Pokud podporuje daná implementace automatickou registraci, obsahuje hlavní program v úvodní pasáži navíc pouze inicializaci objektového adaptéru BOA_init():
int main(int argc, char **argv)	
{
	CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
	CORBA::BOA_var boa = orb->BOA_init(argc, argv);

	ServerImpl serverImpl;		// vytvoření instance objektu
	cout << orb->object_to_string(server) << endl; // výpis IOR
	boa->impl_is_ready(CORBA_ImplementationDef::_nil());
} 
Tato automatická vazba ale není zaručena, u některých implementací je požadována explicitní registrace. Při použití metody delegování musí být navázání vždy explicitní. Vazba objektu na objektový adaptér je jedním ze slabých míst standardu CORBA 2.0 a proto je v současné době připravována nová specifikace přenositelného objektového adaptéru (POA), která by měla uvedené problémy vyřešit.

Po inicializaci objektového adaptéru následuje vytvoření instance implementačního objektu a výpis jeho IOR na standardní výstup. Poslední volaná metoda signalizuje objektovému adaptéru, že implementace je připravena přijímat a zpracovávat požadavky. V daném případě se předpokládá, že program bude spuštěn před příchodem prvního požadavku. Základní objektový adaptér (BOA) by měl dle standardu CORBA podporovat tyto čtyři režimy aktivace objektů:
Sdílený server Sdílený server je spuštěn mechanismem ORB pouze jednou. Po své inicializaci signalizuje připravenost metodou impl_is_ready() a sekvenčně zpracovává všechny požadavky na objekty implementující dané rozhraní. Je typický pro složité služby a persistentní objekty.
Trvalý server Trvalý server je spuštěn mimo prostředí ORB, jinak je jeho funkce stejná jako u sdíleného serveru.
Nesdílený server Nesdílený server obsluhuje pouze jeden objekt implementující dané rozhraní. Je aktivován při požadavku klienta na objekt.
Server na požadavek Server je spuštěn při každém novém požadavku na objekt. Po zpracování požadavku běh serveru končí.
Automatické spouštění serveru při příchodu požadavku vyžaduje registraci programu implementujícího daný objekt ve skladu implementací. Při této registraci se zaznamená jméno programu, parametry pro spuštění programu, rozhraní, které implementuje, a pro nesdílený server také jméno objektu. Konkrétní postup, jak ORB vyhledá odpovídající implementační program, spustí jej a doručí mu požadavek klienta, není definován a závisí na implementaci. Základní objektový adaptér je jediný, který je definován ve standardu CORBA. Řada firem poskytuje ke svým prostředím specializované objektové adaptéry, například pro persistentní objekty v databázích, objekty s automatickou registrací, vestavěné objekty, apod. Teoreticky je možné doplnit dokonce svůj vlastní objektový adaptér, ale jeho návrh je komplikován tím, že rozhraní mezi objektovým adaptérem a ORB není standardizováno.

    3. Objektově orientované služby

Jak lze vidět z uvedených příkladů základní prostředí CORBA ORB pouze podporuje volání vzdálených objektů. Pro tvorbu skutečných aplikací potřebujeme navíc alespoň objektové služby pro registraci a vyhledávání objektů, automatické spouštění serverů implementujících požadované objekty, operace se skladem rozhraní, apod. Tyto služby jsou definovány samostatnými standardy, z nichž jsou v současné době publikovány:
Název služby ftp.omg.com/ 
docs/formal/
Stručný popis funkce
Naming Service 97-02-08.pdf  registrace IOR a zpřístupnění jmény objektů
Event Service 97-02-09.pdf  zasílání asynchronních událostí
Persistent Object Service 97-02-10.pdf  ukládání objektů do souborů a databází
Life Cycle Service 97-02-11.pdf  vytváření a rušení objektů
Concurrency Control 97-02-12.pdf  paralelní přístup k objektům, synchronizace
Externalization Service 97-02-13.pdf  ukládání a obnovení stavu objektů
Relationship Service 97-02-14.pdf  vztahy mezi objekty, ekvivalence objektů
Transaction Service 97-02-15.pdf transakce
Query Service 97-02-16.pdf vyhledávání v souborech objektů, SQL, OQL
Licensing Service 97-02-17.pdf správa licencí
Property Service 97-02-18.pdf vlastnosti objektů
Property Service IDL 97-02-19.pdf rozšíření IDL pro definice vlastností objektů
Security Service 97-02-20.pdf ochrana a bezpečnost, SCIOOP
Time Service Spec. 97-02-22.pdf generování událostí v čase, měření intervalů
Z uvedených služeb jsou nejrozšířenější Naming Service a Life Cycle. Transakční služby, zabezpečení a externalizaci podporují implementace zaměřené spíše na databázové služby.

4. Dostupnost

Prostředí CORBA ORB nabízí celá řada dodavatelů programového vybavení, včetně velkých firem, jako jsou HP, Sun a IBM. Firmy IONA, ExperSoft a Visigenic se dokonce věnují pouze vývoji prostředí CORBA. Kvalitní implementace jsou poměrně drahé, například prostředí IONA Orbix stojí 5000 $ za jednu vývojovou licenci. Naštěstí jsou některé produkty dostupné v časově omezené verzi na odzkoušení a existuje také několik volně dostupných implementací ve zdrojové, či binární podobě. V následující tabulce je uveden stručný přehled:
Firma Produkt URL Objektové služby
Chorus COOL/ORB www.chorus.com/Products/Cool NS
Digital ObjectBroker www.digital.com/info/objectbroker/ NS
ExperSoft CORBAPlus www.expersoft.com/ NS, Event, Rel, Pers, 
Gerald Brose JacORB www.inf.fu-berlin.de/~brose/jacorb/ NS, Event, zdroj zdarma
HP ORB Plus www.hp.com/gsy/orbplus.html NS, LC, Event
IBM Component Broker www.software.ibm.com/ad/cb/ NS, LC, Event, Pers, Trans, Sec, Conc
ICL DAIS www.icl.com/products/dais/ NS, LC, Sec, Trans
IONA Orbix www.iona.com/Products/Orbix/ NS, Event, Sec, Trans
Olivetti/ 
Oracle
OmniOrb2 www.orl.co.uk/omniORB/  
omniORB.html
NS, nemá Any a IR, zdroj zdarma
OO Concepts OmniBroker www.ooc.com/ob.html NS, zdroj zdarma
Sun IIOP ftp.omg.org/pub/interop/iiop.tar.Z implementace IIOP/C++
  NEO www.sun.com/solaris/neo NS, LC, Prop, Event
  JavaIDL www.sun.com/sunsoft/solaris/java-idl/ NS
Visigenic VisiBroker www.visigenic.com/prod/ NS, Events, LC
Uvedený seznam implementovaných objektových služeb je odhadnut z dostupných materiálů a je bez záruky. K dostupným zdrojům je třeba také připočítat WWW (www.omg.com) a FTP server sdružení OMG, kde jsou dostupné všechny publikované materiály, včetně standardu CORBA 2.0.

Závěr

Architektura OMG CORBA je poměrně složitá, ale na druhé straně otevřená a za mnoho let vývoje také koncepčně promyšlená. Bohužel otevřenost architektury je v některých případech na újmu přenositelnosti, protože standard CORBA 2.0 se některým implementačním detailům vyhýbá. Implementace různých výrobců tak sice mohou deklarovat dodržení standardu, ale jsou mezi nimi velké rozdíly, zvláště pak v rozhraní BOA a ORB. Přenositelnost implementací objektů a klientů na úrovni implementačního jazyka tím samozřejmě trpí. Tuto skutečnost si uvědomilo i sdružení OMG a v nedávné době publikovalo dokument ORB Portability Joint Submission. Navrhuje zde zrušit celou pasáž standardu CORBA 2.0 týkající se BOA a nahradit ji novou definicí Portable Object Adapter (POA) s konkrétnějším mapováním do jazyka C a C++. Otázkou ale zůstává, zda odolá architektura CORBA útoku největšího konkurenta, firmě Microsoft s konkurenční technologii DCOM.

Literatura:

The Common Object Request Broker: Architecture and Specification, OMG, 1996

CORBAservices: Common Object Service Specification, OMG, 1996

ORB Portability Joint Submission, OMG, May 1997

COOL-ORB Tutorial, Chorus Systems, 1997

The Orbix Architecture, IONA Technologies, November 1996

VISIGENIC VisiBroker for C++ Programmer s Guide Version 2.0, Visigenic, 1997