Implementarea Tranzactiilor Intr Un Sistem Distribuit Bazat PE Componente

Cuprins

Capitolul 1. Introducere…………………………………………………………………………3

Capitolul 2. Fundamentare teoretică……………………………………………………………5

2.1 Introducere în sistemele distribuite…………………………………………………………5

2.2 Modelul Client-Server………………………………………………………………………7

2.3 Protocolul TCP…………………………………………………………………………..…9

2.4 XPCOM……………………………………………………………………………………12

2.4.1 Componente XPCOM……………………………………………………………………14

2.5 Tranzacții………………………………………………………………………………….17

2.6 Mozilla FireFox……………………………………………………………………………19

2.7 API-ul NSPR………………………………………………………………………………20

Capitolul 3. Specificațiile și arhitectura sistemului………………………………………………22

3.1 Schema bloc a sistemulu……………………………………………………………………21

3.2 Arhitectura Coordonatorului de Tranzacții…………………………………………………23

3.3Arhitectura Componentei Tranzacționale………………………………………………….25

3.4 Cazurile de Utilizare……………………………………….………………………………27

3.4 Cazul de utilizare pentru Coordonatorul de Tranzacții..……..……………………………28

3.5 Cazul de utilizare pentru Componenta Tranzacțională…..…………………………………28

Capitolul 4. Proiectarea în detaliu………………………………………………………………………………… 30

4.1 Structura internă pentru Coordonatorul de Tranzacții……………………………………….30

4.2 Structura internă pentru Componenta Tranzacționale…………………………………………………31

4.3 Diagrama de secvență………………………………………………………………………32

4.4 Diagrama de Clase pentru Coordonatorul de Tranzacții………..…………………………34

4.5 Diagrama de Clase pentru Componenta de Tranzacție……………………………………………….37

4.6 Functile utilizate în Componenta de Tranzacție……………………….………………….39

4.7 Protocolul de comunicare……………….…………………………………………………40

4.8 Utilizarea librariei nspr.lib…………………………………………………………………42

4.9 Crearea unei componente XPCOM…………………………………………………………46

Capitolul 5. Utilizarea componentei………………………………………………………………………………49

Capitolul 6. Concluzii și dezvoltări ulterioare………………………………………………………………..52

Bibliografie…………………………………………………………………………………………………………………..53

Capitolul 1

1.Introducere

Tranzacțiile reprezintă o categorie aparte a sistemelor distribuite.Această lucrare își propune proiectarea, implementarea și testarea unei componente XPCOM pentru a realiza operațiuni asupra unor date cu ajutorul tranzacțiilor într-un sistem distribuit. Codul componentei va fi scris in limbajul C++.

Lucrarea este împărțită în 6 capitole, după cum urmează :

Capitolul 1. Introducere

Oferă o vedere de ansamblu asupra întregii lucrări.

Capitolul 2. Fundamentare teoretică

Acest capitol prezintă cateva chestiuni teoretice legate de sistemele distribuite.Începe cu o introducere in problematica sistemelor distribuite,avantajele și dezavantajele lor în comparație cu sistemele centralizate,câteva aspecte care trebuie avute în vedere la proiectarea lor.În continuare este abordată problema comunicării în sistemele distribuite,se prezintă pe scurt suportul de comunicare folosit .Tot în acest capitol se va prezenta beneficiile aduse de programarea orientată pe componente și în special a componenteleor XPCOM utilizate de platforma Mozilla Firefox.

Capitolul 3. Specificații și arhitectura sistemului

În capitolul 3 sunt prezentate specificațiile sistemului distribuit.Se prezintă modelul de comunicare ales,arhitectura sistemului,stabilirea conexiunilor,funcțiile sistemului.

Capitolul 4. Proiectare în detaliu

Acest capitol prezintă proiectarea și implementarea interfeței.Structura programului și distribuirea componentelor.

Capitolul 5. Utilizarea componentei

În acest capitol este prezentat modul de utilizare a componentei XPCOM

Capitolul 6. Concluzii

Acest capitol conține cateva concluzii legate de performanțele și fiabilitatea sistemului

Bibliografie

Capitolul 2

2.Fundamentare teoretică

2.1 Introducere în sistemele distrbuite

Datorită progresului tehnologic rapid,acest domeniu avansează în ritm alert,iar diferențele între colectarea,transportul,stocarea și prelucrarea informației dispar pe zi ce trece.Pe măsură ce posibilitățile noastre de a colecta,prelucra si distribuii informația cresc tot mai mult,cererea pentru o prelucrare si mai sofisticată a informației crește și mai rapid. Întrepătrunderea dintre domeniul calculatoarelor si cel al comunicaților a avut o influentă profundă asupra modului în care sunt organizate sistemele de calcul.Vechiul model al unui singur calculator care servește problemelor de calcul ale organizației a fost înlocuit de un model în care munca este facută de un număr mare de calculatoare separate dar interconectate.Aceste sisteme se numesc rețele de calculatoare.În literatura de specialitate se face deseori confuzie între o retea de calculatoare si un sistem distribuit.

Într-un sistem distribuit,existența mai multor calculatoare autonome este transparentă pentru utilizator.Acesta poate tasta o comandă pentru a executa un program și programul îl va executa.Este sarcina sistemului de operare să aleagă procesorul cel mai potrivit,apoi să gasească și să transfere toate datele de intrare către respectivul procesor și să depună rezultatele în locul corespunzător.Într-o rețea,utilizatorii trebuie să se conecteze explicit la o anumită masină,să comande explicit execuția proceselor la distanța să transfere explicit fișierele și,în general,să personalizeze toată administrarea rețelei.Într-un sistem distribuit nu este nimic de făcut în mod explicit:totul este realizat automat de către sistem,fără cunoștinta utilizatorului.

Un sistem distribuit este o colecție de calculatoare și procesoare autonome (având o unitate de comandă proprie), interconectate (capabile de a schimba informații între ele).

Sistemele distribuite au apărut ca o necesitate pentru:

– schimbul de informații între noduri;

– siguranța în funcționare: dacă un nod "cade", întregul sistem trebuie (dacă este posibil)

să fie capabil să asigure în continuare funcționarea, prin redirijarea (rutarea) mesajelor prin nodurile funcționale.

Fig.1 Sistem distribuit alcătuit din noduri

Fiecare nod din figura 1 reprezintă un calculator iar linia dintre două noduri(calculatoare) reprezintă legătura de comunicare dintre ele.

Fig.2 Sistem distribuit detaliat

În figura 2 este prezentat același sistem distribuit ca și în prima figură dar de data aceasta puțin mai detaliat.Fiecare calculator are propria memorie locală iar modul de transmitere

a informațiilor între două calculatoare din acest sistem distribuit se poate realiza prin trimiterea

unor mesaje de la un nod la altul folosind legătura de comunicare dintre ele.

Principalele dificultăți în proiectarea sistemelor distribuite sunt:

– Asincronia – timpul absolut la care au loc evenimentele nu poate fi cunoscut precis;

– Cunoașterea locală – fiecare entitate de calcul poate dispune doar de informația pe care o primește, are doar o imagine locală asupra situației globale;

– Căderea componentelor(failures) – entitățile de calcul se pot defecta independent lasând

anumite componente operaționale iar altele nu.

2.2 Modelul Client/Server

Modelul standard pentru aplicații în rețea este “client-server”. Serverul este un proces care așteaptă să fie contactat de un proces client pentru a oferi diverse servicii (acces la resurse). Resursele pot fi fișiere, structuri de date, informații diverse sau resurse fizice ca imprimante, fax-uri, scannere, etc.

Serverul este startat primul, după care se deschide un canal de comunicație pe sistemul pe care se află și se informează “hostul” local că se pot primi cereri de la clienți la o adresă dată. Serverul va asteapta cererile la adresa respectivă.

Un client este un proces care dorește utilizarea unei resurse, având și el o secvență de acțiuni de desfășurat. Astfel, el va deschide un canal de comunicație și se va conecta la un anumit host, la o adresă dată (a serverului). Apoi,va trimite mesajul-cerere către server și va aștepta primirea răspunsului. La terminarea acțiunii,clientul va închide canalul de comunicație. Deschiderea unui canal de comunicație de către server este cotată ca o acțiune pasivă, în timp ce un client deschide un canal în mod activ.

În general, un server este o aplicație care oferă servicii utilizatorilor de internet, un

client este o altă aplicație care solicită un serviciu.Există aplicații alcătuite atât dintr-o parte

client cât și dintr-o parte server,ele pot rula pe același sistem sau pe sisteme diferite.Utilizatorii

invocă partea client a aplicației, care efectuează o cerere referitoare la un serviciu pe care o trimite părtii server a aplicației folosind protocolul TCP/IP pe post de vehicul de transport.Protocolul TCP/IP este explicat în mod detaliat în secțiunea 2.3

