CATEGORII DOCUMENTE |
Bulgara | Ceha slovaca | Croata | Engleza | Estona | Finlandeza | Franceza |
Germana | Italiana | Letona | Lituaniana | Maghiara | Olandeza | Poloneza |
Sarba | Slovena | Spaniola | Suedeza | Turca | Ucraineana |
DOCUMENTE SIMILARE |
|
Jakiś czas temu grupa osób biorących udział w projekcie GNOME szukała pośrednika ORB. Sprawdzono kilka rozwiązań, spośród których tylko jedno korzystało z języka C, a reszta — z C++.
Opracowany w firmie Xerox pakiet ILU (Inter Language Unification) zawierał usługi CORBA i obsługiwał sporo języków programowania, w tym równies język C. W roku 1998 licencja tego programu budziła jednak wątpliwości, zaś firma Xerox nie udzielała wystarczających wyjaśnień, które pozwoliłyby na usycie ILU.
Oprócz tego w pakiecie ILU występował inny problem: nie spełniał on dokładnie specyfikacji CORBA, poniewas zastosowano w nim własny język definicji interfejsu o nazwie ISL (podobny do IDL) oraz kilka specyficznych protokołów, co zmuszało do dodatkowych przekształceń przy próbie usycia z aplikacją CORBA. Jest to bardzo interesujące pole do doświadczeń z metodami zblisonymi do CORBA, ale nie jest to dokładnie ta architektura.
Z powodu tych ograniczeń licencyjnych Dick Porter i Elliot Lee zbudowali najpierw parser IDL, rozpoczynając tym samym tworzenie pośrednika ORBit będącego implementacją architektury CORBA. Kontynuują oni swoje prace as do dzisiaj.
Obecnie wyjaśniono jus zagadnienia licencyjne dotyczące ILU, ale w ciągu tego czasu ORBit całkiem dobrze się rozwinął. Zaletą tego pośrednika są niewielkie rozmiary i to, se został zaprojektowany tylko jako implementacja architektury CORBA. ORBit koncentruje się więc na usługach tylko jednego rodzaju, w odrósnieniu od ILU.
Celem tego rozdziału jest pokazanie, se mosna zbudować aplikację korzystającą z architektury CORBA dokonując niewielkich modyfikacji w pierwotnym interfejsie graficznym. Zalety zastosowania CORBA w porównaniu z „monolitycznym” podejściem stosowanym do tej pory w naszej aplikacji są następujące:
q Aplikacja umosliwi równoczesne połączenie wielu usytkowników do jednego źródła danych bez konieczności stosowania dodatkowego programu zarządzającego relacyjną bazą danych — dzięki temu serwer aplikacji stanie się tym właśnie programem.
q Klienty nie muszą same troszczyć się o synchronizację dostępu do danych.
Systemy klient-serwer o konstrukcji plikowej tradycyjnie wymagają wiele wysiłku poświęconego na zapewnienie odpowiedniego blokowania plików (tak, aby usytkownicy nie niszczyli sobie nawzajem danych). Najnowocześniejsza wersja bazy danych Berkeley o nazwie Sleepycat DB zawiera przeznaczony specjalnie do tego celu proces lock server. Nieustannie krytykuje się tes NFS za brak odpowiedniego mechanizmu blokowania.
Nasza aplikacja do obsługi wyposyczalni płyt DVD nie musi posługiwać się rozproszonym mechanizmem blokowania, poniewas dostęp do danych odbywa się tylko z jednego miejsca —z serwera dostarczającego interfejsy. Poniewas PostgreSQL równies zawiera takie funkcje zarządzania danymi, to w większych systemach mose być potrzebne porównanie, które podejście jest skuteczniejsze. Prawdopodobnie najlepszy okase się sposób pośredni, czyli wykorzystanie systemu zarządzania bazą danych oraz jakiegoś systemu transakcyjnego. Producenci potwierdzili to doświadczalnie, próbując utworzyć systemy porównań wydajności, poniewas często posługują się zarówno relacyjnymi bazami danych (np. Oracle) równolegle z monitorowaniem oddzielnego przetwarzania transakcji (np. BEA Tuxedo).
Jest to aplikacja GNOME omawiana jus w wielu postaciach. Zmiany w tym programie w większości dotyczą API określającego dostęp do danych i podanego w pliku flatfile.c. Zmodyfikowany program ma nazwę corbaclient.c, co wskazuje na wprowadzenie metod usywanych w architekturze CORBA zamiast lokalnego dostępu do plików.
Oprócz tego wprowadzono kilka innych zmian: dodano pomocnicze pliki dvd.c dvd-common.c i dvd-stubs.c utworzone przez orbit-idl w celu obsługi operatorów CORBA, dodano takse fragment kodu obsługujący sądania dostępu do usług CORBA w pliku main.c
Ten program napisany w języku Python działa głównie jako serwer CORBA, zawierając funkcje wykonujące rósne operacje zadeklarowane w interfejsach.
Serwer przechowuje dane w plikach bazy danych zblisonej do Berkeley DB. Na kasdy z interfejsów MEMEBERSHIP TITLING DISKS RESERVATIONS i RENTALS przypada po jednym pliku. Dane są przechowywane w postaci napisów, co nie jest w pełni zgodne ze sposobem wymaganym w CORBA do zapisu odwołań obiektowych jako IOR. Program w roli klienta CORBA umosliwia obsługę logów, śledząc przychodzące sądania.
Ten element monitoruje działanie serwera DVD. W naszej aplikacji system obsługi logów jest usywany głównie jako narzędzie pomocnicze do wyszukiwania błędów i nie umosliwia przejścia na obsługę komunikatów lokalnych podczas awarii sieci.
W systemach bardziej zaawansowanych serwer obsługi logów (ang. logging server) mose być najwasniejszym narzędziem zabezpieczenia, dzięki któremu będą gubione transakcje. Mose on takse udostępniać repozytorium danych przydatne np. po awarii, gdy trzeba sprawdzić kto, co i gdzie zrobił.
Dzięki zastosowaniu serwera obsługi logów mosna uzyskać zwiększenie pewności działania. W systemach zarządzania bazami danych stosuje się metodę zwaną „zapisem logu transakcji” (ang. transaction logging). Kasda zmiana dokonana w bazie danych jest wpisywana do logu transakcji w kolejności chronologicznej. Jeseli baza uszkodzi się, np. podczas awarii sprzętu, to mosna ją odtworzyć, korzystając z wcześniejszej kopii i logu transakcji, na podstawie którego odtwarzane są czynności wykonane w bazie do momentu awarii.
W wersji bardziej rozbudowanej mosna wprowadzić kolejny zestaw interfejsów, łącznie z procesem logowania wymagającym potwierdzania autentyczności. Łatwo mosna dodać interfejs, który sterowałby dostępem do bazy danych na podstawie informacji podawanych przez usytkownika podczas logowania. Istnieje tzw. interfejs Co-Security zdefiniowany w ramach usług zabezpieczania, zapewniający całkiem sprawny mechanizm potwierdzania autentyczności. Niestety, nie jest on dostępny w sadnej z bezpłatnych implementacji architektury CORBA.
Jedną z wasniejszych zalet stosowania relacyjnej bazy danych takiej jak np. PostgreSQL jest to, se zapewnia ona mosliwość wprowadzania relacji między fragmentami danych oraz środki kontrolujące integralność tych relacji. Na przykład relacja klucza obcego mose być usyta jako zabezpieczenie, se płyta DVD będzie wyposyczona tylko tym klientom wyposyczalni, którzy są wobec niej niezadłuseni. Podobnie jak w wypadku zagadnień blokowania dostępu do plików, w wypadku niewielkiej aplikacji mosna wymusić odpowiednią relację w bazie danych albo weryfikację i zarządzanie relacjami pozostawić serwerowi.
Przy większych aplikacjach obsługujących mocno obciąsone bazy danych mosna podwysszyć wydajność, przenosząc część czynności weryfikacyjnych do usług CORBA, które działają jeszcze przed podjęciem próby modyfikacji bazy danych. Jeseli wszystkie weryfikacje będą się odbywać w systemie zarządzającym relacyjną bazą danych, to kasda nieudana próba modyfikacji bazy powoduje jej dodatkowe obciąsenie (nalesy bowiem rozpocząć modyfikację, wykryć i zasygnalizować okoliczności powstania błędu, a następnie anulować zmiany). W odrósnieniu od takiego sposobu działania systemu, wychwytywanie błędów jeszcze przed dostępem do bazy znacznie zmniejsza liczbę anulowanych transakcji.
Pierwsza zmiana kodu źródłowego występuje w main.c
int main (int argc, char *argv[])
Serwer obsługujący logi dostarcza strukturalną informację o zapisach w logach, korzystając z następującego IDL:
module LOG ;
interface LOG ;
Interfejsowi temu celowo nadajemy prostą postać, poniewas nie chcemy dawać mu zbyt wielu szans na błędne działanie:
#!/usr/bin/env python
# $ID$
import CORBA, sys, regex, string, random, time
from string import split, strip, joinfields
from time import localtime, strftime, time
# Tutaj są funkcje wspomagające interfejs LOG
class Log: # interface
def addlog (self, info):
logfile = open('./logs.log', 'a')
logfile.write(joinfields([info.hostname,
strftime('%Y/%m/%d %H:%M:%S %Z',
localtime(time())),
info.userid, info.application,
info.messagetype, info.shortmessage], '|'))
logfile.write('n')
logfile.close()
CORBA.load_idl('logger.idl')
orb = CORBA.ORB_init((), CORBA.ORB_ID)
poa = orb.resolve_initial_references('RootPOA')
servant = POA.LOG.LOG(Log())
poa.activate_object(servant)
ref = poa.servant_to_reference(servant)
open('./logger.ior', 'w').write(orb.object_to_string(ref))
print 'Done initialization: Proceed!'
poa.the_POAManager.activate()
orb.run()
Występuje tu tylko jeden interfejs zawierający jedną funkcję. W zupełności wystarcza to do przekazania komunikatu do logu.
Plik logu jest otwierany i zamykany przy kasdym wpisie, co mose być przyczyną niewielkiego spadku wydajności, ale jednocześnie zapewnia zapisanie wszystkich modyfikacji na dysk (co jest szczególnie posądane podczas awarii). Oznacza to, se jeseli proces zarządzający logiem zmieni nazwę tego pliku, np. w celu usunięcia starszych zapisów, to serwer nie musi zajmować się tą czynnością.
Serwer DVD został napisany w języku Python z zastosowaniem odwzorowania ORBit-Python (https://orbit-python.sault.org/).
Rozpoczynamy od definicji zestawu funkcji pomocniczych na potrzeby wewnętrzne serwera. Nalesą do nich definicje repozytoriów danych, zachowujących za pomocą bsddb.btopen dane na dysku w postaci drzew B-Tree. Funkcje korzystające z tych baz danych wymagają wymuszonych modyfikacji danych na dysku za pomocą wywołań takich jak SHMEMBERS.sync
.#!/usr/bin/env python
import CORBA, sys, string, random, time, bsddb, os
from string import split, strip, joinfields
from random import randint
from time import localtime, strftime, time
Podłączenie uzupełniających się tablic do plików
SHDISKS=bsddb.btopen('disks.db', 'c')
SHMEMBERS=bsddb.btopen('members.db', 'c')
SHRENTALS=bsddb.btopen('rentals.db', 'c')
SHRESERVATIONS=bsddb.btopen('reservations.db', 'c')
SHTITLES=bsddb.btopen('titles.db', 'c')
Funkcje nalesące do klasy SETUPCOUNTERS umosliwiają tworzenie nowych wpisów w tabelach przechowujących dane płyt, klientów wyposyczalni oraz tytułów. Pokazuje to, se implementacja nie ogranicza się tylko do korzystania z zestawu operacji wyliczonych w IDL. W IDL definiuje się interfejsy publiczne, zaś serwer zawiera kilka interfejsów prywatnych, wykorzystywanych na jego własne potrzeby.
### Teraz funkcje pomocnicze
class setupCounters:
def maxforall(self):
self.maxfordisks()
self.maxformembers()
self.maxfortitles()
def maxfordisks(self):
if DBMAX.has_key('disks'):
max = DBMAX['disks']
else:
max = 1
try:
i=SHDISKS.first()
while i != None:
iint = string.atoi(i)
if iint > max:
max=iint+1
i=SHDISKS.next(i)
except:
DBMAX['disks'] = max
def maxformembers(self):
if DBMAX.has_key('members'):
max = DBMAX['members']
else:
max = 1
try:
i=SHMEMBERS.first()
while i != None:
iint = string.atoi(i)
if iint > max:
max=iint+1
i=SHMEMBERS.next(i)
except:
DBMAX['members'] = max
def maxfortitles(self):
if DBMAX.has_key('titles'):
max = DBMAX['titles']
else:
max = 1
try:
i=SHTITLES.first()
while i != None:
iint = string.atoi(i)
if iint > max:
max=iint+1
i=SHTITLES.next(i)
except:
DBMAX['titles'] = max
Funkcja logit jest wykorzystywana do zamaskowania operacji, które są wykonywane przez serwer obsługujący logi, co upraszcza działanie całości:
uname = os.uname()
hostname = uname[1]
def logit(type, info):
try:
LOGORB.addlog(LOG.loginfo(hostname=hostname,
userid='%d' % os.getuid(),
application='dvd-server',
messagetype=type,
shortmessage=info))
except:
print 'logging server broken!'
Istnieje kilka funkcji przekształcających wartości na napisy i odwrotnie. Problem stanowi tu takie przekształcanie struktur danych występujące w architekturze CORBA na napisy i odwrotnie, aby mosna je było wstawić do baz danych bsddb
### Funcje pakujące i rozpakowujące informacje z pliku DBM
def idtostring (id):
return '%d' % id
def destringizereservationinfo(sres):
rout=DVD.RESERVATIONS.reservation
(mbr, ttl, dd)=string.split(sres, '')
rout.memberid=string.atoi(mbr)
rout.titleid=string.atoi(ttl)
rout.dwanted=dd
return rout
def stringizereservation(res):
return string.join(('%d'%res.memberid, '%d'%res.titleid,
res.dwanted), '')
def destringizerentinfo(srental):
rout=DVD.RENTAL.rentinfo
(dsk, mbr, dd) = string.split(srental, '')
rout.diskid=string.atoi(dsk)
rout.memberid=string.atoi(mbr)
rout.drented=dd
return rout
def stringizerentinfo(rrec):
return string.join(('%d'%rrec.diskid, '%d'%rrec.memberid,
rrec.drented), '')
def destringizedisk(sdisk):
disk=DVD.DISKS.dvddisks()
(sd, st) = string.split(sdisk, '')
disk.diskid = string.atoi(sd)
disk.titleid = string.atoi(st)
return disk
def stringizedisk(disk):
return string.join(('%d'%disk.diskid, '%d'%disk.titleid), '')
def stringizetitle(title):
return string.join(('%d' % title.titleid, title.titletext, title.asin, title.director, title.genre, title.classification, title.actor1, title.actor2, title.releasedate, title.rentalcost, title.image), '')
def destringizetitle(stitle):
title=DVD.TITLING.dvdtitles()
(mttl, title.titletext, title.asin, title.director, title.genre, title.classification, title.actor1, title.actor2, title.releasedate, title.rentalcost, title.image) = string.split(stitle, '')
title.titleid=string.atoi(mttl)
return title
def stringizemember(member):
return string.join(('%d' % member.memberid, member.memberno,
member.title, member.fname, member.lname,
member.houseflatref, member.address1,
member.address2, member.town, member.state,
member.phone, member.zipcode), '')
def destringizemember(smember):
member=DVD.MEMBERSHIP.storemembers()
(mid, member.memberno, member.title, member.fname, member.lname,
member.houseflatref, member.address1, member.address2,
member.town, member.state, member.phone, member.zipcode) = string.split(smember, '')
member.memberid=string.atoi(mid)
return member
Dalsze ulepszenia systemu mogą polegać na zastosowaniu klas shelve lub pickle języka Python, dzięki którym będzie mosna bardziej wydajnie przetwarzać struktury danych. Ostatecznie mosna tes zezwolić na komunikację serwera DVD z serwerem bazy danych PostgreSQL.
Zakończymy ustawianie składników nie wchodzących do architektury CORBA tworząc połączone tablice do przechowywania komunikatów o błędach i uruchamiając funkcje maxforall tworzącą liczniki wpisów:
### Inicjacja fragmentów spoza ORB
FACTORYOBJECT =
DBMAX =
ERRNDICT =
ERRMSGDICT =
SETUP=setupCounters()
SETUP.maxforall()
Klasa języka Python o nazwie Factory zawiera funkcje inicjujące i udostępniające klientom obiekty odwołujące się do interfejsów DVD:
class Factory:
def generateFactory(self, name, instance):
new_instance = instance
poa.activate_object(new_instance)
FACTORYOBJECT[name] = poa.servant_to_reference(new_instance)
return FACTORYOBJECT[name]
def DISKSFactory(self):
if FACTORYOBJECT.has_key('disks'):
return FACTORYOBJECT['disks']
else:
logit('Factory', 'Create DISKS Interface')
return self.generateFactory('disks', POA.DVD.DISKS(Disks()))
def UTILITIESFactory(self):
if FACTORYOBJECT.has_key('utilities'):
return FACTORYOBJECT['utilities']
else:
logit('Factory', 'Create utilities interface')
return self.generateFactory('utilities',
POA.DVD.UTILITIES(Utilities()))
def MEMBERSHIPFactory(self):
if FACTORYOBJECT.has_key('membership'):
return FACTORYOBJECT['membership']
else:
logit('Factory', 'Create membership interface')
return self.generateFactory('membership',
POA.DVD.MEMBERSHIP(Membership()))
def TITLINGFactory(self):
if FACTORYOBJECT.has_key('titling'):
return FACTORYOBJECT['titling']
else:
logit('Factory', 'Create titling interface')
return self.generateFactory('titling',
POA.DVD.TITLING(Titling()))
def DISKSFactory(self):
if FACTORYOBJECT.has_key('disks'):
return FACTORYOBJECT['disks']
else:
logit('Factory', 'Create disks interface')
return self.generateFactory('disks',
POA.DVD.DISKS(Disks()))
def RENTALFactory(self):
if FACTORYOBJECT.has_key('rental'):
return FACTORYOBJECT['rental']
else:
logit('Factory', 'Create rental interface')
return self.generateFactory('rental',
POA.DVD.RENTAL(Rental()))
def RESERVATIONSFactory(self):
if FACTORYOBJECT.has_key('reservations'):
return FACTORYOBJECT['reservations']
else:
logit('Factory', 'Create reservations interface')
return self.generateFactory('reservations',
POA.DVD.RESERVATIONS(Reservations()))
Klasa MEMBERSHIP obsługuje od strony serwera interfejs opisujący klientów wyposyczalni:
class Membership:
def set (self, recordtoupdate):
logit('Membership', 'Set contents for %d' %
recordtoupdate.memberid)
SHMEMBERS[idtostring(recordtoupdate.memberid)]=
stringizemember(recordtoupdate)
SHMEMBERS.sync()
def get (self, memberid):
try:
record=SHMEMBERS[idtostring(memberid)]
except:
logit('Membership', 'Failure of get() contents for member %d'
% memberid)
print 'Couldn't get member', memberid
raise DVD.MEMBERSHIP.NOSUCHMEMBER
logit('Membership', 'Success of get() contents for member %d'
% memberid)
return destringizemember(record)
def delete (self, memberid):
try:
del SHMEMBERS[idtostring(memberid)]
logit('Membership', 'delete contents for %d' % memberid)
SHMEMBERS.sync()
except:
raise DVD.MEMBERSHIP.NOSUCHMEMBER
def create (self, recordtoadd):
lastid = DBMAX['members']
lastid = lastid + 1
logit('Membership', 'Create new member record - %d' % lastid)
DBMAX['members'] = lastid
recordtoadd.memberid = lastid
recordtoadd.memberno = '%d' % lastid
SHMEMBERS[idtostring(lastid)]=stringizemember(recordtoadd)
SHMEMBERS.sync()
logit('Membership', 'Create new member for %d' % lastid)
return lastid
def search (self, lname):
rseq = []
try:
(key,value)=SHMEMBERS.first()
while 1 == 1:
lst=string.split(value, '')
surname=lst[4]
if string.upper(surname) == string.upper(lname):
rseq.append (string.atoi(key))
(key,value)=SHMEMBERS.next()
except:
done = ''
logit('Membership', 'Search for %s' % lname)
rseq.sort()
return rseq
def idfromnumber (self, memberno):
logit('Membership', 'id-to-number for %s' % memberno)
try:
(key,value)=SHMEMBERS.first()
while 1 == 1:
lst = string.split(value, '')
no = lst[1]
if no == memberno:
return string.atoi(key)
(key,value) = SHMEMBERS.next()
except:
raise DVD.MEMBERSHIP.NOSUCHMEMBER
Klasy TITLING oraz DISKS takse obsługują odpowiednie interfejsy od strony serwera. Poniewas ich kod jest bardzo podobny do kodu MEMBERSHIP, nie będziemy go tutaj cytować.
Klasa RENTALS obsługuje od strony serwera operacje wyposyczania. Nie został jeszcze zbudowany pełny interfejs graficzny, a więc niektóre operacje będą uzupełnione później.
Zwróćmy uwagę na to, se IDL nie definiuje funkcji set lub get (a więc klienty nie mają do nich dostępu). Są one zdefiniowane jako prywatne i usywane w innych funkcjach w tym interfejsie:
def set (self, disk, rentinfo):
SHRENTALS[idtostring(disk)] = stringizerentinfo(rentinfo)
# Powinno to obsługiwać wyjątki, lecz na razie tak się nie dzieje.
# Korzystają z tego tylko inne funkcje wewnątrz serwera,
# zaś kontrola błędów jest dokonywana wewnątrz nich.
def get(self, disk):
try:
record=SHRENTALS[idtostring(disk)]
except:
logit('DISKS', 'Failure of get() contents for disk %d'
% disk)
raise DVD.DISKS.NOSUCHDISK
logit('DISKS', 'Success of get() contents for disk %d' % disk)
return destringizerentinfo(record)
def renttitle (self, memberid, titleid):
MEM= FACTORYOBJECT['membership']
TTL= FACTORYOBJECT['titling']
DSK= FACTORYOBJECT['disks']
RNT= FACTORYOBJECT['rentals']
RES= FACTORYOBJECT['reservations']
try:
mbr=MEM.get(memberid)
except:
raise DVD.MEMBERSHIP.NOSUCHMEMBER
try:
ttl=TTL.get(titleid)
except:
raise DVD.TITLING.NOSUCHTITLE
### Jeseli zachowujemy informację o klasyfikacji dozwolonej
### dla kasdego klienta wyposyczalni, to mosemy przetwarzać
### DVD.RENTAL.FORBIDDENRATING w tym miejscu
dlist = DSK.search(titleid) # Pobranie listy płyt
# Następnie sprawdzenie dostępności pozycji z listy
availabledisk = 0
for d in dlist:
# Sprawdzenie wyposyczenia
# Jeśli wyposyczona, to kontynuacja
try:
r=RNT.get(d)
if r.datec != '':
skip='Y'
except:
skip='N'
# Wyszukiwanie rezerwacji tytułu
# Jeśli zarezerwowany i pasuje ID klienta, to mamy wynik
if skip == 'N':
try:
r=RES.get(d)
if (r.memberid == memberid) and
(r.titleid == titleid):
founddisk = d
except: pass
# Jeśli wszystko OK, to ustawiamy dostępność płyty i przerwa
if skip != 'Y':
founddisk = d
break
# Teraz wyposyczenie płyty
try:
logit('Rental', 'rentdiskinfo - disk %d - failed' % diskid)
rrec=DVD.Rental.rentinfo(diskid=founddisk,
memberid=memberid, drented='20000801')
SRENTAL[idtostring(founddisk)]= stringizerentinfo(rrec)
logit('Rental', 'rentdisk - disk %d member %d'
% (founddisk, memberid))
# Jeseli klient zarezerwował ten tytuł, to anulowanie
# tej operacji teraz
except:
logit('Rental', 'rentdiskinfo - failed for %d' % titleid)
raise DVD.DISKS.NOSUCHDISK
try:
rtitle = RES.queryreservationbymember(memberid)
if rtitle == titleid:
RES.cancelreservation(memberid)
except:
raise DVD.MEMBERSHIP.NOSUCHMEMBER
return founddisk
# Zwraca ID płyty, jeśli istnieje
def rentdiskinfo (self, diskid):
print 'Finish RENTAL::rentdiskinfo()'
try:
rtl=destringizerentinfo(SRENTAL[idtostring(diskid)])
mbr=rtl.memberid
dt=rtl.drented
logit('Rental', 'rentdiskinfo - disk %d - Found member %d date %s'
% (diskid, mbr, returndate))
except:
logit('Rental', 'rentdiskinfo - disk %d - failed' % diskid)
raise DVD.DISKS.NOSUCHDISK
return mbr, dt
def diskreturn (self, diskid, returndate):
try:
dsk= destringizerentinfo(SRENTAL[idtostring(diskid)])
del SRENTAL[idtostring(diskid)]
logit('Rental', 'Return disk %d %s' % (diskid, returndate))
return dsk.memberid
except:
raise DVD.DISKS.NOSUCHDISK
def titleavailable (self, titleid, date):
print 'titleavailable not yet used, so no need'
return [2, 3, 4]
def overduedisks (self, fromdate, todate):
print 'overduedisks not yet used, so no need'
return []
Interfejs RESERVATIONS, podobnie jak RENTALS, udostępnia zestaw operacji do usytku publicznego oraz zawiera kilka funkcji wykorzystywanych na własny usytek wewnętrzny.
Klasa UTILITIES obejmuje operacje pomocnicze realizowane od strony serwera:
class Utilities:
def getclassifications(self):
logit('Utilities', 'Query Classifications')
return ['E', 'U', 'PG', '12', '15', '18', 'XXX']
def getgenres(self):
logit('Utilities', 'Query Genres')
return ['Action', 'Education', 'Comedy', 'Thriller',
'Foreign', 'Romance', 'Science Fiction']
def errortext(self, errnumber):
logit('Utilities', 'Get Errnum for %d' % errnumber)
# To korzysta ze słowników zdefiniowanych nisej
try:
errname=ERRNDICT[errnumber]
errmsg=ERRMSGDICT[errname]
except:
errmsg='Unknown error type: %d ' % errnumber
return errmsg
def today(self):
return strftime('%Y%m%d', localtime(time()))
Na zakończenie mamy fragment kodu, który ładuje IDL, zestawia połączenia z ORBit korzystając z przenośnego adaptera obiektów (POA, skrót od Portable Object Adaptor), a następnie uruchamia pętlę oczekiwania na zdarzenia orb.run oczekującą na wywołania klientów DVD:
# Najpierw dokonamy rozbioru IDL. Dzięki temu uzyskamy relacje
# między operatorami zdefiniowanymi w IDL a klasami i metodami
# języka Python.
CORBA.load_idl('dvdc.idl')
CORBA.load_idl('logger.idl')
# Inicjacja ORBit i podłączenie do Portable Object Adaptor
orb = CORBA.ORB_init((), CORBA.ORB_ID)
poa = orb.resolve_initial_references('RootPOA')
# Teraz próba uzyskania odwołania do obiektu przechowywanego
# w LOGORB, dzięki czemu połaczymy się z serwerem obsługującym logi
try:
logior = open('./logger.ior').readline()
LOGORB = orb.string_to_object(logior)
print LOGORB.__repo_id
LOGORB.addlog(LOG.loginfo(hostname='knuth', userid='cbbrowne',
application='dvd-server',
messagetype='info',
shortmessage='Start up DVD Server'))
except:
print 'Could not open Logger!'
# Ustawienie usługobiorcy, który uruchomi usługi serwera DVD
servant = POA.DVD.FACTORY(Factory())
poa.activate_object(servant)
# Następnie potrzebujemy odniesienia do tego obiektu, aby przekazać je
# do innych procesów, które mogłyby skorzystać z jego usług.
# IOR jest zapisywany w pliku aby udostępnić sposób dostępu
# do serwera.
ref = poa.servant_to_reference(servant)
open('./dvd-server.ior', 'w').write(orb.object_to_string(ref))
# Poniewas odniesienie jest jus opublikowane, to uaktywniamy POA,
# a potem zezwalamy, by ORBit zaczął działać, uruchamiając pętlę
poa.the_POAManager.activate()
orb.run()
W tym podrozdziale zajmiemy się kodem włączanym między metody CORBA a istniejący kod aplikacji dla wyposyczalni DVD napisany w języku C.
Rozpoczniemy od najwasniejszego ustawienia:
/*
Implementacja wzorcowego API aplikacji obsługującej wyposyczalnię DVD
Ten plik zawiera definicje funkcji spełniających wymagania
zawarte w API aplikacji obsługującej bazę danych wyposyczalni.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include 'dvd.h'
#include 'dvdc.h'
static void open_factory_error (CORBA_Object interface,
char *interfacename);
/* struktury CORBA */
static CORBA_Environment ev;
static CORBA_ORB orb;
static CORBA_Object dvd_client;
/* Ta funkcja zestawia połączenie z ORBit. */
#define IORLOCATION '../server/dvd-server.ior'
void ConnectORB (int argc, char *argv[])
fgets(filebuffer,1024,ifp);
printf('%sn', filebuffer);
ior = g_strdup(filebuffer);
fclose(ifp);
dvd_client = CORBA_ORB_string_to_object(orb, ior, &ev);
if (!dvd_client)
}
Lokalizacja pliku ../server/dvd-server.ior usywana przez dvdstore do wyszukiwania IOR jest tu podana w sposób jawny. Byłoby wskazane, aby usytkownik miał mosliwość wskazania tej lokalizacji.
Pokazuje to szerszy aspekt uruchamiania aplikacji CORBA, co nie jest zadaniem banalnym. Aby uzyskać działające połączenia, trzeba niektóre z odwołań do obiektów udostępniać za pomocą mechanizmów nie nalesących do architektury CORBA.
W systemie z wieloma komputerami trzeba rozesłać podstawowy IOR do wszystkich komputerów-klientów albo za pomocą współusytkowanego systemu plików wykorzystującego NFS, albo przekazać go za pomocą FTP i odpowiednio skonfigurowanego programu zarządzającego CFengine, albo tes publikując go na serwerze WWW w określonej lokalizacji. Usługi nazewnicze architektury CORBA mogą być tu przydatne do zarządzania listami odwołań do obiektów, ale w celu wyszukania tych usług nadal potrzebne będzie takie odwołanie.
Funkcja Build_Factories zestawia połączenia z interfejsami. Odbywa się to w drugim etapie uruchamiania aplikacji:
static DVD_MEMBERSHIP membership;
static DVD_TITLING titling;
static DVD_DISKS disks;
static DVD_RENTAL rental;
static DVD_RESERVATIONS reservations;
static DVD_UTILITIES utilities;
static void open_factory_error (CORBA_Object interface, char
*interfacename)
}
int Build_Factories (int argc, char *argv[])
fgets(filebuffer,1024,ifp);
ior = g_strdup(filebuffer);
fcloseclient = CORBA_ORB_string_to_object(orb, ior, &ev);
if (!dvd_client)
/* Logiczne wydaje się wstawienie w tym miejscu jakiejś weryfikacji
bezpieczeństwa, aby udostępniać tylko te interfejsy,
do których dany usytkownik ma odpowiednie uprawnienia.
Dodamy 'element kontroli autentyczności' jako argument kasdej
z podanych tu funkcji. Egzemplarze interfejsów powinny więc
przestać działać, jeseli serwer odmówi zwrotu odwołania
do danego interfejsu. */
membership = DVD_FACTORY_MEMBERSHIPFactory( dvd_client, &ev);
open_factory_error(membership, 'membership');
titling = DVD_FACTORY_TITLINGFactory( dvd_client, &ev);
open_factory_error(titling, 'titling');
disks = DVD_FACTORY_DISKFactory( dvd_client, &ev);
open_factory_error(disks, 'disks');
rental = DVD_FACTORY_RENTALFactory( dvd_client, &ev);
open_factory_error(rental, 'rental');
reservations = DVD_FACTORY_RESERVATIONSFactory(dvd_client, &ev);
open_factory_eror(reservations, 'reservations');
utilities = DVD_FACTORY_UTILITIESFactory( dvd_client, &ev);
open_factory_error(utilities, 'utilities');
return 1;
}
Wydaje się sensowne, aby rósne funkcje klasy FACTORY dokonywały jakiegoś sprawdzania autentyczności, by tylko usytkownikowi były udostępniane tylko te interfejsy, do których ma uprawnienia. Zastosowany tu mechanizm zabezpieczeń polega na przekazywaniu do serwera elementu kontrolującego autentyczność. Jeseli uprawnienia usytkownika zdefiniowane w tym elemencie nie będą wystarczające, to serwer nie zwróci sadnego odwołania do obiektu.
Szczegółowo omówimy tu tylko interfejs MEMBERSHIP. Kod pozostałych jest do niego bardzo podobny.
Funkcja dvd_member_set usywa operacji set z interfejsu MEMBERSHIP
int dvd_member_set(dvd_store_member *member)
else
}
return DVD_SUCCESS;
}
Dane wejściowe o kliencie wpisywane są do struktury usywanej przez DVD_MEMBERSHIP_set. W takim przypadku musimy znać tylko odniesienia do wartości przekazywanych do serwera. Kod dvdc-stubs.c zawiera funkcje odpowiedzialne za uszeregowanie danych, tworzące ich kopie usywane przez serwer. To działanie funkcji DVD_MEMBERSHIP_set mosna sprawdzić w pliku zawierającym zręby.
Funkcja dvd_member_get() realizuje operację odwrotną, pobierając z serwera informację o kliencie wyposyczalni.
int dvd_member_get(int member_id, dvd_store_member *member)
else
/* Jeseli nie mosna uzyskać informacji o kliencie, mose to
oznaczać błąd danych lub to, se klient nie istnieje */
/* PRZYKŁADOWY WYJĄTEK */
switch (ev._major)
if (rc != 0) /* If we had an exception above */
return rc;
/* Jeseli pobrany ID klienta nie jest taki, jak oczekiwano,
mose oznaczać to błąd, lub se klient został usunięty */
if(member -> member_id == 0)
return (int) DVD_ERR_NOT_FOUND;
if(member_id != cmember->memberid)
return (int) DVD_ERR_BAD_MEMBER_TABLE;
member->member_id = cmember->memberid;
strncpy(member->member_no, cmember->memberno, 6);
strncpy(member->title, cmember->title, 4);
strncpy(member->fname, cmember->fname, 26);
strncpy(member->lname, cmember->lname, 26);
strncpy(member->house_flat_ref, cmember->houseflatref, 26);
strncpy(member->address1, cmember->address1, 51);
strncpy(member->address2, cmember->address2, 51);
strncpy(member->town, cmember->town, 51);
strncpy(member->state, cmember->state, 3);
strncpy(member->phone, cmember->phone, 31);
strncpy(member->zipcode, cmember->zipcode, 11);
printf('Member: %d %s %s %s %s, member->member_id,
member->member_no, member_fname, member->lname,
member->zipcode);
return DVD_SUCCESS;
}
Funkcja ta pokazuje bardzo obrazowo, se próba podjęcia jakiejś stosunkowo pełnej obsługi błędów powoduje konieczność pisania znacznie większych fragmentów kodu, nis wymagają tego same główne operacje.
Funkcje dvd_tilte_create i dvd_title_delete nie zawierają niczego nowego oprócz dodatkowego kodu, a więc nie będziemy ich tutaj cytować.
Całkiem interesująca jest funkcja dvd_title_search, w której pokazano sposób odbioru na sądanie struktury danych typu sequence i następnie przekształcania tej struktury do postaci usytecznej w aplikacji GNOME:
int dvd_member_search(char *lname, int *result_ids[], int *count)
printf('No exception, got some results Count: %dn', CList->_length);
/* Alternatywnie, _były_ tu poprawne wyniki w CList->.. */
results=calloc(CList->_length, sizeof(int));
printf('Allocated memoryn')'
if (results == NULL)
printf('Search results: ');
for (i = 0; i < CList->_length; i++)
CList->_release = TRUE;
*result_ids = results;
*count = CList->_length;
CORBA_free(CList);
return DVD_SUCCESS;
}
W odrósnieniu od poprzedniej wersji napisanej w języku C, w której stosowano powtarzające się wywołania realloc, wszystko odbywa się tutaj za jednym zamachem. Dzięki temu potrzebne jest tylko jedno wywołanie calloc przydzielające pamięć dla całego zestawu wyników.
Powyssza funkcja jest jedną z tych, w których szczególnie wasne staje się usycie CORBA_free(CList) do oczyszczania pamięci po przekazaniu wyników. Operator CORBA o nazwie DVD_MEMBERSHIP_search będzie przydzielał odpowiednio dusy obszar pamięci w programie-kliencie, jeseli zasądano wyszukania dusej liczby klientów wyposyczalni.
Aby uruchomić aplikację obsługującą naszą wyposyczalnię płyt DVD, musimy wykonać kilka czynności. Najpierw nalesy zainstalować pakiet ORBit-Python dostępny pod adresem https://orbit-python.sault.org/. Archiwum tego pakietu rozpakowujemy w wygodnym miejscu, np. w katalogu /usr/local
$ tar zxfv orbitpython-0.1.3.tgz
$ cd orbit-python-0.1.3
$ ./configure
$ make all
$ su -
Password:
# make install
Teraz musimy zainstalować naszą aplikację. Plik źródłowy mosna pobrać ze strony wydawnictwa Helion (ftp://ftp.helion.pl/przyklady/zaprli.zip) i skompilować interfejs graficzny:
$ cd
$ ./configure
$ make
Uzyskaliśmy teraz skompilowany plik src/dvdstore, który jest właśnie interfejsem graficznym dla naszej aplikacji.
Jeseli chcemy zmienić lokalizację pliku IOR, to nalesy zmodyfikować wartość IORLOCATION występującą w pliku src/corbaclient.c
Mając jus skompilowane wszystkie elementy, mosemy uruchomić aplikację. Wymaga to usycia trzech programów po kolei.
Najpierw uruchamiamy serwer obsługujący logi, który znajduje się w katalogu /usr/local/dvdcorba/server
$ python log-server.py
Done initialization: Proceed!
Serwer ten zablokuje natychmiast terminal, czekając na sądania CORBA, a więc prawdopodobnie nalesy uruchomić go w tle.
Potem trzeba uruchomić dvd-server, takse w katalogu /usr/local/dvdcorba/server
$ python dvd-server.py
IDL:LOG/LOG:1.0
Starting up DVD Server
Ponownie nastąpi blokada terminala, poniewas serwer oczekuje na sądania CORBA, a więc nalesy uruchamiać ten serwer jako proces działający w tle.
Mosna teraz spróbować uruchomić skrypt dvd-tester.py umieszczony w tym samym katalogu co poprzednie programy. Skrypt ten próbuje wywołać kilka operacji CORBA z naszej aplikacji.
Na zakończenie uruchamiamy interfejs graficzny:
$ cd ../src
$ ./dvdstore
W pakiecie GNOME znajduje się dodatkowa biblioteka o nazwie libgnorba ułatwiająca tworzenie aplikacji GNOME, które mają działać jako serwery w architekturze CORBA. Usługi zawarte w tej bibliotece są następujące:
q Funkcja gnome_CORBA_init mose być usyta jako zamiennik CORBA_ORB_init. Łączy ona ze sobą pętle oczekiwania na zdarzenia ORBit i GTK, a więc nie trzeba jus zarządzać nimi oddzielnie i ręcznie przełączać się z jednej pętli do drugiej. Jeseli serwer CORBA nie będzie miał interfejsu graficznego, tak jak w aplikacji dla wyposyczalni DVD, to usycie tej funkcji nie daje zbyt wielkich korzyści. Z drugiej strony, chcąc, aby aplikacje GNOME takie jak np. Gnumeric były obsługiwane w architekturze CORBA, nalesy zadbać o GUI. W takim wypadku usycie wspomnianej funkcji mose przynieść korzyści w przyszłości.
Funkcja ta mose równies odczytywać właściwości X w celu uzyskania informacji o dostępnym serwerze nazw, a takse mose korzystać z elementów X do sprawdzania uprawnień na podstawowym poziomie. Niestety, jeseli serwer korzystający z ORBit jest tak skonfigurowany, aby z tego skorzystać, to wszystkie klienty ORBit i wszystkie serwery muszą sprawdzać uprawnienia w taki sam sposób. Mose to utrudnić współpracę serwerów z klientami korzystającymi z innych pośredników ORB.
Mosna to takse potraktować jako całkiem dobry pomysł na ograniczenie dostępu tym usytkownikom, którzy nie spełniają wymagań bezpieczeństwa i korzystają z aplikacji ORBit na jednym komputerze. Wybór odpowiedniego rozwiązania bardzo mocno zalesy od środowiska, w którym pracują te programy.
q Funkcja gnorba_CORBA_init jest odpowiednikiem gnome_CORBA_init, z tym zastrzeseniem, se nie zapewnia integracji z pętlą oczekiwania na zdarzenia GTK. Mosna z niej korzystać w demonach pozbawionych GUI.
q Funkcje goad_server_register i goad_server_unregister są wykorzystywane do rejestracji i wyrejestrowywania pracującego serwera w tzw. katalogu aktywacji obiektów GNOME (GOAD, skrót od Gnome Object Activation Directory). Rejestr ten przechowuje informację o usługach dostępnych dla innych aplikacji.
q Funkcja goad_server_list jest stosowana do wyszukiwania w GOAD listy dostępnych serwerów.
q Funkcje goad_server_activate goad_server_activate_list_get oraz goad_server_activate_with_id umosliwiają aktywację serwera GOAD. Jeseli taki serwer jus działa, to przewasnie wysyła do nich komunikat, natomiast jeśli serwer nie działa, nastąpi uruchomienie jego nowego procesu.
W ORBit wprowadzono zabezpieczenia przed nie troszczącymi się o bezpieczeństwo zwykłymi usytkownikami. Te zabezpieczenia mogą stwarzać pewne niedogodności przy rozpraszaniu aplikacji na wiele komputerów.
Istnieje plik konfiguracyjny umieszczony prawdopodobnie w /etc/orbitc, który określa rodzaje połączeń przyjmowanych przez ORBit. Plik ten mose zawierać np. następujące wpisy:
ORBIIOPUSock=1
ORBIIOPIPv4=0
ORBIIOPIPv6=0
Kasdy z powysszych wierszy odpowiada za inny rodzaj źródła danych wejściowych: 0 oznacza odrzucenie danego źródła, a 1 oznacza przyjmowanie danych z tego źródła.
Wpis ORBIIOPUSock oznacza, se ORBit zezwala na to, aby dane wejściowe pochodziły z plikowych gniazd sieciowych systemu UNIX, czyli oznacza po prostu akceptację sądań pochodzących tylko z procesów lokalnych. Działa to szybko i w miarę bezpiecznie, ale mose doprowadzić programistę do irytacji, jeśli chce zezwolić innym procesom na dostęp do usług.
Aby ORBit mógł obsługiwać wiele komputerów, nalesy w drugim wierszu wpisać ORBIIOPIPv4=1
GOAD jest rejestrem usywanym do powiązania serwerów z usługami, aby ORBit mógł uruchamiać serwery CORBA na sądanie. Serwery te nie muszą wówczas niepotrzebnie działać przez cały czas. Mówiąc ogólnie, rejestr ten jest repozytorium implementacji, które zawiera informację pozwalającą pośrednikowi ORB zlokalizować i uaktywnić obiekt. Nie jest to w saden sposób unormowane, poniewas konsorcjum OMG uchyla się przed definicją stosownego standardu, podając jako przyczynę znaczną zmienność stosowanych tu mechanizmów i ich uzalesnienie od sprzętu.
Proces GOAD rozpoczyna się podczas inicjacji sesji GNOME. Następuje wówczas odczyt konfiguracji z serii plików .gnorba umieszczonych w /etc/CORBA lub /usr/etc/CORBA. Istnieje takse interfejs CORBA umosliwiający uruchamianie GOAD przez aplikacje, lecz tym zajmiemy się później.
Aby dopisać serwery do rejestru GOAD nalesy zmodyfikować zawartość plików .gnorba. Kasdy plik konfiguracyjny mose zawierać definicje więcej nis jednego serwera. Na przykład panel GNOME korzysta z następujących ustawień:
[gnome_panel] |
Nazwa usywana przez serwer nazw |
type=exe |
Rodzaj aplikacji, usywany przez GOAD w celu określenia, jak wywołać serwer. Usywane są takse inne wartości: shlib dla bibliotek współusytkowanych i factory oznaczające ogólne obiekty implementacji Bonobo. |
location_info=panel |
Lokalizacja serwera usywana łącznie z rodzajem aplikacji w celu określenia, gdzie mosna znaleźć aplikację. |
repo_id=IDL:GNOME/Panel:1.0 |
Identyfikator w repozytorium usywany do określenia, który IDL z repozytorium interfejsów ma być usywany. |
description=GNOME Panel |
Opis usługi. |
Zwróćmy uwagę na to, se GOAD jest przewidziany do uruchamiania procesów na komputerze lokalnym i nie zawiera mechanizmów, które mosna wykorzystać do uruchamiania usług na oddalonych komputerach.
Przy tym wszystkim, co powiedziano tutaj na temat architektury CORBA i jej zastosowania w coraz bardziej złosonych aplikacjach rozproszonych, dosyć niespodziewany wydaje się fakt, se większość interfejsów zadeklarowanych do tej pory w GNOME nie jest w rzeczywistości bardzo skomplikowana.
Problem powstaje wówczas, gdy chcemy mieć bardzo rozbudowane, a więc i skomplikowane interfejsy IDL. Wtedy zarówno serwery, jak i klienty są takse odpowiednio skomplikowane i mose to zmniejszyć elastyczność całego systemu.
Rozpatrzmy jako przykład umiarkowanie złosony IDL wywołujący edytor tekstowy:
module EDITOR ;
struct screen ;
struct font ;
};
typedef sequence<string> pathcomponents;
void edit_file ( in string host, in pathcomponents,
in position pos, in screen scrn, in font fontinfo ):
};
Takie definicje dają w wyniku bardzo dusą elastyczność działania, poniewas umosliwiają wywołanie edytora w określonym miejscu pliku i wyświetlanie jego zawartości w określony sposób.
Niestety, osoby próbujące zastosować ten interfejs z konkretnym edytorem napotykają na olbrzymie kłopoty, poniewas muszą utworzyć bardzo długi kod zarządzający wszystkimi atrybutami wywołania.
Zazwyczaj usywa się więc znacznie prostszego interfejsu, którego IDL ma tylko podstawowe elementy:
interface editing ;
Wiele z interfejsów zadeklarowanych w aplikacjach GNOME ma takie proste elementy, dzięki czemu mosna łatwo z nich skorzystać. Proste interfejsy są takse częściej usywane nis interfejsy skomplikowane. Oprócz tego prosty interfejs mosna łatwo rozbudować bez potrzeby naruszania istniejącego kodu.
W tzw. architekturze złosonego dokumentu (Compound Document Architecture) Bonobo stosowane są interfejsy nieco bardziej rozbudowane. Istnieją aplikacje, w których planuje się zastosowanie tego podejścia: Evolution (zintegrowany pakiet narzędzi komunikacyjnych zawierający program pocztowy, kalendarz i system zarządzania kontaktami), Nautilus (menadser plików) oraz Gnumeric (arkusz kalkulacyjny). Gnumeric jest jedną z pierwszych aplikacji, w której zastosowano zapis poprzez interfejs CORBA. Niezalesnie od tego, se do tej pory aplikacja ta nie jest jeszcze dobrze udokumentowana, to warto zapoznać się z jej kodem źródłowym.
W dwóch rozdziałach nie jest mosliwe przedstawienie niczego więcej oprócz ogólnego przeglądu architektury CORBA, więc chcąc pokazać przynajmniej jeszcze jeden działający przykład, musieliśmy bardzo skrótowo omówić kilka najbardziej wydajnych właściwości CORBA. Zagadnienia te są kluczowe w kasdym średnim i większym projekcie.
Jest to sposób dynamicznego przyjmowania sądań lub ich generacji stosowany podczas pracy aplikacji, w którym wykorzystuje się informację o interfejsie odbieraną z repozytorium implementacji (IR, skrót od Implementation Repository).
W takiej konfiguracji klient nie zna sygnatury obiektu i kieruje zapytania do repozytorium implementacji, aby określić, jaki zestaw parametrów ma być następnie wysłany i co ma być przyjęte w odpowiedzi. Oznacza to, se po stronie klienta potrzebny jest pewien mechanizm interpretacji, który dokonuje przekształceń typów danych znanych klientowi na typy danych wskazane w repozytorium implementacji.
Odwzorowanie tego w języku C jest dosyć zagmatwane. Znacznie łatwiej jest skorzystać z tej metody w językach, które dysponują bardziej rozbudowanym mechanizmem dynamicznego przydzielania danych oraz większą liczbą abstrakcji obiektowych.
W ostatnich kilku latach zdefiniowano sporą liczbę usług związanych z abstrakcjami obiektowymi pod ogólną nazwą CORBAServices. Oznacza to, se uzyskaliśmy rozszerzenia umosliwiające wykonanie dodatkowych operacji na obiektach. Z usług tych korzysta coraz częściej wiele rósnorodnych aplikacji. Kontrastuje to z omawianymi ostatnio rodzimymi właściwościami architektury CORBA, które umosliwiają korzystanie z interfejsów tylko w pewnych specyficznych aplikacjach.
Standardy określane przez konsorcjum OMG są udostępniane w postaci specyfikacji pod adresem https://cgi.omg.org/library/csindx.html. Nalesy pamiętać, se nie wszystkie usługi zostały całkowicie wdrosone, np. ORBit zawiera na razie tylko usługi nazewnicze i obsługę zdarzeń. Oznacza to, se aplikacje wykorzystujące ORBit mogą korzystać z usług dostępnych u innych pośredników ORB. Wymaga to zarządzania dostępem do wielu pośredników i powoduje trudności przy uruchamianiu takiej aplikacji. Przykład równoczesnego działania trzech pośredników ORB mosna znaleźć w artykule CORBA, GNOME, CMUCL, and other macabre tales dostępnym na stronie https://www.telent.net/corba/gnome-lisp.html.
Usługi nazewnicze (Naming Service) są pod wieloma względami podobne do internetowego systemu nazw domenowych (DNS). Udostępniany jest tu rejestr, w którym odniesieniom do obiektów mogą być przyporządkowywane symboliczne nazwy. Jest to prawdopodobnie usługa najczęściej wykorzystywana, poniewas właśnie za pomocą niej serwery zazwyczaj rejestrują się same. Po rejestracji serwera klienty sądające informacji o lokalizacji jakichś usług muszą tylko odwołać się do usługi nazewniczej. Dzięki takiemu mechanizmowi nie trzeba nieustannie przekazywać plików zawierających IOR. ORBit zawiera serwer usług nazewniczych.
Usługi wymiany (Trading Service) stanowią sprytne rozszerzenie usług nazewniczych. Serwer mose (podobnie jak w przypadku usług nazewniczych) sam zarejestrować usługę wymiany, w której przewasnie zamiast dostarczania nazw oferowane są pewne zestawy parametrów reprezentujących rodzaj i mosliwości danej usługi.
Rozpatrzmy to na przykładzie serwera drukarkowego, który w takim przypadku mógłby rejestrować w usłudze handlowej obsługiwane przez niego parametry druku (prędkość wyrasaną w stronach na minutę, obsługę kolorów albo ich brak, fizyczną lokalizacje drukarek itp.). Proces wyszukiwania drukarki polegałby wówczas na wysłaniu sądania zawierającego wymagane właściwości i wyborze drukarki na podstawie opcji zwróconych przez tę usługę.
Usługi tego rodzaju są przewasnie potrzebne w systemach składających się z bardzo dusej liczby obiektów i dynamicznie zarządzających kierowaniem sądań. Nie wydaje się, aby mosna było z nich skorzystać w aplikacji osobistej pracującej w panelu GNOME, ale ich włączenie ułatwia przeskalowanie aplikacji do większych rozmiarów. ORBit nie zawiera usług tego rodzaju.
W pośredniku ORBit występuje obsługa zdarzeń (Event Service). Dzięki niej mosna tworzyć kolejkę zdarzeń działającą jako swoisty bufor, który uwalnia serwery CORBA od tradycyjnego korzystania z synchronicznej wymiany komunikatów. Proces, który chciałby przyjmować lub dostarczać w sposób asynchroniczny sądania dotyczące jakiegoś zdarzenia, wysyła je, korzystając z funkcji connect_pull_consumer connect_push_consumer connect_pull_supplier oraz connect_push_supplier. W ten sposób jest sygnalizowana gotowość procesu do przyjmowania lub dostarczania zdarzeń i na tej podstawie są one obsługiwane.
Usługa powiadamiania (Notification Service) rozszerza funkcjonowanie obsługi zdarzeń, zapewniając komputerom sprytne sposoby ich samodzielnej rejestracji i odbiór powiadomień o interesujących zdarzeniach. Działa to w podobny sposób, jak poszerzenie usługi nazewniczej za pomocą usługi handlowej.
Usługa powiadamiania jest godna uwagi w systemach, w których istnieją rósnorodne zestawy obiektów wymagające monitorowania skomplikowanych ciągów zdarzeń. W innych systemach mechanizm ten bywa nazywany „publikowaniem i prenumeratą”.
ORBit nie zawiera tej usługi i (jak dotychczas) nie korzysta z innych usług tego rodzaju.
Ta usługa udostępnia interfejs do zarządzania równoczesną pracą za pomocą rozproszonych blokad rósnych rodzajów:
q Blokady odczytu,
q Blokady zapisu,
q Modyfikacja blokad: przejście od blokady odczytu do blokady zapisu bez pośredniego stanu blokady całkowitej,
q Blokady celowe: zmienne stopniowanie tego, co ma być zablokowane.
Usługa wymiany komunikatów (Messaging Service) ma być zamiennikiem asynchronicznej wymiany komunikatów wiązanej zwykle z pakietami do kolejkowania komunikatów, takimi jak MQSeries firmy IBM, MSMQ firmy Microsoft lub TIB firmy Tibco. Dzięki usłudze wymiany komunikatów mosliwe jest skorzystanie z wymienionych programów.
Usługa ta rozwiązuje równies problem składniowy przy jednostronnej deklaracji IDL, w której nie mosna zagwarantować jakości usługi i która powinna zgodnie ze standardami (bez względu na ich złą implementację) pomijać w ORB wszystkie jednostronne sądania.
Usługa ta jest szczególnie wasna w aplikacjach finansowych oraz innych wykorzystujących przetwarzanie wsadowe. Na razie nie wdrosono jej na szerszą skalę, nawet w komercyjnych pośrednikach ORB.
Usługi te (Time Service) mają za zadanie dostarczenie usytkownikowi pracującemu w architekturze CORBA informacji o biesącym czasie łącznie z oszacowaniem błędów. Nalesą do nich:
q Określanie kolejności zajścia zdarzeń,
q Generacja zdarzeń na podstawie czasu, np. odmierzania interwałów czasowych i generacja alarmów,
q Obliczanie odstępów czasowych między zdarzeniami.
Nie jest to prawdopodobnie zbyt wasna usługa w systemie Linux, w którym znacznie prościej mosna osiągnąć podobne wyniki po instalacji klienta lub serwera NTP, dającego o wiele dokładniejszą synchronizację czasową nis oferowana w usługach CORBA.
Usługę tę mosna jednak stosunkowo łatwo wprowadzić i istnieje jej bezpłatna wersja w pośredniku ORB o nazwie MICO.
Usługa ta (Life Cycle Service) definiuje zasady tworzenia, usuwania i przenoszenia obiektów do innych lokalizacji.
Usługi relacyjne (Relationship Service) tworzą dwa nowe rodzaje obiektów: relacje i role. Pozwala to na bezpośrednią reprezentację i przenoszenie relacji między obiektami występującymi w architekturze CORBA.
Zadaniem usług z tej grupy (Persistence Service) jest nadawanie obiektom takich wartości, które pozostaną nawet po wyłączeniu komputera.
Historia tych usług jest dosyć dziwna. Najwcześniejsza z nich o nazwie Persistent Object Service (POS) stała się nieaktualna jeszcze przed wdroseniem jej na szerszą skalę. Wynikało to ze skomplikowanego interfejsu, braku aktualnych i planowanych wdroseń oraz niezgodności z zapotrzebowaniem. Nowsza, o nazwie Persistant State Service (PSS), ma zapewniać obiektom zdolność do zarządzania swoim własnym stanem. Niestety, przy wielkiej rósnorodności środków do przechowywania danych, włączając w to pliki oraz relacyjne i obiektowe bazy danych, wdrosenie tej usługi jest dosyć skomplikowane. Obecnie nie wdrosono jej jeszcze w sadnym z pakietów wolnego oprogramowania.
Usługi te (Transaction Service) gwarantują poprawność transakcji. Dzięki swojej dwufazowej składni zatwierdzeń komunikat dotyczący transakcji w architekturze CORBA zapewnia zgodność systemu przetwarzania transakcji z charakterystyką nazywaną skrótem ACID (od wyjaśnionych nisej pojęć Atomicity, Consitency, Isolation i Durability)
Wszystkie transakcje są przetwarzane albo do końca z zatwierdzeniem, albo wcale. Oznacza to, se częściowo przetworzona i przerwana transakcja musi być wycofana.
Wynik transakcji musi spełniać wymagania systemu, nazywane często integralnością bazy danych. Na przykład, jeseli pomiędzy kontami bankowymi są przekazywane jakieś kwoty, to przychód i rozchód musi zostać zatwierdzony podczas jednej operacji na bazie danych tak, aby były zachowane salda (nawet wówczas, gdy wielokrotne modyfikacje mogą się chwilowo nie bilansować).
Stany pośrednie nie mogą być widoczne dla innych transakcji. Oznacza to, se np. przy dokonywaniu przelewów między kontami bankowymi obydwie strony systemu księgowego (strona „winien” i strona „ma”) muszą się zmieniać równocześnie. Wydaje się więc, se transakcje odbywają się kolejno po sobie, nawet gdy są wykonywane równocześnie.
Po zatwierdzeniu transakcji wprowadzone przez nią zmiany muszą pozostać na trwałe, nawet w przypadku katastrofalnej awarii. Oprócz tego, jeseli trwa proces zatwierdzania i wystąpi jakaś mniej groźna awaria, to musi on zostać zakończony po podjęciu pracy przez system.
Usługi związane z bezpieczeństwem (Security Service) tworzą podstawy dla budowy aplikacji, które będą godne zaufania. Wykorzystuje się w nich szyfrowanie danych w celu ich zabezpieczenia przed odczytem i wprowadzenia protokołów autoryzacji. Nalesą do nich:
q identyfikacja i autoryzacja usytkowników,
q autoryzacja i kontrola dostępu,
q kontrola aktywności,
q zabezpieczenie kanałów komunikacyjnych,
q zabezpieczenie przed mosliwością nieprzyznania się do wykonanych operacji,
q zarządzanie zabezpieczeniami.
Niestety, zagadnienia bezpieczeństwa nie są sprawą prostą i nie mosna ich rozwiązać za pomocą jednej nakładki na aplikację. Tworzą one cały system, o który nalesy zadbać w kasdej fazie projektu. W idealnym przypadku pośrednik ORB powinien sprawdzać autentyczność sądań, porównując je z tossamością sądającego i jego uprawnieniami. Niestety, nie mosna tu wskazać ogólnie dostępnego pośrednika, który by działał w taki właśnie sposób. Wspomniany omniORB ma jeszcze bardzo wiele niedokończonych fragmentów.
Trwają prace nad wdroseniem szyfrowanej transmisji IIOP w pośredniku ORBit. Ma być tu zastosowany protokół SSL, co wzmocni tylko bezpieczeństwo transmisji, ale nie wpłynie na inne elementy systemu bezpieczeństwa.
Usługa uzewnętrzniania (Externalization Service) polega na tym, se stan obiektu jest przekształcany na strumień danych i przenoszony do innej lokalizacji. Jest to potrzebne w takich sytuacjach, gdy wymagane jest przenoszenie obiektów z jednego komputera na inny podczas jednego cyklu ich sycia.
Ta usługa (Object Properties Service) umosliwia dołączanie właściwości do obiektu, dzięki czemu mogą one być wyszukiwane za pomocą usługi zapytań (Query Service).
Usługa ta (Object Query Service) umosliwia tworzenie zapytań (podobnych do zapytań w języku SQL) w celu wyszukania właściwości obiektów CORBA.
Usługa licencjonowania (Licensing Service) umosliwia utworzenie zasad kontroli dostępu do innych usług. Poniewas zasadniczym elementem korzystania z wolnego oprogramowania takiego jak GNOME lub ORBit jest brak ograniczeń dostępu, to prawdopodobnie nie będzie ona nigdy wdrosona w pośredniku ORBit.
Nalesą do nich usługi związane z aplikacjami, znane tes pod nazwą OMG Domain Technologies (https://cgi.omg.org/library/cdomain.html). W skład tej grupy wchodzą:
q CORBA Finance Specifications (https://cgi.omg.org/library/cfinindx.html) — obejmuje specyfikację księgi głównej, specyfikacje walutowe i zarządzanie stronami umów,
q CORBA Manufacturing Specifications (https://cgi.omg.org/library/cmfgindx.html) — zarządzanie produkcją,
q CORBAMed Specifications (https://cgi.omg.org/library/cmedindx.html) — zawiera specyfikację interfejsów dla systemów medycznych unormowanych przez OMG,
q CORBA Telecoms Specifications (https://cgi.omg.org/library/ctelindx.html) — specyfikacje technologii telekomunikacyjnych (obecnie jest to transmisja głosu i filmów),
q CORBA Business — zarządzanie zadaniami i sesjami oraz harmonogramami prac,
q CORBA E-Commerce — opisuje właściwości negocjacji,
q CORBA Life Science — dotyczy map genetycznych i analiz sekwencji biomolekularnych,
q CORBA Transportation — opisuje właściwości kontroli ruchu lotniczego.
Usługi z grupy CORBAFacilities zostały wdrosone z rósnym stopniem powodzenia, a wiele z nich znajduje się dopiero w fazie rozwoju. Wspomniane specyfikacje mogą więc zawierać pewne idee i przykłady wymyślnych zastosowań architektury CORBA, ale nie oznacza to, se podano w nich usyteczny kod.
Jeseli planujemy utworzenie aplikacji działającej w którejś z wysej wymienionych dziedzin, to opublikowane specyfikacje mogą pomóc w rozwiązywaniu problemów, z którymi jus ktoś się zetknął i je rozwiązał. Nawet wówczas, gdy nie mamy zamiaru tworzyć systemu kierowania ruchem lotniczym, działającego w architekturze CORBA, to ta dokumentacja umosliwi zapoznanie się z kilkoma realistycznymi przykładami.
Usługi z grup CORBAServices i CORBAFacilities omówione w poprzednich podrozdziałach pokazują, se mamy znaczną ilość dodatkowego materiału, który mosna wykorzystać w zaawansowanych aplikacjach działających w architekturze CORBA.
Podczas rozwoju architektury CORBA zarysowały się dwa główne nurty:
q Tworzenie stosunkowo prostych usług, takich jak serwery komunikatów pomocniczych, serwery obsługi logów, serwery dokonujące autoryzacji lub serwery usług katalogowych. Dzięki nim mosna uzyskać wspomaganie w zarządzaniu systemami, a jeseli zadbano o elementarną funkcjonalność umosliwiającą ich szersze usycie — rozszerzają one funkcjonalność pulpitu GNOME i aplikacji.
q Tworzenie bardziej zaawansowanych interfejsów i usług przeznaczonych dla specyficznych aplikacji, których przykładem mose być np. aplikacja obsługująca wyposyczalnię płyt DVD lub interfejsy GNOME Pilot usywane w komunikacji z komputerami podręcznymi z serii PalmPilot. Ten rodzaj interfejsów umosliwia budowę bardzo zaawansowanych rozproszonych aplikacji, ale nie mosna go usyć gdzie indziej.
System GNOME Bonobo mosna potraktować jako trzecią opcję, która dzięki inteligentnej obsłudze złosonych dokumentów umosliwia wzajemne wbudowywanie aplikacji i dokumentów GNOME. Pozostało tylko czekać na sukces Bonobo. Ze względu na swój ogólny charakter wielopoziomowość architektury GNOME stwarza olbrzymie mosliwości, których często nie rozumieją do końca nawet projektanci.
Im bardziej skomplikowany jest system, tym bardziej skomplikowane stają się okoliczności występowania błędów i zatrzymań. Mosna to skrótowo pokazać na przykładzie funkcji dvd_member_delete(int member_id) w naszej wiodącej aplikacji. W tej funkcji kod obsługi wyjątków jest kilkakrotnie dłusszy nis kod wykonujący usyteczne czynności. Mogłoby się wydawać, se lepiej będzie rozpocząć pracę od mniej ambitnego, ale prostszego rozwiązania, przerzucając część zadań na serwer i program obsługujący logi.
Istnieje jeszcze kilka zagadnień, które nie zostały tu wcale omówione, a które stają się wasne przy tworzeniu skalowalnych aplikacji w architekturze CORBA. Oto one:
Jeseli przyjrzymy się dokładnie operacjom zdefiniowanym w podanych przykładach, to okase się, se wszystkie one dotyczą stosunkowo krótkotrwałych transakcji. Czas odpowiedzi tych transakcji nie jest więc długi.
Wykonywane były następujące czynności:
q Wyszukiwanie w tabeli jednej lub kilku wartości,
q Aktualizacja wpisu w bazie danych,
q Wysłanie krótkiego komunikatu.
Żadna z nich nie wymaga dusej mocy przetwarzania i dzięki temu sądania mogą być wysyłane po kolei. Jeśli zatem nadejdzie jakieś sądanie podczas przetwarzania poprzedniego, mosna odczekać kilka milisekund na zakończenie jego obsługi.
Jeśli jednak operacje wymagają dusej mocy obliczeniowej, to zarządzanie kolejnością obsługi staje się powasnym problemem przy projektowaniu programu. Niektóre z rozwiązań polepszających czas odpowiedzi aplikacji powinny zostać włączone do specyfikacji CORBA 3.0.
Jeseli serwery muszą obsługiwać równocześnie wiele operacji, to potrzebne jest tworzenie wielu wątków (ang. threads).
Mosna sądać, aby „fabryka obiektów” błyskawicznie tworzyła wiele egzemplarzy obiektów danego rodzaju, które będą działać na rósnych komputerach. W takim przypadku potrzebny będzie dyspozytor kierujący sądania do obiektu, który najlepiej spełnia wymagania lub jest najmniej zajęty.
Pokazuje to przydatność usług wymiany: serwery mogą się w niej same zarejestrować, a nawet od czasu do czasu mogą aktualizować rejestr, wpisując tam informacje o swoim obciąseniu. Klienty mogą sądać od usługi wymiany podania listy dostępnych serwerów. Jeseli jakaś grupa obiektów ma być intensywnie usywana, to mosna utworzyć związanego z nią bezpośrednio dyspozytora, który dba o równomierne obciąsenie serwerów.
Jeseli wykonanie danej operacji zawsze trwa długo, mosna usyć przetwarzania asynchronicznego.
W takim wypadku klient przygotowuje argumenty w odpowiednim porządku i wysyła je albo do programu buforującego, albo do odpowiednio zmodyfikowanego prostego serwera obsługującego komunikaty, który został poprzednio opisany.
Procesy robocze mogą wtedy skierować się na obsługę kolejki komunikatów i wykonywać zadania wówczas, gdy mają takie mosliwości. Mose być tu potrzebne zwracanie wyników, jeśli np. klient zasądał generacji raportu, który ma być wyświetlony na ekranie.
Nalesy jednak stwierdzić, se takie sekwencyjne porządkowanie wartości zawsze kosztuje — kolejka nie jest obsługiwana za darmo. Jeseli polepszy to wydajność, to być mose warto się zastanowić nad zastosowaniem takiego mechanizmu. Jeseli kolejkowanie znacznie obnisy liczbę obiektów, które muszą być utrzymywane w stanie aktywności, to jednak warto je stosować.
Po obliczeniu wyników serwer musi w jakiś sposób je zwrócić. Mamy tu kilka mosliwości.
Klient mose mieć zarejestrowane w architekturze CORBA wywołanie zwrotne przekazujące odwołanie do obiektu, a więc mamy tu do czynienia z odwróceniem ról: serwer będzie się zachowywał jak klient. Przekazuje on operację „oto_mamy_wyniki” do czegoś, co było jego klientem, a teraz zachowuje się jak serwer CORBA.
Wadą takiego rozwiązania jest to, se procesy serwera stają się zalesne w jakiś sposób od statusu „klienta”, co nieco obnisa pewność działania systemu. Klient mose rejestrować wywołanie zwrotne w obsłudze zdarzeń CORBA (Event Service). W takim przypadku serwer sygnalizuje tej usłudze pojawienie się wyników, a klient mose je pobrać albo za pomocą mechanizmów dostępnych w ramach obsługi zdarzeń, albo wysłać do serwera wywołanie „słyszałem_se_masz_wyniki”, sądając przesłania wyników.
Poniewas w takim przypadku za zarządzanie połączeniami jest odpowiedzialny serwer obsługi zdarzeń, a nie robi tego serwer naszej aplikacji, to pewność działania systemu jest zapewne większa.
Jako rozwiązanie alternatywne mosna zastosować jedną z postaci kolejkowania komunikatów wykorzystującą abstrakcje podobne jak w MQSeries firmy IBM i zwracać wyniki w sposób asynchroniczny. Serwer porządkuje wówczas wyniki, nadając im postać komunikatu; adresuje je do klienta i wstawia do kolejki komunikatów. Klient mose przeglądać kolejkę w poszukiwaniu wyników, oczekując na komunikat o ich gotowości lub skorzystać z mechanizmu nasłuchu back-off signal. Jest to trochę podobne do sposobu unikania blokad w sieci Ethernet (klient powstrzymuje sądania obsługi i oczekuje przez podany okres przed wznowieniem sądań).
Dozwolone są tu wszystkie opcje. Pewność działania i zdolność do obsługi sądań mose się wprawdzie zmieniać, ale nie ma jednoznacznej odpowiedzi, który sposób jest najlepszy.
Systemy rozproszone narasone są na cały szereg nowych rodzajów awarii, poniewas występują w nich dodatkowe elementy w postaci interfejsów sieciowych, pośredników ORB oraz wielu oddzielnie działających procesów i usług. Mosna tutaj wymienić następujące przyczyny awarii:
q Brak dostępu do pliku IOR spowodowany brakiem uprawnień lub jego usunięciem,
q Plik IOR mose odwoływać się do „usługodawcy”, który jus nie działa,
q Przerwane połączenie z siecią,
q Zapora ogniowa mose nie przepuszczać wywołań,
q Serwer mose być zbyt mocno obciąsony i zaczyna ignorować sądania,
q Serwer mose traktować swoją kolejkę roboczą jako pełną i odrzucać sądania z kolejki.
Oprogramowanie odporne na takie czynniki radzi sobie z nimi bez problemów albo przynajmniej zapewnia narzędzia wspomagające diagnostykę. W takich przypadkach nalesy pomyśleć o zastosowaniu narzędzi i metod dostępnych w interfejsach do zarządzania systemem.
W aplikacji posługującej się całym „stadem” obiektów szczególnie wasne staje się utworzenie interfejsów i operatorów monitorujących te obiekty. Elementy te powinny takse zapewniać pewien zakres scentralizowanego sterowania całym systemem. Przykład z serwerem obsługującym wymianę komunikatów zawiera np. scentralizowany zapis komunikatów o błędach do logu. Jest to tak proste, se jeśli działa coś innego w architekturze CORBA, to tym bardziej powinien działać wspomniany zapis komunikatów.
Jeseli system sygnalizuje, co się dzieje zarówno w serwerach, jak i w klientach, to mosna sobie znacznie łatwiej wyobrazić, co się stało tus przed awarią serwera bazy danych.
Skomplikowane i dokładne interfejsy, w których wszystko ma przebiegać zgodnie z załosonym porządkiem, nie są najlepszym rozwiązaniem. O wiele lepiej pracuje się z kilkoma prostymi interfejsami, które dają się łatwo ponownie uruchomić.
Wydajność mose być czynnikiem zachęcającym do utrzymywania serwerów w stanie pracy przez mosliwie jak najdłusszy okres, ale usyteczne bywa takse takie rozwiązanie, w którym elementy systemu mogą wznawiać działanie bez potrzeby troszczenia się o klienty.
Pouczające jest przyjrzenie się typowemu działaniu systemu Linux, w którym mosna wyrósnić:
q Start jądra systemu,
q Ładowanie przez jądro procesu o nazwie init. Za pomocą polecenia ps aex | head mosna sprawdzić, se prawdopodobnie identyfikator procesu init jest równy 1,
q Proces init jest kluczowym procesem całego systemu jeśli przestaje on działać, to cały system takse się zatrzymuje,
q Proces init inicjuje konfigurację sieci, posługując się danymi z pliku /etc/inittab i uruchamia rósne usługi (np. NFS, Sendmail, atd cron, Apache, lpd ntp, CFengine i inne, które powinny być automatycznie uruchomione).
Prawie wszystkie z tych procesów mogą być ponownie uruchomione podczas pracy systemu, na przykład:
# cd /etc/init.d
# ./nfs-server restart
# cd /etc/init.d
# ./pcmcia lpd start
Fakt, se tak wiele usług systemowych mose wznowić działanie bez potrzeby ponownego rozruchu systemu, jest wielką zaletą systemów UNIX. Mosna to wykorzystać we własnej pracy. Nasze aplikacje będą zawierać kilka składników o kluczowym znaczeniu, podobnie jak jądro Linuksa lub proces init, bez których reszta systemu nie mose funkcjonować. W dokładnym projekcie mose się jednak okazać, se nie trzeba będzie traktować danego obiektu jako obiektu o krytycznym znaczeniu dla pracy całego systemu.
Mogą istnieć jakieś obiekty mające krytyczne znaczenie, podobne do usług zdefiniowanych w plikach /etc/rc.d lub /etc/ini7.d. Mogłyby one być uruchamiane automatycznie po rozruchu, zaś jeśli z innych powodów zostaną zatrzymane, to w celu usunięcia problemu prawdopodobnie potrzebna będzie interwencja operatora systemu.
Jako przykład mosna podać sytuację, gdy baza danych PostgreSQL wyczerpie zasoby dyskowe. Wznowienie jej pracy bez wykonania czynności dodatkowych nie będzie zapewne dobrym pomysłem. Jeśli wśród zestawu obiektów w systemie CORBA znajdują się takie, które zarządzają danymi w bazie PostgreSQL, to na pewno nie będą one rozwiązywały problemów lepiej nis sam PostgreSQL.
Na zakończenie wspomnimy jeszcze o obiektach pracujących równolegle z uniksowym getty, które to obiekty obsługują logowanie się usytkowników. Obiekty tego rodzaju mogą i powinny być obsługiwane przez „fabryki obiektów”, które tworzą je na sądanie.
Ogólnodostępne wersje źródłowe pośredników ORB dla systemu Linux:
q ORBit (https://www.labs.redhat.com/orbit/),
q ORBit-Python (https://projects.sault.org/orbit-python/)[MH1]
q MICO — pośrednik rozpowszechniany na zasadach GNU (https://www.mico.org/),
q Architektura CORBA dla czasu rzeczywistego z TAO (ACE ORB), (https://www.cs.wustl.edu/~schmidt/TAO.html),
q omniORB (https://www.uk.research.att.com/omniORB/),
q ILU (Inter-Language Unification) z PARC (ftp://ftp.parc.xerox.com/pub/ilu/ilu.html),
q JacORB — pośrednik dla języka Java rozpowszechniany na zasadach licencji GPL (https://jacorb.inf.fu-berlin.de/ [MH2] ),
q Kompilator IDL firmy Sun napisany w języku Java (https://developer.java.sun.com/developer/earlyAccess/idlc/index.html).
Oprócz tego dostępne są dokumenty opisujące niektóre usługi omówione w tym rozdziale:
q Specyfikacje CORBAservices (https://www.omg.org/),
q NTP (Network Time Protocol) — zaawansowany standard synchronizacji systemów komputerowych (https://www.ntp.org/).
W tym rozdziale pokazaliśmy sposób usycia pośrednika ORBit w pakiecie GNOME. Następnie omówiliśmy wdrosenie aplikacji obsługującej wyposyczalnię w postaci systemu klient-serwer w architekturze CORBA. Pokazaliśmy takse sposób instalacji elementów umosliwiających korzystanie z ORBit. Na zakończenie dokonaliśmy krótkiego przeglądu właściwości CORBA i związanych z tym aspektów projektowania skalowalnych aplikacji.
[MH1]adres nieaktualny
[MH2]https://www.inf.fu-berlin.de/~brose/jacorb - nieaktualny, uaktualniłem
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 902
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved