Professional Documents
Culture Documents
Poetkom 90-ih je bilo otean razvoj mrenih aplikacija. Od mnogobrojnih razloga navodimo samo neke: Razliit hardver raunara Razliita mrena oprema Razliiti mreni protokoli Razliiti operativni sistemi Razliiti programski jezici Sa ciljem da premosti jaz izmeu programa koji su bili pisani na razliitim programskim jezicima, izvravali se na raunarima na kojima su trali razliiti operativni sistemi, koji su bili povezani preko razliitih mrenih tehnologija korienjem razliitih mrenih protokola, nastao je standard CORBA Common Object Request Broker Architecture. CORBA je prvi, najvaniji i pre svega najambiciozniji middleware projekat pokrenut u istoriji. Proizvod je konzorcijuma OMG (Object Management Group) koji broji preko 700 lanova (to pojedinaca to velikih softverskih kompanija). CORBA je papir, tj. specifikacija na preko hiljadu strana.
Istorijat
Verzija 1.0 Datum izlaska okt. 1991 Opis - CORBA objektni model - Osnovni API - Mapiranje na programski jezik C - IDL (Interface Definition Language) jezik za opis interfejsa - Interface repository - interfejsi za BOA (Basic Object Adapter) - interfejsi za rukovanje memorijom - pojasnili objektni model
1.1
feb. 1992
1.2 2.0
- zadrali postojei objektni model - podrka za C++ i Smalltalk - protokoli za komunikaciju: GIOP (General Inter-ORB Protocol), IIOP (Internet Inter-ORB Protocol) - poveana bezbednost: sigurni IIOP i IIOP over SSL - podrka za Ada i COBOL programske jezike - POA (Portable Object Adapter) - poveava portabilnost servera - komunikacija sa DCOM-om - podrka za programski jezik Java
2.1
aug. 1997
2.2
feb. 1998
2.3
jun. 1999
2.4
okt. 2000
mapiranje IDL-a na programski jezik Java mapiranje na C++ portabilnost IDL/Java interoperabilni naming servis minimalna CORBA (Minimum CORBA) CORBA za rad u realnom vremenu (Real-time CORBA)
2.5
sep 2001
- Fault tolerant CORBA specifikacija - Portable interceptors - Common Security - CORBA Core specifikacija - CORBA Component model - Minimum i Real-time CORBA postaju odvojene specifikacije
2.6 3.0
3.0.3 mar. 2004 - samo da se vidi da je CORBA iva Tabela 1. Istorijat CORBA-e CORBA je bila veoma popularna sredinom devedesetih, pre nagle ekspanzije Internet-a. OMG je sporo reagovao (pre svega zbog velikog broja lanova) i nisu na vreme odgovorili na zahteve trita koje se preorijentisalo prema web-u i zbog toga su bili pregaeni. Razlozi zbog kojih CORBA nije postala ono za ta je bila namenjena lee u sledeim injenicama: - skup razvoj aplikacija - CORBA esto suvie komplikovana - mnoge implementacije su pune raznih propusta (bug-ovi, sigurnosne rupe, itd.) Glavni razlog polakog posustajanja CORBA-e je nedovoljno brzo praenje zahteva trita. Tritu je bio potreban otvoren standard koji bi omoguio komunikaciju izmeu razliitih aplikacija kroz otvoreni Internet. CORBA komunikacija koristi vie portove i zato ne prolazi kroz vatrene zidove (firewall). Bez obzira to su CORBA poruke bile binarne i iz tog razloga su se prenosile jako brzo, prva tehnologija koja je znaajnije zapretila CORBA-i je bila SOAP (Simple Object Access Protocol), koji je izdat 1999. godine. SOAP koristi XML poruke koje se lako prenose Internet-om i itljive su i za raunare i za ljude. Iako su XML poruke tekstualne, to znai da koliina prenetih podataka nije optimalna, SOAP je brzo nadirao zbog lakoe upotrebe i lakog prolaenja kroz Internet (korienjem HTTP protokola bez problema prolazi kroz veinu firewall-ova). Sledei dogaaj koji je isto doprineo gubitku trinog uea je bio kada se 2000. i 2001. izduvao Internet balon i kada su mnoge kompanije koje su koristili CORBA-u nestale sa trita. Danas CORBA ima jako mali deo trinog uea, bez obzira na njene mnogobrojne pozitivne karakteristike.
Primena
CORBA je specifikacija koja teoretski dozvoljava da dva CORBA programa komuniciraju bez ikakvih promena iako su: - pisana na razliitim programskim jezicima (npr. C++ i Java) - izvravaju se na razliitim operativnim sistemima (npr. Windows i UNIX)
koriste razliite mrene protokole (npr. TCP/IP i Modbus) izvravaju se na razliitom hardveru (npr. Intel 32 bitni procesori i Alpha procesori) koriste razliite mrene tehnologije (npr. 100 Mbps Ethernet i token ring mrea)
Na ovako sloene zahteve CORBA odgovara tako, to se useli izmeu operativnog sistema i aplikacije i sakrije sloenost operativnog sistema (a zajedno sa OS-om sakriva sloenost mrenih protokola, hardvera raunara i mrenog hardvera). CORBA je izbor onih, kojima je potrebna brzina i nezavisnost od isporuioca hardvera, proizvoaa operativnog sistema i/ili mrene tehnologije. Oni koji se odlue za CORBA-u ne moraju da trpe politiku proizvoaa kada doe do prelaska na sledeu verziju operativnog sistema/hardvera. Kada odreeni OS ili hardver postane nedostupan, CORBA bazirane aplikacije se uz neznatne modifikacije mogu preneti na drugi hardver/operativni sistem. Kod CORBA-e se podaci prenose binarno. Ovakav tip prenosa je puno bri od prenosa tekstualnih sadraja (npr. XML poruke kod SOAP-a). CORBA danas jedino na tritu embedded sistema ima porast trinog uea. Sem te oblasti postoje instalacije u: - rezervacije avio karata - komunikacija izmeu e-commerce aplikacija - telefonskim kompanijama (transakcije) - finansijskim sistemima
Implementacije
Kao to je ve ranije reeno, CORBA je samo papir, tj. specifikacija na vie od hiljadu stranica teksta. Ova specifikacija je bila ispred svog vremena kada je izala (poetkom devedesetih godina dvadesetog veka) i softverska zajednica je sa entuzijazmom prihvatila ovaj novi standard. Krenulo se u pisanje veeg broja implementacija. Implementacija je fizika realizacija CORBA specifikacije koja radi na jednom ili vie operativnih sistema i/ili na odreenoj hardverskoj platformi. Poznatije CORBA specifikacije su prikazane u tabeli 2. Ime CORBA verzija omniORB 2.6 TAO 3.0 ORBit2 2.4 MICO 3.0 IIOP.NET 2.3 Visibroker 2.6 orbacus 2.6 ... Tabela 2. CORBA implementacije Licenca LGPL GPL LGPL LGPL LGPL komercijalna komercijalna
Tabela 2. sadri implementacije sa otvorenim kodom (sa razliitim licencama) i dve komercijalne implementacije. Na katedri za Automatiku i upravljanje sistemima koriste se omniORB i TAO. IIOP.NET je moda najinteresantniji projekat iz tabele, jer je pisan u za .NET framework, bazira se na .NET remoting-u i omoguava komunikaciju izmeu .NET, CORBA i J2EE objekata.
Arhitektura
Slika 1. Opta arhitektura CORBA-e Prikazana slika je relativno loa, ali se najvaniji elementi lepo vide: Object impl server. Preciznije: serverski objekat Client klijent, koristi usluge servera Object Request Broker sloj koji sedi na operativnom sistemu i sakriva njegovu sloenost ORB Interface API preko koga i klijent i server pristupaju ORB-u IDL Skeleton kod dobijen prevoenjem IDL-a. Mapiranje tipova (tzv. marshaling) i bazne klase koje serverski objekat treba da implementira - IDL Stubs poput IDL Skeleton-a, slui za mapiranje tipova - Object adapter poveava portabilnost serverske implementacije jer omoguave pisanje koda servera koji je nezavisan od koriene CORBA implementacije Postoje dve verzije object adapter-a: BOA (Basic Object Adapter) i POA (Portable Object Adapter)
POA je novijeg datuma i praktino razdvaja implementaciju serverskog objekta od objekta koji obrauje zahteve (servant) Od svih objekata sa slike 1., programer koji radi na razvoju CORBA aplikacije pie samo klijenta i implementaciju serverskog objekta.
Instalacija omniORB-a
Postupak instalacije binarne distribucije se sastoji od skidanje omniORB instalacije sa Internet-a raspakivanja ZIP fajla koji sadri binarnu distribuciju i podeavaja sistemske promenljive PATH, dodavanjem putanje do omnioORB-ovog /bin direktorijuma
Kao i veina projekata sa otvorenim kodom, i pre svega projekata koji se piu sa ciljem da bi radili na veem broju operativnih sistema, i omniORB distribucija ima konvencionalnu strukturu direktorijuma. Ova organizacija direktorijuma je prikazana na slici broj 2.
Slika 2. Organizacija direktorijuma kod omniORB-a Najvaniji direktorijumi sa slike broj 2 su: ./bin izvrni fajlovi i DLL-ovi sa implementacijom CORBA-e (za Windows OS) ./doc dokumentacija ./idl IDL fajlovi sa definicijom interfejsa za primere koji dolaze sa instalacijom ./include header fajlovi implementacije (u ovom sluaju omniORB-a) i primera ./lib biblioteke ./src izvorni kod omniORB-a i primera
Slika 3. Putanja do omniORB ./include direktorijuma 2. podeavanje projekata: projekti moraju da budu Win32 konzolne aplikacije. Otvori se podeavanja projekta sa ALT+F7 ili Project Settings (slika 4.). Iz padajueg menija u gornjem levom delu prozora, gde na slici pie Win32 Debug se izabere opcija All configurations
a. na C/C++ tab-u: i. pod kategorijom C++ Language se omogui rad sa izuzecima (selektuje se Enable exception handling ii. pod kategorijom Code generation za run-time biblioteku sa bira Multithreaded DLL (videti sliku 4.) iii. pod kategorijom Preprocessor se do-definiu (poslednje dve za Win XP i 2000) ,__WIN32__, __x86__, _WIN32_WINNT=0x0400, __NT__, __OSVERSION__=4 b. na Link tab-u: i. pod kategorijom Input se dodaju sledee biblioteke posle ve definisanog niza biblioteka (paziti da je potrebno razdvojiti ove biblioteke od ve postojeih u tom polju sa razmakom): ws2_32.lib mswsock.lib advapi32.lib omniORB406_rt.lib omniDynamic406_rt.lib omnithread31_rt.lib
Podeavanje je potrebno malo modifikovati za Debug konfiguraciju, i to u skladu sa sledeim uputstvom: - na C/C++ tabu, pod Code generation za run-time biblioteku birati Multi-threaded debug DLL - na Link tabu, u kategoriji Input se dodaju sledee biblioteke (debug verzije omniORB biblioteka): ws2_32.lib mswsock.lib omnithread31_rtd.lib advapi32.lib omniORB406_rtd.lib omniDynamic406_rtd.lib
Vano je napomenuti da se i novije verzije Visual Studio razvojnih okruenja (2003 i 2005) nametaju na slian nain.
Pre nego to se doda, datoteka eg1.cc se mora preimenovati u eg1.cpp. Ovo se radi iz razloga to je podrazumevano ponaanje VS6 da samo datoteke sa cpp ekstenzijom tumai kao izvorni kod. Posle preimenovanja i dodavanja datoteke eg1.cpp se moe prei na prevoenje prvog primera. Prevodioc e verovatno prijaviti par greaka zbog pogrenih imena fajlova (npr. u kodu u datoteci eg1.cpp se referencira datoteka echo.hh umesto echo.h). Popraviti ove greke i potom pokrenuti prvi echo primer. Dobija se sledei odziv:
Tumaenje koda
Implementacija servera i klijenta se kod ovog primera nalaze u istom EXE fajlu. I klijent i server su implementirani u datoteci eg1.cpp. - class Echo_i implementacija servera sa praznim konstruktorom i destruktorom i implementacijom metode echoString - metoda hello ova metoda simulira ponaanje klijenta: na ulazu dobija referencu na serverski objekat i na njemu poziva metodu echoString - metoda main inicijalizacija ORB-a, kreiranje serverskog objekta i njegova aktivacija na Portable Object Adapter-u (POA-i)
Na slici iznad se vidi koji treba da bude sadraj ova dva projekta. Takoe se vidi i deo koda implementacije servera. Klasa je ve poznata iz prvog primera, kao i njegova jedina (neprazna) metoda echoString. U main metodi se aktivira serverski objekat i ispie se njegov IOR (Interoperable Object Reference). Ovaj IOR je (neitljiv) jedinstveni identifikator servera. U njemu je kodirana IP adresa, port i ime servera. Svakim pokretanjem servera se dobija drugi IOR, jer svaka instanca istog servera dobija jedinstven IOR. Pokree se server (nakon popravljanja eventualnih greaka i prevoenja) i dobija se odziv poput onog na slici ispod.
Kao to se na slici vidi, nakon pokretanja, serverski EXE ispisuje jedinstveni IOR instance serverskog objekta. Klijentu se mora proslediti ovaj IOR da bi mogao da se povee na server. Pre prosleivanja se IOR mora kopirati iz komandnog prozora u tekst editor i potrebno je obrisati svaki prelazak u novi red i apostrofe sa poetka i kraja. Tako se dobija string koji izgleda otprilike ovako: IOR:010000000d00000049444c3a4563686f.......3136382e302e37002505 Klijent se poziva iz komandnog prozora tako to se navede njegovo ime i prosledi mu se serverov IOR. Nakon pritiska na dugme Enter, klijent treba da se povee na server i da pozove serverovu metodu echoString. Odziv klijenta je prikazan na slici ispod.
6. CORBA::Object_var obj = orb->string_to_object(argv[1]); 7. Echo_var echoref = Echo::_narrow(obj); 8. if( CORBA::is_nil(echoref) ) { 9. cerr << "Can't narrow reference to type Echo (or it was nil)." << endl; 10. return 1; 11. } 12. for (CORBA::ULong count=0; count<10; count++) 13. hello(echoref); 14. orb->destroy(); Listing 2. Main metoda klijenta Opis inicijalizacija CORBA provera da li je EXE pozvan sa odgovarajuim brojem parametara dolaenje do serverske reference na osnovu IOR-a (argv[1]) pretvaranje reference u Echo tip provera da li je uspelo dolaenje do reference i cast-ovanje u for petlji se deset puta poziva metoda hello koja poziva echoString metodu na serverskoj referenci Tabela 4. Opis main metode klijenta datoteka eg2_clt.cpp Red 1 2-5 6 7 8-11 12-13
linije koja im govori gde se nalazi omniNames, tj. za neki server server1 bi poziv iz komandne linije izgledao ovako:
server1 -ORBInitRef NameService=corbaname::localhost
Umesto adrese localhost (lokalna maina) moe da se stavi simboliko ime ili IP adresa bilo koje druge dostupne mrene lokacije gde je pokrenut omniNames.
Listing 4. Koda pojednostavljene main metode klijenta (datoteka eg3_clt.cpp) Red Opis 1 inicijalizacija CORBA-e 2 dolaenje do reference na serverski objekat pozivom getObjectReference 3 pretvaranje u Echo tip 4-5 10 poziva preko ranije upoznate metode hello Tabela 6. Opis koda iz listinga 4.
VIII. IX.
X.
Dok se koraci I-II rade samo jednom, ostale korake je potrebno uraditi za CORBA projekte (kako servere tako i klijente). Korak X se podrazumevao na vebama i nije bio pisan.
Rad sa nitima
Rad se nitima (thread) u projektima koji ukljuuju funkcionalnost omniORB-a se omoguava ukljuenjem header datoteke omnithread.h. Preduslov za ovo je da se radi o CORBA projektu koji koristi omniORB (jer gornji header dolazi sa omniORB-om). Do potrebe za uvoenjem vie niti izvravanja programa dolazi kada - ima vie klijenata koji se istovremeno kae na server - se izvravaju izuzetno zahtevni prorauni na raunarima sa vie procesora/jezgara - itd. Za rad sa nitima je potrebno napraviti klasu tipa nit, kreirate primerak te klase i pokrenuti. Na taj nain e se omoguiti izvravanje veeg broja niti u paraleli.
class WorkerThread : public omni_thread { public: WorkerThread(int nid, const STransfer& trans) : m_id(nid), m_trans(trans) {} ~WorkerThread() {} void Start(void) { start_undetached(); } private: void* run_undetached(void*); int m_id; const STransfer& m_trans; }; void* WorkerThread::run_undetached(void*) { cout << "Thread ID=" << m_id << " - Working..." << endl; Sleep(5000); cout << "Thread ID=" << m_id << " - Done." << endl; return 0; }
Listing 9. Korienje ranije definisane niti Kod programa koji rade sa vie niti koji rade sa istim podacima moe doi do nekonzistentnosti podataka. Ovo se izbegava zakljuavanjem. Postoje mnogi naini zakljuavanja podataka. Ovde emo prikazati zakljuavanje sa mutex-om.
Finance::STransfers* Finance_ITransfer_i::GetAllTransfers(const char* strAccount){ m_mutex.lock(); cout << "GetAllTransfers received" << endl; STransfers* pTrans = new STransfers(); pTrans->length(m_vTransfers.size()); for (int i=0; i<m_vTransfers.size(); i++)
Listing 10. Metoda koja koristi mehanizam zakljuavanja (mutex - metode lock i unlock)
Dodatni primer #1
Implementirati CORBA server sa interfejsom Validator koji se sastoji od sledeih metoda: Ime metode Ulazi validateDate string strDate validateNumber string strNumber Tabela 7. Metode servera Validator Izlaz(i) bool bool
Implementirati klijenta koji e se kaiti na server i pozivati metode servera. Reenje: Prvo se definie IDL opis interfejsa Validator. On se sastoji od dve metode i definie se u datoteci validator.idl (videti listing). Ovaj IDL se potom prevodi na C++ sa sledeim pozivom:
omniidl bcxx Wbh=.h Wbs=SK.cpp -Wbexample validator.idl
Prevoenjem IDL datoteke se dobija skeleton koji povezuje na kod sa ORB-om. Nakon pokretanja gore navedene komande nastaju fajlovi: - validator.hh preimenovati u validator.h - validator.cc Sa istoimenim header fajlom ini skeleton. Preimenovati u validator.cpp. - validator_i.cc promeniti ekstenziju u cpp. Poto je koriena opcija Wbexample, IDL prevodioc e izgenerisati i primer, tj. serversku klasu sa praznim metodama. Ove metode je potrebno implementirati. #ifndef __VALIDATOR_IDL__ #define __VALIDATOR_IDL__ interface Validator { boolean validateDate(in string strDate); boolean validateNumber(in string strNumber); }; #endif // __VALIDATOR_IDL__ Listing 5. IDL opis interfejsa Validator
Dodatni primer #2
Implementirati CORBA server koji ima sledea dva interfejsa Ulazi int nFileLength int nDays writeLine string strMessage TestMonitor init int interval monitorAlive string strIPAddress monitorMemUse Tabela 8. Metode servera TestTrace i TestMonitor Interfejs TestTrace Ime metode init Izlaz(i) bool int (MB)
Interfejse definisati u istom IDL fajlu. Prevoenjem se dobija prazna implementacija servera (pod uslovom da se IDL prevodiocu prosledi opcija Wbexample). Prazna implementacija se sastoji od klasa TestTrace_i i TestMonitor_i. Njihove metode se moraju implementirati (barem da vrate vrednost ako je to potrebno i da ispiu neku poruku). Zadaci: - implementirati server koji implementira oba interfejsa iz tabele 8. Server treba da ispie IOR obe serverskog objekta. Minimalna implementacija metode treba da se sastoji od ispisa poruke koja identifikuje metodu i od linije koja vraa vrednost (ako metoda vraa vrednost) - implementirati klijenta koji se kai na jedan od gornja dva interfejsa i poziva barem jednu metodu - promeniti server da registruje oba serverska objekta na omniNames-u. Koristiti modifikovanu bindObjectToName metodu iz Dodatka A (na kraju ovog dokumenta). - promeniti klijenta da se kai na oba serverska interfejsa. Klijent treba da dolazi do referenci preko omniNames-a. Treba da pozove barem jednu metodu oba interfejsa. Koristiti modifikovanu metodu getObjectReference iz dodatka A sa kraja ovog dokumenta
Dodatni primer #3
Implementirati CORBA server koji je opisan IDL-om iz listinga 6. Server da se registruje na omniNames-u sa imenom Example.Date. Napisati CORBA klijentsku aplikaciju koja poziva sve metode servera. Za komunikaciju sa omniNames-om koristiti modifikovane metode iz ove skripte. module DateService { struct MDate { long year; short month; short day; short hour; short minute; short second; long millisecond; }; typedef sequence<MDate> MDateSequence; typedef sequence<boolean> booleanSequence; exception DateError { string reason; }; interface IDateValidator { boolean ValidateDate(in MDate date) raises(DateError); booleanSequence ValidateDates(in MDateSequence dates) raises(DateError); }; interface IDateConversion { MDateSequence GetDatesBetween(in MDate begin, in MDate end) raises(DateError); MDate ToDate(in string strDate) raises(DateError); string ToString(in MDate date) raises(DateError); }; }; Listing 6. IDL opis modula DateService Sledei koncepti su novi u IDL listingu 6:
1. moduli slue za grupisanje veeg broja IDL tipova i interfejsa. Za definisanje modula se koristi kljuna re module (poetak spiska) 2. strukture za definisanje sloenih podataka koji se sastoje od osnovnih tipova (long, float, string, itd.) i drugih struktura. Za definisanje struktura se koristi kluna re struct. 3. nizovi u CORBA IDL-u se niz definie kljunom reju sequence. U listingu 6 se definiu dve sekvence: niz struktura tipa Mdate i niz boolean promenljivih 4. izuzeci znaajna razlika izmeu CORBA-e i COM-a jeste mogunost korienja izuzetaka u klijent-server vezi kod CORBA-e. Podseanja radi, kod COM-a se dojava greaka realizuje slanjem celobrojnih kodova (HRESULT). Izuzetak (engl. exception) se baci na serveru, propagira se kroz CORBA-u i hvata se na klijentu u catch bloku.
Dodatni primer #4
Implementirati CORBA server koji je opisan IDL-om iz listinga 7. Server da se registruje na omniNames-u sve svoje interfejse (npr. ImeModula.ImeInterfejsa). Napisati CORBA klijentsku aplikaciju koja poziva sve metode servera. Za komunikaciju sa omniNames-om koristiti modifikovane metode iz ove skripte.
module Finance { enum ECurrency {E_DINAR, E_EURO, E_POUND}; struct SDateTime { short nYear; short nMonth; short nDay; short nHour; short nMinute; short nSecond; }; struct STransfer { string strFrom; string strTo; ECurrency eCurr; float fValue; SDateTime dtDate; }; typedef sequence<STransfer> STransfers; interface ITransferCallback { void TransferMade(in STransfer trans); }; exception TransferException { string strReason; }; interface ITransfer { void DoTransfer(in STransfer trans); STransfers GetAllTransfers(in string strAccount); STransfers GetTransfers(in string strAccount, in SDateTime dtFrom, in SDateTime dtTo); STransfers GetTransfersByCurrency(in string strAccount, in ECurrency eCurr); void SetTransferCallback(in ITransferCallback callback); };
string strAddress; string strCity; string strPostcode; }; exception AccountException { string strReason; }; interface IAccount { long CreateAccount(in SPerson person) raises(AccountException, TransferException); }; };
Dodatni primer #5
Za interfejs iz listinga 8 a) napraviti CORBA serversku aplikaciju koja implementira interfejs IWarehouse. Napraviti CORBA klijentsku aplikaciju, koja izigrava proizvodnu liniju, i prima dojave preko interfejsa IAssemblyCallback. Server da implementira brojae svih tipova delova vozila (karoserija, toak, motor) i da ih aurira unutar metoda za uzimanje i dodavanje delova (GetPart i PutPart, respektivno). Klijent da periodino preuzima delove iz skladita i da pravi vozila (npr. svakih 10 sekundi) b) napraviti CORBA klijentsku aplikaciju koja prima dojave preko interfejsa IAssemblyCallback i u trenutku nestanka nekog dela poalje odreeni broj tih delova u skladite. c) prepraviti klijenta iz zadatka a) da pokree tri niti, i da svaka nit periodino preuzima delove i pravi vozila
module VehicleFactory { enum EPart { E_BODY, E_WHEEL, E_MOTOR }; // assembly lines are clients who receive callbacks through this interface interface IAssemblyCallback { void NoParts(in EPart eType); // no more parts left }; // the warehouse is the server supplying assembly lines with parts interface IWarehouse { void GetPart(in EPart eType); void PutPart(in EPart eType, in long count); void SetCallback(in IAssemblyCallback assembly); }; };
Reenja
Na serveru uraditi sledee: - snimiti IDL, prevesti ga i ukljuiti skeleton u projekat - promeniti ekstenziju automatski generisane implementacije servera u .cpp i ukljuiti ga u projekat - prepraviti server da radi sa omniNames-om, tj. ukljuiti header datoteku sa sadrajem iz dodatka A i umesto ispisa IOR-a pozvati bindObjectToName - u glavnoj (main) metodi - definisati novi tip vektora za skladitenje tipa IAssemblyCallback_ptr (pokaziva na objekte tipa IAssemblyCallback) i u klasu koja implementira interfejs IWarehouse dodati jedan primerak tog vektora - u metodi SetCallback implementirati ubacivanje kopije dobijenog pokazivaa u skladite, tj. u vektor definisan u prethodnom koraku - u klasu koja implementira interfejs IWarehouse dodati tri promenljive tipa ceo broj (int) za brojanje trenutnog stanja na lageru (broja delova) obavezno ih inicijalizovati u konstruktoru klase
ako broj preostalih delova padne na vrednost ispod 1, onda poslati dojave svim klijentima da je nestao taj deo
Na klijentu uraditi sledee: - za polaznu taku izabrati kod klijenta iz prethodnog primer (Finance_clt.cpp) promeniti ime datoteke u AssemblyLine_clt.cpp) - izbaciti klasu (i njene metode) koja implementira interfejs ITransferCallback iz prethodnog primera i umesto nje ubaciti klasu koja implmenetira interfejs IAssemblyCallback - prepraviti sve pozive i tipove u main metodi svuda staviti odgovarajua imena namespace-ova i klasi - napraviti beskonanu petlju koja uzima delove iz skladita (tj. poziva metodu GetPart na serveru) u petlju ubaciti Sleep od 10 sekundi Na klijentu za b) uraditi sledee: - napraviti novi projekat, prevesti IDL i ukljuiti skeleton u projekat - za polaznu taku iskoristiti klijenta iz prethodnog primera - prepraviti jedninu metodu callback interfejsa da pored ispisa imena metode uradi i slanje delova odgovarajueg tipa preko metode PutPart poslati proizvoljan broj delova. Prilog B sadri kod servera i klijenata za a) i b). Dodatni klijent pod c) uraditi samostalno.
<< "naming service." << endl; return 0; } catch(CORBA::SystemException&) { cerr << "Caught a CORBA::SystemException while using the naming service." << endl; return 0; } return 1; }
static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb, char* pcContext, char* pcName) { CosNaming::NamingContext_var rootContext; try { CORBA::Object_var obj = orb->resolve_initial_references("NameService"); rootContext = CosNaming::NamingContext::_narrow(obj); if( CORBA::is_nil(rootContext) ) { cerr << "Failed to narrow the root naming context." << endl; return CORBA::Object::_nil(); } } catch(CORBA::ORB::InvalidName& ex) { cerr << "Service required is invalid [does not exist]." << endl; return CORBA::Object::_nil(); } // Create a name object, containing the name test/context: CosNaming::Name name; name.length(2); name[0].id = (const char*) pcContext; // string copied name[0].kind = (const char*) "my_context"; // string copied name[1].id = (const char*) pcName; name[1].kind = (const char*) "Object"; try { return rootContext->resolve(name); } catch(CosNaming::NamingContext::NotFound& ex) { cerr << "Context not found." << endl; } catch(CORBA::COMM_FAILURE& ex) { cerr << "Caught system exception COMM_FAILURE -- unable to contact the " << "naming service." << endl; } catch(CORBA::SystemException&) { cerr << "Caught a CORBA::SystemException while using the naming service." << endl; } return CORBA::Object::_nil(); }
class VehicleFactory_IWarehouse_i: public POA_VehicleFactory::IWarehouse { private: // brojaci preostalih delova int nBodies; int nWheels; int nMotors; // skladiste callback objekata CallbackVector m_vCallbacks; void NotifyClients(EPart eType); public: VehicleFactory_IWarehouse_i(); virtual ~VehicleFactory_IWarehouse_i(); // methods corresponding to defined IDL attributes and operations void GetPart(VehicleFactory::EPart eType); void PutPart(VehicleFactory::EPart eType, ::CORBA::Long count); void SetCallback(VehicleFactory::IAssemblyCallback_ptr assembly); }; // konstruktor klase VehicleFactory_IWarehouse_i::VehicleFactory_IWarehouse_i(){ nBodies = 2; nWheels = 6; nMotors = 3; } VehicleFactory_IWarehouse_i::~VehicleFactory_IWarehouse_i(){ } void VehicleFactory_IWarehouse_i::GetPart(VehicleFactory::EPart eType){ cout << "Metoda GetPart - za delove tipa: " << eType << endl; switch (eType) { case E_BODY: if (nBodies > 0) nBodies--; else NotifyClients(E_BODY); break; case E_WHEEL: if (nWheels > 0) nWheels--;
else NotifyClients(E_WHEEL); break; case E_MOTOR: if (nMotors > 0) nMotors--; else NotifyClients(E_MOTOR); break; } } void VehicleFactory_IWarehouse_i::PutPart(VehicleFactory::EPart eType, ::CORBA::Long count){ cout << "Metoda PutPart - za delove tipa: " << eType << endl; cout << " - primljeno ukupno " << count << " delova." << endl; switch (eType) { case E_BODY: nBodies += count; break; case E_WHEEL: nWheels += count; break; case E_MOTOR: nMotors += count; break; } } void VehicleFactory_IWarehouse_i::SetCallback(VehicleFactory::IAssemblyCallback_ptr assembly){ cout << "Metoda SetCallback." << endl; m_vCallbacks.push_back(VehicleFactory::IAssemblyCallback::_duplicate(assembly )); } void VehicleFactory_IWarehouse_i::NotifyClients(EPart eType) { cout << "Slanje obavestenja da nema vise delova tipa: " << eType << endl; for (int i = 0; i < m_vCallbacks.size(); i++) { // mora try-catch zbog visecih callback objekata try { m_vCallbacks[i]->NoParts(eType); } catch (...) { } } }
int main(int argc, char** argv) { try { // Inicijalizacija CORBA-e CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); // pristup POA-i CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
// Kreiranje CORBA objekta u memoriji sa operatorom new VehicleFactory_IWarehouse_i* myVehicleFactory_IWarehouse_i = new VehicleFactory_IWarehouse_i(); // Aktiviranje CORBA objekta na POA-i PortableServer::ObjectId_var myVehicleFactory_IWarehouse_iid = poa>activate_object(myVehicleFactory_IWarehouse_i); // Registrovanje CORBA objekta na omniNames-u { CORBA::Object_var ref = myVehicleFactory_IWarehouse_i->_this(); bindObjectToName(orb, ref, "VehicleFactory", "IWarehouse"); } // Pokretanje POA-e - od ovog trenutka CORBA servanti primaju pozive PortableServer::POAManager_var pman = poa->the_POAManager(); pman->activate(); orb->run(); orb->destroy(); } catch(CORBA::TRANSIENT&) { cerr << "Caught system exception TRANSIENT -- unable to contact the " << "server." << endl; } catch(CORBA::SystemException& ex) { cerr << "Caught a CORBA::" << ex._name() << endl; } catch(CORBA::Exception& ex) { cerr << "Caught CORBA::Exception: " << ex._name() << endl; } catch(omniORB::fatalException& fe) { cerr << "Caught omniORB::fatalException:" << endl; cerr << " file: " << fe.file() << endl; cerr << " line: " << fe.line() << endl; cerr << " mesg: " << fe.errmsg() << endl; } return 0; }
using namespace std; // klasa koja implementira callback interfejs IAssemblyCallback class VehicleFactory_IAssemblyCallback_i: public POA_VehicleFactory::IAssemblyCallback { private: public: VehicleFactory_IAssemblyCallback_i(); virtual ~VehicleFactory_IAssemblyCallback_i(); // implementacija metoda (callback) interfejsa void NoParts(VehicleFactory::EPart eType); }; VehicleFactory_IAssemblyCallback_i::VehicleFactory_IAssemblyCallback_i(){ } VehicleFactory_IAssemblyCallback_i::~VehicleFactory_IAssemblyCallback_i(){ } void VehicleFactory_IAssemblyCallback_i::NoParts(VehicleFactory::EPart eType){ cout << "Callback metoda NoParts." << endl; }
////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { try { // inicijalizacija CORBA-e CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); // pristup POA-i CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); // pokretanje POA-e PortableServer::POAManager_var pman = poa->the_POAManager(); pman->activate(); // pristup serveru, tj. uzimanje reference CORBA::Object_var trobj = getObjectReference(orb, "VehicleFactory", "IWarehouse"); VehicleFactory::IWarehouse_var dref = VehicleFactory::IWarehouse::_narrow(trobj); if( CORBA::is_nil(dref) ) { cerr << "Can't narrow reference to type IWarehouse (or it was nil)." << endl; return 1; } // kreiranje i slanje callback objekta na server VehicleFactory_IAssemblyCallback_i* myVehicleFactory_IAssemblyCallback_i = new VehicleFactory_IAssemblyCallback_i(); PortableServer::ObjectId_var myVehicleFactory_IAssemblyCallback_iid = poa>activate_object(myVehicleFactory_IAssemblyCallback_i); dref->SetCallback(myVehicleFactory_IAssemblyCallback_i->_this()); // preuzimanje delova svakih 10 sekundi while (true) { try
{ dref->GetPart(E_BODY); dref->GetPart(E_MOTOR); for (int i=0; i<4; i++) dref->GetPart(E_WHEEL); Sleep(10000); } catch (...) { ; } } orb->run(); orb->destroy(); } catch(CORBA::TRANSIENT&) { cerr << "Caught system exception TRANSIENT -- unable to contact the " << "server." << endl; } catch(CORBA::SystemException& ex) { cerr << "Caught a CORBA::" << ex._name() << endl; } catch(CORBA::Exception& ex) { cerr << "Caught CORBA::Exception: " << ex._name() << endl; } catch(omniORB::fatalException& fe) { cerr << "Caught omniORB::fatalException:" << endl; cerr << " file: " << fe.file() << endl; cerr << " line: " << fe.line() << endl; cerr << " mesg: " << fe.errmsg() << endl; } return 0; }
static bool bNoMotorsLeft = false; static bool bNoWheelsLeft = false; // klasa koja implementira callback interfejs IAssemblyCallback class VehicleFactory_IAssemblyCallback_i: public POA_VehicleFactory::IAssemblyCallback { private: public: VehicleFactory_IAssemblyCallback_i(); virtual ~VehicleFactory_IAssemblyCallback_i(); // implementacija metoda (callback) interfejsa void NoParts(VehicleFactory::EPart eType); }; VehicleFactory_IAssemblyCallback_i::VehicleFactory_IAssemblyCallback_i(){ } VehicleFactory_IAssemblyCallback_i::~VehicleFactory_IAssemblyCallback_i(){ } void VehicleFactory_IAssemblyCallback_i::NoParts(VehicleFactory::EPart eType){ cout << "Callback metoda NoParts." << endl; switch (eType) { case E_BODY: bNoBodiesLeft = true; break; case E_WHEEL: bNoWheelsLeft = true; break; case E_MOTOR: bNoMotorsLeft = true; break; } }
////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { try { // inicijalizacija CORBA-e CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); // pristup POA-i CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); // pokretanje POA-e PortableServer::POAManager_var pman = poa->the_POAManager(); pman->activate(); // pristup serveru, tj. uzimanje reference CORBA::Object_var trobj = getObjectReference(orb, "VehicleFactory", "IWarehouse"); VehicleFactory::IWarehouse_var dref = VehicleFactory::IWarehouse::_narrow(trobj); if( CORBA::is_nil(dref) ) { cerr << "Can't narrow reference to type IWarehouse (or it was nil)." << endl; return 1;
} // kreiranje i slanje callback objekta na server VehicleFactory_IAssemblyCallback_i* myVehicleFactory_IAssemblyCallback_i = new VehicleFactory_IAssemblyCallback_i(); PortableServer::ObjectId_var myVehicleFactory_IAssemblyCallback_iid = poa>activate_object(myVehicleFactory_IAssemblyCallback_i); dref->SetCallback(myVehicleFactory_IAssemblyCallback_i->_this()); while (true) { if (bNoBodiesLeft) { dref->PutPart(E_BODY, 5); bNoBodiesLeft = false; } if (bNoMotorsLeft) { dref->PutPart(E_MOTOR, 15); bNoMotorsLeft = false; } if (bNoWheelsLeft) { dref->PutPart(E_WHEEL, 3); bNoWheelsLeft = false; } Sleep(5000); } orb->run(); orb->destroy(); } catch(CORBA::TRANSIENT&) { cerr << "Caught system exception TRANSIENT -- unable to contact the " << "server." << endl; } catch(CORBA::SystemException& ex) { cerr << "Caught a CORBA::" << ex._name() << endl; } catch(CORBA::Exception& ex) { cerr << "Caught CORBA::Exception: " << ex._name() << endl; } catch(omniORB::fatalException& fe) { cerr << "Caught omniORB::fatalException:" << endl; cerr << " file: " << fe.file() << endl; cerr << " line: " << fe.line() << endl; cerr << " mesg: " << fe.errmsg() << endl; } return 0; }