Serverul este un program care primește o cerere, îndeplinește serviciul cerut și transmite

rezultatul drept răspuns. Un server poate rezolva, de regulă, mai multe cereri (deservii mai mulți

clienti) în același timp.Comunicarea între nodurile unei rețele constă în transmiterea(recepționarea) de pachete către (de la) gazde ale aceleași rețele sau ale unei alte rețele.

Modelul utilizat pe scară largă în sistemele distribuite (și care va fi cel folosit în continuare) este sistemul Client/Server.

În acest model există:

– o mulțime de procese Server, fiecare jucând rolul de gestionar de resurse pentru o colecție de resurse de un anumit tip;

– o mulțime de procese Client; fiecare execută activități care necesită acces la resurse hard/soft disponibile (partajate) de servere.

Un gestionar de resurse poate avea și el nevoie de resurse gestionate de un alt proces Server. Drept urmare, unele procese pot fi atât de tip Client, cât și de tip Server. Doar serverele gestionează resurse.

Serverele sunt cele care își încep primele activitatea. În mod tipic, un server oferă succesiv clienților posibilitatea de a se conecta la el (spunem că acceptă conexiuni de la clienți). La început clientul își manifestă dorința de a se conecta și, dacă serverul este gata să accepte conexiunea, aceasta se realizează efectiv; este vorba deci de o acțiune de la client către server. Apoi transmisia informațiilor devine bidirecțională, fluxul de informații putând circula acum în ambele sensuri.Teoretic, activitatea unui server se desfășoară la infinit.

2.3 Protocolul TCP

Comunicarea între componentele unei rețele (respectiv unui sistem distribuit) se face prin mulțimi de reguli, numite generic protocoale.TCP(Transmission Control Protocol) este un protocol de nivel intermediar care are la baza conceptul de conexiune.

Protocolul TCP este orientat pe conexiunea punct-la-punct dintre sursă și destinație realizând transfer sigur de informații,fără erori.TCP folosește mesaje de confirmare a recepției corecte pentru fiecare pachet și cere retransmisia celor eronate.

În antetul TCP sunt specificate, pe 16 biți,numerele porturilor logice asociate aplicațiilor sursă și destinație,între care se stabilește comunicația virtuală.Fiecare capăt al conexiunii TCP se numeste socket.

Un protocol cuprinde atât formatul mesajului ce este efectiv transmis, cât și modul în

care trebuie răspuns la mesajul respectiv.

Încapsularea datelor constă în adaugarea unor informații suplimentare la începutul(header),eventual și la sfârsitul blocului de date,în funcție de protocol.Datele circulă în

stiva de protocoale de sus în jos,în cazul re, îndeplinește serviciul cerut și transmite

rezultatul drept răspuns. Un server poate rezolva, de regulă, mai multe cereri (deservii mai mulți

clienti) în același timp.Comunicarea între nodurile unei rețele constă în transmiterea(recepționarea) de pachete către (de la) gazde ale aceleași rețele sau ale unei alte rețele.

Modelul utilizat pe scară largă în sistemele distribuite (și care va fi cel folosit în continuare) este sistemul Client/Server.

În acest model există:

– o mulțime de procese Server, fiecare jucând rolul de gestionar de resurse pentru o colecție de resurse de un anumit tip;

– o mulțime de procese Client; fiecare execută activități care necesită acces la resurse hard/soft disponibile (partajate) de servere.

Un gestionar de resurse poate avea și el nevoie de resurse gestionate de un alt proces Server. Drept urmare, unele procese pot fi atât de tip Client, cât și de tip Server. Doar serverele gestionează resurse.

Serverele sunt cele care își încep primele activitatea. În mod tipic, un server oferă succesiv clienților posibilitatea de a se conecta la el (spunem că acceptă conexiuni de la clienți). La început clientul își manifestă dorința de a se conecta și, dacă serverul este gata să accepte conexiunea, aceasta se realizează efectiv; este vorba deci de o acțiune de la client către server. Apoi transmisia informațiilor devine bidirecțională, fluxul de informații putând circula acum în ambele sensuri.Teoretic, activitatea unui server se desfășoară la infinit.

2.3 Protocolul TCP

Comunicarea între componentele unei rețele (respectiv unui sistem distribuit) se face prin mulțimi de reguli, numite generic protocoale.TCP(Transmission Control Protocol) este un protocol de nivel intermediar care are la baza conceptul de conexiune.

Protocolul TCP este orientat pe conexiunea punct-la-punct dintre sursă și destinație realizând transfer sigur de informații,fără erori.TCP folosește mesaje de confirmare a recepției corecte pentru fiecare pachet și cere retransmisia celor eronate.

În antetul TCP sunt specificate, pe 16 biți,numerele porturilor logice asociate aplicațiilor sursă și destinație,între care se stabilește comunicația virtuală.Fiecare capăt al conexiunii TCP se numeste socket.

Un protocol cuprinde atât formatul mesajului ce este efectiv transmis, cât și modul în

care trebuie răspuns la mesajul respectiv.

Încapsularea datelor constă în adaugarea unor informații suplimentare la începutul(header),eventual și la sfârsitul blocului de date,în funcție de protocol.Datele circulă în

stiva de protocoale de sus în jos,în cazul transmisiei,și de jos în sus,spre aplicații,la recepție.

În cazul folosirii TCP ca protocol de transport pentru o aplicație rulată într-o rețea de calculatoare,încapsularea datelor se realizează în mai multe etape de pe un nivel pe altul,conform figurii 2 :

La nivelul de aplicații,datele utilizatorului sunt încapsulate cu un antet de aplicație într-un mesaj de aplicație.

TCP are următoarele caracteristici principale:

a) Transfer de date în flux continuu – datele circulă în același timp, în ambele sensuri ale conexiunii. Spunem că TCP este o conexiune duplex.

b) Siguranța transmisiei – recuperează pachetele transmise cu erori, pierdute sau cu număr de secvență eronat. Această caracteristică este asigurată prin stabilirea unui număr de secvență fiecărui pachet transmis și necesitatea unui mesaj de confirmare (ACK) din partea receptorului.Dacă,după un anumit interval de timp,expeditorul nu primește un mesaj de confirmare, pachetul este considerat pierdut și este retransmis.

c) Controlul fluxului de date – în fiecare mesaj ACK, trimis de receptor, este conținută o "fereastră" care indică numărul permis de octeți pe care emițătorul îi poate transmite (Principiul ferestrei glisante). În urma unui astfel de mesaj, emițătorul își va dimensiona pachetele transmise la lungimea indicată de receptor. Această lungime este valabilă până la recepționarea următorului mesaj ACK, care conține o altă marime de "fereastră".

d) Multiplexarea – permite mai multor procese, care rulează pe același host, să utilizeze facilitățile protocolului TCP simultan.

e) Controlul conexiunii – în transferul de date dintre două procese putem distinge trei etape: stabilirea conexiunii, controlul conexiunii, închiderea conexiunii.Controlul conexiunii presupune: stabilirea numărului de secvență și a dimensiunii ferestrei, pentru fiecare pachet TCP.

Portul

Portul nu este o locație fizică, ci o extensie software corespunzătoare unui serviciu. Portul este un capat al unei conexiuni logice în rețelele TCP/IP. De fiecare dată când se face o conexiune între două calculatoare (client/server) se face o legatură care implică câte un port de pe fiecare calculator.Serverul poate oferi mai multe servicii, pentru fiecare existând un număr de

port. Porturile din intervalul 0..1023 sunt în general rezervate pentru servicii speciale și pentru clienți privilegiați.

Clientul inițiază conexiunea prin rețea, specificând adresa serverului și portul prin care dorește să comunice. Serverul trebuie să precizeze numai portul; apoi el trebuie să execute o comandă prin care să anunțe că este gata să accepte conexiuni pe portul respectiv,drept urmare el rămâne în așteptare până când un client dorește să se conecteze și conexiunea este stabilită cu succes.Un server poate accepta conexiuni de la mai mulți clienți:pentru fiecare crează un fir de executare.

Anumite servere asteaptă cererile la un port bine cunoscut astfel încât clienții lor știu către ce socket IP să-și îndrepte cererile lor.

Adresa IP/LocalHost

Pentru a putea fi folosită într-o rețea TCP/IP, o interfață trebuie sa aibă asociată o adresă

IP care folosește pentru identificarea interfeței respective când comunicã cu restul lumii..

Adresa 127.0.0.0 este rezervată pentru traficul IP local către gazda locală De obicei,

adresa 127.0.0.1 va fi asociată unei interfețe speciale numită interfață loopback , care se comportă ca un circuit închis. Orice pachet IP trimis prin această interfață, va fi returnat ca și cum ar fi venit de la un calculator din rețea. Acest lucru ne oferă posibilitatea să dezvoltăm și să testăm software de rețea fără să folosim rețea reală. Alta aplicație folositoare este atunci când vrem sa folosim software de rețea pe un calculator care nu este în rețea.

