Aplicatia Java Bazata pe Servlet Uri, cu Comunicatie Wireless

APLICATIA JAVA BAZATA pe servlet-uri, cu comunicatie WIreless

1. INTRODUCERE

1.1 Tehnologia Java

1.2 Avantajele oferite de J2EE

1.3 Tehnologii concurente – Common Gateway Interface

1.4 Aplicatiile multimedia distribuite

1.4.2 Container-ul J2EE

1.5 Servlet-uri

1.6 Compararea tehnologiilor

2. TEHNOLOGIA SERVLET

2.1 Apelarea servlet-urilor2.1.1 Accesarea directa folosind cereri HTTP

2.1.2 Accesarea prin SSI (Server Side Include)

2.2 Structura servlet-urilor

2.2.1 API-ul

2.2.2 Ciclul de viata al unui servlet

2.2.3 Persistenta instantei (instance persistence)

2.2.4 Servlet-uri si fire de executie

2.2.5 Reincarcarea servlet-ului

2.2.6 Init si destroy

2.2.7 Modelul single thread

2.2.8 Caching la nivel client

3. EXTRAGEREA INFORMATIEI

3.1 Informatia la nivelul servlet-ului

3.2 Informatia la nivel de server

3.2.1 Extragerea informatiilor despre server

3.2.2 Prevenirea rularii neautorizate a unui servlet

3.2.3 Determinarea versiunii servlet-ului

3.3 Informatia la nivel de client

3.3.1 Accesarea de informatii privind masina client

3.3.2 Restrictionarea accesului

3.3.3 Accesarea informatiilor despre utilizator

3.3.4 Parametrii pe cerere (Request Parameters)

4. IMPLEMENTAREA SESIUNILOR

4.1 Autentificarea user-ului

4.2 Ascunderea campurilor unor formulare

4.3 API-ul sesiunii

4.3.1 Ciclul de viata al unei sesiuni:

4.3.2 Filtrarea cererii sau a raspunsului

5. SECURITATE

5.1 Autentificarea HTTP

5.1.1 Configurarea autentificarii HTTP

5.2 Certificatele digitale

5.3 Protocolul SSL – Secure Sockets Layer

5.4 Securitatea la nivelul clientului

5.5 Configurarea SSL

5.5.1 Configuraerea autentificarii SSL

5.5.2 Accesarea informatiilor de autentificare SSL

6. COMUNICATIA APPLET – SERVLET

7. JAVA SI TEHNOLOGIA WIRELESS

7.1 Tehnologia J2ME

7.2 Midlet-uri

7.3 De ce Wireless cu Java?

8. APLICATIE SERVLET CU COMUNICATIE WIRELESS

8.1 Aplicatia Web

8.1.1 Interactiunea si consultarea catalogului de produse

8.1.2 Afisarea produselor in urma diferitelor tipuri de cautari

8.1.3 Interactiunea dintre client si cosul de cumparaturi virtual

8.1.4 Comandarea produselor

8.1.5 Baza de date

8.1.5.1 – Legaturile bazei de date

8.1.5.2 ProductsDBO (conexiunea aplicatie – baza de date)

8.2 Aplicatia Wireless

8.2.1 Accesarea, tratarea si incheierea comenzilor active

8.2.2 – Inserarea sau modificarea unui produs in baza de date Mysql

BIBLIOGRAFIE

1. Introducere

Lucrarea de fata isi propune sa prezinte doua tehnologii bazate pe tehnologia Java, care imbinate ofera o alternativa utila si eficienta la celelalte tool-uri prezente pe piata de soft. Aceste tehnologii sunt: Servlet-urile (J2EE) si MIDlet-urile(J2ME).

Aplicatia propriu-zisa este formata din doua parti : -modulul Web

-modulul Wireless

– modulul Web: reprezinta un depozit virtual cu produse farmaceutice, in care clientii pot efectua comenzi on-line.

– modulul Wireless: reprezinta o aplicatie ce poate rula pe dispozitivele mobile si care permite reactualizarea sau popularea bazei de date (Mysql).

Scenariul in care poate fi implementata aplicatia: se poate sa existe un depozit ale carui produse sunt disponibile on-line si pe care clientii le pot comanda si trimite la diferite adrese. Acest depozit ofera posibilitatea ca produslele comandate sa fie livrate direct de agentii de distributie , care pe baza unui soft instalat pe telefoanele mobile, pot accesa si incheia comenzile ce sunt active sau pot introduce noi produse in baza de date.

1.1 Tehnologia Java

In primul rand, prima intrebare care se pune este: de ce Java? Java este o tehnologie inovatoare lansata de compania Sun Microsystems in 1995, care a avut un impact remarcabil asupra intregii comunitati a dezvoltatorilor de software, impunandu-se prin calitati deosebite cum ar fi simplitate, robustete, securitate¸ dar in primul rand prin portabilitate. Astfel, acest limbaj este independent de platforma pe care este instalat, el ruland fara a fi modificat si recompilat pe diferite sisteme cum ar fi Windows, Linux, Apple, etc. Aceasta performanta este atinsa datorita faptului ca programele, odata compilate, genereaza cod masina care nu ruleaza direct pe procesorul platformei, ci pe masina virtuala. Aceasta este practic un procesor virtual care converteste programul astfel incat sa poata fi inteles de catre procesorul gazda, oricare ar fi arhitectura acestuia, existand masini virtuale pentru orice platforma.

Limbajul de programare Java se foloseste pentru dezvoltarea unor tehnologii aplicabile intr-o gama larga de domenii de activitate. Aceste tehnologii au fost grupate in asa numitele platforme de lucru ce reprezinta seturi de biblioteci (API- Application Programming Interface) , precum si diferite programe utilitare specifice:

J2SE- Standard Edition:

Reprezinta platforma ce sta la baza tuturor aplicatiilor Java fiind practic piatra de temelie a limbajului. De asemenea, aici se ofera suport pentru crearea de aplicatii independente si de appleturi.

J2EE-Enterprise Edition:

Ofera API-ul necesar dezvoltarii de aplicatii complexe ce trebuie sa ruleze pe sisteme de calcul mari, cu suport pentru dezvoltare, distribuire si management la nivel de server Web. Un avantaj al acestei tehnologii este simplificarea conectivitatii dintre aplicatia propriu-zisa si celelalte parti componente ale sitemului creat cum ar fi serverul de baze de date, serverul Web, telefonul mobil sau alte device-uri.

J2ME-Micro Edition:

Permite simplificarea crearii de programe pentru dispozitivele mobile, acestea putand fi rulate eficient in conditiile in care resursele hardware sunt mici.

1.2 Avantajele oferite de J2EE

In trecut, limbajul Java oferea suport pentru aplicatiile Web doar prin intermediul unor mici programe numite Applet-uri ce pot fi introduse in codul HTML si rulate intr-un browser Web de oricine avea acces la internet. Dezavantajul acestora il constituie capabilitatile limitate de interactune cu utilizatorul, comunicarea greoaie cu alte sisteme dar problema principala a acestora o reprezinta timpul necesar transferului si compilarii. Creatorii limbajului au facut eforturi serioase privind acest aspect asfel incat codurile binare sa fie cat mai compacte iar masininile virtuale sa ofere un bogat set de clase reducand marimea codului de transferat. Cu toate acestea, in cazul in care se foloseste o conexiune lenta la internet durata pornirii unui applet de 100Kb poate duce pana la un minut. Odata cu introducerea pe piata a tehnologiei J2EE, se pot crea aplicatii server complexe care ofera deasemenea portabilitate maxima. Este evident faptul ca, daca aplicatia poate rula pe mai multe sisteme fara a modifica codul, aceasta devine foarte rentabila pentru piata careia i se adreseaza prin scaderea costului de implementare. Tehnologia orientata spre aplicatiile server ofera si proprietati intrinseci cum ar fi: gestiunea eficienta a memoriei, conversia sigura de tip type-safety, tratarea exceptiilor si programearea pe fire de executie independente (multi-threading).

Aplicatiile server trebuie sa ruleze fara întrerupere, pe durate mari de timp iar aparitia unor probleme cu memoria, poate cauza probleme serioase. Java nu permite aparitia unor astfel de erori, programatorul nu trebuie sa se ocupe de gestiunea memoriei, deci aceasta problema este evitata. Conversia sigura de tip „type-safety” si verificarea limitelor tablourilor „bounds checking” în timpul rularii elimina multe erori de accesare gresita (si neautorizata) a memoriei.

La aplicatiile server mai pot apare mici erori (bugs), care sunt greu de depistat. În acest caz, tratarea exceptiilor în Java poate fi foarte folositoare, deoarece prinde si arunca exceptia si asfel utilizatorul este imediat informat prin log. Astfel prin afisarea unei stive de erori, el poate determina locul unde a aparut problema (stack-trace), astfel încât ulterior se poate analiza cauza care a generat eroarea.

Din punct de vedere al programarii concurente, problema esentiala pentru aplicatiile server, se poate evidentia ca acest aspect este foarte bine tratat de libaj care il face ideal pentru sisteme intens concurente.

1.3 Tehnologii concurente – Common Gateway Interface

Common Gateway Interface reprezinta standardul folosit pentru interactiunea dintre clientul Web si serverul Web. Un program CGI, numit si script se executa pe serverul Web fie in mod explicit (apelat din cadrul paginii printr-o cerere explicita ), fie prin preluarea informatiilor aflate in cadrul campurilor unui formular interactiv sau coordonatelor unei zone senzitive (image map). Acest standard confera interactivitate paginilor Web, documentele HTML putand astfel sa-si modifice in mod dinamic continutul si sa permita prelucrari statice de date.

In timpul unei comunicatii intre browser si server, programul va realiza o tranzactie HTTP. Scenariile CGI rezida pe calculatorul server, permitand astfel comunicarea directa intre server si programe. Aceasta comunicatie ofera posibilitatea scenariului CGI sa receptioneze date in mod dinamic si sa transfere aceste date catre server. O aplicatie CGI poate fi scrisa în orice limbaj de programare, în general cel mai des sunt folosite limbajele C si Perl. CGI foloseste variabile de mediu ca sa transmita parametrii aplicatiilor externe (de ex. QUERY_STRING, PATH_INFO). Utilizarea CGI are însa câteva dezavantaje. Cea mai importanta dintre ele este performanta scazuta, deoarece pentru fiecare cerere trebuie creat un proces separat, ceea ce duce la întârzieri. Un alt dezavantaj este dependenta de o anumita platforma. Cu toate ca standardul CGI este independent de limbajul de programare, deoarece aplicatiile CGI sunt scrise pentru a rula pe un calculator pe care ruleaza un server HTTP ele vor fi dependente de aceasta platforma, iar ca sa ruleze pe un sistem diferit aplicatiile trebuie modificate. Tot la capitolul deficiente se poate adauga si complexitatea interactiunii dintre doua scripturi CGI care ruleaza pe acelasi server.

Un alt standard, dezvoltat ca o extensie pentru CGI este FastCGI. Acesta foloseste procese persistente pentru a rula aplicatii externe, deci în acest caz nu mai este nevoie sa se creeze un proces separat pentru fiecare cerere receptionata. Totusi, daca avem o comunicatie ce impune un transfer mare de date între serverul Web si aplicatia externa, atunci poatem avea o scaderea semnificativa a performantelor datorita timpului necesar pentru crearea si distrugerea de procese .

Pentru a rezolva problemele de performanta, unii producatori de servere Web au dezvoltat interfete de programare în limbajul C/C++ (de exemplu, Netscape cu NSAPI, Microsoft cu ISAPI). Aceste interfete extind direct serverul Web la un nivel inferior, modulele C ruland în acelasi proces ca si serverul. Dezavantajele acestei abordari sunt dependenta de interfata respectiva si de limbajul de programare, precum si complexitatea si lipsa de securitate. Modulele de extensie ruland în acelasi spatiu de adresare cu serverul, daca apare o eroare în extensia C, atunci e posibil ca tot serverul sa cada. O alternativa la aceste solutii este Java, cu programele ce utilizeaza tehnologia servlet.

1.4 Aplicatiile multimedia distribuite

Platforma J2EE foloseste modelul de aplicatie multinivel distribuit pentru solutiile complexe de dezvoltare. Logica aplicatiei este divizata in mai multe componente, in concordanta cu functiile acesteia iar diferitele componente care fac parte din aplicatia J2EE sunt instalate pe diferite sisteme depinzand de nivelul de care apartine in mediul multinivel (multitired architecture). Fig 1. evidentiaza doua aplicatii „multitired” cu partile lor componente:

-Componentele nivelului client care ruleaza pe masina client.

-Componentele nivelului Web care ruleaza pe serverul Web.

-Componentele nivelului de logica care ruleaza deasemenea pe serverul Web.

-Softwareul sistemului de informatii enterprise (Enterpri. Cu toate ca standardul CGI este independent de limbajul de programare, deoarece aplicatiile CGI sunt scrise pentru a rula pe un calculator pe care ruleaza un server HTTP ele vor fi dependente de aceasta platforma, iar ca sa ruleze pe un sistem diferit aplicatiile trebuie modificate. Tot la capitolul deficiente se poate adauga si complexitatea interactiunii dintre doua scripturi CGI care ruleaza pe acelasi server.

Un alt standard, dezvoltat ca o extensie pentru CGI este FastCGI. Acesta foloseste procese persistente pentru a rula aplicatii externe, deci în acest caz nu mai este nevoie sa se creeze un proces separat pentru fiecare cerere receptionata. Totusi, daca avem o comunicatie ce impune un transfer mare de date între serverul Web si aplicatia externa, atunci poatem avea o scaderea semnificativa a performantelor datorita timpului necesar pentru crearea si distrugerea de procese .

Pentru a rezolva problemele de performanta, unii producatori de servere Web au dezvoltat interfete de programare în limbajul C/C++ (de exemplu, Netscape cu NSAPI, Microsoft cu ISAPI). Aceste interfete extind direct serverul Web la un nivel inferior, modulele C ruland în acelasi proces ca si serverul. Dezavantajele acestei abordari sunt dependenta de interfata respectiva si de limbajul de programare, precum si complexitatea si lipsa de securitate. Modulele de extensie ruland în acelasi spatiu de adresare cu serverul, daca apare o eroare în extensia C, atunci e posibil ca tot serverul sa cada. O alternativa la aceste solutii este Java, cu programele ce utilizeaza tehnologia servlet.

1.4 Aplicatiile multimedia distribuite

Platforma J2EE foloseste modelul de aplicatie multinivel distribuit pentru solutiile complexe de dezvoltare. Logica aplicatiei este divizata in mai multe componente, in concordanta cu functiile acesteia iar diferitele componente care fac parte din aplicatia J2EE sunt instalate pe diferite sisteme depinzand de nivelul de care apartine in mediul multinivel (multitired architecture). Fig 1. evidentiaza doua aplicatii „multitired” cu partile lor componente:

-Componentele nivelului client care ruleaza pe masina client.

-Componentele nivelului Web care ruleaza pe serverul Web.

-Componentele nivelului de logica care ruleaza deasemenea pe serverul Web.

-Softwareul sistemului de informatii enterprise (Enterprise information system-EIS) ce ruleaza pe serverul EIS.

Fig.1 – Aplicatii multinivel

Cu toate ca aplicatiile J2EE pot fi pe trei sau patru nivele , se considera ca fac parte dintr-un sistem pe trei nivele deoarece distribuirea aplicatiilor este facuta pe trei locatii diferite: masina client ,masina server si sitemul de baze de date.

1.4.1 Componentele J2EE:

Asa cum se observa din Fig.1 aplicatiile J2EE sunt formate din mai multe parti componente. O componenta este o unitate software functionala, de sine statatoare care comunica cu celelalte parti. Sunt definite urmatoarele componente:

-Aplicatiile client si applet-uri – ruleaza la nivelul client.

-Servlet-urile si paginile JSP – componente Web ce ruleaza pe server.

-Enterprise JavaBeans (EJB) – componente logice ce ruleaza pe server.

Toate acestea sunt scrise in Java si sunt compilate si rulate in acelasi mod ca oricare alt program, diferenta esentiala fata de clasele Java standard fiind data de modul de distribuire.

Componentele nivelului client:

Pot exista atat clienti Web cat si clienti de aplicatie.

Clientul Web: este format din doua parti (1) pagini web dinamice ce contin programe interpretate (HTML, XHTMLE,XML,etc), generate de componentele ce ruleaza la nivelul Web si (2) browserul web care practic interpreteaza aceste limbaje. De obicei clientul nu face cereri catre baza de date si nu executa o logica complexa, aceste operatii dificile fiind facute de servlet sau de EJB, unde se pot pune conditii suplimentare de securitate si viteza de calcul.

Clientul de aplicatie: ruleaza pe masina client si ofera o modalitate prin care userii pot folosi interfete grafice complexe care nu pot fi generate de limbajele interpretate. Aceste interfete sunt create folosind pachetele dedicate pentru GUI (Graphical User Interface) cum ar fi Swing sau AWT(Abstract Window Toolkit). Aceste aplicatii acceseaza direct nivelul logic ,dar daca cerintele aplicatiei o justifica, se pot deschide si conexiuni HTTP pentru o comunicare cu un anumit servlet.

In Fig. 2 se evidentiaza diferitele elemente ce compun nivelul client. Clientul comunica cu nivelul logic fie direct, fie in cazul unui browser, prin transefer de date catre servlet sau JSP. Astfel aplicatia J2EE poate sa foloseasca atat un broser cat si o aplicatie client. Pentru a decide care metoda este mai avantajoasa, trebuie sa se faca un compromis intre a se tine functionarea cat mai mult la nivel de client si a avea acces la o comunicare cat mai directa cu serverul.

Fig.2 – Componentele nivelului client

Componentele nivelului Web:

Acestea pot fi atat servlet-uri cat si pagini create folosind tehnologia JSP. Servlet-urile sunt clasa Java care proceseaza dinamic cereri si construiesc raspunsuri. JSP sunt documente bazate pe text care se executa ca si servlet-urile dar care permit o abordare asemanatoare cu cea folosita pentru a crea continut static (pagini HTML). Paginile HTML si applet-urile sunt integrate in componentele Web in momentul asamblarii rezultatului final dar nu sunt considerate componenete Web asa cum si logica utlizata la nivel de server EIS poate fi integrata in componentele Web dar nu poate fi considerata ca facand parte din acestea.

Componetele nivelului de logica:

Aceste componente executa logica specifica unui domeniu de actvitate pentru care aplicatia este conceputa cum ar fi domeniul bancar, financiar sau vanzari. Fig.3 prezinta cum nivelul logic preia informatia de la client, o proceseaza (daca este nevoie) si o trimite apoi la nielul EIS pentru stocare de masa. Deasemenea acest nivel preia si informatia de la EIS , o prelucreaza si o retransmite clietului.

Fig.3 – Transferul de informatie EIS

1.4.2 Container-ul J2EE

In conditii normale aplicatiile multinivel sunt destul de greu de dezvoltat deoarece ele implica multe linii de cod complicate pentru manipularea tranzactiilor, a firelor de executie sau a resurselor. Arhitectura J2EE independenta si structurata pe componente permite scrierea usoara a codurilor deoarece logica este separata in componente reutilizabile. Ca o completare serverul J2EE ofera servicii fundamentale sub forma de containere pentru fiecare tip de componente. Deoarece programatorul nu este constrans sa dezvolte aceste servicii, ele fiind furnizate de API, se ofera posibilitatea concentrarii doar pe dezvoltarea logicii ce personalizeaza apliatia respectiva.

Un container este o interfata intre o componenta si o functionalitate a unei platforme de nivel inferior care suporta acea componenta. Inainte ca o componenta de oricare tip sa fie executata, aceasta trebuie intai asamblata intr-un modul J2EE adica impachetata intr-un conteiner. Acest proces este ilustrat in Fig.4.

Fig.4 – Tipuri de containere

Tipuri de containere:

-Server Web: partea in care ruleaza aplicatia la nivel Web si care ofera conteinerul Web si EJB.

-Conteiner Web: administreaza componentele servlet si JSP.

-Conteinerul EJB: tine componentele de logica.

-Conteinerul de aplicatie client.

-Contenerul Applet: administreaza rularea applet-ului si este format dintr-un browser si un Plug-In Java, ambele ruland la nivel de client.

1.5 Servlet-uri

De indata ce tehnologia Web a luat amploare s-a simtit imediat nevoia pentru dezvoltarea de continut dinamic. Applet-urile foloseau platforma client pentru a satisface aceasta nevoie dar ele fiind foarte limitate, dezvoltatorii s-au orientat catre nivelul de server. Initial scripturile CGI reprezentau principala tehnologie pentru dezvoltare de continut dinamic, desi ele aveau o serie de neajunsuri majore cum ar fi dependenta de platforma si lipsa de scalabilitate. Pentru a evita aceste neajunsuri a fost creata tehnologia Servlet ca o solutie portabila si usor de implementat.

Un servlet este o clasa Java folosita pentru a extinde capabilitatile serverelor ce includeau aplicatii accesate prin modelul cerere-raspuns. O cerere simpla poate fi afisarea paginii de welcome sau mai complicata, afisearea cosului de cumparaturi. Cu toate ca un servlet poate raspunde la orice tip de cerere, ei sunt folositi de obicei pentru a largii capabilitatea unei aplicatii de pe server. Pentru aceste aplicatii API-ul contine clase specifice protocolului HTTP, acestea fiind grupate in doua pachete: javax.servlet si javax.servlet.http. Toti servletii trebuie sa implementeze interfata Servlet in care sunt declarate metodele ce definesc ciclul de viata al acestuia.

Unul din scopurile uzuale in care este folosita aceasta tehnologie este de a crea o punte de legatura intre browserul Web si o baza de date: Fig.5. Astfel clientul se conecteaza printr-un browser la serverul web, care executa un servlet, iar acesta la randul sau acceseaza baza de date si executa cererea respectiva. Serverul web nu are nevoie de suport intern pentru a executa aceasta operatiune, el fiind ajutat de servlet care preia acest rol. De fapt aceasta tehnologie poate fi utilizata cu succes pentru a implementa aproape orice serviciu de acces la resurse.

Fig.5 – legatura intre browser si baza de date

1.6 Compararea tehnologiilor

Asadar servlet-urile pot fi folosite in locul traditionalelor scripturi CGI. Pentru a alege tehnologia potrivita este necesar conoasterea avantajelor si dezavantajelor unuia in detrimentul celuilalt. Aspectele de care trebuie sa tinem seama sunt:

Performanta: In cazul utilizarii CGI pentru deservirea unui client se creaza un proces nou in care se executa scriptul CGI. Scriptul genereaza pagina HTML si o trimite  clientului. Crearea unui proces nou este o operatie costisitoare din punctul de vedere al sistemului de opearare.
Servlet-ul face acelasi lucru ca un script CGI, insa servlet-ul se ruleaza pe un fire de executie. Crearea unui fir de executie in Java este mult mai eficienta decat crearea unui proces nou CGI. Executia unui script CGI intr-un proces separat cere procesorului sa aleaga dintre procese de mai multe ori in timpul executiei scriptului. Aceasta problema este redusa considerabil daca intregul task poate fi executat intr-un singur proces folosind fire de executie multiple.

Compilarea in byte-code Java: ofera rulare mai rapida decat codurile scrise in limbaje script. Multe din eventualele erori sunt detetctate si rezolvate inca de la compilare deci servlet-urile sunt mai stabile.

Portabilitate: servlet-urile pot fi distribuite foarte usor pe diferite platforme fara a fi nevoie sa se rescrie codul. Astfel acestea opereaza identic fara modificari cand ruleaza pe Windows, Unix sau alt sistem de operare. Totodata, portabilitatea crescuta este data si de compatibilitatea maxima cu multe servere web cunoscute cum ar fi Apache Tomcat, Oracle Application Server.

Rezistenta la blocarea sistemului: Servlet-urile nu au acces direct la locatiile de memorie datorita masinii virtuale Java, deci se reduce substantial riscul de blocare al sistemului, ca rezultat al accesului la memoria individuala. JVM va arunca o exceptie sau va rezolva problema fara a bloca sistemul.

Securitate: exista trei proprietati care fac servleturile mult mai sigure decat scripturile CGI. In primul rand servlet-urile utilizeaza un manager de securitate pentru a crea reguli stricte de securitate. Acest manager poate restrictiona reteaua sau accesul la un fisier pentru cererile neautorizate sau poate acorda drepturi depline servlet-urilor de incredere .Totodata un servlet are acces la toae informatiile continute in fiecare cerere a clientului. Aceasta informatie contine date de autentificare HTTP. Cand se folosesc in conjunctie cu protocoale de securitate cum ar fi SSL , servlet-urile pot verifica identitatea fiecarui client. Dezavantajul este ca odata compilate, fisierele java pot fi destul de usor decompilate, operatiue mult mai grea pentru CGI-uri scrse in C/C++.

2. Tehnologia Servlet

2.1 Apelarea servlet-urilor

In aceasta parte se vor prezenta diferitele metode de accesare a servlet-urilor cu referire in special la cei ce se executa pe serverul Web, accesati prin HTTP. Alte servicii de retea care utilizeaza servlet-uri, cum ar fi serverele FTP vor utiliza mecanisme diferite de accesare.

2.1.1 Accesarea directa folosind cereri HTTP

Cea mai comuna metoda de accesare a unui servlet o reprezinta cererea URL (Fig.5), identica cu cererea programelor CGI. Odata ce clasa servlet-ului a fost compilata si distribuita pe serverul web, ea poate fi apelata printr-o adresa de forma: http://nume_host:port/director/NumeServlet.

Fig.5 – accesarea directa prin cerere HTTP

NumeServlet poate sa fie si un alias care identifica componenta ce manipuleaza cererea, el ajutand la o mai buna structurare a servlet-urilor. Cand serverul Web primeste o cerere, se verifica daca exista o instanta a servlet-ului cerut, iar daca exista cererea se paseaza acesteia, altfel se incarca automat clasa si se creaza o instanta a acesteia care preia cererea. Atunci cand se cere ca servlet-ul sa proceseze o cerere, sunt transferati si parametrii dati de browser. Intr-o executie normala a unui servlet doar o singura instanta a acestuia va fi folosita pentru a servi toate cererile venite la server pe parcursul intregii vieti a servlet-ului.

2.1.2 Accesarea prin SSI (Server Side Include)

Unele servere Web pot asigura si o altfel de abordare numita SSI. Aceste servere apeleaza servlet-ul pentru pre-procesarea unei pagini Web inainte ca aceasta sa fie transmisa clientului. Acest lucru este posbil prin directiva speciala HTML si anume tagul servlet. Fisierele ce contin acest tag au extensia shtml iar sintaxa tagului este urmatoarea:

<SERVLET NAME=NumeServlet CODE=NumeClasaServlet.class

CODEBASE=LocatieServleturi

initparam1=initvalue1 initparam2=initvalue2 …>

<PARAM NAME=param1 VALUE=valoare1>

<PARAM NAME=param2 VALUE=valoare2>

………

</SERVLET>

Se observa ca sintaxa este identica cu cea folosita pentru inserarea in paginile HTML a Appte-urilor.

Fig.5 – accesarea prin SSI

Cand un server Web rapunde printr-un fisier .shtml el cauta in document directive speciale, iar daca este utilizat tagul <servlet> atunci se invoca servlet-ul descris de parametrul name si se genereaza pagina HTML. Parametrul codebase este obtional si indica adresa relativa a servlet-ului. Daca acesta este omis atunci clasa trebuie sa fie in directorul in care se afla si pagina HTML. Tagurile PARAM contin parametrii de cerere pentru servlet care sunt accesibili prin metoda getParameter(String name). Servlet-ul apelat va genera o parte a paginii Web, iar rezultatele servlet-ului vor fi puse în locul unde a fost situat în document tag-ul SERVLET.

2.2 Structura servlet-urilor

2.2.1 API-ul

API-ul Java pentru servlet-uri reprezinta o extensie standard a platformei Java care furnizeaza dezvoltatorilor de aplicatii Web modalitati avansate de extindere a functionalitatii serverelor Web. Spre deosebire de un program obisnuit dar asemanator cu applet-ul, un servlet nu are o metoda main(). In schimb sunt invocate alte metode bine stabilite, de catre server, in procesul de manipulare a cererilor. De fiecare data cand un server trimite o cerere catre servlet, cel din urma invoca metoda service(). Un servlet generic trebuie sa suprascrie metoda service() atasata acestuia pentru a raspunde cererilor servlet-ului corespunzator. Metoda accepta doi parametrii: un obiect pentru tratarea cererii si unul pentru transmiterea raspunsului. In Fig.6 se prezinta cum un servlet generic trateaza o cerere.

Fig.6

In contrast un servlet HTTP in mod normal nu suprascrie metoda service(). In schimb el suprascrie metoda doGet() pentru cereri de tip Get, sau metoda doPost(), pentru cereri Post. Servlet-ul poate utiliza in continutul sau una sau ambele metode, in functie de tipul de cereri pe care le accepta. Metoda service() din HTTPServlet primeste aceste tipuri de cerere si le trimite metodelor doXXX() , de acceea ea nu trebuie suprascrisa. In Fig.7 este prezentat modul cum un servlet HTTP trateaza o cerere de tip GET sau POST.

Fig.7

Un servlet HTTP poate deasemenea sa suprascrie metodele doPut() sau doDelete() pentru manipularea cererilor PUT sau DELETE. Totusi servlet-urile de acest tip de obicei nu au nevoie de aceasta suprascrere, implementarea standard oferita de API fiind suficienta.

2.2.2 Ciclul de viata al unui servlet

Ciclul de viata al unui servlet permite container-elor acestora sa rezolve problemele aparute in cazul scripturilor CGI cum ar fi neajunsurile legate de performanta sau securitate. O modalitate comuna de a rula servlet-uri este ca toate container-ele acestora sa se execute intr-o singura masina virtuala Java(JVM). Prin introducerea tuturor servlet-urilor in acceasi JVM , acestia pot sa comunice eficient intre ei, iar pentru prevenirea accesarilor neautorizate se folosesc regulile de incapsulare (de protectie a datelor) standarde in limbajul Java. Servlet-urile sunt pastrate de JVM in memorie, ca instante persistente pe parcursul diferitelor cereri si de accea se face o economie semnificativa de memorie fata de cazul cand se utilizeaza procese separate.

Ciclul de viata a servlet-ului este foarte flexibil, singura regula comuna este urmarirea urmatorilor pasi:

-crearea si initializarea servlet-ului: init().

-rezolvarea cererilor de la clienti folosind metoda service().

-distrugerea servlet-ului si si scoaterea din memorie prin Garbage Collector: destroy().

2.2.3 Persistenta instantei (instance persistence)

Mai sus s-a subliniat faptul ca servlet-urile persista intre cereri ca instante de obiect. Cu alte cuvinte in momentul cand codul servlet-ului este incarcat serverul creaza o singura instantaa clasei. Aceasta instanta trateaza orice cerere catre servlet. Acest aspect imbunatateste performanta in trei aspecte:

-prin necesarul de memorie scazut.

-prin eliminarea dezavantajului dat de crearea de numeroase obiecte, care altfel ar fi necesara de fiecare data cand este apelat un servlet .

-prin permiterea persistentei. Un servlet poate sa incarce o singura data tot ce e nevoie pentru tratarea mai multor cereri. De exemplu, o conexiune la baza de date poate fi creata o singura data si folosita ori de cate ori este nevoie de un servlet sau chiar de mai multe.

Nu numai servlet-urile persista pe decursul a mai multor cereri ci si firele de executie create de accestea. Probabil acest aspect nu este util servlet-urilor obisnuite dar se deschid noi posibilitati interesante. Consideram ca un fir de executie ce ruleaza in background opereaza anumite calcule in timp ce alt fir afiseaza cele mai noi rezultate. Este asemanator applet-urilor de animatii atunci cand un thread schimba poza in timp ce altul o afiseaza.

2.2.4 Servlet-uri si fire de executie

Daca privim din perspectiva celor care au creat aceasta tehnologie vom afla ca fiecare client reprezinta un nou thread care apeleaza servletul folosind metodele standard: service(), doGet(), doPost() asa cum se arata in Fig.8

Fig.8 – Mai multe thread-uri, o singura instanta a servletului.

Daca servlet-ul la care facem referire doar citeste datele de cerere, returneaza raspunsul si salveaza informatia in variabile locale (acele variabile declarate in interiorul metodelor) atunci nu reprezinta o problema interactiunea dintre aceste thread-uri. Odata ce informatia este salvata si in variabilele de instanta, trebuie sa tinem cont ca fiecare dintre aceste thread-uri poate manipula aceste variabile. Fara o precautie marita se poate ajunge usor la date eronate. Pentru a pune in evidenta aceasta problema luam ca exemplu un servlet (CounterServlet) care incrementeaza o variabila nelocala. Este posibil sa se lanseze doua cereri simultane catre servlet-ul nostru, caz in care sunt mari sanse sa se afiseze aceeasi valoare pentru amble cereri astfel:

count=0

count++ // Thread 1

count++ // Thread 2

out.println(count) // Thread 1

out.println(count) // Thread 2

Primul thread incrementeaza variabila count si exact in momentul urmator, innainte ca acesta sa afiseze pe ecran variabila, al doilea thred incrementeza si el valoare si astfel cele doua thread-uri vor afisa valoarea eronata doi.

Pentru a preveni inconsistenta datelor se adauga blocuri de cod sincronizate. Orice cod din blocul sau metoda sincronizata dispune de un asa numit monitor, care poate fi gandit ca o incuietoare a acestuia.Cand un thread intra in codul synchronized , el „incuie ” acest cod si ia cheia , astfel incat nici un alt thread nu va putea executa respectivele portiuni pana cand cheia nu este inapoiata. Un thread care vrea sa execute blocul si nu are cheia este obligat sa astepte inapoierea acesteia. In acest fel se creaza portiuni executate atomic ce previn accesul simultan al mai multor thread-uri la datele din memoria comuna. De fapt fiecare thread va avea propiul context de executie , si propria stiva pe care pastreaza copii ale datelor din memoria comuna tuturor thread-urilor.

Pentru exemplul de mai sus avem patru variante de rezolvare a problemei. Prima ar fi introducerea cuvantului cheie synchronized in definirea metodei doGet() si astfel asingurand consistenta datelor din intreaga metoda prin folosirea instantei servlet-ului ca monitor.

public synchronized void doGet(HttpServletRequest req,

HttpServletResponse res)

Aceasta abordare nu este eficienta deoarece ar insemna ca servlet-ul sa trateze cate o singura cerere GET la un moment dat.

A doua optiune este sa sincronizam doar codul care poate genera problema:

Count=0;

synchronized(this) {

count++;

out.println(count);

}

Aceasta abordare este mai eficienta deoarece limiteaza timpul in care servlet-ul ruleaza codul sincronizat cu indeplinirea consistentei datelor.

A treia varianta este sa cream un bloc sincronizat care sa faca tot ce este necesar dar rezultatele sa le scoatem in afara lui. In cazul nostru facem incrementarea ca si in cazul precedent dar scoatem din bloc afisarea pe ecran.

synchronized(this) {

count++;

}

out.println(count);

Prin aceasta modificare fortam ca blocul sincronizat sa fie cat mai mic, in timp ce rezultatele sunt aceleasi.

Cea din urma varianta care nu poate fi aplicata exemplului de mai sus este folosirea de variabile locale, deoarece acestea nu sunt valabile pentru alte thread-uri. Totusi la acelasi moment de timp acestea nu sunt persistente intre mai multe cereri si reprezinta o varianta care trebuie evitata.

2.2.5 Reincarcarea servlet-ului

Majoritatea serverelor Web reincarca automat clasa servlet-ului (aflata in directorul standard, anume WEB-INF/classes) daca aceasta a fost modificata, ajutand astfel la sporirea testarii si vitezei de programare. Reincarcarea servlet-ului pare sa fie o operatiune simpla dar se va demonstra contrariul. Obiectele ClassLoader sunt concepute sa incarce o clasa o singura data. Pentru a trece de aceasta limitare si a reincarca servlet-ul de mai multe ori serverele folosesc clase customizate care incarca servlet-urile din directoarele speciale.

Cand un server trimite o cerere la un servlet, el mai intai verifica daca clasa

servlet-ului s-a modificat pe disc. Daca ea s-a modificat serverul abandoneaza clasa de incarcare folosita pentru reincarcarea versiunii veche si creaza o noua instanta clasei de incarcare customizata care reincarca noua versiune. Unele servere imbunatatesc performanta prin verificarea de modificari numai dupa anumite perioade de timp cum ar fi cel parcurs de la verificarea precedenta , sau de la cererea explicita a administratorului.

In versiunile de API mai vechi de 2.2 aceasta modalitate de reincarcare rezulta in incarcarea a diferite servlet-uri de clase de incarcare diferite, o situatie care de obicei ducea la aruncarea exceptiei ClassCastException. Acest lucru se intampla atunci cand servlet-urile imparteau informatie comuna deoarece o clasa incarcata de un ClassLoader nu este aceeasi cu o alta clasa incarcate de un al doilea ClassLoader chiar daca la baza este identica. Odata cu introducerea Servlet API 2.2 s-a impus ca problema cu exceptia ClassCastException sa nu se mai produca pentru servleti-urile modificate din acelasi context. Astfel de cand toate servleti-urile si clasele suport din context vor avea intotdeauna aceelasi ClassLoader nu vor exista exceptii ClassCastException neasteptate in timpul executiei.

Reincarcarea servlet-ului nu este deasemenea efectuata pentru clasele (servlet sau altele) care sunt in classpath-ul serverului. Aceste clase sunt incarcate de core o singura data si retinute in memorie chiar daca clasele sunt modificate. In general este recomandat sa se puna clasele cu suport general (cum ar fi cele utilitare din com.oreilly.servlet) undeva in classpatch-ul serverului unde nu se reincarca. Acest lucru sporeste procesul de reincarcare si permite ca servlet-urile din diferite contexte sa imparta instantele acestor obiecte fara sa se ajunga la ClassCastException.

2.2.6 Init si destroy

La fel ca la applet-uri in servlet-uri se pot definii metodele init() sau destroy(). Serverul apeleaza init() dupa ce acesta creaza instanta servlet-ului si inainte de tratarea vreunei cereri. Metoda destroy() este rulata dupa ce se desfiinteaza servlet-ul si au fost tratate toate cererile care erau in asteptare.

In functie de server si de configuratia aplicatiei metoda init() poate fi apelata in oricare din situatiile:

-cand se porneste serverul.

-cand este apelat servlet-ul pentru prima oara chiar inainte de invocarea metodei service().

-la cererea administratorului serverului.

In toate cazurile se garanteaza ca metoda sa fie apelata si executata inainte manipularea primei cereri.

Metoda init() este utilizate de obicei pentru initializarea servlet-ului – crearea sau incarcarea obiectelor folosite de servlet pentru tratarea cererilor. In interiorul acesteia se poate initializa parametrii utilizati de intreaga clasa cum ar fi valoarea de inceput al unui counter sau valorile default. Acesti parametrii pot fi definiti si in descriptorul web.xml dupa cum urmeaza:

<web-app>

<servlet>

<servlet-name>

counter

</servlet-name>

<servlet-class>

InitCounter

</servlet-class>

<init-param>

<param-name>

initial

</param-name>

<param-value>

1000

</param-value>

<description>

Valoarea initiala pentru counter (optional)

</description>

</init-param>

</servlet>

</web-app>

In metoda destroy, programatorul trebuie sa elibereze resursele foliste care nu sunt preluate de Garbage Collector. Totodata ea da posibilitatea servlet-ului sa afiseze informatia cache nesalvata sau oricare informatie persistenta care trebuie cititita la urmatoarea apelare a metodei init(). Fig 9 prezinta apelul acestor metode.

Fig.9

2.2.7 Modelul single thread

Implicit, o singura instanta a unui servlet poate fi apelata pentru a prelua cereri multiple concurentiale. Asta inseamna ca in general, autorii de servlet-uri trebuie sa aiba grija de siguranta firelor de executie

Un server care incarca un servlet SingleThreadModel garanteaza in concordanta cu documentatia API ca doua thread-uri nu se vor executa concurent in metoda service a servlet-ului. Pentru a se permite acest lucru fiecare fir de executie foloseste o noua instanta a servlet-ului din ServletPool. De-aceea orice servlet ce inplementeaza interfata SingleThreadModel este considerat fara riscuri de inconsistenta a datelor si nu este necesara acces sincronizat la variabilele de instanta. Aceasta interfata nu are metode. Unele servere permit ca numarul de instante per ServletPool sa fie configurat iar altele permit ca in ServletPool sa fie doar o instanta, ce cauzeaza o comportare identica cu folosirea metodei service() sincronizata.

Fig.10 – Modelul Single Thread

Astfel cu aceasta abordare se evita practic sincronizarea in timp ce se efecteaza prelucrari de cereri eficiente. Ca exemplu, cand un servlet ce se conecteaza la o baza de date, uneori este nevoie sa se efectueze automat mai multe cereri catre aceasta ca parte dintr-o singura transactie. Fiecare tranzactie impune crearea unui obiect de conectare si astfel servlet-ul trebuie intr-un fel sa se asigure ca doua thread-uri nu incearca simultan sa acceseze aceeasi conexiune. Acest aspect se poate rezolva si prin blocuri sincronizate, dar folosind SingleThreadModel si avand o singura instanta de conectare per servlet, acesta poate manipula cu usurinta cererile deoarece fiecare instanta are propria sa conexiune.

2.2.8 Caching la nivel client

Pana acum s-a arata ca servlet-ul trateaza cererile GET si POST prin metodele sale doGet() si doPost(). In continoare se vor prezenta cazurile in care nu este nevoie de utilizarea acestor metode pentru prelucarea cererilor. Luam exemplul unui browser care acceseaza in mod repetat un servlet care cauta un numar prim si care trebuie sa apeleze metoda doXXX() doar atunci cand thread-ul de cautare gaseste un nou prim. Acest aspect este indeplinit atunci cand servlet-ul este anuntat de faptul ca iesirea este schimbata prin metoda getLastModified().

Majoritatea serverelor Web cand returneaza un document, includ in raspuns un header Last-Modified. Un exemplu de header Last-Modified ar putea fi:

Tue, 02-May-09 18:37:12 GMT

Acest header anunta clientul cand pagina a fost ultima data modificata. Aceasta informatie, singura poate fi de interes scazut dar se dovedeste utila cand browser-ul reincarca pagina.

Deasemenea cand reincarca o pagina, foarte multe browsere includ in cerere un header

If-Modified-Since . Structura este identica cu headerul Last-Modified

Tue, 03-May-09 19:40:47 GMT

Acest header informeaza serverul momentul de timp cand pagina a fost ultima data modificata de la download-ul acesteia. Serverul poate citi acest header si poate determina daca pagina s-a modificat de la momentul de timp dat. Daca aceasta s-a modificat serverul trebuie sa trimita noul context, altfel serverul poate retrimite un raspusn simplu prin care instiinteaza browserul ca pagina nu s-a modificat si astfel este suficient sa reafiseze versiunea memorata (cached) a documentului. Pentru aceia familiarizati cu protocolul HTTP subliniem ca raspunsul va fi 304 Not Modified .

Aceasta tehnica functioneaza cel mai eficient pentru paginile statice : serverul poate folosi fisirele sistem pentru a afla cand o pagina a fost ultima oara modificata. Pentru documentele cu continut dinamic cum sunt cele returnate de servlet-uri, serverul necesita informatie suplimentara. De unul singur acesta interpreteaza ca cu fiecare acces se modifica si continutul, dovedind ineficienta prin eliminarea avantajelor oferite de headerele Last-Modified si If-Modified-Since. Acest extra ajutor poate sa vina insa de la servlet prin utilizarea metodei getLastModified(). Un servlet trebuie sa implementeze aceasta metoda pentru a returna timpul de la ultima modifcare a raspunsului. Ea este apelata prima oara de server atunci cand se genereaza un raspuns si astfel serverul poate seta header-ul Last-Modified. A doua apelare vine atunci cand se prelucreaza cererile GET sau POST care includ header-ul If-Modified-Since .Astfel serverul poate determina in ce mod sa raspunda. Daca timpul returnat de metoda getLastModified() este mai mic sau egal cu timpul trimis de header-ul Is-Modified-Since atunci serverul returneaza codul Not-Modified, altfel afiseaza iesirea servlet-ului.

Consideram ca exemplu un servlet care afiseaza lista de masini disponibile dintr-o companie de inchirieri auto. Servlet-ul trebuie sa memoreze si sa returneze data cand lista de masini s-a modificat ultima oara. Chiar daca acelasi servlet administreaza mai multe liste , el poate returna timpi diferiti depinzand de lista de masini data ca parametru pe cerere.

Revenind la exemplul cu numerele prime metoda getLastModified() ar putea sa arate astfel:

public long getLastModified(HttpServletRequest req) {

return lastprimeModified.getTime() / 1000 * 1000;

}

Se observa ca aceasta metoda returneaza o valoare de tip long ce reprezinta timpul in milisecunde de la 1 Inauarie 1970 ,00:00 GMT. Este aceeasi reprezentare folosita intern de Java pentru a stoca valori de timp. De aceea servlet-ul foloseste metoda getTime() pentru a returna lastpririmeModified de tip long. Inainte de returnarea acestei valori de timp servletul rotunjeste aceasta valoare pana la cea mai apropiata secunda prin divizare la 1000 si multiplicare cu 1000. Toate valorile returnate de getLastModified trebuie rotunjite in acest fel deoarece header-ele Last-Modifie si Is-Modified-Since sunt redate ca valori rotunjite. Daca getLastModified() returneaza acelasi timp dar cu o valoare mai precisa se poate interpreta eronat ca fiind cu cateva milisecunde mai tarziu decat timpul dat de Is-Modified-Since. Presupunem ca servlet-ul care afiseaza numere prime gaseste un numar valid la momentul 1.229.904.000.000 de milisecunde tercute de anul 1970. Aceasta valoare este transmisa browserului, rotunita la secunda :

Thu, 17-Jul-09 09:17:22 GMT

Acum presupunem ca userul reincarca pagina si browserul anunta serverul, prin header-ul Is-Modified-Since , valoarea de timp de la ultima modificare a paginii.

Thu, 17-Jul-09 09:17:22 GMT

Unele servere au fost setate sa preia valoarea exacta de timp si anume, in cazul nostru 1.229.904.999.650 care este cu 350 milisecunde mai devreme decat timpul returnat de getLastModified() si astfel se ajunge la presupunerea falsa de modificare a contextului servlet-ului. De aceea pentru a nu se ajunge la date eronate metoda getLastModified() trebuie mereu sa rotunjeaza valoarea pana la cea mai apropiata secunda.

Obiectul HttpServletRequest transmis ca parametru metodei getLastModified() este folosit in cazul in care servlet-ul trebuie sa pastreze informatia specifica unei anumitre cererei. In cazul exemplului cu listele de masini se poate folosi aceast varianta pentru a determina care lista a fost ceruta.

3. Extragerea informatiei

Pentru a realiza o aplicatie Web de succes trebuie sa se cunoasca cat mai multe despre mediul in care aceasta va rula cum ar fi date despre caracteristicile serverului folosit sau clientul folosit pentru trimiterea de cereri. Exista mai multe metode care faciliteaza accesul la informatie a servle-tului:

.Un CGI scris in Pearl are sintaxa:

• $port = $ENV{'SERVER_PORT'}; unde $port este o variabila ce nu are tip

Un profram CGI scris in C :

• char *port = getenv("SERVER_PORT"); unde port este un pointer la un string de caractere.

Pe de-alta parte un servlet apeleaza:

int port = req.getServerPort()

Astfel se elimina riscul unor erori deoarece compilatorul garanteaza scrierea corecta, iar tipul returnat este cel particular. Totodata se da posibiliatea implementarii de „calcule amanate”: cand un server porneste un program CGI valoarea fiecarei variabile trebuie precalculata chiar daca este folosita sau nu. Un server care porneste un servlet are avantajul imbunatatirii performantei prin amanarea acestor calcule pana la momentul cand sunt necesare.

3.1 Informatia la nivelul servlet-ului

Oricare servlet poate avea anumiti parametrii de initializare (init) asociati. Acestia sunt accesibili servlet-ului la orice moment de timp, sunt definiti in descriptorul web.xml si sunt de obcei folositi in metoda init() pentru setarea unor valori initiale sau default.

Un servlet foloseste metoda getInitParameter() pentru accesarea parametrilor si returneaza valoarea corespunzatoare string-ului name sau null daca parametrul nu exista.

public String servletConfig.getInitParameter(String name);

Clasa GenericServlet implementeaza interfata ServletConfig si astfel ofera acces direct la metoda getInitParameter() :

public void init() throws ServletException {

String parametru = getInitParameter("parameter");

}

Accesarea numelor parametrilor: – un servlet poate afla numele tuturor parametrilor sai folosind metoda :

public Enumeration ServletConfig.getInitParameterNames()

Aceasta returneaza numele tuturor parametrilor „init” ca o enumerare de string-uri. Se foloste indeosebi pentru debug si este deasemenea accesibila direct servlet-ului.

Deasemenea in interfata ServletConfig exista o metoda ce returneaza numele inregistrat al servlet-ului.

public String ServletConfig.getServletName()

Daca servlet-ul este neinregistrat metoda intoarce numele clasei acestuia. Aceasta metoda este folositoare atunci cand scriem in log sau cand salvam informatia de instanta a servlet-ului intr-o resursa comuna cum ar fi baza de date sau cand folosim ServletContext.

3.2 Informatia la nivel de server

Un servlet poate avea acces la caracteristicile serverului pe care ruleaza cum ar fi portul, date despre softul de implemetare, si alte detalii. Servlet-ul poate folosi aceasta informatie pentru instiintarea clientului, pentru customizarea comportamentului in functie de tipul serverului sau chiar pentru a restrictiona explicit serverele pe care pot sa ruleze servlet-urile respective.

3.2.1 Extragerea informatiilor despre server

Un servlet acceseaza majoritatea informatiilor despre server prin intermediul obiectului ServletContext in care se executa. Inainte de API 2.2 ServletContext era in general chiar o referinta la serverul insusi. Acum aceasta regula s-a modificat in sensul ca trebuie sa existe un ServletContext diferit pentru fiecare aplicatie Web de pe server.

Sunt disponibile cinci metode pe care servlet-ul le poate utiliza pentru a afla detalii despre server: doua prin care se utilizeaza obiectul ServletRequest transmis servlet-ului si trei care sunt apelate prin obiectul ServletContext in care este executat servlet-ul.

Un servlet poate sa solicite numele serverului si portul unei cereri cu metodele getServerName() si respectiv getServerPort:

public String ServletRequest.getServerName()

public int ServletRequest.getServerPort()

Aceste metode fac parte din clasa ServletRequest deoarece valorile sunt diferite in functie de cereri distincte daca serverul are mai mult de un nume (tehnica numita hosting virtual). Numele returnat ar putea fi www.servlets.com in timp ce portul returnat 8080.

Metodele getServerInfo() si getAttribute() membre a clasei ServletContext ofera informatii despre software-ul ce a creat serverul si despre atribute:

public String ServletContext.getServerInfo()

public Object ServletContext.getAttribute(String name)

getServerInfo – returneaza informatia despre numele si versiunea softului serverului separate de slash. Sirul de caractere returnat poate fi de forma Tomcat Web Server/3.2. plus uneori , informatii aditionale .

getAttribute() – returneaza valoarea data de numele atributului ca un obiect sau null daca atributul nu exista. Serverele au si optiunea de plasare explicita a atributelor in context pentru utilizarea lor de catre servlet. De exemplu un server poate sa afiseze statistici la incarcare, sa returneze o referinta la un pachet de resurse. Singurul atribut pe care serverul este obligat sa-l foloseasca este javax.servlet.context.tempdir care ofera o referinta de tip java.io.File la un director privat contextului.

Servlet-urile pot deasemenea adauga propriile lor atribute contextului folosind metoda setAttribute(). Se poate accesa documentatia serverului folosit pentru lista cu atributele sale. O lista cu toate atributele curente stocate de server sau de servlet-uri se poate obtine folosind metoda getAttributeNames():

public Enumeration ServletContext.getAttributeNames()

3.2.2 Prevenirea rularii neautorizate a unui servlet

Sunt multe posibilitati prin care sa implementam eficient informatia venita de la server. Sa presupunem ca am creat un servlet care nu dorim sa ruleze oriunde. Poate dorim sa-l vindem si pentru a limita posibiliatea de copieri neautorizate trebuie sa impunem rularea servlet-ului doar pe masina clientului, printr-o licenta software. Alternativ se poate crea un generator de licenta pe baza unui servlet si trebuie sa fim siguri ca el sa functioneze doar in spatele firewall-ului nostru. Aceste presupuneri pot fi aplicate foarte usor in practica deoarece servlet-ul are acces instant la informatiile despre server. Iata un exemplu in care aplicam cele de mai sus:

String key = getInitParameter("key");

String host = req.getServerName();

int port = req.getServerPort();

//Verificam daca parametrul”key” permite accesul la servlet

if (! keyFitsServer(key, host, port))

out.println("Servlet piratat");

}