2.4 XPCOM

Programarea bazată pe componente este o ramură a ingineriei programării, în care obiectivul cheie este descompunerea încă din faza de proiectare a unui proiect amplu în componente care au un scop bine definit și o interfață care conține intrările și ieșirile prin care componenta se leagă de alte componente sau de sistem.

Pentru a nu fi confundate cu obiectele, putem spune că componentele sunt construite din mai multe obiecte, prezintă un nivel mai înalt de abstractizare și oferă o anumită funcționalitate cu ajutorul interfețelor implementate.

Prin definiție o componentă este un obiect scris pentru o specificație și care îndeplinește

următoarele criterii de bază:

refolosire – o componentă trebuie să fie proiectată și implementată astfel încât să poată fi folosită în diverse programe;

nespecifică unui context – ar trebui să poată fi folosită și de alte programe care nu au legătură cu domeniul în care este folosită componenta;

să poată comunica cu alte componente – interfața trebuie astfel concepută încât alipirea la alte componente, scrise chiar și în alt limbaj de programare, să se facă cât mai ușor;

să fie încapsulată – cei care folosesc componenta nu vor știi ce se întâmplă de fapt în interiorul acesteia;

autonomie față de alte componente – o componentă nu va depinde niciodată de nimic. Acest lucru, ca și comunicarea cu alte componente, sunt posibile cu ajutorul IDL (Interface Description Language), care este un limbaj comun de descriere a interfețelor componentelor.

De asemenea, pentru ca o componentă să poată fi refolosită eficient, aceasta trebuie să raporteze mesaje de eroare folositoare și să fie testată intens pentru a descoperii orice neajunsuri care pot apărea în cazul unei folosiri neprevăzute.

Când a apărut prima dată această idee de programare bazată pe componente nu existau standardele necesare creării lor ca în ziua de azi (COM, XPCOM, etc.), astfel că programatorii nu erau motivați să proiecteze un sistem în vederea refolosirii unor „bucăți” din el în alte proiecte. De-a lungul timpului, odată cu necesitatea implementării de programe tot mai complexe în timpi tot mai scăzuți, programatorii au fost constrânși să adopte ideea de refolosire a unor bucăți de cod, ajungându-se în cele din urmă la standardele de azi.

În momentul de față există mai multe companii dezvoltatoare de software care folosesc asemenea componente care sunt create pe diferite interfețe dezvoltate de acestea. Printre cele mai importante putem enumera:

XPCOM (Cross Platform Component Object Model) de la Mozilla – folosită în lucrarea de față – este, ca și COM de la Microsoft, un framework (o interfață cadru) care permite dezvoltatorilor să

creeze programe din module mai mici numite componente care apoi sunt asamblate la rularea programului;

Motivul principal al alegerii în lucrarea de față a tehnologiei XPCOM este posibilitatea dezvoltării de aplicații care pot rula pe mai multe sisteme de operare (Windows, Linux, MAC) și față de CLX, resursele disponibile cu privire la modalitatea dezvoltării unor astfel de componente sunt mult mai ridicate.

2.4.1 Componente XPCOM

XPCOM reprezintă o metodologie de programare a aplicațiilor distribuite, inspirată de COM(Component Object Model), independentă de platforma hardware si software: fragmente de cod oferă interfețe independente de limbaj și platformă spre alte obiecte care pot să acceseze diferite servicii. Astfel, proiectarea și compilarea aplicației se pot realiza indiferent de implementarea obiectelor, programatorii trebuind să cunoască numai interfețe oferite de obiecte. Aceste interfețe vor fi descrise într-un limbaj special denumit XPIDL, extensie a limbajului de definire a interfețelor IDL (Interface Definition Language) folosit de COBRA și COM. XPConnect este tehnologia prin intermediul căreia interfețele descrise de XPIDL sunt conectate la părțile de cod care implementează obiectele în JavaScript, limbajul utilizat de XUL.

Nucleul navigatorului, purtând numele de Gecko, reprezintă o componentă modulară, bazată pe clienții Netscape/Mozilla, care poate fi inclusă atât în aplicații Web de mari dimensiuni cu propriile lor interfețe-utilizator cât și în dispozitive miniaturizate. Filosofia dezvoltării actuale și viitoare a nucleului ține cont de următoarele aspecte:

a) Gecko nu reprezintă un browser Web, neavând propria sa interfață, și nu are integrate servicii auxiliare (de exemplu, clientul de poștă electronică sau editorul HTML) și nu oferă facilități suplimentare (e.g. bookmarks) ;

b) se bazează numai pe standarde deschise redactate de Consorțiul Web: HTML 4.0, CSS1, CSS2, DOM1, DOM2, XML, RDF etc., iar HTML dinamic este simulat prin DOM;

c) stă independent de platforma (prin tehnologia NSPR), foarte compact (prima versiune putea fi stocată pe o singură dischetă) și rapid;

d) partea de comunicare în rețea este ea însăși modulară, purtând numele de Necko;

e) este extensibil, sursele fiind publice;

f) oferă suport pentru navigatoarele mai vechi.

În acest mod, nucleul poate fi folosit de mai multe navigatoare sau aplicații, în diferite circumstanțe și rulând pe diverse platforme, interfața cu acesta putând fi aleasă de utilizator, beneficiind de flexibilitatea oferită de XUL.

Folosind tipul info, un program poate determina fiecare parametru sau atribut al oricărei metode date pe unele interfețe. Cu aceste cunoștințe, el poate muta datele înainte și înapoi între interfața și alte câteva medii. Acele alte medii pot fi motoare de scriptare sau proxi-mecanisme pentru trecerea firului, procesului sau a rețelei de granițe. În cazul unui motor de scriptare, reiese modul în care o componentă este definită în mediul de scriptare, astfel încât modul scriptat poate invoca metode pe o componentă a interfeței.

XPConnect este un strat suplimentar construit in partea de sus a XPCOM, care poate transforma o interfață XPCOM într-un motor JavaScript, citind un fișier XPCOM de tip bibleotecă. XPConnect permite, de asemenea, componentelor XPCOM să fie scrise în întregime în JavaScript, astfel putem avea un cod C++ numit ca un JS component, sau putem folosi JS pentru a încărca sau manipula un component C++ compilat. Alături de JavaScript, limbajul Python a fost adăugat ca o altă scriptare alternativă, folosind un mecanism similar cu XPConnect.

Fig1.Componentă XPCOM în interfața cadru

Când construim o componentă sau un modul(mai multe componente) și le compilăm într-o librărie se exportă o singură metodă numită NSGetModule.Această funcție este punctul de intrare pentru a accesa librăria.Această funcție este apelată în timpul inregistrării componentei dar și atunci când XPCOM vrea să descopere ce interfețe sau clase implementează respectivul modul/librărie.

Pe lângă funcția NSGetModule se poate observa în structura existentă două interfețe: nsIModule și nsIFactory.Aceste interfețe controlează crearea componentei.Pentru a întelege când o componentă dintr-o librărie este apelată trebuie să întelegem procesul de inițializare a XPCOM.Când o aplicație pornește ea poate să inițializeze XPCOM.Secvența de evenimente care pornește inițializarea unui XPCOM poate veni atât din partea clientului cât și din partea aplicației când pornește.

Exista 6 pași importanți pentru pornirea unui XPCOM

1.Aplicația pornește XPCOM

2.XPCOM trimite o notificare că vrea să pornească

3.XPCOM găsește și procesează “component manifest”(fișier special care conține informații despre componentele din sistemul local)

4.XPCOM găsește și procesează “type library manifest”(fișier special care conține informații

despre librăriile din sistem

5.Dacă există componente noi,XPCOM le inregistrează

-XPCOM apelează autoînregistrarea

-XPCOM înregistreaza noua componentă

-XPCOM apelează sfârșitul autoînregistrarii

6.Pornirea XPCOM este completă,XPCOM anuntă că a pornit.

2.5 Tranzacții

O tranzacție este specificată de client ca un set de operații pe un obiect cu scopul de a fi rulate de o “unitate invizibilă” de pe serverul care conține respectivele obiecte.O tranzacție se desfăsoară în mai multe etape.

Pentru început un proces anunță că dorește să realizeze o tranzacție împreună cu unul sau mai multe procese.Se negociază opțiuni,se creează obiecte și se realizează operațiile necesare.Când toată munca a fost terminată inițiatorul tranzacției anunță că dorește ca toate schimbările făcute să devină permanente.Dacă celelalte procese participante sunt de acord starea sistemului este salvată,dar dacă cel puțin unul refuză sau din cauza unei erori nu poate fi deacord,sistemul este adus în starea inițială,din momentul în care a început tranzacția.

Scopul unei tranzacții este de a garanta integritatea tututoror obiectelor manipulate de un server să rămână într-o stare consistentă atunci când sunt accesate.Tranzacția se aplică obiectelor recuperabile și are intenția sa fie atomică.Mai este numită și tranzacție atomică

Există două aspecte asupra acestei atomicitați:

Totul sau nimic:O tranzacție fie se realizează cu succes și rezultatele acesteia se scriu în obiecte sau dacă apare o eroare nu se înregistrează deloc.

Acest efect totul sau nimic are deasemenea 2 particularitați:

a)atomicitatea erorii – efectele sunt atomice chiar dacă serverul cade(crash)

b)durabilitate – după ce o tranzacție s-a completat cu succes toate efectele sale sunt salvate în memoria permanentă adică datele salvate vor rezista chiar daca serverul o să pice.

Izolare:Fiecare tranzacție trebuie realizată fără existența unei interferențe din partea

unei alte tranzacții.Ea nu trebuie sa fie văzaută de altă tranzacție.Pentru a face posibilă

durabilitatea și atomicitatea unei erori obiectele de pe server trebuie să fie recuperabile.Când un

proces de pe server cade”crash” din cauza hardweare sau softweare,schimbările efectuate de

tranzacțiile anterioare trebuie să fie disponibile în memoria permanentă astfel că atunci când

procesul picat este înlocuit de un proces nou să poată să recupereze obiectele.

Consistentă : constantele sistemului nu sunt modificate,chiar dacă în timpul executării tranzacției,pentru o perioada scurtă de timp,există modificări la sfârsitul tranzacției ele sunt aduse în starea inițială

Un server care acceptă tranzacții trebuie să știe să sincronizeze operațiile suficient de

repede astfel încât să se asigure condițiile de izolare.O cale de a face acest lucru posibil este

executarea tranzacților într-un mod serial: fiecare pe rând într-o ordine arbitrară.Din păcate această soluție nu se poate aplica(e dificilă) la un server al căror resurse sunt împarțite cu un alt user.

Dacă un server nu este construit cu grijă atunci operațiunile clienților pot câteodată să interfereze între ele.Această interferență ar putea produce valori eronate obiectelor.

Operații atomice la server

Folosirea mai multor fire de execuție “threads” este un beneficiu în perfomanța multor

servere.Deasemenea folosirea lor permit operaților de la mai mulți clienți să ruleze într-un mod

concurențial pentru accesarea obiectelor.Metodele obiectelor trebuie construite în așa fel încât să permită folosirea mai multor fire.

Firele de execuție seamănă cu procesele, pot fi la fel planificate pentru execuție.

Principala diferență este că firul se execută în spațiul de adresare al procesului căruia aparține și

poate modifica valori care sunt văzute și de celelalte fire care aparțin aceluiași proces.Din

această cauză apare necesitatea ca firele să comunice între ele, adică trebuie sincronizat accesul

la datele utilizate în comun. Sincronizarea asigură siguranța datelor, adică prin sincronizare se

previn situațile ca un fir să modifice o variabilă care este utilazată de către un alt fir de execuție.

Dacă un fir de execuție “thread” invocă o metodă sincronizată dintr-un obiect atunci

obiectul respectiv este închis “locked” astfel încât dacă un alt fir “thread” invocă una din metodele sincronizate ale respectivului obiect va fi blocat până când primul închis “lock” se va

deschide.Această formă de sincronizare fortează execuția firelor “threads” să se efectueze separat

în timp și asigură faptul că variabilele unui obiect sunt accesate într-un mod controlat și ordonat.

Fără sincronizare două invocări pentru un “deposit” ar putea citi balanța curentă înainte ca aceasta să fie incrementată rezultând o valoare incorectă.Orice metodă care accesează o variabilă instantă care poate varia trebuie să fie obligatoriu sincronizată.Acestea se numesc operații atomice.Folosirea metodelor sincronizate în Java este o cale de a rezolva problema.Dar în alte limbaje de programare pentru serverele “multi – thread” opreațile pe obiecte au deasemenea nevoie de opreații atomice pentru a ține obiectele consistente.Acest lucru se poate realiza prin folosirea excluderilor mutuale MUTEX.

Un mutex este un obiect de sincronizare care poate fi deținut (posedat, acaparat) doar de

un singur proces (sau thread) la un moment dat. Drept urmare, operațiile de bază cu mutex-uri

sunt cele de obținere(lock) și de eliberare(unlock). Odată obținut de un proces, un mutex devine

indisponibil pentru orice alt proces. Orice proces care încearcă să acapareze un mutex indisponibil, se va bloca (un timp definit sau nu) asteptând ca el sa devină disponibil. Mutex-

urile sunt cel mai des folosite pentru a permite unui singur proces la un moment dat să acceseze

o resursă.

2.6 Mozilla Firefox

Mozilla este o platformă portabilă open-source care pune la dispoziția programatorilor funcționalitățile necesare dezvoltării unor aplicații,care prezintă o interactivitate ridicată pentru utilizatori. Acest lucru este posibil datorită funcționalității pe care se bazează proiectul prezentat, și anume programarea bazată pe componente.Această platformă înglobează mai multe tehnologii, după cum se poate observa în figura următoare, însă despre cele mai importante (NSPR și XPCOM)

Interfețele componentelor sunt descrise cu ajutorul unui limbaj independent de platformă numit XPIDL (Cross Platform Interface Definition Language), care este varianta proprie adoptată de XPCOM pentru limbajul IDL. Această interfață are rolul de a face conversiile de variabile de intrare și de ieșire și a le transmite din limbajul în care se programează (în cazul de față C++) într-un fișier cu extensia idl, necesare pentru crearea componentei.

Pe cealaltă parte se află XPConnect, un strat al XPCOM care oferă accesul la componente cu ajutroul variabilelor prin intermediul unor limbaje (ex: JavaScript) folosite pentru realizarea comunicării în interfața cu utilizatorul. Această interacțiune între XPConnect și

JavaScript se realizează cu ajutorul unui Contract ID (reprezentat de un șir de caractere unic în care se specifică domeniul, modulul, numele componentei și numărul versiunii) sau a unui UUID (Universal Unique Identifier), care este un număr unic de identificare format din 32 de caractere (cifre și litere).

Partea responsabilă pentru interfeța cu utilizatorul în cazul acestei aplicații este un

browser web, care conține un limbaj independent numit DOM (Document Object Model), cerut de limbajul JavaScript pentru a vedea sau modifica o pagină web în mod dinamic.

2.7 API-ul NSPR

NSPR (Netscape Portable Runtime) este o interfață de programare (sau API) folosită pentru a oferi componentelor create cu ajutorul acesteia portabilitatea necesară pentru a putea fi rulate pe diverse sisteme de operare. Până în momentul de față acest API poate fi folosit în crearea de aplicații pe principalele sisteme de operare existante pe piață (Windows, Linux și Mac OS).

Modul de funcționare: obiectivul NSPR-ului este de a oferi un serviciu uniform pe o gamă largă de medii de sisteme de operare. Acesta se străduiește să nu exporte cel mai mic numitor comun, dar să exploateze cele mai bune caracteristici ale fiecarui sistem pe care rulează și încă sa ofere serviciu

uniform.

Principalele facilități oferite sunt:

crearea, administrarea și planificarea firelor de execuție într-un mod propriu de priorități independent de sistemul de operare;

sincronizarea firelor de execuție prin operații de tip mutex;

operații de intrare/ieșire de tip socket;

măsurarea exactă a intervalelor de timp și a sincronizărilor prin operații specifice;

administrarea memoriei printr-un mecanism propriu de alocare și golire a memoriei;

posibilitatea de folosire a librăriilor puse la dispoziție de către setul de

aplicații Gecko SDK.

Firele sunt principalele particularități ale NSPR. Oferta de fire pentru industrie este destul de variată. NSPR, departe de perfecțiune, ofera un singur API, la care clienții pot programa și pot aștepta comportament rezonabil de consistent. Sistemele de operare oferă totul, începând de la concept non-fire și mergând în sus până la sofisticat, scalabil și implementări eficiente. NSPR face mai mult decât sistemele pot oferi. Este un scop al NSPR-ului ca el să impună pe cât posibil accesul la caracteristicile sistemului.

Referitor la rețea, partea de NSPR se ocupă cu manipularea adresei de rețea. NSPR definește o rețea-obiect, care este adresa IP. Atât timp cat acest obiect nu este declarat opac, API oferă metode care permit și încurajează clienții sa trateze adresele ca elemente polimorfice. În acest domeniu, scopul este de a oferi o cale de migrare între IPv4 și Ipv6. În acest scop, este posibil să se efectueze traduceri din șiruri de caractere ASCII (nume DNS) în structurile de adrese de rețea ale NSPR-ului, fară vreo reținere pentru că tehnologia de adresare este Ipv4 sau Ipv6. API-ul NSPR este inclus în setul de aplicații și unelte Gecko SDK.