else

out.println("Servlet valid");

3.2.3 Determinarea versiunii servlet-ului

Deasemenea un servlet poate cere serverului versiunea de API suportata de acesta. Pe langa utilitatea pentru debugging , un programator poate folosi aceasta informatie pentru a decide daca sa foloseasca o noua abordare pentru a rezolva un task sau una mai veche si probabil mai putin eficienta. API-ul servlet-urilor ofera doua metode pentru indeplinirea acestui scop:

public int ServletContext.getMajorVersion()

public int ServletContext.getMinorVersion()

Pentru versiunea API 2.4 cele doua metode trebuie sa returneze valorile 2 si respectiv 4. Pentru a determina versiunea suportata pentru toate serverele se poate folosi com.oreilly.servlet.VersionDetector. Aceasta clasa nu cere serverului versiunea acceptata, in schimb ea verifica clasele si variabilele valabile la compilare si pe baza cunostintelor din arhiva de API-uri poate calcula versiunea de la 1.0 la 2.5. Deoarece clasa nu foloseste cele doua metode de mai sus, aceasta metoda functioneaza nu numai pentru toate versiunile de API ci si compileaza indiferent de versiunea suportata de server.

3.3 Informatia la nivel de client

Pentru fiecare cerere, servlet-ul poate afla detalii despre masina client si pentru paginile ce necesita autentificare, despre userul actual. Aceste informatii pot fi folosite pentru informarea datelor de acces, asocierea informatiilor unui anume user sau restrictia accesului la anumiti clienti.

3.3.1 Accesarea de informatii privind masina client

Un servlet poate folosi getRemoteAddr() si getRemoteHost() pentru accesarea adreselor IP si a numelor de host (hostnames) pentru masina client:

public String ServletRequest.getRemoteAddr()

public String ServletRequest.getRemoteHost()

Ambele valori sunt de tip String iar informatia provine de la socket-ul care conecteaza serverul cu clientul si astfel adresa remote si numele de host pot fi al unui server proxy. Un exemplu de adresa Ip remote ar putea fi 192.25.80.112 si de host remote dist.engr.sgi.com.

Acestea pot fi convertite la obiect de tip java.net.InetAddress folosind metoda :

InetAddress remoteInetAddress = InetAddress.getByName(req.getRemoteAddr());

3.3.2 Restrictionarea accesului