Capitolul 3. Specificații și arhitectura sistemului

3.1 Schema bloc a sistemului

Fig.1 Schema bloc a sistemului

Se consideră un sistem format din două componente majore: un server(Coordonator de Tranzacții) și un număr de clienți(Componente de Tranzacții).

Coordonatorul de Tranzacții este cel care va coordona mesajele de primire/trimitere în sistem.El va trebui să știe să comunice cu toate componentele tranzacțiilor pentru a putea coordona acțiunile lor până ce tranzacțiile se vor comite.

3.2 Arhitectura Coordonatorului de Tranzacții

Fig.1 Arhitectura Coordonatorului de Tranzacții

Nivelul de rețea al aplicației va fi unul local.Vom folosi o interfațã loopback , care se comportă ca un circuit închis. Orice pachet IP trimis prin această interfață, va fi returnat ca și cum ar fi venit de la un calculator din rețea.Sistemul de Operare folosit va fi Windows XP.Aplicația va utiliza platforma Mozilla o platformă portabilă open-source care pune la dispoziția programatorilor funcționalitățile necesare dezvoltării unor aplicații,care prezintă o interactivitate ridicată pentru utilizatori. NSPR (Netscape Portable Runtime) este o interfață de

programare (sau API) folosită pentru a oferi componentelor create cu ajutorul acesteia portabilitatea necesară pentru a putea fi rulate pe diverse sisteme de operare. Până în momentul

de față acest API poate fi folosit în crearea de aplicații pe principalele sisteme de operare existente pe piață (Windows, Linux și Mac OS).

Nivelul Decizional,Coordonatorul de Tranzacții și Canalul de Comunicare luate împreună alcătuiesc Componenta XPCOM.Canalul de comunicare care va fi folosit este unul bazat pe protocolul TCP\IP.Acesta este un canal sigur de transmitere de informații recuperând pachetele transmise cu erori, pierdute sau cu număr de secvență eronat.Datele circulă în același timp,în ambele sensuri ale conexiunii.Coordonatorul de Tranzacții va face parte dintr-o tranzacție distribuită și va trebui să știe să comunice cu ceilalți participanți la tranzacție.

Nivelul Decizional este locul unde se va lua o decizie finală în privința unei tranzacții.Datorită celei mai importante proprietăți a unei tranzacții:atomicitatea(totul sau nimic) remarcăm faptul că atunci când o tranzacție distribuită ajunge la sfârsitul execuției toate componentele ei trebuie să fie completate cu succes.În caz contrar dacă o parte dintr-o tranzacție este anulată(aborted) atunci toată tranzacția trebuie să fie anulată.Un mod simplu de a completa o tranzacție respectând atomicitatea ei este acela în care coordonatorul de tranzacții comunică cererea de comitere sau anulare către toți participanții unei tranzacții.Acest exemplu este inadecvat deoarece atunci când un participant cere să comită o tranzacție el nu lasă coordonatorului libertatea de a lua o decizie unilaterală pentru a anula tranzacția.

Protocolul în doi pași este construit în așa fel încât orice participant poate să anuleze partea lui de tranzacție.Dacă o parte dintr-o tranzacție este anulată atunci toată tranzacția trebuie sa fie anulată. În timpul procesului de tranzacție participanții(Componentele Tranzacției) vor trimite o confirmare de participare la tranzacție.Cererea unui participant de a comite(realizare cu succes) sau abort(anulare) a unei tranzacții trebuie să fie trimisă la Coordonatorul de Tranzacții.Coordonatorul trebuie sa informeze ceilalți participanți atunci când una din Componente face abort.Într-o tranzacție distribuită coordonatorul comunică cu participanții pentru a realiza protocolul de comitere în doi pasi.

Pentru acest lucru Coordonatorul va folosi o funcție “CanCommit?” prin care întreabă toți participanții dacă vor sau nu vor să comită tranzacția în care sunt implicați.Participantul poate să raspundă cu Da/Nu.Înainte să spună “Da” participantul(Componenta de Tranzacție) se pregătește să comită salvând obiectul/obiectele în memoria permanentă.Daca votul este negativ

“Nu” atunci participantul va face abort la respectiva tranzacție în care este implicat.Coordonatorul va culege toate voturile de la toți participanții.Dacă toate voturile sunt

“Da” atunci Coordonatorul va decide să comită tranzacția și trimite o cerere DoCommit(comitere cu succes) la toți participanții si va trimite “DoAbort”(anulare tranzactie) în caz contrar.

3.3Arhitectura Componentei tranzactionale

Fig.1 Arhitectura componentei tranzacționale

După cum se poate observa arhitectura Componentei de Tranzacție este asemănătoare cu cea a Coordonatorului de Tranzacție.Arhitectura componentei se diferențiază printr-o interefață intereacțiune.

Această interfață intereacțiune este compusă din urmatoarele funcții :

1.Funcția ÎnregistrareTranzacție

Această funcție va avea rolul de a înregistra informațiile despre o anumită tranzacție.Utilizatorul își manifestă dorința de a începe o anumită tranzacție.Această informație este trimisă către Coordonatorul de Tranzacții.

2.Funcția PrimeșteNotificare

Având în vedere că o componentă XPCOM nu va putea comunica cu celelate componente printr-o comunicare bazată pe evenimente singura metodă de interacțiune pe care o vom putea folosi este metoda de comunicare prin interogare periodică(pooling).Pentru a realiza acest tip de comunicare Componenta va “întreaba” periodic Coordonatorul dacă are de realizat ceva.

3.Funcția StartRăspuns

Dacă Coordonatorul de Tranzacție va trimite unei Componente o cerere de începere a unor operații care fac parte dintr-o anumită tranzacție în care și Componenta respectivă este implicată atunci Componenta,prin intermediul acestei funcții,va fi nevoită să îi raspundă Coordonatorului dacă este pregatită sau nu este pregatită să înceapă tranzacția.

4.Funcția ExecutăTranzacție

Această funcție va trimite o valoare afirmativă sau negativă cu privire la execuția părții de tranzacție pe care Coordonatorul de Tranzacții a solicitat-o unei Componente.

5.Funcția Finalizare

Aceasta funcție la fel ca și funcția de execuție va trimite un răspuns către Coorodonatorul de Tranzacții dacă componenta este deacord sau nu este deacord să finalizeze partea de tranzacție în care este implicată.

3.4 Cazurile de utilizare

3.4.1 Cazul de utilizare pentru Coordonatorul de Tranzacții

Fig.1 Cazul de utilizare pentru Coordonatorul de Tranzacți

Coordonatorul de tranzacții va înregistra prima dată tranzacția pe care a primit-o de la utilizator adăugându-i un identificator unic.Acest identificator unic va fi alocat de Coordonatorul de Tranzacții și trimis înapoi la Componenta de Tranzacții.

Coordonatorul de Tranzacții va avea obligația să informeze și celelalte Componente care vor fi parte activă la această tranzacție să înceapă executarea operațiunilor.

Pe baza răspunsurilor pe care le va primi de la componentele din tranzacția cerută de utilizator,după ce componentele și-au efectuat partea de tranzacție cu succes sau cu esec,Coordonatorul trebuie să se hotarască și să stabilească o decizie finală de comitere sau anulare a tranzacției.

Ultimul pas este finalizarea tranzacției.În acest ultim pas Coordonatorul de Tranzacție asteaptă răspunsul afirmativ sau negativ de comitere a tranzacției de la fiecare Componentă de Tranzacție participantă.

3.5 Cazul de utilizare pentru Componenta Tranzacțională.

Fig.1 Cazul de utilizare pentru Componentă tranzacțională

Componenta tranzacțională va trebuii să realizeze următorii pași :

-Să comunice Coordonatorului tranzacția pe care utilizatorul dorește să o efectueze dar și celealte tranzacții la care respectiva Componentă poate participă.Acest lucru se realizează prin trimiterea unui mesaj de început către coordonator.

-Coordoantorul va trimite un mesaj de confirmare către Componentă în care specifică acesteia că poate să pornească partea ei de tranzacție.

-Componenta pornește tranzacția și realizează operațiile necesare pentru a completa partea tranzacției pe care o are de îndeplinit.

-Componenta trebuie să trimită un mesaj afiramtiv sau negativ de efectuare a părții de tranzacție în care este implicată.

-Ultimul pas este cel de finalizare în care Componenta trimite un mesaj pozitiv sau negativ cu privire la finalizarea părții de tranzacție în care este implicată.

Capitolul 4. Proiectarea în detaliu

4.1 Structura programului

4.1 Structura internă a Coordonatorului de Tranzacții

Fig1. Structura interna de conectare a Coordonatorului de Tranzacții

Pentru fiecare componentă conectată la Coordonatorul de tranzacții se crează un obiect din clasa “PentuConectare”.Acest obiect conține toate informațiile despre Componentă.Cu ajutorul firelor de execuție(threads) va realiza schimbul de mesaje între Coordonatorul de Tranzacții și toate Componentele de Tranzacție care vor lua parte la efectuarea unei tranzacții cerută de utilizator.Conexiunea dintre cele două entități se realizează cu ajutorul unui obiect de tip socket.

4.2 Structura internă pentru Componenta de Tranzacție

Fig.2 Structura internă de conectare pentru Componenta de Tranzacție

Componenta are o structură simplă de conectare formată dintr-un obiect Socket și un obiect Conectare.Transmiterea și primirea de mesaje la fel ca și în cazul Coordonatorului de Tranzacții se realizează cu ajutorul a două fire de execuție.

Obiectul Socket este realizat cu ajutorul funcțiilor NSPR utilizând header-urile

#include <prio.h>; #include <prerror.h>; #include <prnetdb.h>

4.3 Diagrama de secvență

Fig.1 Diagrama de seventă

După cum se observă în diagrama de secventă, comunicarea dintre Coordonatorul de Tranzacții și Componentele Tranzacției care sunt implicate într-o anumită tranzacție se va realiza parcurgând următoarele etape:

Componenta de Tranzactie1 va solicita acordul Coordonatorului de Tranzacții pentru a începe o anumită tranzacție în care va fi implicată și Componenta de Tranzacție2.

Dacă informațiile primite de la Componenta de Tranzacție1 vor fi corecte Coordonatorul de Tranzacții va genera un identificator unic(TID) pentru tranzacția respectivă și îl va trimite într-un mesaj împreună cu acordul de începere a tranzacției,mesaj îndreptat către Componenta Tranzacție.Deasemenea Coordonatorul de Tranzacții va verifica ce alte Componente de Tranzacție mai sunt implicate în tranzacția ID după care le va trimite și lor un mesaj de începere a tranzacției ID.

După ce Componenta de Tranzacție1 și Componenta de Tranzacție2 efectuează operațiile necesare pentru a realiza tranzacția ID fiecare dintre ele va trimite câte un mesaj de STARE către Coordonatorul de Tranzacții în care vor confirma dacă respectivele operații care fac parte din respectiva tranzacție au fost sau nu au fost finalizate cu succes.

În funcție de răspunsul pe care l-a primit Coorodonatorul de Tranzacții de la cele două Componente acesta va lua o decizie dacă va finaliza sau nu tranzacția ID.Dacă răspunsurile primite de la cele două Compontentele de Tranzactie vor fi afirmative atunci va trimite un mesaj către cele două Componente pentru a se asigura că părțile implicate în tranzacția ID sunt deacord cu finalizarea.

Gestionarul de Tranzacții primește mesajul de confirmare din partea participanților la tranzacție și va comite sau va anula tranzacția.

4.4 Diagrama de Clase pentru Coordonatorul de Tranzacții

Sistemul este format din mai multe clase construite cu librăria libnspr de tip NSPR care oferă funcționalități simple :fire de execuție,socluri și elemente de legătură cu clasele la un nivele mai inalt.Canalele de comunicație moștenesc soclurile și firele de execuție,pentru a oferi un control mai avansat al fluxului de mesaje.Peste aceste canale sunt construite serviciile,care deja au functionalități complexe.În aplicația noastră avem două tipuri de servicii,un serviciu Client care reprezintă defapt o “Componenta de Tranzacție” și un serviciu Server care reprezintă “Coordonatorul de Tranzacții”.

În această parte vom prezenta într-un mod mai detaliat clasele componente ale Coordonatorului de Tranzacții.Una dintre cele mai importante clase la acest membru de aplicație este clasa PentruConectare.Această clasă crează un obiect pentru fiecare client care se va conecta la Coordonator pentru a stoca informațiile componentei: tranzacțiile la care poate participa componenta respectivă.Această clasă mostenește clasele Socket și TwinThread deoarece va folosi două fire de execuție: t, t2 care se vor ocupa de primirea și trimiterea measjelor și un socket pentru conectare.Primul fir de execuție se va ocupa cu cititul datelor de pe socket astfel încât mesajele care vor fi primite se vor direcționa către funcția processInMesage() pentru a fi procesate.Al doilea fir de execuție se ocupă cu trimiterea datelor pe socket pentru a ajunge la Componentă.Prima dată se extrage un mesaj primit de la o Componentă dintr-o listă Mutex,acest mesaj trebuie procesat dupa care Coordonatorul de Tranzacții crează un răspuns pe baza mesajului primit.În headerul acestei clase avem construită o structură de tip MesajH pentru mesajele care vor fi trimise către componente.Tot aici există o listă std::list< unsigned int > m_tranzactiiCunoscute unde sunt stocate toate tranzacțiile cunoscute de Coordonatorul de Tranzactii.Pentru fiecare Componenta există cate un obiect PentruConectare.Aceste obiecte sunt puse într-o listă care aparține clasei Conectare.Deasemenea clasa Conectare conține și structura unei componente struct componente(stare; stareTranz; timpulActiunii ).Tot aici am adaugat și structura unei tranzacții care este compusă din:

tranzId(id ul tranzacției)