Datorita politicii de restrictie privind anumite materiale unele situri Web trebuie sa implementeze acces limitat la anumite download-uri. Servlet-ul, cu abiliteatea sa de accesare a informatilor despre client este capabil de asftfel de realizari. De exemplu servlet-ul poate verifica masina client si sa dea acces tuturor cu exceptia tarilor din „Terrorist7”( Cuba, Iran, Iraq, North Korea, Libya, Syria, si Sudan).

Exemplu:

String remoteHost = req.getRemoteHost();

if (! isHostAllowed(remoteHost)) {

out.println("Acces <BLINK>nepermis</BLINK>");

}

else {

out.println("Acces permis");

}

private boolean isHostAllowed(String host) {

return (!host.endsWith(".cu") &&

!host.endsWith(".ir") &&

!host.endsWith(".iq") &&

!host.endsWith(".kp") &&

!host.endsWith(".ly") &&

!host.endsWith(".sy") &&

!host.endsWith(".sd"));

}

3.3.3 Accesarea informatiilor despre utilizator

Utila atunci cand vrem sa restrictionam accesul mai in amanunt decat simpa verificare a tarii. De exemplu, avem un magazin virtual si vrem sa fie autentificati numai userii care poseda card bancar. Aprope orice server Web are capacitatea sa restrictioneze accesul utilizatorilor. Mecanismul este urmatorul: prima oara cand browserul incearca sa acceseze aceasta pagina serverul HTTP raspunde cu o cerere de autentificare. Cand browserul primeste acest raspuns de obicei el afiseaza o fereastra cerand un nume de user si o parola aferenta. (Fig 11)

Fig.11 – Restrictionare la nivel de server

Odata ce userul a introdus aceste informatii browserul incearca inca odata sa acceseze pagina dar adaugand la cerere si informatiile respective. Daca serverul accepta perechea user/parola, incepe tratarea cererii, altfel serverul refuza din nou accesul si se reia procesul.

Cum implica folosirea servlet-urilor acest aspect? Cand accesul la un servlet a fost restrictionat de server servlet-ul poate accesa numele userului care a fost acceptat folosind metoda

public String HttpServletRequest.getRemoteUser()

Se observa ca aceata informatie este obtinuta de la obiectul HttpServletRequest, subclasa HTTP a ServletRequest. Aceasta metoda returneaza numele userului care a formulat cererea sub forma de String sau null daca accesul la servlet nu a fost restrictionat.

Un servlet poate deasemenea utiliza metoda urmatoare pentru a afla tipul de autentificare folosit:

public String HttpServletRequest.getAuthType()

Metoda returneaza tipul de autentificare folosit BASIC, DIGEST, FORM, or CLIENT-CERT sau null in caz contar. Mai multe detalii se vor da in capitolul de securitate.

3.3.4 Parametrii pe cerere (Request Parameters)

Fiecare accesare a unui servlet poate avea asociata un numar de parametrii pe cerere. Acesti parametii sunt perechi nume/valoare care ajuta servlet-ul cu informatia suplimentara necesara tratarii unei cereri. A nu se confunda parametrii pe cerere cu parametrii init care sunt asociati cu servletul insusi.

Un servlet HTTP acceseaza parametrii pe request ca parte explicita din cererea transmisa prin URL (cereri GET) sau codat (cereri POST) iar uneori sunt folosite amandoua. Partea simpla este ca fiecare servlet acceseaza parametrii in acelasi fel folosind metodele:

public String ServletRequest.getParameter(String name)

public String[] ServletRequest.getParameterValues(String name)

Metoda getParameter() returneaza valoarea atribuita parametrului name sau null in caz ca acesta nu exista. Daca exista posibiliatea ca un parametru sa aibe mai multe valori, atunci trebuie folosita metoda getParameterValues() care returneaza toate valorile parametrului aferent sub forma unui array de stringuri. Se remarca situatia in care informatia provine de la o cerere POST si care nu mai este accesibila daca aceasta informatie a fost deja citita deoarece datele POST pot fi citite o singura data. Ca exemplu putem da un servlet dictionar care poate utiliza metoda getParameter() pentru a afisa cuvantul cautat:

Partea de formular HTML:

<FORM METHOD=GET ACTION="/servlet/Dictionar">

Introduceti cuvantul ce trebuie cautat: <INPUT TYPE=TEXT NAME="cuvant"><P>

<INPUT TYPE=SUBMIT><P>

</FORM>

Urmatorul cod acceseaza cuvantul trimis ca parametru:

String word = req.getParameter("cuvant");

String definition = getDefinition(”cuvant”);

out.println(word + ": " + definition);

In final mai amintim doua metode de interes si anume metoda de accesare a tuturor numelor parametrilor care returneaza o enumerare de String-uri folosita in special pentru debugging:

public Enumeration ServletRequest.getParameterNames()

si metoda care returneaza String-ul de interogare GET :

public String ServletRequest.getQueryString()

4. Implementarea sesiunilor

HTTP reprezinta un simplu protocol ce nu ofera o modalitate prin care serverul Web sa recunoasca faptul ca o succesiune de cereri sunt asociate unui singur uesr. De exemlu o pagina ce contine un cos de cumparaturi, trebuie sa asocieze acest servlet cu clientul respectiv si sa afiseze de cate ori este nevoie continutul acestuia.

Solutia este ca un client sa furnizeze un identificator unic prin care se poate urmari actiunile efectuate de acestea.

4.1 Autentificarea user-ului

O modalitate de implementare utila este atasarea informatiilor ce provin de la autentificarea unui user. Aceasta autentificare a fost detaliata in capitolul precedent si este implemetata atunci cand serverul Web restrictioneaza accesul la anumite resurse pentru clientii care introduc un user si o parola. Daca se primeste acces numele utilizatorului este disponibil servletului prin apelarea metodei getRemoteUser().

Astfel putem folosi numele utilizatorului (username) pentru implementarea sesiunii. Odata ce utilizatorul este logat browserul memoreaza perechea nume/parola si o retransmite ori de cate ori se acceseaza noi pagini din situl respectiv.

Un servlet ce foloseste aceasta metoda adauga un obiect nou in cosul de cumparaturi folosind urmatorul cod:

String name = req.getRemoteUser();

if (name == null) {

// Pagina protejata si autentificare esuata

}

else {

String[] items = req.getParameterValues("item");

if (items != null) {

for (int i = 0; i < items.length; i++) {

addItemToCart(name, items[i]);

} } }

Princialul avantaj pentru aceasta abordare il reprezinta usurinta implementarii si faptul ca tehnica functioneaza chair daca userul acceseaza pagina de pe masini diferite sau inchide browserul si apoi revine la pagina respectiva.

Ca dezavantaj subliniem necesitatea ca fiecare user sa-si creeze un cont unic si apoi sa se autentifice de fiecare data cand acceseaza situl. Majoritatea userilor accepta acest tip de securitate pentru informatiile speciale, dar pentru accesari ordinare devine inadecvat. Totodata acest mecanism nu ofera si posibilitaea unui „log out” fortand userul sa inchida browserul pentru asta. O ultima problema o reprezinta imposibilitatea ca userul sa poata avea mai multe sesiuni in acelasi timp. Pentru toate aceste probleme se recomanda folosirea unor abordari diferite dezvoltate in contiunuare.

4.2 Ascunderea campurilor unor formulare

O modalitate de implematare a sesiunilor anonime o reprezinta folosirea formularelor ascunse. Asa cum sugereaza si numele aceste blocuri HTML nu sunt afisate in pagina, ele avand rolul de transmisie a unor informatii intre diverse pagini:

FORM ACTION="/servlet/MovieFinder" METHOD="POST">

<INPUT TYPE=hidden NAME="cod_postal" VALUE="94040">

<INPUT TYPE=hidden NAME="nivel" VALUE="expert">

</FORM>

Cu ajutorul acestui segment de cod putem actualiza servlet-ul ce reprezinta cosul de cumparaturi si astfel sa avem sesiune anonima pana in momentul in care userul se decide sa comande produsele respective.

4.3 API-ul sesiunii

Din fericire nu se impune ca intotdeauna sa se foloseasca tehnicile studiate mai sus. API-ul servlet ofera o serie de clase si metode speciale pentru acest scop, suportate pentru orice tip de server Web care accepta servlet-uri.

Fiecare user ce acceseaza situl este asociat cu un obiect de tip servlet.http.HttpSession pe care servlet-ul il poate folosi pentru a primii informatii despre acesta. Pentru a se permite servlet-ului sa lucreze independent, fiecare context pastreaza propria sa lista cu instante de tip HttpSession iar un servlet ce ruleaza in propriul sau context nu poate accesa informattile pe sesiune stocate de un alt servlet.

Un servlet foloseste metoda urmatoare pentru a extrage obiectul HttpSession curent:

public HttpSession HttpServletRequest.getSession(boolean create)

Astfel se intoarce sesiunea curenta asociata cu userul ce a formulat cererea. Daca solicitantul nu are o sesiune curenta valida, se creaza una daca variabila create este true , sau se transmite null in caz contrar.

Se poate adauga informatie pe sesiune folosind metoda ce atribuie obiectul cu un nume semnificativ:

public void HttpSession.setAttribute(String name, Object value)

Pentru a obtine un obiect atasat unei sesiuni se foloseste:

public void HttpSession.getAttribute(String name, Object value),

iar pentru a accesa toate numele tuturor obietelor atasate sesiunii se foloseste metoda ce intoarce o enumerare de obiecte String pentru toate acestea:

public Enumeration HttpSession.getAttributeNames()

4.3.1 Ciclul de viata al unei sesiuni:

O sesiune fie expira automat dupa un timp setat de inactivitate (pentru Tomcat valoarea standard este 30 de minute), fie manual, cand este explicit invalidata de servlet. O oprire a serverului poate sa nu invalideze o sesiune, depinzand de capabilitatile acestuia. Cand o sesiune expira sau este invalidata obiectul HttpSession si datele continute de acesta sunt sterse din sistem. Daca se doreste obtinerea acestor informatii dupa aceste conditii , atunci trebuie sa se utilizeze locatii de stocare externe cum ar fi baze de date sau sa se foloseasca alte tehnologii cum ar fi filtrele.

4.3.2 Filtrarea cererii sau a raspunsului

Un filtru este un obiect care poate transforma header-ul sau continutul unei cereri sau unui raspuns. Filtrele difera fata de componentele Web prin faptul ca filtrele nu creaza de obicei un raspuns. In schimb acestea ofera un mecanism ce poate fi atasat oricarei resurse Web.

Principalele actiuni pe care un filtru le poate face sunt urmatoarele:

sa intercepteze invocarea unui servlet inainte ca servlet-ul sa fie apelat;

sa examineze o cerere inainte ca servletul sa fie apelat;

sa modifice antetul si partea de date a cererii furnizand o versiune noua a obiectului;

sa modifice atat antetul cat si partea de date a raspunsului;

sa intercepteze o invocare a unui servlet dupa ce servlet-ul a fost apelat.

Un filtru poate fi configurat in asa fel incat sa actioneze asupra unui servlet sau a unui grup de servlet-uri. Unul sau mai multe filtre pot sa filtreze unul sau mai multe servlet-uri.

Filtrele implementeaza clasa javax.servlet.Filter si definesc urmatoarele 3 metode:

init(FilterConfig config) – apelata inainte ca filtrul sa intre in functiune – creeaza configuratia filtrului;

doFilter(ServletRequest req, ServletResponse res, FilterChain chain) – realizeaza efectiv filtrarea.

destroy() – apelata dupa ce servlet-ul a iesit din functiune.

Serverul creaza obiectul FilterChain care contine filtrele ce urmeaza a fi procesate.

Interfata FilterConfig are metode care obtin numele filtrului, parametrii sai de initializare, si contextul servlet-ului activ.

Metoda init(FilterConfig)

pregateste filtrul pentru lucru

apeleaza metoda doFilter() de oricate ori apar cereri pentru folosirea filtrului

Metoda doFilter()

realizeaza filtrarea; fiecare filtru primeste cererea si raspunsul curent. Filtrul poate sa faca orice cu cererea si raspunsul; poate sa modifice obiectele in asa fel incit sa le schimbe comportamentul. Filtrul apeleaza apoi chain.doFilter() ca sa transefere controlul urmatorului filtru.

Dupa ce s-a revenit din apel, filtrul poate, la sfirsitul propriei sale metode doFilter(),sa execute actiuni aditionale asupra raspunsului, de exemplu, poate sa salveze (log) informatii despre raspuns,sau poate sa refuze sa apeleze urmatorul filtru.

Metoda destroy()

indica faptul ca filtrul a fost scos din functiune

Fig12.1 – filtrarea unei cereri

Fig 12.2 – postprocesarea raspunsului

5. Securitate

Datorita dezvoltarii tehnologiei de comert electronoc dar si a retelelor intranet securitatea a devenit un factor principal in dezvoltarea acestor aplicatii.

Securitatea este ramura care se ocupa cu pastrearea informatiilor confidentiale si publicarea lor decat persoanelor autorizate. Se remarca patru mari ramuri ce definesc securitatea:

Autenticitatea – posibilitatea identificarii partilor implicate

Permisiuni – limitarea accesului la resurse la anumiti useri sau programe

Confidentialitate – asigurarea ca doar partile implicate poate intelege comunicarea.

Integritatea – posibilitatea impunerii ca continutului de comunicatie sa nu poate fi schimbat in timpul tranzactiei.

Acestea aspecte de securitate se pot interpreta astfe: un client trebuie sa fie sigur de faptul ca comunica cu un server legitim (autenticitate), deasemenea orice informatie transmisa de acesta cum ar fi conturi de carti de credit trebuie sa fie inaccesibile accesarilor neautorizate (confidentialitate). Serverul este pe de alta parte responsabil de permisiuni, daca o companie ofera informatii confidentiale angajatilor sai trebuie sa se asigura de autorizarea accesului la acestea numai userului autentificat. In final, ambele parti au nevoide de integritate pentru a fi sigure ca informatia trimisa ajunge la destinatie nealterata.

Autenticitatea, permisiunea, confidentialitatea si integritea sunt toate unite de tehnologia de certificare digitala (digital certificate technology), care permite serverului web si clientului folosirea unei tehnologii avansate de criptografie pentru manipularea identificarii si criptarii intr-o maniera securizata. Datorita suportului continut de tehnologia Java, servlet-urile sunt o platforma excelenta pentru dezvoltarea de aplicatii web securizate ce implementeaza tehnologia de certificare digitala.

5.1 Autentificarea HTTP

Protocolul HTTP ofera suport nativ pentru autentificare numit autentificare de baza (bazic authentication) bazat pe o cerere simpla de tip cerere raspuns ce foloseste perechea nume utilizator/parola. Cu aceasta tehnica , serverul web foloseste baza de date pentru stocarea acestor perechi folosite pentru stabilirea accesului la anumite resurse (fisiere, directoare , servleturi, etc).

Aceasta autentificare de baza folosita singura este de obicei foarte slaba deoarece ea nu ofera confidentialitate sau integritate. Problema care apare este transmiterea parolelor pe retea chiar daca acestea sunt usor codate. Oricine monitorizeaza fluxul de date TCP/IP are acces imediat si total la informatiile transferate deci si la numele utilizatror si parola daca nu se foloseste o criprare SSL aditionala (discutata in acest capitol).

Autentificarea Digest este o varianta a schemei de autentificare de baza care in schimb sa transmita o parola direct pe retea, ea trimite hash-ul acesteia (folosind algoritmul de criptare MD5 ).

5.1.1 Configurarea autentificarii HTTP

Folosind taguri in descriptorul web, constrangerile de securitate pot fi programate astfel incat anumite pagini din aplicatie sa poata fi accesate numai de userii cu drept. Servlet-urile folosesc un model de autorizare bazata pe roluri (role-based authorization) pentru controlul accesului. Datorita acestui model permisunile de acces sunt in administrarea unei entitati abstracte numite „rol securizat” ce permite accesul unui user sau grup de user care fac parte din acest rol. De exemplu se poate dori ca un site care afiseaza informatii despre salariile unei companii sa poata fi accesat decat de userii care au rol de manageri.

Descriptorul web specifica tipul de acces permis pentru fiecare rol dar nu atribuie un rol specific unui user. Acest lucru se face in momentul lansarii aplicatiei utilizand tool-urile specifice serverului.

Exemplu: presupunem ca avem un servlet care are nevoie de restrictie pentru accesul la acesta si baza de date in care se pastreaza lista cu numele utilizator, parola si rolul fiecarui user.

<security-constraint>

<web-resource-collection>

<web-resource-name>

SecretProtection

</web-resource-name>

<url-pattern>

/servlet/SalaryServer

</url-pattern>

<url-pattern>

/servlet/secret

</url-pattern>

<http-method>

GET

</http-method>

<http-method>

POST

</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>

manager

</role-name>

</auth-constraint>

</security-constraint>

<login-config>

<auth-method>

BASIC <!– BASIC, DIGEST, FORM, CLIENT-CERT –>

</auth-method>

<realm-name>

Default <!– optional, folositor doar pentru BASIC –>

</realm-name>

</login-config>

<security-role>

<role-name>

manager

</role-name>

</security-role>

</web-app>

Acest descriptor protejeaza toate cererile de tip GET sau POST la servlet/secret si la servlet/SalaryServer pentru ca numai userii cu rol de manager sa poata avea acces. Se poate interpreta astfel:

Tagul <security-constraint> protejeaza <web-resource-collection> si astfel accesul este garantat numai pentru rolurile din <auth-constraint>.Fiecare <web-resource-collection> contine un nume, un numar de url-uri ce trebuiesc protejate si un numar de metode HTTP pentru care accesul ar trebui sa fie restrictionat.

Tagul <login-config> specifica metodologia de logare folosita pentru aplicatie.In acest caz a fost folosita autentificarea de baza.<auth-method> poate accepta valorile BASIC,DIGEST, FORM si CLIENT-CERT reprezentand tipurile disponibile de autentificari.

In final tagul <security-role> specifica lista re doluri ce pot fi folosite de aplicatie.

Autentificarea bazata pe formular

Folosind aceasta metoda userii se pot autentifica printr-o pagina simpla de logare.

<login-config>

<auth-method>

FORM <!– BASIC, DIGEST, FORM, CLIENT-CERT –>

</auth-method>

<form-login-config> <!– only useful for FORM –>

<form-login-page>

/loginpage.html

</form-login-page>

<form-error-page>

/errorpage.html

</form-error-page>

</form-login-config>

</login-config>