std::list < componente* > părțileTranzacției(părțile compomponente ale tranzacției

Un obiect care stă la baza transportului de date este derivat din clasa MesajH.Această clasă conține toate setările necesare pentru ca datele să ajungă la destinație.Clasa reprezintă defapt headerul(antetul) mesajului.Acest antet conține subtipul mesajului care poate fi de tip Server(Coordonator de Tranzacții) sau Client(Componentă).Pe lângă subtipul mesajului mai avem și un Id care este un identificator unic,el reprezintă tranzacția la care se adresează mesajul curent.O altă componentă importantă în antetul mesajului este status care conține starea mesajului ce poate lua valoarea de true sau false.Ultima componentă din antetul mesajului este dataSize care face referire la datele din mesaj.

Clasa Conectare moștenește clasele ServerSocket și TwinThread.În această clasă se realizează conectarea.Constructorul clasei crează un socket.La fel ca și clasa Pentru Conectare această clasă folosește două fire de execuție.Primul fir de execuție acceptă noi socketuri și le pune într-o listă de tip Mutex.Rolul celui de-al doilea fir de execuție este acela de a șterge conexiunile moarte.

Clasa ServerSocket moștenește clasa Socket și implementează metode pentru a pune serverul în starea de “ascultare” și pentru a accepta cereri de conexiune.Mai conține și membrul m_port folosit pentru a specifica pe ce port să se pornească ascultarea.Clasa Socket este construită cu ajutorul functilor de tip NSPR gen PR_NewTCP Socket();PR_Send();PR_Recv().

4.5 Diagrama de Clase pentru Componenta de Tranzacție

A doua parte a aplicației este Componenta de Tranzactie.Această componentă este construită pe aceleași principii care au stat la baza construirii Coorodnatorului de Tranzacții. Este formată din mai multe clase construite cu ajutorul librăriei libnspr de tip NSPR care oferă funcții utile pentru construcția firelor de execuție,socluri și mutex.Canalele de comunicație moștenesc soclurile și firele de execuție,pentru a oferi un control mai avansat al fluxului de mesaje.

Clasa cea mai importantă a componentei de tranzacții este clasa Tranzacție care conține toate funcțiile importante pentru realizarea cu success a unei tranzacții.Această clasă conține funcția de pornire Tranzactie(),executare Executare() si finalizare Finalizare() a părții de tranzacție în care este implicată o componentă.Funcția getNotificare() rezolvă problema comunicării,o componentă XPCOM nu poate posta evenimente cătere alte componente.Singura metoda de interacțiune cu alte componente este metoda de comunicare prin interogare periodică numită și pooling această funcție realizează acest lucru.

Clasa Conectare este foarte importantă deoarece se ocupă de partea de conectare a Componentei.Deasemenea adaugă la începutul listei de tip mutex m_outMessageList mesajele aferente fiecărui Id al tranzacțiilor existente pe componenta respectivă astfel Coordonatorul știe ce tranzazcții poate realiza fiecare Componentă în parte dacă se vor conecta mai multe Componente.Structura de schimb de mesaje este identică cu cea din partea Coordonatorului.Se folosesc două fire de execuție,primul fir de execuție se ocupă cu cititul datelor de pe socket astfel încât mesajele care vor fi primite se direcționează către funcția processInMesage() pentru a fi procesate.Al doilea fir de execuție se ocupă cu trimiterea datelor pe socket pentru a ajunge la Coordonatorul de Tranzacții.Prima dată se verifică dacă s-a primit mesaj de la Coordonatorul de tranzacții,acest mesaj trebuie procesat după care Componenta crează un răspuns pe baza mesajului primit.

Clasa ClientSocket moștenește clasa Socket și implementeaza metode pentru a realiza o conexiune cu un server.Această clasă inițiază o cerere de conexiune după care verifică starea soclului.Printre membrii acestei clase se pot menționa următorii: pAddr și m_iPort prin care se specifică adresa și portul la care să se facă conectarea și m_bConnected este utilizat pentru stabilirea stării soclului.

Clasa Thread implementează datele necesare pentru funcționarea unui fir de execuție pe baza funcțiilor din NSPR.Printre datele membru putem aminti m_Thread care este descriptorul firului de execuție și două variabile de tip Boolean m_bRunning și m_bExited utilizate pentru a

semnala starea firului.Funcțiile membru start(),stop() sunt folosite pentru a porni și pentru a opri

firul de execuție.Pentru a lansa un fir de execuție trebuie derivate o clasă din Thread și suprascrisă metoda Run(),instanțiată clasa,apoi se va apela metoda start().Firul de execuție va rula până când metoda Run() își va încheia execuția sau este apelată metoda stop().

Clasa TwinThread încapsulează două fire de execuție,unul prin moștenirea clasei Thread,iar al doilea printr-un membru de tipul clasei ThreadRunner care moștenește la rândul ei clasa Thread.Metodele t2start().t2stop(),t2isRunning și t2isExited() se folosesc pentru a porni,opri,respectiv interoga starea celui de-al doilea fir de execuție.

Clasa Socket încapsulează funcționalitatea unui soclu utilizat pentru a stabili o conexiune TCP/IP între Coordonatorul de Tranzacții și Componentă.Funcțiile importante din această clasa sunt getData() si sendData(),aceste doua funcții sunt folosite pentru a recepționa și pentru a trimite date pe soclu.

Clasa Mutex la fel ca și clasele Socket si Thread sunt construite cu ajutorul unor funcții speciale din librăria de tip NSPR.Aceste funcții sunt PR_Lock construiește o încuietoare(lock),PR_Unlock eliberează o încuietoare(lock) specificată.Dacă se încearcă să se deschidă o încuietoare(lock) care nu este blocată atunci va rezulta o eroare.Funcția PR_DestroyLock este folosită pentru a distruge o încuietoare.

4.6 Funcțile utilizate în Componenta de Tranzacții

1. ÎnregistreazăTranzacția(string ID) // Înregistrează o nouă tranzacție ID

{

string getT.Id()

…..

}

2. getNotificare(ID) //Interoghează periodic Coordonatorul pentru a vedea ce trebuie făcut

{

0 – nu s-a intamplat nimic

1 – start tranzactie

2 – executat?

3 – finalizare OK

4 – finalizareERR

3. StartTranzactie() //salvează starea inițială și începe să efectueze operațiile tranzacției

{

salvează starea inițială.

….

}

4.Executat(bool) //trimite Coordonatorului o valoare de tip boolean pentru a confirma sau infirma executarea tranzacției.

{

……

}

5.Finalizare(bool stare) // Finalizarea tranzacției…comisă sau anulată

{ daca stare este true atunci s-a comis tranzacția

daca stare este false atunci trebuie incarcată starea inițială }

4.7 Protocolul de Comunicare

La nivelul de aplicații,datele utilizatorului sunt încapsulate cu un antet de aplicație într-un mesaj de aplicație.

Fig.1 Exemplu de Mesaj aplicație.

Fig.2 Definirea antetului aplicației și datele utilizatorului.

Figura 2 reprezintă antetul mesajului de comunicare definit de către programator cu scopul de a transmite mesaje între componentă-coorodnator sau invers pentru realizarea etapelor necesare efectuării unei tranzacții.Lungimea mesajului este de 6 octeți.

Acest protocol este împărțit în 3 bucăți.Prima parte definește “Tipul” mesajului care poate fi interpretat de Client(Componentă) sau Server(Coordonator Tranzacții)

-Tipurile de mesaje :

MTT_ÎNREGISTREAZĂ_TRANZACȚIE = 1, // Componenta înregistrează tranzacție

MTT_CERERE_START_TRANZACȚIE, //Componenta face o cerere pentru început

Tranzacție

MTT_START_TRANZACȚIE, //Coordonatorul acceptă start tranzacție

MTT_START_RĂSPUNS, //Componenta răspunde la start tranzacție

MTT_EXECUTĂ_TRANZACȚIE, //Coordonatorul întreabă Componenta dacă s-a

executat tranzacția

MTT_EXECUTĂ_RĂSPUNS, //Răspunsul Componentei pentru Executare

MTT_FINALIZARE_TRANZACȚIE, //Coordonatorul întreabă Componenta dacă a

finalizat tranzacția

MTT_FINALIZARE_RĂSPUNS, //Răspuns finalizare adevărat/fals

-A doua componentă pentru antetul de mesaj este “Stare mesaj”.Cu această componentă se poate verifica starea de succes/fail a mesajului trimis.Componenta este de tip boolean si poate lua valorile:

1: pentru true

0: pentru false

-A treia componentă pentru atentul de mesaj este ID-ul.Această componentă marchează identificatorul unic al tranzacției la care tipul mesajului face referire.

Exemplu de trimitere mesaj :

………………..

4.8 Utilizarea librăriei nspr.lib

Aplicația folosește bibleoteca nspr.lib.Prin intermediul funcțiilor membre ale acestei bibleoteci atât serverul cât și clientul construiesc partea de socket incluzând următoarele header-uri #include<prio.h> #include <prerror.h> #include <prnetdb.h> cu următoarele funcții:

PRFileDesc :

Este folosită să reprezinte descrierea unui socket

Socket::Socket(void* sock)

{

setSocket((PRFileDesc*)sock);

}

PR_NewTCP Socket() :

Crează un nou IPv4 TCP socket

Dacă se completează cu succes atunci este creat un pointer către obiectul PRFileDesc

IPv4 este a patra revizuire a IP(Internet Protocol).Este un protocol de conectivitate în rețea pentru realizarea transferului pachetelor(secvențe de pachete).Aceste pachete sunt “buffered” și “queued” în funcție de traficul rețelei respective.

bool ServerSocket::makeSocket( void )

{

PRFileDesc* sock = PR_NewTCPSocket();

if( sock == NULL )

{

return false;

}

PR_Close()

Închide un socket

if ( (status<0) && (m_socket !=NULL) )

{

PR_Close (m_socket);

m_socket = NULL;

}

PR_Recv()

Primește bytes de la un socket conectat

readed = PR_Recv(m_socket, &buffer[total],bufferSize – total, 0, PR_INTERVAL_NO_TIMEOUT );

– m_socket este un pointer către un obiect PRFileDesc reprezentând un socket

– &buffer[total] este un pointer către bufferul care ține datele primite

– bufferSize – total este dimensiunea bufferului în bytes

– (flags)0 acest parametru trebuie să fie tot timpul zero.

PR_Send()

Trimite bytes de la un socket conectat.

sended = PR_Send (m_socket,&buffer[total],bufferSize – total, 0, PR_INTERVAL_NO_TIMEOUT);

PR_NetAddr

Este o structură folosită împreună cu funcțiile de manipulare pentru a specifica o adresa în rețea

PRNetAddr socketInfo;

PR_InitializeNetAddr()

PR_InitializeNetAddr inițializează sau reinițializează o adresă din rețea.Depozitarea adresei de rețea este alocată si ramâne responsabilitatea clientului apelant.

PR_InitializeNetAddr(PR_IpAddrAny, m_uiPort, &socketInfo)

PR_IpAddrAny este valoarea care se atribuie adresei IP din rețea.

m_uiport este valoarea portului unde este atribuită structura

&socketInfo este un pointer către structura PRNetAddr

PR_Bind():

Cu ajutorul acestei funcții serverul leagă socketul la un port cunoscut

Această funcție are următorii parametrii:

– un pointer către un obiect PRFileDesc

– un pointer către un obiect PRNetAddr care reprezintă specificarea unei adrese de rețea

if (PR_FAILURE == PR_Bind(sock, &socketInfo))

{

printf("%d",PR_GetError());

return false;

PR_Listen()

Această funcție ascultă/asteaptă conexiuni de la un socket specificat

Ea are următorii parametrii:

un pointer către un obiect PRFileDesc reprezentând socketul care va fi folosit pentru a asculta conexiuni noi

numărul maxim,lungimea coadei de așteptare a conexiunilor

if (PR_FAILURE == PR_Listen(sock, 10))

return false;

PR_Accept()

Acceptă o conexiune de la un socket specificat

Această funcție are următorii parametrii

-un pointer către un obiect PRFileDesc reprezentând socketul unde apelantul este hotărât să accepte conexiuni noi

-un pointer către o structură de tip PRNetAddr.In “output” această structură conține adresa entității conectate

-o valoare de tipul PRIntervalTime care specifică intervalul de timp în care trebuie să se completeze operația de acceptare

Dacă acceptarea conexiunii a fost realizată cu succes această funcție va returna un pointer către o nouă structură PRFileDesc reprezentând conexiunea nou acceptată

sock = PR_Accept( m_socket, &socketAddress, PR_INTERVAL_NO_TIMEOUT );

}

4.9 Crearea unei componente XPCOM folosind cod in C++

1. Se descarcă Gecko SDK pentru sistem,care se poate gasi la http://ftp.mozilla.org/pub/ mozilla.org/mozilla/releases/mozilla1.7/. , urmând a fi extras într-un fișier local.

2. Se crează un GUID pentru interfața principala, pentru Windows se poate folosi guidgen, iar pentru Linux se utilizează uuidgen.

3. Se crează fișierul definirii interfeței –IMyTransaction.idl.

4. Se generează header-ul interfeței și fișierul typelib înafara fișierului care definește interfața, folosind utilitarul xpidl pe care primit cu Gecko SDK. Se inlocuiește în comenzile următoare “_DIR_” cu întreaga cale către xpcom/idl întâlnită sub directorul de bază al Gecko SDK:

xpidl -m header -I_DIR_ IMyTransaction.idl va crea fișierul-header IMyTransaction.h.

xpidl -m typelib -I_DIR_ IMyTransaction.idl va crea fișierul-typelib IMyTransaction.xpt.

5. Header-ul interfeței IMyTransaction.h conține șabloane utile pentru la crearea fișierului header al componentei și al fișierului implementație. Se pot copia si lipi șabloanele pentru a crea aceste fișiere, fiind nevoie doar de schimbarea numelui componentei.

6). Se crează fișierul header al componentei – MyTransaction.h. Acest lucru se începe prin inserarea codului de protectie dubla-includere(#ifndef _MY_TRANSACTION_H_….), după care se adaugă #include "IMyTransaction.h" pentru a include defeniția interfeței. Apoi se crează un GUID pentru componentă, la care se adaugă liniile următoare, care definesc numele componentei, ID-ul si GUID:

#define MY_TRANSACTION_CONTRACTID "@mydomain.com/XPCOMSample/MyComponent;1”

#define MY_TRANSACTION_CLASSNAME " Tranzactie"

#define MY_TRANSACTION_CID GUID componentei

7) Se crează fișierul implementație al componentei – MyTransaction.cpp. Se daugă #include "MyTransaction.h" pentru a include definițiile noii componente.

8) Se crează fișierul definiției modulului – MyTransactionModule.cpp. Se adaugă #include "nsIGenericFactory.h" pentru a include definițiile Mozilla GenericFactory #include "MyTransaction.h" pentru a include definițiile componentei, NS_GENERIC_FACTORY_CONSTRUCTOR(MyTransaction) pentru a defini constructorul pentru noua componenta,

static nsModuleComponentInfo components[] =

{

{

MY_TRANSACTION_CLASSNAME,

MY_TRANSACTION_CID,

MY_TRANSACTION_CONTRACTID,

MyTransactionConstructor,

} }

pentru a defini numele clasei, ID-ul și GUID-ul componentei și NS_IMPL_NSGETMODULE ("MyTransactionModule", components) pentru a exporta informațiile de mai sus catre Mozilla.

Compilarea componentei

Se înregistrează noua componentă în Mozilla. Se copiază fișierele MyTransaction.dll și IMyTransactuib.xpt în directorul cu componentele Mozilla. În Windows, acest director se găsește, în general, la: C:\Program Files\Mozilla Firefox\components,.Se rulează comanda regxpcom primită cu Gecko SDK pentru a înregistra noua componentă,se șterg fișierele xpti.dat și compreg.dat din directorul de profil al Mozilla, iar acestea vor fi compilate automat de catre Mozilla data viitoare cand va fi restartat.

Se testează noua componentă ,începând prin restartarea Mozilla, după care se deschide fișierul MyTranzacțieTest.html

Înregistrarea componentei XPCOM

Componentele se crează și se înregistrează cu ajutroul setului de unelte Gecko SDK astfel:

se crează un .dll din proiectul făcut în visual C++;

se crează un fișier .idl care conține un UUID (universal unique identifier) și conține funcții pentru a prelua variabilele din .dll prin intermediul interfețelor de tip nsiSupport și Iunknown (interfață din care este derivată interfața XPCOM);

cu ajutorul utilitarului xpidl.exe din Gecko se crează header-ul .h și librăria de tipuri .xpt a interfeței componentei;

se crează header-ul componentei care conține: includerea header-ului interfeței; Contract ID-ul explicat în „Platforma Mozilla. Arhitectură”; numele componentei și un GUID (General Unique Identifier);

se crează o interfață JavaScript de tipul celei de mai jos;

se copiază fișierele .xpt și .dll în directorul de componente al aplicației Mozilla;

se rulează aplicația Gecko regxpcom.exe pentru a înregistra o nouă componentă;

după restartul browser-ului Mozilla, se poate rula JavaScriptul pentru a rula aplicația.

Capitolul 5. Utilizarea componentei

Pentru testarea aplicației realizate, s-a construit o altă aplicație, o pagina Web. Această aplicație este realizată cu ajutorul unor elemente de bază ale Limbajului HTML, precum și cu anumite elemente ale Limbajului Java Script.

Limbajului HTML

HTML (Hypertext Markup Language) este un limbaj creat în scopul de a descrie, în mod text, formatul paginilor Web; fișierele create în acest limbaj vor fi interpretate de navigatoare, care vor afișa paginile în forma dorită (cu texte formatate, liste, tabele, formule, imagini, hiperlegături, obiecte multimedia.

Limbajul JavaScript

JavaScript este unul din cele mai populare limbaje de programare "client side", pentru crearea paginilor WEB. Este un limbaj de tip "interpretor" fiind recunoscut de majoritatea browser-elor, cum ar fi: Internet Explorer, Mozzila Firefox, Opera etc. A fost dezvoltat de Sun Microsystems fiind asemănător cu C , C++

JavaScript a fost proiectat sa ofere noi facilități pentru interacțiune cu paginile HTML.

Este o unealtă de programare pentru design-erii de WEB.

JavaScript este un limbaj de scriptare interpretat.

Este un limbaj simplu și ușor de folosit.

Instrucțiunile acestui limbaj sunt direct inserate în paginile HTML.

JavaScript este un limbaj interpretat. (programele sunt executate fără a fi compilate).

Ce se poate face cu JavaScript ?

Se pot insera texte dinamice în pagini WEB

JavaScript poate reacționa la diverse evenimente

JavaScript poate scrie și citi elemente HTML

JavaScript se poate folosi la validări de date pe partea clientului

Poate detecta browser-ul clientului

Capitolul 6. Concluzii și dezvoltări ulterioare

Prin realizarea acestui proiect s-a evidențiat facilitățiile oferite de programarea distrbuită bazată pe componente pentru realizarea unor tranzacții.Acest stil de programare cu ajutorul componentelor XPCOM facilitează dezvoltarea unor aplicații care pot fi împărtite în mai multe bucătii pentru o întelegere mai usoară a programului de către o gamă largă de utilizatori fără a fi nevoie obligatoriu de programatorul care a conceput respectiva aplicație.Această perspectivă de concepere a aplicațiilor are un mare avantaj deoarece componentele rezultate din aplicație pot fi folosite în mai multe programe.

Bibliografie

[1] George Couloris,Distributed Systems:Concepts and Design,Ed. Pearson Education 2001;

[2] Andrew S. Tanebaum, Maarten van Steen – Distribuited Systems,principles and paradigms’Prentice Hall 2002

[3] Andrew S.Tanenbaum – “Rețele de calculatoare. Ediția 4”, Ed. Byblos 2004;

[4] Dr.Kris Jamsa & Lars Kandler – Totul despre C si C++ Manual fundamental de programare;Ed. Teora 2007;

[5] D. Turner, I. Oeschger, Creating XPCOM Components, Brownhen Publishing, 2003;

[6] http://en.wikipedia.org/;

[7] http://mb.eschew.org/16 – XPCOM Objects ;

[8] http://inf.ucv.ro/courses/CB3105/resources/Introducere%20in%20UML.pdf;

[9] http://www.cs.cmu.edu/~mihaib/articles/tranzactii/tranzactii-html.html;

[10] http://thor.info.uaic.ro/~pnoro/NET/limbaj/18%20fire%20de%20executie.pdf;

[11] http://fpce9.fizica.unibuc.ro/telecom/transm_ctrl_prot_tcp.htm;

[12] http://freedownloadbooks.net/;

Similar Posts