De fiecare data cand serverul primeste o cerere pentru o resursa protejata, serverul verifica mai intai daca userul a fost autentificat. De exemplu, serverul incearca sa acceseze obiectul Principal pus pe sesiune. Daca el gaseste acest obiect, atunci se verifica rolurile obiectului cu cele care permit accesul la resursa. Userului i se garanteaza accesul doar daca obiectul Principal apartine rolului cerut. Daca serverul nu localizeaza acest obiect sau daca rolurile nu corespund, clientul este retrimis catre o pagina de logare.

5.2 Certificatele digitale

Unele aplicatii complexe necesita un nivel de securitate mai ridicat decat cel oferit de cele enumerate mai sus. Acest lucru este implementat prin tehnologia de certificate digitale care folosesc sistemul de criptografiere bazat pe chei. Astfel fiecare user are doua chei folosite pentru criptarea si decriptarea informatiilor: o cheie publica accesibila oricui si una privata tinuta secreta. Aceste chei sunt legate matematic dar nu se poate determina una in functie de cealalta. Presupunem ca exemplu ca Popescu vrea sa-i trimita un mesaj privat lui John. El determina cheia publica a lui John si o foloseste pentru criptarea mesajului. Cand John primeste mesajul el foloseste cheia sa privata pentru decriptare. Oricine incearca sa intercepteze mesajul ilegal obtine un cod indescifrabil.

Schema de criptare folosind cheia publica este bazata in general pe algoritmul RSA care foloseste numere prime foarte mari pentru generarea unei perechi de chei asimetrice (adica fiecare cheie poate decoda mesajul codat de cealalta). Cheile individuale sunt de diferite lungimi, pentru securitate maxima el pot fi de 1024 sau 2048 biti lungime.

Deoarece cheile sunt foarte mari, este inadecvat ca un user sa introduca o cheie la fiecare cerere. In schimb cheile publice sunt stocate pe disc sub forma de certificate digitale, iar cele private sunt stocate criptat tot pe disc si protejate de un passphrase.

Criptografia ce foloseste cheia publica rezolva problema de confidentialitate deoarece comunicatia este criptata. Ea rezolva totodata si problema de integritate. John stie ca mesajul pe care l-a primit nu a fost alterat deoarece a putut fi decodat. Dar avem problema de autentificare: John nu are cum sa afle ca mesajul primit este de la Popescu. Aici intervine semnatura digitala. Deoarece chieia publica este asimetrica fata de cea privata, Popescu poate la inceput sa-si foloseasca cheia sa privata pentru a coda mesajul si apoi sa foloseasca cheia publica a lui John pentru a-l codifica din nou. Cand John va primi mesajul , acesta il va decoda mai intai folosind cheia sa privata apoi folosind cheia publica a lui Popescu. Deoarece numai Popescu poate coda mesaje folosind cheia sa privata – mesaje ce pot fi decodate folosind cheia sa publica – John va sti cu siguranta ca mesajul primit este de la Popescu.

Criptarea este diferita atunci cand sunt folosite sistemul de criptare cu o singura cheie. Avantajul major al utilizarii sistemului cu chei este posibilitatea implementarii unor comunicatii sigure, dar avem si dezajantaj si anume necesitatea efectuarii unor calcule elaborate. Ca un compromis, multe sisteme de criprare folosesc cheile asimetrice publice si private pentru identificare, si apoi schimba o cheie simetrica separata, pentru criptarea mesajului transmis. Cheia simetrica este de obicei bazata pe DES –Data Encription Standard.

Ultima problema care trebuie rezolvata este cea de autenticitate : cum poate sti un user ca celalalt este cea ce pare. Popescu si John se cunsoc asa ca John este convins ca cheia publica transmisa de Popescu este cea adevarata. Pe de alta parte daca Ana vrea sa-i dea lui popescu cheia sa publica dar cei doi nu se cunosc , atunci nu exista nici un motiv ca Popescu creada ca Anca poate fi alta persoana.Daca presupunem ca John o cunoaste pe Ana atunci el poate sa-si foloseasca cheia privata pentru a semna cheia publica a acesteia. Apoi cand Popescu primeste cheia el poate detecta ca John , cel in care are incredere garanteaza pentru identitatea Anei.

In cazul unei aplicatii propriuzise aceasta garantare venita de la a treia parte este de obicei implementata de o autoritate acreditata (certificate authority) cum ar fi VeriSign Corporation. Deoarece VeriSign este o organizatie cunoscuta cu o cheie publica cunoscuta, cheile semnate si garantate de aceasta se presupun a fi de incredere. VeriSign ofera un pachet de clase de Id-uri digitale, fiecare cu un nivel de incredere si cu un pret. Clasele de nivel superior sunt verificate individual de angajatii companiei. Alte firme care ofera „certificate authority” sunt:

Thawte Consulting (http://www.thawte.com)

Entrust Technologies (http://www.entrust.com)

5.3 Protocolul SSL – Secure Sockets Layer

Protocolul SSL se afla intre protocolul de nivel de aplicatie (in acest caz HTTP) si protocolul de transport (pentru internet, in mare parte TCP/IP). Acesta manipuleaza elementele de securitate necesare folosind criptografia cu cheia publica pentru criptarea informatiilor transmise intre client si server. SSL a fost introdus pe piata de firma Netscape , si treptat a devenit standardul pentru comunicatia securizata, el fiind baza protocolului TSL – Transport Layer Security. SSL ofera suport pentru autentificarea serverului, confidentialitate si integritate, el functionand dupa urmatorii pasi:

1.Un client se conecteaza la o pagina securizata folosind protocolul HTTPS (HTTP plus SSL).

2.Serverul semneaza cheia publica trimisa de client cu cheiea sa privata si o trimite inapoi browserului.

3 Browserul foloseste cheia publica a serverului pentru a verifica daca acea persoana care a semnat cheia chiar o detine.

4 Browserul verifica daca o autoritate de certificare de incredere a semnat cheia. Daca nu este semnata , atunci browserul intreaba userul daca keia poate fi de incredere si procedeaza in concordanta cu raspunsul primit.

5 Clientul genereaza o cheie simetrica (DES) pentru sesiunea respectiva care este criptata cu cheia publica a serverului si este trimisa acestuia. Noua cheie este folosita pentru criptarea tuturor informatiilor transmise. Aceasta cheie simetrica este folosita datorita dezavantajului dat de numeroasele calcule ce trebuiesc facute in sistemele de criptare cu cheie publica.

Toti acesti pasi sunt transparenti pentru servlet-uri si pentru programatorii acestora, tot ce trebuie facut este sa se obtina un certificat pentru server care va fi instalat si configurat. Informatia transferata intre servlet-uri si clienti este acum codata.

5.4 Securitatea la nivelul clientului

SSL ofera deasemenea suport pentru certificate cleint. Dupa ce s-a autentificat cu serverul, acesta solicita certificatul clientului. Clientul, apoi trimite certificatul sau, iar serverul face acceasi autentificare pe care a facut-o si clientul, comparand certificatul acestuia cu o biblioteca de certificate (sau stocand acest certificat pentru a identifica userul la o vizita ulterioara). Ca o masura de securitate, multe browsere solicita ca respectivul client sa introduca o parola inainte ca acesta sa trimita certificatul respectiv.

Odata ce clientul a fost autentificat, serverul poate permite accesul la anumite resurse cum ar fi servlet-urile sau alte fisiere, doar cu autentificarea HTTP. Procesul ofera un nivel superior de autentificare deoarece serverul cunoaste ca acel client cu certificat Smith este chiar el (si poate sti care Smith este prin citirea certificatului sau unic). Dezavantajele acestor certificari la nivel de client sunt acelea ca un user trebuie sa obtina si sa instaleze certificatele, serverul trebuie sa stocheze intr-o baza de date toate cheile publice acceptate, iar serverul trebuie sa suport cel putin SSL 3.0

5.5 Configurarea SSL

O aplicatie web care necesita securitate SSL (HTTPS) poate indica acest aspect serverului prin descriptorul web. Atnci cand este nevoie de SSL, fisierul web.xml trebuie modificat astfel incat tag-ul <security-constraint> sa contina <user-data-constraint> ce indica constrangerile de securitate.

<!– …etc… –>

<security-constraint>

<web-resource-collection>

<web-resource-name>

SecretProtection

</web-resource-name>

<url-pattern>

/servlet/SalaryServer

</url-pattern>

<url-pattern>

/servlet/secret

</url-pattern>

<http-method>

GET

</http-method>

<http-method>

POST

</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>

manager

</role-name>

</auth-constraint>

<user-data-constraint>

<transport-guarantee>

CONFIDENTIAL <!– INTEGRAL sau CONFIDENTIAL –>

</transport-guarantee>

</user-data-constraint>

</security-constraint>

<!– …etc… –>

Adaugarea <user-data-contstaint> indica faptul ca aceasta colectie de resurse solicita nu numai ca userii sai sa apartina rolului de manager, ci deasemenea userul trebuie sa se conecteze folosind o conexiune care este confidentiala.

Tagul <transport-quarantee> are doua valori INTEGRAL si CONFIDENTIAL. Prima valoare garanteaza ca datele nu se modifica in timpul comunicatiei. CONFIDENTIAL solicita garantia ca datele sa nu poata fi citite de o a treia parte neautorizata.O garantie de tip CONFIDENTIAL implica valoarea de tip INTEGRAL. Aceasta lasa serverul sa decida ce algoritm de criptare corespunde ca INTEGRAL si care pentru CONFIDENTIAL. Majoritatea algoritmilor SSL corespund pentru amandoua, cu toate ca un server poate sa trateze o criptare DES pe 56-biti ca fiind suficienta pentru INTEGRAL (deaorece pentru decodare trebuie ca datele sa nu fie modificate) , dar nesuficienta pentru CONFIDENTIAL (deoarece ea poate fi foarte usor crack-uita). In practica utilizata pentru tehnologia web de azi exista doar o mica diferenta intre cele doua iar CONFIDENTIAL este garantia standard folosita.

Tagurile <auth-constraint> si <user-data-constraint> pot exista unul fara celalalt. De exemplu o pagina de solicitare a datelor de pe cardul bancar va avea nevoie de o comunicatie de tip CONFIDENTIAL dar poate ramane vizibila pentru toti utilizatorii.

5.5.1 Configuraerea autentificarii SSL

Odata cu cresterea popularitatii SSL, foarte multe situri au implementat certificatele client pentru autentificaera userilor. Se ofera astfel o metoda automata si securizate de determinare a identitatii userilor. Depinzand de nivelul de incredere asociat certificatului clientului acest mecanism de autentificare poate fi considerat suficient de sigur pentru a suporta incheieri de contracte legale sau sisteme de vot electronic.

Deasemenea se poate implementa autentificarea bazata pe certificatele client si prin simpla modificare a tagului <login-config>.

login-config>

<auth-method>

CLIENT-CERT <!—clientul trebuie autentificat folosind X.509 cert –>

</auth-method>

</login-config>

Acest segment anunta serverul ca toate autentificarile facute pentru aceasta aplicatie web vor fi facute flosind certificatele client , in scimbul alternativelor date de formularele standard. Clientul nu va intampina o pagina de logare cu toate ca browserul va cere o parola pentru a debloca certificatul acestuia inainte de a fi trimis serverului. Daca clientul nu are un astfel de certificat , atunci accesul este blocat.

5.5.2 Accesarea informatiilor de autentificare SSL

Cu autentificarea de tip BASIC sau DIGEST , toate detaiile de tp SSL sunt tratate de server transparent pentru servlet-uri. Cu alte cuvinte nu este nevoie ca servlet-ul sa faca ceva special pentru a rula pe un server securizat. Uneori, este posibil totusi ca un servlet sa primeasca informatii utlile de autentificare SSL. De exemplu un servlet poate sa solicite informatii despre securitatea conexiunii folosind urmatoarea metoda:

public boolean ServletRequest.isSecure()

Aceasta metoda returneaza true daca serverul considera aceasta conexiune sigura. Puterea de criptare ce poate fi considerata sigura este diferita in functie de implemntarea serverului si este specificata in documentatia aferenta. Din nefericire nu exista un mod standard prin care un servlet sa identifice algoritmul de criptare folosit pentru conexiune sau dimensiunea in biti (40,56,128) a cheiei simetrice folosite pentru criptare.

Cand un client a fost autentificat folosind CLIENT-CERT, numele principal al acestuia poate fi accesat prin metoda: getUserPrincipal() Acest nume este preluat din campul Distinguished Name al certificatului.

In final concluzionam ca defiecare data cand un certificat client este trimis la un server , un servlet poate sa acceseze acest certificat ca un atribut pe cerere.

java.security.cert.X509Certificate cert =

(java.security.cert.X509Certificate)

req.getAttribute("javax.servlet.request.X509Certificate");

6. Comunicatia applet – servlet

Dezvoltatorii de aplicatii Web folosesc applet-urile Java pentru a creea pagini intercative si atractive. Aceste applet-uri sunt practic mici programe Java care sunt compilate in cod binar independent de platforma de lucru. Acest cod este de obicei salvat pe un server. Tag-ul HTML <APPLET> este folosit pentru a include o referinta la clasa ce trebuie inclus in pagina. Atunci cand browserul primeste pagina HTML codul applet-ului este deasemenea downloadat iar masina virtuala java (JVM) atasata browserului ruleaza codul applet-ului si afiseaza rezultatul in interiorul paginii HTML. Astfel, se observa ca applet-urile sunt executate la nivel client.

Servlet-urile Java sunt rulate pe de alta parte la nivelul serverului. Majoritatea applet-urilor sunt formate din obiecte componente cum ar fi blocuri pentru text, butoane, etichete, continute pe diferte containere si avand diferite aspecte generate de interfata LayoutManager. Evenimentele generate de diferitele obiecte din applet sunt tratate folosind interfete specializate cum ar fi ActionListener cu metoda sa specifica ActionPerformed().

Partea de comunicatie se face prin stabilirea conexiunii cu serverul, invocarea servlet-ului si transmiterea datelor catre acesta.

Pentru inceput se creaza un obiect URL reprezentand adresa servlet-ului.Acest obiect va contine urmatoarele informatii in ordinea urmatoare:

-numele domeniului serverului

-directorul serverului unde este continut servlet-ul cu care vrem sa comunicam.

-numele servlet-ului

-una sau mai multe perechi de nume/valoare transmise

Ex: URL servletUrl = new URL(“http://localhost:8080/DepozitMedicamente/StoreServlet?client=Popescu”);

Odata ce obiectul de tip URL a fost creat , conexiunea cu servlet-ul este stabilita folosind urmatorul cod:

URLConnection servletConnection = servletUrl.openConnection();

Informatia fiind astfel transmisa, ea poate fi forte usor accesata de servlet prin metoda GET folosind metoda getParameter() prezentata in capitolele precedente.

Pentru a trimite date de tip POST servlet-ului, se foloseste din nou clasa URLConnection dar de aceasta data trebuie sa informam conexiunea URL ca vom trimite informatiile folosind OutputStream. Metoda POST este mai utila deoarece permite transmisia de diferite tipuri de date (text simplu, binar, etc), tot ce trebuie facut este sa se seteze tipul de continut (content-type) in header-ul de cerere HTTP.Exemplu de metoda ce permite transferul de date binare:

servletConnection.setRequestProperty ("Content-Type", "application/octet-stream");

Servlet-ul prin metoda doPost extrage un obiect de tip ObjectInputStream de la applet:

ObjectInputStream inputFromApplet= new ObjectInputStream(request.getInputStream());

7. Java si tehnologia Wireless

In ultimi ani tehnologiile Java 2 Micro Edition (J2ME) si XML au avut o crestere semnificativa in popularitate. Folosite impreuna, aceste tehnici pot reprezenta cheia dezvoltarii de solutii software pentru dispozitivele Wireless cum ar fi PDA-uri, telefoane mobile sau pagere. Pentru a pune in evidenta avantajele folosirii acestor tehnologii se va avea in vedere:

– Avantajul folosirii J2ME in detrimentul tehnologiei conventionale WAP .

– Usurinta dezvoltarii unei infrastructuri de tip client/server pentru comnunicatie Wireless.

– Cum ajuta J2ME la dezvoltarea portalurilor Wireless

Wireless Access Protocol(WAP) reprezinta incercarea de a crea un standard pentru dezvoltarea de aplicatii pentru retelele de comunicatie Wireless. Initial, firme ca Eriscson, Motorola, Nokia s-au unit si au creat acest protocol de comunicatie care functioneaza pe diferite tipuri de tehnologii wireless.

7.1 Tehnologia J2ME

Se adreseaza in mod explicit dispozitivelor mobile, acest lucru fiind realizat prin implementarea unei noi masini virtuale (KVM), optimizata pentru arhitecturi pe 16 sau 32 biti cu un nivel limitat de memorie. Totodata ea accepta acelasi set de bytecod-uri si acelasi format al fisierelor de clase ca si masina virtuala clasica.

Deoarece aceasta arhitectura se adreseaza unei game foarte variate de produse , ea are la baza doua componente principale: configuratii si profile. Configuratiile sunt formate din biblioteci Java de baza, specifice unei anumite categorii de dispozitive. De exemplu se poate dezvolta o configuratie pentru dispozitivele care au o memorie mai mica de 256KB. Fiecare configuratie are atasat un anumit profil, care este format din biblioteci specifice dispozitivelor mobile pentru interfata cu utilizatorul, retea si modul de stocare al datelor. Fiecare profil are propriul sau mediu de executie si este proiectat pentru dispozitive similare.

Se evidentiaza doua tipuri de configuratii:

Connectet Limited Device Configuration (CLDC) – proiectata special pentru acele dispozitive cu resurse limitate cum ar fi unele telefoane mobile sau PDA-uri care ofera memorie intre 128KB si 512KB pentru masina virtuala KVM.

Connected Device Configuration (CDC) – proiectata pentru dispozitive mult mai puternice cum ar fi PDA-urile de ultima generatie sau dispozitivele de retea. Acestea folosesc masina virtuala Java clasiva (JVM) si au mai multe functii decat configuratia CLDC (functii matematice,de securitate, de intrare iesire.), de fapt CDC include CLDC.

Pentru a garanta o flexibilitate cat mai mare fata de dezvoltarea rapida a noilor tehnologii si fata de varietatea produselor, este introdus conceptul de profil. Acesta este in principal o extensie a unei configuratii, si ofera un set de biblioteci API specifice exclusiv pentru anumite tipuri de dispozitive.

Fig.13- Platforma J2ME

Pentru configuratia CLDC cel mai important profil este MIDP – Mobile Information Device Profile. Acesta a fost deja adoptat deja de marii producatori de soft din domeniu, el definind API-uri pentru componente de interfata cu utilizatorul, tratarea evenimentelor, stocarea persistenta. Modelul de programare MIDP este o combinatie intre programarea standard si programarea Web. Astfel, in mod similar applet-urilor inserate in pagina HTML, midlet-urile se includ cu ajutorul unui fisier Java Descriptor (JAD) si sunt rulate de un micro-browser instalat pe respectivul dispozitiv.

Pentru configuratia CDC evidentiem doua profiluri:

FP – Foundation Profile reprezinta primul nivel de profil si ofera suport pentru dispozitivele lipsite de resurse fara a folosi un GUI standard. El are urmatoarele caracteristici:

– Are la baza tehnologia API J2SE si astfel se permite dezvoltarea usoara a aplicatiilor.

-Este special conceput pentru sporirea performantelor in medii ostile

– Nu are suport GUI. Multe produse sau dispozitive embedded nu au nevoie de o interfata grafica cu utilizatorul (GUI). De exemplu o imprmanta conectat intr-o retea ar putea avea un server Web inclus care ofera un mecanism de configurare a diferitelor obtiuni. Astfel, deoarece acest profil nu ofera suport GUI, el poate fi integrat intr-un mediu cu acest suport. De exemplu afisajul LCD al unei imprimnte poate fi controlat printr-un sistem GUI care lucreaza in colaborare cu profilul FP .Exemplu de produse ce pot include FP: imprimante de retea, routere, aplicatii server.

PP – Personal Profile reprezinta pachetul API ce ofera suport pentru dispozitivele cu resurse limitate ce au un GUI bazat pe pachetul AWT. El are urmatoarele caracteristici:

– Compatibilitate totala AWT

– Suport pentru aplicatii de tip applet

– Suport pentru PBP – Personal Base Profile – un subset destinat dispozitivelor cu acces la retea si anumite elemente de interfata grafica.

Exemple de scenarii in care se poate folosii acest profil : PDA, browsere Web proprii dispozitivului.

Pachetele de clase puse la dispozitie pentru programarea in J2ME limiteaza practic programatorul, ele fiind specifice aplicatiilor mobile. Astfel pachetele existente in MIDP si CLDC sunt:

java.lang

java.io

java.util

javax.microedition.io

javax.microedition.lcdui

javax.microedition.midlet

javax.microedition.rms

Clasele comune din J2SE si J2ME sunt foarte putine iar la unele lipsesc anumite functii, de exemplu CLDC nu ofera suport pentru virgula mobila si de aceea au fost scoase clasele Float si Double precum si metodele aferente din celelalte clase care le foloseau.

7.2 Midlet-uri

Un Midlet este o aplicatie Java ce se executa in cadrul masinii virtuale si care extinde clasa javax.microedition.midlet.MIDlet. Pentru inceput, sistemul ce este responsabil cu managementul aplicatiilor instalate pe dispozitivul mobil incarca MIDlet-ul pentru executie, apoi este apelat constructorul clasei dupa care se trece in starea Intrerupt. In Fig 14 se subliniaza starile prin care poate trece un MIDlet precum si metodele de transit dintre acestea.

Fig.14 – Starile unui MIDlet

Activarea respectivului MID-let se face prin apelul medodei startApp. Daca in timp ce aplicatia ruleaza, avem actiuni externe cum ar fi primirea unui mesaj sau a unui apel atunci se trece in starea Intrerupt. Totodata se poate ajunge in aceasta stare si prin apelarea explicita a metodei notifyPaused.

Functionarea MIDlet-ului este asigurata prin utilizarea claselor speciale de grafica, astfel interfata grafica a acestuia poate fi realizata prin API de nivel scazut sau de nivel ridicat. API de nivel scazut reprezinta posibilitatea utilizarii obiectelor de tip Canvas care permit acces total la fiecare pixel existent pe ecranul dispozitivului. API-ul folosit la dezvoltarea unei interfete grafice de nivel rdicat implica folosirea unor obiecte grafice predefinite cum ar fi formularele (Form) si elementele ce le compun : TextField, StringItem, ChoiceGroup. Fig.15 prezinta modul de comunicare intre MIDlet si celelelte aplicatii conexe.

Fig.15

7.3 De ce Wireless cu Java?

Exista multe avantaje prin implementarea tehnologiei Java in dispozitivele Wireless, in detrimentul solutiilor conventionale, dar doua dintre ele sunt cele mai importante: securitatea si functionalitatea:

Securitatea – In prezent dispozitivele WAP acceseaza si afiseaza datele prin intermediul unui micro-browser ceea ce inseamna ca folosesc un gateway pentru conversia de la protocoalele de internet (TCP-IP ,SSL) la reteaua Wireless. Gateway-ul dintre un dispozitiv mobil si server poate fi o potentiala bresa de securitate. Se poate sa exista SSL intre server si gateway dar daca se inlocuieste acesta si se pun datele in alt format de securitate (cum ar fi WAP sau WTLS), atunci datele pot fi accesate neautorizat pe retea. Deoarece este usor de dezvoltat aplicatii Java portabile care ruleaza peste protocolul HTTP, noua generatie de tehnologie pentru dispozitivele mobile introduc un nivel de securitate superior.

Functionalitatea – Aplicatiile java de pe dispozitivele mobile pot rula chiar si atunci cand aceste dispozitive sunt in afara razei de semnal sau sunt deconectate de la retea. Astfel utilizatorul poate interactiona cu aceste programe, poate adauga date in memoria interna, iar cand reteaua permite, se face automat sincronizarea cu elementele externe(ex baza de date). Acest aspect este in contradictie cu WAP-ul care necesita in permanenta conexiunea la intrnet. Alte avantaje importante sunt: portabilitatea aplicatiilor intre dispozitivele ce contin nucleul CDLC sau CDC indiferent de producator si transferul dinamic de aplicatii ce pot rula apoi pe platforma Java.

8. Aplicatie Servlet cu comunicatie Wireless

Aplicatia implementeaza un magazin virtual de medicamente (depozit pentru farmacii) al carui baza de date poate fi populata sau actualizata de pe un telefon mobil. Astfel, evidentiem doua module principale ce compun aceasta aplicatie:

Modulul Web, ce reprezinta practic un magazin virtual, cu care clientul poate sa interactioneze dinamic si sa cumpere diferite produse .

Modulul Wireless, utilizat de angajatii firmei pentru accesarea si tratarea comenzilor active, cat si pentru actualizarea in timp real a bazei de date.

8.1 Aplicatia Web

Optiunile de baza pe care acest modul le pune la dispozitie clientului sunt :

Consultarea catalogului de produse (medicamente) care ofera informatii

despre denumire, pret, producator, stoc activ si cantitate rezervata, cat si o scurta descriere a acestor produse.

Posibilitati avansate de cautare: dupa tipul de oferta, dupa producator, dupa

numele unui anumit produs sau dupa o combinare a acestor obtiuni.

Posibilitatea vizualizarii in orice moment de timp a cosului de cumparaturi

care ofera date referitoare la fiecare tip de produs achizitionat cat si date despre suma totala de plata si numarul de produse existente in cos la momentul respectiv.

Inregistrare ca membru al magazinului printr-o pereche de nume utilizator/

parola, ce permite identificarea unica al fiecarui client.

Posibilitatea completarii unui formular prin care este introdusa adresa la care

vor fi trimise produsele din cosul de cumparaturi, precum si metoda de livrare si modalitatile de plata. Totodata utilizatorul are posibilitatea sa aleaga o anumita adresa din istoricul de adrese aferente contului sau (adrese destinatatie foloste anterior).

In final, clientul este informat despre starea comenzii curente (inregistrata cu

succes sau eroare in caz contrar) si este afisat intreg istoricul cu comenzile ce au fost solicitate de la inregistrarea utilizatorului respectiv (specificandu-se explicit starea fiecareia: „activa” sau „livrata”, precum si anumite date ce caracterizeaza fiecare comanda in parte).

Toate aceste module prezentate mai sus interactioneaza intre ele, si pentru o buna structurare a functionalitatilor fiecarui modul, fiecare tip de actiune este impachetat intr-un anumit pachet: applets (ce contine toate clasele ce extind Applet sau JApplet ) , cart (clasele folosite pentru implementarea cosului de cumparaturi), database (pentru comunicatia cu baza de date si pentru accesarea usoara a datelor ce o compun), listeners (clasele ce sunt apelate in anumite momente caracterizate de ciclul de viata al unui servlet), servlts (ce include totalitatea servlet-urilor utilizate pentru crearea contextului dinamic), wirelessCommunicationServlets (clase utilizate pentru comunicatia dintre dispozitivul Wireless si baza de date).

Pentru o prezentare cat mai clara a principiilor de functionare ce stau la baza aplicatiei Web trebuie prezentate mai intai clasele folosite de servlet-uri pentru procesarea continutului dinamic. Se evidentiaza urmatoarele clase:

database.productsDBO

Aceasta clasa reprezinta conexiunea cu baza de date si contine metodele necesare accesarii datelor de interes din baza.

database.productsDetails

Aceasta clasa este folosita pentru a crea obiecte ce contin totalitatea datelor ce caracterizeaza un anumit produs. Datele sunt introduse prin constructor :

public ProductsDetails(int product_id, String name, String description,

double price, String manufecturer, boolean offer, byte discount, int stock, int reserved)

Accesarea acestora devine apoi foarte usoara prin apelarea metodelor de tip „getters”.

database.customerDetails

Abordarea este identica cu cea prezentata mai sus, diferenta consta in crearea de obiecte ce contin totalitatea informatiilor referitoare la un anumit client (user). Declararea constructorului este urmatoarea:

public CustomerDetails(int customerId, String firstName,

String lastName, String address, String city, String telephone,String

username, String password, long pin)

Cart.ShoppingCart si Cart.ShoppingCartItem

Clase folosite pentru implementarea cosului de cumparaturi. ShoppingCartItem reprezinta obiectele ce caracterizeaza un anumit produs introdus in cos. Aceste obiecte sunt formate din doua variabile : ProductDetails pd;

int quantity; ,

iar referintele acestora sunt deasemenea impuse prin constructor. Metode implementate, pe langa cele de getters si setters mai avem metode folosite pentru incrementarea/decrementarea cantitatii, in cazul in care produsul este deja in cos

public void incrementQuantity(int newQuant){

quantity+=newQuant; }

//daca se sterg din cos anumite produse

ublic void decrementQuantity(int newQuant){

quantity-=newQuant; }

Clasa ShoppingCart este utilizata pentru memorarea obiectelor de tip ShoppingCartItem intr-o colectie de tip Map, si controlul acestor obiecte. Astfel, pentru introducerea de obiecte in colectie trebuie sa tinem seama de doua aspecte:

Daca obiectul este deja continut de colectie, caz in care se incrementeaza valoarea quantity :

if (items.containsKey(prodId)) {

ShoppingCartItem scitem = (ShoppingCartItem) items.get(prodId);

scitem.incrementQuantity(quant);}

Daca obiectul nu este continut de colectie atunci se instantiaza ShoppingCartItem folosind datele trimise ca parameru in momentul introducerii produsului in cosul de cumparaturi:

else {

ShoppingCartItem newItem = new ShoppingCartItem(pd,quant);

items.put(prodId, newItem);

Totodata in aceasta clasa sunt implementate metode folosite pentru manipularea obiectelor introduse in colectie cum ar fi afisarea produselor din cos (List getProductsInCart()) stergerea unui produs (void remove(int prodId,int quant)), extragerea sumei totale de plata (double getTotal()) sau golirea cosului de cumparaturi (void finalize()).

listeners.Listener1

Clasa ce implementeaza ServletContextListener, folosita pentru accesarea si distrugerea de obiecte in functie de ciclul de viata al unui servlet. Astfel, atunci cand servlet-ul este initializat, se pune in contextul acestuia un atribut ce contine un obiect de tip ProductsDBO:

public void contextInitialized(ServletContextEvent event) {

context=event.getServletContext();

try {

ProductsDBO prodDB = new ProductsDBO();

context.setAttribute("prodDB", prodDB);

} catch (Exception ex) {

System.out.println("Eroare, nu se poate face legatura cu baza de date ");

ex.getMessage());

}}

iar cand contextul este distrus, se elibereaza resursele folosite:

public void contextDestroyed(ServletContextEvent event) {

context=event.getServletContext();

ProductsDBO prodDB=(ProductsDBO)context.getAttribute("prodDB");

if(prodDB!=null){

prodDB.remove();//se inchide conexiunea cu baza de date

}

context.removeAttribute("prodDB");

Accesarea obiectelor puse pe context de catre clasa listener se poate face din orice servlet din metoda init() astfel:

prodDB=(ProductsDBO) getServletContext().getAttribute("prodDB");

if (prodDB == null) {

System.out.println("Obiectul de conectare la baza de date inacesibil");

}

Prima obtiune pusa la dispozitie de „depozitul de medicamente” on-line o reprezinta consultarea catalogului de produse si interactiunea prin diferite metode cu aceste produse.

8.1.1 Interactiunea si consultarea catalogului de produse

In Fig.16 este prezentat modul de afisare al catalogului, la prima accesare de catre utilizator, precum si posibilitatile de interactiune cu acesta.

Fig.16

Aceasta prima accesare evidentiaza doua servlet-uri: BannerServlet si StoreServlet.

BannerServlet – folosit pentru integrarea elementelor statice (poza, applet) in raspunsul altor servlet-uri. Applet-ul integrat reprezinta practic motorul de cautare in site, iar pentru afisarea dinamica a listei de selectie a producatorului, acestia sunt accesati din baza de date si transmisi applet-ului la fiecare incarcare a acestuia.

List manufacturers=dbo.getManufacturers();// selectare producatori

Iterator i=manufacturers.iterator();

while(i.hasNext()){

++count;

String count1=new Integer(count).toString(); //folosit pentru

//diferentierea numelor parametrilor trimisi

String namee=(String) i.next(); //nume producator

out.println("<param name=\"name"+count1+"\" value=\""+namee+"\">");}

Pentru fiecare producator se trimite perechea „name/value” unde parametrul „name” reprezinta string-ul format din „name” concatenat cu parametrul „count” iar „value” reprezinta chiar numele producatorului.

DepozitApplet . Reprezita clasa applet-ului folosit in proiect, el fiind format din doua obiecte de tip JComboBox unul pentru alegerea tipului de oferta (Toata oferta, Doar oferte speciale) si unul pentru alegerea unui anumit producator. Totodata acesta mai inculde si un JTextField cu care utilizatorul poate sa caute un produs dupa nume.

Comunicatia applet-servlet se face in momentul in care apare un eveniment nou dupa cum urmeaza:

daca utilizatorul alege un anumit tip de oferta si/sau un anumit producator

actiunea este tratata de metoda public void actionPerformed(ActionEvent e) iar obiectul asupra caruia s-a actionat este determinat folosind numele acestuia:

JComboBox o = (JComboBox) e.getSource();

//daca obiectul care a generat evenimentul este cel pentru //selectarea producatorului

if(o.getName().equalsIgnoreCase("option")){

//se face conexiunea cu servlet-ul si se transmite numele

//producatorului

}

if(o.getName().equalsIgnoreCase("offerObtion")){

//se face conexiunea cu servlet-ul si se transmite tipul de oferta //selectata

}

daca utilizatorul actioneaza si asupra obiectului de tip JTextField acest

evenimentul este tratat prin metoda:

public void caretUpdate(CaretEvent e)

Aceasta metoda preia String-ul introdus si il trimite servlet-ului.

Datele astfel preluate din applet la aparitia unor anumite evenimente trebuie transmise unui servlet pentru prelucare. Acest lucru este facut printr-o conexiune deschisa prin obiectul URLConnection la adresa respectivului servlet:

String location = "http://localhost:8080/DepozitMedicamente/StoreServlet?manufacturer="+selectedManufacturer;

Se observa ca datele sunt transmise servlet-ului StoreServlet, accesibile printr-o cerere de tip GET.

Principalele linii de cod folosite pentru aceasta conexiune sunt:

URL testServlet=null;

URLConnection servletConnection=null;

selectedManufacturer = (String)selected.getSelectedItem();

testServlet = new URL(location);

servletConnection = testServlet.openConnection();

Datorita transmiterii datelor printr-un String interpretat printr-o cerere GET, trebuie sa tinem cont de diferitele caractere speciale ce nu pot fi transmise direct („&”,”%”). Acestea vor fi inlocuite cu alte caractere ce pot fi transmise si reinlocuite in momentul utilizarii lor:

if(selectedManufacturer.contains("&")){

selectedManufacturer=selectedManufacturer.replace('&','`');}

StoreServlet este servlet-ul apelat la prima incarcare a site-ului, reprezita practic catalogul cu produse si include BannerServlet. Principalele functionalitati ale acestuia sunt:

posibilitatea afisarii produselor in functie de prima litera a acestora prin

introducerea unui element HTML de tip <select> care prin implementarea onChange() va trimite aceluiasi servlet un parametru ce contine litera selectata. Astfel prin accesarea bazei de date se returneaza produsele ale caror prima litera coincide cu cea transmisa prin parametrul letterSelected:

//litera selectata din elementul<select>

String letterSelected=request.getParameter("s1");

if(letterSelected==null){

letterSelected="a"; //in cazul in care nu este selectata alta //litera

}

else{

List list = prodDB.getFirstLetterSelected(letterSelected);

Iterator i=list.ietartor();

While(i.hasNext){ //acceseaza toate produsele corespunzatoare.

//afiseaza produsele care corespund cerintei}

afisarea costului produselor in functie de procentul de discount. Costul fiecarui

produs este stocat in baza de date in campul „price” iar campul „offer”, de tip boolean specifica daca produsul este la oferta (1) sau nu (0). Daca produsul este la oferta atunci in campul „discount” este inserat procentul de discount al produsului respectiv. Cu ajutorul acestei abordari, putem afisa catalogul de produse cu costul aferent fiecaruia:

boolean isOferta=pd.isOferta();//pd este obiect de tip ProductDetails //cu care vom prelua toate datele referitoare la un anumit produs

if(isOferta==true){

//afiseaza si utilizeaza pretul in functie de procent

}

posibilitatea specificarii cate produse de un anumit tip se doreste a fi introduse in

cosul de cumparaturi si afisarea costului total al acestora. Aceast aspect este realizat prin introducerea unor butoane HTML de incrementare si decrementare , iar costul total este afisat intr-un element de tip <text> folosit cu atributul „readonly”. Cand este actionat butonul „adauga” , se executa o functie JavaScript care trimite aceluiasi servlet parametrii folositi pentru introducerea produsului in cosul de cumparaturi (id-ul produsului si cantitatea). Acesti parametrii sunt preluati astfel:

String quant=request.getParameter("quantity"); //numarul de produse de acest

//tip

String id1=request.getParameter("id"); //id-ul produsului

Daca acesti doi parametrii devin diferiti de „null” atunci se extrage obiectul de tip ProductDetails corespunzator id-ului si se adauga in cos:

ProductsDetails productsDetails=prodDB.getProductDetails(id);

cart.add(id, quantity, productsDetails);

Obiectul de tip ShoppingCart este pus pe sesiune astfel incat pentru fiecare utilizator exista cate un cos separat, accesibil in orice moment. Mai intai se verifica daca obiectul face parte din sesiunea curenta, iar daca nu, este pus pe sesiune astfel:

ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");

// daca userul nu are cos de cumparaturi se creaza unul

if (cart == null) {

cart = new ShoppingCart();

session.setAttribute("cart", cart);

}

Asa cum s-a aratat mai sus datele transmise de applet sunt receptionate de acest servlet si accesate folosind metoda de preluare a parametrilor de pe cerere:

//daca se selecteaza un anumit producator

String selectedManufacturer=request.getParameter("manufacturer");

//daca se selecteaza tipul de oferta

String selectedOffer=request.getParameter("offerSelected");

//daca se cauta un anumit produs

String searchField=request.getParameter("field");

Acesti parametrii sunt tranferati apoi servlet-ului SearchResultServlet responsabil cu afisarea rezultatelor cautarii. Transferul contextului catre alt servlet se face prin actionarea butonului „Cauta” care executa cod JavaScript si care apoi trimite parametrii ce vor fi accesibili prin cerere GET:

"<script type=\"text/javascript\">" +

"var address=\"http://localhost:8080/DepozitMedicamente/SearchResultServlet?manufacturer=" +

selectedManufacturer+"&selectedOffer="+selectedOffer+"&searchField="+searchField+"\";" +

"window.location=address;</script>"

// apoi stergem informatia pentru a evita o eroare generata de o posibila

//cautare cu datele salvate de la o cautare anterioara

selectedManufacturer=null;

selectedOffer=null;

searchField=null;

8.1.2 Afisarea produselor in urma diferitelor tipuri de cautari

SearchResultServlet

Aceasta clasa preia datele trimise de applet si afiseaza produsele in functie de toti parametrii. Astfel, daca un parametru aferent unui obiect din Applet nu a generat un eveniment pana la actionarea butonului „Cauta”, atunci cautarea nu ia in calcul filtrarea dupa acest criteriu:

//daca nu este selectat un anumit producator sau daca a fost selectat campul „Toti producatorii”

if((selectedManufacturer==null)||

(selectedManufacturer.equals("Toti_producatorii"))){

selectedManufacturer=”%”;

}

//daca nu e selectat tipul de oferta sau daca a fost selectat campul “Toata oferta”

if((selectedOffer==null) ||(selectedOffer.equals("toata_ofera"))){

selectedOffer="%";

}

//daca nu este completat campul de cautare sau daca acesta a fost sters

if((searchField==null)||((searchField!=null)&&(searchField.equals("")))){

fieldUpdated="%";

}

Caracterul “%” este folosit la interogarea bazei de date atunci cand se doreste sa nu se tina cont de anumiti parametrii. Astfel pentru orice tip de cautare este apelata acceasi metoda din ProductsDBO :

List getProducts(String offerSelected,String manufacturer,String search) ;

Aceasta metoda acceseaza baza de date si returneaza informatiile din tabela „products” pe baza urmatoarei interogari:

String query="SELECT * FROM products WHERE manufacturer LIKE ? and oferta LIKE ? and name LIKE ?";

Exemplu: daca vrem sa cautam produsele ce sunt la oferta si au ca producator firma „Pfizer” (Fig.17) atunci parametrul name devine ”%” si nu este luat in considerare de query.

Fig.17

Rezultatul cautarii din Fig.17 il reprezinta totalitatea produselor ce sunt la oferta si au ca producator firma Pfizer. Totodata, in cazul introducerii unui sir de caractere in campul de cautare, interogarea va returna toate produsele ce contin respectivul sir de caractere (nefiind nevoie scrierea exacta a numelui unui anumit produs)(Fig.18).

Fig.18 – cautare dupa nume

8.1.3 Interactiunea dintre client si cosul de cumparaturi virtual

ViewCartServlet

Acest servlet este responsabil cu toate aspectele ce caracterizeaza cosul de cumparaturi al unui anumit client. Accesarea produselor se face prin apelarea metodei

List cartList=cart.getProductsInCart();

care returneaza o lista cu obiecte de tip ShoppingCartItem . Acestea sunt apoi iterate si folosite pentru afisarea tuturor informatiilor aferente fiecarui produs:

Iterator i=cartList.iterator();

while(i.hasNext()){

ShoppingCartItem sci=(ShoppingCartItem) i.next();

ProductsDetails pDetails= sci.getProductsDetails();

int quantity=sci.getQuantity();

//urmeaza codul HTML de afisare a tabelei cu produsele din cos

}

Sunt afisate si alte informatii de interes cum ar fi suma totala de plata, numarul de produse diferite din cos, cantitatea totala de produse (Fig.19)

Acest servlet ofera clientului si cateva optiuni de intetractiune cu acesta si anume posibilitatea stergerii unui anumit produs, stergerea continutului intregului cos, legatura cu StoreServlet pentru continuarea cumparaturilor si legatura cu FormServlet pentru comandarea produselor.

Fig.19 –Cosul de cumparaturi

8.1.4 Comandarea produselor

FormServlet

Este servlet-ul ce impementeaza autentificarea unica a fiecarui client printr-o pereche User/Parola. Exista doua variante:

Clientul are deja un cont pe site caz in care este rugat sa introduca datele de logare pentru a putea comanda produsele (Fig 20.1)

Clientul nu are inca un cont activ, caz in care trebuie sa bifeze obtiunea pentru membru nou (Fig 20.2)

In ambele variante sunt folosite formulare HTML care transmit datele prin metoda POST catre servlet-ul RecievedFormServlet.

Fig 20.1 – logare membru existent

Fig 20.2 – creare cont membru nou

RecievedFormServlet

Prima actiune efectuata de acest servlet este preluarea informatiilor de logare si introducerea lor in baza de date. In cazul in care avem client nou, acesta trebuie sa completeze in intregime formularul cu datele sale corecte altfel vor aparea mesaje de eroare ce vor indruma la corectarea respectivei greseli. Apoi aceste informatii sunt preluate si introduse in baza de date folosind metoda :

prodDB.insertUser(firstName, lastName, address,city, telephone, pin, user,pass);

metoda ce introduce in tabela „customers” datele ce caracterizeaza persoana care a efectuat comanda, iar in tabela „userpass” perechea user/parola aferenta clientului. Apoi dupa autentificare se extrage obiectul ce caracterizeaza clientul logat (CustomerDetails):

//extragere obiect de tipul customerDetails aferent perechii userName/password

customerDetails cs=prodDB.selectCustomer(userName, password);

Daca autentificarea a avut loc cu succes (daca obiectul „cs” nu este nul) atunci se afiseaza o pagina in care clientul este rugat sa confirme daca intradevar doreste sa comande respectivele produse (Fig 21.1). Daca datele de logare nu corespund nici unui client atunci acesta este rugat sa se autentifice din nou (Fig 21.2).

Fig.21.1 – Confirmarea comenzii sau anularea ei

Fig 21.2 – Date de logare eronate

Din motive de securitate, toate datele transferate catre acest servlet sunt obtinute prin metoda POST (este evident faptul ca nu putem trimite parole ca siruri de caractere accesibile prin cerere GET).

Daca se actioneaza butonul „Comanda” atunci, actiunea este tratata tot de acest servlet dar prin metoda GET (se trimite un parametru pe cerere GET). Astfel, clientul este rugat sa introduca datele ce vor reprezenta adresa unde se expediaza comanda, precum si modalitatea de plata si modalitatea de livrare (Fig.22). In cazul in care clientul a mai trimis comenzi la diferite destinatii, acestea sunt accesate automat din baza de date si afisate intr-un obiect de tip drop-down. Daca se actioneaza asupra unui element din acesta, formularul este automat completat venind astfel in sprijinul clientului. Metoda ce verifica daca exista adrese utilizate anterior de clientul autentificat este:

List addresses=prodDB.getCustomerAddresses(custId);

metoda ce acceseaza baza de date si returneaza o lista cu toate adresele utilizate de clientul autentificat unic prin cheia sa primara (custId).

Fig.22 – Formular de comanda

Dupa ce formularul a fost completat in intregime si trimis, datele vor fi preluate tot de acest servlet. Astfel, folosind parametrul viewForm putem sa controlam daua afisari diferite ale aceluiasi servlet:

viewForm=request.getParameter(„viewForm”);

if(viewForm==null){

//urmeaza codul de afisare al formularului prezent in Fig.22

}

//daca viewForm!=null

else{

//se afiseaza istoricul de comenzi

//se trimite viewForm=”true” pentru a nu se mai afisa formularul

}

Atunci cand viewForm devine diferit de nul, sunt preluate datele oferite de client si introduse in baza de date intr-un mod sincronizat (pentru a nu se permite declansarea unor erori ca urmare folosirii aplicatiei Web de mai multi utilizatori).

Preluarea datelor din formular:

String cName=request.getParameter("cName");

String cAddress=request.getParameter("cAddress");

String cCity=request.getParameter("cCity");

String cCountry=request.getParameter("cCountry");

String cTelephone=request.getParameter("cTelephone");

String delivary=request.getParameter("sendMethod");

String payDate=request.getParameter("s1");

Introducerea lor in baza de date: datele ce compun adresa destinatie vor fi stocate in tabela „reviver_data” iar celelalte in tabela „transactions”. Totodata acum se actioneaza si comanda propriu-zisa care reactualizeaza baza de date prin schimbarea stocurilor aferente produselor ce au fost comandate si trecerea acestor valori in categoria „rezervat”. Stocul considerat rezervat reprezinta cantitatea de produse ce sunt prezente in depozit dar pentru care exista comenzi active.

/se introduc datele in baza de date

synchronized (this) {

prodDB.insertOrder(custId,cName,cAddress, cCity, cCountry,

cTelephone, cart.getTotal(), delivary, payDate);

//se efectueaza comanda cu effect in baza de date

prodDB.orederingCart(cart);

}

Ultima actiune ce trebuie efectuata de servlet in urma celor prezentate mai sus, o reprezinta afisarea istorcului de comenzi (Fig.23). Acest lucru este indeplinit prin utilizarea a doua metode: (1) una ce extrage din baza de date toate comenzile aferente utilizatorului curent si (2) alta care extrage continutul fiecarei comenzi:

Datele referitoare la comenzi sunt: data si ora efectuarii comenzii, suma totala de plata, adresa la care trebuie/au fost trimise produsele precum si starea comenzii respective (comanda activa sau comanda livrata) .

List list=prodDB.getOrderById(custId);

Iterator iterator=list.iterator();

while(iterator.hasNext()){

//urmeaza cod ce extrage si afiseaza informatia 1), iar pentru fiecare set ce caracterizeaza comanda se va afisa si datele ce compun aceasta comanda – 2)

List history=prodDB.getOrdersHistory(orderId);

Iterator it=history.iterator();

While(it.hasNext)

//cod ce afiseaza continutul unei comenzi

Datele ce caracterizeaza continutul unei comenzi sunt : denumire produs, descriere, pret pe unitate, producator, eventualul discount si cantitatea comandata pentru fiecare produs.

Fig 23 – Istoric comenzi

8.1.5 Baza de date

8.1.5.1 – Legaturle bazei de date

Baza de date ce compune aceasta aplicatie este formata din sapte tabele ce sunt strans legate intre ele:

Customers – contine datele referitoare la clientii ce doresc sa comande diferite produse oferite de magazinul virtual (id, nume,prenume,adresa,oras,telefon,cnp) (Fig 24.1).

Fig. 24.1 – Tabela clientilor

Transactions – memoreaza informatiile despre o anumita tranzactie (id, data si ora efectuarii tranzactiei, suma totala de plata, modalitatea de plata si starea comenzii-1 pentru comanda activa si 0 pentru comanda incheiata)(Fig 24.2).

Fig 24.2 – Tabela de tranzactii

Reciver_data – tabela ce contine adresele de destinatie ale comenzilor efectuate de diferiti client (id, numele companiei, adresa, oras, tara, numar de telefon)(Fig 24.3)

Fig 24.3– Tabela cu inforatiile despre adresele destinatie

Orders – tabela de legatura ce permite corespondenta intre client, tranzactie si adrese destinatie(Fig. 24.4)

Fig 24.4 – Tabela de comenzi

Products – contine toata informatia aferenta produselor disponibile in stoc (id, nume produs, descriere, pret, producator, oferta, discount, stoc, rezervat). Campul oferta poate sa fie „0” sau „1” , astfel se permite prin program implementarea tipului boolean (1=true si 0=false). In cazul in care campul „oferta” este trecut pe pozitia „1” atunci se impune introducerea in campul „discount” a procentului de reducere.

Campul stock contine numarul de produse de acest tip din depozit

Campul reserved contine numarul de produse ce sunt in decurs de livrare (Fig 24.5).

Fig 24.5 – Tabela cu produsele din depozit

Products_to_cart este deasemenea o tabela de legatura ce permite implementarea relatiei many-to-may intre tabela „Comenzi” si tabela „Products”. Totodata aici se memoreaza si cantitatea comandata aferenta fiecarui produs. Aceasta tabela permite implementarea istoricului de comenzi .(Fig 24.6)

Fig 24.6 – Tabela pentru istoricul de comenzi

Userpass este tabela responsabila cu memorarea perechilor user/parola unice pentru fiecare client (Fig 24.7)

Fig 24.7 – Tabela ce contine perechile user/parola

Legaturile dintre tabelele bazei de date sunt evidentiate in Fig 25. Baza sageatei indica cheia primara iar varful evidentiaza cheia secundara.

Fig. 25 – Relatiile dintre tabelele bazei de date, evidetiind cheile de legatura

8.1.5.2 ProductsDBO (conexiunea aplicatie – baza de date)

ProductsDBO reprezinta clasa responsabila de conexiunea la baza de date si de interogarile efectuate asupra acesteia. De fiecare data cand aplicatia Web necesita accesarea de informatii din baza de date, se instantiaza un nou obiect de tipul ProductsDBO si se creaza o noua conexiune cu aceasta, iar apoi, folosind metodele definite, se extrag informatiile dorite. Deoare folosim sistemul propriu ca si server de baze de date avem urmatoarea conexiune data de contructorul clasei:

Connection con;

//constructorul clasei

public ProductsDBO(){

String userName = "root";

String password = "licenta";

String url = "jdbc:mysql://localhost/medicamente";

//se incarca driver-ul Mysql

Class.forName ("com.mysql.jdbc.Driver").newInstance ();

//se extrage obiectul de tip Connection care reprezinta conexiunea cu baza de //date

con = DriverManager.getConnection (url, userName, password);

}

In continuare, conexiunea ce ne intereseaza fiind efectuata, ramane de implementat mecanismul ce permite accesarea bazei de date de mai multi utilizatori, in acelasi timp, fara alterarea datelor. Acest aspect este indeplinit prin utilizarea metodelor „sincronizate” ce permit controlul conexiunii:

//in cazul in care conexiunea este libera se creaza obiectul responsabil cu aceasta, in caz contrar //se asteapta eliberarea ei

protected synchronized Connection getConnection() {

while (conFree == false) {

try {

wait();

} catch (InterruptedException e) {

}

}

// variabila „conFree” informeaza existenta unei conexiuni in desfasurare

conFree = false;

notify();

return con;

}

//metoda ce elibereaza conexiunea

protected synchronized void releaseConnection() {

conFree = true;

notify();

}

Informatiile de interes sunt accesate din baza de date in urma unor interogari „sql” incapsulate in metode ce pot fi accesate oricand din program. Exemplu de interogari :

Pentru extragerea rezultatelor cautarii din applet (se poate cauta un produs in

functie de tipul de oferta, de numele producatorului si de numele acestuia).

SELECT * FROM products WHERE manufacturer LIKE ? and oferta LIKE ? and name LIKE

Pentru extragerea numelor tuturor producatorilor sau pentru afisarea produselor in

functie de prima litera selectata folosim:

SELECT DISTINCT manufacturer FROM products; sau

SELECT * from products WHERE name LIKE ? ;

unde „?” este inlocuit cu litera selectata, concatenata cu „%”.

Inserara informatiilor unui client nou ce a completat datele de inregistrare sunt

introduse in tabele „Customers” si Userpass astfel:

INSERT INTO customers (first_name,last_name,address,city,telephone,cnp) VALUES (?,?,?,?,?,?);

INSERT INTO userpass (user_name,password) VALUES (?,?);

Extragerea tuturor adreselor aferente unui client, utilizate pentru expedierea de

produse sunt listate prin utilizatea unui JOIN intre tabelele „Customers”, „Orders” si „Reciver_data” :

SELECT DISTINCT reciver_data.rec_id, reciver_data.company_name,

reciver_data.company_address, reciver_data.company_city FROM

customers, orders, reciver_data WHERE (customers.customer_id=?) AND

(customers.customer_id=orders.customer_id) AND

(orders.reciver_id=reciver_data.rec_id)";

Inserarea unei noi comenzi este efectuata prin metoda „inserOrder” care are ca

parametrii, toate informatiile ce trebuie introduse in tabela „Reciever_data” si „Transaction”. Totodata acum se populeaza si tabela „Orders” cu tooate cheile secundare necesare legaturii dintre tabele. Prima operatiune efectuata este verificarea daca adresa de destinatie (Recived_data) a mai fost utilizata (pentru a nu introduce acceasi adresa de doua ori in baza de date):

String existsSelectedAddress=

“SELECT rec_id FROM reciver_data WHERE company_name=? AND

company_address=? AND company_city=? AND company_country=? AND

company_phone=?";

Daca interogarea intoarce un rezultat atunci sarim peste etapa de inserare a acestor informatii in baza :

existAddress= false;

PreparedStatement pstm= con.prepareStatement(existsSelectedAddress);

. . .

//se introduce parametrii pentru interogare

. . .

ResultSet rs=pstm.executQuery()

if(rs0.next()){

existAddress=true;

}

In continuare, daca parametrul „existAddress” este fals se executa urmatorul „insert” ce introduce datele referitoare la adresa de destinatie in tabela „Reciver_data”:

String updateReciverData=

"INSERT INTO reciver_data,

company_name,company_address,company_city,company_country,

company_phone ) VALUES (?,?,?,?,?)";

Tot acum sunt introduse si datele ce caracterizeaza respectiva tranzactie, urmand ca apoi sa se selecteze id-ul unic al acesteia:

String updateTransaction=

"insert into transactions (transaction_date, amount_paid,

pay_date,active) VALUES (?,?,?,1)";

String selectLastTransactionId=

"SELECT MAX(transaction_id) as transaction_id FROM transactions";

In final se populeaza tabela „Orders”:

String updateOrders=

"insert into orders (customer_id,transaction_id,reciver_id) values (?,?,?)";

Deoarece avem mai multe interogari ce trebuie executate in acelasi timp, pentru a nu permite aparitia de erori generate de diferite fire de executie, vom folosi metoda con.setAutoCommit(false), care este implemntata special pentru acest lucru.

In final sunt dezvolate metodele ce permit afisarea „istoricului de comenzi” atasat

fiecarui client. Astfel, pentru fiecare utilizator inregistrat se cunoaste cheia primara a acestuia (customer_id), cheie ce permite idetificarea tuturor comenzilor (si implicit a adresei destiantie si a datelor despre trazactie aferente fiecarei comenzi) atasate ei. Acest aspect este indeplinit astfel:

String select=

"SELECT orders.order_id, transactions.transaction_date,

transactions.amount_paid,transactions.pay_date, transactions.active,

reciver_data.company_name, reciver_data.company_address,

reciver_data.company_city, reciver_data.company_country,

reciver_data.company_phone FROM orders,transactions,reciver_data

WHERE orders.customer_id=? AND orders.reciver_id=reciver_data.rec_id

AND orders.transaction_id=transactions.transaction_id ORDER BY

transactions.transaction_date desc;";

Apoi, pentru fiecare set de informatii atasat unei comenzi se executa inetrogarea ce extrage toate produsele atasate comenzii respective:

String select=

"select * FROM products,products_to_cart,orders WHERE

orders.order_id=? AND orders.order_id=products_to_cart.order_id AND products_to_cart.product_id=products.product_id;";

8.2 Aplicatia Wireless

Partea a II-a a aplicatiei isi propune reactualizarea sau popularea bazei de date (dezvoltate anterior) printr-un dispozitiv Wireless. Aplicatia este de sine statatoare, si comunica cu serverul Mysql prin intermediul unor servlet-uri special create pentru receptionarea si transmiterea datelor catre telefonul mobil. La deschiderea aplicatiei, utilizatorul este rugat sa se conecteze la baza de date, pentru a putea comunica cu aceasta si daca acest aspect este realizat atunci se prezinta doua optiuni (Fig. 26):

– Afisarea clientilor ce au comenzi active

Inserarea unui nou produs in baza de date sau reactualizarea unui produs deja existent

Fig.26 – optiunile utilizatorului

Se evidentiaza astfel doua structuri diferite ce compun aplicatia pentru telefonul mobil si anume partea care este responsabila cu accesarea si tratarea comenzilor active aferente clientilor si partea de populare (reactualizare) a bazei de date. Clasa principala, pe baza careia aceasta aplicatie poate fi rulata este „LoadMIDlet”, clasa care permite clientului selectia unei actiuni ce duce la una din structurile prezentate.

8.2.1 Accesarea, tratarea si incheierea comenzilor active

Daca in continuare se solicita „afisare clienti ce au comenzi active ”, clasa LoadMIDlet lanseaza un nou fir de executie (thread) care acceseaza servlet-ul GetUsersWithOrdersServlet , responsabil cu solicitarea si transmiterea respectivelor informatii din baza de date (Fig 27).

Fig 27 – Clientii ce au comenzi active

Conexiunea pe care thread-ul o face cu servlet-ul este realizata prin apelarea URL-ului acestuia:

//URL-ul de conexiune cu servlet-ul

String url = "http://localhost:8080/DepozitMedicamente/GetUsersWithOrdersServlet";

//se deschide conexiunea care poate sa primeasca sau sa trimita date

HttpConnection hc =(HttpConnection) Connector.open(url, Connector.READ_WRITE);

//stream-ul de trimitere date

OutputStream os=hc.openOutputStream();

//stream-ul de receptie date

InputStream in= hc.openInputStream();

Atunci cand servlet-ul GetUsersWithOrdersServlet este apelat de MIDlet, acesta acceseaza baza de date si returneaza toti clientii ce au comenzi ce trebuie onorate. Interogarea bazei de date este urmatoarea:

String select=

"SELECT DISTINCT customers.customer_id, customers.first_name, customers.last_name, FROM customers,orders, transactions WHERE customers.customer_id=orders.customer_id AND orders.transaction_id=transactions.transaction_id AND transactions.active=1;";

Informatia este transmisa apoi printr-un sir de caractere ce poate fi interpretat de MIDlet.

Apoi utilizatorul poate selecta din lista, un anumit client, moment in care se lanseaza un nou fir de executie ce primeste ca parametru id-ul clientului selectat. Acest id este transferat catre GetUserOrderingsServlet, servlet responsabil cu extragerea din baza de date a informatiilor ce caracterizeaza comenzile respectivului client (Fig. 28). Pentru a putea extrage id-ul trimis de MIDlet , in servlet este definita o metoda ce extrage informatia de pe fluxul de intrare (input stream):

private String readDataFromRequest(HttpServletRequest request) {

String content = null;

BufferedReader bf = null;

try {

//se pune intr-un buffer informatia venita pe fluxul de intare

bf = new BufferedReader(new InputStreamReader(request

.getInputStream()));

//se citeste linia (singura de interes)si se returneaza

content = bf.readLine();

} catch (IOException io) {

io.printStackTrace();

}

//se returneaza chiar id-ul clientului

return content;

}

Pe baza id-ului primit se acceseaza informatiile din baza si se transmit sub forma de text formatat catre MIDlet, informatii ce permit afisarea comenzilor clientului selectat, in ordinea vechimii acestora . Textul formatat contine caractere speciale ce vor ajuta MIDlet-ul sa interpreteze corect informatia venita pe fluxul de intrate:

Text formamat:

~Data efectuarii comenzii – 2009-06-04 16:09:48.0

Suma totala de plata – 669.24

Metoda de plata – 60zile

Adresa destinatar:

Numele companiei – Alcor

Adresa – Piata Alba Iulia nr 51

Judet – Bucuresti

Telefon – 021 345342

––––––––––––––––––––-

Iar la sfarsitul tuturor comenzilor sunt transmise si id-urile acestora (id-uri folosite pentru a identifica o comanda selectata):

~`10|4|3|2|1|

MIDlet-ul preia informatia astfel:

//se primeste informatia pe fluxul de intrare

InputStream is=httpConnection.openInputStream();

//caracterul ce va fi citit in while

int ch=0;

boolean jump=false;

//executa bucla pana cand se citesc toate caracterele

while((ch=is.read())!=-1){

//daca acel caracter citit „ch” nu reprezinta inceput de afisare a unei noi comenzi( ~ ) sau daca //nu reprezinta sfarsitul de afisare al tuturor comenzilor( ` ) se extrage o comanda

if(((char)ch!='~')&&((char)ch!='`')&&(jump==false)){

sb.append((char)ch);

}

//daca s-a terminat de citit o comanda, aceasta este introdusa in lista pentru a putea fi selectata de //utilizatorul telefonului mobil

else if((char)ch=='~') {

userList.append(sb.toString(), null);

sb=new StringBuffer();

}

//daca s-au terminat de adaugat in lista toate comenzile se informeaza ca urmatorul flux de date //va fi un sir de numere ce reprezinta fiecare id al comenzilor afisate (informarea se face prin //atributul jump=true)..

else if((char)ch=='!'){

jump=true;

continue;

}

//caracterul „|” informeaza trecerea la un alt id

else if((char)ch!='|'){

jump=true;

orderBuffer.append((char)ch);

}

//fiecare id este introdus intr-un vector v

else{

v.addElement(orderBuffer);

orderBuffer=new StringBuffer();

}

Fig.28 – Comenzile clientului Adamescu Marian

In continuare, utilizatorul selecteaza o anumita comanda din lista afisata pe ecranul telefonului pentru a accesa informatiile referitoare la produsele continute in aceasta. Astfel se creaza un nou fir de executie (GetProductsInOrderConnect) care afiseaza aceste informatii si care ofera obtiunea de „Incheie comanda”. Datele aferente unei comenzi sunt transmise MIDlet-ului prin cerere asupra servlet-ului GetContentOrderServlet, care pe baza id-ului comenzii selectate va returna datele ce o caracterizeaza (Fig.29).

Fig.29 – Lista ce caracterizeaza continutul unei comenzi

In final, cand produsele respective vor fi livrate, utilizatorul va actiona butonul „Incheie comanda” care va avea ca efect modificarea campului „Rezervate” din aplicatia Web si etichetarea respectivei comenzi in istoric ca find „Comanda livrata:”

//daca se actioneaza butonul „Incheie comanda” se creaza thread-ul DeleteOrderConnect ce are ca parametrii: id-ul comenzii, formularul actual, obiectul de afisare a formularului si obiect de tip MIDlet pentru comanda exit.

public void commandAction(Command c, Displayable d) {

if((d==orderForm)&&(c==endOrder)){

DeleteOrderConnect doc=new

DeleteOrderConnect(orderId,orderForm,mDisplay,midlet);

Thread thread=new Thread(doc);

thread.start();

mDisplay.setCurrent(orderForm);

}

MIDlet-ul DeleteOrderConnect acceseaza servlet-ul SetOrderInactiveServlet care, pe baza id-ului comenzii acceseaza baza de date si modifica informatia referitoare la cantitatea de produse rezervate (specifica unui anumit produs), si eticheteaza comada ca fiind „terminata” (se trece campul „active” din tabela „transaction” pe „0”). Interogarile cu baza de date sunt prezentate mai jos, interogari ce trebuie desemenea executate toate in acelasi timp ( setAutoComit(false) ).

String selectProductsInOrder=

"SELECT products_to_cart.amount,products.reserved,products.product_id FROM orders,products_to_cart,products WHERE orders.order_id=? AND orders.order_id=products_to_cart.order_id AND products_to_cart.product_id=" +

"products.product_id";

String insertActive=

"UPDATE transactions,orders SET transactions.active=0 WHERE orders.order_id=? AND orders.transaction_id=transactions.transaction_id ";

String updateReserved=

"UPDATE products SET reserved=? WHERE product_id=?";

8.2.2 – Inserarea sau modificarea unui produs in baza de date Mysql

Utilizatorul acestui soft poate sa doreasca sa modifice produsele din baza de date direct de pe telefonul sau mobil. Pentru acest lucru este folosit un formular ce trebuie completat in intregime, iar datele vor fi trimise servlet-lui responsabil cu actualizarea bazei de date (InsertProductServlet).

Astfel daca utilizatorul alege obtiunea „Inserati un produs in baza de date”, se afiseaza formularul respectiv (Fig.30).

Crearea formularului (MIDlet-ul InsertProductForm):

//se creaza obiectul de tip Form (formular)

Form insertForm=new Form(„Intoduceti un produs in baza de date”)

//se creaza obiectele ce vor compune formularul

pName=new TextField("Numele produsului", "", 64, TextField.ANY);

pDescription=new TextField("Descriere", "", 64, TextField.ANY);

//se impune ca in campul de pret sa se introduca doar valori numerice

pPrice=new TextField("Pret(ron)", "", 5, TextField.NUMERIC);

pManufacturer=new TextField("Producator", "", 64, TextField.ANY);

// butoane radio pentru a specifica daca produsul este la oferta sau nu

offer=new ChoiceGroup("Este produsul la oferta? ", ChoiceGroup.EXCLUSIVE, new String[] {"Da", "Nu"}, null);

offer.setSelectedIndex(1, true);

pDiscount=new TextField("Discount (%)", "", 2, TextField.NUMERIC);

pStock=new TextField("Stoc", "", 5, TextField.NUMERIC);

//daca se selecteaza butonul „Da” din ChoiceGroup este afisat automat un nou camp ce va contine procentul de reducere (Fig 30).

public void itemStateChanged(Item item) {

if((item==offer)&&(offer.getSelectedIndex()==0)){

//se inlatura ultimul obiect adaugat (stoc)

insertForm.delete(5);

//se introduce elementul pentru discount

insertForm.insert(5, pDiscount);

// in final se introduce campul ce specifica numarul de produse disponibile

insertForm.insert(6,pStock);

}

//dupa actionarea butonului „Trimite”, daca unul din campurile prezente nu este completat, se informeaza acest lucru:

if((name.equals(""))||(description.equals(""))||(price.equals(""))||(manufacturer.equals(""))

||(stock.equals(""))){

//”index este folosit pentru afisarea doar o singura data a mesajului de alert”

if(index!=0){

insertForm.delete(index);

}

index=insertForm.append(alert);

}

//daca toate campurile sunt completate, se extrage informatia dorita si se transmite prin //parametru catre noul fir de executie InsertProductConnect:

//sb reprezinta informatia continuta ca un obiect de tip StringBuffer

InsertProductConnect ipc=new InsertProductConnect(sb);

Thread thread=new Thread(ipc);

thread.start();

Insert productConnect comunica cu servlet-ul InsertProductServlet care este responsabil cu reactualzarea bazei de date.

Fig 20 – Formularul de inserare si eventualele actiuni rezultate in urma diferitelor evenimente

BIBLIOGRAFIE

1. Bryan Brasham, Kathy Sierra, BertBates: Head First Servlet and JSP, 2nd.Edition,

Mar. 2008

2. Jason Hunter, William Crawford: Java Servlet Programming, 2nd.Edition, April 2001

3. *** http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html – The J2EE 1.4 Tutorial

Dec 2005

4. http://java.sun.com/javaee/5/docs/firstcup/doc/toc.html – Your First Cup: An Introduction to the Java EE Platform

5. Qusay H. Mahmoud, Learning Wireless Java, Second Edition 2006

6. *** http://blogs.sun.com/mobility_techtips/entry/comparing_mobile_platforms_java_me – Bruce Hopkins, Comparing Mobile Platforms. Article 2008

7. http://developers.sun.com/mobility/midp/articles/wtoolkit/ -Wireless Development Tutorial

8. http://developers.sun.com/mobility/midp/articles/mcommerce/ – Integrated Java Technology for End-to-End m-Commerce, article by Alka Gupta and Mayank Srivastava. 2003

9. http://java.sun.com/products/sjwtoolkit/wtk2.5.2/ – Documentation home for Sun Wireless Toolkit for CLDC, 2007

BIBLIOGRAFIE

1. Bryan Brasham, Kathy Sierra, BertBates: Head First Servlet and JSP, 2nd.Edition,

Mar. 2008

2. Jason Hunter, William Crawford: Java Servlet Programming, 2nd.Edition, April 2001

3. *** http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html – The J2EE 1.4 Tutorial

Dec 2005

4. http://java.sun.com/javaee/5/docs/firstcup/doc/toc.html – Your First Cup: An Introduction to the Java EE Platform

5. Qusay H. Mahmoud, Learning Wireless Java, Second Edition 2006

6. *** http://blogs.sun.com/mobility_techtips/entry/comparing_mobile_platforms_java_me – Bruce Hopkins, Comparing Mobile Platforms. Article 2008

7. http://developers.sun.com/mobility/midp/articles/wtoolkit/ -Wireless Development Tutorial

8. http://developers.sun.com/mobility/midp/articles/mcommerce/ – Integrated Java Technology for End-to-End m-Commerce, article by Alka Gupta and Mayank Srivastava. 2003

9. http://java.sun.com/products/sjwtoolkit/wtk2.5.2/ – Documentation home for Sun Wireless Toolkit for CLDC, 2007

Similar Posts

  • Tehnici, Servicii Si Solutii de Securitate Pentru Intraneturi Si Portaluri

    1. INTRODUCERE 2. CRIPTOGRAFIA 2.1 Caracteristici generale 2.2 Criptografia cu cheie secretă 2.3 Criptografia cu cheie publică 2.4 Managementul cheilor și distribuția acestora 2.5 Funcțiile Hash 2.6 Utilizarea semnăturilor digitale. Riscuri de securitate 2.7 Certificate digitale. Riscuri de securitate 3. TEHNICI, SERVICII ȘI SOLUȚII DE SECURITATE PENTRU INTRANETURI ȘI PORTALURI 3.1 Autentificarea Kerberos V5 3.1.1…

  • Managementul Documentelor. Sistemele de Management Si Arhivare Electronica

    Cuprins Introducere – Managementul documentelor 1 Capitolul 1. Sisteme de management 5 1.1 Document pe hârtie versus document electronic 5 1.2 Digitizarea și semnătura electronică 8 1.3 Sistemele de management ale documentelor 12 1.4 Sistemul de management al calității 13 Capitolul 2. Gestionarea documentelor în sistem electronic 16 2.1 Ce este Document Management System (DMS)…

  • Aplicatie Informatica Privind Urmarirea Operativa a Miscarii Marfurilor

    CAPITOLUL I PREZENTAREA GENERALĂ A AGENTULUI ECONOMIC Cadrul general de funcționare Denumirea societății: S.C. ELPREST S.R.L. Forma juridică: Societatea comercială “ ELPREST “ S.R.L. este persoană juridică română, cu capital integral privat și formă juridică de societate cu răspundere limitată Sediul societății: România – Craiova, strada România Muncitoare nr:132, județul Dolj. Societatea poate avea sucursale,…

  • Proiectarea Unei Aplicatii Magazin Online Folosind Php Si Mysql

    Cuprins Capitolul 1. Introducere 1.1. Tehnologia in ziua de azi…………………………………………………………………..2 1.2. Site-uri si aplicații web………………………………………………………………………….3 1.3. Introducere a conținutului lucrării……………………………………………..7 Capitolul 2. Prezentarea tehnologiilor utilizate 2.1. Internet…………………………………………………………………………………………………9 2.2. World Wide Web…………………………………………………………………………………..11 2.3. HTML…………………………………………………………………………………………………..12 2.4. JavaScript……………………………………………………………………………………………..18 2.5. CSS……………………………………………………………………………………………………….22 2.6. XAMPP…………………………………………………………………………………………………25 2.7. PHP……………………………………………………………………………………………………….26 2.8.MySql……………………………………………………………………………………………………..31 2.9. Apache……………………………………………………………………………………………………40 Capitolul 3. Proiectarea și Implementarea aplicației 3.1. Baza de date utilizată………………………………………………………………………………42…

  • Curbe Si Suprafete Bezier

    Prefață Modelarea geometrica este un instrument de bază în inginerie și în știință. Fundamentată ca o ramură nouă a informaticii și matematicii impusă de deyvoltarea tehnologiei calculatoarelor, modelarea geometrică (cunoscută și sub numele de Computer Aided Geometric Design sau prescurtat CAGD) este o geometrie bayată pe calculator. Primul beneficiar al tehnicilor CAGD a fost industria…