Sunteți pe pagina 1din 371

Universitatea Transilvania din Bra sov Facultatea de Matematic aInformatic a

ERNEST SCHEIBER

PROGRAMARE DISTRIBUITA IN JAVA

Bra sov

Prefat a
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit programarea aplicat iilor client - server: socluri Java; apelarea metodelor de la distant a (Remote Method Invocation - RMI ); CORBA - Common Object Request Brocker Arhitecture ; mesageria Java; servlet; Java Server Pages - JSP; Enterprise Java Bean. Accentul cade pe detaliile tehnice de realizare a comunicat iilor si pe arhitectura programelor / aplicat iilor care le utilizeaz a. Trebuie semnalat faptul c a exemplele date nu incorporeaz a aspecte indispensabile unei aplicat ii informatice la standardele zilei: securitate, autenticare si autorizare; interfat a grac a pentru componenta client; utilizarea bazelor de date relat ionale / orientate obiect / NoSQL. Metodele si instrumentele de programare vor exemplicate pe problema foarte simpl a de calcul a celui mai mare divizor comun a dou a numere naturale. Codul acestei metode de calcul poate Varianta imperativ a ca metod a 3

1 2 3 4 5 6 7 8 9 10 11

public long cmmdc( long m, long n ) { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r ! = 0 ) ; return c ; }

care se poate transforma ntr-o lambda expresie


1 2 3 5 6 7 8 9 10 11 12 13 14 15

i n t e r f a c e CmmdcService { long cmmdc( long m, long n ) ; } s t a t i c CmmdcService cmmdcService=( long m, long n ) > { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r ! = 0 ) ; return c ; };

Varianta declarativ a / recursiv a


1 2 3 4 5 6 7 8 9

public long cmmdc( long m, long n ) { i f (m ==n ) return m; else i f (m >n ) return cmmdc(m n , n ) ; else return cmmdc(m, n m) ; }

Guava: Google Core Libraries for Java posed a o metoda de calcul a celui mai mare divizor a dou a numere naturale com.google.common.math.LongMath. gcd(...). Pentru aplicat iile care utilizeaz a o baz a de date, sistemul de gestiune a bazei de date (SGBD) va una dintre sistemele Derby/Javadb sau mysql. Tiparul de nv a tare propus este 1. Se instaleaz a toate resursele necesare (Se exemplic a la laborator). 2. Se execut a aplicat ia / aplicat iile din curs (Se exemplic a la laborator).

5 3. Pentru ecare tehnologie, pe suportul oferit de curs, se programeaz ao alt a aplicat ie. Propunem urm atoarele teme: Conversia dintre grade Celsius si grade Fahrenheit (F = 1.8C + 32). Crearea, ntret inerea si utilizarea unei agende de adrese de e-mail. Agenda este o baz a de date. 4. In nal, se rezolv a tema pentru examen. Nu de put ine ori metodele / tehnologiile utilizate presupun utilizarea unui sablon de programare specic. Din acest punct de vedere, acest curs se dore ste a un suport metodic.

Produsele informatice utilizate


Pe durata existent ei, produsele informatice evolueaz a prin versiunile pe care produc atorii ni le pun la dispozit ie. Nu de put ine ori o versiune nou a nu este compatibil a cu versiunea anterioar a, fapt care necesit a adaptarea programelor client. Lista urm atoare precizeaz a versiunile produselor utilizate n curs, indicate n majoritatea cazurilor prin resursa de instalare.

No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Versiunile produselor informatice utilizate n lucrare Produsul informatic Resursa/versiunea apache-ant apache.ant-1.8.1-bin.tar.gz apache-commons-leupload commons-leupload-1.3-bin.tar.gz apache-ftpserver ftpserver-1.0.6.tar.gz apache-maven apache-maven-3.1.0-bin.tar.gz apache-tomcat apache-tomcat-7.0.42.tar.gz apacheds apacheds-2.0.0-M15.tar.gz glasssh glasssh-4.0.zip google appengine appengine-java-sdk-1.8.0.zip db-derby db-derby-10.10.1.1-bin.tar.gz httpcomponents-client httpcomponents-client-4.3-bin.tar.gz httpcomponents-asyncclient httpcomponents-asyncclient-4.0-beta4-bin.tar.gz Java (jdk) jdk-7u40-windows-{i586;x64}.exe junit junit4.11.zip mysql mysql-5.6.10-win{32;x64}.zip mysql-connector mysql-connector-java-5.1.24.tar.gz OpenDS OpenDS-2.3.0-build003.zip openmq openmq5.0-binary-WINNT.zip

Cuprins
1 Introducere 15

TEHNOLOGII PENTRU RET ELE LOCALE


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21
23 23 24 25 30 33 38 43 44 58 61

2 Programare cu socluri Java 2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . . 2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . . 2.2.1 Aplicat ie client server cu socluri . . . 2.2.2 Streaming . . . . . . . . . . . . . . . . 2.3 Datagrame . . . . . . . . . . . . . . . . . . . . 2.3.1 Aplicat ii client server cu datagrame. 2.3.2 Multicast vs. Broadcast . . . . . . . . 2.4 Canale de comunicat ie . . . . . . . . . . . . . 2.5 Recept ie cu Selector . . . . . . . . . . . . . 2.6 Comunicat ii asincrone prin canale . . . . . . .

3 Reg asirea obiectelor prin servicii de nume 67 3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 67 3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4 Invocarea procedurilor la distant a 4.1 Remote Method Invocation . . . . 4.1.1 Crearea unei aplicat ii RMI . 4.1.2 Tipare de programare . . . . 4.1.3 Obiect activabil la distant a 4.2 CORBA . . . . . . . . . . . . . . . 4.2.1 Conexiunea RMI - CORBA 4.2.2 Aplicat ie Java prin CORBA 9 77 77 81 87 93 97 98 103

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

10 5 Mesaje n Java 5.1 Java Message Service (JMS) . . . . . . . . . . . 5.2 Open Message Queue 5 . . . . . . . . . . . . . . 5.3 Elemente de programare - JMS-2 . . . . . . . . 5.3.1 Modul programat: Trimiterea unui mesaj 5.3.2 Recept ia sincron a a unui mesaj . . . . . 5.3.3 Recept ia asincron a a unui mesaj . . . . . 5.3.4 Publicarea mesajelor . . . . . . . . . . . 5.3.5 Abonare si recept ia mesajelor . . . . . . 5.3.6 Cazul abonatului partajat . . . . . . . . 5.3.7 Obiecte administrator prin JNDI . . . . 5.3.8 Comunicat ia prin coad a - queue . . . . . 5.3.9 Comunicat ia pe baz a de subiect - topic . 5.3.10 Aplicat ie JMS slab cuplat a. . . . . . . . 5.3.11 Programare JMS prin glasssh . . . . . .

CUPRINS

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

113 . 113 . 115 . 116 . 116 . 118 . 120 . 122 . 123 . 124 . 127 . 128 . 131 . 133 . 136

II

COMUNICAT II PRIN INTERNET


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

139
. . . . 141 141 147 148 150

6 HyperText Transfer Protocol 6.1 Transact ie http . . . . . . . . . . 6.2 Server Web - container de servlet 6.3 Serverul Web apache-tomcat . . . 6.4 Glasssh . . . . . . . . . . . . . .

7 Applet - Miniaplicat ie Java 153 7.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 7.2 Desf a surarea unui applet . . . . . . . . . . . . . . . . . . . . . . 155 7.3 Comunicare Java - JavaScript ntr-un applet . . . . . . . . . . . 161 8 Conexiune simpl a prin clase din java.net 163 8.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 163 9 Servlet 9.1 Marcajul <form> . . . . . . . . . . . . 9.2 Realizarea unui servlet . . . . . . . . . 9.2.1 Codul unui servlet . . . . . . . 9.3 Procesare asincron a n Java Servlet 3.0 9.4 Dezvolt ari n servlet-api 3.1 . . . . . . 9.4.1 Procesare asincron a neblocant a 165 166 167 170 177 180 180

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

CUPRINS

11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 188 188 194 196 198 200 201 204 206 207 211 212 219 220 223 224 227 227 232 234 234 236 239 240 245 246 246 250 252 254

9.4.2 Modicarea protocolului http: upgrade 9.5 Facilit a ti de programare cu servlet . . . . . . . 9.5.1 Program client al unui servlet . . . . . 9.5.2 Servlete nl ant uite . . . . . . . . . . . 9.5.3 Sesiune de lucru . . . . . . . . . . . . . 9.5.4 Cookie . . . . . . . . . . . . . . . . . . 9.5.5 Autenticare . . . . . . . . . . . . . . 9.5.6 Servlet cu conexiune la o baz a de date 9.5.7 Imagini furnizate de servlet . . . . . . 9.5.8 Servlet cu RMI . . . . . . . . . . . . . 9.5.9 Servlet cu JMS . . . . . . . . . . . . . 9.5.10 Servlet cu jurnalizare . . . . . . . . . . 9.6 FileUpload . . . . . . . . . . . . . . . . . . . . 9.7 Desc arcarea unui sier . . . . . . . . . . . . . 9.8 Filtru . . . . . . . . . . . . . . . . . . . . . . 9.9 Eveniment si auditor . . . . . . . . . . . . . . 9.10 Server apache-tomcat ncorporat . . . . . . . . 10 Java Server Page JSP 10.1 Tehnologia JSP . . . . . . . . . . . . . . . 10.1.1 Declarat ii JSP . . . . . . . . . . . . 10.1.2 Directive JSP . . . . . . . . . . . . 10.1.3 Marcaje JSP predenite . . . . . . 10.1.4 Pagini JSP cu componente Java . . 10.2 JSP Standard Tag Library JSTL . . . . . 10.2.1 Biblioteca de baz a . . . . . . . . . 10.2.2 Biblioteca de lucru cu baze de date 10.3 Marcaje JSP personale . . . . . . . . . . . 10.3.1 Marcaje f ar a atribute si f ar a corp. . 10.3.2 Marcaje cu atribute si f ar a corp. . . 10.3.3 Marcaje cu corp. . . . . . . . . . . 10.4 Servlet si JSP n Google App Engine . . . 11 Enterprise Java Beans 11.1 Session EJB . . . . . . . . . . . . . . . . . 11.1.1 Component a EJB sesiune stateless 11.1.2 Aplicat ie JEE cu module EJB, Web 11.1.3 Component a EJB sesiune singleton 11.1.4 Component a EJB sesiune stateful .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . si client RMI-IIOP . . . . . . . . . . . . . . . . . . . . . .

259 . 260 . 261 . 264 . 266 . 268

12

CUPRINS

11.1.5 Component a EJB MessageDriven . . . . . . . . . . . . . 271 11.1.6 Component a EJB Entity . . . . . . . . . . . . . . . . . . 274 12 Java Web Start 279 12.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 13 Java Management Extensions 13.1 Standard MBean . . . . . . . . . . . 13.1.1 Crearea unui Standard MBean 13.1.2 Crearea unui MBeanServer . . 13.1.3 Notic ari . . . . . . . . . . . 13.1.4 Agent MBean . . . . . . . . . 13.1.5 Invocarea la distant a . . . . . 285 . 286 . 286 . 288 . 292 . 295 . 296

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

III

ANEXE

311
313 . 313 . 316 . 318 333 337 341 343 . 343 . 344 . 345 349 . 349 . 350 . 352

A Unelte de dezvoltare A.1 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 apache-ant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 apache-maven . . . . . . . . . . . . . . . . . . . . . . . . . . . B Testare cu junit C Jurnalizare D Component a Java E Adnot ari E.1 Denirea unei adnot ari . . . . . . . . . . . . . . . . . . . . . . E.2 Declararea unei adnot ari . . . . . . . . . . . . . . . . . . . . . E.3 Procesarea unei adnot ari . . . . . . . . . . . . . . . . . . . . . F Utilizarea SGBD n Java F.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . F.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . F.3 S ablonul de utilizare a unei baze de date . . . . . . . . . . . .

CUPRINS

13

IV

TEME DE LABORATOR

357

G Teme de aplicat ii 359 G.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . 359 Bibliograe 371

14

CUPRINS

Capitolul 1 Introducere
Ret elele locale, internetul, r asp andirea pe o arie geograc a a resurselor si a locat iilor n care se petrec act iuni ce tin de o activitate bine denit a sau sunt urm arite, gestionate din alte locuri au drept consecint a existent a aplicat iilor distribuite. Termenul distribuit se refer a tocmai la faptul c a componente ale aplicat iei se a a pe calculatoare diferite dar ntre care au loc schimburi de date. Dac a p art ile unei aplicat ii sau resursele utilizate se g asesc pe calculatoare distincte atunci aplicat ia se nume ste distribuit a. Intre p art ile sau resursele unei aplicat ii distribuite au loc schimburi de date, ceea ce se face utiliz and diferite mecanisme la realizarea c arora concur a sistemul de calcul, sistemul de operare si limbajul de programare. Astfel se vorbe ste de programare distribuit a ca mijloc de realizare a aplicat iilor distribuite. Pe l ang a algoritm, structuri de date, limbaj de programare, la realizarea unei aplicat ii distribuite intervin comunicat iile: schimbul de date dintre dou a componente aate pe calculatoare diferite. Punem n evident a dou a modele de aplicat ii distribuite: client-server: Programul server execut a cererile client ilor. O aplicat ie client server se compune din: componenta server - alc atuit a din programe / clase ce asigur a una sau mai multe funct iuni (servicii), care pot apelate de c atre client i. componenta client - alc atuit a din programe / clase care permit accesul la server si apelarea serviciilor acestuia. Serverul si clientul (client ii) ruleaz a, de obicei, pe calculatoare distincte. Un server trebuie s a satisfac a cererile mai multor client i. 15

16

CAPITOLUL 1. INTRODUCERE

Durata de viat a a unei aplicat ii client server este dat a de durata funct ion arii serverului. Aceast a durat a poate alc atuit a din intervale disjuncte de timp, ntre acele intervale, din diverse motive, serverul este inactiv. Intervalul de timp determinat de conectarea unui client la server si p an a la deconectare poart a numele de sesiune. In aceast a perioad a, clientul poate invoca mai multe servicii ale serverului. Un client poate init ia mai multe sesiuni. Un client trebuie s a- si reg aseasc a datele n cadrul unei sesiuni, ntre sesiuni, pe toat a durata de viat a a aplicat iei. Astfel se pune problema ret inerii / persistent ei datelor pentru ecare client n parte. Amintim urm atoarele tehnologii Java pentru realizarea aplicat iilor clientserver: Tehnologii destinate ret elelor locale, nebazate pe protocolul http. Socluri RMI (Remote Method Invocation) CORBA (Common Object Request Brocker Arhitecture) JMS (Java Message Service)

Comunicat iile utilizeaz a porturi care nu trebuie s a e nchise de eventuale aplicat ii de tip rewall. Tehnologii cu comunicat ii prin Internet, bazate pe protocolul http. Servlet si JSP (Java Server Pages) Java Web Start WebSocket dispecer-lucr ator: Programul dispecer distribuie sarcinile de executat lucr atorilor si le coordoneaz a activitatea. Exist a multe abord ari de programere a aplicat iilor dispecer-lucr ator. Exist a diferent e mari ntre o aplicat ie care ruleaz a pe un calculator si o aplicat ie distribuit a1 latent a (latency ) - exist a mai multe denit ii:
Waldo J., Wyant G., Wollrath A., Kendall S., 1994, A Note on Distributed Computing. Sun Microsystems Corporation, Technical report, SMLI TR-94-29.
1

17 diferent a n timp ntre o operat ie executat a pe un calculator la distant a de execut ia ei pe calculatorul local. diferent a n timp ntre momentul recept ion arii r aspunsului la o cerere si momentul lans arii ei. diferent a n timp ntre momentul recept ion arii unei cereri si momentul transmiterii r aspunsului. Recept ia rezultatului unei operat ii executate pe un calculator la distant a se poate programa sincron de obicei recept ia blocheaz a rul de execut ie al apelului p an a la sosirea rezultatului; asincron recept ia se obt ine ntr-un obiect dedicat care se execut a n afara rului de execut ie al apelului. O preocupare continu a este dezvoltarea de tehnologii hard si soft pentru mic sorarea latent ei. accesul la memorie (memory access ) Aplicat iile distribuite pot rula pe platforme diferite (de exemplu Java si .NET) iar componentele ei pot realizate n limbaje de programare diferite. Instrumente de programare cadre de lucru (framework ) care mijlocesc realizarea aplicat iilor asigur a accesul la resursele aate n memoria calculatoarelor. Exist a o preocupare pentru produse care asigur a interoperabilitatea dintre platformele de calcul. pr abu sirea part ial a (partial failure ) const a n ncetarea funct ion arii unei p art i a aplicat iei distribuite, dar care continu a s a e accesibil a. Tratarea acestei probleme pare a cea mai dicil a tem a a program arii distribuite. Teorema CAP (Eric Brewer, 2000) trateaz a leg atura dintre pr abu sirea part ial a, disponibilitatea aplicat iei si consistent a datelor. Preciz am sensul unor not iuni utilizate n lucrare: protocol - pachet de reguli, sablon utilizat n comunicat ii, n accesarea unor resurse. Exemple de protocoale utilizate sunt: http - HyperText Transfer Protocol este principalul protocol utilizat n comunicat iile prin Internet; https protocol http securizat;

18

CAPITOLUL 1. INTRODUCERE

le - protocol pentru specicarea sierelor aate pe calculatorul local; ftp - File Transfer Protocol - protocol pentru transferul sierelor ntre dou a calculatoare; smtp - Simple Message Transfer Protocol utilizat de po sta elecronic a. host - calculatorul gazd a, cel pe care se lucreaz a. Acest calculator se specic a printr-o adres a IP (Internet Protocol ) sau printr-un nume. port - o adres a de memorie cuprins a ntre 0 si 65535. Porturile cuprinse ntre 0 si 1023 sunt rezervate sistemului de operare. Dintre acestea amintim: Port Utilizat de 80 http 443 https 25 smtp Referint ele resurselor se indic a folosind Uniform Resource Identiers - (URI) si mai precis Uniform Resource Locator - (URL). URI identic a o resurs a n timp ce URL desemneaz a locat ia resursei. URL se consider a ca un caz particular de URI. Sintaxa folosit a pentru URI este protocol://host[:port][cale][?cerere] Un rol important n dezvoltarea tehnologiilor legate de limbajul Java revine organizat iilor de standardizare: Java Community Process JCP; Advancing open standards for the information society OASIS; The Internet Engineering Task Force IETF.

Intreb ari recapitulative


1. Explicat i not iunea de latent a . 2. Explicat i termenul de protocol si dat i exemple de protocoale de comunicat ie. 3. Explicat i not iunea de pr abu sire part ial a.

19 4. Ce desemneaz a denumirea Java Community Process ? 5. Precizat i sintaxa unui URI.

20

CAPITOLUL 1. INTRODUCERE

Partea I TEHNOLOGII PENTRU RET ELE LOCALE

21

Capitolul 2 Programare cu socluri Java


Comunicat ia bazat a pe socluri Java constituie modalitatea de nivelul inferior pentru realizarea aplicat iilor distribuite.

2.1

TCP vs. UDP

Calculatoarele ce ruleaz a n ret ea comunic a ntre ele folosind protocolul TCP (Transmission Control Protocol) sau UDP (User Datagram Protocol). Intr-un program Java se utilizeaz a clasele pachetului java.net prin intermediul c arora se acceseaz a nivelele deservite de protocoalele TCP sau UDP. In felul acesta se pot realiza comunicat ii independente de platforma de calcul. Pentru a alege clasa Java care s a e utilizat a trebuie cunoscut a diferent a dintre TCP si UDP. TCP C and dou a aplicat ii comunic a ntre ele se stabile ste o conexiune prin intermediul c areia se schimb a date. Folosind protocolul TCP, comunicat ia garanteaz a c a datele trimise dintr-un cap at ajung n cel alalt cap at cu p astrarea ordinii n care au fost trimise. Acest tip de comunicat ie seam an a cu o convorbire telefonic a. TCP furnizeaz a un canal sigur de comunicat ie ntre aplicat ii. UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date numite datagrame de la o aplicat ie la alta f ar a s a se asigure faptul c a datagramele ajung la destinat ie si nici ordinea lor de sosire. Acest tip de comunicat ie seam an a cu trimiterea scrisorilor prin po st a. 23

24

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.2

Soclu TCP

Pentru a comunica utiliz and TCP programul client si programul server stabilesc o conexiune sigur a. Fiecare program se leag a la conexiune printr-un soclu (socket). Un soclu este cap atul unei c ai de comunicat ie bidirect ional ntre dou a programe ce ruleaz a n ret ea. Un soclu este legat de un port prin care nivelul TCP poate identica aplicat ia c areia i sunt transmise datele. Pentru a comunica at at clientul c at si serverul citesc date de la si scriu date la soclul legat la conexiunea dintre ele. In pachetul java.net clasele Socket si ServerSocket implementeaz a un soclu din partea clientului si respectiv din partea serverului. Clientul cunoa ste numele calculatorului pe care ruleaz a serverul c at si portul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearc a un rendez-vous cu serverul de pe ma sina serverului si la portul serverului. Dac a totul decurge bine, serverul accept a conexiunea. Dup a acceptare, serverul creaz a pentru client un nou soclu legat la un alt port n a sa fel nc at ascultarea cererilor la soclul init ial s a poat a continua n timp ce sunt satisf acute cererile clientului conectat. Din partea clientului, dup a acceptarea conexiunii soclul este creat si este utilizat pentru comunicat ia cu serverul.

Clasa java.net.Socket
Resursele clasei Socket sunt destinate clientului. Constructori public Socket(String host, int port ) throws UnknownHostException, IOException Creaz a un soclu conectat la calculatorul cu portul specicat. public Socket(InetAddress host, int port ) throws IOException Creaz a un soclu conectat la calculatorul cu portul specicat. Metode public InputStream getInputStream() throws IOException Returneaz a un ux de intrare ata sat soclului, pentru citirea (preluarea) informat iilor de la soclu.

2.2. SOCLU TCP

25

public OutputStream getOutputStream() throws IOException Returneaz a un ux de ie sire ata sat soclului, pentru scrierea (transmiterea) informat iilor la soclu. public synchronized void close() throws IOException nchide soclul de referint a .

Clasa java.net.ServerSocket
Resursele clasei ServerSocket sunt destinate serverului. Constructori public ServerSocket(int port ) throws IOException Creaz a un soclu la portul specicat. Dac a port =0, atunci va utilizat orice port disponibil. Capacitatea sirului (tamponului) de a steptare pentru cererile de conectare se xeaz a la valoarea implicit a 50. Cererile n exces vor refuzate. public ServerSocket(int port, int lung ) throws IOException In plus xeaz a lungimea sirului (tamponului) de a steptare. Metode public Socket accept() throws IOException Metoda blocheaz a procesul (rul de execut ie) apelant p an a la sosirea unei cereri de conectare si creaz a un soclu client prin care se va desf a sura comunicarea cu solicitantul acceptat. public synchronized void close() throws IOException nchide soclul de referint a .

2.2.1

Aplicat ie client server cu socluri

Serverul trebuie s a satisfac a simultan solicit arile mai multor client i. Fiecare client apeleaz a programul server la acela si port si n consecint a cererile de conectare sunt recept ionate de acela si ServerSocket. Serverul recept ioneaz a apelurile secvent ial. La un apel, se creaz a de partea severului un soclu prin care se va face schimbul de date cu clientul. Cererile client ilor pot satisface concurent/paralel, utiliz and re de execut ie ce implementeaz a serviciul oferit sau secvent ial - n cazul unor servicii de durat a scurt a.

26

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.2.1 Sistem client - server pentru calculul celui mai mare divizor comun a dou a numere naturale. Portul obiectului de tip ServerSocket este 7999. Programul client CmmdcClient se conecteaz a la server, transmite serverului cele dou a numere naturale si recept ioneaz a rezultatul pe care apoi l a seaz a. In esent a orice program client trebuie s a execute: 1. Deschide/creaz a un soclu. 2. Deschide/creaz a uxuri de date pentru comunicat ia cu serverul. 3. Transmite si recept ioneaz a date potrivit specicului aplicat iei (protocolului serverului). Acest pas variaz a de la un program client la altul. 4. Inchiderea uxurilor de date. 5. Inchiderea soclului.
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

import import import import

j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; java . net . Socket ; java . u t i l . Scanner ;

public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; try ( S o c k e t cmmdcSocket = new S o c k e t ( hos t , p o r t ) ; DataInputStream i n=new DataInputStream ( cmmdcSocket . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out= new DataOutputStream ( cmmdcSocket . getOutputStream ( ) ) ) { out . w r i t e L o n g (m) ; out . w r i t e L o n g ( n ) ; r=i n . readLong ( ) ; System . out . p r i n t l n ( R e q u i r e d r e s u l t : +r ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

2.2. SOCLU TCP

27

Se presupune c a programul server ruleaz a pe calculatorul local si utilizeaz a portul 7999. Dac a ace sti parametri se modic a - de exemplu serverul ruleaz a n ret ea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem ace sti parametri prin java CmmdcClient atlantis 8200 Partea server este alc atuit a din mai multe clase: Clasa MyMServer, independent a de un serviciu anume, preia apelurile client ilor si lanseaz a satisfacerea cererii.
1 2 3 4 5 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

import import import import import

java . net . ServerSocket ; java . net . Socket ; j a v a . i o . IOException ; java . u t i l . concurrent . ExecutorService ; java . u t i l . concurrent . Executors ;

public c l a s s MyMServer { s t a t i c f i n a l i n t NTHREADS=100; s t a t i c E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException { i n t p o r t =7999; boolean l i s t e n i n g=true ; try ( S e r v e r S o c k e t s e r v e r S o c k e t=new S e r v e r S o c k e t ( p o r t ) ) { System . out . p r i n t l n ( The s e r v e r i s l i s t e n i n g on p o r t 7999 ) ; while ( l i s t e n i n g ) { AppThread o b j=new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) ; exec . execute ( obj ) ; // v a r i a n t a // new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) . s t a r t ( ) ; } } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ; System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } } }

In ciclul while, la recept ia unei solicit ari de conexiune se creaz a si se lanseaz a un r de execut ie a c arei metod a run cont ine act iunile ce r aspund solicit arii. Clasa AppTread - r de execut ie responsabil de preluarea datelor si de transmitere a rezultatului.
1 2 3 4 6 7

import import import import

java . net . Socket ; j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; j a v a . i o . IOException ;

public c l a s s AppThread extends Thread { S o c k e t s o c k e t=n u l l ;

28

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( DataOutputStream out = new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ; DataInputStream i n = new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ) { long m=0 ,n=0 , r ; App app=new App ( ) ; m =i n . readLong ( ) ; n=i n . readLong ( ) ; r=app . cmmdc(m, n ) ; out . w r i t e L o n g ( r ) ; socket . close ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

Clasa App corespunz atoare calcului celui mai mare divizor comul a dou a numere naturale.
1 2 3

public c l a s s App { public long cmmdc( long m, long n ) { . . . } }

Rularea programelor. Se porne ste la nceput programul server MyMServer iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator al ret elei. Dac a programul client se execut a pe alt calculator dec at cel pe care ruleaz a programul server, atunci la apelarea clientului trebuie precizat numele calculatorului server si eventual portul utilizat. O alt a arhitectur a a aplicat iei este dezvoltat a n continuare. Aceast a arhitectur a este mai bun a n sensul c a poate utilizat a n alte cadre de lucru / de dezvoltare (de exemplu OSGi, Junit ). Aplicat ia se va compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6

package i s e r v e r ; import j a v a . n e t . S e r v e r S o c k e t ; public i n t e r f a c e IMyMServer { public S e r v e r S o c k e t g e t S e r v e r S o c k e t ( i n t p o r t ) ; public void myAction ( S e r v e r S o c k e t s e r v e r S o c k e t ) ; }

2.2. SOCLU TCP

29

Implementarea interfet ei
1 2 3 4 5 6 7 8 10 12 13 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38 39

package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n e t . S o c k e t ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; public c l a s s MyMServer implements IMyMServer { public S e r v e r S o c k e t g e t S e r v e r S o c k e t ( i n t p o r t ) { ServerSocket s e r v e r S o c k e t = null ; try { s e r v e r S o c k e t = new S e r v e r S o c k e t ( p o r t ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ; System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } System . out . p r i n t l n ( S e r v e r S o c k e t i s r e a d y . . . ) ; return s e r v e r S o c k e t ; } public void myAction ( S e r v e r S o c k e t s e r v e r S o c k e t ) { i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { AppThread o b j=new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) ; exec . execute ( obj ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }

Clasele AppThread, App sunt cele utilizate anterior. Clas a de lansare a serverului
1 2 3 4 6 7 8 9 10 11 12 13 14

package s e r v e r ; import j a v a . n e t . S e r v e r S o c k e t ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; S e r v e r S o c k e t s e r v e r S o c k e t=myMServer . g e t S e r v e r S o c k e t ( p o r t ) ; myMServer . myAction ( s e r v e r S o c k e t ) ; }

30
}

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

15

Aplicat ia client este nemodicat a.

2.2.2

Streaming

Prin socluri se pot transmite uxuri de date (streaming ). Modul de programare depinde de natura datelor ce trebuie vehiculate (text, sunet, grac a). Exemplul 2.2.2 Clientul solicit a serverului transmisia unui sier text, cerere care va satisf acut a de server. Clientul cunoa ste lista sierelor pe care le poate trimite serverul. Structura aplicat iei este: Client StreamClient.java Server MyMServer.java AppThread.java Clasa StreamClient
1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

import import import import import import import

j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; java . net . Socket ; j a v a . i o . IOException ; j a v a . i o . EOFException ; j a v a . i o . UTFDataFormatException ; java . u t i l . Scanner ;

public c l a s s S t r e a m C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; System . out . p r i n t l n ( A l e g e t i f i s i e r u l : ) ; System . out . p r i n t l n ( 1 : c a p i t o l . t x t ) ; System . out . p r i n t l n ( 2 : j u n i t . t e x ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ; try ( S o c k e t c l i e n t S o c k e t = new S o c k e t ( hos t , p o r t ) ; DataInputStream i n = new DataInputStream ( c l i e n t S o c k e t . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out = new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) { out . w r i t e I n t ( n o F i l e ) ; System . out . p r i n t l n ( R e c e i v e d : ) ; String s ; while ( ! ( s=i n . readUTF ( ) ) . e q u a l s ( e n d O F f i l e ) ) System . out . p r i n t l n ( s ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

2.2. SOCLU TCP

31

Clasa MyThread.java
1 2 3 4 5 6 7 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 40 41 42 43 44

import import import import import import import

java . net . Socket ; j a v a . i o . DataInputStream ; j a v a . i o . DataOutputStream ; java . io . F i l e ; java . io . FileReader ; java . i o . BufferedReader ; j a v a . i o . IOException ;

public c l a s s AppThread extends Thread { S o c k e t s o c k e t=n u l l ; public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( DataInputStream i n = new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ; DataOutputStream out = new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ) { i n t n o F i l e=i n . r e a d I n t ( ) ; System . out . p r i n t l n ( n o F i l e ) ; S t r i n g f i l e N a m e= ; i f ( n o F i l e ==1) f i l e N a m e= c a p i t o l . t x t ; else f i l e N a m e= j u n i t . t e x ; F i l e i n p u t F i l e=new F i l e ( f i l e N a m e ) ; F i l e R e a d e r f r=new F i l e R e a d e r ( i n p u t F i l e ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( f r ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) out . writeUTF ( s ) ; out . writeUTF ( e n d O F f i l e ) ; out . f l u s h ( ) ; br . c l o s e ( ) ; fr . close (); System . out . p r i n t l n ( A c t i v i t y F i n i s h e d ! ) ; socket . close ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

Exemplul 2.2.3 Clientul solicit a serverului transmisia unui sier grac, cerere care va satisf acut a de server. Clientul cunoa ste lista sierelor pe care le poate trimite serverul. Pe acea si structur a codurile claselor sunt Clasa StreamClient
1 2

import j a v a . i o . DataOutputStream ; import j a v a . i o . InputStream ;

32

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

3 4 5 6 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

import import import import import import

j a v a . awt . image . B u f f e r e d I m a g e ; java . net . Socket ; j a v a . i o . IOException ; j a v a x . i m a g e i o . ImageIO ; j a v a . awt . Image ; java . u t i l . Scanner ;

public c l a s s S t r e a m C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; System . out . p r i n t l n ( A l e g e t i f i s i e r u l : ) ; System . out . p r i n t l n ( 1 : xml p i c . j p g ) ; System . out . p r i n t l n ( 2 : b r a s o v . j p g ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ; try ( S o c k e t c l i e n t S o c k e t = new S o c k e t ( hos t , p o r t ) ; InputStream i n=c l i e n t S o c k e t . g e t I n p u t S t r e a m ( ) ; DataOutputStream out = new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) { out . w r i t e I n t ( n o F i l e ) ; B u f f e r e d I m a g e b i=ImageIO . r e a d ( i n ) ; Image image=(Image ) b i ; ShowImage s=new ShowImage ( image ) ; s . show ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( C l i e n t c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

Clasa MyThread.java
1 2 3 4 5 6 7 8 9 10 12 13 15 16 17 19 20 21 22 23 25

import import import import import import import import import import

java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . OutputStream ; j a v a x . i m a g e i o . stream . FileImageOutputStream ; j a v a . i o . DataInputStream ; j a v a x . i m a g e i o . ImageIO ; j a v a . i o . IOException ; java . io . F i l e ; j a v a . awt . image . B u f f e r e d I m a g e ; j a v a . awt . Image ;

public c l a s s AppThread extends Thread { S o c k e t s o c k e t=n u l l ; public AppThread ( S o c k e t s o c k e t ) { t h i s . s o c k e t=s o c k e t ; } public void run ( ) { try ( OutputStream out=s o c k e t . getOutputStream ( ) ; DataInputStream i n=new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ) { i n t n o F i l e=i n . r e a d I n t ( ) ; System . out . p r i n t l n ( n o F i l e ) ; S t r i n g f i l e N a m e= ;

2.3. DATAGRAME

33

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

i f ( n o F i l e ==1) f i l e N a m e=xml p i c . j p g ; else f i l e N a m e= b r a s o v . j p g ; F i l e f i l e =new F i l e ( f i l e N a m e ) ; B u f f e r e d I m a g e b i=ImageIO . r e a d ( f i l e ) ; ImageIO . w r i t e ( bi , j p g , out ) ; out . f l u s h ( ) ; socket . close ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

2.3

Datagrame

Pentru utilizarea datagramelor pachetul java.net pune la dispozit ie clasele DatagramSocket DatagramPacket MulticastSocket O aplicat ie trimite si recept ioneaz a pachete DatagramPacket prin intermediul unui DatagramSocket. Un pachet DatagramPacket poate trimis la mai mult i destinatari prin intermediul unui MulticastSocket. Reamintim c a o datagram a este un mesaj trimis prin ret ea a c arei sosire nu este garantat a iar momentul de sosire este neprecizat.

Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesit a crearea unui obiect DatagramPacket care cont ine corpul mesajului si adresa destinat iei. Apoi acest obiect DatagramPacket poate pus n ret ea n vederea trimiterii sale. Primirea unui pachet UDP necesit a crearea unui obiect DatagramPacket si apoi acceptarea unui pachet UDP din ret ea. Dup a primire, se poate extrage din obiectul DatagramPacket adresa surs a si cont inutul mesajului. Constructori Exist a doi constructori pentru datagrame UDP. Primul constructor este folosit pentru primirea de pachete si necesit a doar furnizarea unei memorii tampon, iar cel alalt este folosit pentru trimiterea de pachete si necesit a specicarea adresei destinatarului.

34

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

DatagramPacket(byte[ ] buer ,int lung ) Acest contructor este folosit pentru primirea pachetelor. Un pachet se memoreaz a n tamponul buer av and lung octet i. Dac a lungimea pachetului dep a se ste aceast a lungime, atunci pachetul este trunchiat iar octet ii n plus se pierd. DatagramPacket(byte[ ] buer ,int lung ,InetAddress adresa ,int port ) Acest constructor este folosit pentru crearea unui pachet n vederea expedierii. Corpul pachetului este cont inut n tamponul buer av and lung octet i. Pachetul va trimis c atre adresa si portul specicat. Trebuie s a existe un server UDP care ascult a la portul specicat pentru trimiterea pachetelor. Un server UDP poate coexista cu un server TCP care ascult a acela si port. Metode InetAddress getAddress() returneaz a adresa IP a expeditorului. int getPort() returneaz a portul expeditorului. byte[] getData() returneaz a cont inutul pachetului. int getLength() returneaz a lungimea pachetului. void setAddress(InetAddress adresa ) xeaz a adresa IP a pachetului. void setPort(int port ) xeaz a portul. void setData(byte[] buer ) xeaz a cont inutul pachetului. void setLength(int lung ) xeaz a lungimea pachetului.

2.3. DATAGRAME

35

Clasa java.net.DatagramSocket
Aceast a clas a se folose ste at at pentru trimiterea, c at si pentru primirea obiectelor DatagramPacket. Un obiect DatagramSocket ascult a la un port cuprins ntre 1 si 65535 (porturile cuprinse ntre 1 si 1023 sunt rezervate pentru aplicat iile sistem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect DatagramSocket pentru trimiterea pachetelor c atre diferite destinat ii si primirea pachetelor de la diferite surse. Constructori DatagramSocket() throws SocketException Creaz a un obiect DatagramSocket cu un num ar de port aleator; DatagramSocket(int port ) throws SocketException Creaz a un obiect DatagramSocket cu num arul de port specicat; Metode Clasa DatagramSocket cont ine metode pentru trimiterea si primirea de obiecte DatagramPacket, nchiderea soclului, determinarea informat iilor adresei locale si setarea timpului de primire. void send(DatagramPacket pachet ) throws IOException Trimite pachet ul prin ret ea. Dac a se trimit pachete la o destinat ie necunoscut a sau care nu ascult a, n cele din urm a se genereaz a o except ie IOException. void receive(DatagramPacket pachet ) throws IOException Metoda prime ste un singur pachet UDP n obiectul pachet specicat. Apoi, pachetul poate inspectat pentru determinarea adresei IP surs a, portul surs a si lungimea mesajului. Execut ia metodei este blocat a p an a c and se prime ste cu succes un pachet sau se scurge timpul de a steptare. InetAddress getLocalAddress() Returneaz a adresa local a c atre care este legat acest DatagramSocket; int getLocalPort() Returneaz a num arul de port unde ascult a DatagramSocket. void close() Inchide DatagramSocket.

36

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

void setSoTimeout(int timpDeA steptere ) throws SocketException Metoda xeaz a timpul de a steptare ( n milisecunde) a soclului. Metoda receive() se va bloca pentru timpul de a steptare specicat pentru primirea unui pachet UDP, dup a care va arunca o except ie Interrupted Exception. Dac a valoarea parametrului este 0, atunci soclul este blocat. int getSoTimeout() throws SocketException Returneaz a timpul de a steptare. void setSendBufferSize(int lungime ) throws SocketException Fixeaz a lungimea tamponului de trimitere a soclului la valoarea specicat a. Nu poate trimis mesaj UDP de lungime mai mare de aceast a valoare. int getSendBufferSize() throws SocketException Returneaz a lungimea tamponului de trimitere a soclului. void setReceiveBufferSize(int lungime ) throws SocketException Fixeaz a lungimea tamponului de primire a soclului la valoarea specicat a. Nu poate primit un mesaj UDP de lungime mai mare de aceast a valoare. int getReceiveBufferSize() throws SocketException Returneaz a lungimea tamponului de primire a soclului. void connect(InetAddress adresa, int port ) throws SocketException Conecteaz a soclul la adresa si portul specicat. Aceast a metod a nu este cerut a pentru operat iile uzuale UDP. void disconnect() Deconecteaz a soclul conectat. InetAddress getInetAddress() Returneaz a obiectul InetAddress c atre care este conectat soclul sau null dac a acesta nu este conectat. int getPort() Returneaz a portul la care este conectat soclul sau -1 dac a acesta nu este conectat.

2.3. DATAGRAME

37

Clasa java.net.InetAddress
Datele pot trimise prin ret ea indic and adresa IP corespunz atoare ma sinii destinat ie. Clasa InetAddress furnizeaz a acces la adresele IP. Nu exist a constructori pentru aceast a clas a. Instant ele trebuie create folosind metodele statice: InetAddress getLocalHost() throws UnknownHostException Returneaz a un obiect InetAddress corespunz ator ma sinii locale. InetAddress getByName(String host ) throws UnknownHostException Returneaz a un obiect InetAddress corespunz ator ma sinii host, parametru care poate specicat prin nume (de exemplu atlantis) sau prin adresa IP (168.192.0.1). InetAddress [ ]getAllByName(String host ) throws UnknownHostException Returneaz a un sir de obiecte InetAddress corespunz ator ec arei adrese IP a ma sinii host. Metodele clasei InetAddress byte [ ] getAddress() Returneaz a sirul de octet i corespunz ator obiectului InetAddress de referint a. String getHostName() Returneaz a numele ma sinii gazd a. String getHostAddress() Returneaz a adresa IP a ma sinii gazd a. boolean isMulticastAddress() Returneaz a true dac a obiectul InetAddress reprezint a o adres a IP multicast (cuprins ntre 224.0.0.0 si 239.255.255.255). Exemplul urm ator a seaz a numele si adresa calculatorului gazd a c at si acela al calculatoarelor ale c aror nume este transmis programului ca parametru. Exemplul 2.3.1

38

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

import j a v a . n e t . I n e t A d d r e s s ; import j a v a . n e t . UnknownHostException ; public c l a s s AdreseIP { public s t a t i c void main ( S t r i n g a r g [ ] ) { I n e t A d d r e s s a d r e s a=n u l l ; try { a d r e s a=I n e t A d d r e s s . g e t L o c a l H o s t ( ) ; System . out . p r i n t l n ( C a l c u l a t o r u l gazda a r e : ) ; System . out . p r i n t l n ( numele : +a d r e s a . getHostName ( ) ) ; System . out . p r i n t l n ( a d r e s a IP : +a d r e s a . g e t H o s t A d d r e s s ( ) ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( UnknownHostException : +e . g e t M e s s a g e ( ) ) ; } i f ( a r g . l e n g t h > 0) { f o r ( i n t i =0; i <a r g . l e n g t h ; i ++){ try { a d r e s a=I n e t A d d r e s s . getByName ( a r g [ i ] ) ; System . out . p r i n t l n ( C a l c u l a t o r u l +a r g [ i ]+ a r e : ) ; System . out . p r i n t l n ( a d r e s a IP \ getByName \ : +a d r e s a ) ; byte [ ] b=a d r e s a . g e t A d d r e s s ( ) ; f o r ( i n t j =0; j <b . l e n g t h ; j ++) i f ( b [ j ] < 0) System . out . p r i n t (256+b [ j ]+ . ) ; else System . out . p r i n t ( b [ j ]+ . ) ; System . out . p r i n t l n ( ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( UnknownHostException : + e . getMessage ( ) ) ; } } } } }

2.3.1

Aplicat ii client server cu datagrame.

Un pachet de tip DatagramPacket este alc atuit dintr-un sir de octet i. Este datoria programatorului s a transforme datele (mesajul) n siruri de octet i la expediere si la recept ie. Transformarea unui obiect serializabil ntr-un sir de octet i si invers se poate realiza cu schema

2.3. DATAGRAME

39

Object ObjectOutputStream ByteArrayOutputStream output - DatagramPacket


? ? ? ?

Object ObjectInputStream ByteArrayInputStream input - DatagramPacket


6 6 6 6

Fie socket un obiect de tip DatagramSocket prin intermediul c aruia se execut a expedierea / recept ionarea pachetelor de tip DatagramPacket. In principiu expedierea si transformarea obiectului obj ntr-un sir de octet i se poate realiza cu secvent a de cod ByteArrayOutputStream baos=new ByteArrayOutputStream(256); ObjectOutputStream out=new ObjectOutputStream(baos); out.writeObject(obj); byte[] bout=baos.toByteArray(); DatagramPacket packet=new DatagramPacket(bout,bout.length, address,port); socket.send(packet); unde address si port sunt adresa si portul destinatarului. Dac a packet este un obiect DatagramPacket recept ionat atunci metodele getAddress() si getPort() furnizeaz a adresa si portul expeditorului Recept ionarea si transformarea invers a este byte[] bin=new byte[256]; packet=new DatagramPacket(bin,bin.length); socket.receive(packet); ByteArrayInputStream bais=new ByteArrayInputStream(bin); ObjectInputStream in=new ObjectInputStream(bais); obj=in.readObject(); Dac a mesajul este un obiect String atunci el se transform a ntr-un sir de octet i cu metoda byte[] String.getByte() si invers, el se obt ine prin new String(bin) sau new String(packet.getData()). Exemplul 2.3.2 Program am aplicat ia de calculul a celui mai mare divizor comun a dou a numere naturale.

40

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

In vederea transportului denim clasa


1 2 4 5 6 7 8 9 10

package s e r v e r ; import j a v a . i o . S e r i a l i z a b l e ; public c l a s s P r o t o c o l implements S e r i a l i z a b l e { long x , y ; P r o t o c o l ( long x , long y ) { t h i s . x=x ; t h i s . y=y ; } }

Clientul va trimite un obiect Protocol, care va cont ine datele problemei si va recept iona un obiect de acela si tip cu rezultatul (cel mai mare divizor comun) n primul c amp al obiectului. Aceasta clasa este disponibil a at at serverului c at si clientului. Se va utiliza arhitectura de aplicat ie dezvoltat a n nalul sect iunii anterioare. Aplicat ia se va compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6

package i s e r v e r ; import j a v a . n e t . DatagramSocket ; public i n t e r f a c e IMyMServer { public DatagramSocket getDatagramSocket ( i n t p o r t ) ; public void myAction ( DatagramSocket datagramSocket ) ; }

Implementarea interfet ei
1 2 3 4 5 6 7 8 9 10 11 12 14 16 17 18 19 20 21 22

package s e r v e r . impl ; import s e r v e r . App ; import s e r v e r . P r o t o c o l ; import i s e r v e r . IMyMServer ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . DatagramPacket ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . i o . IOException ; import j a v a . i o . ByteArrayInputStream ; import j a v a . i o . ByteArrayOutputStream ; import j a v a . i o . O b j e c t I n p u t S t r e a m ; import j a v a . i o . ObjectOutputStream ; public c l a s s MyMServer implements IMyMServer { public DatagramSocket getDatagramSocket ( i n t p o r t ) { DatagramSocket datagramSocket = n u l l ; try { datagramSocket = new DatagramSocket ( p o r t ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Could not l i s t e n on p o r t : +p o r t ) ;

2.3. DATAGRAME

41

23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59

System . e r r . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } System . out . p r i n t l n ( DatagramSocket i s r e a d y . . . ) ; return datagramSocket ; } public void myAction ( DatagramSocket datagramSocket ) { DatagramPacket p a c k e t=n u l l ; App app=new App ( ) ; P r o t o c o l p=n u l l ; while ( true ) { try { byte [ ] b i n=new byte [ 4 0 4 8 ] ; p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ; datagramSocket . r e c e i v e ( p a c k e t ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; p . x=app . cmmdc( p . x , p . y ) ; p . y =0; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; I n e t A d d r e s s a d d r e s s=p a c k e t . g e t A d d r e s s ( ) ; i n t p o r t=p a c k e t . g e t P o r t ( ) ; p a c k e t=new DatagramPacket ( bout , bout . l e n g t h , a d d r e s s , p o r t ) ; datagramSocket . send ( p a c k e t ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } } }

Clas a de lansare a serverului


1 2 3 4 6 7 8 9 10 11 12 13 14 15

package s e r v e r ; import j a v a . n e t . DatagramSocket ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; DatagramSocket datagramSocket=myMServer . getDatagramSocket ( p o r t ) ; myMServer . myAction ( datagramSocket ) ; } }

Aplicat ia client

42

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

package c l i e n t ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . DatagramPacket ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . i o . ByteArrayInputStream ; import j a v a . i o . ByteArrayOutputStream ; import j a v a . i o . O b j e c t I n p u t S t r e a m ; import j a v a . i o . ObjectOutputStream ; import s e r v e r . P r o t o c o l ; import j a v a . u t i l . S c a n n e r ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t S e r v e r= l o c a l h o s t ; i n t p o r t S e r v e r =7999; i f ( a r g s . l e n g t h > 0) h o s t S e r v e r=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t S e r v e r=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; try { DatagramSocket s o c k e t=new DatagramSocket ( ) ; P r o t o c o l p=new P r o t o c o l ( 0 , 0 ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i p r i m u l numar : ) ; p . x=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i a l d o i l e a numar : ) ; p . y=s c a n n e r . nextLong ( ) ; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; I n e t A d d r e s s a d d r e s s=I n e t A d d r e s s . getByName ( h o s t S e r v e r ) ; DatagramPacket p a c k e t = new DatagramPacket ( bout , bout . l e n g t h , a d d r e s s , p o r t S e r v e r ) ; s o c k e t . send ( p a c k e t ) ; byte [ ] b i n=new byte [ 4 0 4 8 ] ; p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ; socket . r e c e i v e ( packet ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; System . out . p r i n t l n ( Cmmdc = +p . x ) ; socket . close ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }

2.3. DATAGRAME

43

2.3.2

Multicast vs. Broadcast

Clasa java.net.MulticastSocket
Prin intermediul unui soclu de tip MulticastSocket se pot recept iona datagrame expediate de un server c atre tot i client ii cu un asemenea soclu. Constructori MulticastSocket(int port ) throws SocketException Metode void joinGroup(InetAddress adres a ) throws SocketException Soclul se conecteaz a la grupul denit de adresa IP (de tip D, adic a cuprins ntre 224.0.0.0 si 239.255.255.255). void leaveGroup(InetAddress adres a ) throws SocketException Soclul se deconecteaz a la grupul denit de adresa IP. void close() Preg atirea clientului n vederea recept ion arii datagramelor printr-un soclu de tip MulticastSocket const a din MulticastSocket socket= new MulticastSocket(port); InetAddress adresa=InetAddress.getByName("230.0.0.1"); socket.joinGroup(adresa); In nal, clientul se deconecteaz a si nchide soclul. socket.leaveGroup(adresa); socket.close(); Pachetele trimise de programul server trebuie s a se adreseze grupului, identicat prin adresa IP de tip D. Astfel prin multicast serverul trimite pachete la o adres a de grup si la un port xat. Pachetele emise de server sunt recept ionate de orice client ce creaz a un soclu de tip MulticastSocket pentru portul la care emite serverul si care se al atur a grupului. Prin broadcast serverul emite datagrame c atre orice calculator al ret elei locale la un anumit port. Faptul c a emiterea datagramelor este de tip broadcast se indic a prin

44

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

DatagramSocket.setBroadcast(true) Orice client care si creaz a un soclu la portul la care emite serverul recept ioneaz a datagramele trimise de server. Adresa utilizat a de server la crearea datagramelor trebuie s a identice ret eaua. Observat ie. In cazul unui calculator izolat este nevoie de instalarea driverului Microsoft Loopback Adapter, care simuleaz a existent a unei pl aci de ret ea active. Exemplul 2.3.3 Multicast si Broadcast: programele server emit din cinci n cinci secunde ora exact a. Un client va recept iona c ate cinci datagrame. Codurile sunt date n Fig. 2.1 si Fig. 2.2, respectiv pentru partea de server si cea de client.

2.4

Canale de comunicat ie

Odat a cu versiunea j2sdk1.4 apar clase noi pentru operat ii de intrare - ie sire n pachetele java.nio si java.nio.channels. Pachetul java.nio.channels cont ine clase pentru comunicat ia n ret ea, si anume canalele de comunicat ie. Utiliz am clasele java.nio.channels.SocketChannel, java.nio.channel. DatagramChannel. Informat ia transportat a n aceste canale de comunicat ie trebuie nglobat a n obiecte container de tip Buffer.

Clasa java.nio.Buffer
Ierarhia claselor Buffer abstract Buffer ByteBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer CharBuffer Un obiect de tip typeBuffer este un tampon (container) care cont ine date de tipul specicat de denumirea clasei. Un obiect de tip Buffer este caracterizat de

2.4. CANALE DE COMUNICAT IE

45

MulticastServer import java.io.*; import java.net.*; import java.util.*; import java.text.DateFormat; public class MulticastServer{ public static void main(String[] args){ long FIVE_SECONDS = 5000; boolean sfarsit=false; int serverPort=7000; int clientPort=7001; byte[] buf = new byte[256]; Date data=null; DatagramPacket packet = null; try(DatagramSocket socket= =new DatagramSocket(serverPort)){ while (! sfarsit){ data=new Date(); String df=DateFormat. getTimeInstance().format(data); buf = df.getBytes(); // send it InetAddress group = InetAddress.getByName("230.0.0.1"); packet=new DatagramPacket(buf, buf.length,group,clientPort); socket.send(packet); // sleep for a while Thread.sleep(FIVE_SECONDS); } } catch (Exception e) { System.out.println(e.getMessage()); } } }

BroadcastServer import java.io.*; import java.net.*; import java.util.*; import java.text.DateFormat; public class BroadcastServer{ public static void main(String[] args){ long FIVE_SECONDS = 5000; boolean sfarsit=false; int serverPort=7000; int clientPort=7001; byte[] buf = new byte[256]; Date data = null; DatagramPacket packet = null; try(DatagramSocket socket= new DatagramSocket(serverPort)){ while (! sfarsit) { data=new Date(); String df=DateFormat. getTimeInstance().format(data); buf = df.getBytes(); InetAddress group = InetAddress.getByName("192.168.0.255"); packet=new DatagramPacket(buf, buf.length,group,clientPort); socket.setBroadcast(true); socket.send(packet); Thread.sleep(FIVE_SECONDS); } } catch (Exception e) { System.out.println(e.getMessage()); } } }

Table 2.1: Clasele server.

46

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

MulticastClient import java.io.*; import java.net.*; public class MulticastClient { public static void main(String[] args) throws IOException { DatagramPacket packet; byte[] buf = new byte[256]; int clientPort=7001; MulticastSocket socket= new MulticastSocket(clientPort); InetAddress address= InetAddress.getByName("230.0.0.1"); socket.joinGroup(address); int i=-1; do{ i++; packet=new DatagramPacket(buf, buf.length); socket.receive(packet); String received=new String(packet.getData()); System.out.println("Am primit: "+received); } while(i<5); socket.leaveGroup(address); socket.close(); } }

BroadcastClient import java.io.*; import java.net.*; public class BroadcastClient { public static void main(String[] args) throws IOException { DatagramPacket packet; byte[] buf = new byte[256]; int clientPort=7001; DatagramSocket socket= new DatagramSocket(clientPort);

int i=-1; do{ i++; packet=new DatagramPacket(buf, buf.length); socket.receive(packet); String received=new String(packet.getData()); System.out.println("Am primit: "+received); } while(i<5); socket.close(); } }

Table 2.2: Clasele client.

2.4. CANALE DE COMUNICAT IE

47

capacitate (capacity) num arul elementelor care pot nmagazitate n tampon; limit a (limit) marginea superior a a indicelui; indice (position) valoarea curent a a indicelui, ce corespunde unui cursor ce indic a nceputul zonei unde se introduc sau de unde se extrag date din tampon. Metode generale clear() permite unui obiect de tip Buffer s a e re nc arcat. Fixeaz a limita = capacitate si indice = 0. ip() preg ate ste obiectul de tip Buffer pentru consultare (citire). Fixeaz a limita =num arul elementelor din tampon si indice = 0. rewind() preg ate ste obiectul de tip Buffer pentru re-citire. remaining() returneaz a num aul octet ilor cuprin si ntre valoarea indicelui si limit a.

Clasa java.nio.ByteBuffer
Instant ierea unui obiect se obt ine prin metoda static a static ByteBuffer allocate(capacitate ) Introducerea si extragerea datelor din tampon se poate face n mod relativ - implic a modicarea indicelui tamponului; absolut - far a modicarea indicelui. Metode Introducerea datelor n mod relativ: ByteBuffer put(byte b ) ByteBuffer putTip (tip x ) Extragerea datelor n mod relativ: byte get()

48 tip getTip ()

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Introducerea datelor n mod absolut: ByteBuffer put(int index ,byte b ) ByteBuffer putTip (int index ,tip x ) Extragerea datelor n mod absolut: byte get(int index ) tip getTip (int index ) unde tip poate char, short, int, long, float, double. Alte metode public final boolean hasRemaining() Dac a indicele nu este egal cu limita atunci returneaz a true, semnal and existent a n tampon a unor octet i. static ByteBuffer wrap(byte[] array ) public static ByteBuffer wrap(byte[] array ,int oset ,int length ) Converte ste sirul de octet i ntr-un obiect ByteBuffer. public final byte[] array() Transformarea invers a, obiectul ByteBuffer este convertit ntr-un sir de octet i. Un obiect de tip ByteBuffer se poate percepe ca un obiect de tip LongBuffer, DoubleBuffer, etc prin ByteBuffer bb=ByteBuffer.allocate(10); LongBuffer lb=bb.asLongBuffer(); DoubleBuffer db=bb.asDoubleBuffer();

2.4. CANALE DE COMUNICAT IE

49

Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress si ncapsuleaz a adresa unui calculator din Internet mpreun a cu un port n vederea leg arii la un ServerSocket. Constructori: InetSocketAddress(InetAddress addr ,int port ) InetSocketAddress(String numeCalculator ,int port ) InetSocketAddress(int port )

Clasa java.nio.channels.ServerSocketChannel
Crearea unui obiect de tip ServerSocketChannel se realizeaz a prin static ServerSocketChannel open() throws IOException Unui asemenea obiect i se asociaz a un ServerSocket prin metoda ServerSocket socket() throws IOException. Obiectul de tip ServerSocket trebuie leagat la un port de comunicat ie prin metoda void bind(InetSocketAddress endpoint ) throws IOException. S ablonul de utilizare este try{ ServerSocketChannel ssc=ServerSocketChannel.open(); ServerSocket ss=ssc.socket(); InetSocketAddress isa=new InetSocketAddress(addr,port); ss.bind(isa); } catch(Exception e){. . .} La apelul unui client, serverul trebuie s a genereze un obiect de tip Socket Channel prin care se vor derula comunicat iile cu clientul. Acest canal de comunicat ie se obt ine cu metoda accept().

50

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaz a prin static SocketChannel open() throws IOException Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului cu metoda connect(InetSocketAddress addr ). Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datele se transmit prin metoda int write(ByteBuffer surs a) si se recept ioneaz a prin metoda int read(ByteBuffer destinat ie ) Valoarea returnat a de cele dou a metode reprezint a num arul octet ilor trimi si / recept ionat i. Doar octet ii unui obiect de tip ByteBuffer cuprin si ntre indice si limit a sunt transmi si prin canal. Astfel, dup a nc arcarea unui obiectului ByteBuffer cu metode relative trebuie apelat a metoda flip(). Canalul se nchide cu metoda close(). Exemplul 2.4.1 Calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ie client-server bazat pe canale de comunicat ie prin socluri se compune din: Aplicat ia server alc atuit a din: Interfat a
1 2 3 4 5 6

package i s e r v e r ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; public i n t e r f a c e IMyMServer { public S e r v e r S o c k e t C h a n n e l g e t S e r v e r S o c k e t C h a n n e l ( i n t p o r t ) ; public void myAction ( S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l ) ; }

Implementarea interfet ei

2.4. CANALE DE COMUNICAT IE

51

1 2 3 4 5 6 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 38 39 40 41 42 43

package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; import j a v a . i o . IOException ; public c l a s s MyMServer implements IMyMServer { public S e r v e r S o c k e t C h a n n e l g e t S e r v e r S o c k e t C h a n n e l ( i n t p o r t ) { S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l=n u l l ; try { s e r v e r S o c k e t C h a n n e l = S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; S e r v e r S o c k e t s s=s e r v e r S o c k e t C h a n n e l . s o c k e t ( ) ; s s . bind ( i s a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( S e r v e r S o c k e t C h a n n e l E r r o r : + e . getMessage ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return s e r v e r S o c k e t C h a n n e l ; } public void myAction ( S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l ) { i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { AppThread o b j=new AppThread ( s e r v e r S o c k e t C h a n n e l . a c c e p t ( ) ) ; exec . execute ( obj ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }

Clasa AppThread
1 2 3 4 6 7 9 10 11

package s e r v e r ; import j a v a . i o . IOException ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . B y t e B u f f e r ; public c l a s s AppThread extends Thread { S o c k e t C h a n n e l s o c k e t C h a n n e l=n u l l ; public AppThread ( S o c k e t C h a n n e l s o c k e t C h a n n e l ) { t h i s . s o c k e t C h a n n e l=s o c k e t C h a n n e l ; }

52

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

public void run ( ) { try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // L o n g B u f f e r l b = bb . a s L o n g B u f f e r ( ) ; s o c k e t C h a n n e l . r e a d ( bb ) ; // V a r i a n t a 1 long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; // V a r i a n t a 2 // l o n g m =l b . g e t ( 0 ) ; // l o n g n=l b . g e t ( 1 ) ; App app=new App ( ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; // V a r i a n t a 1 bb . putLong ( 0 , r ) ; // V a r i a n t a 2 // l b . p u t ( r ) ; s o c k e t C h a n n e l . w r i t e ( bb ) ; socketChannel . c l o s e ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : + e . getMessage ( ) ) ; } } }

Clas a de lansare a serverului


1 2 3 4 6 7 8 9 10 11 12 13 14 15 16

package s e r v e r ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; ServerSocketChannel serverSocketChannel = myMServer . g e t S e r v e r S o c k e t C h a n n e l ( p o r t ) ; myMServer . myAction ( s e r v e r S o c k e t C h a n n e l ) ; } }

Aplicat ia client
1 2 3 4 5 6 7 9

package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ; public c l a s s CmmdcClient {

2.4. CANALE DE COMUNICAT IE

53

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S o c k e t C h a n n e l s c=n u l l ; try { I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ; s c=S o c k e t C h a n n e l . open ( ) ; sc . connect ( i s a ) ; } catch ( UnknownHostException e ) { System . e r r . p r i n t l n ( S e r v e r n e c u n o s c u t : +h o s t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C o n e c t a r e i m p o s i b i l a l a : + h o s t+ pe p o r t u l +p o r t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // V a r i a n t a 1 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; // V a r i a n t a 2 // L o n g B u f f e r l b=bb . a s L o n g B u f f e r ( ) ; // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ; try { s c . w r i t e ( bb ) ; bb . c l e a r ( ) ; s c . r e a d ( bb ) ; // V a r i a n t a 1 r=bb . getLong ( 0 ) ; // V a r i a n t a 2 // r=l b . g e t ( 0 ) ; System . out . p r i n t l n ( Cmmdc : +r ) ; sc . clos e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E r o a r e de c o m u n i c a t i e +e . g e t M e s s a g e ( ) ) ; } } }

Varianta comentat a corespunde cazului n care se utilizear a clasa acoperitoare LongBuffer. Alternativ, se poate lucra cu obiecte. Pentru exemplul dat, utiliz and clasa Protocol, introdus a n sect iunea dedicat a datagramelor, codul privind trimiterea ti recept ia datelor din clasele AppThread si CmmdcClient va

54

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

. . . B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 0 2 4 ) ; s o c k e t C h a n n e l . r e a d ( bb ) ; byte [ ] b i n=bb . a r r a y ( ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; P r o t o c o l p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; App app=new App ( ) ; p . x=app . cmmdc( p . x , p . y ) ; p . y =0; ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; bb=B y t e B u f f e r . wrap ( bout ) ; s o c k e t C h a n n e l . w r i t e ( bb ) ; socketChannel . c l o s e ( ) ; . . .

si, respectiv,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

. . . B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 2 0 4 8 ) ; P r o t o c o l p=new P r o t o c o l (m, n ) ; try { ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ; ObjectOutputStream out=new ObjectOutputStream ( baos ) ; out . w r i t e O b j e c t ( p ) ; byte [ ] bout=baos . toByteArray ( ) ; bb=B y t e B u f f e r . wrap ( bout ) ; s c . w r i t e ( bb ) ; bb . c l e a r ( ) ; s c . r e a d ( bb ) ; byte [ ] b i n=bb . a r r a y ( ) ; ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ; O b j e c t I n p u t S t r e a m i n=new O b j e c t I n p u t S t r e a m ( b a i s ) ; p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ; System . out . p r i n t l n ( Cmmdc : +p . x ) ; sc . clos e ( ) ; . . .

Clasa java.nio.channels.DatagramChannel
S ablonul de programare pentru instant ierea unui obiect de tip DatagramChannel este DatagramChannel dc=null; InetSocketAddress isa=new InetSocketAddress(port); try{ dc=DatagramChannel.open(); DatagramSocket datagramSocket=dc.socket(); datagramSocket.bind(isa);

2.4. CANALE DE COMUNICAT IE

55

} catch(Exception e){. . .} unde port este portul folosit de DatagramChannel. Dac a port=0 atunci se alege aleator un port disponibil. Transmiterea unui obiect ByteBuffer se face cu metoda public int send(ByteBuffer src , SocketAddress target ) throws IOException Metoda returneaz a num arul de octet i expediat i. Recept ia unui ByteBuffer se obt ine cu metoda public SocketAddress receive(ByteBuffer dst ) throws IOException Obiectul returnat reprezint a adresa expeditorului. Exemplul 2.4.2 Calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ia server este alc atuit a din: Interfat a
1 2 3 4 5 6

package i s e r v e r ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; public i n t e r f a c e IMyMServer { public DatagramChannel getDatagramChannel ( i n t p o r t ) ; public void myAction ( DatagramChannel datagramChannel ) ; }

Implementarea interfet ei
1 2 3 4 5 6 7 8 9 11 13 14 15 16 17 18 19

package s e r v e r . impl ; import s e r v e r . App ; import i s e r v e r . IMyMServer ; import j a v a . n e t . DatagramSocket ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . i o . IOException ; public c l a s s MyMServer implements IMyMServer { public DatagramChannel getDatagramChannel ( i n t p o r t ) { DatagramChannel datagramChannel=n u l l ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; try { datagramChannel = DatagramChannel . open ( ) ; DatagramSocket datagramSocket=datagramChannel . s o c k e t ( ) ; datagramSocket . bind ( i s a ) ;

56

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

} catch ( IOException e ) { System . out . p r i n t l n ( DatagramChannelError : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return datagramChannel ; } public void myAction ( DatagramChannel datagramChannel ) { i n t NTHREADS=100; while ( true ) { App app=new App ( ) ; try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // L o n g B u f f e r l b = bb . a s L o n g B u f f e r ( ) ; S o c k e t A d d r e s s s a=datagramChannel . r e c e i v e ( bb ) ; // V a r i a n t a 1 long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; // V a r i a n t a 2 // l o n g m =l b . g e t ( 0 ) ; // l o n g n=l b . g e t ( 1 ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; // V a r i a n t a 1 bb . putLong ( 0 , r ) ; // V a r i a n t a 2 // l b . p u t ( r ) ; datagramChannel . send ( bb , s a ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : + e . getMessage ( ) ) ; } } } }

Clas a de lansare a serverului


1 2 3 4 6 7 8 9 10 11 12 13 14 15 16

package s e r v e r ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; DatagramChannel datagramChannel = myMServer . getDatagramChannel ( p o r t ) ; myMServer . myAction ( datagramChannel ) ; } }

2.4. CANALE DE COMUNICAT IE

57

Aplicat ia client
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . I n e t A d d r e s s ; import j a v a . n e t . DatagramSocket ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException { S t r i n g s e r v e r H o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) s e r v e r H o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; I n e t S o c k e t A d d r e s s s e r v e r=null , i s a=n u l l ; try { s e r v e r= new I n e t S o c k e t A d d r e s s ( I n e t A d d r e s s . getByName ( s e r v e r H o s t ) , p o r t ) ; } catch ( UnknownHostException e ) { System . out . p r i n t l n ( Unknown h o s t : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } i s a=new I n e t S o c k e t A d d r e s s ( 0 ) ; DatagramChannel dc=n u l l ; try { dc=DatagramChannel . open ( ) ; DatagramSocket s o c k e t = dc . s o c k e t ( ) ; s o c k e t . bind ( i s a ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( Couldn t open t h e DatagramChannel + e . getMessage ( ) ) ; System . e x i t ( 1 ) ; } long m, n , r ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; // V a r i a n t a 1 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; // V a r i a n t a 2 // L o n g B u f f e r l b=bb . a s L o n g B u f f e r ( ) ; // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ; try { dc . send ( bb , s e r v e r ) ; bb . c l e a r ( ) ; dc . r e c e i v e ( bb ) ; // V a r i a n t a 1 r=bb . getLong ( 0 ) ; // V a r i a n t a 2

58

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

59 60 61 62 63 64 65 66 67 68 69

// r=l b . g e t ( 0 ) ; System . out . p r i n t l n ( Cmmdc = +r ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( C l i e n t e r r o r : +e . g e t M e s s a g e ( ) ) ; } finally { i f ( dc != n u l l ) dc . d i s c o n n e c t ( ) ; } } }

2.5

Recept ie cu Selector

Programarea recept iei cererilor client ilor f ar a utilizarea relor de execut ie se poate face utiliz and clasele java.nio.channel.Selector Gestioneaz a obiectele SocketChannel nregistrate si transmite cererile care trebuie satisf acute. java.nio.channel.SelectionKey Obiect utilizat de selector pentru sortarea cererilor. O cheie identic a un client si tipul cererii. Figura 2.1 prezint a structura unei aplicat ii.
1

Clasa java.nio.channel.Selector Metode public static Selector open() throws IOException Instat iaz a un obiect de tip Selector. public Set<SelectionKey> selectedKeys() Returneaz a cheile inregistrate de selector. public int select() throws IOException Metod a blocant a p an a la selectarea unui canal.
Imaginea este preluat a din Naccarato G., http://www.onjava.com, 2002.
1

Introducing Nonblocking Sockets,

2.5. RECEPT IE CU SELECTOR

59

Figure 2.1: Structura unei aplicat ii. Inregistrarea selectorului se face de c atre obiectiul SocketChannel sau ServerSocketChannel prin metoda public final SelectionKey register(Selector selector, int ops ) throws ClosedChannelException Operat iile pot SelectionKey.OP CONNECT SelectionKey.OP ACCEPT SelectionKey.OP READ SelectionKey.OP WRITE Canalul se congureaz a pe modul ne-blocant prin configureBlocking(false) throws IOException Clasa java.nio.channel.SelectionKey Metode public final boolean isConnectable() public final boolean isReadable() public final boolean isWritable() public final boolean isAcceptable() public void cancel()

60

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.5.1 Aplicat ia server pentru aplicat ia de calcul a celui mai mare divizor comun. Aplicat ia server va format a de clasele AppServer si App, cea utilizat a n acest capitol.
1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 19 20 21 22 23 24 25 26 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

package s e r v e r ; import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . S e l e c t i o n K e y ; import j a v a . n i o . c h a n n e l s . S e l e c t o r ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n e t . S e r v e r S o c k e t ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . I t e r a t o r ; import j a v a . u t i l . S e t ; import j a v a . i o . IOException ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l=n u l l ; try { s e r v e r S o c k e t C h a n n e l = S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; S e r v e r S o c k e t s s=s e r v e r S o c k e t C h a n n e l . s o c k e t ( ) ; s s . bind ( i s a ) ; serverSocketChannel . configureBlocking ( false ) ; System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; S e l e c t o r s e l e c t o r = S e l e c t o r . open ( ) ; SelectionKey serverkey = s e r v e r S o c k e t C h a n n e l . r e g i s t e r ( s e l e c t o r , S e l e c t i o n K e y .OP ACCEPT ) ; ByteBuffer b u f f e r = ByteBuffer . a l l o c a t e ( 1 6 ) ; while ( true ) { selector . select (); Set < S e l e c t i o n K e y > k e y s = s e l e c t o r . s e l e c t e d K e y s ( ) ; f o r ( I t e r a t o r i = k e y s . i t e r a t o r ( ) ; i . hasNext ( ) ; ) { S e l e c t i o n K e y key = ( S e l e c t i o n K e y ) i . n e x t ( ) ; i . remove ( ) ; i f ( key == s e r v e r k e y ) { i f ( key . i s A c c e p t a b l e ( ) ) { SocketChannel c l i e n t = serverSocketChannel . accept ( ) ; c l i e n t . configureBlocking ( false ) ; SelectionKey clientkey = c l i e n t . r e g i s t e r ( selector , S e l e c t i o n K e y .OP READ ) ; } } else { i f ( key . i s R e a d a b l e ( ) ) { S o c k e t C h a n n e l c l i e n t = ( S o c k e t C h a n n e l ) key . c h a n n e l ( ) ; int bytesread = c l i e n t . read ( b u f f e r ) ; long m =b u f f e r . getLong ( 0 ) ; long n=b u f f e r . getLong ( 8 ) ; App app=new App ( ) ;

2.6. COMUNICAT II ASINCRONE PRIN CANALE

61

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

long r=app . cmmdc(m, n ) ; buffer . clear (); b u f f e r . putLong ( 0 , r ) ; c l i e n t . write ( buffer ) ; buffer . clear (); client . close (); key . c a n c e l ( ) ; } } } } } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( B u f f e r O p E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

Aplicat ia client nu sufer a nici o modicare.

2.6

Comunicat ii asincrone prin canale

Utilizarea canalelor asincrone, introduse n Java 7, face apel la metode neblocante. Astfel sunt introduse clasele: java.nio.channels.AsynchronousServerSocketChannel si java.nio.channels.AsynchronousSocketChannel. Tehnicile de programare utilizate se bazeaz a pe utilizarea claselor: java.util.concurrent.Future

Interfat a Future<V>
Metode V get() boolean isDone() Valoarea true rezult a dac a s-a obt inut / generat obiectul de tip V. Un obiect de tip V care rezult a n urma apel arii metodei cu semn atura Future<V> metoda(. . . ) se va utiliza doar dup a vericarea gener arii ei, de exemplu cu metoda isDone().

62

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa AsynchronousServerSocketChannel
Un obiect de tip AsynchronousServerSocketChannel se obt ine cu metoda static a open(). Metode static AsynchronousServerSocketChannel open() throws IOException AsynchronousServerSocketChannel bind(SocketAddress addr ) Se precizeaz a portul la care se leag a canalul asincron. Clasa InetSocketAddress este extinde clasa SocketAddress. public Future<AsynchronousSocketChannel> accept() Metoda neblocant a genereaz a un soclu prin care se realizeaz a conexiunea din partea serverului cu un client.

Clasa AsynchronousSocketChannel
Metodei public static AsynchronousSocketChannel open() throws IOException public abstract Future<Void> connect(SocketAddress remote ) public Future<Integer> read(ByteBuffer dst ) Metoda returneaz a num arul octet ilor nc arcat i n dst. public Future<Integer> write(ByteBuffer src ) Metoda returneaz a num arul octet ilor expediat i din src. Exemplul 2.6.1 Utiliz am modelul aplicat iei dezvoltat a pe baza clasei ServerSocketChannel: 1. IMyMServer.java
1 2 3 4 5 6 7 8

package i s e r v e r ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; public i n t e r f a c e IMyMServer { public A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l getAsynchronousServerSocketChannel ( int port ) ; public void myAction ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l asynchronousServerSocketChannel ) ; }

2.6. COMUNICAT II ASINCRONE PRIN CANALE

63

2. MyMServer.java
1 2 3 4 5 6 7 8 9 10 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

package s e r v e r . impl ; import s e r v e r . AppThread ; import i s e r v e r . IMyMServer ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s MyMServer implements IMyMServer { public A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l getAsynchronousServerSocketChannel ( int port ){ A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l=n u l l ; try { asynchronousServerSocketChannel = A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l . open ( ) ; I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ; a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l . bind ( i s a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l E r r o r : + e . getMessage ( ) ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( S e r v e r r e a d y . . . ) ; return a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; } public void myAction ( A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l asynchronousServerSocketChannel ){ i n t NTHREADS=100; E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool (NTHREADS) ; while ( true ) { try { Future <AsynchronousSocketChannel > f u t u r e = asynchronousServerSocketChannel . accept ( ) ; while ( ! f u t u r e . i s D o n e ( ) ) ; AppThread o b j=new AppThread ( f u t u r e . g e t ( ) ) ; exec . execute ( obj ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( MyActionException : +e . g e t M e s s a g e ( ) ) ; } } } }

3. AppThread.java
1 2 3 4

package s e r v e r ; import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . c o n c u r r e n t . Future ;

64

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

6 7 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

public c l a s s AppThread extends Thread { private AsynchronousSocketChannel a s c=n u l l ; public AppThread ( AsynchronousSocketChannel a s c ) { t h i s . a s c=a s c ; } public void run ( ) { try { B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; Future < I n t e g e r > f r=a s c . r e a d ( bb ) ; while ( ! f r . i s D o n e ( ) ) ; long m =bb . getLong ( 0 ) ; long n=bb . getLong ( 8 ) ; App app=new App ( ) ; System . out . p r i n t l n (m + <> +n ) ; long r=app . cmmdc(m, n ) ; bb . c l e a r ( ) ; bb . putLong ( 0 , r ) ; Future < I n t e g e r > fw=a s c . w r i t e ( bb ) ; while ( ! fw . i s D o n e ( ) ) ; asc . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( S e r v e r c o m u n i c a t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ; } } }

4. AppServer.java
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16

package s e r v e r ; import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ; import s e r v e r . impl . MyMServer ; import i s e r v e r . IMyMServer ; public c l a s s AppServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; IMyMServer myMServer=new MyMServer ( ) ; AsynchronousServerSocketChannel asynchronousServerSocketChannel = myMServer . g e t A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ( p o r t ) ; myMServer . myAction ( a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ) ; } }

5. CmmdcClient.java
1 2 3 4 5 6 7

package c l i e n t ; import j a v a . n e t . UnknownHostException ; import j a v a . n e t . I n e t S o c k e t A d d r e s s ; import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ; import j a v a . n i o . B y t e B u f f e r ; import j a v a . u t i l . S c a n n e r ; import j a v a . i o . IOException ;

2.6. COMUNICAT II ASINCRONE PRIN CANALE

65

8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =7999; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; AsynchronousSocketChannel a s c=n u l l ; try { I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ; a s c=AsynchronousSocketChannel . open ( ) ; asc . connect ( i s a ) ; } catch ( UnknownHostException e ) { System . e r r . p r i n t l n ( S e r v e r n e c u n o s c u t : +h o s t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( C o n e c t a r e i m p o s i b i l a l a : + h o s t+ pe p o r t u l +p o r t+ +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; long m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; B y t e B u f f e r bb=B y t e B u f f e r . a l l o c a t e ( 1 6 ) ; bb . putLong ( 0 ,m) . putLong ( 8 , n ) ; try { Future < I n t e g e r > fw=a s c . w r i t e ( bb ) ; while ( ! fw . i s D o n e ( ) ) ; bb . c l e a r ( ) ; Future < I n t e g e r > f r=a s c . r e a d ( bb ) ; while ( ! f r . i s D o n e ( ) ) ; r=bb . getLong ( 0 ) ; System . out . p r i n t l n ( Cmmdc : +r ) ; asc . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E r o a r e de c o m u n i c a t i e +e . g e t M e s s a g e ( ) ) ; } } }

Intreb ari recapitulative


1. Precizat i termenul socket (soclu ).

66

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2. Precizat i clasele Java necesare unei aplicat ii client-server cu socluri (socket). 3. Precizat i diferent a de simetrie privind instant ierea dintre un obiect de tip Socket si unul de tip ServerSocket. 4. Care este rolul unui obiect de tip ServerSocket si cum se utilizeaz a? 5. Precizat i metodele unui obiect Socket, necesare n transmiterea si recept ia datelor. 6. Precizat i termenul multicast. 7. In ce const a participarea serverului la transmisie multicast ? 8. In ce const a participarea unui client la recept ia multicast ? 9. Precizat i termenul broadcast. 10. In ce const a participarea serverului la transmisie broadcast ? 11. In ce const a participarea unui client la recept ia broadcast ? 12. Care este rolul unui obiect de tip DatagramPacket ? 13. Precizati metodele clasei DatagramSocket utilizate la expedierea si la recept ia unui datagram. 14. Ce parametri caracterizeaz a un obiect de tip Buffer ? 15. Ce asem anare exist a ntre comunicat ia bazat a de datagrame si cea prin intermediul canalelor ?

Capitolul 3 Reg asirea obiectelor prin servicii de nume


Oric arui obiect i sunt asociate un nume si o referint a . Reg asirea / c autarea obiectului se face pornind de la numele obiectului, prin referint a se ajunge la obiect. Exemple date prin sablonul (Nume Referint a Obiect) 1. Accesul la o carte ntr-o bibliotec a: Titlul c art ii Referint a c art ii din bibliotec a Carte 2. Contactul telefonic cu o persoana: Nume persoan a Num ar telefon Persoan a Un serviciu de nume cont ine asocieri dintre nume de obiecte si obiecte si poate oferi facilit a ti de reg asire a obiectelor.

3.1

Java Naming and Directory Interface

Java Naming and Directory Interface - JNDI este o interfat a de programare (Application Programming Interface - API ) care descrie funct ionalitatea unui serviciu de nume. Cuv antul servici este utilizat n sens comun, entitate care pune la dispozit ie facilit a ti de folosire. Al aturi de interfat a JNDI, arhitectura JNDI mai cont ine interfat a Service Provider Interface - SPI. Implementarea interfet ei SPI de un furnizor de servicii JNDI are ca efect independent a programului Java de furnizorul de servicii JNDI. 67

68

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

JNDI este implementat de serviciile de nume: Filesystem are ca obiect asocierea dintre numele de sier sau catalog cu obiectul corespunz ator. DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu adresa IP. RMI registry utilizat n aplicat ii RMI, din Java. Are ca obiect asocierea ntre un nume de serviciu de invocare ale obiectelor la distant a cu un delegat al serviciului (stub). COS - Common Object Service Naming utilizat n aplicat ii CORBA. Are ca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor la distant a cu referint a la serviciu. LDAP - Lightweight Directory Access Protocol dene ste un protocol pentru accesarea datelor ret inute ntr-un catalog LDAP (LDAP directory, information directory ). Un catalog LDAP permite ret inerea si reg asirea referint elor obiectelor denite pe un calculator.

Interfat a javax.naming.Context
Printr-un context se va nt elege o mult ime de asocieri nume - obiect. Corespunz ator unui context, JNDI dene ste interfat a Context, cu metodele void bind(String nume ,Object object ) void rebind(String nume ,Object object ) void unbind(String nume ) Object lookup(String nume ) NamingEnumeration list(String nume ) Returneaz a lista cu nume obiectelor mpreuna cu tipul lor. NamingEnumeration listBindings(String nume ) Returneaz a lista cu nume obiectelor mpreuna cu tipul si locat ia acestora. Specicat iile JNDI prev ad denirea unui context init ial, implementat prin clasa javax.naming.InitialContext, clas a ce implementeaz a interfat a Context. Constructori.

3.1. JAVA NAMING AND DIRECTORY INTERFACE

69

public InitialContext() throws NamingException public void InitialContext(Hashtable<?,?> environment )throws NamingException Pentru crearea contextului init ial trebuie specicat a clasa care creaz a contextul init ial prin parametrul java.naming.factory.initial sau constanta Context.INITIAL CONTEXT FACTORY. Acest parametru se poate da n mai multe moduri: Includerea n obiectul Hashtable care apare n constructorul clasei InitalContext. Hashtable env=new Hashtable() env.put("java.naming.factory.initial",...); Context ctx=InitialContext(env); sau Hashtable env=new Hashtable() env.put(Context.INITIAL_CONTEXT_FACTORY,...); Context ctx=new InitialContext(env); Ca parametru de sistem furnizat la lansarea programului Java, prin java -Djava.naming.factory.initial=... ClasaJava Parametrul se poate da n interiorul programului prin System.setProperty("java.naming.factory.initial",...); sau System.setProperty(Context.INITIAL_CONTEXT_FACTORY,...); Atribut n sierul de propriet a ti jndi.properties. In aceste ultime dou a cazuri, contextul initial se creaz a prin Context ctx=new InitialContext();

70

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Funct ie de serviciul de nume, clasa care creaz a contextul init ial este dat n tabelul Serviciul de nume Filesystem COS RMI DNS LDAP Clasa com.sun.jndi.fscontext.RefFSContextFactory com.sun.jndi.cosnaming.CNCtxFactory com.sun.jndi.rmi.registry.RegistryContextFactory com.sun.jndi.dns.DnsContextFactory com.sun.jndi.ldap.LdapCtxFactory

Exemplul 3.1.1 Utiliz and serviciul JNDI Filesystem se creaz a un context prin intermediul c areia se a seaz a cont inutul unui catalog indicat de client.
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40

import import import import import import import import import

j a v a x . naming . Context ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . B i n d i n g ; j a v a x . naming . NamingEnumeration ; j a v a x . naming . NamingException ; j a v a x . naming . NameClassPair ; java . io . F i l e ; java . u t i l . Hashtable ; java . u t i l . Scanner ;

c l a s s Lookup { public s t a t i c void main ( S t r i n g [ ] a r g s ) { Context c t x=n u l l ; / // V a r i a n t a 1 H a s h t a b l e env = new H a s h t a b l e ( 1 1 ) ; env . p u t ( C o n t e x t . INITIAL CONTEXT FACTORY, com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ) ; try { c t x = new I n i t i a l C o n t e x t ( env ) ; } c a t c h ( NamingException e ) { System . o u t . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } / / // V a r i a n t a 2 System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ) ; try { c t x = new I n i t i a l C o n t e x t ( ) ; } c a t c h ( NamingException e ) { System . o u t . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } / // V a r i a n t a 3 try { c t x = new I n i t i a l C o n t e x t ( ) ;

3.1. JAVA NAMING AND DIRECTORY INTERFACE

71

41 42 43 44 46 47 48 49 50 51 53 54 55 56 57 58 60 61 62 63 64 65 66 67 68 69 70 71 72

} catch ( NamingException e ) { System . out . p r i n t l n ( I n i t i a l C o n t e x t E r r o r : +e . g e t M e s s a g e ( ) ) ; } S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i r e f e r i n t a a b s o l u t a a unui c a t a l o g : ) ; S t r i n g myName=s c a n n e r . n e x t ( ) ; try { System . out . p r i n t l n ( \ n c t x . l o o k u p ( +myName+ ) p r o d u c e ) ; System . out . p r i n t l n ( c t x . l o o k u p (myName ) ) ; System . out . p r i n t l n ( \ n C o n t i n u t u l c a t a l o g u l u i +myName+ e s t e : \ n ) ; NamingEnumeration l s t =c t x . l i s t (myName ) ; while ( l s t . hasMore ( ) ) { NameClassPair nc = ( NameClassPair ) l s t . n e x t ( ) ; System . out . p r i n t l n ( nc ) ; } System . out . p r i n t l n ( \ n C o n t i n u t u l c a t a l o g u l u i +myName+ e s t e : \ n ) ; NamingEnumeration l s t 1 = c t x . l i s t B i n d i n g s (myName ) ; while ( l s t 1 . hasMore ( ) ) { B i n d i n g bd = ( B i n d i n g ) l s t 1 . n e x t ( ) ; System . out . p r i n t l n ( bd ) ; } ctx . c l o s e ( ) ; } catch ( NamingException e ) { System . out . p r i n t l n ( Lookup f a i l e d : + e . g e t M e s s a g e ( ) ) ; } } }

Apelarea clasei, n varianta dat a, const a din


java -Djava.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory Lookup

sau
java Lookup

caz, n care, n catalogul curent se g ase ste sierul jndi.properties cu cont inutul
java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory

Serviciul de nume Filesystem este dat de sierele: fscontext.jar si providerutil.jar.

3.1.1

LDAP

LDAP poate privit ca un sistem de gestiune a unei baze de date (ne relat ional). Baza de date este alc atuit a din atribute ale c aror nume este precizat de protocolul LDAP. Punctele de intrare (r ad acinile) sunt date de DN (Distinguished Name ). Uzual DN se dene ste printr-una din variantele

72

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

1. o=organization ,c=country 2. o=organization 3. dc=domain content 1 ,dc=domain content 2 De exemplu, dc=example,dc=com 4. uid=user id ,ou=organization unit De exemplu, uid=admin,ou=system Un utilizator este caracterizat prin atributul cn - common name si are acces la LDAP prin precizarea simultan a a atributelor DN si cn. Implement ari gratuite LDAP sunt: OpenDS (Open Directory Service ); ApacheDS (Apache Directory Service ). Apache Directory Studio incorporeaz a si ofer a interfat a grac a de administrare pentru ApacheDS. Vom utiliza produsul OpenDS. Instalarea const a din: 1. dezarhivarea distribut iei; 2. se completeaz a sursa sierului OpenDS-*\setup.bat cu set OPENDS JAVA HOME=... ca prima linie; 3. se execut a OpenDS-*\setup.bat. Prin intermediul unei interfet e grace se xeaz a o parola pentru cn=Directory Manager. Fie 1q2w3e aceast a parol a. un punct de intrare, e acesta DN: dc=example,dc=com. Implicit, serverul OpenDS utilizeaz a portul 389. Operat iile de congurare se fac utiliz and interfat a grac a a componentei OpenDS Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . . set OpenDS_HOME=. . .\OpenDS-* %OpenDS_HOME%\bat\control-panel.bat

3.1. JAVA NAMING AND DIRECTORY INTERFACE

73

Declararea unui punct de intrare (utilizator) se face prin Manage Entries Entries New User, urmat de completarea datelor cerute. Schimbarea parolei unui utilizator se face tot din Manage Entries urmat de clic-dreapta pe DN si Reset User Password. Prin aceast a component a se poate porni si opri serverul OpenDS, ambele operat ii put and executate si apel and start-ds, stop-ds din catalogul OpenDS HOME\bat. Act iunile care pot ntreprinse de un client care interact ioneaz a cu serverul constau n autenticare: datele necesare sunt DN si parola; conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea implic a crearea unui punct de intrare precizat prin cn; c autarea / localizarea (lookup) unui punct de intrare precizat prin cn. Exemplul 3.1.2 Program pentru nregistrarea si stergerea referint ei unui obiect de tip Cmmdc.
1 2 3 4 5 6 8 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

import import import import import import

java . u t i l . Hashtable ; java . u t i l . Scanner ; j a v a x . naming . Context ; j a v a x . naming . NamingException ; j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ; j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;

public c l a s s LDAPServerCmmdc { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i f u r n i z o r u l LDAP: ) ; System . out . p r i n t l n ( 1 : OpenDS ) ; System . out . p r i n t l n ( 2 : Apache D i r e c t o r y S e r v i c e ) ; i n t p r o v i d e r=s c a n n e r . n e x t I n t ( ) ; H a s h t a b l e env = new H a s h t a b l e ( ) ; env . put ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . l d a p . LdapCtxFactory ) ; i f ( p r o v i d e r ==1){ env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 3 8 9 / dc=example , dc=com ) ; env . put ( Context . SECURITY PRINCIPAL , cn=D i r e c t o r y Manager ) ; env . put ( Context . SECURITY CREDENTIALS, 1 q2w3e ) ; } else { env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 1 0 3 8 9 / u i d=admin , ou=system ) ; env . put ( Context . SECURITY PRINCIPAL , u i d=admin , ou=system ) ; env . put ( Context . SECURITY CREDENTIALS, s e c r e t ) ; } DirContext ctx = null ;

74

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

System . out . p r i n t l n ( A l e g e t i o p e r a t i a : 1 bind ; 2 unbind ) ; i n t o p e r=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \ cn \ + + a o b i e c t u l u i Cmmdc ) ; System . out . p r i n t l n ( cn= ) ; S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ; try { c t x = new I n i t i a l D i r C o n t e x t ( env ) ; i f ( o p e r ==1){ Cmmdc o b j=new Cmmdc ( ) ; S t r i n g s t r= cn=+cmmdcObj ; c t x . bind ( s t r , o b j ) ; } else { c t x . unbind ( cn=+cmmdcObj ) ; } ctx . c l o s e ( ) ; } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPserverCmmdc : } } }

+e . g e t M e s s a g e ( ) ) ;

Codul clasei Cmmdc este


1 2 3 4 5 6 7 8 9 10

public c l a s s Cmmdc implements j a v a . i o . S e r i a l i z a b l e { public long cmmdc( long a , long b ) { while ( b != 0 ) { long r = a % b ; a = b; b = r; } return a ; } }

Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc reg asit pe baza referintei din serverul LDAP.
1 2 3 4 5 6 8 9 10 11 12 13 14 15

import import import import import import

java . u t i l . Hashtable ; j a v a x . naming . Context ; j a v a x . naming . NamingException ; j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ; j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ; java . u t i l . Scanner ;

public c l a s s LDAPClientCmmdc { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i f u r n i z o r u l LDAP: ) ; System . out . p r i n t l n ( 1 : OpenDS ) ; System . out . p r i n t l n ( 2 : Apache D i r e c t o r y S e r v i c e ) ; i n t p r o v i d e r=s c a n n e r . n e x t I n t ( ) ; H a s h t a b l e env = new H a s h t a b l e ( ) ;

3.1. JAVA NAMING AND DIRECTORY INTERFACE

75

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

env . put ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . l d a p . LdapCtxFactory ) ; i f ( p r o v i d e r ==1){ env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 3 8 9 / dc=example , dc=com ) ; env . put ( Context . SECURITY PRINCIPAL , cn=D i r e c t o r y Manager ) ; env . put ( Context . SECURITY CREDENTIALS, 1 q2w3e ) ; } else { env . put ( Context . PROVIDER URL, l d a p : / / l o c a l h o s t : 1 0 3 8 9 / u i d=admin , ou=system ) ; env . put ( Context . SECURITY PRINCIPAL , u i d=admin , ou=system ) ; env . put ( Context . SECURITY CREDENTIALS, s e c r e t ) ; } DirContext ctx = null ; try { c t x=new I n i t i a l D i r C o n t e x t ( env ) ; i f ( c t x != n u l l ) { System . out . p r i n t l n ( I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \ cn \ + a o b i e c t u l u i Cmmdc ) ; System . out . p r i n t l n ( cn= ) ; S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ; O b j e c t o b j e c t = c t x . l o o k u p ( cn=+cmmdcObj ) ; System . out . p r i n t l n ( Primul numar ) ; long a=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( Al d o i l e a numar ) ; long b=s c a n n e r . n e x t I n t ( ) ; Cmmdc o b j =(Cmmdc) o b j e c t ; System . out . p r i n t l n ( R e z u l t a t u l cmmdc e s t e : +o b j . cmmdc( a , b ) ) ; ctx . c l o s e ( ) ; } } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPClientCmmdc : +e . g e t M e s s a g e ( ) ) ; } } }

76

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Capitolul 4 Invocarea procedurilor la distant a


Invocarea procedurilor la distant a (Remote Procedure Call RPC ) nseamn a apelarea unei metode a unui obiect aat pe un alt calculator ca si cum acesta s-ar aa pe calculatorul local. Se vor prezenta dou a cazuri: Invocarea procedurilor la distant a n cazul mediului omogen Java. Denumirea tehnologiei n acest caz este Invocarea metodei la distant a Remote Method Invocation (RMI). Prin mediu omogen se nt elege faptul c a at at compontenta server c at si componenta client sunt programate n acela si limbaj de programare, Java n cazul de fat a . Invocarea procedurilor la distant a n cazul medii neomogene. Solut ia n acest caz este dat de Common Object Request Broker Arhitecture (CORBA).

4.1

Remote Method Invocation

Reg asirea obiectelor la distant a. Ideea g asirii unui obiect la distant a este c a serverul nscrie un reprezentant al s au numit stub (ciot) ntr-un obiect registry - registru. Acest obiect se creaz a cu programul rmiregistry.exe din distribut ia java si se lanseaz a n execut ie prin start rmiregistry [port ] unde valoarea implicit a a portului este 1099. Comanda start apart ine sistemului de operare. rmiregistry este un serviciu de nume JNDI. 77

78

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

Un client obt ine din registry stub-ul serverului, prin intermediul c aruia realizeaz a comunicat ia cu programul server. C and un obiect al clientului apeleaz a o metod a a unui obiect aat la distant a , se va face, de fapt, un apel de metod a a unui obiect care reprezint a serverul. Acesta este stub -ul, aat pe acea si ma sin a cu clientul. Rolul acestui obiect este s a mpacheteze (marshalling) parametrii de apel ai metodei ntr-un mesaj ce va transferat prin ret ea. Impachetarea se face ntr-o manier a independent a de calculator, mai precis sirurile de caractere si obiecte sunt transmise ntr-un format care nu se bazeaz a pe referint e. Pentru obiecte se utilizeaz a serializarea obiectelor Java. Serializarea datelor reprezint a transformarea acestora din tipuri de date diferite ntr-un sir de octet i care va transportat prin ret ea f ar a interpretare, dar care p astreaz a informat iile despre structura init ial a a datelor. Deserializarea este procesul invers de refacere a structurilor trimise prin ret ea. Mesajul asamblat este transmis c atre server, care stie s a desfac a mesajul recept ionat invoc and n mod corespunz ator metoda referit a de client. Atunci c and clientul face apel la o metod a aat a pe o alt a ma sin a, este invocat stub-ul client, care ncepe conversat ia cu serverul. Acest lucru este complet transparent utilizatorului, care are impresia c a invoc a o metod a local a. Metodele apelate la distant a trebuie declarate ca apart in and unei interfet e ce extinde interfat a java.rmi.Remote. Fiecare asemenea metod a trebuie s a arunce o except ie java.rmi.RemoteException. Obiectele care circul a prin ret ea trebuie s a implementeze interfat a java.io.Serializable. Structura unei aplicat ii RMI. O aplicat ie RMI este alc atuit a din trei componente: 1. O interfat a la distant a (remote ) n care se declar a serviciile puse la dispozit ie de server; 2. Aplicat ia server care poate implementa serviciile interfet ei la distant a si nscrie n registry stub-ul corespunz ator; 3. Aplicat ia client ce apeleaz a unul sau mai multe servicii ale serverului. Aplicat ia server trebuie s a aib a acces la clasele interfet ei si a celor care o implementeaz a. Locat ia acestor clase se xeaz a prin atributul de nume java.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unul din protocoalele http, ftp, file. Utiliz and protocoalele http sau ftp arhiva interfet ei si a claselor care o implementeaz a se depun ntr-un server Web (Microsoft Internet Interchange

4.1. REMOTE METHOD INVOCATION

79

Server (IIS), apache-tomcat, respectiv ntr-un server ftp (apache-ftp ). In momentul lans arii aplicat iei server, serverul http / ftp trebuie s a e activ. Dac a se indic a prin protocolul file calea c atre cataloagele care cont in clasele interfet ei si ale implement arii lor atunci ultimul caracter al c aii este /. Din punctul de vedere al execut iei sunt implicate componentele: Serviciul de nume rmiregistry; Aplicat ia server; Aplicat ia client. Aplicat ia server si rmiregistry trebuie s a ruleze pe acela si calculator. Registrul rmiregistry implementeaz a interfat a java.rmi.registry.Registry1 . Metodele oferite sunt: void bind(String numeServiciu , Remote obj )throws RemoteException, AlreadyBoundException, AccessException Inregistreaz a n registry obiectul obj ce implementeaz a interfat a Remote sub numele numeServiciu. void rebind(String numeServiciu , Remote obj )throws RemoteException, AccessException Re nregistreaz a n registry obiectul obj ce implementeaz a interfat a Remote sub numele numeServiciu. Aceast a metod a poate apelat a doar dac a programul care face nregistrarea se a a pe acea si ma sin a ca registrul registry. String[] list()throws RemoteException, AccessException Returneaz a o list a a tuturor serviciilor nregistrate n registry. Remote lookup(String numeServiciu )throws RemoteException, NotBoundException, AccessException Returneaz a stub-ul serviciului nregistrat sub numele numeServiciu. void unbind(String numeServiciu )throws RemoteException, NotBoundException, AccessException S terge din registru serviciul.
1

Varianta direct a, f ar a a folosi facilit a tile JNDI pentru rmiregistry.

80

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

Localizarea registrului se obt ine utiliz and metoda static a getRegistry a clasei java.rmi.registry.LocateRegistry. public static Registry getRegistry() throws RemoteException public static Registry getRegistry(String host ) throws RemoteException public static Registry getRegistry(int port ) throws RemoteException public static Registry getRegistry(String host ,int port ) throws RemoteException Metoda public static Registry createRegistry(int port ) throws RemoteException creaz a un registru la portul specicat pe calculatorul local. Ansamblul (rmiregistry, port ) determin a n mod univoc o aplicat ie / serviciu. Interfat a Remote serve ste la marcarea interfet elor ale c aror metode urmeaz a a apelate de pe alt a ma sin a virtual a Java. Un obiect de tip java.rmi.server.UnicastRemoteObject mijloce ste transmiterea obiectelor si serve ste la generarea unui stub unui serviciu. Generarea stub-ului unui serviciu se obt ine prin intermediul metodei statice static Remote UnicastRemoteObject.exportObject(Remote obj ,int port ) Inregistrarea stub-ului unui serviciu descris de interfat a IService si implementat de clasa ServiceImpl n registry se face prin ServiceImpl obj=new ServiceImpl(); IService stub=(IService)UnicastRemoteObject.exportObject(obj,0); // Varianta cu apel rmiregistry direct /* Registry registry=LocateRegistry.getRegistry(host,port); registry.bind("MyServiceName",stub); */ // Varianta JNDI String sPort=(new Integer(port)).toString(); System.setProperty(Context.INITIAL_CONTEXT_FACTORY,

4.1. REMOTE METHOD INVOCATION

81

"com.sun.jndi.rmi.registry.RegistryContextFactory"); System.setProperty(Context.PROVIDER_URL,"rmi://"+host+":"+sPort); Context ctx=new InitialContext(); ctx.bind("MyServiceName",stub); Un client care dore ste s a foloseasc a trebuie s a cunoasc a: calculatorul pe care se g ase ste obiectul registry si portul la care ascult a serviciul; numele sub care serviciul s-a nregistrat n registry; metodele puse la dispozit ie de serviciu.

4.1.1

Crearea unei aplicat ii RMI

Exemplic am construirea unei aplicat ii RMI n care serviciul asigurat de server este calculul celui mai mare divizor comun a dou a numere naturale. 2 Pentru exemplele care urmeaz a, presupunem c a textele surs a se ret in n subcataloage ale unui catalog src, la care are acces doar programatorul, iar clasele obt inute prin compilare se depun n subcataloagele unui catalog public\classes, accesibil prin ret ea. Dezvoltarea unei aplicat ii se va face pe un calculator. In acest sens, celor 3 componente li se asociaz a cataloagele \i - pentru interfat a la distant a , \s pentru componenta server si \c - pentru componenta client. Pa si necesari compil arii si desf a sur arii componentelor aplicat iei se vor realiza prin intermediul lui ant. Pentru ecare component a se vor executa succesiv obiectivele: 1. Install - creaz a o structur a de cataloage src si public\classes. 2. Init - creaz a structura de cataloage specic a aplicat iei. 3. Compile - compileaz a programele surs a. Dezvoltarea unei aplicat ii RMI const a din parcurgerea urm atorilor pa si: 1. Denitea interfet ei la distant a .

Sistemul de operare utilizat este Windows

82

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

1 2 3 4

package cmmdc ; public i n t e r f a c e ICmmdc extends j a v a . rmi . Remote { long cmmdc( long a , long b ) throws j a v a . rmi . RemoteException ; }

Presupunem ca programatorul interfet ei ret ine textul surs a ICmmdc.java n catalogul \i\src\cmmdc. 2. Compilarea si arhivarea interfet ei se poate realiza sierul ant-build
1 2 3 5 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32

<project name= I n t e r f a c e d e f a u l t= I n s t a l l b a s e d i r= . > <description> I n t e r f a c e a c t i o n s </ description> < ! s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d > <property name= package v a l u e=cmmdc /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c /> <mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / d e s t d i r= p u b l i c / c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> < j a r b a s e d i r= p u b l i c / c l a s s e s d e s t f i l e = p u b l i c / c l a s s e s /$ { package } /$ { package } . j a r i n c l u d e s= $ { package } / . c l a s s /> </ target> </ project>

3. Implementarea interfet ei remote prin construirea aplicat iei server.

1 2 3 4 5 6 7 8

package s e r v e r ; import cmmdc . ICmmdc ; import j a v a . rmi . s e r v e r . UnicastRemoteObject ; // V a r i a n t a cu a p e l r m i r e g i s t r y d i r e c t import j a v a . rmi . r e g i s t r y . R e g i s t r y ; import j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; // V a r i a n t a JNDI import j a v a x . naming . Context ;

4.1. REMOTE METHOD INVOCATION

83

9 11 13 15 16 17 18 19 20 21 22 24 25 26 27 28 30 31 32 33 34 35 36 38 39 40 41 42 43 44

import j a v a x . naming . I n i t i a l C o n t e x t ; public c l a s s CmmdcImpl implements ICmmdc {

public long cmmdc( long a , long b ) { . . . } public s t a t i c void main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ; try { CmmdcImpl o b j=new CmmdcImpl ( ) ; ICmmdc s t u b =(ICmmdc) UnicastRemoteObject . e x p o r t O b j e c t ( obj , 0 ) ; // V a r i a n t a d i r e c t a / R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h o s t , p o r t ) ; r e g i s t r y . b i n d ( CmmdcServer , s t u b ) ; / // V a r i a n t a JNDI S t r i n g s P o r t =(new I n t e g e r ( p o r t ) ) . t o S t r i n g ( ) ; System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . rmi . r e g i s t r y . R e g i s t r y C o n t e x t F a c t o r y ) ; System . s e t P r o p e r t y ( Context . PROVIDER URL, rmi : / / +h o s t+ : +s P o r t ) ; Context c t x=new I n i t i a l C o n t e x t ( ) ; c t x . bind ( CmmdcServer , s t u b ) ; System . out . p r i n t l n ( CmmdcServer r e a d y ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcImpl e r r : + e . g e t M e s s a g e ( ) ) ; } } }

Textul surs a al programului server CmmdcImpl.java se ret ine n catalogul \s\src\server 4. (a) Compilarea programului server; (b) Crearea obiectului registry ; (c) Lansarea serverului n lucru se obt in cu ant cu
1 2 4 6 7 8 9 10

<project name= S e r v e r d e f a u l t= I n s t a l l b a s e d i r= . > <description> S e r v e r a c t i o n s </ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= s e r v e r /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v i c e c l a s s v a l u e=CmmdcImpl

/>

84

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

11 12 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30 32 33 34 35 36 37 38 39 41 42 43 44 45 47 48 49 50 51 52 54 55 56 58 59 61 62 63 64 65 66 67 68 69

<property name= p o r t v a l u e= 1099 /> <property name= h o s t v a l u e= l o c a l h o s t /> <target name= I n s t a l l > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c /> <mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r } /$ { j a r f i l e } t o d i r= p u b l i c / c l a s s e s /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / d e s t d i r= p u b l i c / c l a s s e s classpath= p u b l i c / c l a s s e s /$ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> <unjar src= p u b l i c / c l a s s e s /$ { j a r f i l e } d e s t= p u b l i c / c l a s s e s /> </ target> <target name=Rmi> <exec e x e c u t a b l e= r m i r e g i s t r y > <arg v a l u e= $ { p o r t } /> </ exec> </ target> <target name= A r c h i v e > < j a r d e s t f i l e =cmmdc . j a r b a s e d i r= p u b l i c / c l a s s e s > <include name= $ { package } / /> <include name=cmmdc/ /> </ j a r> </ target> <target name= S e r v e r > <java c l a s s n a m e= $ { package } . $ { s e r v i c e c l a s s } classpath= $ { path } / s / p u b l i c / c l a s s e s f o r k= t r u e > <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e= f i l e : $ { path } / s / p u b l i c / c l a s s e s / /> < ! <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e=h t t p : //$ { h o s t } : 8 0 8 0 / rmi /cmmdc . j a r /> > < ! <jvmarg v a l u e= Djava . rmi . s e r v e r . c o d e b a s e=f t p : //$ { h o s t } : 2 1 2 1 / rmi /cmmdc . j a r /> > <arg l i n e= $ { p o r t } />

4.1. REMOTE METHOD INVOCATION

85

70 71 72

</ java> </ target> </ project>

Obiectivele Rmi si Server se lanseaz a n ferestre dos distincte care r am an active pe durata de viat a a aplicat iei server. Obiectivul Archive creaz a arhiva jar necesar a desf a sur arii interfet ei si a claselor care o implementeaz a ntr-un server http / ftp. A sa cum s-a amintit mai sus, acest a arhiv a este preluat a de aplicat ia server, la lansare, prin atributul java.rmi.server.codebase. Server ftp Utiliz am serverul ftp apache-ftpserver. Instalarea const a din dezarhivarea arhivei desc arcate. Lansarea serverului se obt ine prin
set FTP_SERVER_HOME=. . . set JAVA_HOME=. . . %FTP_SERVER_HOME%\bin\ftpd.bat res/conf/ftpd-typical.xml

Resursele / sierele puse la dispozit ie de serverul ftp sunt puse n catalogul FTP SERVER HOME\res\home. Serverul RMI cu server ftp. Se creaz a arhiva cmmdc.jar cu cont inutul
cmmdc | ICmmdc.class server | CmmdcImpl.class

care se depune n serverul ftp, n catalogul rmi. 5. Realizarea programului client

1 2 3 4 5 6 7 8 9 11

package c l i e n t ; import cmmdc . ICmmdc ; import j a v a . u t i l . S c a n n e r ; // V a r i a n t a cu a p e l r m i r e g i s t r y d i r e c t import j a v a . rmi . r e g i s t r y . R e g i s t r y ; import j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; ; // V a r i a n t a JNDI import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; public c l a s s CmmdcClient {

86

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46

public s t a t i c void main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =Long . par se Lo ng ( s c a n n e r . n e x t ( ) ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ; long x =0; try { // V a r i a n t a d i r e c t a / R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h o s t , p o r t ) ; ICmmdc o b j =(ICmmdc) r e g i s t r y . l o o k u p ( CmmdcServer ) ; / // V a r i a n t a JNDI S t r i n g s P o r t =(new I n t e g e r ( p o r t ) ) . t o S t r i n g ( ) ; System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY, com . sun . j n d i . rmi . r e g i s t r y . R e g i s t r y C o n t e x t F a c t o r y ) ; System . s e t P r o p e r t y ( Context . PROVIDER URL, rmi : / / +h o s t+ : +s P o r t ) ; Context c t x=new I n i t i a l C o n t e x t ( ) ; ICmmdc o b j =(ICmmdc) c t x . l o o k u p ( CmmdcServer ) ; x=o b j . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcClient e x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

Sursa programului client CmmdcClient.java apart ine catalogului \c\src\client 6. Compilarea programului client si lansarea acestuia n execut ie.
1 2 4 6 7 8 9 10 11 12 14 15 16 17

<project name= C l i e n t d e f a u l t= I n s t a l l b a s e d i r= . > <description> C l i e n t a c t i o n s </ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= c l i e n t /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= h o s t v a l u e= l o c a l h o s t /> <property name= p o r t v a l u e= 1099 /> <property name= c l i e n t c l a s s v a l u e= CmmdcClient /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c />

4.1. REMOTE METHOD INVOCATION

87

18 19 20 22 23 24 25 26 27 28 30 31 32 33 34 35 37 38 39 40 41 42 43 44 45 46 47

<delete d i r= c l a s s e s /> <mkdir d i r= c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r }\ $ { j a r f i l e } t o d i r= c l a s s e s /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c i n c l u d e s= $ { package } / . j a v a d e s t d i r= c l a s s e s classpath= c l a s s e s \ $ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> </ target> <target name=Run depends= Compile description= S t a r t t h r c l i e n t > <java c l a s s n a m e= $ { package } . $ { c l i e n t c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= c l a s s e s /$ { j a r f i l e } /> <pathelement path= c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>

4.1.2

Tipare de programare

Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamic a a unui server. Prin aceea schem a, se va crea o clas a - fabrica de obiecte - care implementeaz a c ate o metod a get, ce returneaz a o instant a de server. Aceste metode sunt declarate ntr-o interfat a la distant a . Un client, apel and o asemenea metod a, va instant ia serverul dorit si va obt ine stub-ul corespunz ator. In felul acesta se vor putea utiliza o mult ime de aplicat ii distincte prin intermediul unui singur rmiregistry. Fiec arei aplicat ii i corespunde un server, instant iat la apelul clientului de metoda get corespunz atoare. Programarea unui server care poate lansat dinamic trebuie s a satisfac a restrict iile: Clasa serverului extinde clasa UnicastRemoteObject.

88

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

Exist a un constructor f ar a argumente ce arunc a except ia java.rmi.Remote Exception. Pentru exemplicarea tehnicii de lucru relu am aplicat ia pentru calculul celui mai mare divizor comun a dou a numere naturale, consider and interfat a
1 2 3 4

package cmmdc0 ; p u b l i c i n t e r f a c e ICmmdc0 e x t e n d s j a v a . rmi . Remote { p u b l i c l o n g compute ( l o n g m, l o n g n ) throws j a v a . rmi . RemoteException ; }

Aceas a interfat a va implementat a de clasa ServerCmmdc. Metoda compute este o metod a de calcul a celui mai mare divizor comun a dou a numere. Obiecte de tip ServerCmmdc se creaz a, de la distant a prin fabrica de obiecte FabObiecte, o clas a ce implementeaz a interfat a
1 2 3 4

package cmmdc0 ; p u b l i c i n t e r f a c e I F a b O b i e c t e e x t e n d s j a v a . rmi . Remote { p u b l i c ICmmdc0 getCmmdc ( ) throws j a v a . rmi . RemoteException ; }

Codurile claselor ServerCmmdc si FabObiecte sunt


1 2 3 5 7 9 10 11 12

package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject implements ICmmdc0 { p u b l i c ServerCmmdc ( ) throws RemoteException {} p u b l i c l o n g compute ( l o n g m, l o n g n ) throws RemoteException { . . . } }

respectiv
1 2 3 4 5 7 9 10 11 12 14 15 16 17 18

package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; p u b l i c c l a s s FabObiecte implements I F a b O b i e c t e { p u b l i c ICmmdc0 getCmmdc ( ) throws RemoteException { ServerCmmdc cmmdc=new ServerCmmdc ( ) ; r e t u r n cmmdc ; } p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ;

4.1. REMOTE METHOD INVOCATION

89

19 20 21 22 23 24 25 26 27 28 29 30

try { FabObiecte o b j=new FabObiecte ( ) ; I F a b O b i e c t e s t u b =( I F a b O b i e c t e ) UnicastRemoteObject . e x p o r t O b j e c t ( obj , 0 ) ; R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h os t , p o r t ) ; r e g i s t r y . bind ( O b j e c t F a c t o r y , s t u b ) ; System . out . p r i n t l n ( O b j e c t F a c t o r y r e a d y ) ; } catch ( Exception e ){ System . out . p r i n t l n ( F a c t o r y e r r +e . g e t M e s s a g e ( ) ) ; } } }

Aplicat ia client se compune din dou a clase 1. RemoteClient Clientul obt ine stub-ul serviciului, prin intermediul c aruia apeleaz a metada getCmmdc() a fabricii de obiecte, obt in and un obiect remote de tip ServerCmmdc, ce implementeaz a interfat a la distant a ICmmdc0.
1 2 3 4 5 7 9 11 13 14 15 16 17 18 19 20 21 22 23 24

package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject { ICmmdc0 remote=n u l l ; p u b l i c RemoteClient ( ) throws RemoteException {} p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException { I F a b O b i e c t e f a b r i c a=n u l l ; try { R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h ost , p o r t ) ; I F a b O b i e c t e o b j =( I F a b O b i e c t e ) r e g i s t r y . l o o k u p ( O b j e c t F a c t o r y ) ; remote=o b j . getCmmdc ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

2. ClientCmmdc0 Apeleaz a metoda compute a obiectului remote.


1 2 4 6 7

package cmmdc0 ; im po rt j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s ClientCmmdc0 { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ;

90

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; try { RemoteClient c t=new RemoteClient ( ho st , p o r t ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; l o n g n=s c a n n e r . nextLong ( ) ; l o n g x=c t . remote . compute (m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . e x i t ( 0 ) ; } }

Apelul invers Callback


Se nume ste apel invers apelarea de c atre programul server a unei metode a clientului. In RMI realizarea unui apel invers presupune: 1. denirea unei interfet e la distant a ce va implementat de programul client; 2. programul client ce implementeaz a interfat a extinde clasa UnicastRemote Object si are un constructor ce arunc a o except ie java.rmi.RemoteException. Extindem aplicat ia anterioar a cu posibilitatea suplimentar a a serverului (ServerCmmdc ) de a alege metoda de calcul a celui mai mare divizor comun dintre varianta imperativ a si cea recursiv a. Extindem interfat a ICmmdc0 cu metoda public void setMethod(ICallbackCmmdc obj)throws RemoteException;
1 2 3 4 5

package cmmdc0 ; p u b l i c i n t e r f a c e ICmmdc0 e x t e n d s j a v a . rmi . Remote { p u b l i c l o n g compute ( l o n g m, l o n g n ) throws j a v a . rmi . RemoteException ; p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws j a v a . rmi . RemoteException ; }

unde ICallbackCmmdc este interfat a

4.1. REMOTE METHOD INVOCATION

91

1 2 3 4

package cmmdc0 ; p u b l i c i n t e r f a c e ICallbackCmmdc e x t e n d s j a v a . rmi . Remote { p u b l i c S t r i n g getMethod ( ) throws j a v a . rmi . RemoteException ; }

ce va implementat a n clasa RemoteClient. Programul ServerCmmdc devine


1 2 3 5 6 7 9 11 12 13 14 15 16 17 18 20 21 22 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 43 44 45

package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject implements ICmmdc0 { p r i v a t e S t r i n g method=n u l l ; p u b l i c ServerCmmdc ( ) throws RemoteException {} p u b l i c l o n g compute ( l o n g m, l o n g n ) { l o n g x =0; i f ( method . e q u a l s ( NERECURSIV ) ) x=n e r e c u r s i v (m, n ) ; i f ( method . e q u a l s ( RECURSIV ) ) x=r e c u r s i v (m, n ) ; return x ; } p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws RemoteException { method=o b j . getMethod ( ) ; } p r i v a t e long r e c u r s i v ( long a , long b){ i f ( a==b ) return a ; else i f ( a<b ) r e t u r n r e c u r s i v ( a , ba ) ; else r e t u r n r e c u r s i v ( ab , b ) ; } p r i v a t e l o n g n e r e c u r s i v ( l o n g m, l o n g n ) { long r , c ; do { c=n ; r= m %n ; m =n ; n=r ; } while ( r !=0); return c ; } }

Dup a obt inerea stub-ului, clientul apeleaz a metoda setMethod a serverului remote, care, prin apel invers, apeleaz a metoda getMethod din RemoteClient. Clientul stabile ste metoda de calcul si apeleaz a metoda compute a lui remote.

92 Programele client devin


1 2 3 4 5 6 8 9 10 12 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32 33 34 35 36 37 38 39

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

package cmmdc0 ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ; im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ; im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ; im po rt j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject implements ICallbackCmmdc { ICmmdc0 remote=n u l l ; p u b l i c RemoteClient ( ) throws RemoteException {} p u b l i c S t r i n g getMethod ( ) { S c a n n e r s c a n n e r=new S ca n n e r ( System . i n ) ; System . out . p r i n t l n ( A l e g e t i v a r i a n t a a l g o r i t m u l u i l u i E u c l i d ) ; System . out . p r i n t l n ( 1 a l g o r i t m u l ne r e c u r s i v ) ; System . out . p r i n t l n ( 2 a l g o r i t m u l r e c u r s i v ) ; i n t x=s c a n n e r . n e x t I n t ( ) ; S t r i n g method=n u l l ; i f ( x==1) method=NERECURSIV ; else method=RECURSIV ; r e t u r n method ; } p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException { I F a b O b i e c t e f a b r i c a=n u l l ; try { R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h os t , p o r t ) ; I F a b O b i e c t e o b j =( I F a b O b i e c t e ) r e g i s t r y . l o o k u p ( O b j e c t F a c t o r y ) ; remote=o b j . getCmmdc ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

si
1 2 4 5 6 7 8 9 10 11 12 13 14 15 16

package cmmdc0 ; im po rt j a v a . u t i l . S c a n n e r ; p u b l i c c l a s s ClientCmmdc0 { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; i n t p o r t =1099; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; S c a n n e r s c a n n e r=new S ca n n e r ( System . i n ) ; try { RemoteClient c t=new RemoteClient ( ho st , p o r t ) ; c t . remote . setMethod ( c t ) ; System . out . p r i n t l n ( m = ) ;

4.1. REMOTE METHOD INVOCATION

93

17 18 19 20 21 22 23 24 25 26 27 28

long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; l o n g n=s c a n n e r . nextLong ( ) ; l o n g x=c t . remote . compute (m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( Exception e ){ System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . e x i t ( 0 ) ; } }

4.1.3

Obiect activabil la distant a

O instant a a clasei UnicastRemoteObject reprezint a un obiect la distant a care ruleaz a n permanent a, folosind resursele ma sinii server. Incep and cu versiunea JDK 1.2, prin ntroducerea clasei java.rmi.activation.Activatable si a programului rmid (...\jdk...\bin\rmid.exe) se pot crea programe care nregistreaz a informat ii despre obiecte la distant a ce vor create si executate la cerere. Invocarea de la distant a a unei metode apart in and unui asemenea obiect are ca efect activarea obiectului. Pe ecare ma sin a virtual a Java exist a un grup de activare (activation group), care realizeaz a activarea. Activarea este f acut a de un activator. Un activator cont ine o tabel a care face leg atura dintre clasa obiectului cu URL-ul acestuia si eventual, cu date necesare init ializ arii obiectului. Atunci c and activatorul constat a c a nu exist a un obiect referit, face apel la grupul de activare care va produce activarea obiectului. Din punctul de vedere al clientului utilizarea mecanismului de activare la distant a nu implic a modic ari. Modic arile intervin numai din punctul de vedere al serverului si al nregistr arii sale. Relu am aplicat ia dezvoltat a la nceputul capitolului, privind calculul celui mai mare divizor comun a dou a numere naturale. Aplicat ia server este compus a din dou a clase 1. o clasa ce implementeaz a interfat a ICmmdc : CmmdcActivabil; 2. clasa Setup, cu metoda main, care face posibil a mecanismul de activare si nscrie serviciul n registry. Aceast a clas a este preluat a din tutorialul dedicat activ arii a documentat iei ce nsot e ste distribut ia Java. Clasa ce implementeaz a interfat a la distant a trebuie

94

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

1. s a extind a clasa Activatable; 2. s a aib a un constructor ce are doi parametrii (a) un identicator al grupului de activare, de tip ActivationID, utilizat de demonul de activare rmid; (b) un obiect de tip MarshalledObject cu date de init ializare a obiec tului activabil. In cazul nostru, acest parametru nu va folosit. Codul surs a al clasei CmmdcActivabil este
1 2 3 4 5 6 8 9 11 12 13 14 16 17

package acmmdc ; im po rt j a v a . rmi . RemoteException ; im po rt j a v a . rmi . M a r s h a l l e d O b j e c t ; im po rt j a v a . rmi . a c t i v a t i o n . A c t i v a t a b l e ; im po rt j a v a . rmi . a c t i v a t i o n . A c t i v a t i o n I D ; im po rt cmmdc . ICmmdc ; p u b l i c c l a s s CmmdcActivabil e x t e n d s A c t i v a t a b l e implements ICmmdc { p u b l i c CmmdcActivabil ( A c t i v a t i o n I D id , M a r s h a l l e d O b j e c t data ) throws RemoteException { s u p e r ( id , 0 ) ; } p u b l i c l o n g cmmdc( l o n g m, l o n g n ) { . . . } }

Clasa Setup necesit a o serie de date furnizare ca propriet a ti: 1. drepturile de securitate ale grupului de activare myactivation.policy=group.policy; cu cont inutul
grant codeBase "${myactivation.impl.codebase}" { // permission to read and write objects file permission java.io.FilePermission "${myactivation.file}","read,write"; // permission to listen on an anonymous port permission java.net.SocketPermission "*:1024-","accept"; };

2. java.class.path=no.classpath ceea ce previne grupul de activare s a ncarce o clas a din classpath -ul local; 3. localizarea (URL) clasei ce implementeaz a interfat a myactivation.impl.codebase;

4.1. REMOTE METHOD INVOCATION

95

4. localizarea unui sier cu date de init ializare a obiectului activabil myactivation.file; 5. numele sub care nregistreaz a serviciul n registry myactivation.name. Programul Setup realizeaz a: 1. Construirea unui descriptor al grupului de activare. Grupul de activare este un container ce gestioneaz a obiectele activabile cont inute. 2. Inregistrarea descriptorului grupului de activare si obt inerea unui identicator al grupului de activare. 3. Construirea descriptorului de activare. Trebuie cunoscute idendicatorul grupului de activare; numele clasei ce implementeaz a interfat a la distant a ; localizarea (URL) clasei ce implementeaz a interfat a la distant a ; obiectul de tip MarshalledObject, cu datele de init ializare a obiectului activabil. 4. Inregistrarea descriptorului de activare, n urma c areia se obt ine stub-ul obiectului activabil. 5. Inregistrarea stub-ului mpreun a cu numele serviciului n registry. Codul clasei setup este
1 3 4 5 6 8 10 12 14 15 16 17 18

package acmmdc ; im po rt im po rt im po rt im po rt j a v a . rmi . ; j a v a . rmi . a c t i v a t i o n . ; j a v a . rmi . r e g i s t r y . ; java . u t i l . Properties ;

p u b l i c c l a s s Setup { p r i v a t e Setup ( ) {} p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { // Argumentul l i n i e i de comanda S t r i n g implClass = ; i f ( args . length < 1) { System . out . p r i n t l n ( u s a g e : ) ; System . out . p r i n t l n ( j a v a [ o p t i o n s ] examples . a c t i v a t i o n . Setup < i m p l C l a s s > ) ;

96

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40 41 42 44 45 46 47 48 50 51 53 54 55 57 58 59 60 61 62

System . e x i t ( 1 ) ; } else { implClass = args [ 0 ] ; } // C o n s t r u i r e a d e s c r i p t o r u l u i g r u p u l u i de a c t i v a r e S t r i n g p o l i c y=System . g e t P r o p e r t y ( m y a c t i v a t i o n . p o l i c y , group . p o l i c y ) ; S t r i n g implCodbase=System . g e t P r o p e r t y ( m y a c t i v a t i o n . impl . c o d e b a s e ) ; S t r i n g filename=System . g e t P r o p e r t y ( m y a c t i v a t i o n . f i l e , ) ; P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; p r o p s . put ( j a v a . s e c u r i t y . p o l i c y , p o l i c y ) ; p r o p s . put ( j a v a . c l a s s . path , n o c l a s s p a t h ) ; p r o p s . put ( m y a c t i v a t i o n . impl . c o d e b a s e , implCodebase ) ; i f ( filename != n u l l && ! filename . equals ( ) ) { p r o p s . put ( m y a c t i v a t i o n . f i l e , filename ) ; } A c t i v a t i o n G r o u p D e s c groupDesc = new A c t i v a t i o n G r o u p D e s c ( props , n u l l ) ; // I n r e g i s t r a r e a g r u p u l u i de a c t i v a r e p e n t r o b t i n e r e a // i d e n t i f i c a t o r u l u i de a c t i v a r e Ac tivat ionG roupI D groupID= A c t i v a t i o n G r o u p . getSystem ( ) . r e g i s t e r G r o u p ( groupDesc ) ; System . e r r . p r i n t l n ( A c t i v a t i o n group d e s c r i p t o r r e g i s t e r e d . ) ; // C o n s t r u i r e a d e s c r i p t o r u l u i de a c t i v a r e M a r s h a l l e d O b j e c t data = n u l l ; i f ( filename != n u l l && ! filename . equals ( ) ) { data = new M a r s h a l l e d O b j e c t ( filename ) ; } A c t i v a t i o n D e s c d e s c= new A c t i v a t i o n D e s c ( groupID , i m p l C l a s s , implCodebase , data ) ; // I n r e g i s t r a r e a d e s c r i p t o r u l u i de a c t i v a r e Remote s t u b = A c t i v a t a b l e . r e g i s t e r ( d e s c ) ; System . e r r . p r i n t l n ( A c t i v a t i o n d e s c r i p t o r r e g i s t e r e d . ) ; // I n r e g i s t r a r e a s e r v i c i u l u i i n r e g i s t r y S t r i n g name = System . g e t P r o p e r t y ( m y a c t i v a t i o n . name ) ; L o c a t e R e g i s t r y . g e t R e g i s t r y ( ) . r e b i n d ( name , s t u b ) ; System . e r r . p r i n t l n ( Stub bound i n r e g i s t r y . ) ; } }

Sursele celor dou a programe CmmdcActivabil.java si respectiv Setup.java sunt n catalogul \c\src\acmmdc. Lansarea serverului n execut ie const a din 1. Pornirea demon -ului rmid start rmid -J-Djava.security.policy=rmid.policy -J-Dmyactivation.policy=group.policy unde rmid.policy este

4.2. CORBA

97

grant { // allow activation groups to use certain system properties permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=${myactivation.policy}"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.class.path=no_classpath"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dmyactivation.impl.codebase=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dmyactivation.file=*";};

iar group.policy are codul


grant codeBase "${myactivation.impl.codebase}" { // permission to read and write objects file permission java.io.FilePermission "${myactivation.file}","read,write"; // permission to listen on an anonymous port permission java.net.SocketPermission "*:1024-","accept"; };

2. Pornirea registry -ului start rmiregistry 3. Lansarea programului Setup set classpath=\s\public\classes\cmmdc.jar;\s\public\classes java -Djava.rmi.server.codebase=file:/s/public/classes/ -Dmyactivation.impl.codebase=file:/s/public/classes/ -Dmyactivation.name=CmmdcServer -Dmyactivation.file="" -Dmyactivation.policy=group.policy acmmdc.Setup acmmdc.CmmdcActivabil Localizarea (URL) interfet ei la distant a se precizeaz a prin java.rmi.server.codebase; Drept client se utilizeaz a programul realizat n sect iunea 4.1.

4.2

CORBA

Ret elele de calculatoare sunt eterogene n timp ce majoritatea interfet elor de programare a aplicat iilor sunt orientate spre platforme omogene. Pentru a facilita integrarea unor sisteme dezvoltate separat, ntr-un singur mediu distribuit eterogen, OMG (Object Management Group consort iu

98

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

cuprinz and peste 800 de rme) a elaborat standardul CORBA (Common Object Request Broker Arhitecture): un cadru de dezvoltare a aplicat iilor distribuite n medii eterogene. La CORBA au aderat toate marile rme de software - cu exceptia Microsoft, rm a care a dezvoltat propriul s au model DCOM (Distributed Component Object Model), incompatibil CORBA. Aplicat ia server se nregistreaz a ntr-un Object Request Broker (ORB) sub un nume simbolic - nume servici. Pe baza acestui nume de servici, un client acces and ORB va avea acces la funct iile oferite de aplicat ia server. ORB este un pachet de servicii, independent de aplicat ii, dar care permit aplicat iilor s a interact ioneze prin ret ea. ORB face parte din middleware un intermediar ntre softul de ret ea si cel de aplicat ie. Un ORB se poate executa local pe un singur calculator sau poate conectat cu oricare alt ORB din Internet, folosind protocolul IIOP -- Internet Inter ORB Protocol, denit de CORBA 2. Distribut ia jdk ofer a un ORB utilizabil n Java sub forma unui servici JNDI. CORBA face o separare ntre interfat a unui obiect si implementarea sa si folose ste un limbaj neutru pentru denirea interfet elor: IDL -- Interface Definition Language. IDL permite realizarea descrierii de interfet e independent de limbajul de programare si de sistemul de operare folosit. O interfat a IDL dene ste leg atura dintre client si server.

4.2.1

Conexiunea RMI - CORBA

Firma Oracle - Sun Microsystems a dezvoltat o solut ie prin care interfet ele RMI pot implementate pentru a putea accesate ca obiecte CORBA. Aceasta este cunoscut a sub numele de solut ia RMI-IIOP, concretizat a printr-o serie de pachete din distribut ia jdk. In acest fel nu mai este necesar utilizarea limbajului IDL pentru descrierea interfet elor la distant a . Instrumente necesare utiliz arii solut iei RMI-IIOP: compilatorul rmic Opt iunea -iiop genereaza stub-ul si leg atura (tie) din partea serverului. Cu opt iunea -d se specic a catalogul n care aceste siere sunt scrise. serviciul ORB care asigur a reg asirea resurselor CORBA. Acest server se lanseaz a n execut ie prin

4.2. CORBA

99

start orbd -ORBInitialPort [port ] Programele orbd, rmic sunt n distribut ia jdk.

Dezvoltarea unei aplicat ii RMI-IIOP


Exemplic am prin aplicat ia care implementeaz a un serviciu de calcul a celui mai mare divizor comun a dou a numere naturale. Etapele realiz arii aplicat iei sunt: 1. Elaborarea interfet ei este identic a cu cea a aplicat iei RMI. 2. Implementarea interfet ei
1 2 3 4 6 7 9 10 11 13 14

package cmmdciiop ; im po rt j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ; im po rt cmmdc . ICmmdc ; im po rt j a v a . rmi . RemoteException ; // Se e x t i n d e c l a s a P o r t a b l e R e m o t e O b j e c t // s i nu UnicastRemoteObject p u b l i c c l a s s CmmdcImpl e x t e n d s P o r t a b l e R e m o t e O b j e c t implements ICmmdc { // C o n s t r u c t o r u l c l a s e i p u b l i c CmmdcImpl ( ) throws RemoteException {} p u b l i c l o n g cmmdc( l o n g a , l o n g b ) { . . . } }

3. Realizarea programului server.


1 2 3 5 6 7 8 9 10 11 12 13 14 15 17 18 19 20

package cmmdciiop ; im po rt j a v a x . naming . I n i t i a l C o n t e x t ; im po rt j a v a x . naming . Context ; p u b l i c c l a s s CmmdcServer { p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; try { // 1 : C r e a r e a u n e i i n s t a n t e CmmdcImpl CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ; // 2 : I n r e g i s t r a r e a u n e i r e f e r i n t e a s e r v i c i u l u i // u t i l i z a n d JNDI API System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . cosnaming . CNCtxFactory ) ;

100

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

21 22 23 24 25 26 27 28 29 30 31

System . s e t P r o p e r t y ( j a v a . naming . p r o v i d e r . u r l , i i o p : // +h o s t+ : +p o r t ) ; Context c t x = new I n i t i a l C o n t e x t ( ) ; c t x . r e b i n d ( CmmdcService , cmmdcRef ) ; System . out . p r i n t l n ( Cmmdc S e r v e r : Ready . . . ) ; } catch ( Exception e ) { System . out . p r i n t l n ( CmmdcServer: + e . g e t M e s s a g e ( ) ) ; } } }

4. Compilarea programelor CmmdcImpl.java si CmmdcServer.java. 5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunz ator interfet ei ator ICmmdc si a sierului Tie cmmdciiop. CmmdcImpl Tie.class corespunz clasei CmmdcImpl. Acestea se obt in rul and utilitarul rmic - din distrubut ia Java cu opt iunea -iiop rmic -iiop cmmdciiop.CmmdcImpl 6. Pornirea serverului CORBA de reg asire a serviciilor start orbd -ORBInitialPort 1050 7. Lansarea serverului n execut ie. Activit a tile legate de server se obt in prin ant cu sierul build
1 2 4 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22

<project name= S e r v e r d e f a u l t= I n s t a l l b a s e d i r= . > <description> S e r v e r a c t i o n s</ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= cmmdciiop /> <property name= i n t e r f a c e package v a l u e=cmmdc /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v i c e c l a s s v a l u e=CmmdcServer /> <property name= i m p l e m e n t a t i o n c l a s s v a l u e=CmmdcImpl <property name= h o s t v a l u e= l o c a l h o s t /> <property name= p o r t v a l u e= 1050 />

/>

<target name= I n s t a l l > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= p u b l i c />

4.2. CORBA

101

23 24 25 26 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 49 50 51 52 53 55 56 57 58 59 60 61 62 63 64

<mkdir d i r= p u b l i c /> <delete d i r= p u b l i c / c l a s s e s /> <mkdir d i r= p u b l i c / c l a s s e s /> </ target> <target name= I n i t > <mkdir d i r= s r c /$ { package } /> <mkdir d i r= p u b l i c / c l a s s e s /$ { package } /> <copy f i l e = $ { i n t e r f a c e j a r } /$ { j a r f i l e } t o d i r= p u b l i c / c l a s s e s /> <unjar src= p u b l i c / c l a s s e s /$ { j a r f i l e } d e s t= p u b l i c / c l a s s e s /> <delete d i r= p u b l i c / c l a s s e s /META INF /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c d e s t d i r= p u b l i c / c l a s s e s i n c l u d e s= $ { package }\ classpath= p u b l i c \ c l a s s e s \ $ { j a r f i l e } i n c l u d e a n t r u n t i m e= f a l s e /> <rmic c l a s s n a m e= $ { package } . $ { i m p l e m e n t a t i o n c l a s s } s o u r c e b a s e= s r c i i o p= y e s b a s e= p u b l i c / c l a s s e s classpath= p u b l i c / c l a s s e s /> </ target> <target name=Orb> <exec e x e c u t a b l e= orbd > <arg l i n e= O R B I n i t i a l P o r t $ { p o r t } O R B I n i t i a l H o s t $ { h o s t } /> </ exec> </ target> <target name= S e r v e r description= S t a r t t h r s e r v e r > <java c l a s s n a m e= $ { package } . $ { s e r v i c e c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= p u b l i c / c l a s s e s /$ { j a r f i l e } /> <pathelement path= p u b l i c / c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>

orbd si aplicat ia server se pot aa pe calculatoare distincte. 8. Editarea programului client.

1 2 3 4 5 6 8 9

package cmmdciiop ; import j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; import j a v a . u t i l . S c a n n e r ; import cmmdc . ICmmdc ; public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g a r g s [ ] ) {

102

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

10 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 34 35 36 37 38 39 40 41 42 43 44

S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =Long . par se Lo ng ( s c a n n e r . n e x t ( ) ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ; try { System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l , com . sun . j n d i . cosnaming . CNCtxFactory ) ; System . s e t P r o p e r t y ( j a v a . naming . p r o v i d e r . u r l , i i o p : / / +h o s t+ : +p o r t ) ; Context c t x = new I n i t i a l C o n t e x t ( ) ; // STEP 1 : Get t h e O b j e c t r e f e r e n c e from t h e Name S e r v c t x e // u s i n g JNDI c a l l . O b j e c t o b j r e f = c t x . l o o k u p ( CmmdcService ) ; System . out . p r i n t l n ( C l i e n t : Obtained a r e f . t o Cmmdc s e r v e r . ) ; // STEP 2 : Narrow t h e o b j e c t r e f e r e n c e t o t h e c o n c r e t e t y p e and // i n v o k e t h e method . ICmmdc o b j =(ICmmdc) P o r t a b l e R e m o t e O b j e c t . narrow ( o b j r e f , ICmmdc . c l a s s ) ; long x=o b j . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc=+x ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n + e . g e t M e s s a g e ( ) ) ; } } }

9. Compilarea si lansarea clientului n execut ie. Clientul trebuie s a dispun a de sierul stub (cmmdc. ICmmdc Stub.class) si bine nt eles de interfat a ICmmdc.jar. Fi sierul buildle pentru executarea clientului:
1 2 4 6 7 8 9 10 11 12 13 14 15

<project name= C l i e n t d e f a u l t= I n s t a l l b a s e d i r= . > <description> C l i e n t a c t i o n s</ description> <property name= path l oc a t io n= . . . /> <property name= package v a l u e= cmmdciiop /> <property name= i n t e r f a c e j a r l oc a t io n= $ { path } / i / p u b l i c / c l a s s e s /cmmdc /> <property name= j a r f i l e v a l u e=cmmdc . j a r /> <property name= s e r v e r package v a l u e= cmmdciiop /> <property name= i n t e r f a c e package v a l u e=cmmdc /> <property name= i n t e r f a c e stub l o c a t i o n l oc a t io n= $ { path } / s / p u b l i c / c l a s s e s /$ { i n t e r f a c e package } /> <property name= stub c l a s s v a l u e= S t u b . c l a s s /> <property name= h o s t v a l u e= l o c a l h o s t />

4.2. CORBA

103

16 17 19 20 21 22 23 24 25 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 46 47 48 49 50 52 53 54 55 56 57 58 59 60 61

<property name= p o r t v a l u e= 1050 /> <property name= c l i e n t c l a s s v a l u e= CmmdcClient /> <target name= I n s t a l l > < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > <delete d i r= s r c /> <mkdir d i r= s r c /> <delete d i r= c l a s s e s /> <mkdir d i r= c l a s s e s /> </ target> <target name= I n i t > < ! C r e a t e t h e time stamp > <tstamp /> <mkdir d i r= s r c /$ { package } /> <mkdir d i r= c l a s s e s /$ { package } /> <delete d i r= c l a s s e s /$ { s e r v e r package } /> <mkdir d i r= c l a s s e s /$ { s e r v e r package } /> <delete d i r= c l a s s e s /$ { i n t e r f a c e package } /> <mkdir d i r= c l a s s e s /$ { i n t e r f a c e package } /> <copy f i l e = $ { i n t e r f a c e j a r }\ $ { j a r f i l e } t o d i r= c l a s s e s /> <copy t o d i r= c l a s s e s /$ { i n t e r f a c e package } > < f i l e s e t d i r= $ { i n t e r f a c e stub l o c a t i o n } i n c l u d e s= $ { stub c l a s s } /> </ copy> <unjar src= c l a s s e s /$ { j a r f i l e } d e s t= c l a s s e s /> <delete d i r= c l a s s e s /META INF /> </ target> <target name= Compile depends= I n i t description= c o m p i l e t h e s o u r c e > <javac s r c d i r= s r c d e s t d i r= c l a s s e s i n c l u d e s= $ { package } \ . j a v a classpath= c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> </ target> <target name=Run depends= Compile description=Run t h e c l i e n t > <java c l a s s n a m e= $ { package } . $ { c l i e n t c l a s s } f o r k= t r u e > <classpath> <pathelement l oc a t io n= c l a s s e s /$ { j a r f i l e } /> <pathelement path= c l a s s e s /> </ classpath> <arg l i n e= $ { h o s t } $ { p o r t } /> </ java> </ target> </ project>

4.2.2

Aplicat ie Java prin CORBA

Scopul acestei sect iuni este prezentarea dezvolt arii unei aplicat ii pe baza unei interfet e bazat pe IDL. Pentru dezvoltarea aplicat iilor n limbajul de programare Java, translatarea interfet ei IDL n Java se realizeaz a cu utilitarul idlj din distribut ia jdk. Corespondent a ntre entit a tile IDL si Java este dat a n Tabelul 4.1

104

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

Tip IDL module boolean char, wchar octet string, wstring short, unsigned short long, unsigned long long long, unsigned long long oat double xed enum, struct, union sequence, array interface (non-abstract)

Any

Tip Java package boolean char byte java.lang.String short int long oat double java.math.BigDecimal class array signature interface, operations interface, helper class, holder class org.omg.CORBA.Any

Table 4.1: Entit a ti IDL si Java

Legarea cererii unui client de codul serviciului care satisface cererea utilizeaz a componenta CORBA Portable Object Adapter (POA).

Model cu server temporal


Exemplic am dezvoltarea unei aplicat ii distribuite CORBA n cazul n care serviciul pus la dispozit ie de server este calculul celui mai mare divizor comun a dou a numere naturale. Dezvoltarea unei aplicat ii distribuite CORBA cu mediul nativ Java presupune parcurgerea urm atoarelor pa si: 1. Realizarea interfet ei IDL care nseamn a (a) Editarea programului de interfat a :
1 2 3 4 5

module CmmdcApp{ i n t e r f a c e Cmmdc{ long long cmmdc( i n long long a , i n long long b ) ; }; };

4.2. CORBA

105 Salv am acest text ntr-un sier denumit Cmmdc.idl. Cmmdc va numele interfet ei utilizat de un client si implementat de server. Serviciul cont ine o singur a metod a cmmdc.

(b) Translatarea interfet ei n Java idlj -fall Cmmdc.idl Programul idlj creaz a un subcatalog CmmdcApp cu un pachet Java CmmdcApp cont in and sierele: Cmmdc.java CmmdcPOA.java ; CmmdcOperations.java; CmmdcStub.java; CmmdcHelper.java; CmmdcHolder.java. 2. Realizarea programelor server. Punem n evident a programul servant CmmdcImpl.java ce implementeaz a interfat a Cmmdc.
1 2 4 5 7 8 9 11 12

im po rt CmmdcApp . ; im po rt o r g . omg .CORBA.ORB; p u b l i c c l a s s CmmdcImpl e x t e n d s CmmdcPOA { p r i v a t e ORB orb ; p u b l i c CmmdcImpl (ORB orb ) { t h i s . orb = orb ; } p u b l i c l o n g cmmdc( l o n g a , l o n g b ) { . . . } }

si programul CmmdcServer.java, care nscrie n registrul ORB referint ele servantului. Activit a tile ce trebuie ntreprinse sunt declarate prin comentarii n textul surs a al programului
1 2 3 4 5 6 7

im po rt im po rt im po rt im po rt im po rt im po rt im po rt

CmmdcApp . ; o r g . omg . CosNaming . NameComponent ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg .CORBA.ORB; o r g . omg . P o r t a b l e S e r v e r .POA; o r g . omg . P o r t a b l e S e r v e r . POAHelper ;

106

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

9 10 11 12 13 15 16 17 18 19 21 22 24 25 26 28 29 30 31 33 34 35 36 38 40 41 42 43 44 45 46 47 48

p u b l i c c l a s s CmmdcServer { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { try { // C r e a s e s i i n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // O b t i n e r e a u n e i r e f e r i n t e POA s i // a c t i v a r e a g e s t i o n a r u l u i POAManager POA rootPOA = POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( RootPOA ) ) ; rootPOA . the POAManager ( ) . a c t i v a t e ( ) ; // C r e a r e a unui s e r v a n t CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ; // O b t i n e r e a u n e i r e f e r i n t e p e n t r u s e r v a n t o r g . omg .CORBA. O b j e c t r e f=rootPOA . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ; Cmmdc h r e f = CmmdcHelper . narrow ( r e f ) ; // O b t i n e r e a s e r v i c i u l u i NameService o r g . omg .CORBA. O b j e c t o b j R e f = orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt ncRef=NamingContextExtHelper . narrow ( o b j R e f ) ; // L e g a r e a s e r v a n t u l u i i n NameService S t r i n g name = CmmdcService ; NameComponent path [ ] = ncRef . to name ( name ) ; ncRef . r e b i n d ( path , h r e f ) ; System . out . p r i n t l n ( CmmdcServer r e a d y and w a i t i n g // Gata p e n t r u s a t i s f a c e r e a orb . run ( ) ; clientilor . . . );

} catch ( Exception e ) { System . e r r . p r i n t l n ( ERROR: + e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( CmmdcServer E x i t i n g . . . ) ; } }

Aceast a clas a corespunde unui sablon de programare adaptat exemplului tratat. In acest caz numele serviciului inregistrat n ORB va CmmdcService. Evident a numelor serviciilor CORBA nregistrate n ORB este f acut a de serviciul NameService. 3. Realizarea programului client CmmdcClient.java :
1 2 3 4 5 7 8

im po rt im po rt im po rt im po rt im po rt

CmmdcApp . ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg .CORBA.ORB; java . u t i l . Scanner ;

p u b l i c c l a s s CmmdcClient { s t a t i c Cmmdc cmmdc ;

4.2. CORBA

107

10 11 12 13 15 16 17 18 19 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { try { // c r e a r e a s i i n i t i a l i z a r e a unui r e p r e z e n t a n t ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // o b t i n e r e a u n e i r e f e r i n t e p e n t r u s e r v i c i u l d e n u m i r i l o r // s e r v i c i i l o r i n r e g i s t r a t e o r g . omg .CORBA. O b j e c t o b j R e f = orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt ncRef = NamingContextExtHelper . narrow ( o b j R e f ) ; // o b t i n e r e a u n e i r e f e r i n t e l a s e r v i c i u l d o r i t S t r i n g name = CmmdcService ; cmmdc = CmmdcHelper . narrow ( ncRef . r e s o l v e s t r ( name ) ) ; System . out . p r i n t l n ( Obtained a h a n d l e on s e r v e r o b j e c t : + cmmdc ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; l o n g m, n ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Cmmdc=+cmmdc . cmmdc(m, n ) ) ; } catch ( Exception e ) { System . out . p r i n t l n ( ERROR : + e ) ; e . p r i n t S t a c k T r a c e ( System . out ) ; } } }

Din nou clasa client cont ine sablonul de accesare a unui serviciu CORBA. Programele se compileaz a javac CmmdcApp\*.java 4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distribut ia jdk. start orbd -ORBInitialHost localhost -ORBInitialPort 1050 5. Pornirea programului server prin start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050 6. Lansarea programului client prin

108

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050

Model cu server persistent


Se consider a acea si interfat a Cmmdc.idl. Partea de server este alc atuit a din clasa servant CmmdcImpl.java care implementeaz a interfat a Cmmdc -prezentat n sect iunea anterioar a si clasa PersistentServer care asigur a leg atura cu serviciile ORB; accesul la clasa servantului.
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 20 21 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39

im po rt im po rt im po rt im po rt im po rt im po rt im po rt im po rt im po rt

java . u t i l . Properties ; o r g . omg .CORBA.ORB; o r g . omg .CORBA. P o l i c y ; o r g . omg . CosNaming . NamingContextExtHelper ; o r g . omg . CosNaming . NamingContextExt ; o r g . omg . CosNaming . NameComponent ; o r g . omg . P o r t a b l e S e r v e r .POA; o r g . omg . P o r t a b l e S e r v e r . POAHelper ; o r g . omg . P o r t a b l e S e r v e r . L i f e s p a n P o l i c y V a l u e ;

public class PersistentServer { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { P r o p e r t i e s p r o p e r t i e s = System . g e t P r o p e r t i e s ( ) ; p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l H o s t , l o c a l h o s t ) ; p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l P o r t , 1050 ) ; try { // Pas 1 : C r e a s e s i i n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , p r o p e r t i e s ) ; // Pas 2 : C r e a r e a unui s e r v a n t CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ; // Pas 3 : O b t i n e r e a u n e i r e f e r i n t e POA s i // a c t i v a r e a g e s t i o n a r u l u i POAManager // // Pas 31 : O b t i n e r e a r a d a c i n i i rootPOA POA rootPOA = POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( RootPOA ) ) ; // Pas 32 : C r e a t e s e c u r i t a t i i P e r s i s t e n t P o l i c y P o l i c y [ ] p e r s i s t e n t P o l i c y = new P o l i c y [ 1 ] ; p e r s i s t e n t P o l i c y [ 0 ] = rootPOA . c r e a t e l i f e s p a n p o l i c y ( L i f e s p a n P o l i c y V a l u e . PERSISTENT ) ; // Pas 33 : C r e a r e a o b i e c t u l u i POA cu s e c u r i t a t e a t h e P e r s i s t e n t P o l i c y POA p e r s i s t e n t P O A=rootPOA . create POA ( childPOA , n u l l , p e r s i s t e n t P o l i c y ) ; // Pas 34 : A c t i v a r e a m a n a g e r u l u i PersistentPOA POAManager , p e r s i s t e n t P O A . the POAManager ( ) . a c t i v a t e ( ) ; // // Pas 4 : A s o c i e r e a s e r v a n t u l u i cu PersistentPOA

4.2. CORBA

109

40 42 43 44 45 47 48 49 50 51 53 54 55 56 57 58 59 60 61

p e r s i s t e n t P O A . a c t i v a t e o b j e c t ( cmmdcImpl ) ; // Pas 5 : // // Numele // Numele F i x a r e a c o n t e x t u l u i RootNaming s i l e g a r e a de numele s e r v a n t u l u i s e r v i c i u l u i de nume : NameService s e r v a n t u l u i PersistentCmmdcServer

o r g . omg .CORBA. O b j e c t o b j R e f= orb . r e s o l v e i n i t i a l r e f e r e n c e s ( NameService ) ; NamingContextExt r o o t C o n t e x t=NamingContextExtHelper . narrow ( o b j R e f ) ; NameComponent [ ] nc = r o o t C o n t e x t . to name ( P e r s i s t e n t C m m d c S e r v e r ) ; r o o t C o n t e x t . r e b i n d ( nc , p e r s i s t e n t P O A . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ) ; // Pas 6 : Gata p e n t r u s a t i s f a c e r e a orb . run ( ) ; clientilor

} catch ( Exception e ) { System . e r r . p r i n t l n ( E x c e p t i o n i n P e r s i s t e n t S e r v e r S t a r t u p + e . getMessage ( ) ) ; } } }

Programul client
1 2 3 5 6 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34

im po rt CmmdcApp . ; im po rt o r g . omg .CORBA.ORB; im po rt j a v a . u t i l . S c a n n e r ; public class PersistentClient { p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1050 ; i f ( a r g s . l e n g t h > 0) h o s t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) p o r t=a r g s [ 1 ] ; try { // Pas 1 : I n i t i a l i z a r e ORB ORB orb = ORB. i n i t ( a r g s , n u l l ) ; // Pas 2 : R e z o l v a r e a p e r s i s t e n t e i // S e r v i c i u l NameService r u l e a z a pe h o s t cu p o r t u l p o r t // Numele s e r v i c i u l u i c e r u t l u i NameService e s t e // P e r s i s t e n t C m m d c S e r v e r o r g . omg .CORBA. O b j e c t o b j = orb . s t r i n g t o o b j e c t ( c o r b a n a m e : : +h o s t+ : +p o r t+#P e r s i s t e n t C m m d c S e r v e r ) ; Cmmdc cmmdc=CmmdcHelper . narrow ( o b j ) ; // Pas 3 : U t i l i z a r e a s e r v i c i u l u i S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( C a l l i n g P e r s i s t e n t S e r v e r . . ) ; i n t m, n , r ; System . out . p r i n t l n ( m = ) ; m =s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n ( n= ) ; n=s c a n n e r . n e x t I n t ( ) ; System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ; }

110

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

35 36 37 38 39 40

catch ( Exception e ) { System . e r r . p r i n t l n ( E x c e p t i o n i n P e r s i s t e n t C l i e n t . j a v a . . . + e . getrMessage ( ) ) ; } } }

Serverul trebuie s a e pe acela si calculator pe care ruleaz a orbd. Executarea aplicat iei presupune: 1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distribut ia jdk. orbd -ORBInitialPort 1050 -serverPollingTime 200 2. Activarea serverului: (a) Se lanseaz a utilitarul servertool servertool -ORBInitialPort 1050 (b) Se nregistreaz a serverul mpreun a cu numele serviciului pe care l ndepline ste: servertool > register -server PersistentServer -applicationName PersistentCmmdcServer -classpath cale_catre_fisierele_server\ Indeplinirea act iunii de nregistrare a serverului este indicat printr-un mesaj de forma server registered (serverid=257). Alte comenzi servertool Comanda servertool> servertool> servertool> servertool> Semnicat ie shutdown -serverid 257 Oprirea serviciului unregister -serverid 257 S tergerea serviciului quit Inchiderea utilitarului help

Observat ie 4.2.1 Dac a se utilizeaz a referint a c:\Program Files\Java\jdk1.7.0 *\bin

4.2. CORBA

111

n variabila de sistem PATH ( n loc de c:\Progra 1\Java\jdk1.7.0 *\bin) atunci apelarea serviciilor orbd si servertool se va face prin
c:\Progra~1\Java\jdk1.7.0_*\bin\orbd -ORBInitialPort 1050 -serverPollingTime 200 c:\Progra~1\Java\jdk1.7.0_*\bin\servertool -ORBInitialPort 1050

3. Executarea clientului java PersistentClient [hostORB [portORB]]

Intreb ari recapitulative


1. Precizat i abrevierea RMI. 2. Care sunt componentele unei aplicat ii client-server bazat pe RMI? 3. C ate si care sunt entit a tile care particip a la execut ia unei aplicat ii clientserver bazat pe RMI? 4. Care este rolul ndeplinit de (rmi)registry ? 5. Ce asigur a sablonul de programare Fabrica de obiecte n RMI? 6. Ce asigur a sablonul de programare Callback n RMI? 7. Explicat i caracterul sincron al comunic arii n RMI. 8. Care sunt activit a tile pe care un server RMI le are de indeplinit ? 9. Care sunt componentele unei aplicat ii client server bazat pe CORBA? 10. C ate si care sunt entit a tile care particip a la execut ia unei aplicat ii clientserver bazat pe CORBA? 11. Care este ideea solutiei CORBA pentru asigurarea interoperabilit a tii ntre client si server realizate n limbaje de programare diferite. 12. Explicat i caracterul sincron al comunic arii n CORBA. 13. Ce ofer a RMI-IIOP ? 14. Precizat i modelele de aplicat ii CORBA prezentate n curs si diferent a dintre ele din punctul de vedere al execut iei.

112

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT A

Capitolul 5 Mesaje n Java


Comunicat ia prin apelul la distant a - inclusiv RMI - este sincron: programul apelant se blocheaz a si a steapt a ca metoda apelat a s a se termine si s a furnizeze rezultatul cerut. Cu alte cuvinte apelul de procedur a la distant a cere at at clientului c at si serverului s a e simultan disponibile. 1 Comunicat iile asincrone ntre programe permit realizarea unor sisteme de programe cu un grad mult mai sc azut de cuplare, n sensul c a lansarea unei cereri si recept ionarea rezultatului se pot executa n momente diferite de timp. Asemenea aplicat ii se pot realiza prin comunicat ii de mesaje, mesaje care sunt ret inute de un intermediar (serviciu de mesagerie, server, broker, messaging middleware).

5.1

Java Message Service (JMS)

JMS dene ste un cadru de programare Java (API) pentru realizarea aplicat iilor bazate pe comunicat ii asincrone. Prezentarea se bazeaz a pe interfat a de programare (API) JMS-2, pentru care exist a implementarea de referint a Open Message Queue 5.* de la Oracle. Pentru interfat a de programare (API) JMS-1, exist a mai multe implement ari JMS, dintre care semnal am: Open Message Queue * apache ActiveMQ apache qpid
1

In accept iunea din acest capitol.

113

114

CAPITOLUL 5. MESAJE IN JAVA

Apache-qpid implementeaz a protocolul Advanced Message Queue Protocol (AMQP) referitor la modul de reprezentare a datelor ntr-un mesaj. Scopul protocolului este asigurarea interoperabilit a tii ntre aplicat ii de mesagerie realizate n diferite limbaje de programare. Versiunea Java a lui apache-qpid are n vedere interfat a de programare JMS 1. O aplicat ie JMS este alc atuit a din un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeaz a specicat iile JMS; client JMS : aplicat ie Java care trimite si recept ioneaz a mesaje; mesaje : obiecte utilizate n schimbul de informat ii de client i JMS; obiecte administrator - obiecte (resurse) create de administrator pentru a utilizate de client ii JMS, precum fabrica de conexiuni, obiectele destinat ie pentru ret inerea mesajelor. Aplicat iile dezvoltate pe baza JMS 1 functioneaz a si n cazul utiliz arii unui furnizor de servicii realizat pentru JMS-2. In esent a , JMS-2 simplic a programarea fat a de JMS-1. Modele de comunicat ie: Comunicat ii punctuale : Un mesaj este generat de un produc ator (expeditor) si la care va avea acces un singur consumator (destinatar). Mesajul este depus ntr-o coad a, de unde este preluat de c atre consumatorul care s-a legat de coad a. Dac a de coad a nu se leag a nici un consumator, atunci mesajul este p astrat n coad a. Comunicat ii axate pe subiect (topic) : Mesajele sunt depuse (publicate) n destinat ii specice subiectului. Consumatorii ce au subscris la acel subiect au acces la mesajele respective. Mai multi produc atori pot genera mesaje specice unui subiect, mesaje care pot accesate de consumatorii care au subscris subiectului. Consumatorii abonat i pe un subiect pot abonat simplu - valabi, adic a are acces la mesajele emise dup a momentul abon arii, pe durata conexiunii la furnizorul de servicii JMS; abonat permanent - valabil si dup a o ntrerupere a conexiunii la furnizorul de servicii JMS;

5.2. OPEN MESSAGE QUEUE 5

115

abonat partajat - mai multi abonat i utilizeaz a acea si conexiune; abonat partajat si permanent. Structura unui mesaj Un mesaj este alc atuit din Antet (header) : cont ine informat ii pentru identicarea destinat iei c at si pentru identicarea mesajului. Propriet a ti : au caracter opt ional si sunt sub forma (nume, valoare). Propriet a tile ajut a consumatorii s a selecteze mesajele. Corpul mesajului : opt ional. Potrivit specicat iilor JMS exist a 6 tipuri de mesaje. javax.jms.Message : mesaj f ar a corp; javax.jms.StreamMessage : corpul mesajului cont ine un ux Java de date de tip predenit; javax.jms.ByteMessage : javax.jms.MapMessage : corpul mesajului cont ine o familie de perechi (nume, valoare); javax.jms.TextMessage : corpul mesajului cont ine un string; javax.jms.ObjectMessage : corpul mesajului cont ine un obiect serializat. Ata sament (opt ional).

5.2

Open Message Queue 5

Instalarea variantei de sine st at atoare. In mediul Windows, n funct ie de resursa desc arcat a instalarea const a din: Se dezarhiveaz a sierul openmq*-binary-Windows.zip Se xeaz a atributele sierului etc\mq\imqenv.conf. Lansarea serviciului JMS. Orice aplicat ie JMS necesit a funct ionarea serviciului JMS. Serviciul JMS se instaleaz a prin imqbrokerd Funct ionarea corect a este indicat a prin mesajul

116

CAPITOLUL 5. MESAJE IN JAVA

imqbroker@hostname:7676 ready Dac a se dore ste schimbarea portului atunci se folose ste opt iunea -port port. Pe un calculator pot coexista mai multe servicii JMS doar dac a folosesc porturi distincte si au nume diferite. In acest caz, lansarea unui nou serviciu se face prin imqbrokerd -port port -name name Cu utilitarul imqsvcadmin putem dezinstala : imqsvcadmin remove verica : imqsvcadmin query instala : imqsvcadmin install serviciul JMS ca serviciu Windows. Dezinstalarea si instalarea are efect odat a cu repornirea calculatorului. Compilarea si executarea unui program necesit a completarea variabilei sistem classpath cu sierele JMS HOME\lib\jms.jar JMS HOME\lib\imq.jar

5.3

Elemente de programare - JMS-2

Semnal am dou a modalit a ti de programare / generare / reg asire a obiectelor administrator: Programat: obiectele administrator se instant iaz a prin API-ul oferit de produsul informatic; Prin JNDI. Codul surs a al programelor este independent de furnizorul de servicii de mesagerie. Elementele specice se declar a n siere de propriet a ti.

5.3.1

Modul programat: Trimiterea unui mesaj

Trimiterea unui mesaj necesit a: 1. Generarea obiectelor administrator

5.3. ELEMENTE DE PROGRAMARE - JMS-2

117

(a) Fabrici de conexiuni. com.sun.messaging.ConnectionFactory cf= new com.sun.messaging.ConnectionFactory();

Clasa com.sun.messaging.ConnectionFactory are descendent ii QueueConnectionFactor TopicConnectionFactory. (b) Obiectul destinat ie. In cazul comunicat iilor punctuale obiectul destinat ie este de tip javax.jms.Queue, iar crearea se face prin Queue q=new com.sun.messaging.Queue(numeCoada); Pentru comunicat ii axate pe subiect, obiectul destinat ie, de tip javax.jms.Topic se instant iaz a prin Topic t=new com.sun.messaging.Topic(subiect); 2. Instant ierea unui obiect de tip javax.jms.JMSContext JMSContext ctx=cf.createContext(); In nal, contextul se nchide ctx.close(); Prin intermediul unui obiect de tip JMSContext se obt in produc atorii de mesaje, de tip javax.jms.JMSProducer, dar si consumatorii de mesaje, de tip javax.jms.JMSConsumer. 3. Instant ierea unui produc ator de mesaje JMSProducer producer=ctx.createProducer(); Crearea si expedierea mesajelor se realizeaz a cu metodele clasei JMSProducer JMSProducer send(Destination destination, byte[] body ) JMSProducer send(Destination destination, Serializable body ) JMSProducer send(Destination destination, Map<String,Object> body ) JMSProducer send(Destination destination, String body )

118

CAPITOLUL 5. MESAJE IN JAVA

JMSProducer send(Destination destination, Message message ) Un obiect care implementeaz a interfat a javax.jms.Message se obt ine prin ctx.createMessage(). Exemplul 5.3.1 Clasa urm atoare genereaz a ntr-un r de execut ie, un num ar de mesaje de tip TextMessage ntr-o comunicat ie punctual a. Sf ar situl expedierii mesajelor se indic a prin generarea unui mesaj de tip Message. Num arul mesajelor este indicat de un parametru al constructorului.
1 2 3 5 6 7 9 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35

import j a v a x . jms . Queue ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgSenderT extends Thread { int n ; S t r i n g queueName ; MsgSenderT ( S t r i n g queueName , i n t n ) { t h i s . queueName=queueName ; t h i s . n=n ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } }

5.3.2

Recept ia sincron a a unui mesaj

Primele dou a act iuni sunt identice cu cele de la trimiterea unui mesaj: 1. Generarea obiectelor administrator.

5.3. ELEMENTE DE PROGRAMARE - JMS-2

119

2. Instant ierea unui obiect de tip javax.jms.JMSContext. 3. Instant ierea unui consumator de mesaje JMSConsumer consumer = ctx.createConsumer(q); Recept ia unui mesaj se obt ine cu una din metode Message receive() Recept ie blocant a. Message receive(long timeout ) Recept ie ntr-un interval de timp. Message receiveNoWait() Recept ie neblocant a. Exemplul 5.3.2 Recept ia de tip sincron a mesajelor ntr-un r de execut ie este efectuat de clasa urm atoare:
1 2 3 4 5 7 8 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;

public c l a s s SyncMsgReceiverT extends Thread { S t r i n g queueName ; SyncMsgReceiverT ( S t r i n g queueName ) { t h i s . queueName=queueName ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; }

120

CAPITOLUL 5. MESAJE IN JAVA

32 33 34 35 36 37 38 39

ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } }

Exemplul 5.3.3 Trimiterea si recept ia mesajelor se face prin aplicat ia


1 2 3 4 5 6 7 8 9 10 11 12 13 14

c l a s s MsgHelloT { public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t n=3; S t r i n g queueName=MyQueue ; i f ( a r g s . l e n g t h > 0) queueName=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgSenderT s e n d e r=new MsgSenderT ( queueName , n ) ; SyncMsgReceiverT r e c e i v e r =new SyncMsgReceiverT ( queueName ) ; receiver . start (); sender . s t a r t ( ) ; } }

5.3.3

Recept ia asincron a a unui mesaj

Recept ia asincron a a mesajelor presupune implementarea interfet ei MessageListener ce cont ine o singur a metod a public void onMessage(Message mesaj); care xeaz a prelucrarea mesajului. Metoda setMessageListener(MessageListener obj ) a clasei JMSConsumer xeaz a obiectul ce implementeaz a interfat a Messagelistener. Astfel, caracterul asincron const a din faptul c a mesajele sunt preluate de ascult ator - adic a obiectul ce implementeaz a interfat a MessageListener si nu de clientul JMS. ideea exemplelor anterioare, un consumator de tip asinExemplul 5.3.4 In cron al mesajelor este dat n clasa urm atoare:

5.3. ELEMENTE DE PROGRAMARE - JMS-2

121

1 2 3 4 6 7 9 10 11 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31 32 33

import import import import

j a v a x . jms . MessageConsumer ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;

public c l a s s AsyncMsgReceiverT extends Thread { S t r i n g queueName ; AsyncMsgReceiverT ( S t r i n g queueName ) { t h i s . queueName=queueName ; } public void run ( ) { try { com . sun . m e s s a g i n g . QueueConnectionFactory c f= new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . createConsumer ( q ) ; T e x t L i s t e n e r t e x t L i s t e n e r=new T e x t L i s t e n e r ( ) ; consumer . s e t M e s s a g e L i s t e n e r ( t e x t L i s t e n e r ) ; t e x t L i s t e n e r . run ( ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } }

mpreun a cu ascult atorul


1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23

import import import import

j a v a x . jms . M e s s a g e L i s t e n e r ; j a v a x . jms . JMSException ; j a v a x . jms . TextMessage ; j a v a x . jms . Message ;

public c l a s s T e x t L i s t e n e r implements M e s s a g e L i s t e n e r { boolean s f a r s i t = f a l s e ; public void onMessage ( Message message ) { i f ( message instanceof TextMessage ) { TextMessage m=(TextMessage ) message ; try { S t r i n g s= m. g e t T e x t ( ) ; System . out . p r i n t l n ( s ) ; } catch ( JMSException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } else s f a r s i t =true ; } public void run ( ) {

122
while ( ! s f a r s i t ) { try { Thread . s l e e p ( 1 ) ; } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } }; } }

CAPITOLUL 5. MESAJE IN JAVA

24 25 26 27 28 29 30 31

5.3.4

Publicarea mesajelor

Publicarea mesajelor corespunz atoare unui subiect se face asem an ator cu transmiterea mesajelor n comunicat ia punctual a, dar folosind instant e ale claselor dedicate acestui tip de comunicat ie. Exemplul 5.3.5
1 2 3 5 6 7 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

import j a v a x . jms . Topic ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgPublisherT extends Thread { int n ; String subiect ; MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { super ( ) ; t h i s . n=n ; t h i s . s u b i e c t=s u b i e c t ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , H e l l o +i ) ; } p r o d u c e r . send ( t , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } }

5.3. ELEMENTE DE PROGRAMARE - JMS-2

123

5.3.5

Abonare si recept ia mesajelor

Dac a t este obiectul de tip Topic, client ii se aboneaz a - subscriu - unui subiect prin JMSConsumer consumer = ctx.createConsumer(t); Subscrierea este valabil a at ata timp c at clientul este activ. Pentru a primi toate mesajele specice subiectului, chiar si c and clientul este inactiv, acesta trebuie s a e durabil, adic a crearea consumatorului s a se fac a prin ctx.setClientID(clientID); JMSConsumer consumer = ctx.createDurableConsumer(t,clientName); In ambele cazuri, clientul prime ste doar mesajele publicate din momentul subscrierii. Exemplul 5.3.6
1 2 3 4 5 7 8 9 10 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34

import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;

public c l a s s MsgSubscriberT extends Thread { String subiect ; String clientID ; S t r i n g clientName ; MsgSubscriberT ( S t r i n g s u b i e c t , S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { t h i s . s u b i e c t=s u b i e c t ; t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ; }

124

CAPITOLUL 5. MESAJE IN JAVA

35 36 37 38 39 40 41 42 43 44 45

else break ; } ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S u b s c r i b e r f i n i s h e d ) ; } }

Apelarea celor dou a activit a ti se face prin Exemplul 5.3.7


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

c l a s s MsgPS { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g s u b i e c t=JMS ; i n t n=3 , noAbonati =3; i f ( a r g s . l e n g t h > 0) s u b i e c t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t , n ) ; MsgSubscriberT [ ] abonat=new MsgSubscriberT [ noAbonati ] ; publisher . start ( ) ; f o r ( i n t i =0; i <noAbonati ; i ++){ abonat [ i ]=new MsgSubscriberT ( s u b i e c t , ID+i , i d +i ) ; abonat [ i ] . s t a r t ( ) ; } } }

5.3.6

Cazul abonatului partajat

Mai mult i client JMS folosesc acea si conexiune iar abonamentul se identic a printr-un nume (String). Dintre ace si client i doar unul recept ioneaz a mesajele care sunt emise dup a momentul abon arii. Exemplul 5.3.8 Fat a de exemplul anterior se vor expedia mai multe mesaje de tip Message.
1 2 3 5 6 7

import j a v a x . jms . Topic ; import j a v a x . jms . JMSContext ; import j a v a x . jms . JMSProducer ; public c l a s s MsgPublisherT extends Thread { int n ; String subiect ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

125

9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { super ( ) ; t h i s . n=n ; t h i s . s u b i e c t=s u b i e c t ; } public void run ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , H e l l o +i ) ; } f o r ( i n t i =0; i <n ; i ++)p r o d u c e r . send ( t , c t x . c r e a t e M e s s a g e ( ) ) ; ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } }

Pentru a folosi acea si conexiune recept ia mesajelor este programat a n dou a clase : Se instant iaz a o fabric a de conexiuni si un num ar de client i care vor utiliza acea si conexiune. Fiecare client este un r de execut ie care este gestionat de o cuv a (pool ) de re de execut ie.
1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 22 23

import import import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; java . u t i l . concurrent . ExecutorService ; java . u t i l . concurrent . Executors ;

public c l a s s R e c e i v e r s T extends Thread { String subiect ; String sharedSubscriptionName ; i n t noAbonati ; com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f ; R e c e i v e r s T ( i n t noAbonati , S t r i n g s u b i e c t , String sharedSubscriptionName ){ t h i s . s u b i e c t=s u b i e c t ; t h i s . noAbonati=noAbonati ; t h i s . s h a r e d S u b s c r i p t i o n N a m e=s h a r e d S u b s c r i p t i o n N a m e ; } public void run ( ) { E x e c u t o r S e r v i c e e x e c=E x e c u t o r s . newFixedThreadPool ( noAbonati ) ;

126

CAPITOLUL 5. MESAJE IN JAVA

25 26 27 28 30 31 32 33 34 35 36 37 38 39 41 42 43 44

try { c f=new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; f o r ( i n t i =0; i <noAbonati ; i ++){ S t r i n g c l i e n t N a m e= C l i e n t +i ; MsgSubscriberT t=new MsgSubscriberT ( c f , s u b i e c t , sharedSubscriptionName , clientName ) ; exec . execute ( t ) ; } e x e c . shutdownNow ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( R e c e i v e r s : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( R e c e i v e r s f i n i s h e d ) ; } }

Client ii JMS propriu-zi si


1 2 3 4 5 7 8 9 10 11 12 14 15 16 17 18 19 20 21 23 24 25 26 27 28 30 31 32 33 34

import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ;

public c l a s s MsgSubscriberT extends Thread { String subiect ; String clientID ; S t r i n g clientName ; String sharedSubscriptionName ; com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f ; MsgSubscriberT ( com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f , S t r i n g subiect , S t r i n g sharedSubscriptionName , S t r i n g clientName ){ t h i s . c f=c f ; t h i s . s u b i e c t=s u b i e c t ; t h i s . s h a r e d S u b s c r i p t i o n N a m e=s h a r e d S u b s c r i p t i o n N a m e ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . c r e a t e S h a r e d C o n s u m e r ( t , sharedSubscriptionName ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

127

35 36 37 38 39 40 41 42 43 44 45 46

} else break ; } ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( M s g S u b s c r i b e r : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S u b s c r i b e r +c l i e n t N a m e+ f i n i s h e d ) ; } }

Aplicat ia este condus a de clasa


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

public c l a s s MsgPS { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g s u b i e c t=JMS ; S t r i n g s h a r e d S u b s c r i p t i o n N a m e= o u r S u b s c r i p t i o n ; i n t n=3 , noAbonati =3; i f ( a r g s . l e n g t h > 0) s u b i e c t=a r g s [ 0 ] ; i f ( a r g s . l e n g t h > 1) n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t , n ) ; R e c e i v e r s T a b o n a t i=new R e c e i v e r s T ( noAbonati , s u b i e c t , sharedSubscriptionName ) ; abonati . s t a r t ( ) ; publisher . start ( ) ; } }

5.3.7

Obiecte administrator prin JNDI

Obiectele administrator coada sau topic, care ret in mesajele se precizeaz a n siere de propriet a ti - jndi.properties. Pentru Open Message Queue acest sier este Varianta Oracle-Open Message Queue
1 2 3 5 7 8 9 11 12 13

j a v a . naming . f a c t o r y . i n i t i a l = com . sun . j n d i . f s c o n t e x t . RefFSContextFactory j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp # use the f o l l o w i n g property to c o n f i g u r e the d e f a u l t connector # r e g i s t e r some q u e u e s i n JNDI u s i n g t h e form # queue . [ jndiName ] = [ physicalName ] queue . queue = myqueue # r e g i s t e r some t o p i c s i n JNDI u s i n g t h e form # t o p i c . [ jndiName ] = [ physicalName ] t o p i c . t o p i c = mytopic

128

CAPITOLUL 5. MESAJE IN JAVA

In acest caz este nevoie de crearea n prealabil a obiectelor corespunz atoare conexiunii, a cozii (queue) si a subiectului (topic). Aceaste obiecte se creaz a cu utilitarul imqobjmgr din distribut ia Oracle-Open Message Queue. Obiectele se pot crea cu sierul de comenzi:
1 2 3 4 5 6 7 8 9 10 11 12 13

s e t PATH =d : \mq\ b i n ;%PATH % imqobjmgr add t q f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t rem imqobjmgr add t t f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t imqobjmgr add t q l queue j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t rem imqobjmgr add t t l t o p i c j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . f s c o n t e x t

. RefFSContextFactory

. RefFSContextFactory

. RefFSContextFactory

. RefFSContextFactory

Obiectele se pot sterge cu sierul de comenzi:


1 2 3 4 5 6 7 8 9 10 11 12 13

s e t PATH =d : \mq\ b i n ;%PATH % imqobjmgr d e l e t e t q f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t t f l C o n n e c t i o n F a c t o r y j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t q l queue j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i . imqobjmgr d e l e t e t t l t o p i c j j a v a . naming . p r o v i d e r . u r l= f i l e : /// d : /Temp j j a v a . naming . f a c t o r y . i n i t i a l =com . sun . j n d i .

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

Relu am aplicat iile anterioare privind transmiterea / recept ia unui mesaj prin comunicat ie punctual a utiliz and o coad a si publicarea si recept ionarea unui mesaj prin comunicat ie bazat a pe subiect ntr-o variant a independentent a de suportul middleware de serviciu de mesagerie folosit. Reg asirea resurselor gestionate de serviciul de mesagerie se va face utiliz and JNDI.

5.3.8

Comunicat ia prin coad a - queue

Aplicat ia este alc atuit a din clasele MsgHelloT, MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT, TextListener. Fat a de versiunea prezentat a anterior se modic a doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT. In clasa MsgHelloT c ampul queueName reprezint a numele JNDI al cozii. Clasa MsgSenderT
1 2

import j a v a x . jms . QueueConnectionFactory ; import j a v a x . jms . Queue ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

129

3 4 5 6 7 8 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60 61

import import import import import import

j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;

public c l a s s MsgSenderT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g QUEUE JNDI NAME = queue ; private I n i t i a l C o n t e x t c t x ; private i n t n ; MsgSenderT ( S t r i n g queueName , i n t n ) { QUEUE JNDI NAME=queueName ; t h i s . n=n ; } public void run ( ) { try { setupJNDI ( ) ; QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Queue q=(Queue ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } private void setupJNDI ( ) { P r o p e r t i e s p r o p e r t i e s = new P r o p e r t i e s ( ) ; try { p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream ( j n d i . p r o p e r t i e s ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( JNDI P r o p e r t i e s E r r o r : +e . g e t M e s s a g e ( ) ) ; } try { c t x = new I n i t i a l C o n t e x t ( p r o p e r t i e s ) ; } catch ( NamingException e ) { System . e r r . p r i n t l n ( E r r o r S e t t i n g up JNDI Context : + e ) ; } } private void c l o s e J N D I ( ) { try { ctx . c l o s e ( ) ;

130

CAPITOLUL 5. MESAJE IN JAVA

62 63 64 65 66 67

} catch ( NamingException e ) { System . e r r . p r i n t l n ( Unable t o c l o s e JNDI Context : + e ) ; } } }

Clasa SyncMsgReceiverT
1 2 3 4 5 6 7 8 9 10 12 13 14 15 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 50

import import import import import import import import import import

j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;

public c l a s s SyncMsgReceiverT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g QUEUE JNDI NAME = queue ; private I n i t i a l C o n t e x t c t x ; SyncMsgReceiverT ( S t r i n g queueName ) { QUEUE JNDI NAME=queueName ; } public void run ( ) { try { setupJNDI ( ) ; QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Queue q=(Queue ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = j m s c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }

5.3. ELEMENTE DE PROGRAMARE - JMS-2

131

51

5.3.9

Comunicat ia pe baz a de subiect - topic

Aplicat ia este alc atuit a din clasele MsgPS, MsgPublisherT, MsgSubscriberT. Fat a de versiunea prezentat a anterior se modic a doar clasele MsgPublisherT si MsgSubscriberT. In clasa MsgPS c ampul subiect reprezint a numele JNDI ata sat topic-ului. Clasa MsgPublisherT
1 2 3 4 5 6 7 8 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 43 45

import import import import import import import import

j a v a x . jms . T o p i c C o n n e c t i o n F a c t o r y ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;

public c l a s s MsgPublisherT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g TOPIC JNDI NAME = t o p i c ; private I n i t i a l C o n t e x t c t x ; private i n t n ; MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) { t h i s . n=n ; TOPIC JNDI NAME=s u b i e c t ; } public void run ( ) { try { setupJNDI ( ) ; T o p i c C o n n e c t i o n F a c t o r y c f= ( T o p i c C o n n e c t i o n F a c t o r y ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Topic t =( Topic ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( t , Despre JMS+ +i ) ; } p r o d u c e r . send ( t , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }

132
}

CAPITOLUL 5. MESAJE IN JAVA

46

Clasa MsgSubscriberT
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 53 55

import import import import import import import import import import

j a v a x . jms . T o p i c C o n n e c t i o n F a c t o r y ; j a v a x . jms . Topic ; j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . naming . I n i t i a l C o n t e x t ; j a v a x . naming . NamingException ; java . u t i l . Properties ; j a v a . i o . IOException ;

public c l a s s MsgSubscriberT extends Thread { f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ; S t r i n g TOPIC JNDI NAME = t o p i c ; private I n i t i a l C o n t e x t c t x ; private S t r i n g c l i e n t I D ; private S t r i n g c l i e n t N a m e ; MsgSubscriberT ( S t r i n g s u b i e c t , S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) { TOPIC JNDI NAME=s u b i e c t ; t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; } public void run ( ) { try { setupJNDI ( ) ; T o p i c C o n n e c t i o n F a c t o r y c f= ( T o p i c C o n n e c t i o n F a c t o r y ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; Topic t =( Topic ) c t x . l o o k u p (TOPIC JNDI NAME ) ; ; JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; jmsctx . s e t C l i e n t I D ( c l i e n t I D ) ; JMSConsumer consumer = j m s c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; closeJNDI ( ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( c l i e n t N a m e+ r e c e i v e d : + m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S u b s c r i b e r f i n i s h e d ) ; } private void setupJNDI ( ) { . . . } private void c l o s e J N D I ( ) { . . . }

5.3. ELEMENTE DE PROGRAMARE - JMS-2

133

56

5.3.10

Aplicat ie JMS slab cuplat a

Aplicat ia va alc atuit a din trei client i: Client care preia si rezolv a cererile iar r aspunsurile sunt trimise solicitantului ntr-un mesaj pe un subiect indicat de acesta. Acest client preia mesajele corespunz atoare unui subiect public. Client care lanseaz a cererea. Acest client va crea un abonat durabil pe subiectul pe care se va prelua r aspunsul. Subiectul face parte din cerere. Client care preia r aspunsul. Exemplul 5.3.9 Calculul celui mai mare divizor comun a dou a numere naturale. Clasa MsgCmmdcServer
1 2 3 4 5 6 8 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

import import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . jms . JMSProducer ; MsgCmmdcServer {

public c l a s s

public s t a t i c void main ( S t r i n g [ ] a r g s ) { MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ; server . service (); } private void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = c t x . c r e a t e S h a r e d C o n s u m e r ( t , Cmmdc ) ; JMSProducer p r o d u c e r = c t x . c r e a t e P r o d u c e r ( ) ; while ( true ) { Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage tm=(TextMessage ) msg ; S t r i n g s=tm . g e t T e x t ( ) ; S t r i n g [ ] s s=s . s p l i t ( ) ; long m =Long . par se Lon g ( s s [ 0 ] ) ;

134

CAPITOLUL 5. MESAJE IN JAVA

33 34 35 36 37 38 39 40 41 43 44 45 46 47 49 50

long n=Long . p ars eL ong ( s s [ 1 ] ) ; S t r i n g t o p i c=s s [ 2 ] ; long c=cmmdc(m, n ) ; Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c ) ; p r o d u c e r . send ( t1 , ( new Long ( c ) ) . t o S t r i n g ( ) ) ; System . out . p r i n t l n ( S e r v e r s e n t +c+ t o +t o p i c ) ; } } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } private long cmmdc( long m, long n ) { . . . } }

Clasa MsgClientSender
1 2 3 4 5 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 34 35 36 37 38

import import import import import

j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; j a v a x . jms . JMSConsumer ; java . u t i l . Scanner ;

public c l a s s MsgClientSender { private S t r i n g msg , c l i e n t I D , clientName , t o p i c R e s u l t ; MsgClientSender ( S t r i n g c l i e n t I D , S t r i n g clientName ){ t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i m : ) ; long m =s c a n n e r . nextLong ( ) ; S t r i n g sm=new Long (m) . t o S t r i n g ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i n : ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ; System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ; t o p i c R e s u l t=s c a n n e r . n e x t ( ) ; msg=sm+ +sn+ +t o p i c R e s u l t ; } private void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t1 , c l i e n t N a m e ) ; JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ; p r o d u c e r . send ( t , msg ) ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

135

39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55

ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } public s t a t i c void main ( S t r i n g [ ] a r g s ) { i f ( a r g s . l e n g t h < 2) { System . out . p r i n t l n ( Usage : ) ; System . out . p r i n t l n ( j a v a M s g C l i e n t S e n d e r c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } M s g C l i e n t S e n d e r c l i e n t=new M s g C l i e n t S e n d e r ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }

Clasa MsgClientReceiver
1 2 3 4 5 6 8 9 11 12 13 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

import import import import import import

j a v a x . jms . TextMessage ; j a v a x . jms . Message ; j a v a x . jms . Topic ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; java . u t i l . Scanner ;

public c l a s s MsgClientReceiver { private S t r i n g t o p i c R e s u l t , c l i e n t I D , c l i e n t N a m e ; MsgClientReceiver ( S t r i n g c l i e n t I D , S t r i n g clientName ){ t h i s . c l i e n t I D=c l i e n t I D ; t h i s . c l i e n t N a m e=c l i e n t N a m e ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ; t o p i c R e s u l t=s c a n n e r . n e x t ( ) ; } public void s e r v i c e ( ) { try { com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; Topic t=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ; JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ; ctx . setClientID ( c l i e n t I D ) ; JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n ( Cmmdc : + m. g e t T e x t ( ) ) ; break ; } } ctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) {

136

CAPITOLUL 5. MESAJE IN JAVA

40 41 42 44 45 46 47 48 49 50 51 52 53

System . out . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; } } public s t a t i c void main ( S t r i n g [ ] a r g s ) { i f ( a r g s . l e n g t h < 2) { System . out . p r i n t l n ( Usage : ) ; System . out . p r i n t l n ( j a v a MsgSOAPClientReceiver c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } M s g C l i e n t R e c e i v e r c l i e n t=new M s g C l i e n t R e c e i v e r ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }

5.3.11

Programare JMS prin glasssh

Diferent a fat a de versiunile amintite mai sus constau n obiectele administrator, fabrica de conexiuni, obiectul / sursa destinat ie care se creaz a de administratorul glasssh.
1. Se lanseaz a serverul de aplicat ii glasssh set GLASSFISH_HOME=. . .\glassfish3 set PATH=%GLASSFISH_HOME%\bin;%PATH% asadmin start-domain domain1 Lansarea serverului de aplicat ie implic a pornirea serverului JMS. 2. Dintr-un navigator se apeleaz a administratorul http://localhost:4848. 3. Resources JMS Resources Destination Resources Se creaz a c ate un obiect destinat ie cu datele: JNDI Name myQueue myTopic Physical Name myQueue myTopic Resource Type javax.jms.Queue javax.jms.Topic Resources JMS Resources Connection Factories Se creaz a c ate o fabric a de conexiuni cu datele: Pool Name myQueueConnectionFactory, respectiv myTopicConnectionFactory Resource Type javax.jms.QueueConnectionFactory, respectiv javax.jms.TopicConnectionFactory

Aceste obiecte se injecteaz a ntr-o clas a utiliz nd adnotarea javax.annotation. Resource

5.3. ELEMENTE DE PROGRAMARE - JMS-2

137

import javax.annotation.Resource; . . . public class . . . @Resource(lookup="myQueueConnectionFactory") private static QueueConnectionFactory cf; @Resource(lookup="myQueue") private static Queue q; O aplicat ie se arhiveaz a cu jar cu indicarea clasei cu metoda main si se lanseaz a prin intermediul procedurii acoperitoare glassfish\bin\ appclient.bat appclient -client numeArhiva.jar [-targetserver host:3700]

Exemplul 5.3.10 Aplicat ie cu comunicat ie punctual a. Clasa expeditorului


1 2 3 4 5 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

import import import import import

j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSProducer ; javax . annotation . Resource ;

public c l a s s MsgSender { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c Queue q ; private s t a t i c i n t n=3; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ; f o r ( i n t i =0; i <n ; i ++){ p r o d u c e r . send ( q , H e l l o +i ) ; } p r o d u c e r . send ( q , j m s c t x . c r e a t e M e s s a g e ( ) ) ; jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { // System . o u t . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } System . out . p r i n t l n ( Sen de r f i n i s h e d ) ; } }

Clasa unui client sincron

138

CAPITOLUL 5. MESAJE IN JAVA

1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

import import import import import import import

j a v a x . jms . QueueConnectionFactory ; j a v a x . jms . Queue ; j a v a x . jms . JMSContext ; j a v a x . jms . JMSConsumer ; j a v a x . jms . Message ; j a v a x . jms . TextMessage ; javax . annotation . Resource ;

public c l a s s SyncMsgReceiver { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c Queue q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ; JMSConsumer consumer = j m s c t x . createConsumer ( q ) ; Message msg=n u l l ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { i f ( msg instanceof TextMessage ) { TextMessage m=(TextMessage ) msg ; System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } else break ; } jmsctx . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { // System . o u t . p r i n t l n ( JMSException : +e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } System . out . p r i n t l n ( Consumer f i n i s h e d ) ; } }

Intreb ari recapitulative


1. Explicat i caracterul de cuplare slab a al unei aplicat ii bazat pe JMS. 2. Care este rolul furnizorului (provider) JMS? 3. Precizat i si explicat i modelele de comunicat ii cu mesaje n JMS. 4. Precizat i modelele de programare al unui client JMS prezentate n curs. Probleme: StreamMessage

Partea II TEHNOLOGII CU COMUNICAT II PRIN INTERNET

139

Capitolul 6 HyperText Transfer Protocol


Protocolul http- HyperText Transfer Protocol (http) este destinat schimburilor de informat ii n Internet. In vederea schimburilor dintre calculatoare prin Internet, reprezentarea datelor se face utiliz and n principal: eXtensible Markup Language (XML) - subset al limbajului Standard Generalized Markup Language (SGML); JavaScript Object Notation (JSON). HyperText Markup Language (HTML), XHTML, HTML 5 sunt principalele limbaje pentru publicarea informatiilor pe Web. Aceste limbaje deriv a de asemenea din SGML.

6.1

Transact ie http

Protocolul http este de tip client-server: Navigatoarele Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, Opera, Apple Safari sunt aplicat ii client uzuale. Informat iile sunt g azduite / generate de servere Web de c atre site-uri si servicii Web. Exemple de servere Web sunt apache HTTP Server, Microsoft Internet Interchange Server. O categorie aparte - esent ial a pentru platforma Java - este dat a de servere Web container de servlet si Java Server Pages (JSP). Protocolul http este unidirect ional. Transmiterea unui mesaj conform protocolului http const a din 141

142

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

1. stabilirea unei conexiuni c atre un destinatar; 2. expedierea mesajului; 3. nchiderea conexiunii. Acest ciclu de act iuni se nume ste tranzact ie http. Practic, ntr-o aplicat ie Web, expedierea unei cereri de un client c atre un server Web si receptionarea r aspunsului furnizat de server presupun dou a tranzact ii http. Un mesaj de tip cerere difer a de un mesaj de tip r aspuns prin structura unor elemente constitutive. Serverul nu ret ine informat ii ntre dou a tranzact ii http. Acest comportament se exprim a prin terminologia: protocolul http este f ar a stare - stateless. Transmisia datelor se realizeaz a utiliz and de obicei protocolul TCP. Referint ele resurselor se indic a folosind URI / URL. Cererile si r aspunsurile sunt reprezentate ca linii de text separate de caracterul <CR><LF>, av and structura 1. preambul - format dintr-o linie; 2. antete (header ) - 0 sau mai multe atribute (nume:valoare); 3. o linie goal a; 4. corpul mesajului - opt ional. Preambulul unei cereri cont ine: 1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE, OPTIONS}; 2. referint a resursei (URL); 3. Versiunea protocolului http. Preambulul unui r aspuns cont ine: 1. Versiunea protocolului http; 2. codul r aspunsului: num ar natural format din trei cifre cu semnicat iile

6.1. TRANSACT IE HTTP

143

Categoria 1** 2** 3** 4** 5**

Indic a mesaj de informare mesaj de succes redirectare c atre alt URL eroare in mesajul clientului eroare din partea serverului

Categoria este dat a de prima cifr a. 3. String explicit and codul r aspunsului. Un antet (header ) este un atribut, adic a o pereche (nume:valoare). Protocolul http dene ste o palet a larg a de atribute. Exemple de antete sunt date n tabelul urm ator: Antet Semnicat ie Exemplu host Gazda si portul serverului Web localhost:8080 user-agent Navigatorul care a lansat cererea Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2 referer URL-ul cererii http://localhost:8080/apphello/ accept-encoding Tipuri de arhive acceptate gzip,deate,sdch accept-charset Tipuri de codicare acceptate ISO-8859-1,utf-8;q=0.7,*;q=0.3 accept-language Cea mai potrivit a limb a pentru nt elegerea cont inutului en-US,en;q=0.8 content-type Tipul MIME al corpului mesajului http://application/x-www-form-urlencoded content-length Lungimea corpului mesajului 22 Corpul mesajului este reprezentat printr-un text. Dac a cont inutul este imagine, cod binar, etc., atunci acesta este codicat n text. Codul Multipurpose Internet Mail Exchange (MIME) precizeaz a natura cont inutului unei resurse:

144

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

text/plain text/html text/xml image/png image/jpg application/octet-stream application/x-www-form-urlencoded Ne propunem s a punem n evident a mesajele http.

Mesaj cerere http


Dintr-un navigator se va lansa prin intermediul unui document html o cerere c atre un ipotetic servlet dintr-un server Web. Cererea este interceptat a de o clas a Java cu un soclu TCP, ServerSocket, care preia mesajele pe portul serverului Web. Codul clasei Java este
1 2 3 4 5 6 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

import import import import import import import import

java . net . ServerSocket ; java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . io . BufferedWriter ; java . io . FileWriter ;

public c l a s s RequestHTTPMsg { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S o c k e t s o c k e t=n u l l ; try { S e r v e r S o c k e t s e r v e r S o c k e t=new S e r v e r S o c k e t ( 8 0 8 0 ) ; s o c k e t=s e r v e r S o c k e t . a c c e p t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( InputStream i s=s o c k e t . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i s ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; F i l e W r i t e r fw=new F i l e W r i t e r ( ou tp ut . t x t , true ) ; B u f f e r e d W r i t e r bw=new B u f f e r e d W r i t e r ( fw ) ) { for ( ; ; ) { S t r i n g s=br . r e a d L i n e ( ) ; i f ( s==n u l l ) break ; System . out . p r i n t l n ( s ) ; bw . w r i t e ( s ) ; bw . newLine ( ) ; } } catch ( IOException e ) { System . out . p r i n t l n ( I n p u t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;

6.1. TRANSACT IE HTTP

145

36 37 38

} } }

Rezultatul cererii depinde de metoda GET sau POST utilizat a n formularul html folosit. Pentru metoda GET cererea http este
GET /apphello/hello?name=mk&tip=text%2Fhtml HTTP/1.1 Host: localhost:8080 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

iar pentru metoda POST cererea http este


POST /apphello/hello HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 23 Cache-Control: max-age=0 Origin: null User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2 Content-Type: application/x-www-form-urlencoded Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 name=mk&tip=text%2Fhtml

Formularul html utilizat are codul


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

<html> <head>< t i t l e > S e r v l e t u l H e l l o</ t i t l e ></ head> <body> <center> <h1> Pagina de a p e l a r e a s e r v l e t u l u i H e l l o S e r v l e t </ h1> <form method= p o s t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / a p p h e l l o / h e l l o > <p> I n t r o d u c e t i numele : <input type= t e x t name=name s i z e =20> <p> <input type= submit value= A p e l e a z a > <input type= h id de n name= t i p value= t e x t / html > </ form> </ center> </ body> </htm

146

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Mesaj r aspuns http


Un servlet (apphello ) este activ ntr-un server Web. O clas a Java lanseaz a o cerere http c atre acel servlet - chiar unul din mesajele obt inute mai sus dup a care recept ioneaz a r aspunsul dat de servlet. Codul clasei Java
1 2 3 4 5 6 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 42 43 44 45 46 47 48 49 50 51

import import import import import import import import

java . net . Socket ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . io . BufferedWriter ; java . io . FileWriter ; java . io . PrintWriter ; java . u t i l . Scanner ;

public c l a s s ResponseHTTPMsg { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g reqGET=GET / a p p h e l l o / h e l l o ?name=mk&t i p=t e x t%2Fhtml HTTP/ 1 . 1 \ r \ n+ Host : l o c a l h o s t : 8 0 8 0 \ r \ n+ C o n n e c t i o n : keep a l i v e \ r \ n+ User Agent : M o z i l l a / 5 . 0 ( Windows NT 6 . 1 ; WOW64) + AppleWebKit / 5 3 5 . 2 (KHTML, l i k e Gecko ) + Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i / 5 3 5 . 2 \ r \ n+ Accept : t e x t / html , a p p l i c a t i o n / xhtml+xml , a p p l i c a t i o n /xml ; + q = 0 . 9 , / ; q =0.8 \ r \ n+ Accept Encoding : g z i p , d e f l a t e , sdch \ r \ n+ Accept Language : enUS , en ; q =0.8 \ r \ n+ Accept C h a r s e t : ISO 8859 1, u t f 8; q = 0 . 7 , ; q =0.3 \ r \ n ; S t r i n g reqPOST=POST / a p p h e l l o / h e l l o HTTP/ 1 . 1 \ r \ n+ Host : l o c a l h o s t : 8 0 8 0 \ r \ n+ C o n n e c t i o n : keep a l i v e \ r \ n+ Content Length : 23 \ r \ n+ CacheC o n t r o l : maxage =0\ r \ n+ O r i g i n : n u l l \ r \ n+ User Agent : M o z i l l a / 5 . 0 ( Windows NT 6 . 1 ; WOW64) + AppleWebKit / 5 3 5 . 2 (KHTML, l i k e Gecko ) + Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i / 5 3 5 . 2 \ r \ n+ Content Type : a p p l i c a t i o n /xwww form u r l e n c o d e d \ r \ n+ Accept : t e x t / html , a p p l i c a t i o n / xhtml+xml , a p p l i c a t i o n /xml ; + q = 0 . 9 , / ; q =0.8 \ r \ n+ Accept Encoding : g z i p , d e f l a t e , sdch \ r \ n+ Accept Language : enUS , en ; q =0.8 \ r \ n+ Accept C h a r s e t : ISO 8859 1, u t f 8; q = 0 . 7 , ; q =0.3 \ r \ n+ \ r \ n+ name=mk&t i p=t e x t%2Fhtml ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( P r e c i z a t i metoda HTTP : ) ; System . out . p r i n t l n ( 1 : GET; 2 : POST ) ; i n t metoda ; do { metoda=s c a n n e r . n e x t I n t ( ) ; } while ( ( metoda!=1)&&(metoda ! = 2 ) ) ; try ( S o c k e t s o c k e t=new S o c k e t ( l o c a l h o s t , 8 0 8 0 ) ;

6.2. SERVER WEB - CONTAINER DE SERVLET

147

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

InputStreamReader i s r =new InputStreamReader ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; F i l e W r i t e r fw=new F i l e W r i t e r ( ou tp ut . t x t , true ) ; B u f f e r e d W r i t e r bw=new B u f f e r e d W r i t e r ( fw ) ; P r i n t W r i t e r pw=new P r i n t W r i t e r ( s o c k e t . getOutputStream ( ) , true ) ){ switch ( metoda ) { case 1 : // Lansarea u n e i c e r e r i GET pw . p r i n t l n ( reqGET ) ; break ; case 2 : // Lansarea u n e i c e r e r i POST pw . p r i n t l n ( reqPOST ) ; } for ( ; ; ) { S t r i n g s=br . r e a d L i n e ( ) ; i f ( s==n u l l ) break ; System . out . p r i n t l n ( s ) ; bw . w r i t e ( s ) ; bw . newLine ( ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

Indiferent de metoda cererii, mesajul http de r aspuns este


HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/html Content-Length: 119 Date: Sun, 30 Oct 2011 16:35:47 GMT <html> <head><title>HelloServlet</title></head> <body> <h1>HelloServlet</h1> <p> Hi mk ! </p> </body> </html>

6.2

Server Web - container de servlet

In prezent sunt disponibile mai multe servere Web n care poate instalat un servlet si un sier JSP Java Server Pages. Despre un asemenea server Web se spune c a este container de servlet si JSP. Dintre produsele gratuite amintim apache-tomcat

148 jetty glasssh

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Acest server Web este utilizat n Glasssh - o implementare JEE (Java Enterprise Edition) sprijinit de Oracle. jboss application server Geronimo, o alta implementare JEE dezvoltat a de fundat ia apache, poate utiliza containerul apache-tomcat sau jetty. Serverul Apache HTTP Server si Windows Internet Information Server nu sunt servere Web containere de servlet si JSP.

6.3

Serverul Web apache-tomcat

Serverul Web apache-tomcat, (pe scurt tomcat ) este distribuit gratuit si poate desc arcat pornind de la adresa www.apache.org. Instalarea serverului n mediul Windows revine la dezarhivarea sierului desc arcat apache-tomcat-***, ntr-un catalog TOMCAT HOME. Utilizarea serverului necesit a xarea a doi parametri sistem: CATALINA HOME= calea la catalogul n care s-a instalat produsul - TOMCAT HOME; ia Java utilizat a. JAVA HOME=calea la distribut Pachetul cont ine cataloagele1 : bin, common, conf, logs, server, shared, temp, webapps, work. Serverul se lanseaz a prin comanda TOMCAT HOME\bin\startup si se opre ste cu comanda TOMCAT HOME\bin\shutdown Din catalogul TOMCAT HOME, lansarea se poate obt ine cu ajutorul sierului de comenzi (*.bat) set CATALINA_HOME=. . . set JAVA_HOME=. . . bin\startup
1

Numele si num arul cataloagelor este dependent de distribut ia apache-tomcat.

6.3. SERVERUL WEB APACHE-TOMCAT

149

Opt ional se poate instala / activa managerul / administatorul serverului Web tomcat. Vericarea funct ion arii serverului Web tomcat se face apel and dintr-un navigator pagina http://host:port unde host este numele calculatorului pe care ruleaz a tomcat; Portul implicit este 8080. Reu sita este ilustrat a de imaginea motanului

Toate aplicat iile se depun n catalogul TOMCAT HOME\webapps. Asem an ator se procedeaz a si n cazul serverului Web jetty. Nu este nevoie de nici o congurare suplimentar a, lansarea f ac andu-se prin cd . . .\jetty-hightide-* java -jar start.jar Din nou aplicat iile se depun n catalogul \jetty-hightide-8.0.*\webapps.

Secure Socket Layer n tomcat


Transmisia utiliz and Secure Socket Layer - SSL (mai nou Transport Layer Security - TLS) nseamn a criptarea datelor care circul a ntre client si server. Realizarea presupune 1. Generarea unui certicat de securitate cu utilitarul keytool din distribut ia Java, de exemplu
keytool -genkey -alias tomcat -keyalg RSA -keystore {cale}/tomcatKeystore -dname "cn=SE, ou=cs, o=unitbv, l=brasov, c=RO" -keypass 1q2w3e -storepass 1q2w3e

Parametrul keystore xeaz a locat ia si denumirea sierului certicatului de securitate. Se denesc dou a parole keypass parola certicatului de securitate;

150

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

storepass parola de protect ie a locat iei certicatului de securitate. Parametrul cale desemneaz a calea c atre catalogul unde n care se creaz a sierul tomcatKeystore - certicatul de securitate. Uzual, certicatul de securitate se mut a n catalogul TOMCAT HOME\conf. 2. Modicarea sierului apache-tomcat-*\conf\server.xml Se decomenteaz a elementul
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />

Acest element Connector se completeaz a cu atributele


keystoreFile="conf\tomcatKeystore" keystorePass="1q2w3e"

3. Serverul Web se apeleaz a prin


https://localhost:8443

6.4

Glasssh

Instalarea si lansarea serverului. Instalarea const a din dezarhivarea arhivei desc arcate. Este recomandat includerea n sierul GLASSFISH HOME\grassfish\config\ asenv.bat a liniei set AS_JAVA=c:\Progra~1\Java\jdk1.* Utilizarea paginilor JSP necesit a aceast a setare. Prin intermediul paginii de administrare se poate schimba parola administratorului (admin ). Containerele n care se depun aplicat iile se a a ntr-un domeniu. Implicit, n catalogul glasssh\domain se creaz a domeniul cu numele domain1: GLASSFISH HOME\glassfish\domains\domain1. Lansarea serverului se poate face prin: a Din GLASSFISH HOME\glassfish\bin se comand asadmin start-domain domain1 Oprirea serverului se poate face prin:

6.4. GLASSFISH

151 asadmin stop-domain domain1

Administrarea serverului se face prin pagina Web http://localhost:4848 utilitarul GLASSFISH HOME\bin\asadmin.bat Administratorul serverului are posibilitatea s a creeze domenii noi: Astfel crearea unui domeniu nou, av and numele numeDomeniu, situat n catalogul dirDomeniu se obt ine prin asadmin create-domain --adminport 4848 --domaindir dirDomeniu numeDomeniu S tergerea domeniului se obt ine prin asadmin delete-domain --domaindir dirDomeniu numeDomeniu Lansarea si oprirea serverului glasssh se comand a prin asadmin start-domain --domaindir dirDomeniu numeDomeniu asadmin stop-domain --domaindir dirDomeniu numeDomeniu

152

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Capitolul 7 Applet - Miniaplicat ie Java


O categorie deosebit a de programe Java l reprezint a miniaplicat iile (applet -uri), care se execut a prin intermediul unui program de navigare n WWW (World Wide Web) browser (Mozilla Firefox, Google Chrome, Microsoft InternetExplorer, Opera, Apple Safari. La aparit ia limbajului de programare Java, acest tip de aplicat ie a reprezentat unul din factorii de impact prin noutatea si simplitatea solut iei oferite. Applet-ul este o resurs a program, depus a ntr-o zona public a, accesibil a prin Internet (server Web.) Un program de navigare preia codul applet-ului si l execut a. Apelarea unui applet se face dintr-un sier html. O aplicat ie applet nu este o aplicat ie de tip client server dar este prin modul de utilizare este o aplicat ie distribuit a. Datorit a acestui mod de folosire, applet-urile au o structur a special a si sunt supuse la reguli stricte de securitate, printre care acela de a nu putea scrie informat ii pe calculatorul pe care se execut a - calculatorul clientului. Metoda actual a de apelare a unui applet se face prin intermediul unei resurse Deployment Toolkit (DT) - o bibliotec a de funct ii javascript. Resursa DT este apelabil a la adresa http://java.com/js/deployJava.js sau http://www.java.com/js/deployJava.js DT utilizeaz a protocolul Java Network Launching Protocol (jnlp) si evit a problemele de compatibilitate cu programul navigator. Aceast a resurs a realizeaz a desc arcarea applet-ului c at si lansarea n execut ie. Pe calculatorul client, adic a pe care ruleaz a applet-ul, trebuie s a e instalat jre - Java Runtime Environment - versiunea pe 32 bit i. Programarea unui applet se face prin extinderea clasei java.applet.Applet sau javax.swing.JApplet. Clasa Applet extinde clasa java.awt.Panel iar clasa JApplet extinde clasa Applet. 153

154

CAPITOLUL 7. APPLET - MINIAPLICAT IE JAVA

Interfat a grac a, n cazul extinderii clasei Applet, va utiliza controlurile apart in and interfet ei de programare AWT (Abstract Window Toolkit ), iar n cazul extinderii clasei JApplet se vor utiliza controluri JavaFX / Swing.

7.1

Clasa Applet

Structura unui applet este import java.applet.*; import java.awt.*; public classNumeClas a extends Applet{ public void init(){ Act iuni efectuate la instant ierea clasei applet-ului. } public void start(){ Act iuni efectuate la lansarea applet-ului n execut ie sau la re ntoarcerea n pagina applet-ului. } public void paint(Graphics g){ Act iuni efectuate ori de c ate ori este necesar a redesenarea ferestrei applet-ului. } public void stop(){ Act iuni efectuate la oprirea applet-ului, ca urmare a nchiderii ferestrei corespunz atoare applet-ului. } public void destroy(){ Act iuni efectuate la distrugerea applet-ului, ce au loc c and navigatorul p ar ase ste documentul html din care s-a apelat applet-ul. } } Executarea applet-ului este controlat de programul navigator si revine la apelarea metodelor init, start, stop. Acest fenomen se nume ste inversarea controlului.

URAREA UNUI APPLET 7.2. DESFAS

155

7.2

Desf a surarea unui applet

Prin desf a surarea (deployment) unei aplicat ii se nt elege realizarea structurilor de cataloage si siere dar si a operat iilor care trebuie ntreprinse n vederea funct ion arii unei aplicat ii distribuite. Desf a surarea unui applet se poate face n mai multe feluri: Varianta 1 1. Arhivarea sierelor class ale applet-ului. 2. Certicarea arhivei jar se realizeaz a rul and succesiv (a) (b) (c)
keytool -genkey -keystore myKeystore -alias myself -dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO" -keypass abc123 -storepass 123abc keytool -selfcert -alias myself -keystore myKeystore -keypass abc123 -storepass 123abc jarsigner -keystore myKeystore -keypass abc123 -storepass 123abc resursa.jar myself

keytool.exe si jarsigner.exe se g asesc n distribut ia jdk. Primele dou a act iuni au ca rezultat obt inerea certicatului myKeystore iar ultima act iune reprezint a nglobarea certic arii n arhiva resursa.jar. 3. Editarea sierului html de apelare a applet-ului. S ablonul specic apel arii applet-ului este
<BODY> . . . <script src="http://java.com/js/deployJava.js"></script> <script> var attributes={ code:numele_clasei_Applet, archive:numele_arhivei_jar,width:...,height:...}; var parameters={. . .}; var minimumVersion=1.6; deployJava.runApplet(attributes, parameters, minimumVersion); </script> . . . </BODY>

4. Cele dou a siere (arhiva jar, sierul html) se depun ntr-un catalog al unui server Web, asigur and vizibilitatea aplicat iei n Internet.

156

CAPITOLUL 7. APPLET - MINIAPLICAT IE JAVA

Vericarea aplicat iei se poate face, dintr-un program navigator, prin simpla apelare a sierului html. In acest caz, calculatorul trebuie s a e conectat la internet. Dac a dispunem de deployJava.js atunci acest sier se al atur a celorlalte dou a resurse, iar atributul src al elementului script va src="deployJava.js". Exemplul 7.2.1 Hello +nume. Numele se transmite miniaplicat iei ca parametru. Codul applet-ului este:
1 2 4 5 7 8 9 10 11

import j a v a . awt . ; import j a v a . a p p l e t . ; public c l a s s I n c e p u t extends Applet { public void i n i t ( ) { } public void p a i n t ( G r a p h i c s g ) { S t r i n g name=g e t P a r a m e t e r ( nume ) ; g . d r a w S t r i n g ( H e l l o +name+ ! ! , 5 0 , 60 ) ; } }

Fi sierul html de apelare (inceput.html )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

< ! doctype html> <head> <meta charset= u t f 8> </ head> <body> < s c r i p t src= h t t p : / / j a v a . com/ j s / d e p l o y J a v a . j s ></ s c r i p t> < s c r i p t> v a r a t t r i b u t e s = { code : I n c e p u t . c l a s s , a r c h i v e : i n c e p u t . j a r , width : 3 0 0 , h e i g h t : 3 0 0 } ; v a r p a r a m e t e r s={nume : XYZ } ; v a r minimumVersion = 1 . 6 . 0 ; d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , minimumVersion ) ; </ s c r i p t> </ body> </ html>

Varianta 2 Pe aceast a cale se va edita un sier de congurare cu extensia jnlp. Realizarea applet-ului const a din: 1. Arhivarea sierelor class ale applet-ului. 2. Certicarea arhivei jar. 3. Editarea unui sier de congurare jnlp. Structura acestui sier este

URAREA UNUI APPLET 7.2. DESFAS

157

<?xml version="1.0" encoding="UTF-8"?> <jnlp spec="1.0+" codebase="http://host:port/cale_applet" href=""> <information> <title>. . .</title> <vendor>. . .</vendor> </information> <resources> <!-- Application Resources --> <j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se" max-heap-size="128m" /> <jar href="numele_arhivei_jar" main="true" /> </resources> <security> <all-permissions/> </security> <applet-desc name="numele_simbolic_al_applet-ului" main-class="clasa_principala_a_applet-ului" width="latimea_ferestrei_applet-ului" height="inaltimea_ferestrei_applet-ului"> </applet-desc> </jnlp> 4. Editarea sierului html de apelare a applet-ului. S ablonul specic apel arii applet-ului este
<BODY> . . . <script src="http://java.com/js/deployJava.js"></script> <script> var attributes={code:numele_arhivei_jar,width:...,height:...}; var parameters={jnlp_href: cmmdc.jnlp}; var minimumVersion=1.6; deployJava.runApplet(attributes, parameters, minimumVersion); </script> . . . </BODY>

158

CAPITOLUL 7. APPLET - MINIAPLICAT IE JAVA

5. Cele trei siere (eventual patru cu deployJava.js ) se depun ntr-un catalog al unui server Web, asigur and vizibilitatea aplicat iei n Internet. Exemplul 7.2.2 Calculul celui mai mare divizor comun a dou a naturale. Introducerea datelor exterioare se face prin intermediul unei interfet e grace. Applet-ul extinz and clasa Applet are codul
1 2 3 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32 33 34 35 37 38 39 41 42

import j a v a . awt . ; import j a v a . a p p l e t . ; import j a v a . awt . e v e n t . ; public c l a s s VisualCmmdc extends Applet implements A c t i o n L i s t e n e r { T e x t F i e l d tm , tn , r e z ; public void i n i t ( ) { setBackground ( Color . yellow ) ; GridLayout g l=new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ; setLayout ( g l ) ; L a b e l lm=new L a b e l ( Primul numar : ) ; add ( lm ) ; tm=new T e x t F i e l d ( 1 , 5 ) ; add ( tm ) ; L a b e l l n=new L a b e l ( Al d o i l e a numar : ) ; add ( l n ) ; tn=new T e x t F i e l d ( 1 , 5 ) ; add ( tn ) ; Button compute=new Button ( C a l c u l e a z a ) ; compute . a d d A c t i o n L i s t e n e r ( t h i s ) ; add ( compute ) ; r e z=new T e x t F i e l d ( 1 , 5 ) ; rez . setEditable ( false ) ; add ( r e z ) ; } public void p a i n t ( G r a p h i c s g ) { S t r i n g sm=tm . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; S t r i n g sn=tn . g e t T e x t ( ) ; long n=Long . p ars eL ong ( sn ) ; long c=cmmdc(m, n ) ; r e z . s e t T e x t ( ( new Long ( c ) ) . t o S t r i n g ( ) ) ; } public void a c t i o n P e r f o r m e d ( ActionEvent ae ) { repaint ( ) ; } long cmmdc( long m, long n ) { . . . } }

iar n cazul extinderii clasei JApplet (cu elemente grace JavaFX)


1 2 3 4 5

import import import import import

j a v a . awt . C o n t a i n e r ; j a v a x . swing . JApplet ; j a v a f x . embed . swing . JFXPanel ; j av a fx . a p p l i c a t i o n . Platform ; j a v a f x . scene . c o n t r o l . Label ;

URAREA UNUI APPLET 7.2. DESFAS

159

6 7 8 9 10 11 12 13 15 16 18 19 20 21 22 23 24 25 26 27 28 29 31 32 33 34 35 37 38 39 40 42 43 44 45 47 48 49 50 51 52 53 54 55 56 57 58 59 61 62 63 64

import import import import import import import import

javafx javafx javafx javafx javafx javafx javafx javafx

. scene . control . TextField ; . s c e n e . c o n t r o l . Button ; . scene . paint . Color ; . e v e n t . ActionEvent ; . e v e n t . EventHandler ; . s c e n e . Group ; . s c e n e . Scene ; . s c e n e . l a y o u t . GridPane ;

public c l a s s VisualCmmdc extends JApplet { s t a t i c private T e x t F i e l d tm , tn , r e z ; public void i n i t ( ) { C o n t a i n e r c o n t e n t = getContentPane ( ) ; f i n a l JFXPanel f x P a n e l = new JFXPanel ( ) ; c o n t e n t . add ( f x P a n e l ) ; c o n t e n t . s e t V i s i b l e ( true ) ; P l a t f o r m . r u n L a t e r ( new Runnable ( ) { @Override public void run ( ) { initFX ( fxPanel ) ; } }); } private s t a t i c void i n i t F X ( JFXPanel f x P a n e l ) { Group r o o t = new Group ( ) ; Scene s c e n e = new Scene ( r o o t , 6 0 0 , 2 5 0 , C o l o r .LIGHTGREEN ) ; fxPanel . setScene ( scene ) ; GridPane g r i d P a n e = new GridPane ( ) ; L a b e l mLabel = new L a b e l ( Primul numar ) ; g r i d P a n e . add ( mLabel , 1 , 1 ) ; // column=1 row=1 tm=new T e x t F i e l d ( ) ; g r i d P a n e . add ( tm , 2 , 1 ) ; L a b e l nLabel = new L a b e l ( Al d o i l e a numar ) ; g r i d P a n e . add ( nLabel , 1 , 2 ) ; // column=1 row=1 tn=new T e x t F i e l d ( ) ; g r i d P a n e . add ( tn , 2 , 2 ) ; Button b ut to n = new Button ( C a l c u l e a z a ) ; bu tt on . se tO nA ct ion ( new EventHandler <ActionEvent > () { @Override public void h a n d l e ( ActionEvent e ) { S t r i n g sm = tm . g e t T e x t ( ) ; S t r i n g sn = tn . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; long n=Long . pa rs eL ong ( sn ) ; long r=cmmdc(m, n ) ; r e z . s e t T e x t ( ( new Long ( r ) ) . t o S t r i n g ( ) ) ; } }); g r i d P a n e . add ( button , 1 , 3 ) ; r e z = new T e x t F i e l d ( ) ; g r i d P a n e . add ( r e z , 2 , 3 ) ; r o o t . g e t C h i l d r e n ( ) . add ( g r i d P a n e ) ; fxPanel . setScene ( scene ) ;

160
}

CAPITOLUL 7. APPLET - MINIAPLICAT IE JAVA

65 67 68

s t a t i c long cmmdc( long m, long n ) { . . . } }

Fi sierul de congurare jnlp (cmmdc.jnlp ) este


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < j n l p s p e c= 1.0+ c o d e b a s e= h r e f= > < i n f o r m a t i o n> < t i t l e > V i s u a l Cmmdc</ t i t l e > < vendor> T r a n s i l v a n i a U n i v e r s i t y o f Brasov</ vendor> </ i n f o r m a t i o n> < r e s o u r c e s> < ! A p p l i c a t i o n R e s o u r c e s > < j 2 s e version= 1.6+ h r e f= h t t p : // j a v a . sun . com/ p r o d u c t s / a u t o d l / j 2 s e maxheap s i z e= 128m /> < j a r h r e f=cmmdc . j a r main= t r u e /> </ r e s o u r c e s> < r e s o u r c e s o s=Windows> < j f x : j a v a f x r u n t i m e version= 2.0+ h r e f= h t t p : // j a v a d l . sun . com/ webapps / download / G e t F i l e / j a v a f x l a t e s t / windows i 5 8 6 / j a v a f x 2 . j n l p /> </ r e s o u r c e s> < s e c u r i t y> < a l l p e r m i s s i o n s /> </ s e c u r i t y > < a p p l e t d e s c name=VisualCmmdc Applet main c l a s s=VisualCmmdc width= 300 h e i g h t= 300 > </ a p p l e t d e s c> </ j n l p>

iar apelarea se face din (VisualCmmdc.html )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

< ! d o c t y p e html> <head> <meta c h a r s e t= u t f 8> < l i n k r e l= s t y l e s h e e t h r e f= mycss . c s s > </ head> <body> < c e n t e r> <h1> Cel mai mare d i v i z o r comun </ h1> < s c r i p t s r c= h t t p : // j a v a . com/ j s / d e p l o y J a v a . j s ></ s c r i p t > < s c r i p t> v a r a t t r i b u t e s = { c o d e : cmmdc , w i d t h : 3 0 0 , h e i g h t : 3 0 0 } ; v a r p a r a m e t e r s = { j n l p h r e f : cmmdc . j n l p } ; v a r minimumVersion= 1 . 6 ; d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , minimumVersion ) ; </ s c r i p t > </ c e n t e r> </ body> </ html>

7.3. COMUNICARE JAVA - JAVASCRIPT INTR-UN APPLET

161

7.3

Comunicare Java - JavaScript ntr-un applet

Se pot apela funct ii JavaScript denite n documentul html din care se apeleaz a applet-ul. Prin intermediul unui obiect de tip netscape.javascript.JSObject, creat prin static JSObject getWindow(java.applet.Applet applet ) se apeleaz a metoda call(String numeFunct ieJavaScript, java.lang.Object[] args ). S ablonul de utilizare este import netscape.javascript.*; public void init(){ . . . JSObject window=JSObject.getWindow(null); window.call("numeFunctieJavaScript",args); . . . } Pachetul netscape.javascript se a a n distribut ia jdk n catalogul JAVA HOME\ jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie s a cont in a aceast a referint a .

162

CAPITOLUL 7. APPLET - MINIAPLICAT IE JAVA

Capitolul 8 Conexiune simpl a prin clase din java.net


Pachetul java.net ofer a, prin intermediul claselor URL, URLConnection, HttpURLConnection, HttpsURLConnection, JarURLConnection o posibilitate elementar a de acces a unor resurse din Internet.

8.1

Clasa java.net.URL

Clasa java.net.URL permite realizarea unei conexiuni cu un server Web1 potrivit protocolurilor http, https, ftp, le, jar. Constructori URL(String spec ) throws MalformedURLException Creaz a un obiect URL legat de resursa specicat a de spec, care trebuie s a e o referint a URL valid a. Metode InputStream openStream() throws IOException Returneaz a uxul de intrare pentru citirea resursei. URLConnection openConnection() throws IOException Returneaz a o instant a a conexiunii cu obiectul denit de URL.
1

apache-tomcat, apache, Micrsoft IIS (Internet Information Services), etc.

163

164

PRIN CLASE DIN JAVA.NET CAPITOLUL 8. CONEXIUNE SIMPLA

Exemplul 8.1.1 Pe baza referint ei c atre un sier html dintr-un catalog vizibil al unui server Web, s a se a seze cont inutul sierului. In codul reprodus mai jos, sierul Hello.html se a a pe serverul apachetomcat, n catalogul webapps\url.
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

im po rt im po rt im po rt im po rt

j a v a . n e t .URL; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ;

p u b l i c c l a s s ReadHTTP{ p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { S t r i n g adr= h t t p : // l o c a l h o s t : 8 0 8 0 / u r l / H e l l o . html ; // System . s e t P r o p e r t y ( h t t p . proxyHost , 1 0 . 3 . 5 . 1 3 3 ) ; // System . s e t P r o p e r t y ( h t t p . pr o x y P o r t , 3128 ) ; URL u r l=n u l l ; try { u r l=new URL( adr ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( InputStream i n=u r l . openStream ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; ){ String s ; do { s=br . r e a d L i n e ( ) ; i f ( s != n u l l ) System . out . p r i n t l n ( s ) ; } w h i l e ( s != n u l l ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }

In cazul n care resursa - n exemplul dat reprezentat de sierul Hello.html - este accesibil doar n urma autentic arii basic sau digest (Cap. Servlet, Autenticare, 9.5.5) atunci codul de mai sus trebuie completat cu
final String username = "digest"; final String password = "digest"; Authenticator.setDefault(new Authenticator(){ @Override protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(username,password.toCharArray()); } });

Un exemplu privind utilizarea clasei java.net.HttpURLConnection este dat n capitolul Servlet.

Capitolul 9 Servlet
Printre aplicat iile distribuite de tip client-server, n care comunicat iile se bazeaz a pe protocolul http, se disting: Aplicat ii Web (site): Cererea adresat a serverului este lansat a uzual de o persoan a utiliz and un program navigator: Google Chrome, Mozilla Firefox, Microsoft InternetExplorer, Opera, Apple Safari, etc. Servicii Web: Cererea c atre server se face de un program. Aplicat ia server si client se programeaz a utiliz and interfet e de programare specice. Un servlet este un program Java care se excut a pe un server Web, compatibil; gestionat de serverul Web; capabil s a recept ioneze si s a r apund a cererilor formulate de client i. De asemenea vom utiliza termenul servlet si pentru aplicat ia Web corespunz atoare. Pe platforma de programare Java, servlet-ul este componenta care st a la baza majorit a tii cadrelor de dezvoltare (framework ) pentru aplicat ii si servicii Web. Programarea si utilizarea unui servlet necesit a: Cunoa sterea marcajului html <form> pentru realizarea formularelor de introducere a datelor; Utilizarea unui server Web, container de servlet i. 165

166

CAPITOLUL 9. SERVLET

9.1

Marcajul <form>

Intr-un document html introducerea datelor se poate obt ine utiliz and marcajul <form> ...</form> . Atribute ale marcajului <form> . Reamintim c a atributele se prezint a ca perechi (nume, valoare) si se scriu n antetul marcajului sub forma nume = valoare. Nume action method Valoare adresa tip URL GET Semnicat ia valorii Resursa care prelucreaz a formularul. Mesajul trimis serverului Web cont ine dup a adresa URL numele si valorile parametrilor introdu si. Ad augarea se face potrivit sintaxei ?numeParam1=valoare&numeParam2=valoare. . . Lungimea mesajului nu poate dep a si 255 caractere. Transmisia datelor se face n uxuri de date. Permite transferul unor siere de pe ma sina clientului pe ma sina serverului. Parametru de identicare a formularului (opt ional). Nume atribuit formularului (opt ional). Metod a JavaScript executat a naintea apel arii serverului Web (opt ional).

POST

id name onSubmit

In cont inutul marcajului <form> putem include elemente de control prin marcajele <input> <option> <select> <textarea> Atributele marcajului < input> sunt:

9.2. REALIZAREA UNUI SERVLET

167

Nume type

Valoare Semnicat ie text Se a steapt a introducerea unui text password Se a steapt a introducerea unei parole submit Se marcheaz a sf ar situl complet arii formularului reset Se reinit ializeaz a formularul file Permite selectarea unui sier hidden Transmite mai departe un atribut f ar a vizualizarea lui name numele controlului value valoarea (init ial a) a controlului size num arul caracterelor ata sat controlului In cazul marcajului < select> utilizarea este <select name="nume"> <option value="valoare"> Valoare . . . . . . . . . . . . . . . . </select> Valoarea atributului nume este dat a de valoarea selectat a.

9.2

Realizarea unui servlet

Interfat a de programare (API) pentru servlet nu face parte din JDK, ind implementat de ecare produc ator de server Web container de servlet. Structura minimal a a unui servlet este catalogAppServlet |--> WEB-INF | |--> classes | | | *.class | |--> lib | | | *.jar | index.html Catalogul classes cont ine sierele class ale aplicat iei servlet. Catalogul lib este opt ional si va cont ine resursele jar suplimentare cerute de clasele servlet-ului. Prin intermediul sierului index.html se apeleaz a aplicat ia servlet. Adresa de apelare (URL - Universal Resource Locator ) a aplicat iei servlet este http://host:port/catalogAppServlet

168

CAPITOLUL 9. SERVLET

Dac a n loc de index sierul html de apelare are alt nume, de exemplu xyz.html atunci adresa de apelare va http://host:port/catalogAppServlet/xyz.html host este numele calculatorului pe care ruleaz a serverul Web - gazda aplicat iei servlet. Portul implicit utilizat de un server Web container de servlet este 8080. Catalogul aplicat iei este denumit context -ul servlet-ului. Apelarea servlet-ului se poate face: din meniul File/Open al unui navigator; ca referint a ntr-un document html <a href="URL-servlet ">...</a> Din documentul html pomenit anterior, apelarea clasei servlet se face uzual prin intermediul atributului action a elementului form. Valoarea atributului este numele de apel al servlet-ului. Prin Asynchronous JavaScript And Xml - AJAX un servlet se poate apela dintr-o funct ie Javascript. Leg atura cu clasa servlet-ului se poate realiza programat prin adnot ari n codul servlet-ului; descriptiv n catalogul WEB-INF se editeaz a sierul web.xml. In versiunile anterioare ale interfet ei de programare servlet aceasta a fost unica opt iune. Trebuie demarcat a diferent a dintre apelarea / lansarea n execut ie a clasei servlet de apelarea aplicat iei Web. Modul programat se bazeaz a pe adnotarea javax.servlet.annotation. WebServlet cu elementele: String name String[ ] urlPatterns @WebInitParams[ ] initParams boolean asyncSupported long asyncTimeout Modul descriptiv In sierul web.xml apar elementele

9.2. REALIZAREA UNUI SERVLET

169

1. <servlet> leag a numele servlet-ului denit n elementul <servlet-name> de clasa servlet-ului dat n elementul <servlet-class> . 2. <servlet-mapping> dene ste numele sub care servlet-ul identicat prin <servlet-name>nume servlet < /servlet-name> se invoc a din programul navigator. Acest identicator - numeApel - se xeaz a n elementul <url-pattern> . Identicatorul are ca prex caracterul / (slash). Structura unui sier web.xml este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e > < s e r v l e t> < s e r v l e t name> n u m e s e r v l e t 1</ s e r v l e t name> < s e r v l e t c l a s s >Nume clasa</ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t> < s e r v l e t name> n u m e s e r v l e t 2</ s e r v l e t name> < s e r v l e t c l a s s >Nume clasa</ s e r v l e t c l a s s > </ s e r v l e t > . . . < s e r v l e t mapping> < s e r v l e t name> n u m e s e r v l e t 1</ s e r v l e t name> < u r l p a t t e r n>/ numeApel 1</ u r l p a t t e r n> </ s e r v l e t mapping> < s e r v l e t mapping> < s e r v l e t name> n u m e s e r v l e t 2</ s e r v l e t name> < u r l p a t t e r n>/ numeApel 2</ u r l p a t t e r n> </ s e r v l e t mapping> . . . </webapp>

Unui element <servlet> i pot corespunde mai multe elemente <servlet-mapping>, prin utilizarea de numeApel diferite. Opt ional web.xml poate cont ine elementul
<welcome-file-list> <welcome-file> fisier.html sau jsp </welcome-file> </welcome-file-list>

cu precizarea sierelor html sau jsp care apeleaz a aplicat ia Web. Declarat ia sierului index.html este implicit a. Compilarea clasei servlet necesit a completarea variabilei de mediu classpath cu sierul TOMCAT HOME\lib\servlet-api.jar. Odat a completat a structura de cataloage si siere ale aplicat iei servlet aceast a structur a trebuie copiat a n catalogul TOMCAT HOME\webapps. Aceast a operat ie se nume ste desf a surarea (deployment ) sau instalarea servlet-ului. Copierea se poate executa si cu serverul Web pornit. Pentru instalarea unui servlet exist a mai multe alternative:

170

CAPITOLUL 9. SERVLET

Din catalogul catalogAppServlet se realizeaz a arhiva catalogAppServlet.war jar cfv catAppServlet.war WEB-INF\ index.html care se copiaz a n catalogul TOMCAT HOME\webapps. Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este instalat. Aceast a instalare se nume ste instalare dinamic a - hot deployment. Dac a sierul war este creat, atunci n locul copierii, instalarea se poate face prin componenta manager a lui tomcat. O aplicat ie servlet arhivat a war se poate instala de la distat a prin produsele: apache-tomcat-deployer cargo

9.2.1

Codul unui servlet

Un servlet implementeaz a interfat a Servlet sau extinde una din clasele GenericServlet sau HttpServlet. GenericServlet implementeaz a interfat a Servlet, iar HttpServlet extinde clasa GenericServlet. Extinz and clasa GenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte ale interfet ei Servlet. Metodele interfet ei Servlet sunt: abstract public void init(ServletConfig cong ) Se apeleaz a o singur a dat a la lansarea servlet-ului. abstract public void service(ServletRequest req, ServletResponse res )throws ServletException,IOException Metoda este apelat a de serverul Web pentru rezolvarea cererii unui client. abstract public void destroy() Se apeleaz a o singur a dat a la distrugerea servlet-ului. public String getServletInfo() public ServletConfig getServletConfig()

9.2. REALIZAREA UNUI SERVLET

171

In cele ce urmeaz a o clasa servlet va o clas a care extinde clasa HttpServlet. In locul metodei service(...), programatorul suprascrie metodele doGet(...) sau doPost(...), n funct ie de metoda utilizat a de client la lansarea cererii. Practic, un servlet const a din scrierea metodelor void init(ServletConfig cong ) Aceast a metod a este opt ional a. public void init(ServletConfig config) throws ServletException{ super.init(config); // cod de initializare } Obiectul cong are o metod a String getInitParameter(String numeParam ) cu ajutorul c areia se pot recupera parametri de initializare asociat i servlet-ului si care se dau e prin adnotarea WebInitParam prin sablonul import javax.servlet.annotation.WebInitParam; @WebServlet(urlPatterns = "/numeApel", initParams = { @WebInitParam(name = "numeParam", value = "valoareParam"), . . . } ) e n sierul web.xml prin elementele <init-param> <param-name> NumeleParametrului </param-name> <param-value> Valoare </param-value> </init-param> cuprinse n elementul <servlet>. protected void doGet(HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException Trateaz a o cerere trimis a cu metoda GET (vezi marcajul <form>).

172

CAPITOLUL 9. SERVLET

protected void doPost(HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException Trateaz a o cerere trimis a cu metoda POST (vezi marcajul <form>). Activit a tile de ntreprins ntr-o metod a doGet() sau doPost() sunt 1. Stabilirea naturii r aspunsului: res.setContentType(String tip ) unde tip specic a tipul MIME - Multipurpose Internet Mail Extensions al r aspunsului: "text/html" - pagin a html; "text/xml" - document xml; "text/plain" - text; "image/jpg" - imagine jpg; "image/gif" - imagine gif. 2. Se obt ine o referint a c atre un obiect care realizeaz a transmisia datelor c atre navigatorul clientului: ServletOutputStream out = res.getOutputStream(); sau PrintWriter out=res.getWriter(); 3. Se preiau datele cererii cu una din metodele interfet ei HttpServletRequest: String getParameter(String numeParametru ) java.util.Enumeration getParameterNames() Adit ional se pot aa calculatorul cu serverul web: getServerName(); portul: getServerPort(); catalogul servlet-ului: getContextPath(). 4. Rezolv a cererea clientului; 5. Formeaz a si scrie r aspunsul; 6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor c atre navigatorul clientului prin out.close().

9.2. REALIZAREA UNUI SERVLET

173

Un c amp (global) declarat n clasa servletului este comun ec arei instant e a servletului. Un utilizator lanseaz a o cerere c atre servlet. De obicei acest lucru se realizeaz a prin completarea unui formular al unui document html. Programul navigator trimite cererea serverului Web prin intermediul c aruia este lansat servlet-ul n act iune. Ciclul de viat a al unui servlet. C and un servlet este apelat prima dat a de c atre serverul Web se execut a metoda init. Dup a aceasta, ec arei cereri lansate de un utilizator i se asociaz a un r de execut ie n care se apeleaz a metoda service. Metoda service apeleaz a apoi metodele doGet(), doPost(). Exemplul 9.2.1 Servlet-ul Hello: Clientul transmite numele servlet-ului care i r aspunde cu mesajul de salut Hi + nume!. Formularul html prin care clientul introduce numele este (index.html )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Pagina de a p e l a r e a s e r v l e t u l u i H e l l o S e r v l e t </ h1> <form method= p o s t action= h e l l o > <table> < tr> <td>< l a b e l> I n t r o d u c e t i numele </ l a b e l></ td> <td> <input type= t e x t name=name s i z e= 20 > </ td> </ tr> < tr> <td> <input type= submit value= C a l c u l e a z a > </ td> </ tr> </ table> <input type= h id de n name= t i p value= t e x t / html > </ form> </ center> </ body> </ html>

In modul programat servlet-ului are codul


1 2 3 4

import import import import

j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ;

174

CAPITOLUL 9. SERVLET

5 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32

import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / h e l l o ) public c l a s s H e l l o S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g nume=r e q . g e t P a r a m e t e r ( name ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e > H e l l o S e r v l e t </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1> H e l l o S e r v l e t </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( Hi + nume+ ! ) ; out . p r i n t l n ( </p> ) ; out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

In modul descriptiv, n locul liniilor de cod 7-9 va folosit sierul web.xml


1 2 3 4 5 6 7 9 10 11 12 13

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e > < s e r v l e t> < s e r v l e t name> h e l l o </ s e r v l e t name> < s e r v l e t c l a s s > H e l l o S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> h e l l o </ s e r v l e t name> < u r l p a t t e r n>/ h e l l o </ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>

Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaz a structura:
hello | |---> src | | | HelloServlet.java | |---> web | | |---> WEB-INF | | | |---> classes | | | |---> lib | | | | web.xml | | | index.html | build.xml

9.2. REALIZAREA UNUI SERVLET

175

si se utilizeaz a sierul build.xml


1 2 3 4 6 7 8 9 10 11 13 14 15 16 17 18 20 21 22 23 24 25 27 28 29 30

< p r o j e c t b a s e d i r= . default= g e n e r a t e . war > < p r o p e r t y name=TOMCAT HOME v a l u e= . . . /> < p r o p e r t y name= d i s t . name v a l u e= a p p h e l l o P /> < p r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r=web/WEB INF/ l i b > < i n c l u d e name= . j a r /> </ f i l e s e t > < p a t h e l e m e n t path= $ {TOMCAT HOME} / l i b / s e r v l e t a p i . j a r /> </ path> < t a r g e t name= i n i t > < d e l e t e d i r= $ { d i s t . d i r } /> < d e l e t e d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r= $ { d i s t . d i r } /> </ t a r g e t> < t a r g e t name= c o m p i l e depends= i n i t > < j a v a c c l a s s p a t h r e f= m y c l a s s p a t h i n c l u d e a n t r u n t i m e= f a l s e s r c d i r= $ { b a s e d i r } / s r c d e s t d i r=web/WEB INF/ c l a s s e s /> </ t a r g e t> < t a r g e t name= g e n e r a t e . war depends= c o m p i l e > < j a r d e s t f i l e = $ { d i s t . d i r } /$ { d i s t . name } . war b a s e d i r=web /> </ t a r g e t> </ p r o j e c t>

Observat ie. Valoarea parametrului dist.name dene ste parametrul catalogAppServlet. Se lanseaz a n execut ie serverul Web tomcat, se ncarc a servlet-ul n serverul Web si dintr-un navigator se deschide pagina http://localhost:8080/apphello Exemplul 9.2.2 Servlet pentru calculul celui mai mare divizor comun a dou a numere.
1 2 3 4 5 6 7 9 10 12 14

import import import import import import import

j a v a . i o . IOException ; java . io . PrintWriter ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

@WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { public long cmmdc( long m, long n ) { . . . } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )

176

CAPITOLUL 9. SERVLET

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40 41 42

throws S e r v l e t E x c e p t i o n , IOException { S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g t i p=r e q . g e t P a r a m e t e r ( t i p ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cmmdc(m, n ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; i f ( t i p . e q u a l s ( t e x t / html ) ) { S t r i n g t i t l e = CmmdcServlet ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc i s +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; } else { r e s . setContentType ( t e x t / p l a i n ) ; out . p r i n t l n ( x ) ; } out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

apelabil prin documentul html (index.html )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Pagina de a p e l a r e CmmdcServlet </ h1> <form method= g e t action=cmmdc> <table> < tr> <td>< l a b e l> Primul numar </ l a b e l></ td> <td> <input type= t e x t name=m s i z e= 5 r e q u i r e d p a t t e r n= [ 0 9 ] { 1 , } > </ td> </ tr> < tr> <td>< l a b e l> Al d o i l e a numar </ l a b e l></ td> <td> <input type= t e x t name=n s i z e= 5 r e q u i r e d p a t t e r n= [ 0 9 ] { 1 , } > </ td> </ tr> < tr> <td> <p><input type= submit value= C a l c u l e a z a >

9.3. PROCESARE ASINCRONA IN JAVA SERVLET 3.0

177

29 30 31 32 33 34 35 36

</ td> </ tr> </ table> <input type= h id de n name= t i p value= t e x t / html > </ form> <center> </ body> </ html>

Pentru xarea naturii r aspunsului text/html sau text/plain s-a introdus variabila tip, care n sierul de invocare index.html prime ste pe ascuns valoarea text/html. In cazul n care vom apela servlet-ul dintr-un program, va avantajos s a primim r aspunsul ca text/plain.

9.3

Procesare asincron a n Java Servlet 3.0

Rezolvarea unei cereri adresat de un client unui servlet (metoda doGet / doPost) se execut a de c atre serverul Web ntr-un r de execut ie. Aceast a execut ie este sincron a n sensul n care trecerea la instruct iunea urm atoare are loc doar la ncheierea execut iei instruct iunii curente. Firul de execut ie este creat si lansat de serverul Web. Interfat a de programare Servlet 3.0 ofer a posibilitatea unui execut ii asincrone: satisfacerea cererii clientului se face ntr-un r de execut ie lansat de clasa servlet-ului. Terminarea activit a tii clasei servlet nu mai este legat a de rezolvarea cererii clientului si de trimiterea r aspunsului. Acest mod de execut ie se indic a prin adnotarea @WebServlet(urlPaterns="/numeApel " ,asyncSupported=true) Suportul asincron necesit a un context, obiect de tip AsyncContext AsyncContext asyncCtx=req.startAsync(req,res); Activit a tile ce trebuie ndeplinite pentru satisfacerea cererii clientului se lanseaz a ntr-un r de execut ie, obiect care este parte a unei familii gestionate de o clas a ce implementeaz a interfat a Executor: public ScheduledThreadPoolExecutor(int corePoolSize ) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue ) Interfat a AsyncListener permite noticarea evenimentelor void onComplete(AsyncEvent ae ) void onTimeout(AsyncEvent ae )

178 void onError(AsyncEvent ae ) void onStartAsync(AsyncEvent ae )

CAPITOLUL 9. SERVLET

Obiectul de tip AsyncEvent este creat n momentul satisfacerii cererii clientului, dep a sirii timpului alocat sau producerii unei erori. Exemplul 9.3.1 Varianta asincron a a servlet-ului de calcul a celui mare divizor comun.
1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 23 24 25 26 27

package m y s e r v l e t ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . AsyncContext ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r ; import j a v a . u t i l . c o n c u r r e n t . S c h e d u l e d T h r e a d P o o l E x e c u t o r ; import j a v a . i o . IOException ; import l i s t e n e r s . MyAsyncListener ; @WebServlet ( u r l P a t t e r n s= /cmmdc , a s y n c S u p p o r t e d=true ) public c l a s s A s y n c S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { AsyncContext asyncCtx=r e q . s t a r t A s y n c ( req , r e s ) ; asyncCtx . a d d L i s t e n e r ( new MyAsyncListener ( ) ) ; E x e c u t o r e x e c u t o r=new S c h e d u l e d T h r e a d P o o l E x e c u t o r ( 1 0 ) ; e x e c u t o r . e x e c u t e ( new AsyncWebService ( asyncCtx ) ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Firul de execut ie responsabil cu ndeplinirea cererii clientului este


1 2 3 4 5 6 8 9 11 12 13 15

package m y s e r v l e t ; import j a v a x . s e r v l e t . S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . AsyncContext ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; public c l a s s AsyncWebService implements Runnable { AsyncContext asyncCtx ; public AsyncWebService ( AsyncContext asyncCtx ) { t h i s . asyncCtx=asyncCtx ; } public void run ( ) {

9.3. PROCESARE ASINCRONA IN JAVA SERVLET 3.0

179

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 40 41

S e r v l e t R e q u e s t r e q=asyncCtx . g e t R e q u e s t ( ) ; S e r v l e t R e s p o n s e r e s=asyncCtx . g e t R e s p o n s e ( ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) ; S t r i n g sn=r e q . g e t P a r a m e t e r ( n ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cmmdc(m, n ) ; S t r i n g r e s u l t=new Long ( x ) . t o S t r i n g ( ) ; try { P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g t i t l e =Cmmdc S e r v l e t ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc i s +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public long cmmdc( long m, long n ) { . . . } }

Clasa care implementeaz a interfat a AsyncListener


1 2 3 4 6 8 10 11 12 13 14 16 17 18 19 20 22 23 24 25 26 28 29 30

package l i s t e n e r s ; import j a v a x . s e r v l e t . AsyncEvent ; import j a v a x . s e r v l e t . A s y n c L i s t e n e r ; import j a v a x . s e r v l e t . S e r v l e t R e q u e s t ; public c l a s s MyAsyncListener implements A s y n c L i s t e n e r { public MyAsyncListener ( ) { } public void onComplete ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : onComplete f o r r e q u e s t : +r ) ; } public void onTimeout ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : onTimeout f o r r e q u e s t : +r ) ; } public void o n E r r o r ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ; System . out . p r i n t l n ( A s y n c L i s t e n e r : o n E r r o r f o r r e q u e s t : +r ) ; } public void o n S t a r t A s y n c ( AsyncEvent ae ) { S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ; S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ;

180

CAPITOLUL 9. SERVLET

31 32 33

System . out . p r i n t l n ( A s y n c L i s t e n e r : o n S t a r t A s y n c f o r r e q u e s t : +r ) ; } }

9.4

Dezvolt ari n servlet-api 3.1

Servlet-api 3.1 este implemetat n glasssh 4.0.

9.4.1

Procesare asincron a neblocant a

Diferent a major a const a n faptul c a solicitarea clientului este trimis a nemijlocit si ndeplinit a de o clas a tip listener. Clasa javax.servlet.ServletInputStream Metode public int readLine(byte[] b, int o, int len ) throws IOException public void setReadListener(ReadListenerreadListener ) Interfat a javax.servlet.ReadListener declar a metodele void onDataAvailable() throws IOException void onAllDataRead() throws IOException) void onError(Throwable t) Exemplul 9.4.1
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18

import import import import import import import import import import

j a v a . i o . IOException ; java . io . PrintWriter ; j a v a . n e t .URL; j a v a x . s e r v l e t . AsyncContext ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . ServletInputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ;

@WebServlet ( u r l P a t t e r n s = { / n o n b l o c k } , a s y n c S u p p o r t e d=true ) public c l a s s N o n B l o c k i n g S e r v l e t extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ; c h a r s e t=UTF8 ) ; try ( P r i n t W r i t e r ou tp ut = r e s . g e t W r i t e r ( ) ) { ou tp ut . p r i n t l n ( <html> ) ;

9.4. DEZVOLTARI IN SERVLET-API 3.1

181

19 20 21 23 24 25 26 27 28 29 31 32 33 34 35 36

ou tp ut . p r i n t l n ( <body> ) ; ou tp ut . p r i n t l n ( <h1> S e r v l e t N o n B l o c k i n g S e r v l e t a t + r e q . g e t C o n t e x t P a t h ( ) + </h1> ) ; AsyncContext c o n t e x t = r e q . s t a r t A s y n c ( ) ; ServletInputStream input = req . getInputStream ( ) ; i n p u t . s e t R e a d L i s t e n e r ( new CmmdcListener ( i n p u t , c o n t e x t , ou tp ut ) ) ; ou tp ut . p r i n t l n ( </body> ) ; ou tp ut . p r i n t l n ( </html> ) ; } } @Override protected void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

mpreun a cu
1 2 3 4 5 7 9 10 11 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

import import import import import

j a v a . i o . IOException ; j a v a x . s e r v l e t . AsyncContext ; javax . s e r v l e t . ReadListener ; javax . s e r v l e t . ServletInputStream ; java . io . PrintWriter ;

public c l a s s CmmdcListener implements R e a d L i s t e n e r { private S e r v l e t I n p u t S t r e a m i n p u t = n u l l ; private AsyncContext c o n t e x t = n u l l ; private P r i n t W r i t e r out = n u l l ; public CmmdcListener ( S e r v l e t I n p u t S t r e a m in , AsyncContext ac , P r i n t W r i t e r ou tp ut ) { input = in ; c o n t e x t = ac ; out = ou tp ut ; } @Override public void o n D a t a A v a i l a b l e ( ) { try { S t r i n g B u i l d e r sb = new S t r i n g B u i l d e r ( ) ; i n t l e n = 1; byte b [ ] = new byte [ 1 0 2 4 ] ; while ( i n p u t . i s R e a d y ( ) && ( l e n = i n p u t . r e a d ( b ) ) != 1) { S t r i n g data = new S t r i n g ( b , 0 , l e n ) ; out . w r i t e ( data ) ; out . w r i t e ( <p> ) ; S t r i n g r e z=s o l v e r ( data ) ; out . w r i t e ( r e z ) ; } } catch ( IOException e ) { System . out . p r i n t l n ( o n A v a i l a b l e E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } }

182

CAPITOLUL 9. SERVLET

39 40 41 42 43 45 46 47 48 49 51 52 53 54 55 56 57 58 59 61 62

@Override public void onAllDataRead ( ) { System . out . p r i n t l n ( onAllDataRead ) ; context . complete ( ) ; } @Override public void o n E r r o r ( Throwable t ) { t . printStackTrace ( ) ; context . complete ( ) ; } private S t r i n g s o l v e r ( S t r i n g data ) { S t r i n g [ ] s=data . s p l i t ( & ) ; S t r i n g [ ] s 0=s [ 0 ] . s p l i t ( = ) ; long m =Long . par se Lo ng ( s 0 [ 1 ] ) ; S t r i n g [ ] s 1=s [ 1 ] . s p l i t ( = ) ; long n=Long . p ars eL ong ( s 1 [ 1 ] ) ; S t r i n g r =(new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ; return Cmmdc : +r ; } private long cmmdc( long m, long n ) { . . . } }

9.4.2

Modicarea protocolului http: upgrade

Schema este utilizat a deja pentru utilizarea protocolului websocket. In apelul http trebuie inserat antetul (header ) Upgrade. Odat a aceast antet recunoscut, solicitarea clientului este rezolvat a ntr-o clas a care implementeaz a interfat a javax.servlet.http.HttpUpgradeHandler. Interfat a declar a metodele void init(WebConnection wc ) void destroy() Interfat a javax.servlet.http.WebConnection Metode ServletInputStream getInputStream() throws IOException ServletOutputStream getOutputStream() throws IOException Clasa care implementeaz a interfat a HttpUpgradeHandler se declar a n servlet prin metoda interfet ei HttpServletRequest <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass ) throws IOException, ServletException In principiu clasa servlet-ului este independent a de specicul aplicat iei.

9.4. DEZVOLTARI IN SERVLET-API 3.1

183

1 2 3 4 5 7 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30

import import import import import

javax . javax . javax . javax . javax .

servlet servlet servlet servlet servlet

. ServletException ; . http . HttpServlet ; . http . HttpServletRequest ; . http . HttpServletResponse ; . a n n o t a t i o n . WebServlet ;

@WebServlet ( u r l P a t t e r n s = { / upgrade } ) public c l a s s U p g r a d e S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { i f ( upgrade . e q u a l s ( r e q . g e t H e a d e r ( Upgrade ) ) ) { res . setStatus (101); r e s . s e t H e a d e r ( Upgrade , upgrade ) ; r e s . s e t H e a d e r ( C o n n e c t i o n , Upgrade ) ; res . flushBuffer () ; System . out . p r i n t l n ( Upgrade OK +r e q . g e t H e a d e r ( Upgrade ) ) ; MyHttpUpgradeHandler h a n d l e r = r e q . upgrade ( MyHttpUpgradeHandler . c l a s s ) ; } else { System . out . p r i n t l n ( No upgrade : ) ; } } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Problema care r am ane de rezolvat este inserarea antetului Update. Rezolvarea consta n generarea unui mesaj http care se va transmite printr-un soclu TCP. Mesajul http folose ste metoda post, iar datele din corpul mesajului sunt preluate prin interfat a HttpInputStream. Pentru problema calculului celui mai mare divizor comun a dou a numere naturale clasa MyHttpUpgradeHandler este
1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19

import import import import

javax . javax . javax . javax .

servlet servlet servlet servlet

. ServletOutputStream ; . ServletInputStream ; . h t t p . WebConnection ; . h t t p . HttpUpgradeHandler ;

public c l a s s MyHttpUpgradeHandler implements HttpUpgradeHandler { private WebConnection wc = n u l l ; @Override public void i n i t ( WebConnection wc ) { t h i s . wc=wc ; try { S e r v l e t I n p u t S t r e a m i n p u t = wc . g e t I n p u t S t r e a m ( ) ; S e r v l e t O u t p u t S t r e a m o ut pu t=wc . getOutputStream ( ) ; S t r i n g CRLF = \ r \ n ; S t r i n g r e s S t r = update / 1 . 0 + CRLF ; r e s S t r += S e r v e r : G l a s s f i s h / S e r v e r T e s t + CRLF ; r e s S t r += Content Type : t e x t / html + CRLF ; r e s S t r += C o n n e c t i o n : Upgrade + CRLF ;

184

CAPITOLUL 9. SERVLET

20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60

r e s S t r += CRLF ; byte [ ] b=new byte [ 2 5 6 ] ; input . read (b ) ; S t r i n g data=new S t r i n g ( b ) . t r i m ( ) ; S t r i n g r e z=s o l v e r ( data ) ; r e s S t r +=r e z + CRLF ; ou tp ut . w r i t e ( r e s S t r . g e t B y t e s ( ) ) ; ou tp ut . f l u s h ( ) ; } catch ( E x c e p t i o n ex ) { throw new RuntimeException ( ex ) ; } } @Override public void d e s t r o y ( ) { try { wc . c l o s e ( ) ; } catch ( E x c e p t i o n ex ) { System . out . p r i n t l n ( D e s t r o y wc E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ; } } private S t r i n g s o l v e r ( S t r i n g data ) { System . out . p r i n t l n ( S o l v e r : +data ) ; S t r i n g [ ] s=data . s p l i t ( ) ; S t r i n g r=1 ; try { long m =Long . par se Lo ng ( s [ 0 ] ) ; long n=Long . pa rs eL ong ( s [ 1 ] ) ; r =(new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ; } catch ( NumberFormatException e ) { System . out . p r i n t l n ( NumberFormatException : +e . g e t M e s s a g e ( ) ) ; } return Cmmdc : +r ; } private long cmmdc( long m, long n ) { . . . } }

iar lansarea aplicat iei se face dintr-un program client, n care se genereaz a mesajul http cu anterul Upgrade, mesaj expediat printr-un soclu TCP. Client Java
1 2 3 4 5 6 7 9 10 11 12

import import import import import import import

java . net . Socket ; j a v a . i o . InputStream ; j a v a . i o . OutputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; j a v a . i o . IOException ; java . u t i l . Scanner ;

public c l a s s J C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ;

9.4. DEZVOLTARI IN SERVLET-API 3.1

185

13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

long m =s c a n n e r . nextLong ( ) ; S t r i n g sm=new Long (m) . t o S t r i n g ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ; S t r i n g data=sm+ +sn ; S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 8080 ; S t r i n g c o n t e x t R o o t= / upgrade ; S t r i n g CRLF = \ r \ n ; S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ; r e q S t r += User Agent : Java / 1 . 7 + CRLF ; r e q S t r += Host : + h o s t + : + p o r t + CRLF ; r e q S t r += Accept : t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 + CRLF ; r e q S t r += Upgrade : upgrade + CRLF ; r e q S t r += C o n n e c t i o n : Upgrade + CRLF ; r e q S t r += Content t y p e : a p p l i c a t i o n /xwww form u r l e n c o d e d + CRLF ; r e q S t r += T r a n s f e r Encoding : chunked + CRLF ; r e q S t r += CRLF ; r e q S t r += data + CRLF ; S o c k e t s o c k e t=n u l l ; try { s o c k e t=new S o c k e t ( hos t , I n t e g e r . p a r s e I n t ( p o r t ) ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try ( OutputStream out=s o c k e t . getOutputStream ( ) ; InputStream i n=s o c k e t . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; ){ out . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ; out . f l u s h ( ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; }; socket . close ( ) ; // System . e x i t ( 0 ) ; } catch ( IOException e ) { System . out . p r i n t l n ( I n p u t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

Client servlet
1 2 3 4 5 6 7

import import import import import import import

java . i o . BufferedReader ; j a v a . i o . IOException ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; j a v a . i o . OutputStream ; java . io . PrintWriter ; java . net . Socket ;

186

CAPITOLUL 9. SERVLET

9 10 11 12 13 15 16 18 19 20 21 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54 56 57 58 59 60 62 63 64 66

import import import import import

javax . javax . javax . javax . javax .

servlet servlet servlet servlet servlet

. ServletException ; . a n n o t a t i o n . WebServlet ; . http . HttpServlet ; . http . HttpServletRequest ; . http . HttpServletResponse ;

@WebServlet ( u r l P a t t e r n s = { / c l i e n t } ) public c l a s s C l i e n t S e r v l e t extends H t t p S e r v l e t { protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { String m =r e q . g e t P a r a m e t e r ( m ) ; S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ; r e s . setContentType ( t e x t / html ; c h a r s e t=UTF8 ) ; P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; f i n a l S t r i n g CRLF = \ r \ n ; f i n a l S t r i n g h o s t = r e q . getServerName ( ) ; // l o c a l h o s t ; f i n a l i n t p o r t = r e q . g e t S e r v e r P o r t ( ) ; // 8 0 8 0 ; f i n a l S t r i n g c o n t e x t R o o t = / upgrade ; f i n a l S t r i n g data = m + +n ; InputStream i n p u t = n u l l ; OutputStream o ut pu t = n u l l ; BufferedReader r e a d e r = null ; Socket s = null ; try { out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head> ) ; out . p r i n t l n ( < t i t l e > S e r v l e t C l i e n t T e s t </ t i t l e > ) ; out . p r i n t l n ( </head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>Http Upgrade P r o c e s s </h1> ) ; // S e t t i n g t h e HTTP u p g r a d e r e q h e a d e r S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ; r e q S t r += User Agent : Java / 1 . 7 + CRLF ; r e q S t r += Host : + h o s t + : + p o r t + CRLF ; r e q S t r += Accept : t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 + CRLF ; r e q S t r += Upgrade : upgrade + CRLF ; r e q S t r += C o n n e c t i o n : Upgrade + CRLF ; r e q S t r += Content t y p e : a p p l i c a t i o n /xwww form u r l e n c o d e d + CRLF ; r e q S t r += T r a n s f e r Encoding : chunked + CRLF ; r e q S t r += CRLF ; r e q S t r += data + CRLF ; s = new S o c k e t ( hos t , p o r t ) ; input = s . getInputStream ( ) ; ou tp ut = s . getOutputStream ( ) ; ou tp ut . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ; ou tp ut . f l u s h ( ) ; out . p r i n t l n ( <h2>S e n d i n g upgrade r e q t o s e r v e r . . . . . . < / h2> ) ; out . p r i n t l n ( <h3>Request h e a d e r with data : < /h3> ) ; out . p r i n t l n ( ) ; S t r i n g r e q S t r D i s p l a y = r e q S t r . r e p l a c e A l l ( \ r \ n , </br > ) ;

9.4. DEZVOLTARI IN SERVLET-API 3.1

187

67 68 69 71 73 74 75 77 78 79 80 82 83 85 86 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 119 120 121 122 123 124 125

out . p r i n t l n ( r e q S t r D i s p l a y ) ; out . p r i n t l n ( </br ></br > ) ; out . f l u s h ( ) ; r e a d e r = new B u f f e r e d R e a d e r ( new InputStreamReader ( i n p u t ) ) ; out . p r i n t l n ( <h2> S e r v e r a c c e p t upgrade req , send back t h e r e s : < /h2> ) ; out . p r i n t l n ( <h3>Response h e a d e r : < /h3> ) ; out . p r i n t l n ( ) ; // Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r p r i n t H e a d e r ( r e a d e r , out ) ; out . p r i n t l n ( </br ></br > ) ; out . f l u s h ( ) ; out . p r i n t l n ( <h2> S e r v e r send back t h e r e s with new p r o t o c o l and data : < /h2> ) ; out . p r i n t l n ( <h3>Response h e a d e r with data : < /h3> ) ; // Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r p r i n t H e a d e r ( r e a d e r , out ) ; // Reading t h e echo d a t a S t r i n g dataOutput ; i f ( ( dataOutput = r e a d e r . r e a d L i n e ( ) ) != n u l l ) { // P r i n t o u t t h e d a t a a f t e r h e a d e r out . p r i n t l n ( </br > + dataOutput + </br > ) ; out . p r i n t l n ( </br ></br > ) ; out . p r i n t l n ( <h2>C o n n e c t i o n with new p r o t o c o l e s t a b l i s h e d </h2> ) ; } out . f l u s h ( ) ; out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; } catch ( IOException e ) { System . out . p r i n t l n ( C l i e n t S e r v l e t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } finally { i f ( r e a d e r != n u l l ) { reader . close ( ) ; } i f ( ou tp ut != n u l l ) { o ut pu t . c l o s e ( ) ; } i f ( i n p u t != n u l l ) { input . c l o s e ( ) ; } i f ( s != n u l l ) { s . close (); } } } protected void p r i n t H e a d e r ( B u f f e r e d R e a d e r r e a d e r , P r i n t W r i t e r out ) throws IOException { f o r ( S t r i n g l i n e ; ( l i n e = r e a d e r . r e a d L i n e ( ) ) != n u l l ; ) { i f ( l i n e . isEmpty ( ) ) { break ; } out . p r i n t l n ( l i n e + </br > ) ;

188
} }

CAPITOLUL 9. SERVLET

126 127 129 130 131 132 133 134

@Override protected void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

9.5
9.5.1

Facilit a ti de programare cu servlet


Program client al unui servlet

Apelarea unui servlet dintr-un program Java adic a lansarea unei cereri si recept ionarea r aspunsului furnizat de servlet se poate obt ine sincron cu produsul httpcomponents-client, asincron cu produsul httpcomponents-asyncclient. Ambele produse sunt dezvoltate de apache. Caracterul sincron / asincron const a n faptul c a recept ia si prelucrarea r aspunsului oferit de servlet are loc n metoda din care s-a lansat cererea, respectiv ntr-un alt obiect. Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos ca r aspunsul servlet-ului e text/plain, n loc de text/html. Cazul sincron Catalogul lib din httpcomponents-client cont ine, printre altele, sierele httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar. Pentru compilare trebuie declarat a n variabila de sistem classpath referint a c atre httpclient-*.jar si httpcore-*.jar dar pentru execut ie este nevoie si de referint a c atre commons-logging-*.jar. Dezvoltarea unui client presupune: 1. Crearea unui obiect de tip org.apache.http.client.CloseableHttpClient: CloseableHttpClient httpclient = HttpClients.createDefault(); 2. Declararea metodei de transmitere a datelor get, post cu inserarea datelor din cerere.

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

189

GET HttpGet httpget = new HttpGet(uri); unde uri este String-ul de apelare a servlet-ului, de forma http://host:port/catalog/numeApel?numeParam=valParam &. . . , O solut ie mai elegant a este List<NameValuePair> qparams = new ArrayList<NameValuePair>(); qparams.add(new BasicNameValuePair("param_1", value_1)); qparams.add(new BasicNameValuePair("param_2", value_2)); . . . try{ URI uri = URIUtils.createURI("http", "localhost", 8080, "/catalog/numeApel",URLEncodedUtils.format(qparams,"UTF-8"), null); HttpGet httpget = new HttpGet(uri); . . . } catch(. . .){. . .} POST List<NameValuePair> qparams = new ArrayList<NameValuePair>(); qparams.add(new BasicNameValuePair("param_1", value_1)); qparams.add(new BasicNameValuePair("param_2", value_2)); . . . try{ UrlEncodedFormEntity params=new UrlEncodedFormEntity(qparams, "UTF-8"); HttpPost httppost=new HttpPost(uri); httppost.setEntity(params); . . . } catch(. . .){. . .} cu uri=http://host:port/catalog/numeApel. Clasele HttpGet, HttpPost apart in pachetului org.apache.http.client.methods. 3. Lansarea cererii.

190

CAPITOLUL 9. SERVLET

HttpResponse response=httpclient.execute(httpget); respectiv HttpResponse response=httpclient.execute(httppost); 4. Preluarea r aspunsului. HttpEntity entity=response.getEntity(); if(entity!=null){ InputStream is=entity.getContent(); int l; byte[] tmp=new byte[2048]; while((l=is.read(tmp))!=-1){} . . . } Exemplul 9.5.1 Dezvolt am un program client pentru servlet-ul CmmdcServlet (post).
1 2 4 5 6 7 8 9 10 11 13 14 16 17 19 20 21 22 23 24 26 27 28 29

import j a v a . u t i l . S c a n n e r ; import o r g . apache . h t t p . H t t p E n t i t y ; import import import import import import import import o r g . apache . h t t p . impl . c l i e n t . C l o s e a b l e H t t p C l i e n t ; o r g . apache . h t t p . c l i e n t . methods . HttpPost ; o r g . apache . h t t p . c l i e n t . methods . C l o s e a b l e H t t p R e s p o n s e ; o r g . apache . h t t p . impl . c l i e n t . H t t p C l i e n t s ; java . u t i l . List ; java . u t i l . ArrayList ; o r g . apache . h t t p . NameValuePair ; o r g . apache . h t t p . message . BasicNameValuePair ;

import o r g . apache . h t t p . c l i e n t . e n t i t y . UrlEncodedFormEntity ; import j a v a . i o . ; public c l a s s ClientCmmdcServlet { s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; String m =s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; System . out . p r i n t l n ( n= ) ; S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; CloseableHttpClient httpclient = HttpClients . createDefault ( ) ; L i s t <NameValuePair > qparams = new A r r a y L i s t <NameValuePair > ( ) ; qparams . add ( new BasicNameValuePair ( m , m) ) ; qparams . add ( new BasicNameValuePair ( n , n ) ) ;

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

191

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

qparams . add ( new BasicNameValuePair ( t i p , t e x t / p l a i n ) ) ; try { UrlEncodedFormEntity params=new UrlEncodedFormEntity ( qparams , UTF8 ) ; HttpPost h t t p p o s t=new HttpPost ( u r i ) ; h t t p p o s t . s e t E n t i t y ( params ) ; C l o s e a b l e H t t p R e s p o n s e r e s p o n s e=h t t p c l i e n t . e x e c u t e ( h t t p p o s t ) ; H t t p E n t i t y e n t i t y=r e s p o n s e . g e t E n t i t y ( ) ; i f ( e n t i t y != n u l l ) { InputStream i s=e n t i t y . g e t C o n t e n t ( ) ; int l ; byte [ ] tmp=new byte [ 2 0 4 8 ] ; while ( ( l=i s . r e a d ( tmp))!= 1) {} System . out . p r i n t l n ( Cmmdc = +(new S t r i n g ( tmp ) . t r i m ( ) ) ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

O solut ie elementar a bazat a pe clasa java.net.HttpURLConnection este


1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

import import import import import import

j a v a . n e t .URL; j a v a . n e t . HttpURLConnection ; java . u t i l . Scanner ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; java . io . PrintWriter ;

public c l a s s CmmdcClient { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; S t r i n g msg=m =+ m +&n=+n+&t i p=t e x t / p l a i n ; try { S t r i n g urlGET= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc? +msg ; URL u r l=new URL( urlGET ) ; HttpURLConnection conn=(HttpURLConnection ) u r l . op enConne ction ( ) ; conn . setRequestMethod ( GET ) ; System . out . p r i n t l n ( conn . getResponseCode ( ) ) ; System . out . p r i n t l n ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( new InputStreamReader ( conn . g e t I n p u t S t r e a m ( ) ) ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; } br . c l o s e ( ) ; conn . d i s c o n n e c t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } try { S t r i n g urlPOST= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ;

192

CAPITOLUL 9. SERVLET

37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

URL u r l=new URL( urlPOST ) ; HttpURLConnection conn=(HttpURLConnection ) u r l . op enConne ction ( ) ; conn . setRequestMethod ( POST ) ; conn . s e t U s e C a c h e s ( f a l s e ) ; conn . s e t D o I n p u t ( true ) ; conn . setDoOutput ( true ) ; conn . s e t R e q u e s t P r o p e r t y ( Content Type , a p p l i c a t i o n /xwww form u r l e n c o d e d ) ; P r i n t W r i t e r pw=new P r i n t W r i t e r ( conn . getOutputStream ( ) ) ; pw . p r i n t l n ( msg ) ; pw . f l u s h ( ) ; System . out . p r i n t l n ( conn . getResponseCode ( ) ) ; System . out . p r i n t l n ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ; B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( new InputStreamReader ( conn . g e t I n p u t S t r e a m ( ) ) ) ; String s ; while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) { System . out . p r i n t l n ( s ) ; } br . c l o s e ( ) ; pw . c l o s e ( ) ; conn . d i s c o n n e c t ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }

Cazul asincron Variabila classpath cont ine referent ele c atre serele jar aate n catalogul lib din httpcomponent-asyncclient. Programarea const a din

1. Crearea unei instant e a clasei org.apache.http.impl.nio.client.DefaultHttpAsync CloseableHttpAsyncClient httpclient = HttpAsyncClient.createDefault(); httpclient.start(); 2. Lansarea unei cereri apel and o metod a execute: <T> Future<T> execute( org.apache.http.nio.protocol.HttpAsyncRequestProducer requestProducer, org.apache.http.nio.protocol.HttpAsyncResponseConsumer<T> responseConsumer, org.apache.http.concurrent.FutureCallback<T> callback ) O instant a de tip HttpAsyncRequestProducer se obt ine prin

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

193

HttpAsyncMethods.createGet(uri) Drept instant a a clasei HttpAsyncResponseConsumer poate o clas a ce extinde clasa org.apache.http.nio.client.methods.AsyncCharConsumer. Exemplul 9.5.2
1 3 4 5 6 7 8 9 11 12 13 15 16 18 19 20 21 22 23 24 25 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 49

import j a v a . u t i l . S c a n n e r ; import import import import import import import o r g . apache . h t t p . HttpResponse ; o r g . apache . h t t p . impl . n i o . c l i e n t . C l o s e a b l e H t t p A s y n c C l i e n t ; o r g . apache . h t t p . n i o . IOControl ; o r g . apache . h t t p . impl . n i o . c l i e n t . H t t p A s y n c C l i e n t s ; o r g . apache . h t t p . n i o . c l i e n t . methods . AsyncCharConsumer ; o r g . apache . h t t p . n i o . c l i e n t . methods . HttpAsyncMethods ; o r g . apache . h t t p . p r o t o c o l . HttpContext ;

import j a v a . n i o . C h a r B u f f e r ; import j a v a . i o . IOException ; import j a v a . u t i l . c o n c u r r e n t . Future ; public c l a s s AsyncClientCmmdcServlet { s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; String m =s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; System . out . p r i n t l n ( n= ) ; S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ; S t r i n g r e q u e s t D a t a= ?m =+ m +&n=+n+&t i p=t e x t / p l a i n ; System . out . p r i n t l n ( r e q u e s t D a t a ) ; CloseableHttpAsyncClient h t t p c l i e n t = HttpAsyncClients . c r e a t e D e f a u l t ( ) ; httpclient . start (); try { Future <Boolean > f u t u r e = h t t p c l i e n t . e x e c u t e ( HttpAsyncMethods . c r e a t e G e t ( u r i+r e q u e s t D a t a ) , new MyResponseConsumer ( ) , n u l l ) ; Boolean r e s u l t = f u t u r e . g e t ( ) ; i f ( r e s u l t != n u l l && r e s u l t . b o o l e a n V a l u e ( ) ) { System . out . p r i n t l n ( Request s u c c e s s f u l l y e x e c u t e d ) ; } else { System . out . p r i n t l n ( Request f a i l e d ) ; } System . out . p r i n t l n ( S h u t t i n g down ) ; } finally { httpclient . close (); } System . out . p r i n t l n ( Done ) ; } s t a t i c c l a s s MyResponseConsumer extends AsyncCharConsumer<Boolean >{ @Override

194

CAPITOLUL 9. SERVLET

50 52 53 54 55 56 57 58 59 61 62 64 65 66 67 68 69

protected void o n R e s p o n s e R e c e i v e d ( f i n a l HttpResponse r e s p o n s e ) {} @Override protected void onCharReceived ( f i n a l C h a r B u f f e r buf , f i n a l IOControl i o c t r l ) throws IOException { System . out . p r i n t l n ( Cmmdc : ) ; while ( b u f . hasRemaining ( ) ) { System . out . p r i n t ( b u f . g e t ( ) ) ; } } @Override protected void r e l e a s e R e s o u r c e s ( ) {} @Override protected Boolean b u i l d R e s u l t ( f i n a l HttpContext c o n t e x t ) { return Boolean .TRUE; } } }

9.5.2

Servlete nl ant uite

Un servlet apeleaz a la un moment dat alt servlet. S ablonul de lucru este RequestDispatcher dispatcher= getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat"); if(dispatcher!=null) dispatcher.include(request,response); Exemplul 9.5.3 Un servlet VerifServlet veric a parametri cererii. Pentru problema calculului celui mai mare divizor comun a dou a numere, dac a cei doi parametri sunt numere ntregi, atunci se apeleaz a servlet-ul ComputeServlet, altfel se formeaz a un mesaj de eroare. Codurile celor dou a servlete sunt: VerifServlet.java
1 2 3 4 5 6 7 8 9 11 12 13

package cmmdc ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . R e q u e s t D i s p a t c h e r ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / v e r i f ) public c l a s s V e r i f S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

195

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 58 59 60 61 62

throws S e r v l e t E x c e p t i o n , IOException { P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g message= ; long m, n ; i f ( ( sm==n u l l ) | | ( sm . e q u a l s ( ) ) ) { message=Numar a b s e n t ; } else { try { m =Long . par se Lon g ( sm ) ; } catch ( NumberFormatException e ) { message=Nu e s t e numar ; } } i f ( ( sn==n u l l ) | | ( sn . e q u a l s ( ) ) ) { message=Numar a b s e n t ; } else { try { n=Long . p ars eL ong ( sn ) ; } catch ( NumberFormatException e ) { message=Nu e s t e numar ; } } out . p r i n t l n ( <html><body> ) ; i f ( message . e q u a l s ( ) ) { out . p r i n t l n ( <h3> R e z u l t a t u l ob&#355; i n u t </h3> ) ; R e q u e s t D i s p a t c h e r d i s p a t c h e r= getServletContext ( ) . getRequestDispatcher ( / c a l c u l ) ; i f ( d i s p a t c h e r != n u l l ) d i s p a t c h e r . i n c l u d e ( req , r e s ) ; } else { out . p r i n t l n ( <h3> Date e r o n a t e </h3> ) ; out . p r i n t l n ( message ) ; } out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

ComputeServlet.java
1 2 3 4 5 6 7

package cmmdc ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;

196

CAPITOLUL 9. SERVLET

8 10 11 13 15 16 17 18 19 20 21 23 24 25 26 27

import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / c a l c u l ) public c l a s s ComputeServlet extends H t t p S e r v l e t { public long cmmdc( long m, long n ) { . . . } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { long m =Long . par se Lo ng ( r e q . g e t P a r a m e t e r ( m ) ) ; long n=Long . p ars eL ong ( r e q . g e t P a r a m e t e r ( n ) ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; out . p r i n t l n ( <H1> Cmmdc = +cmmdc(m, n)+</H1> ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

9.5.3

Sesiune de lucru

In cazul protocolului HTTP, de ecare dat a c and un client deschide sau revine la o pagin a Web se deschide o nou a conexiune cu serverul Web iar acesta nu ret ine informat iile referitoare la client pe perioada conexiunii respective. Perioada de timp c at un client este n conexiune cu o pagin a Web se nume ste sesiune. Exist a posibilitatea p astr arii unor informat ii pe durata unei sesiuni prin intermediul unui obiect de tip javax.servlet.http.HttpSession. Inaintea satisfacerii unei cereri, servlet-ul veric a existent a unui obiect HttpSession. Acest obiect se creaz a la prima apelare de c atre un client a servlet-ului prin HttpSession sesiune =request.getSession(true); Un obiect HttpSession poate ret ine atribute, adic a perechi de forma (nume, valoare). Introducerea unui atribut se realizeaz a prin void setAttribute(String nume , Object valoare ) iar extragerea valorii unui atribut se obt ine prin Object getAttribute(String nume ) Metoda String nume [ ] getValueNames() returneaz a numele tuturor atributelor denite. Un atribut se elimin a cu metoda void removeAttribute(String nume ).

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

197

Exemplul 9.5.4 Exemplul urm ator num ar a de c ate ori se apeleaz a servletul ntr-o sesiune. Se dene ste un atribut noAcces, care la prima apelare este init ializat iar apoi este m arit cu c ate o unitate la ecare nou a apelare a servletului.
1 2 3 4 5 6 7 8 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 37 38 39 40 41

import import import import import import import import

j a v a . i o . IOException ; java . io . PrintWriter ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . http . HttpSession ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

@WebServlet ( u r l P a t t e r n s = / s e s i u n e ) public c l a s s S e s i u n e extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S t r i n g mesaj ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; H t t p S e s s i o n s e s s i o n=r e q . g e t S e s s i o n ( true ) ; I n t e g e r c o n t o r =( I n t e g e r ) s e s s i o n . g e t A t t r i b u t e ( noAcces ) ; i f ( c o n t o r==n u l l ) { c o n t o r=new I n t e g e r ( 1 ) ; mesaj= S a l u t ! ; } else { c o n t o r=new I n t e g e r ( c o n t o r . i n t V a l u e ( ) + 1 ) ; mesaj= Bine a t i r e v e n i t ! ; } s e s s i o n . s e t A t t r i b u t e ( noAcces , c o n t o r ) ; out . p r i n t l n ( <html><body> ) ; out . p r i n t l n ( <h1>+mesaj+</h1> ) ; out . p r i n t l n ( Numarul de a c c e s a r i a l a c e a s t e i p a g i n i e s t e + contor . intValue ( ) ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Apelarea servlet-ului se face din


1 2 3 4 5 6 7 8

< ! doctype html> <head> <meta charset= u t f 8> < l i n k r e l = s t y l e s h e e t href= mycss . c s s > </ head> <body> <center> <h1> Formular de a c c e s </ h1>

198

CAPITOLUL 9. SERVLET

9 10 11 12 13 14 15 16

<form method= g e t action= s e s i u n e > <p> <input type= submit value= A c c e s e a z a > </ form> </ center> </ body> </ html>

9.5.4

Cookie

Un Cookie este un sier de dimensiune mic a trimis de c atre programul server clientului ca parte a header-ului Http. Acesta cont ine informat ii despre sesiunea curent a care salvate pe disc vor putea accesate n sesiuni ulterioare. C and un navigator emite o cerere c atre un server, cookie-urile anterioare primite de c atre client de la serverul respectiv sunt trimise din nou serverului ca parte a cererii formulat a de client. Cookie-urile sunt sterse automat n momentul expir arii. Unii client i nu permit memorarea cookie-urilor. In acest caz, clientul este informat c a acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale / acces arii paginii Web. Implicit, durata de viat a a unui cookie este sesiunea curent a a navigatorului (p an a se nchide navigatorul). Clasa Cookie Contructor Cookie(String nume , String valoare ) Metode void setDomain(String model ) Domeniul este o adres a URL ce restrict ioneaz a accesul cookie-urilor la acel domeniu. model trebuie s a cont in a cel put in dou a caractere .. void setMaxAge(int durat a ) Fixeaz a durata de existent a a cookie-ului - n secunde. Valoarea implicit a este -1, adic a cookie-ul exist a p an a la nchiderea programului navigator. void setComment(String comentariu ) void setSecure(boolean ag ) Valoarea implicit a este false.

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

199

Trimiterea unui cookie clientului: public void HttpServletResponse.addCookie(Cookie cookie ) Recunoa sterea cookie-urilor de c atre servlet: Cookie [ ] cookies=request.getCookies(); if(cookies!=null){ for(int i=0;i<cookies.length;i++){ String name=cookies[i].getName(); String valoare=cookies[i].getValue(); . . . } exemplul urm Exemplul 9.5.5 In ator se num ar a de c ate ori se apeleaz a servletul pe durata de viat a a cookie-ului.

1 2 3 4 5 6 7 8 9 11 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

package c o o k i e ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . h t t p . Cookie ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / c o o k i e ) public c l a s s A p e l a r i extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , HttpServletResponse res ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S t r i n g mesaj= ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; Cookie myCookie=n u l l ; i n t c o n t o r =0; Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ; boolean sw= f a l s e ; i f ( c o o k i e s != n u l l ) { f o r ( i n t i =0; i < c o o k i e s . l e n g t h ; i ++){ S t r i n g name=c o o k i e s [ i ] . getName ( ) ; i f ( name . e q u a l s ( u r m a r i r e ) ) { sw=true ; c o n t o r=I n t e g e r . p a r s e I n t ( c o o k i e s [ i ] . g e t V a l u e ( ) ) ; c o n t o r ++; mesaj= Bine a t i r e v e n i t ! ; System . out . p r i n t l n ( G a s i t +c o n t o r ) ; } }

200

CAPITOLUL 9. SERVLET

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 54 55 56 57 58 59

} i f ( sw ) { myCookie=new Cookie ( u r m a r i r e , ( new I n t e g e r ( c o n t o r ) ) . t o S t r i n g ( ) ) ; } else { myCookie=new Cookie ( u r m a r i r e , ( new I n t e g e r ( 1 ) ) . t o S t r i n g ( ) ) ; c o n t o r =1; mesaj= S a l u t ! ; } myCookie . setMaxAge ( 1 0 0 0 0 0 0 ) ; r e s . addCookie ( myCookie ) ; out . p r i n t l n ( <html><body> ) ; out . p r i n t l n ( <h1>+mesaj+</h1> ) ; out . p r i n t l n ( Numarul de a c c e s a r i a l a c e a s t e i p a g i n i e s t e +c o n t o r ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , HttpServletResponse res ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

9.5.5

Autenticare

Serverul Web apache-tomcat poate executa autentic arile basic si digest. Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password). Aceste informat ii sunt ret inute n serverul Web, n sierul conf\tomcat-users.xml ind asociate unui element <role>, de exemplu
<role <role . . . <user <user rolename="BASIC_ROLE"/> rolename="DIGEST_ROLE"/> username="basic" password="basic" roles="BASIC_ROLE"/> username="digest" password="digest" roles="DIGEST_ROLE"/>

Codul servlet-ului nu este implicat, iar cerint a de autenticare solicitat a unui client se precizeaz a n sierul web.xml
<security-role> <role-name>BASIC_ROLE</role-name> </security-role> <security-constraint> <web-resource-collection> <web-resource-name>Restricted Access - Members Only</web-resource-name> <url-pattern>/cmmdc</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>BASIC_ROLE</role-name> </auth-constraint> <user-data-constraint>

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

201

<transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <!-<realm-name>My realm name</realm-name> --> </login-config>

Opt ional poate denit un domeniu (realm). In cazul apel arii dintr-un program Java a unui servlet, la care accesul presupune autenticare, aceasta se realizeaz a prin intermediul claselor pachetului httpcomponents-client :
import import import import org.apache.http.auth.AuthScope; org.apache.http.auth.UsernamePasswordCredentials; org.apache.http.impl.auth.BasicScheme; org.apache.http.protocol.BasicHttpContext;

. . . DefaultHttpClient httpclient = new DefaultHttpClient(); // Activitati pentru autentificare httpclient.getCredentialsProvider().setCredentials( new AuthScope(host,Integer.parseInt(port)), // new AuthScope(host,Integer.parseInt(port),realm), new UsernamePasswordCredentials(username,password) ); BasicHttpContext context=new BasicHttpContext(); BasicScheme schema = new BasicScheme(); // DigestScheme schema = new DigestScheme(); context.setAttribute("preemptive-auth", schema); . . . HttpResponse response=httpclient.execute(httppost,context); . . .

In cazul autentic arii digest, datele de identicare sunt criptate iar in cazul autenticarii basic se utilizeaz a codarea base64.

9.5.6

Servlet cu conexiune la o baz a de date

Folosind Anexa C consider am Exemplul 9.5.6 Consultarea unei agende de adrese e-mail. Se utilizeaz a o baz a de date AgendaEMail alc atuit a dintr-un singur tabel adrese (id int, nume varchar(20), email varchar(30)). Utiliz and SGBD derby servlet-ul este

202

CAPITOLUL 9. SERVLET

1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 46 47 48 49 50 51 52 54 55 56 57 58

import import import import import import import import import import import import import

j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . ServletOutputStream ; javax . s e r v l e t . ServletConfig ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a . s q l . Statement ; java . s q l . Connection ; j a v a . s q l . DriverManager ; j a v a . s q l . SQLException ; java . s q l . ResultSet ;

@WebServlet ( u r l P a t t e r n s = / a d r e s e ) public c l a s s A g e n d a E M a i l S e r v l e t extends H t t p S e r v l e t { Statement i n s t r u c t i u n e=n u l l ; C o n n e c t i o n con=n u l l ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) throws S e r v l e t E x c e p t i o n { super . i n i t ( c o n f i g ) ; // SGBD Derby S t r i n g j d b c D r i v e r= o r g . apache . derby . j d b c . C l i e n t D r i v e r ; S t r i n g URLBazaDate= j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ; // SGBD Mysql // S t r i n g j d b c D r i v e r =com . mysql . j d b c . D r i v e r ; // S t r i n g URLBazaDate= j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ; try { C l a s s . forName ( j d b c D r i v e r ) . n e w I n s t a n c e ( ) ; con=DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ; i n s t r u c t i u n e=con . c r e a t e S t a t e m e n t ( ) ; } catch ( ClassNotFoundException e ) { System . out . p r i n t l n ( D r i v e r i n e x i s t e n t JDBC : +j d b c D r i v e r ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( Baza de d a t e i n e x i s t e n t a +URLBazaDate ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void d e s t r o y ( ) { try { i f ( con != n u l l ) con . c l o s e ( ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g myAtribut , myVal ; r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

203

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 89 90 91 92 93

myAtribut=r e q . g e t P a r a m e t e r ( c r i t e r i u ) ; myVal=r e q . g e t P a r a m e t e r ( termen ) ; myVal= \ +myVal+ \ ; try { S t r i n g s q l= s e l e c t from a d r e s e where + myAtribut+ = +myVal ; R e s u l t S e t r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e >AgendaEMail </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>Agenda de Adrese em a i l </h1> ) ; out . p r i n t l n ( <p/> ) ; out . p r i n t l n ( <b> Nume <> Adresa em a i l </b> ) ; out . p r i n t l n ( <br/> ) ; while ( r s . n e x t ( ) ) { out . p r i n t ( r s . g e t S t r i n g ( nume)+ <> +r s . g e t S t r i n g ( e m a i l ) ) ; out . p r i n t l n ( <br/> ) ; } out . p r i n t l n ( </body> ) ; out . p r i n t l n ( </html> ) ; out . c l o s e ( ) ; } catch ( SQLException e ) { System . out . p r i n t l n ( SQLException : +e . g e t M e s s a g e ( ) ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Apelarea servlet-ului se face din


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

<html> <body> <h1> Cautare i n baza de d a t e AgendaEMail</ h1> <form method= g e t action= a d r e s e > <p> C r i t e r i u de c a u t a r e : < s e l e c t name= c r i t e r i u > <option value=nume>dupa Nume <option value= e m a i l >dupa Email </ s e l e c t> <br> <p> E n t i t a t e a c a u t a t a <input type= t e x t name= termen s i z e =30> <p><input type= submit value= Cauta > </ form> </ body> </ html>

Testarea aplicat iei presupune: 1. Realizarea bazei de date:

204 2. Testarea servlet-ului: (a) Pornirea serverului bazei de date.

CAPITOLUL 9. SERVLET

(b) Se veric a prezent a n catalogul servlet-ului ...\WEB-INF\lib a sierului derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar. (c) Pornirea serverului tomcat sau re nc arcarea servlet-ului. (d) Apelarea servlet-ului din pagina Web.

9.5.7

Imagini furnizate de servlet

Indic am dou a modalit a ti prin care un client obt ine o imagine furnizat a de un servlet. Imaginea poate proveni dintr-un sier extern sau poate creat a de servlet. Imaginea este transmis a direct clientului n uxul de ie sire de tip ServletOutputStream, tipul MIME al r aspunsului ind response.setContentType("image/ext "); ext {gif, jpg, png, . . .}. Textul surs a al servlet-ului este:

1 2 3 4 5 6 7 8 10 11 12 14 16 17 18 19 20 21 22 23 24

package g r a p h g i f ; import j a v a . i o . IOException ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . n i o . f i l e . Path ; import j a v a . n i o . f i l e . Paths ; import j a v a . n i o . f i l e . F i l e s ; @WebServlet ( u r l P a t t e r n s = / g r a p h g i f ) public c l a s s MyGraphG extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ; S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ; Path path=Paths . g e t ( pathTomcat+f s+ webapps +f s+ c o n t e x t P a t h+f s+ w a l k i n g s a n t a . g i f ) ;

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

205

25 26 27 28 29 30 31 32 33 34 35 36

try { r e s . setContentType ( image / g i f ) ; F i l e s . copy ( path , out ) ; } catch ( E x c e p t i o n e ) { r e s . setContentType ( t e x t / p l a i n ) ; System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; out . p r i n t l n ( C e r e r e a d v o a s t r a nu p o a t e f i } out . c l o s e ( ) ; } }

satisfacuta );

Pe calculatorul serverului Web, imaginea se salveaz a ntr-un sier grac, dup a care servlet-ul scrie n uxul de ie sire un document html cu o leg atur a (link) c atre sierul cu imaginea creat a anterior. Navigatorul clientului va desc arca si vizualiza imaginea. Dac a tipul sierului grac este jpg sau png atunci textul surs a al servletului este:

1 2 3 4 5 6 7 8 10 11 12 13 14 15 17 19 21 22 23 24 25 26 27 29 30 31 32 33

package g r a p h j p g ; import j a v a . i o . IOException ; import j a v a . i o . P r i n t W r i t e r ; import j a v a . i o . F i l e ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import import import import import import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a x . i m a g e i o . ImageIO ; j a v a . awt . Frame ; j a v a . awt . Font ; j a v a . awt . G r a p h i c s ; j a v a . awt . image . B u f f e r e d I m a g e ;

@WebServlet ( u r l P a t t e r n s = / g r a p h j p g ) public c l a s s MyGraphP extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; r e s . setContentType ( t e x t / html ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ; S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ; S t r i n g f i l e R e f=pathTomcat+f s+ webapps +f s+c o n t e x t P a t h+f s ; S t r i n g numeFis= d e s e n ; S t r i n g e x t= j p g ; // sau png // Formarea i m a g i n i i Frame frame = n u l l ;

206

CAPITOLUL 9. SERVLET

34 35 36 37 38 39 40 41 42 43 44 46 48 49 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

Graphics g = null ; B u f f e r e d I m a g e image=n u l l ; try { frame = new Frame ( ) ; frame . a d d N o t i f y ( ) ; image = ( B u f f e r e d I m a g e ) frame . c r e a t e I m a g e ( 8 0 0 , 6 0 ) ; g = image . g e t G r a p h i c s ( ) ; // F i x a r e a f o n t u l u i g . s e t F o n t ( new Font ( S e r i f , Font . ITALIC , 4 8 ) ) ; // E d i t a r e a unui t e x t g . d r a w S t r i n g ( T e h n o l o g i i d i s t r i b u i t e i n Java , 1 0 , 5 0 ) ; // S a l v a r e a i m a g i n i i i n t r un f i s i e r j p g sau png F i l e f=new F i l e ( f i l e R e f+numeFis+ . +e x t ) ; ImageIO . w r i t e ( image , j p g , f ) ; // Raspunsul c a t r e c l i e n t out . p r i n t l n ( <HTML >< BODY > ) ; out . p r i n t l n ( <h2>Imagine p r e l u a t a de pe s e r v e r </h2> ) ; out . p r i n t l n ( <p><a h r e f =\ h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / + numeFis+ . +e x t+ \> ) ; out . p r i n t l n ( V i z u a l i z a r e a i m a g i n i i </a> ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } finally { // E l i b e r a r e a r e s u r s e l o r i f ( g != n u l l ) g . d i s p o s e ( ) ; i f ( frame != n u l l ) frame . r e m o v e N o t i f y ( ) ; } } }

Dac a tipul sierului grac va gif atunci linia 34 se nlocuie ste cu


FileOutputStream fos=new FileOutputStream(f); Acme.JPM.Encoders.GifEncoder encoder = new Acme.JPM.Encoders.GifEncoder(image,fos); encoder.encode();

Clasa GifEncoder care realizeaz a codarea, face parte din pachetul Acme.JPM.Encoders, disponibil gratuit la adresa web http://www.acme.com.

9.5.8

Servlet cu RMI

Un servlet poate client al unei aplicat ii RMI. Interfat a la diatant a se depune n catalogul WEB-INF\lib al servlet-ului. Apelarea programului server RMI se face prin InterfataDistanta obj=(InterfataDistanta) Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

207

Exemplul 9.5.7 Client servlet pentru aplicat ia RMI de calcul al celui mai mare divizor comun a dou a numere naturale.
1 2 3 4 5 6 7 9 10 12 13 14 15 17 18 19 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 43 44 45 46 47

import import import import import import import

java . io . ; j a v a . rmi . ; j a v a . rmi . r e g i s t r y . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; cmmdc . ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

@WebServlet ( u r l P a t t e r n s = / s e r v l e t r m i ) public c l a s s ServletRMI extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; long m=(new Long ( sm ) ) . l o n g V a l u e ( ) , n=(new Long ( sn ) ) . l o n g V a l u e ( ) ; long x =0; S t r i n g h o s t=r e q . g e t P a r a m e t e r ( h o s t ) . t r i m ( ) ; S t r i n g s P o r t=r e q . g e t P a r a m e t e r ( p o r t ) ; i n t p o r t=I n t e g e r . p a r s e I n t ( s P o r t ) ; try { ICmmdc o b j =(ICmmdc) Naming . l o o k u p ( // +h o s t+ : +p o r t+ /CmmdcServer ) ; x=o b j . cmmdc(m, n ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( CmmdcClient e x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } S t r i n g t i t l e = CmmdcServlet ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

9.5.9

Servlet cu JMS

De data aceasta cererea clientului se rezolva asincron:

208

CAPITOLUL 9. SERVLET

In prima faz a se apeleaz a un servlet care apeleaz a un server JMS. Solut ia este ret inut a de furnizorul serviciului de mesagerie pe o destinat ie cu un subiect furnizat de client. Pentru reg asirea rezultatului, servlet-ul creaz a clientului un abonament durabil, funct ie de numele subiectului. In faza a doua, clientul apeleaz a un alt servlet, a c arei funct ie este preluarea rezultatului. Clientul trebuie sa furnizeze subiectul destinat iei rezultatului. Exemplul 9.5.8 Codul serverului JMS
1 2 3 5 7 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

import j a v a x . jms . ; import j a v a . i o . ; import j a v a . u t i l . S t r i n g T o k e n i z e r ; public c l a s s MsgCmmdcServer {

long cmmdc( long m, long n ) { . . . } public void s e r v i c e ( ) { try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n tDate=s e s s i o n . c r e a t e T o p i c ( Cmmdc ) ; T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ; conn . s t a r t ( ) ; TextMessage txtMsg=n u l l ; S t r i n g sm= , sn= , t o p i c= ; while ( true ) { txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ; S t r i n g msg=txtMsg . g e t T e x t ( ) ; S t r i n g [ ] s t=msg . s p l i t ( ) ; sm=s t [ 0 ] ; sn=s t [ 1 ] ; t o p i c=s t [ 2 ] ; System . out . p r i n t l n ( sm+ : +sn+ : +t o p i c ) ; long a=Long . par se Lon g ( sm ) ; long b=Long . pa rs eL ong ( sn ) ; long c=cmmdc( a , b ) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ; MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( t R e s u l t ) ; txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( ( new Long ( c ) ) . t o S t r i n g ( ) ) ;

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

209

43 44 45 46 47 48 49 50 51 53 54 55 56 57

p r o d u c e r . send ( txtMsg ) ; System . out . p r i n t l n ( E x p e d i a t r a s p u n s ) ; } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } System . out . p r i n t l n ( S e r v e r f i n i s h e d ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ; server . service (); } }

Codul servlet-ului care transmite datele problemei serverului JMS


1 2 3 4 5 6 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

package jms ; import j a v a x . jms . ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / s e n d e r ) public c l a s s J M S S e n d e r S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; String m =r e q . g e t P a r a m e t e r ( m ) ; S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ; S t r i n g t o p i c=r e q . g e t P a r a m e t e r ( t o p i c ) ; S t r i n g c l i e n t I D=r e q . g e t P a r a m e t e r ( c l i e n t I D ) ; S t r i n g c l i e n t N a m e=r e q . g e t P a r a m e t e r ( c l i e n t N a m e ) ; try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; conn . s e t C l i e n t I D ( c l i e n t I D ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ; T o p i c S u b s c r i b e r consumer= s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ; D e s t i n a t i o n t = s e s s i o n . c r e a t e T o p i c ( Cmmdc ) ; MessageProducer p r o d u c e r = s e s s i o n . c r e a t e P r o d u c e r ( t ) ; TextMessage txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; S t r i n g mesaj= m + +n+ +t o p i c ;

210

CAPITOLUL 9. SERVLET

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 60 61 62 63

txtMsg . s e t T e x t ( mesaj ) ; p r o d u c e r . send ( txtMsg ) ; session . close (); conn . c l o s e ( ) ; out . p r i n t l n ( <html><body b g c o l o r=\#c c b b c c \>< c e n t e r > ) ; out . p r i n t l n ( <h1> JSP Cmmdc </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( D a t e l e au f o s t e x p e d i a t e s e r v e r u l u i ) ; out . p r i n t l n ( </ c e n t e r ></body ></html> ) ; } catch ( E x c e p t i o n e ) { out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } out . c l o s e ( ) ; System . out . p r i n t l n ( P u b l i s h e r f i n i s h e d ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Codul servlet-ului care preia rezultatul


1 2 3 4 5 6 8 9 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31 32 33 34

package jms ; import j a v a x . jms . ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / r e c e i v e r ) public c l a s s J M S R e c e i v e r S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; S t r i n g t o p i c=r e q . g e t P a r a m e t e r ( t o p i c ) ; S t r i n g c l i e n t I D=r e q . g e t P a r a m e t e r ( c l i e n t I D ) ; S t r i n g c l i e n t N a m e=r e q . g e t P a r a m e t e r ( c l i e n t N a m e ) ; try { // V a r i a n t a ApacheMessageQueue // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f= // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory ( // tcp :// l o c a l h o s t :61616); // V a r i a n t a Oracle Sun MessageQueue com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ; // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ; // c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ; conn . s e t C l i e n t I D ( c l i e n t I D ) ; T o p i c S e s s i o n s e s s i o n= conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ; Destination tResult = session . createTopic ( topic ) ; T o p i c S u b s c r i b e r consumer=

I DE PROGRAMARE CU SERVLET 9.5. FACILITAT

211

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 54 55 56 57 58

s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ; conn . s t a r t ( ) ; TextMessage txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ; S t r i n g cmmdc=txtMsg . g e t T e x t ( ) ; session . close (); conn . c l o s e ( ) ; out . p r i n t l n ( <html><body b g c o l o r=\#c c b b c c \>< c e n t e r > ) ; out . p r i n t l n ( <h1> JSP Cmmdc </h1> ) ; out . p r i n t l n ( <p> ) ; out . p r i n t l n ( R e z u l t a t u l o b t i n u t : +cmmdc ) ; out . p r i n t l n ( </ c e n t e r ></body ></html> ) ; } catch ( E x c e p t i o n e ) { out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } out . c l o s e ( ) ; System . out . p r i n t l n ( S u b s c r i b e r f i n i s h e d ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

In catalogul lib al servlet-ului trebuie incluse sierele jar ale serviciului JMS folosit.

9.5.10

Servlet cu jurnalizare

Exemplul 9.5.9 Servlet cu jurnalizare. Fi sierul log se va aa n catalogul aplicat iei si va oferit clientului spre consultare.
1 2 3 4 5 6 7 8 9 10 11 13 15 17 18 20 21 22

package l o g t e s t ; import j a v a . i o . IOException ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a . u t i l . l o g g i n g . Logger ; import j a v a . u t i l . l o g g i n g . F i l e H a n d l e r ; import j a v a . u t i l . l o g g i n g . S i m p l e F o r m a t t e r ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / l o g g i n g ) public c l a s s L o g g e r S e r v l e t extends H t t p S e r v l e t { private s t a t i c Logger l o g g e r=Logger . g e t L o g g e r ( l o g t e s t . L o g g e r S e r v l e t ) ; public void i n i t ( ) { try { F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( webapps / l o g g e r / r e s u l t s . l o g ) ;

212

CAPITOLUL 9. SERVLET

23 24 25 26 27 28 29 31 32 33 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 52 53 54 55 56

l o g g i n g F i l e . s e t F o r m a t t e r ( new S i m p l e F o r m a t t e r ( ) ) ; l o g g e r . addHandler ( l o g g i n g F i l e ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException { S t r i n g f i l e S e p = System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . warning ( WARN : H e l l o ) ; l o g g e r . s e v e r e ( ERROR : H e l l o ) ; r e s . setContentType ( t e x t / html ) ; j a v a . i o . P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ; out . p r i n t l n ( <html><head>< t i t l e > S e r v l e t l o g g i n g </ t i t l e ></head><body> ) ; out . p r i n t l n ( <h2> H e l l o from L o g g e r S e r v l e t </h2> ) ; out . p r i n t l n ( <br/> ) ; out . p r i n t l n ( <a h r e f =\ h t t p : / / + r e q . getServerName ()+ : + r e q . g e t L o c a l P o r t ()+ f i l e S e p+ l o g g e r +f i l e S e p+ r e s u l t s . l o g \> V i z u a l i z a t i f i s i e r u l l o g </a> ) ; out . p r i n t l n ( </body ></html> ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException { doGet ( req , r e s ) ; } }

9.6

FileUpload

Deseori clientul trebuie s a furnizeze unui servlet un volum mare de date, depozitate ntr-un sier. Un produs care ne ajut a s a ndeplinim acest obiectiv este commons-leupload - dezvoltat de apache. Commons-FileUpload - dezvoltat n cadrul apache - este un produs care simplic a transferul unui sier de la un client la programul server (le upload). Interfat a de programare a produsului se refer a la partea de server - n cazul de fat a reprezentat prin servlet. Instalarea produsului const a din dezarhivarea sierului desc arcat din Internet. In plus este nevoie de commons-io

9.6. FILEUPLOAD

213

Fi sierele commons-leupload-*.*.jar commons-io-*.*.jar se depun n catalogul lib al servlet-ului. Transferarea unui sier, din partea clientului nu ridic a nici o problem a. In sierul html de apelare, se dene ste un formular <form action=. . . enctype="multipart/form-data" method="post"> iar un sier de nc arcat se xeaz a prin intermediul marcajului <input type="file" name=. . . size=. . .> Programul navigator a seaz a o fereastr a de c autare, prin care clientul selecteaz a sierul pe care dore ste s a-l ncarce. Dac a partea de client este un program, atunci se utilizeaz a commonshttpclient, 9.5.1 De partea de server punem n evident a dou a sabloane de programare: Fi sierele nc arcate sunt ret inute naintea utiliz arii. Datele sierelor se utilizeaz a n ux, n momentul parvenirii lor. In primul caz, programarea nc arc arii revine la 1. Crearea unei fabrici pentru manipularea sierelor pe disc FileItemFactory factory = new DiskFileItemFactory(); 2. Crearea unei unelte de nc arcare ServletFileUpload upload = new ServletFileUpload(factory);

3. Analiza (parsarea) mesajului furnizat de client List fileItems = upload.parseRequest(req);

214

CAPITOLUL 9. SERVLET

Fiecare element al listei implementeaz a interfat a FileItem. Se pot xa parametrii dimensiunea zonei de pe disc destinat a datelor de nc arcat DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemorySize); catalogul temporar de ret inere a datelor de nc arcat factory.setRepositoryPath(tempDirectory); sau direct DiskFileItemFactory factory = new DiskFileItemFactory( maxMemorySize, tempDirectory); dimensiunea maxim a a unui sier upload.setSizeMax(maxRequestSize); 4. Prelucrarea elementelor nc arcate Iterator iter=fileItems.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { // Prelucrarea elementului item care corespunde unei // date din formularul html care nu este de tip fisier } else{ // Prelucrarea elementului item de tip fisier } } 5. In cazul unui element care nu este de tip sier putem obt ine numele si valoarea atributului furnizat de client String name = item.getFieldName(); String value = item.getString(); 6. In cazul unui sier putem aa numele c ampului input, numele sierului, dimensiunea sierului

9.6. FILEUPLOAD

215

String fieldName = item.getFieldName(); String fileName = item.getName(); long sizeInBytes = item.getSize(); 7. Dac a dorim s a salv am sierul pe calculatorul server atunci prelucrarea este File uploadedFile = new File(...); item.write(uploadedFile); 8. Dac a datele sierului se ncarc a n memoria calculatorului atunci prelucrarea este InputStream in = item.getInputStream(); //preluarea datelor din fluxul in . . . in.close(); Alternativ, datele se pot ret ine ca un sir de octet i prin byte[] data = item.get(); Exemplul 9.6.1 S a se obt in a n memoria serverului matricea cont inut a ntr un sier text. In sierul text, ecare linie cont ine o linie a matricei, iar elementele sunt separate prin spat ii. Metoda getMatrix utilizat a va reface matricea din datele sierului.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

package u pl oa d ; import j a v a . i o . IOException ; import j a v a . i o . InputStream ; import j a v a . i o . InputStreamReader ; import j a v a . i o . B u f f e r e d R e a d e r ; import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ; import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ; import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; import j a v a . u t i l . L i s t ; import j a v a . u t i l . I t e r a t o r ; import j a v a . u t i l . V e c t o r ; import o r g . apache . commons . f i l e u p l o a d . d i s k . D i s k F i l e I t e m F a c t o r y ; import o r g . apache . commons . f i l e u p l o a d . s e r v l e t . S e r v l e t F i l e U p l o a d ; import o r g . apache . commons . f i l e u p l o a d . F i l e I t e m F a c t o r y ; import o r g . apache . commons . f i l e u p l o a d . F i l e I t e m ;

216

CAPITOLUL 9. SERVLET

20 21 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

@WebServlet ( u r l P a t t e r n s = / u pl o ad ) public c l a s s F i l e U p l o a d S e r v l e t extends H t t p S e r v l e t { public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / p l a i n ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; try { F i l e I t e m F a c t o r y f a c t o r y = new D i s k F i l e I t e m F a c t o r y ( ) ; ServletFileUpload up lo ad = new S e r v l e t F i l e U p l o a d ( f a c t o r y ) ; L i s t i t e m s = up l oad . p a r s e R e q u e s t ( r e q ) ; u pl oa d . s e t S i z e M a x ( 1 0 0 0 0 0 0 ) ; I t e r a t o r i t e r=i t e m s . i t e r a t o r ( ) ; while ( i t e r . hasNext ( ) ) { F i l e I t e m item = ( F i l e I t e m ) i t e r . n e x t ( ) ; i f ( ! item . i s F o r m F i e l d ( ) ) { S t r i n g f i l e N a m e = item . getName ( ) ; out . p r i n t l n ( f i l e N a m e ) ; long s i z e I n B y t e s = item . g e t S i z e ( ) ; out . p r i n t l n ( s i z e I n B y t e s ) ; InputStream i n=item . g e t I n p u t S t r e a m ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; double [ ] [ ] m a t r i x=g e t M a t r i x ( br ) ; int m =m a t r i x . l e n g t h ; i n t n=m a t r i x [ 0 ] . l e n g t h ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++) out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; out . p r i n t l n ( ) ; } br . c l o s e ( ) ; isr . close (); in . close ( ) ; out . c l o s e ( ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private double [ ] [ ] g e t M a t r i x ( B u f f e r e d R e a d e r br ) throws E x c e p t i o n { Vector <Double > v=new Vector <Double > ( 1 0 ) ; double [ ] [ ] m a t r i x=n u l l ; try { String line , s ; i n t m=0 ,n , mn ; do { l i n e=br . r e a d L i n e ( ) ; i f ( l i n e != n u l l ) { m++; S t r i n g [ ] s t=l i n e . s p l i t ( ) ; for ( S t r i n g s : s t ){ v . addElement ( new Double ( s ) ) ; } } }

9.6. FILEUPLOAD

217

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

while ( l i n e != n u l l ) ; i f ( v . s i z e () > 0) { mn=v . s i z e ( ) ; n=mn/m; m a t r i x=new double [m ] [ n ] ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++){ m a t r i x [ i ] [ j ] = ( ( Double ) v . elementAt ( i n+j ) ) . d o u b l e V a l u e ( ) ; System . out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; } System . out . p r i n t l n ( ) ; } } } catch ( E x c e p t i o n e ) { throw new E x c e p t i o n ( e . g e t M e s s a g e ( ) ) ; } return m a t r i x ; } }

Pentru compilare se completeaz a variabila de sistem classpath cu referint a c atre sierul commons-fileupload-*.*.jar. Formularul clientului este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

<html> <head> < s c r i p t l a n g u a g e= j a v a s c r i p t > < ! function checkIt (){ var f i s =document . l i n e a r . m y f i l e . value ; i f ( f i s== ) { a l e r t ( S e l e c t a t i f i s i e r u l corespunzator matricei ); return f a l s e ; } return true ; } // > </ s c r i p t> </ head> <body> <h1> I n c &#259; r c a r e a unui f i &#351; i e r </ h1> <form method= p o s t action= u pl oa d e n c t y p e= m u l t i p a r t / form data name= l i n e a r onSubmit= r e t u r n c h e c k I t ( ) > <p> S e l e c t a &#355; i f i &#351; i e r u l <p> <input type= f i l e name= m y f i l e s i z e =30> <p> <input type= submit value= Expediaza f i s i e r u l > </ form> </ body> </ html>

In al doilea caz, codul pentru acela si exemplu este


1

package u pl oa d ;

218

CAPITOLUL 9. SERVLET

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 21 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 60

import import import import import import import import import import import import import import import import

j a v a . i o . IOException ; j a v a . i o . InputStream ; j a v a . i o . InputStreamReader ; java . i o . BufferedReader ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; java . u t i l . List ; java . u t i l . I t e r a t o r ; java . u t i l . Vector ; o r g . apache . commons . f i l e u p l o a d . s e r v l e t . S e r v l e t F i l e U p l o a d ; o r g . apache . commons . f i l e u p l o a d . F i l e I t e m I t e r a t o r ; o r g . apache . commons . f i l e u p l o a d . F i l e I t e m S t r e a m ;

@WebServlet ( u r l P a t t e r n s = / u pl o ad ) public c l a s s F i l e U p l o a d S e r v l e t extends H t t p S e r v l e t { public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / p l a i n ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; try { S e r v l e t F i l e U p l o a d up lo ad = new S e r v l e t F i l e U p l o a d ( ) ; F i l e I t e m I t e r a t o r i t e r = up l oad . g e t I t e m I t e r a t o r ( r e q ) ; while ( i t e r . hasNext ( ) ) { F i l e I t e m S t r e a m item = i t e r . n e x t ( ) ; S t r i n g name = item . getFieldName ( ) ; out . p r i n t l n ( name ) ; i f ( ! item . i s F o r m F i e l d ( ) ) { S t r i n g f i l e N a m e = item . getName ( ) ; out . p r i n t l n ( f i l e N a m e ) ; InputStream i n=item . openStream ( ) ; InputStreamReader i s r =new InputStreamReader ( i n ) ; B u f f e r e d R e a d e r br=new B u f f e r e d R e a d e r ( i s r ) ; double [ ] [ ] m a t r i x=g e t M a t r i x ( br ) ; int m =m a t r i x . l e n g t h ; i n t n=m a t r i x [ 0 ] . l e n g t h ; f o r ( i n t i =0; i < m; i ++){ f o r ( i n t j =0; j <n ; j ++) out . p r i n t ( m a t r i x [ i ] [ j ]+ ) ; out . p r i n t l n ( ) ; } br . c l o s e ( ) ; isr . close (); in . close ( ) ; out . c l o s e ( ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private double [ ] [ ] g e t M a t r i x ( B u f f e r e d R e a d e r br ) throws E x c e p t i o n { . . . }

9.7. DESCARCAREA UNUI FIS IER

219

62

9.7

Desc arcarea unui sier

Consider am cazul: Exemplul 9.7.1 Fi sierul ales de client dintr-o lista disponibil a este desc arcat ind transmis navigatorului.
1 2 3 4 5 6 7 8 9 10 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38

import import import import import import import import import import

j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a . n i o . f i l e . Path ; j a v a . n i o . f i l e . Paths ; java . nio . f i l e . F i l e s ;

@WebServlet ( u r l P a t t e r n s = / download ) public c l a s s D o w n l o a d S e r v l e t extends H t t p S e r v l e t { public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g f i l e =r e q . g e t P a r a m e t e r ( f i l e ) ; System . out . p r i n t l n ( f i l e ) ; Path c a l e=Paths . g e t ( webapps / download / r e s o u r c e s / + f i l e ) ; try { System . out . p r i n t l n ( c a l e+ f i l e ) ; r e s . setContentType ( A p p l i c a t i o n / Octet stream ) ; r e s . addHeader ( Content D i s p o s i t i o n , attachment ; f i l e n a m e=+ f i l e ) ; F i l e s . copy ( c a l e , out ) ; } catch ( E x c e p t i o n e ) { r e s . setContentType ( t e x t / p l a i n ) ; out . p r i n t l n ( C e r e r e a d v o a s t r a nu p o a t e f i s a t i s f a c u t a ) ; } out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

R andul 18 are ca efect p astrarea numelui si a extensiei pentru sierul selectat a se desc arca.

220

CAPITOLUL 9. SERVLET

9.8

Filtru

Un ltru se asemean a unui servlet, dar activitatea ntreprins a vizeaz a uzual context ul, adic a ansamblul servlet ilor care fac parte din aplicat ia Web. Un ltru se declar a n sierul web.xml prin <web-app> . . . <filter> <filter-name>nume_filtru</filter-name> <filter-class>clasa_filtrului</filter-class> </filter> <filter-mapping> <filter-name>nume_filtru</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> . . . </web-app> Clasa ltrului implementeaz a interfat a Filter, adic a metodele public void init(FilterConfig lterCong ) throws ServletException public void destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain lterChain ) throws IOException, ServletException Exemplul 9.8.1 Contextul myservlet cont ine doi servlet i HelloServlet si CmmdcServlet, apelabili respectiv din hello.html, cmmdc.html. S a se programeze un ltru care Redirecteaz a solicitarea /myservlet/hello c atre /cmmdc.html. Dac a se cere ca natura r aspunsului s a e text/xml atunci invalideaz a cererea. Servlet ii HelloServlet si CmmdcServlet sunt cei dezvoltat i la nceputul acestui capitol. Filtrul are codul

9.8. FILTRU

221

1 2 3 4 5 6 7 8 9 10 12 13 15 16 17 19 20 21 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

import import import import import import import import import import

j a v a . i o . IOException ; javax . s e r v l e t . ServletRequest ; javax . s e r v l e t . ServletResponse ; javax . s e r v l e t . RequestDispatcher ; javax . s e r v l e t . F i l t e r ; javax . s e r v l e t . F i l t e r C o n f i g ; javax . s e r v l e t . FilterChain ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ;

public c l a s s M y F i l t e r D i s p a t c h e r implements F i l t e r { private F i l t e r C o n f i g f i l t e r C o n f i g ; public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws S e r v l e t E x c e p t i o n { this . f i l t e r C o n f i g = f i l t e r C o n f i g ; } public void d e s t r o y ( ) { this . f i l t e r C o n f i g = null ; } public void d o F i l t e r ( S e r v l e t R e q u e s t r e q u e s t , S e r v l e t R e s p o n s e r e s p o n s e , F i l t e r C h a i n f i l t e r C h a i n ) throws IOException , S e r v l e t E x c e p t i o n { HttpServletRequest req = ( HttpServletRequest ) request ; HttpServletResponse res = ( HttpServletResponse ) response ; S t r i n g u r i = r e q . getRequestURI ( ) ; System . out . p r i n t l n ( F i l t e r URI= +u r i ) ; System . out . p r i n t l n ( u r i ) ; i f ( u r i . equals ( / myservlet ) | | u r i . equals ( / myservlet / ) ) f i l t e r C h a i n . doFilter ( request , response ) ; else { i f ( u r i . equals ( / myservlet / h e l l o )){ S t r i n g d i s p a t c h e r U r i= /cmmdc . html ; R e q u e s t D i s p a t c h e r rd=r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( d i s p a t c h e r U r i ) ; rd . f o r w a r d ( r e q u e s t , r e s p o n s e ) ; } else { i f ( u r i . e q u a l s ( / m y s e r v l e t /cmmdc ) ) { S t r i n g t i p=r e q . g e t P a r a m e t e r ( t i p ) ; i f ( t i p . e q u a l s ( t e x t /xml ) ) { r e s . s e n d E r r o r ( H t t p S e r v l e t R e s p o n s e . SC FORBIDDEN ) ; } } f i l t e r C h a i n . doFilter ( request , response ) ; } } } }

Fi sierul web.xml este


1 2 3 4 6

<? xml version= 1 . 0 e n c o d i n g=ISO 8859 1 ?> < !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp>

222

CAPITOLUL 9. SERVLET

7 8 9 10 12 13 14 15 16

< f i l t e r> < f i l t e r name> f i l t e r D i s p a t c h e r </ f i l t e r name> < f i l t e r c l a s s > M y F i l t e r D i s p a t c h e r</ f i l t e r c l a s s > </ f i l t e r > < f i l t e r mapping> < f i l t e r name> f i l t e r D i s p a t c h e r </ f i l t e r name> < u r l p a t t e r n>/ </ u r l p a t t e r n> </ f i l t e r mapping> </webapp>

Pentru nt elegerea aplicat iei prezent am si codul sierului cmmdc.html


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

<html> <head> < t i t l e> Cmmdc S e r v l e t </ t i t l e > </ head> <body bgcolor=#c c b b c c > <center> <h1> Cmmdc S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc> <table border= 1 > < tr> <td> Primul numar </ td> <td> <input type= t e x t name=m s i z e =10> </ td> </ tr> < tr> <td> Al d o i l e a numar </ td> <td> <input type= t e x t name=n s i z e =10> </ td> </ tr> < tr> <td> Natura r a s p u n s u l u i </ td> <td> < s e l e c t name= t i p > <option value= t e x t / html > t e x t / html <option value= t e x t / p l a i n > t e x t / p l a i n <option value= t e x t /xml> t e x t /xml </ s e l e c t> </ td> </ tr> < tr> <td> <input type= submit value= C a l c u l e a z a > </ td> <td></ td> </ tr> </ table> </ form> </ center> </ body> </ html>

Alternativ, sierul web.xml se poate elimina prin utilizarea adnot arilor:


. . . import javax.servlet.annotation.WebFilter; @WebFilter(filterName="MyFilterDispatcher",urlPatterns={"/cmmdc","/html"}) public class MyFilterDispatcher implements Filter {. . .}

9.9. EVENIMENT S I AUDITOR

223

9.9
n:

Eveniment si auditor

Tehnologia Servlet permite urm arirea si intervent ia de c atre serverul Web ciclul de viat a al unui servlet, prin interfat a javax.servlet.ServletContextListener evolut ia obiectului javax.servlet.http.HttpSession prin interfat a javax.servlet.http.HttpSessionListener Interfat a ServletContextListener declar a metodele void contextInitialized(ServletContextEvent sec ) void contextDestroyed(ServletContextEvent sec ) Interfat a HttpSessiontListener declar a metodele void sessionCreated(HttpSessionEvent hse ) void sessionDestroyed(HttpSessionEvent hse ) Clasa care implementeaz a una din aceste interfet e se declar a n sierul web.xml printr-un element <listener>> <listener> <listener-class> clasa_listener </listener-class> </listener> Exemplul 9.9.1 Auditor care sesizeaz a nc arcarea si disparit ia unui servlet a s and n fereastra DOS a serverului Web un mesaj.
1 2 3 5 6 7 8 9 10 11 12 13 14 15 16 17

import j a v a x . s e r v l e t . S e r v l e t C o n t e x t L i s t e n e r ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t E v e n t ; import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ; public c l a s s F i r s t C o n t e x t L i s t e n e r implements S e r v l e t C o n t e x t L i s t e n e r { public void c o n t e x t D e s t r o y e d ( S e r v l e t C o n t e x t E v e n t e v e n t ) { System . out . p r i n t l n ( Web app was removed . ) ; } public void c o n t e x t I n i t i a l i z e d ( S e r v l e t C o n t e x t E v e n t e v e n t ) { System . out . p r i n t l n ( Web app i s r e a d y . ) ; S e r v l e t C o n t e x t s c=e v e n t . g e t S e r v l e t C o n t e x t ( ) ; System . out . p r i n t l n ( s c . g e t C o n t e x t P a t h ( ) ) ; System . out . p r i n t l n ( s c . g e t E f f e c t i v e M a j o r V e r s i o n ( ) ) ; System . out . p r i n t l n ( s c . g e t E f f e c t i v e M i n o r V e r s i o n ( ) ) ; } }

224 Exemplul 9.9.2


1 2 4 5 7 8 9 10 11 12 13 14 15 16

CAPITOLUL 9. SERVLET

import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n L i s t e n e r ; import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n E v e n t ; public c l a s s F i r s t S e s s i o n L i s t e n e r implements H t t p S e s s i o n L i s t e n e r { static int u s e r s = 0 ; public void s e s s i o n C r e a t e d ( H t t p S e s s i o n E v e n t e ) { u s e r s ++; } public void s e s s i o n D e s t r o y e d ( H t t p S e s s i o n E v e n t e ) { u s e r s ; } public s t a t i c i n t g e t C o n c u r r e n t U s e r s ( ) { return u s e r s ; } }

9.10

Server apache-tomcat ncorporat

Intr-o clas a Java se poate ncorpora un server tomcat n care pot instalate una sau mai mult i servet i. Resursele necesare sunt cont inute n apache-tomcat*-embedded, iar sierele jar cont inute trebuie declarate n variabila de sistem classpath. S ablonul de programare este:
1 2 3 5 6 7 8 9 10 12 13 15 16 18 19 20 21 22 23 24 25

import o r g . apache . c a t a l i n a . s t a r t u p . Tomcat ; import o r g . apache . c a t a l i n a . Context ; import j a v a . i o . F i l e ; public c l a s s EmbeddedTomcat { public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { Tomcat tomcat = new Tomcat ( ) ; tomcat . s e t B a s e D i r ( . ) ; tomcat . s e t P o r t ( 9 0 9 0 ) ; // p o r t u l s e r v e r u l u i F i l e docBase = new F i l e ( . ) ; Context c t x t = tomcat . addContext ( / , docBase . g e t A b s o l u t e P a t h ( ) ) ; Tomcat . a d d S e r v l e t ( c t x t , n u m e S e r v l e t , new C l a s a S e r v l e t ( ) ) ; c t x t . a d d S e r v l e t M a p p i n g ( /numeApel , n u m e S e r v l e t ) ; tomcat . s t a r t ( ) ; tomcat . g e t S e r v e r ( ) . a w a i t ( ) ; } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }

9.10. SERVER APACHE-TOMCAT INCORPORAT

225

Intreb ari recapitulative


1. Precizat i sensurile si cont inutul cuv antului servlet. 2. Unde se instaleaz a o aplicat ie servlet n serverul Web apache-tomcat ? 3. Cum se poate apela aplicat ia servlet si, dar servlet-ul propriu zis? 4. Extinz and clasa HttpServlet, ce trebuie s a fac a programatorul? 5. Care sunt modurile de programare a unui servlet si precizat i diferent a dintre ele. 6. Care sunt sarcinile de indeplinit n metoda doGet ?

226

CAPITOLUL 9. SERVLET

Capitolul 10 Java Server Page JSP


10.1 Tehnologia JSP

Tipul tehnologiei JSP este denumit procesare de sabloane (template engine). JSP este o tehnologie similar a cu PHP, ASP.NET, apache-velocity, etc. JSP permite includerea de cod Java ntr-un document html. Un asemenea document se depoziteaz a ntr-un server Web, container de servlet, cu extensia jsp, eventual jspx. Apelarea documentului JSP se realizeaz a prin meniul File/Open a unui navigator, cu http://host:port/cale/doc.jsp referint a html <a href="http://host:port/cale/doc.jsp"> valoare a atributului action ntr-un marcaj form <form action="http://host:port/cale/doc.jsp" ... >

Prin cale se nt elege calea de la catalogul webapps p an a la catalogul ce cont ine sierul jsp. Vom depozita sierele JSP ntr-un catalog jsp din arborele webapps |--> JSPApp | |--> WEB-INF | | |--> classes | | | web.xml 227

228 | | |--> jsp | |

CAPITOLUL 10. JAVA SERVER PAGE JSP

doc.jsp

caz n care cale=JSPApp/jsp. Astfel, schimb and numele sierului Hello.html


1 2 3 4 5

<html> <body> Hello </ body> </ html>

n Hello.jsp si plas andu-l n catalogul jsp se obt ine acela si efect, dar prelucrarea paginilor / documentelor este diferit a. Fi sierul html este prelucrat doar de programul navigator si poate deschis ca sier, n timp ce sierul JSP este prelucrat de serverul Web cu a sarea prin intermediul navigatorului. Prelucrarea efectuat a de serverul Web const a din transformarea paginii / documentului JSP ntr-un servlet, care este compilat si lansat n execut ie. Din aceastr a cauz a prima invocare a paginii / documentului JSP dureaz a mai mult dec at apel arile ulterioare. Fi sierul JSP poate construit pe un document xhtml, av and preambulul <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> sau document html 5. In acest caz preambulul este <!doctype html> Apelarea paginii / documentului JSP se face prin jsp/Hello.jsp Exist a dou a moduri de a include elemente JSP ntr-un text html: prin elemente specice JSP. Fi sierul are extensia jsp si se nume ste pagin a JSP. prin elemente xml apart in and spat iului de nume http://java.sun.com/JSP/Page Fi sierul poate avea extensia jsp sau jspx si se nume ste document JSP. Comentariile JSP se scriu de forma <%-- Comentariu --%>

10.1. TEHNOLOGIA JSP

229

Consider am urm atorul exemplu introductiv: Exemplul 10.1.1 Putem a sa valoarea unei variabile Java (de exemplu data calendaristic a) prin Varianta paginii JSP
1 2 3 4 5 7 8 9 10 12 13 14 15 16 17

<html> <body> <p> Data c a l e n d a r i s t i c a 1 : < %= new j a v a . u t i l . Date ( ) % > <p> <% j a v a . u t i l . Date data1=new j a v a . u t i l . Date ( ) ; % > Data c a l e n d a r i s t i c a 2 : < %= data1 % > <p> <% j a v a . u t i l . Date data2=new j a v a . u t i l . Date ( ) ; % > Data c a l e n d a r i s t i c a 3 : <% out . p r i n t ( data2 ) ; % > </ body> </ html>

Dac a se utilizeaz a operatorul de a sare = atunci dup a expresia de a sat nu se pune ;. Variabila predenit a out este de tip javax.servlet.jsp.JspWriter. Varianta documentului JSP
1 2 3 4 5 6 7 8 9

<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?> <html xmlns : j s p= h t t p : / / j a v a . sun . com/JSP/ Page > <body> <j s p : s c r i p t l e t> j a v a . u t i l . Date d=new j a v a . u t i l . Date ( ) ; </ j s p : s c r i p t l e t > < j s p : e x p r e s s i o n> d </ j s p : e x p r e s s i o n> </ body> </ html>

Codul Java nglobat ntr-un text html se nume ste scriptlet. Sintaxa utilizat a este Varianta paginii JSP <% cod Java %>

230 Varianta documentului JSP

CAPITOLUL 10. JAVA SERVER PAGE JSP

<jsp:scriptlet> codJava </jsp:scriptlet> Domeniul de valabilitate. Domeniul de valabilitate dene ste intervalul de timp, de existent a al unui obiect, ind denit prin valorile: Valoare page request Domeniu de valabilitate pagina curent a n pagina curent a, n paginile incluse si n paginile c atre care se face o redirectare session n sesiunea curent a application pe durata rul arii aplicat iei In orice pagin a Variabila out request response session page pageContext application exception Astfel String request.getParameter(String numeParametru ) furnizeaz a valoarea parametrului numeParametru dintr-un formular html. Exemplul 10.1.2 Pagina JSP Hello: Clientul transmite numele paginii care i r aspunde cu mesajul de salut Hi + nume + !. Codul paginii JPS (hello.jsp ) este
1 2 3 4 5

/ document JSP sunt predenite obiectele: Tip/Clasa javax.servlet.jsp.JspWriter javax.servlet.ServletRequest javax.servlet.ServletResponse javax.servlet.http.HttpSession java.lang.Object, this javax.servlet.jsp.PageContext javax.servlet.ServletContext ServletContext.getServletCong().getContext() java.lang.Throwable

<html> <head> < t i t l e > j s p h e l l o </ t i t l e > </ head> <body>

10.1. TEHNOLOGIA JSP

231

6 7 8 9 10 11 12 13 14

<center> <h1> Pagina de r &#259; spuns </ h1> <p> <% out . p r i n t l n ( Hi +r e q u e s t . g e t P a r a m e t e r ( name)+ ! ) ; % > </ center> </ body> </ html>

apelat din (index.html )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

<html> <head> < t i t l e > JSP H e l l o </ t i t l e > </ head> <body bgcolor=#bbeebb > <center> <h1> Pagina de a p e l a r e JSP </ h1> <form method= p o s t action= j s p / h e l l o . j s p > <p> Numele : <input type= t e x t name=name s i z e =20> <p> <input type= submit > </ form> </ center> </ body> </ html>

Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui apache-ant. In acest scop se creaz a structura:
jsphello | |--> src | |--> web | | | |--> jsp | | | | hello.jsp | | |--> WEB-INF | | | |--> classes | | | |--> lib | | | | web.xml | | | index.html

Fi sierul web.xml este simplu


1 2 3 5 6 7 8 9 11 12

< p r o j e c t b a s e d i r= . default= g e n e r a t e . war > < p r o p e r t y name= d i s t . name v a l u e=JSPApp /> < p r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r=web/WEB INF/ l i b > < i n c l u d e name= . j a r /> </ f i l e s e t > </ path> < t a r g e t name= i n i t > < d e l e t e d i r= $ { d i s t . d i r } />

232
< d e l e t e d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r=web/WEB INF/ c l a s s e s /> <mkdir d i r= $ { d i s t . d i r } /> </ t a r g e t> < t a r g e t name= c o m p i l e depends= i n i t > < j a v a c c l a s s p a t h r e f= m y c l a s s p a t h s r c d i r= s r c d e s t d i r=web/WEB INF/ c l a s s e s i n c l u d e a n t r u n t i m e= f a l s e /> </ t a r g e t>

CAPITOLUL 10. JAVA SERVER PAGE JSP

13 14 15 16 18 19 20 21 22 23 25 26 27 28

< t a r g e t name= g e n e r a t e . war depends= c o m p i l e > < j a r d e s t f i l e = $ { d i s t . d i r } /$ { d i s t . name } . war b a s e d i r=web /> </ t a r g e t> </ p r o j e c t>

10.1.1

Declarat ii JSP

Printr-o declarat ie JSP, putem deni c ampuri(variabile) si metode Java ce pot apoi folosite, respectiv apelate n documentul respectiv. O declarat ie JSP se dene ste printr-un marcaj <%! . . . %> sau, n format XML <jsp:declaration> . . . </jsp:declaration> Exemplul 10.1.3 Calculul celui mai mare divizor comun a dou a numere naturale cu metoda de calcul este denit a ntr-o declarat ie JSP. Pagina JSP a aplicat iei cmmdc.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

<html> <body> <H1 > CMMDC </H1 > <%! l o n g cmmdc( l o n g m, l o n g n ) { . . . } % > Rezultatul este <% String sm=r e q u e s t . g e t P a r a m e t e r ( m ) ; String sn=r e q u e s t . g e t P a r a m e t e r ( n ) ; long m =Long . pa rse Lo ng ( sm ) , n=Long . pa rse Lo ng ( sn ) ; out . p r i n t l n (cmmdc(m, n ) ) ; % > </ body> </ html>

apelat din documentul cmmdc.html

10.1. TEHNOLOGIA JSP

233

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

<html> <body> <h1> C a l c u l u l Cmmdc </ h1> <form method= p o s t action= j s p /cmmdc . j s p > <p> Primul numar e s t e <input type= t e x t name=m value= s i z e =5> <p> Al d o i l e a numar e s t e <input type= t e x t name=n value= s i z e =5> <p> <input type= submit value= C a l c u l e a z a > <input type= r e s e t value=Abandon> </ form> </ body> </ html>

Exist a dou a metode jspInit() si jspDestroy() care dac a sunt declarate de programator atunci sunt executate la nceputul si la sf ar situl ciclului de viat a a paginii / documentului JSP. Exemplul 10.1.4 Metoda jspInit init ializeaz a un num ar cu 0 iar metoda jspDestroy a seaz a num arul pe calculatorul serverului. Un client introduce un num ar care este adunat la cel ret inut de pagina JSP. Efectul metodei jspDestroy are loc n urma opririi aplicat iei JSP. Codul paginii JSP este
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

<html> <head> < t i t l e > I n i t </ t i t l e > </ head> <body> <%! i n t numar ; public void j s p I n i t (){ numar=0; } public void jspDestroy (){ System . out . p r i n t l n ( numar ) ; } % > <center> <h1> Pagina de r &#259; spuns </ h1> <p> <% String sn=r e q u e s t . g e t P a r a m e t e r ( numar ) ; i n t n=I n t e g e r . p a r s e I n t ( sn ) ; numar+=n ; out . p r i n t l n ( Numarul e s t e : +numar ) ; % > </ center> </ body> </ html>

234

CAPITOLUL 10. JAVA SERVER PAGE JSP

10.1.2

Directive JSP

Directivele JSP xeaz a informat ii pentru tot documentul jsp. O directiv a jsp se indic a prin marcajul <%@ directiv a atribut1 atribut2 . . . %> sau n format XML <jsp:directive.directiva atribut1 atribut2 . . . /> unde ecare atribut are sintaxa nume=valoare. Directivele pot : page, include, taglib. Directiva page. Ment ion am atributele list a de pachete separate prin , text Informat ia se poate reg asi apel and metoda getServletInfo() errorPage= adresa url a paginii ce trateaz a except ia isErrorPage= "true | false" import= info= Directiva include permite includerea unor siere .html sau .jsp n document <%@ include file= sier html, jsp %> Includerea are loc n locul n care apare directiva. Referint a la sierul html sau jsp se face relativ la catalogul paginii JSP init iale (adic a cea n care apare directiva). Directiva taglib indic a bibliotecile de marcaje utilizate n documentul jsp, av and atributele uri= uri - Universal Resource Identier - a bibliotecii de marcaje prefix= prexul marcajului

10.1.3

Marcaje JSP predenite

Un marcaj JSP dene ste o act iune care se execut a n timpul proces arii paginii jsp. Sintaxa marcajelor JSP seam an a cu cea a marcajelor html sau xml <prefix : marcaj atribute />

10.1. TEHNOLOGIA JSP

235

Dintre marcajele JSP predenite adic a cu prexul JSP amintim: <jsp : <jsp : include page=numeFi sier jsp sau html /> forward page=numeFi sier jsp sau html />

Prelucrarea care urmeaz a va cea din sierul ment ional. Diferent a dintre cele dou a elemente const a n faptul c a include prevede revenirea n pagina JSP init ial a iar forward nu. Referint a la sierul html sau jsp se face relativ la catalogul paginii JSP init iale. In cazul marcajelor <jsp: include>, <jsp: forward> se pot transmite parametri prin marcajele incluse <jsp:param name="nume " value=valoare "/> sau <jsp:params> <jsp:param name="nume " value=valoare "/> . . . . . . </jsp:params> <jsp : useBean id=numeComponent aJava class=numeClasa scope=domeniu />

unde domeniu precizeaz a domeniul de valabilitate al componentei Java, adic a page, request, session, application. Creaz a un obiect numeComponent aJava de tip numeClasa av and domeniul de valabilitate dat a de domeniu. <jsp : setProperty name=numeComponent aJava property=numeProp value=valoare />

Acest marcaj este echivalent cu codul Java numeComponent aJava .setNumeProp(valoare). <jsp : setProperty name=numeComponent aJava property="*" /> vizeaz a toate propriet a tile componentei Java, xarea valorilor f ac anduse cu datele unui formular. Numele parametrilor din formularele de introducere a datelor trebuie s a coincid a cu identicatorii c ampurilor din componenta Java corespunz atoare.

236 <jsp :

CAPITOLUL 10. JAVA SERVER PAGE JSP

getProperty name=numeComponent aJava property=numeProp />

Preia si a seaz a valoarea c ampului numeComponent aJava.numeProp.

10.1.4

Pagini JSP cu componente Java

Clasa componentei Java care se va utiliza ntr-o pagin a JSP trebuie inclus a ntr-un pachet. Relu am exemplul 10.1.2 cu o component a Java corespunz atoare numelui din formularul index.html. Exemplul 10.1.5
1 2 3 4 5 6 7 8 9 10

package j s p ; public c l a s s H e l l o B e a n { private S t r i n g name= ; public S t r i n g getName ( ) { return name ; } public void setName ( S t r i n g name ) { t h i s . name=name ; } }

In acest caz, pagina JSP este (hello.jsp )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

< j s p : useBean id= o b j c l a s s= j s p . H e l l o B e a n scope= r e q u e s t /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <head> < t i t l e > j s p h e l l o </ t i t l e > </ head> <body> <h1> Pagina de r &#259; spuns </ h1> <center> <% out . p r i n t l n ( Hi +o b j . getName ()+ ! ) ; % > </ center> </ body> </ html>

Mai mult, se poate include formularul n pagina JSP, bine nt eles sterg andu-l din sierul html:
1 2 3 4 5 6

< j s p : useBean id= o b j c l a s s= j s p . H e l l o B e a n scope= r e q u e s t /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <head> < t i t l e > j s p h e l l o </ t i t l e > </ head>

10.1. TEHNOLOGIA JSP

237

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

<body> <center> <h1> Pagina JSP a p l i c a &#355; i a H e l l o </ h1> <form method= p o s t > <p> <h3> I n t r o d u c e t i numele : </ h3> <input type= t e x t name=name s i z e =20> <p> <input type= submit > </ form> <p> <% out . p r i n t l n ( Hi +o b j . getName ()+ ! ) ; % > </ center> </ body> </ html>

Exemplul 10.1.6 Pagin a JSP pentru calculul celui mai mare divizor comun cu metoda de calcul denit a ntr-o component a Java. Utiliz and documentului html din Exemplul 10.1.3 se dene ste componenta Java
1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 26 28

package cmmdc ; public c l a s s CmmdcBean { private S t r i n g m = ; private S t r i n g n= ; private S t r i n g cmmdc ; public void setM ( S t r i n g m) { t h i s .m = m; } public void setN ( S t r i n g n ) { t h i s . n=n ; } public S t r i n g getM ( ) { return m; } public S t r i n g getN ( ) { return n ; } public S t r i n g getCmmdc ( ) { long a=Long . par se Lon g (m) ; long b=Long . p ars eL ong ( n ) ; return ( new Long (cmmdc( a , b ) ) ) . t o S t r i n g ( ) ; } long cmmdc( long m, long n ) { . . . } }

Instant iem o componenta Java si i x am propriet a tile (adic a i transmitem parametri problemei) dup a care apel am metoda ce calculeaz a rezultatul dorit n pagina JSP:

238

CAPITOLUL 10. JAVA SERVER PAGE JSP

1 2 3 4 5 6 7 8 9 10

< j s p : useBean id= o b j c l a s s=cmmdc . CmmdcBean scope= a p p l i c a t i o n /> < j s p : s e t P r o p e r t y name= o b j p r o p e r t y= /> <html> <body> Cel mai mare d i v i z o r comun a l n u m e r e l o r <p> < %=o b j . getM ( ) % > si < %=o b j . getN ( ) % > este < %=o b j . getCmmdc ( ) % > </ body> </ html>

Exemplul 10.1.7 Generarea unei except ii (errhandler.jsp):

1 2 3 4 5 6 7 8 9 10 11 12 13 14

<% @ page e r r o r P a g e= e r r o r p a g e . j s p % > <html> <body> <% String m a t e r i a=r e q u e s t . g e t P a r a m e t e r ( m a t e r i a ) . t r i m ( ) ; i f ( m a t e r i a . e q u a l s ( AN ) ) { out . p r i n t l n ( <hr >< f o n t c o l o r=red > A l e g e r e c o r e c t a ! < / f o n t > ) ; } else{ throw new E x c e p t i o n ( N a t i f a c u t a l e g e r e a c o r e c t a ) ; } % > </ body> </ html>

cu pagina de tratare a except iei (errorpage.jsp )


1 2 3 4 5 7 8 10 11 13 14 15 16 17 18 20 21

< ! Aceste comentarii sunt f o a r t e importante in c a z u l u t i l i z a r i i n a v i g a t o r u l u i IE s i a l u i apache tomcat 5 . . . / 6 . . . In l i p s a l o r nu s e g e n e r e a z a s a l t u l l a e x c e p t i e p r i n p a g i n a j s p . R o l u l c o m e n t a r i i l o r e s t e marirea l u n g i m i i f i s i e r u l u i de f a t a . O a l t e r n a t i v a e s t e ca d i n IE6 . . . O p t i o n s sa s e d e z a c t i v e z e o p t i u n e a Show f r i e n d l y HTTP e r r o r message Cu n a v i g a t o r u l F i r e f o x nu e x i s t a a c e a s t a problema . > <% @ page i s E r r o r P a g e= t r u e % > <html> <body> <div a l i g n= c e n t e r > < %= e x c e p t i o n . g e t M e s s a g e ( ) % > </ div> </ body> </ html>

10.2. JSP STANDARD TAG LIBRARY JSTL

239

apelate prin
<html> <body> <form method=p o s t action= j s p / e r r h a n d l e r . j s p > Care e s t e m a t e r i a p r e f e r a t a d i n a n i i de s t u d i u u n i v e r s i t a r ? <p> A l g o r i t m i c a s i programare <input type= r a d i o name= m a t e r i a value=AP checked> <p> A n a l i z a numerica <input type= r a d i o name= m a t e r i a value=AN> <p> Inteligenta artificiala <input type= r a d i o name= m a t e r i a value=IA> <p> <input type=submit> </ form> </ body> </ html>

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

10.2

JSP Standard Tag Library JSTL

JSTL este o familie de biblioteci de marcaje ce ofer a o serie de facilit a ti activit a tii de realizare a paginilor Web. JSTL ajut a la separarea activit a tii de programare de aceea a proiectare (design) a paginii Web. JSTL este alc atuit a din 5 biblioteci: URI Descriere http://java.sun.com/jsp/jstl/core Biblioteca de baz a http://java.sun.com/jsp/jstl/xml Biblioteca de prelucrare a documentelor xml http://java.sun.com/jsp/jstl/fmt Biblioteca de formatare a datelor http://java.sun.com/jsp/jstl/sql Biblioteca de lucru cu baze de date http://java.sun.com/jsp/jstl/functions Biblioteca de funct ii ajut atoare Instalarea bibliotecilor. Bibliotecile sunt livrate mpreun a cu apachetomcat-* n catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin sierele jstl.jar si standard.jar. Utilizarea bibliotecilor. In vederea utiliz arii, cele dou a siere trebuie copiate n catalogul lib al aplicat iei care utilizeaz a bibliotecile. In pagina / documentul JSP, o bibliotec a utilizat a trebuie declarat a printro directiv a taglib.

240

CAPITOLUL 10. JAVA SERVER PAGE JSP

10.2.1

Biblioteca de baz a

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> Marcaje din biblioteca de baz a: c:set Fixeaz a o valoare ntr-o variabil a. Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce va stoca valoarea expresiei. value opt ional Expresia care va evaluat a si atribuit a variabilei scope opt ional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application. Referirea la o variabil a se face prin sintaxa ${numeVariabil a} Referirea la valoarea unui c amp dintr-un formular se face prin ${param.numeC amp } Al aturi de obiectul param, alte obiecte predenite sunt cookie, header, initParam, pageContext. Se pot deni variabile cu acela si nume dar av and domenii de valabilitate diferit a. Referirea se face prin ${pageScope.numeVariabil a }, ${requestScope.numeVariabil a }, ${sessionScope.numeVariabil a }, ${applicationScope.numeVariabil a }. Plas and clauza empty naintea unei variabile, ${empty numeVariabil a }, se obt ine false sau true dup a cum variabila are sau nu atribuit a o valoare. c:remove S terge o variabil a. Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce se sterge. scope opt ional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application.

10.2. JSP STANDARD TAG LIBRARY JSTL

241

c:out A seaz a o valoare. Atribute ale marcajului: Atribut value default Fel Descriere obligatoriu Valoarea ce se evalueaz a si se a seaz a. opt ional Cea ce se a seaz a n cazul n care expresia nu poate evaluat a. escapeXml opt ional true / false. Valoarea implicit a este true. Pe false interpreteaz a caracterele din value ca si cod html. c:if Test, vericarea unei condit ii. Atribute ale marcajului: Atribut Fel Descriere test obligatoriu Condit ia de test. var opt ional Numele variabilei ce va stoca valoarea testului. scope opt ional Domeniul de valabilitate al variabilei denit a anterior. In cazul n care condit ia are valoarea true se prelucreaz a corpul marcajului, n caz contrar, acesta este ignorat. Exemplul 10.2.1 Preluarea datelor unui formular cu c ampurile de intrare nume, prenume si email se face prin pagina JSP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

< H T M L > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e p r e f i x= c % > < B O D Y > <p> <c : i f t e s t= $ { empty param . nume } var= testNume > <c : out value=Numele l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not testNume } > Nume : <c : out value= $ { param . nume } /> </ c : i f > <p> <c : i f t e s t= $ { empty param . prenume } var= testPrenume > <c : out value= Prenumele l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not testPrenume } > Prenume : <c : out value= $ { param . prenume } /> </ c : i f > <p> <c : i f t e s t= $ { empty param . e m a i l } var= t e s t E m a i l >

242

CAPITOLUL 10. JAVA SERVER PAGE JSP

20 21 22 23 24 25 26

<c : out value= Adresa EMail l i p s e s t e ! /> </ c : i f > <c : i f t e s t= $ { not t e s t E m a i l } > Em a i l : <c : out value= $ { param . e m a i l } /> </ c : i f > </B O D Y > </H T M L >

c:choose Marcajul de select ie poate cont ine oric ate marcaje c:when si cel mult un marcaj c:otherwise. Fiecare marcaj c:when cont ine obligatoriu atributul test. Dac a ntr-un marcaj c:when condit ia are valoarea true, atunci se prelucreaz a corpul acelui marcaj. In cazul n care toate marcajele c:when au fost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcaj f ar a atribute). c:forEach Ciclu. Atribute ale marcajului: Atribut items var Fel Descriere opt ional Colect ia care se parcurge. opt ional Numele variabilei n care se stocheaz a valoarea elementului curent. begin opt ional Valoarea init ial a a variabilei var. end opt ional Valoarea nal a a variabilei var. step opt ional Valoarea pasului de iterare. Implicit este 1. varStatus opt ional Informat ii despre elementul curent. Variabila varStatus are c ampurile: index valoarea curent a a elementului dup a care se realizeaz a ciclarea; count num arul iterat iei curente; first are valoarea true dac a este primul element al ciclului; last are valoarea true dac a este ultimul element al ciclului; Exemplul 10.2.2 Lista parametrilor formularului de apelare a exemplului anterior se a seaz a prin:
<h2> Lista parametrilor din formular </h2> <ul> <c:forEach items="${param}" var="p"> <li> <c:out value="${p.key}"/> = <c:out value="${p.value}" />

10.2. JSP STANDARD TAG LIBRARY JSTL

243

</li> </c:forEach> </ul>

Exemplul 10.2.3 Lista parametrilor unui header se a seaz a prin:

<h2> Lista campurilor din antet </h2> <ul> <c:forEach items="${header}" var="h"> <li> <c:out value="${h.key}"/> = <c:out value="${h.value}"/> </li> </c:forEach> </ul>

Exemplul 10.2.4 Evident ierea fontului cu care se scriu titlurile ntr-un document html:

<c:forEach begin="1" end="6" var="i" > <c:out value="<h${i}> Heading ${i} </h${i}>" escapeXml="false" /> </c:forEach>

c:forTokens Asigur a acea si funct ionalitate ca si clasei java.util.String Tokenizer. Atribute ale marcajului: Atribut value Fel Descriere obligatoriu Valoarea ce se evalueaz a si se a seaz a. expresiei. default opt ional Cea ce se a seaz a n cazul n care expresia nu poate evaluat a. escapeXml opt ional true / false. Valoarea implicit a este true. Pe false interpreteaz a caracterele din value ca si cod html. c:import Permite includerea altor pagini JSP n pagina curent a. Atribute ale marcajului:

244

CAPITOLUL 10. JAVA SERVER PAGE JSP

Atribut Fel Descriere url obligatoriu Adresa documentului importat. context opt ional Context-ul paginii / documentului importat. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. var opt ional Numele variabilei n care va stocat documentul importat. scope opt ional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application. Cu marcajul c:param se pot xa parametri pentru pagina importat a. Acest marcaj are dou a atribute name si value. Acesti parametri se transmit cu metoda get. c:redirect Redirectarea activitatea c atre o alt a pagin a. Atribute ale marcajului: Atribut Fel Descriere url obligatoriu Adresa paginii c atre care se face redirectarea. context opt ional Context-ul paginii c atre care se face redirectarea. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. Prin redirectare, parametrii nu sunt retransmi si automat mai departe. c:url Ret ine adrese URL. Atribute ale marcajului: Atribut Fel Descriere value obligatoriu Adresa documentului de ret inut. context opt ional Context-ul documentului. Simbolul /, urmat de numele unei aplicat ii de pe acela si server. var opt ional Numele variabilei n care va stocat a adresa documentului. scope opt ional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application.

10.2. JSP STANDARD TAG LIBRARY JSTL

245

10.2.2

Biblioteca de lucru cu baze de date

<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> Marcaje din biblioteca de baz a: sql:setDataSource Fixeaz a referint a la baza de date. Atribute ale marcajului: Atribut dataSource driver url username password var scope Fel opt ional opt ional opt ional opt ional opt ional opt ional opt ional Descriere Referint a la baza de date Driver-ul bazei de date url-ul bazei de date nume utilizatorului bazei de date parola de acces la baza de date variabila cu referint a la baza de date Domeniul de valabilitate al variabilei var.

sql:query O interogare a bazei de date. Atribute ale marcajului: Atribut sql dataSource startRow maxRows var scope Fel obligatoriu opt ional opt ional opt ional obligatoriu opt ional Descriere Fraza sql Referint a la baza de date Linia de la care se ncepe interogarea Num arul maxim de rezultate acceptate Variabila cu rezultatele interog arii bazei de date Domeniul de valabilitate al variabilei var.

sql:update Actualizarea bazei de date. Atribute ale marcajului: Atribut Fel Descriere sql obligatoriu Fraza sql dataSource opt ional Referint a la baza de date Exemplul 10.2.5 S a se a seze lista din agenda de adrese e-mail creat a n exemplul din Cap. Servlet.

246

CAPITOLUL 10. JAVA SERVER PAGE JSP

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

< H T M L > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e p r e f i x= c % > <% @ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / s q l p r e f i x= s q l % > < B O D Y > <p> <s q l : setDataSource d r i v e r= o r g . apache . derby . j d b c . C l i e n t D r i v e r u r l= j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail var=db /> < s q l : query d a t a S o u r c e= $ { db } var= r e z u l t s q l= s e l e c t from a d r e s e /> <c : i f t e s t= $ { r e z u l t . rowCount g t 0 } > <table> < tr> <c : f o r E a c h i t e m s= $ { r e z u l t . columnNames } var= c o l > <th> <c : out value= $ { c o l } /> </ th> </ c : f o r E a c h> </ tr> <c : f o r E a c h i t e m s= $ { r e z u l t . rowsByIndex } var= l i n e > < tr> <c : f o r E a c h i t e m s= $ { l i n e } var= elem > <td> <c : out value= $ { elem } /> </ td> </ c : f o r E a c h> </ tr> </ c : f o r E a c h> </ table> </ c : i f > </B O D Y > </H T M L >

10.3

Marcaje JSP personale

Programatorul poate crea marcaje JSP proprii care se grupeaz a n colect ii numite biblioteci de marcaje. O bibliotec a de marcaje este reprezentat a de o identicator dat sub forma unui URI (Universal Resource Identier ).

10.3.1

Marcaje f ar a atribute si f ar a corp.

Pentru a crea unui asemenea marcaj JSP propriu este necesar a denirea a patru componente: 1. O clas a de denit ie a comportamentului marcajului JSP (tag handler class).

10.3. MARCAJE JSP PERSONALE

247

2. Descriptorul de bibliotec a de marcaje JSP, care leag a clasa de denit ie a marcajului cu identicatorul bibliotecii de marcaje. 3. Marcajul taglib a sierului web.xml, care permite serverului Web s a g aseasc a descriptorul bibliotecii de marcaje. 4. Fi sierul JSP ce utilizeaz a marcajul JSP (clientul). Exemplic am acest a tehnologie prin Exemplul 10.3.1 S a se realizeze un marcaj dateTag, a c arui efect s a e a sarea datei calendaristice. 1. Clasa de denit ie a comportamentului marcajului. Programul const a din: (a) Importul pachetelor import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; Aceste pachete se g asesc n sierul jsp-api.jar. (b) Un marcaj f ar a atribute si f ar a corp trebuie s a extind a clasa TagSupport si s a suprascrie metoda doStartTag, care dene ste activitatea intreprins a c and este nt alnit marcajul ntr-un document jsp. Metoda trebuie s a returneze constanta SKIP BODY. public class NumeClasa extends TagSupport{ public int doStartTag(){ . . . return SKIP_BODY; } } (c) Scrierea n uxul de ie sire se face cu un obiect JspWriter, care se obt ine cu pageContext.getOut(). Metoda print a clasei JspWriter poate genera o except ie IOException. Textul surs a al clasei de denit ie a comportamentului marcajului dateTag este:

248

CAPITOLUL 10. JAVA SERVER PAGE JSP

1 2 3 4 5 7 8 9 10 11 12 13 14 15 16 17 18

package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; import j a v a . u t i l . Date ; public c l a s s DateTag extends TagSupport { public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; out . p r i n t l n ( new Date ( ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( DateTagException +e . g e t M e s s a g e ( ) ) ; } return SKIP BODY ; } }

2. Descriptorul de bibliotec a de marcaje JSP este dependent de versiunea tomcat folosit a. Acest sier trebuie s a aib a extensia tld (Taglib Language Denition). Localizarea acestui sier este denit a n elementul taglib din web.xml. In cazul unei distribut ii apache-tomcat-5.*, acest sier este (mylibtag.tld) :
<? xml version= 1 . 0 e n c o d i n g=ISO 8859 1 ?> < !D O C T Y P E taglib PUBLIC //Sun Microsystems , I n c . / /DTD JSP Tag L i b r a r y 1 . 2 / /EN h t t p : // j a v a . sun . com/ j 2 e e / dtd /web j s p t a g l i b r a r y 1 2 . dtd > < ! a t a g l i b r a r y d e s c r i p t o r > < t a g l i b> < t l i b version> 1 . 0 </ t l i b version> < j s p version> 1 . 2 </ j s p version> < s h o r t name> mytags </ s h o r t name> < u r i> h t t p : // c s . u n i t b v . r o / m y t a g l i b</ u r i> < d e s c r i p t i o n > L i b r a r i e de m a r c a j e </ d e s c r i p t i o n > < t a g> <name> dateTag </name> <tag c l a s s > j s p . DateTag </ tag c l a s s > <bodyc o n t e n t> EMPTY </bodyc o n t e n t> < d e s c r i p t i o n > f u r n i z e a z a data c u r e n t a </ d e s c r i p t i o n > </ t a g> </ t a g l i b >

1 2 3 4 6 7 8 9 10 11 12 14 15 16 17 18 19 20

Elementul uri cont ine identicatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib. Pentru ecare marcaj propriu se completeaz a un marcaj tag. Pentru un marcaj propriu f ar a atribute elementele acestui marcaj sunt (a) name Numele simbolic al marcajului.

10.3. MARCAJE JSP PERSONALE

249

(b) tag-class Referint a la sierul class al clasei de denit ie a comportamentului marcajului propriu. Referint a se face relativ la catalogul ...\WEB-INF\classes (c) description Descrierea marcajului propriu. (d) body-content In cazul nostru are valoarea EMPTY. In cazul unui marcaj cu corp se d a valoarea JSP. 3. Marcajul taglib din sierul web.xml
<taglib> <taglib-uri> http://cs.unitbv.ro/mytaglib </taglib-uri> <taglib-location> /WEB-INF/mylibtag.tld </taglib-location> </taglib>

Elementele marcajului taglib sunt: (a) taglib-uri Identicatorul bibliotecii de marcaje. (b) taglib-location Locat ia sierului descriptor de bibliotec a de marcaje (numele calicat al sierului, adic a alc atuit din cale plus numele sierului). Astfel elementele constitutive se vor g asi n: webapps |--> mytag | |--> WEB-INF | | |--> classes | | | |--> jsp | | | | |--> DateTag.class | | | web.xml | | | mylibtag.tld | |--> jsp | | | dateTag.jsp 4. Marcajele proprii se utilizeaz a cu sintaxa <prex : NumeMarcaj />

250

CAPITOLUL 10. JAVA SERVER PAGE JSP

Referint a la catalogul cu toate componentele necesare marcajului si prexul se xeaz a n directiva taglib. Un sier jsp care utilizeaz a marcajul realizat este (dateTag.jsp) :

1 2 3 4 5 6 7 8 9 10 11 12 13 14

<html> <head> < t i t l e> Tag p e n t r u data c a l e n d a r i s t i c a c u r e n t a </ t i t l e > </ head> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <p> Data c u r e n t a e s t e : <mk : dateTag /> </ body> </ html>

apelat din
1 2 3 4 6 7 8 9 10

<html> <body> <form method= g e t action= j s p / dateTag . j s p > Data c a l e n d a r i s t i c &#259;: <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>

10.3.2

Marcaje cu atribute si f ar a corp.

Realiz am un marcaj ziuaTag cu un atribut ziua care va a sat n momentul prelucr arii marcajului. 1. Pentru ecare atribut clasa ce dene ste act iunea marcajului trebuie s a cont in a o metod a public void setNumeAtribut (String value){...} care preia valoarea atributului dat a de parametrul value. Exemplul 10.3.2

10.3. MARCAJE JSP PERSONALE

251

Pentru exemplul enunt at aceast a clas a este

1 2 3 4 6 7 9 10 11 13 14 15 16 17 18 19 20 21 22 23

package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; public c l a s s ZiuaTag extends TagSupport { String ziua ; public void s e t Z i u a ( S t r i n g v a l u e ) { z i u a=v a l u e ; } public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; out . p r i n t l n ( z i u a ) ; } catch ( IOException e ) { System . out . p r i n t l n ( ZiuaTagException +e . g e t M e s s a g e ( ) ) ; } return SKIP BODY ; } }

2. In descriptorul bibliotecii de marcaje pentru ecare atribut se dene ste un marcaj <attribute>...< /attribute> av and incluse marcajele Nume marcaj Semnicat ie name numele atributului required true | false dup a cum atributul e obligatoriu sau nu rtexprvalue true | false dup a cum atributul se poate utiliza ntr-o expresie < %= numeAtribut % > Fel obligatoriu obligatoriu opt ional

Marcajul <tag> din descriptorul bibliotecii de marcaje devine


<tag> <name> ziuaTag </name> <tag-class> jsp.ZiuaTag </tag-class> <body-content> EMPTY </body-content> <description> furnizeaza argumentul ziua curenta </description> <attribute> <name> ziua </name> <required> true </required> <rtexprvalue> true </rtexprvalue> </attribute> </tag>

252

CAPITOLUL 10. JAVA SERVER PAGE JSP

3. Utilizarea acestui marcaj este exemplicat n

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

<html> <body> <form method= g e t action= j s p / ziuaTag . j s p > <p> A s t a z i , e s t e < s e l e c t name= z i u a > <option value= l u n i > Luni <option value= m a r t i > Marti <option value= m i e r c u r i > M i e r c u r i <option value= j o i > J o i <option value= v i n e r i > V i n e r i <option value= s i mb a ta > Simbata <option value= duminica > Duminica </ s e l e c t> <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>

unde ziuaTag.jsp este


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

<html> <head> < t i t l e > Tag cu marcaj </ t i t l e > </ head> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <p> <% String z i=r e q u e s t . g e t P a r a m e t e r ( z i u a ) ; % > Ziua e s t e : <mk : ziuaTag z i u a=<%= z i % > /> </ body> </ html>

10.3.3

Marcaje cu corp.

In metoda doStartTag valoarea returnat a trebuie s a e EVAL BODY INCLUDE, n loc de SKIP BODY. In descriptorul bibliotecii de marcaje apare <body-content> JSP </body-content> n loc de EMPTY. Dac a se dore ste ca marcajul s a execute act iuni dup a interpretarea corpului, atunci acele activit a ti sunt denite n metoda doEndTag. Aceast a metod a

10.3. MARCAJE JSP PERSONALE

253

returneaz a valoarea EVAL PAGE sau SKIP PAGE dup a cum se dore ste sau nu continuarea proces arii paginii jsp. Exemplul 10.3.3 Fie marcajul modTag care modic a un text n caractere mari sau mici dup a valoarea atributului trans. Acest marcaj poate include ale elemente. Codul clasei ce prelucreaz a marcajul este
1 2 3 4 6 7 8 10 11 12 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31

package j s p ; import j a v a x . s e r v l e t . j s p . J s p W r i t e r ; import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ; import j a v a . i o . IOException ; public c l a s s ModTag extends TagSupport { String text ; boolean toUpperCase ; public void s e t T e x t ( S t r i n g v a l u e ) { t e x t=v a l u e ; } public void s e t T r a n s ( S t r i n g v a l u e ) { toUpperCase=(new Boolean ( v a l u e ) ) . b o o l e a n V a l u e ( ) ; } public i n t doStartTag ( ) { try { J s p W r i t e r out=pageContext . getOut ( ) ; i f ( toUpperCase ) out . p r i n t l n ( t e x t . toUpperCase ( ) ) ; else out . p r i n t l n ( t e x t . toLowerCase ( ) ) ; } catch ( IOException e ) { System . out . p r i n t l n ( ModTagException +e . g e t M e s s a g e ( ) ) ; } return EVAL BODY INCLUDE ; } }

Descriptorul bibliotecii de marcaje se completeaz a cu


<tag> <name> modTag </name> <tag-class> jsp.ModTag </tag-class> <body-content> JSP </body-content> <description> modifica caracterele </description> <attribute> <name> text </name> <required> true </required> <rtexprvalue> true </rtexprvalue> </attribute> <attribute>

254

CAPITOLUL 10. JAVA SERVER PAGE JSP

<name> trans </name> <required> true </required> <rtexprvalue> true </rtexprvalue> </attribute> </tag>

O pagin a de utilizare a marcajului modTag cu un corp nevid este


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

<html> <body> <form method= g e t action= j s p / modtextTag . j s p > I n t r o d u c e o f r a z &#259; <input type= t e x t name= t e x t s i z e= 40 > <p> Se t r a n s f o r m &#259; &#238;n l i t e r e < s e l e c t name= t r a n s > <option value= upperCase > mari <option value= l o w e r C a s e > m i c i </ s e l e c t> <p><input type= submit value= A f i s e a z a > </ form> </ body> </ html>

mpreun a cu modtextTag.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

<html> <body> <% @ t a g l i b u r i= h t t p : / / c s . u n i t b v . r o / m y t a g l i b p r e f i x=mk % > <% String text=r e q u e s t . g e t P a r a m e t e r ( t e x t ) ; String t r a n s=r e q u e s t . g e t P a r a m e t e r ( t r a n s ) ; String t ; i f ( t r a n s . e q u a l s ( upperCase ) ) t= t r u e ; else t= f a l s e ; % > <p> <mk : modTag text=<%= t e x t % > t r a n s=<%=t% >> <mk : dateTag /> </mk : modTag> </ body> </ html>

10.4

Servlet si JSP n Google App Engine

Prezent am desf a surarea unui servlet ntr-un produs sau platform a de cloud computing. Dintre produsele de cloud computing disponibile n prezent amintim: Amazons Elastic Compute Cloud -(EC2) produs de referint a, dar comercial;

10.4. SERVLET S I JSP IN GOOGLE APP ENGINE

255

Google App Engine (GAE); Microsoft Azure; In cele urmeaz a se va utiliza Google App Engine.1 GAE permite: nc arcarea unei aplicat ii Web pe un simulator local al platformei de Cloud Computing; nc arcarea unei aplicat ii Web pe platforma Google de Cloud Computing. In prezent, pe platforma GAE se pot nc arca aplicat ii realizate n Java, Python si Go, al aturi de care care pot ap area siere http, css, js. Exist a c ate o distribut ie distinct a pentru ecare din aceste limbaje de programare. Prezent am numai nc arcarea pe simulatorul local al platformei GAE, n versiunea Java construit peste serverul Web jetty. Instalarea produsului const a din dezarhivarea sierului appengine-javasdk-*. Utilizarea. In vederea nc arc arii unui servlet pe simulatorul local se creaz a structura de cataloage si siere
www |--> | | | | | | | WEB-INF |--> classes | | *.class |--> lib | | *.jar | web.xml | appengine-web.xml index.html

Singurul sier specic GAE este appengine-web.xml. Codul acestui ser este
1 2 3 4 6 8

< appengine webapp xmlns= h t t p : // a p p e n g i n e . g o o g l e . com/ ns / 1 . 0 > < ! R e p l a c e t h i s w i t h your a p p l i c a t i o n i d from h t t p : // a p p e n g i n e . g o o g l e . com > < a p p l i c a t i o n ></ a p p l i c a t i o n > <version>1</ version> </ appengine webapp>

Datele sierului web.xml corespund servlet-ului, iar prin sierul index.html se apeleaz a aplicat ia Web. Parametrul action al elementului form are forma simplicat a action=/numeApel, unde numeApel coincide cu valoarea atributului urlPattern.
1

O alta alternativ a gratuita este emulatorul oferit de Microsoft Azure.

256

CAPITOLUL 10. JAVA SERVER PAGE JSP

Dac a aplicat ia se ncarc a pe platforma Google de Cloud Computing atunci trebuie completat elementul <application>. Lansarea simulatorului si nc arcarea se poate face prin comenzile
set GAE\_HOME=. . .\appengine-java-sdk-* %GAE\_HOME%\bin\dev_appserver www

lansate ntr-o fereast a DOS, n catalogul care-l cont ine pe www. Aplicat ia se apeleaz a prin http://localhost:8080. Dac a n loc de index.html se utilizeaz a alt nume, atunci apelarea aplicat iei este http://localhost:8080/fi sier.html. O aplicat ie JSP se trateaz a asem an ator. Distribut ia GAE pentru Java cont ine sablonul unei aplicat ii mpreun a cu un sier build.xml (appengine-java-sdk-*\demos\new project template) prin intermediul c aruia, cu ajutorul lui ant, se construie ste catalogul www descris anterior. Exemplul 10.4.1 Servlet-ul CmmdcServlet instalat n platforma Google App Engine de Cloud Computing. S ablonul se copiaz a n zona de lucru sub numele appcmmdc si se completeaz a cu sierele servlet-ului (CmmdcServlet.java, cmmdc.html ) rezult and:
appcmmdc |--> html | | cmmdc.html |--> src | |--> WEB-INF | | | appengine-web.xml | | | web.xml | | CmmdcServlet.java | build.xml

Se execut a cu ant obiectivul implicit din build.xml, urmat de lansarea simulatorului din interiorul catalogului appcmmdc. Deoarece numele sierului html difer a de index, aplicat ia se apeleaz a prin http://localhost:8080/cmmdc.html. Alternativ, aplicat ia se poate construi cu Eclipse folosind o component a (plug-in ) specic a. GAE cont ine n plus un serviciu de autenticare si autorizare UserService, un sistem de persistent a a datelor Datastore, Task-Queue.

Intreb ari recapitulative


1. Care este tipul tehnologiei JSP ?

10.4. SERVLET S I JSP IN GOOGLE APP ENGINE

257

2. Precizat i diferent a dintre o pagin a JSP si un document JSP. 3. Unde se instaleaz a o pagina JSP? 4. Care este rolul unei declarat ii JSP ? 5. Care este rolul unei directive JSP ? 6. Cum apeleaz a o pagin a JSP ? 7. Cum prelucreaz a un server Web o pagina / document JSP ? 8. Care sunt tr as aturile unei componente Java (bean) ? 9. Care este rolul unui element <jsp:useBean> ?

258

CAPITOLUL 10. JAVA SERVER PAGE JSP

Capitolul 11 Enterprise Java Beans


In prezent se evident iaz a dou a abord ari privind realizarea aplicat iilor de complexitate mai mare (aplicat iilor de ntreprindere ): Java Enterprise Edition - JEE este o extensie a interfet ei de programare (API ) Java, pentru care exist a mai multe implement ari. Principalul promotor este al modelului este Oracle , dar este sust inut si de RedHat - JBoss.; Spring a c arei dezvoltare tine de rma VMware. Spring este alc atuit din mai multe cadre de lucru. Acest model de dezvoltare este sust inut de Google. Java Enterprise Edition este un cadru de lucru care nglobeaz a pe o serie implement ari ale interfet elor de programare (JDBC, JMS, JNDI, JSF, RMIIIOP, JPA, JTA, JAAS, etc), resurse care sunt utilizate prin intermediul unei componente Enterprise Java Bean - EJB. O component a EJB este o clas a Java - de obicei de tip POJO - care face parte din aplicat ia server, cont ine metodele care rezolv a o problem a (business logic ) si este cont inut ntr-un server de aplicat ii. Serverul de aplicat ii asigur a unei componente EJB o serie de funct ionalit a ti, ca injectarea dependint elor, conexiunea cu bazele de date, gestiunea tranzact iilor, etc. Serverul de aplicat ii poate interpretat si ca un container de componente EJB. Se spune c a serverul de aplicat ie JEE asigur a accesul la contextul n care ruleaz a aplicat ia, adic a la resursele serverului, si la injectarea dependint elor (Context and Dependency Injection -CDI ). Servere de aplicat ii gratuite: glasssh - Oracle - parte a produsului glasssh v3. 259

260

CAPITOLUL 11. ENTERPRISE JAVA BEANS

geronimo - apache, sprijinit de I.B.M. JOnAS. Glasssh, geronimo sunt implement ari ale extensiei Java Enterprise Edition - JEE. In acela si timp, aceste servere Web sunt containere EJB, de servlet si JSP. In cele ce urmeaz a vom utiliza glasssh. Tipuri de componente EJB: Session - sesiune EJB. Message Driven - preia mesaje de tipul Java Message Service (JMS). Vom folosi prescurtarea MDB - Message Driven Bean. Entity

11.1

Session EJB

Starea unui obiect Java este dat a de valorile c ampurilor sale. Din punctul de vedere al ret inerii st arii, exist a urm atoarele tipuri de componente sesiune EJB: stateless - f ar a ret inerea st arii; stateful - cu ret inerea st arii pe parcursul sesiunii serverului; singleton - exist a o singur a instant a a componentei EJB. Durata de viat a a componentei coincide cu intervalul de timp n care componenta EJB este activ a n serverul de aplicat ii. Aplicat iile cu component a EJB constau din: componenta EJB - desf a surat a n serverul de aplicat ii. Aceast a component a poate totodat a si un serviciu Web de tip JAX-WS; aplicat ie client care poate client Web - servlet sau client al serviciului Web de tip JAX-WS; client RMI-IIOP (Internet Inter ORB Protocol).

11.1. SESSION EJB

261

In terminologia JEE componenta EJB, clientul Web si clientul RMI-IIOP formeaz a c ate un modul. Componenta EJB si clientul Web formeaz a o aplicat ie JEE care se instaleaz a n serverul de aplicat ii JEE. Modulele EJB si RMI-IIOP se arhiveaz a cu extensia jar iar modulul Web se arhiveaz a cu extensia war. Aplicat ia JEE se arhiveaz a cu extensia ear -Enterprise ARchive - sau war. Un client RMI-IIOP apeleaz a modulul EJB prin intermediul programului glassfish\bin\appclient.exe
appclient -client modul-iiop.jar [-targetserver host:port] arg1 . . .

Portul implicit este 3700.

11.1.1

Component a EJB sesiune stateless

S ablonul pentru crearea unei componente EJB de tip stateless session este
import javax.ejb.Stateless; @Stateless public class Componenta{ public tip metoda(. . .){. . .} . . . }

Exemplul 11.1.1 Cel mai mare divizor comun a dou a numere naturale. Componentei EJB are codul
1 2 4 5 6 7

package cmmdc . e j b ; import j a v a x . e j b . S t a t e l e s s ; @Stateless public c l a s s CmmdcBean { public long cmmdc( long m, long n ) { . . . } }

Aplicat ia client va un servlet g azduit de acela si server de aplicat ie. Accesul la componenta EJB se poate programa: prin injectare, utiliz and adnot ari; prin JNDI. In ambele cazuri serverul Web este responsabil de instant ierea componentei EJB.

262 Injectare cu adnotare

CAPITOLUL 11. ENTERPRISE JAVA BEANS

Serverul de aplicat ie injecteaz a n servlet o instant a a componentei EJB sau altfel explicat
@EJB Type var; @EJB(name="xyz") Type var;

injecteaz a (realizeaz a o referint a ) pentru var c atre un obiect de tipul Type specicat. Actiunea este declan sat a de adnotarea EJB. Codul servlet-ului este
1 2 3 4 5 6 7 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 33 34 35 36 37

package cmmdc . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import cmmdc . e j b . CmmdcBean ; import j a v a x . e j b . EJB ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { @EJB CmmdcBean cb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ; long m =Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ; long x=cb . cmmdc(m, n ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; S t r i n g t i t l e =Cmmdc S e r v l e t ; r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <P>Cmmdc : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Desf a surarea aplicat iei


ejbcmmdc |--> WEB-INF | |--> classes | | |--> cmmdc | | | |--> ejb | | | | | CmmdcBean.class | | | |--> web

11.1. SESSION EJB

263

| |

| | | index.html

CmmdcServlet.class

Aceast a structur a se arhiveaz a cu jar, dar cu extensia war. Acces la componenta EJB prin JNDI Referint a JNDI are structura prex /[nume app ][/nume modul ]/nume EJB unde prex poate Prex Vizibilitatea rezultatului java:global Componenta se poate utiliza de oriunde. Coincide cu numele arhivei ear. java:app Componenta se poate utiliza n aplicat ie Coincide cu numele arhivei jar sau war. java:module Componental se poate utiliza n modul In cazul exemplului codul servlet-ului va
1 2 3 4 5 6 7 8 10 11 12 14 15 16 17 18 19 20 21 22 23 24 26 27 29 30 31 32

package cmmdc . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import cmmdc . e j b . CmmdcBean ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = /cmmdc ) public c l a s s CmmdcServlet extends H t t p S e r v l e t { CmmdcBean cb ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) throws S e r v l e t E x c e p t i o n { super . i n i t ( c o n f i g ) ; Context c t x=n u l l ; try { c t x=new I n i t i a l C o n t e x t ( ) ; cb=(CmmdcBean) c t x . l o o k u p ( j a v a : module /CmmdcBean ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; } } public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { . . . } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { . . . } } }

264

CAPITOLUL 11. ENTERPRISE JAVA BEANS

11.1.2

Aplicat ie JEE cu module EJB, Web si client RMIIIOP

Modic am arhitectura aplicat iei anterioare denind un modul EJB pentru componta EJB.
modul-ejb |--> numePachet | | *.class

un modul Web, a c arei arhiv a va avea extensia war.


modul-Web |--> WEB-INF | |--> classes | | | *.class | index.html

Desf a surarea aplicat iei va


|--> | | | META-INF | application.xml modul-ejb.jar modul-Web.war

Instalarea aplicat ie, adic a a ansamblului alc atuit din cele 2 module se face prin intermediul administratorului. Fi sierul application.xml precizeaz a structura aplicat iei
<?xml version="1.0" encoding="UTF-8"?> <application version="5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd"> <display-name>nume-aplicatie</display-name> <module> <ejb>modul-ejb.jar</ejb> </module> <module> <web> <web-uri>modul-web.war</web-uri> <context-root>/context</context-root> </web> </module> </application>

Aceast a organizare necesit a modicarea componentei EJB din sect iunea 11.1.1 n sensul denirii unei interfet e cu adnotarea Remote. Componenta EJB implementeaz a interfat a si n plus, dac a interfat a are numele Xyz atunci componenta EJB va avea numele XyzBean. Pentru exemplul discutat codurile sunt:

11.1. SESSION EJB

265

1 2 4 5 6 7

package cmmdc . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e Cmmdc{ public long cmmdc( long m, long n ) ; }

si
1 2 4 5 6 7

package cmmdc . e j b ; import j a v a x . e j b . S t a t e l e s s ; @Stateless public c l a s s CmmdcBean implements Cmmdc{ public long cmmdc( long m, long n ) { . . . } }

Modulul / clientul Web este cel prezentat anterior n sect iunea 11.1.1, cu diferent a c a referint a la componenta EJB se face prin interfat a . In cazul exemplului tratat, desf a surarea clientului RMI-IIOP va
cmmdc-iiop |--> cmmdc | |--> client | | | | |--> ejb | | |

CmmdcClient.class Cmmdc.class

Codul clientului prin injectare este


1 2 3 4 6 7 8 10 11 12 13 14 15 16 17 18 19

package cmmdc . c l i e n t ; import j a v a x . e j b . EJB ; import cmmdc . e j b . Cmmdc ; import j a v a . u t i l . S c a n n e r ; public c l a s s CmmdcClient { @EJB private s t a t i c Cmmdc cb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; long x=cb . cmmdc(m, n ) ; System . out . p r i n t l n ( Cmmdc : +x ) ; } }

Dac a se utilizeaz a referint a prin JNDI atunci adresarea componentei EJB va : java:global/cmmdc-ear/cmmdc-ejb/CmmdcBean Dac a dist este catalogul cu arhiva clientului atunci apelarea acestuia este

266

CAPITOLUL 11. ENTERPRISE JAVA BEANS

set GLASSFISH_HOME=. . .\glassfish3 %GLASSFISH_HOME%\glassfish\bin\appclient -client dist\cmmdc-iiop.jar -targetserver localhost:3700

Apelarea modulului Web se face n mod obi snuit, prin: http://host:8080/context unde context a fost denit n sierul application.xml.

11.1.3

Component a EJB sesiune singleton

Serverul de aplicat ie creaz a o singur a instant iaz a a componentei EJB care este utilizat a de tot i client ii. Diferent a const a n utilizarea adnot arii @Singleton n loc de @Stateless. Utiliz am modelul din sect iunea 11.1.2. Consider am doar varianta bazat a pe adnot ari. Exemplul 11.1.2 Num ararea solicit arilor de utilizare a componentei EJB. Codul componentei EJB singleton
1 2 4 5 6 7

package s i n g l e . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e S i n g l e { public i n t g e t I n d e x ( ) ; } package s i n g l e . e j b ; import j a v a x . e j b . S i n g l e t o n ; @Singleton public c l a s s S i n g l e B e a n implements S i n g l e { private i n t i n d e x =0; public i n t g e t I n d e x ( ) { return ++i n d e x ; } }

1 2 4 5 6 7 8 9 10

Servlet-ul aplicat iei client are codul


1 2 3 4 5 6 7 9 10 11

package s i n g l e . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import s i n g l e . e j b . S i n g l e ; import j a v a x . e j b . EJB ; import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; @WebServlet ( u r l P a t t e r n s = / s i n g l e ) public c l a s s S i n g l e S e r v l e t extends H t t p S e r v l e t { @EJB

11.1. SESSION EJB

267

12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33

S i n g l e sb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { i n t x=sb . g e t I n d e x ( ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g t i t l e = S i n g l e S e r v l e t ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ; out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Apelarea servlet-ului se face din sierul index.html


1 2 3 4 5 6 7 8 9 10 11

<html> <body bgcolor=#c c b b c c > <center> <h1> EJB S i n g l e S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / e j b s i n g l e / s i n g l e > <p><input type= submit value= A p e l e a z a > </ form> </ center> </ body> </ html

Aplicat ia client are codul


1 2 3 4 6 7 8 10 11 12 13 15 16 17 18 19 20

package s i n g l e . c l i e n t ; import j a v a x . e j b . EJB ; import s i n g l e . e j b . S i n g l e ; import j a v a . u t i l . S c a n n e r ; public c l a s s S i n g l e C l i e n t { @EJB private s t a t i c S i n g l e nb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; S t r i n g ch=Y ; i n t i n d e x =0; while ( ch . e q u a l s ( Y ) ) { i n d e x=nb . g e t I n d e x ( ) ; System . out . p r i n t l n ( Numarul de a p e l a r i : +i n d e x ) ; System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ; do { ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ;

268

CAPITOLUL 11. ENTERPRISE JAVA BEANS

21 22 23 24 25

} while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; } } }

11.1.4

Component a EJB sesiune stateful

Diferent a formal a fat a de modelele Stateless si Singleton const a n utilizarea adnot arii @Stateful. Consider am un exemplu ce deriv a din cel precedent. Exemplul 11.1.3 Num ararea solicit arilor de utilizare a componentei EJB. Componenta EJB are interfat a
1 2 4 5 6 7 8

package numara . e j b ; import j a v a x . e j b . Remote ; @Remote public i n t e r f a c e Numara { public i n t g e t I n d e x ( ) ; public void remove ( ) ; }

si implementarea
1 2 3 5 6 7 8 9 10 12 13 14

package numara . e j b ; import j a v a x . e j b . S t a t e f u l ; import j a v a x . e j b . Remove ; @Stateful public c l a s s NumaraBean implements Numara { private i n t i n d e x =0; public i n t g e t I n d e x ( ) { return ++i n d e x ; } @Remove public void remove ( ) {} }

Metoda cu adnotarea Remove are ca efect stergerea instant ei componentei EJB din serverul de aplicat ii. Din acest motiv, apelarea acestei metode ntr-un modul Web, are ca efect compromiterea servlet-ului. Injectarea componentei EJB are loc n momentul activ arii servlet-ului. Astfel ecare client Web va utiliza acea si component a EJB. Modulul IIOP este mult mai util. La ecare apelare a modulului IIOP are loc injectarea unei componente EJB. Serverul de aplicat ii p astreaz a starea componentei pe durata de utilizare a modulului IIOP. Codul modulului Web

11.1. SESSION EJB

269

1 2 3 4 5 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40

package numara . web ; import j a v a . i o . ; import j a v a x . s e r v l e t . ; import j a v a x . s e r v l e t . h t t p . ; import numara . e j b . Numara ; import j a v a x . e j b . EJB ; public c l a s s NumaraServlet extends H t t p S e r v l e t { @EJB Numara nb ; public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S t r i n g o p e r=r e q . g e t P a r a m e t e r ( o p e r ) ; P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ; r e s . setContentType ( t e x t / html ) ; S t r i n g t i t l e =Numara S e r v l e t ; out . p r i n t l n ( <HTML ><HEAD ><TITLE> ) ; out . p r i n t l n ( t i t l e ) ; out . p r i n t l n ( </TITLE></HEAD >< BODY > ) ; out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ; switch ( o p e r ) { case i n d e x : i n t x=nb . g e t I n d e x ( ) ; out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ; break ; case e x i t : out . p r i n t l n ( <p> OK: Pe r a s p u n d e r e a d v o a s t r a ) ; nb . remove ( ) ; break ; } out . p r i n t l n ( </BODY ></HTML > ) ; out . c l o s e ( ) ; } public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

apelat din
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

<html> <body bgcolor=#c c b b c c > <center> <h1> EJB Numar&#259; S e r v l e t </ h1> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / ejbnumara /numara> <table> < tr> <td> S e l e c t a &#355; i o p e r a &#355; i a</ td> <td> < s e l e c t name= o p e r > <option value= i n d e x > Num&#259; r de a p e l &#259; r i <option value= e x i t > S t e r g e componenta EJB </ s e l e c t> </ td> </ tr>

270

CAPITOLUL 11. ENTERPRISE JAVA BEANS

17 18 19 20 21 22 23 24 25

< tr> <td> <input type= submit value= A p e l e a z a ></ td> <td /> </ tr> </ table> </ form> </ center> </ body> </ html>

Codul modulului IIOP


1 2 3 4 6 7 8 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41

package numara . c l i e n t ; import j a v a x . e j b . EJB ; import numara . e j b . Numara ; import j a v a . u t i l . S c a n n e r ; public c l a s s NumaraClient { @EJB private s t a t i c Numara nb ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; S t r i n g ch=Y , msg= ; i n t op , i n d e x =0; while ( ch . e q u a l s ( Y ) ) { System . out . p r i n t l n ( O p e r a t i i : 1 . Numara 2 . S t e r g e componenta EJB ) ; System . out . p r i n t l n ( O p e r a t i a : ) ; op=s c a n n e r . n e x t I n t ( ) ; switch ( op ) { case 1 : i n d e x=nb . g e t I n d e x ( ) ; msg=Numarul de a p e l a r i : +(new I n t e g e r ( i n d e x ) ) . t o S t r i n g ( ) ; break ; case 2 : nb . remove ( ) ; msg=Sa s t e r s componenta EJB ; break ; default : msg=Cod o p e r a t i e e r o n a t ; break ; } System . out . p r i n t l n ( msg ) ; System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ; do { ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; } } }

Rul and modulele IIOP ale aplicat iilor corespunz atoare adnot arilor Stateful si Singleton observat i diferent a rezultatelor furnizate.

11.1. SESSION EJB

271

11.1.5

Component a EJB MessageDriven

O component a EJB MessageDriven (MDB) preia mesaje care sunt trimise c atre un obiect destinat ie predenit de tip Queue sau Topic. Componenta EJB este adnotat a cu @MessageDriven(mappedName=nume Destinat ie ) Prelucrarea mesajelor primite se programeaz a n metoda onMessage a interfet ei MessageListener. A sarea unor mesaje se obt ine prin intermediul unei jurnaliz ari java.util. logging.Logger. Textele apar n sierul server.log aat n catalogul log al domeniului. Obiectele administrator - fabrica de conexiuni, obiectul destinat ie - se creaz a naintea desf a sur arii componentei EJB.

Crearea obiectelor administrator


Dintr-un navigator, apel and http://localhost:4848 se acceseaz a administratorul grac (web). Resources | JMS Resources se vor crea obiectele 1. Destination Resources myQueue JNDI Name : myQueue javax.jms.Queue Physical Destination Name : myTopic JNDI Name : myTopic javax.jms.Topic Physical Destination Name : 2. Connection Factories myQueueConnectionFactory Pool Name : myQueueConnectionFactory javax.jms.QueueConnectionFactory Resource Type : Din

myTopicConnectionFactory Pool Name : myTopicConnectionFactory javax.jms.TopicConnectionFactory Resource Type :

Exemplul 11.1.4 O aplicat ie client trimite un num ar de mesaje c atre o component a MDB. Codul componentei EJB

272

CAPITOLUL 11. ENTERPRISE JAVA BEANS

1 2 3 4 5 6 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26

package mdb ; import j a v a x . e j b . MessageDriven ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . jms . M e s s a g e L i s t e n e r ; import j a v a . u t i l . l o g g i n g . Logger ; @MessageDriven ( mappedName=myQueue ) public c l a s s MessageBean implements M e s s a g e L i s t e n e r { private s t a t i c f i n a l Logger l o g g e r = Logger . g e t L o g g e r ( MessageBean . c l a s s . getName ( ) ) ; public void onMessage ( Message msg ) { TextMessage txtMsg = n u l l ; try { i f ( msg instanceof TextMessage ) { txtMsg = ( TextMessage ) msg ; l o g g e r . i n f o ( MESSAGE BEAN: + txtMsg . g e t T e x t ( ) ) ; System . out . p r i n t l n ( txtMsg . g e t T e x t ( ) ) ; } } catch ( Throwable th ) { th . p r i n t S t a c k T r a c e ( ) ; } } }

Desf a surarea componentei MDB va


simple-mdb |--> META-INF | | application.xml | simple-mdb.jar

Fi sierul simple-mdb.jar nu cont ine dec at clasa mdb.MessageBean, reprodus a mai sus. Codul clientului cu reg asirea obiectilor prin adnotare
1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20

package mdb ; import j a v a x . jms . QueueConnection ; import j a v a x . jms . QueueConnectionFactory ; import j a v a x . jms . D e s t i n a t i o n ; import j a v a x . jms . Q u e u e S e s s i o n ; import j a v a x . jms . MessageProducer ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . a n n o t a t i o n . R e s o u r c e ; public c l a s s MessageClient { @Resource ( l o o k u p= myQueueConnectionFactory ) private s t a t i c QueueConnectionFactory c f ; @Resource ( l o o k u p=myQueue ) private s t a t i c D e s t i n a t i o n q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { QueueConnection conn = c f . c r e a t e Q u e u e C o n n e c t i o n ( ) ; QueueSession s e s s i o n =

11.1. SESSION EJB

273

21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37

conn . c r e a t e Q u e u e S e s s i o n ( f a l s e , Q u e u e S e s s i o n .AUTO ACKNOWLEDGE) ; MessageProducer s e n d e r = s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage msg = s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; f o r ( i n t i = 0 ; i < 5 ; i ++) { msg . s e t T e x t ( Mesaj t r i m i s + ( i + 1 ) ) ; s e n d e r . send ( msg ) ; } System . out . p r i n t l n ( Sen de r has f i n i s h e d ) ; session . close (); System . e x i t ( 0 ) ; } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }

si prin JNDI
1 2 3 4 5 6 7 8 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 39 40

package mdb ; import j a v a x . jms . QueueConnection ; import j a v a x . jms . QueueConnectionFactory ; import j a v a x . jms . D e s t i n a t i o n ; import j a v a x . jms . Q u e u e S e s s i o n ; import j a v a x . jms . MessageProducer ; import j a v a x . jms . Message ; import j a v a x . jms . TextMessage ; import j a v a x . naming . Context ; import j a v a x . naming . I n i t i a l C o n t e x t ; public c l a s s MessageClient { private s t a t i c QueueConnectionFactory c f ; private s t a t i c D e s t i n a t i o n q ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { Context c t x=n u l l ; try { c t x=new I n i t i a l C o n t e x t ( ) ; c f =( QueueConnectionFactory ) c t x . l o o k u p ( myQueueConnectionFactory ) ; q=( D e s t i n a t i o n ) c t x . l o o k u p ( myQueue ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } try { QueueConnection conn = c f . c r e a t e Q u e u e C o n n e c t i o n ( ) ; Q u e u e S e s s i o n s e s s i o n = conn . c r e a t e Q u e u e S e s s i o n ( f a l s e , Q u e u e S e s s i o n .AUTO ACKNOWLEDGE) ; MessageProducer s e n d e r = s e s s i o n . c r e a t e P r o d u c e r ( q ) ; TextMessage msg = s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; f o r ( i n t i = 0 ; i < 5 ; i ++) { msg . s e t T e x t ( Mesaj t r i m i s + ( i + 1 ) ) ; s e n d e r . send ( msg ) ; } System . out . p r i n t l n ( Sen de r has f i n i s h e d ) ; session . close (); System . e x i t ( 0 ) ;

274
} catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }

CAPITOLUL 11. ENTERPRISE JAVA BEANS

41 42 43 44 45 46

Clientul se execut a prin intermediul lui appclient.

11.1.6

Component a EJB Entity

O componenta de tip entity simplic a accesul la o baz a de date ntr-o aplicat ie JEE. Crearea bazei de date
Glasssh cont ine SGBD JavaDB (derby ). Vom lansa serverul glasssh si prin intermediul utilitarului ij vom crea baza de date AgendaEMail. Crearea se face n modul descris n anexa dedicat a utiliz arii unei SGBD ntr-un program Java.

Denirea elementelor de conexiune dintre glasssh si baza de date


Dintr-un navigator, apel and http://localhost:4848 se acceseaz a administratorul grac (web). Resources | JDBC se vor crea 1. JDBC Connection Pool cuv a de conexiuni la baza de date; 2. JDBC Resources leg atura dintre numele JNDI asociat bazei de date cu cuva de conexiuni creat a anterior. JDBC Connection Pool 1. Pool Name adresePool un nume simbolic ata sat cuvei 2. Resource Type Se selecteaza java.sql.Driver 3. Database Driver Vendor Se selecteaz a Derby 4. Introspect Se bifeaz a Enabled 5. Next 6. Driver Classname Se selecteaz a org.apache.derby.jdbc.ClientDriver 7. Additional Properties Se bifeaz a URL si se completeaz a coloana Value cu jdbc:derby:\. . . calea c atre locat ia bazei de date. . .\AgendaEMail 8. Finish JDBC Resources 1. JNDI Name jdbc/Adrese un nume simbolic ata sat resursei 2. Pool Name Se selecteaz a adresePool, numele cuvei de conexiuni 3. OK Din

11.1. SESSION EJB

275

Aplicat ie cu component a Entity O componenta Entity va adnotat a @Entity si corespunde unui tabel al bazei de date relat ionale. Exemplul 11.1.5 Aplicat ie de consultarea a bazei de date AgendaEMail. Desf a surarea aplicat iei este
agendae-ear |--> META-INF | | persistence.xml | agenda-ejb.jar

unde agenda-ejb.jar are structura


|--> ejb | | AgendaEMail.class | | AgendaEMailBean.class |--> entity | | Adrese.class |--> META-INF | | persistence.xml

Clasa Adrese.java este componenta Entity si corespunde tabelei adrese.


1 2 3 4 5 6 7 9 10 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

package e n t i t y ; import j a v a . i o . S e r i a l i z a b l e ; import j a v a x . p e r s i s t e n c e . E n t i t y ; import j a v a x . p e r s i s t e n c e . I d ; import j a v a x . p e r s i s t e n c e . GeneratedValue ; import j a v a x . p e r s i s t e n c e . GenerationType ; import j a v a . i o . S e r i a l i z a b l e ; @Entity public c l a s s Adrese implements S e r i a l i z a b l e { @Id @GeneratedValue ( s t r a t e g y=GenerationType . IDENTITY) private i n t i d ; private S t r i n g nume ; private S t r i n g e m a i l ; public S t r i n g getNume ( ) { return nume ; } public void setNume ( S t r i n g nume ) { t h i s . nume = nume ; } public S t r i n g g e t E m a i l ( ) { return e m a i l ; } public void s e t E m a i l ( S t r i n g e m a i l ) { this . email = email ; } public i n t g e t I d ( ) { return i d ; }

276
public void s e t I d ( i n t i d ) { this . id = id ; } }

CAPITOLUL 11. ENTERPRISE JAVA BEANS

32 33 34 35

Accesul la baza de date se realizeaz a printr-o component a EJB Session stateless Codul interfet ei AgendaEMail.java este
1 2 3 4 6 7 8 9 10

package e j b ; import j a v a x . e j b . Remote ; import e n t i t y . Adrese ; import j a v a . u t i l . L i s t ; @Remote public i n t e r f a c e AgendaEMail { public L i s t <Adrese > g e t E m a i l ( S t r i n g nume ) ; public L i s t <Adrese > getNume ( S t r i n g e m a i l ) ; }

implementat de clasa AgendaEMailBean.java


1 2 3 4 5 6 7 9 10 11 12 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31

package e j b ; import j a v a x . e j b . S t a t e l e s s ; import j a v a x . p e r s i s t e n c e . P e r s i s t e n c e C o n t e x t ; import j a v a x . p e r s i s t e n c e . EntityManager ; import j a v a x . p e r s i s t e n c e . Query ; import e n t i t y . Adrese ; import j a v a . u t i l . L i s t ; @Stateless public c l a s s AgendaEMailBean implements AgendaEMail { @ P e r s i s t e n c e C o n t e x t ( unitName= a g e n d a e p e r s i s t e n c e c t x ) EntityManager em ; public L i s t <Adrese > g e t E m a i l ( S t r i n g nume ) { S t r i n g nm= \ +nume+ \ ; S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . nume=+nm ; System . out . p r i n t l n ( s q l ) ; Query query=em . c r e a t e Q u e r y ( s q l ) ; L i s t <Adrese > l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ; return l i s t ; } public L i s t <Adrese > getNume ( S t r i n g e m a i l ) { S t r i n g eml= \ +e m a i l+ \ ; S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . e m a i l=+eml ; System . out . p r i n t l n ( s q l ) ; Query query=em . c r e a t e Q u e r y ( s q l ) ; L i s t <Adrese > l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ; return l i s t ; } }

Fi sierul de congurare persistence.xml este


1 2 3 4

< p e r s i s t e n c e xmlns= h t t p : // j a v a . sun . com/xml/ ns / p e r s i s t e n c e version= 1 . 0 > < p e r s i s t e n c e u n i t name= a g e n d a e p e r s i s t e n c e c t x > < j t a data s o u r c e> j d b c / Adrese</ j t a data s o u r c e> < p r o p e r t i e s>

11.1. SESSION EJB

277

5 6 7 8 9 10 11 12

< !Use t h e j a v a 2 d b f e a t u r e > < p r o p e r t y name= t o p l i n k . ddl g e n e r a t i o n v a l u e= none /> < ! Generate t h e s q l s p e c i f i c t o Derby d a t a b a s e > < p r o p e r t y name= t o p l i n k . j d b c . d r i v e r v a l u e= o r g . apache . derby . j d b c . C l i e n t D r i v e r /> </ p r o p e r t i e s > </ p e r s i s t e n c e u n i t> </ p e r s i s t e n c e >

Se observ a urm atoarele corelat ii Valoarea agendae persistence ctx atributului name a elementului persis tence-unit este utilizat n clasa AgendaEMailBean n adnotarea @PersistenceContext Elementul jta-data-surse cont ine numele JNDI a bazei de date denit n glasssh. Aplicat ia client Desf a surarea aplicat iei client este
agendae-client |--> ejb | | AgendaEMail.class |--> entity | | Adrese.class |--> META-INF | | MANIFEST.MF | Client.class

Fi sierul MANIFEST.MF este completat cu


Main-Class: Client Class-Path: agendae-ejb.jar

Clasa Client.java are codul


1 2 3 4 5 6 7 9 10 11 12 14 15 16 17

import import import import import import import

e j b . AgendaEMail ; j a v a x . e j b . EJB ; java . u t i l . List ; java . u t i l . I t e r a t o r ; java . u t i l . Scanner ; j a v a . u t i l . InputMismatchException ; e n t i t y . Adrese ;

public c l a s s C l i e n t { @EJB private s t a t i c AgendaEMail bean ; private s t a t i c L i s t <Adrese > l i s t =n u l l ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { i n t p r e l , no ; S t r i n g ch=Y , nume= , e m a i l= ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;

278

CAPITOLUL 11. ENTERPRISE JAVA BEANS

18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

I t e r a t o r <Adrese > i t e r=n u l l ; Adrese i n r e g=n u l l ; try { while ( ch . s t a r t s W i t h ( Y ) ) { do { System . out . p r i n t l n ( Continue ? (Y/N) ) ; ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; i f ( ch . s t a r t s W i t h ( Y ) ) { System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ; System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ; do { p r e l =0; try { p r e l=s c a n n e r . n e x t I n t ( ) ; } catch ( InputMismatchException e ) { } } while ( ( p r e l <1)&&( p r e l > 2 ) ) ; switch ( p r e l ) { case 1 : System . out . p r i n t l n ( Numele ) ; nume=s c a n n e r . n e x t ( ) . t r i m ( ) ; l i s t =bean . g e t E m a i l ( nume ) ; i t e r= l i s t . i t e r a t o r ( ) ; System . out . p r i n t l n ( A d r e s e l e de e m a i l p e n t r u : +nume ) ; while ( i t e r . hasNext ( ) ) { i n r e g =( Adrese ) i t e r . n e x t ( ) ; System . out . p r i n t l n ( i n r e g . g e t E m a i l ( ) ) ; } break ; case 2 : System . out . p r i n t l n ( Email ) ; e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ; l i s t =bean . getNume ( e m a i l ) ; i t e r= l i s t . i t e r a t o r ( ) ; System . out . p r i n t l n ( I n r e g i s t r a r i l e p e n t r u a d r e s a : +e m a i l ) ; while ( i t e r . hasNext ( ) ) { i n r e g =( Adrese ) i t e r . n e x t ( ) ; System . out . p r i n t l n ( i n r e g . getNume ( ) ) ; } break ; default : System . out . p r i n t l n ( Comanda e r o n a t a ) ; } } } } catch ( E x c e p t i o n e ) { e . printStackTrace ( ) ; } } }

Capitolul 12 Java Web Start


12.1 Java Web Start

O aplicat ie Java destinat a a utilizat a pe un calculator poate valoricat a si ntr-o ret ea, pe baza protocolului Java Network Launching Protocol - JNLP. Tehnologia poart a numele de Java Web Start. Aplicat ia Java trebuie s a satisfac a o serie de restrict ii: Aplicat ia trebuie arhivat a cu jar; Arhiva jar trebuie certicat a. Certicarea se realizeaz a cu utilitarele keytool.exe si jarsigner.exe din distribut ia jdk; Eventualele date necesare aplicat iei se introduc prin intermediul unei interfet e grace (JavaFX, swing, SWT, apache-pivot ); Acces limitat la propriet a tile si resursele sistemului client. Aplicat iei i se ata seaz a un sier xml, dar cu extensia jnlp, care se va apela dintr-un navigator. Pentru acest sier folosim terminologia de sier jnlp. Fi sierul jnlp xeaz a: referint a URL a aplicat ie (prin atributul codebase); arhivele jar utilizate (prin atributul href); clasa cu metoda main (prin atributul main-class). Ansamblul de resurse formeaz a o aplicat ie Web care poate desf a surat a ntr-un server Web (container de servlet) sau poate incorporat ntr-un servlet. Ar at am activit a tile care trebuie ntreprinse n cazul unui exemplu simplu dat de clasa VisualCmmdc.java. 279

280

CAPITOLUL 12. JAVA WEB START

1 2 3 4 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29 31 32 33 35 36 37 38 39 40 41

public c l a s s VisualCmmdc extends j a v a x . swing . JFrame { public VisualCmmdc ( ) { initComponents ( ) ; } private long cmmdc( long m, long n ) { . . . } private void i n i t C o m p o n e n t s ( ) { // cod g e n e r a t de Netbeans } private void cmmdcButtonMouseClicked ( j a v a . awt . e v e n t . MouseEvent e v t ) { try { S t r i n g sm=mTextField . g e t T e x t ( ) ; S t r i n g sn=n T e x t F i e l d . g e t T e x t ( ) ; long m =Long . par se Lo ng ( sm ) ; long n=Long . pa rs eL ong ( sn ) ; long c=cmmdc(m, n ) ; S t r i n g s =(new Long ( c ) ) . t o S t r i n g ( ) ; cmmdcTextField . s e t T e x t ( s ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } private void exitForm ( j a v a . awt . e v e n t . WindowEvent e v t ) { System . e x i t ( 0 ) ; } public s t a t i c void main ( S t r i n g a r g s [ ] ) { new VisualCmmdc ( ) . s e t V i s i b l e ( true ) ; } private private private private private private } j a v a x . swing . JButton cmmdcButton ; j a v a x . swing . J L a b e l mLabel ; j a v a x . swing . J L a b e l nLabel ; j a v a x . swing . J T e x t F i e l d mTextField ; j a v a x . swing . J T e x t F i e l d n T e x t F i e l d ; j a v a x . swing . J T e x t F i e l d cmmdcTextField ;

Interfat a grac a a programului este ilustrat a n Fig. 12.1

Figure 12.1: Interfat a grac a pentru rezolvarea ecuat iei algebrice.

12.1. JAVA WEB START

281

Instalare ntr-un server Web


Pentru instalarea aplicat iei ntr-un server Web, se parcurg pa sii: 1. Se arhiveaz a aplicat ia jar cfv cmmdc.jar *.class 2. Certicarea se obt ine prin (a) (b) (c)
keytool -genkey -keystore myKeystore -alias myself -dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO" -keypass abc123 -storepass 123abc keytool -selfcert -alias myself -keystore myKeystore -keypass abc123 -storepass 123abc jarsigner -keystore myKeystore -keypass abc123 -storepass 123abc resursa.jar myself

Primele dou a act iuni au ca rezultat obt inerea certicatului myKeystore iar ultima act iune reprezint a nglobarea certic arii n arhiva resursa.jar - n cazul exemplului cmmdc.jar. 3. Se editeaz a sierul launch .jnlp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < j n l p c o d e b a s e= h t t p : // h o s t : 8 0 8 0 /cmmdc> < i n f o r m a t i o n> < t i t l e > . . . </ t i t l e > < vendor> . . . </ vendor> < d e s c r i p t i o n > . . . </ d e s c r i p t i o n > </ i n f o r m a t i o n> < r e s o u r c e s> < j 2 s e version= 1.2+ /> < j a r h r e f=cmmdc . j a r /> </ r e s o u r c e s> < s e c u r i t y> < a l l p e r m i s s i o n s /> </ s e c u r i t y > < a p p l i c a t i o n d e s c main c l a s s=VisualCmmdc /> </ j n l p>

host se nlocuie ste cu numele calculatorului care g azduie ste serverul Web. 4. Se creaz a sier de apelare a aplicat iei (cmmdc.html )
1 2 3 4

<html> <body bgcolor=# AAEEAA> <center> <h3> V i s u a l Cmmdc A p p l i c a t i o n </ h3>

282

CAPITOLUL 12. JAVA WEB START

5 6 7 8 9

<a href= h t t p : / / h o s t : 8 0 8 0 / cmmdc/ l a u n c h . j n l p > Launch t h e a p p l i c a t i o n </ a> </ center> </ body> </ html>

5. Ansamblul
cmmdc | cmmdc.jar | cmmdc.html | launch.jnlp

se copiaz a n serverul Web. Dintr-un navigator, apelarea aplicat iei este http://host:port/cmmdc/ cmmdc. html. Fi sierul jnlp se descarc a pe calculatorul clientului si se proceseaz a cu bin\javaws.exe din Java.

Aplicat ia Java ca servlet


Pentru includerea aplicat ie Java ntr-un servlet, primii trei pa si prezentat i mai sus coincid. Singura diferent a const a n cont inutul referintelor, dup a host va apare portul utilizat de serverul Web container de servlet, uzual host:8080. 4. Intr-un catalog de lucru se creaz a structura de cataloage si siere:
app | cmmdc.jar | launch.jnlp WEB-INF |--> lib | | jnlp-servlet.jar | web.xml cmmdc.html

Fi sierul jnlp-servlet.jar se preia din distribut ia JDK, din catalogul sample/jnlp/servlet. Fi sierul web.xml este
1 2 3 4 5 6

? xml v e r s i o n= 1 . 0 e n c o d i n g= i s o 8859 1?> < !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp> < ! Standard Ac ti o n S e r v l e t C o n f i g u r a t i o n ( w i t h d e b u g g i n g ) >

12.1. JAVA WEB START

283

7 8 9 10 11 12 13 14 15 16 17 18 19

<webapp> < s e r v l e t> < s e r v l e t name> J n l p D o w n l o a d S e r v l e t</ s e r v l e t name> < s e r v l e t c l a s s> j n l p . sample . s e r v l e t . J n l p D o w n l o a d S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> J n l p D o w n l o a d S e r v l e t</ s e r v l e t name> < u r l p a t t e r n> . j n l p</ u r l p a t t e r n> </ s e r v l e t mapping> </webapp> </webapp>

5. Cont inutul catalogului de lucru se arhiveaz a ntr-un sier war. jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html 6. Utiliz and apache-tomcat sau jetty, de exemplu, sierul war se copiaz a n catalogul webapps al serverului web. Dintr-un navigator, apelarea aplicat iei se obt ine prin http://host:8080/cmmdc/cmmdc.html. Dac a aplicat ia Java utilizeaz a imagini grace acestea trebuie arhivate mpreun a cu aplicat ia, de exemplu ntr-un catalog images. Inc arcarea si a sarea unei imagini program andu-se prin ClassLoader cl=this.getClass().getClassLoader(); URL file=cl.getResource("images/pic1.jpg"); Image img=Toolkit.getDefaultToolkit().getImage(file); graphics.drawImage(img,x,y,this); 1. Dac a aplicat ia Java utilizeaz a alte resurse date prin siere jar atunci toate sierele jar trebuie s a poarte acea si certicare. 2. Fi sierele jar certicate se depun n catalogul app\lib. 3. In sierul jnlp, n elementul resources, pentru ecare sier jar utilizat se introduce declarat ia <jar href=lib/resource.jar/> Dac a arhiva jar a aplicat iei Java este executabil a atunci, n sierul jnlp, elementul application-desc poate lipsi. Intr-o arhiv a jar executabil a, sierul MANIFEST.MF indic a clasa cu metoda main si eventualele resurse externe utilizate ( siere jar) prin propriet a tile

284

CAPITOLUL 12. JAVA WEB START

Main-class: numeClasa Class-path: lib/resursa1.jar lib/resursa2.jar . . .

Pentru a obt ine sierul MANIFEST.MF cu aceste propriet a ti se editeaz a un sier text cu cont inutul de mai sus, denumit de exemplu myManifest.mf, si se arhiveaz a prin
jar cfvm numeArhiva.jar myManifest.mf *.class lib

Intreb ari recapitulative


1. Ce posibilitate ofer a tehnologia Java Web Start ? 2. O aplicat ie Java urmeaz a s a e valoricat pe Internet prin Java Web Start. Dac a aplicat ia necesit a date ale clientului ce restrict ie exist a si cum se satisface restrict ia ?

Capitolul 13 Java Management Extensions


Java Management Extensions (JMX) face posibil a ca un obiect Java s a permit a gestionarea metodelor si a anumitor c ampuri de c atre alte obiecte. Obiectele Java care si expun astfel resursele se numesc MBean - uri si formeaz a temelia cadrului de lucru JMX. Exist a mai multe tipuri de MBean-uri: Standard MBean; Dynamic MBean; Open MBean; Model MBean; MXBean; Un obiect care gestioneaz a resursele unui MBean se nume ste agent sau server MBean. Agentul dispune de mijloace care interact ioneaz a cu un MBean, permit a ndu-i: accesul la valorile unui c amp si la modicarea lor; invocarea metodelor. In general, un agent poate denit ca autorul unei act iuni; factor care provoac a act iuni; reprezentant al unei institut ii ns arcinat cu ndeplinirea unor act iuni. 285

286

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Terminologia server MBean se justic a prin faptul c a poate invocat de un program client. In aceast a ipostaz a, serverul MBean are rolul unui container de MBean-uri si de gestionare si execut ie a apelurilor client ilor. Structura unei aplicat ii JMX cont ine dou a nivele: componentele MBean; agentul (serverul MBean).

13.1
13.1.1

Standard MBean
Crearea unui Standard MBean

O component a MBean este alc atuit a dintr-o interfat a si o clas a care implementeaz a interfat a satisf ac and urm atoarele restrict ii: 1. interfat a are numele clasei care o implementeaz a av and n plus suxul MBean; 2. Interfat a si clasa care o implementeaz a apart in aceluia si pachet; 3. constructorii si metodele expuse trebuie s a e publice. In continuare c ampurile si metodele destinate expunerii se vor denumi atribute, respectiv operat ii. Fiec arui atribut xxx i se ata seaz a cel put in una din metodele public void setXxx(tip xxx){ this.xxx=xxx; } si / sau public tip getXxx(){ return xxx; } Un atribut se precizeaz a doar prin aceste metode, f ar a denirea / declararea c ampului corespunz ator. C ampul se dene ste n clasa ce implementeaz a interfat a MBean-ului. Astfel, un MBean este caracterizat de

13.1. STANDARD MBEAN

287

atribute care pot consultate (citite), modicate (scrise) sau cu ambele opt iuni. operat ii notic ari cu evident a modic arilor suferite de atribute. Exemplul 13.1.1 Construim un MBean cu atributele label ce poate numai citit; cursEuro care poate consultat si modicat; operat iile public String sayHello() a seaz a un mesaj; public long cmmdc(long m, long n); de calcul a celui mai mare divizor comun a dou a numere naturale. Interfat a IntroMBean este
1 3 4 5 6 8 9 10 11 12 13 14

package b a s i c ; public i n t e r f a c e IntroMBean { // O p e r a t i i public S t r i n g s a y H e l l o ( ) ; public long cmmdc( long m, long n ) ; // A t r i b u t e // read o n l y public S t r i n g g e t L a b e l ( ) ; // read w r i t e public double getCursEuro ( ) ; public void s e t C u r s E u r o ( double c u r s E u r o ) ; }

ind implementat de clasa Intro

288

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

1 3 5 6 7 9 10 11 13 14 15 17 18 19 21 22 23 24 25 26 28 29

package b a s i c ; public c l a s s I n t r o implements IntroMBean { // A t r i b u t e private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ; private double c u r s E u r o = 4 . 5 0 ; public S t r i n g g e t L a b e l ( ) { return l a b e l ; } public double getCursEuro ( ) { return c u r s E u r o ; } public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) { this . cursEuro = cursEuro ; } // O p e r a t i i public S t r i n g s a y H e l l o ( ) { S t r i n g message= H e l l o World ! ; System . out . p r i n t l n ( message ) ; return message ; } public long cmmdc( long m, long n ) { . . . } }

In acest caz nu s-a implementat posibilitatea notic arilor atributului cursEuro.

13.1.2

Crearea unui MBeanServer

Un agent sau MBean server implementeaz a interfat a MBeanServer. Un asemenea obiect se obt ine printr-una din metodele statice static MBeanServer ManagementFactory.getPlatformMBeanServer() Utilitarul jconsole permite conectarea la serverul MBean. static MBeanServer MBeanServerFactory.createMBeanServer() In agent se nregistreaz a componente MBean. Un obiect MBean este caracterizat de un nume, un obiect de tip ObjectName. Inregistrarea si / sau crearea unei componente MBean necesit a denirea n prealabil a acestui nume. Structura unei nume este domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . . unde

13.1. STANDARD MBEAN

289

domeniu este un nume simbolic (String). Dac a domeniul este stringul vid atunci se consider a valoarea implicit a DefaultDomain. atribute uzuale: type=numele MBean-ului index=num ar de identicare a MBean-ului Cel put in un atribut este obligatoriu. Clasa ObjectName Constructori ObjectName(String nume ) Parametrul nume are structura descris a mai sus. ObjectName(String domeniu , Hashtable<String,String> tabel ) ObjectName(String domeniu , String numeAtribut , String valAtribut ) Metode static ObjectName getInstance(String nume ) Inregistrarea si utilizarea MBean-ului face apel la metodele interfet ei MBeanServer. ObjectInstance Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblului alc atuit de un obiect ObjectName asociat unui MBean si numele clasei corespunz atoare. Interfat a MBeanServer Metode ObjectInstance registerMBean(Object obj , ObjectName nume ) Inregistreaz a pe platform a, instant a obj a unui MBean av and numele nume.

290

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

void unregister(ObjectName nume ) ObjectInstance createMBean(String numeClas a , ObjectName nume ) Creaz a si nregistreaz a un MBean de clas a numeClas a si de nume nume. ObjectInstance createMBean(String numeClas a , ObjectName nume , Object[] param , String[] sign ) In plus, sirul param cont ine parametri constructorului, de tip, respectiv sign. String getDefaultDomain() Object invoke(ObjectName mbeanName , String operationName , Object[] param , String[] paramTip ) Se invoc a operat ia operationName a MBean-ului mbeanName. Parametri necesari operat iei mpreun a cu tipurile corespunz atoare sunt dat i n variabilele param si respectiv paramTip. Object getAttribute(ObjectName mbeanName ,String atribut ) Returneaz a valoarea atributului atribut a mbean-ului mbeanName. void setAttribute(ObjectName mbeanName ,Attribute atribut ) Fixeaz a valoarea atributului atribut a MBean-ului mbeanName. Ret inem doar constructorul clasei Attribute prin Attribute(String nume , Object valoare ) MBeanInfo getMBeanInfo(ObjectName mbeanName ) Returneaz a un obiect de tip MBeanInfo util inspect arii resurselor unui MBean. Exist a mai multe sabloane de programare a nregistr arii unei componente MBean. Exemplul 13.1.2 Se creaz a dou a componente MBean de tip Intro care vor inspectate prin intermediul utilitarului jconsole1 - distribut ia jdk . Utilitarul jconsole permite apelarea operat iilor, modicarea atributelor si semnaleaz a notic arile.
In acest caz, este nevoie ca variabilele de tip clas a acoperitoare Double, Long s a e nlocuite prin tipuri predenite.
1

13.1. STANDARD MBEAN

291

1 2 3 4 6 7 8 9 10 11 12 14 15 16 17 19 20 22 23 25 26 27 29 30 31 32 33 34 35 36 37

package b a s i c ; import j a v a . l a n g . management . ManagementFactory ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanServer ; public c l a s s Main { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g domeniu= ; i f ( a r g s . l e n g t h > 0) domeniu=a r g s [ 0 ] ; try { // S e r v e r u l p l a t f o r m e i MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ; // V a r i a n t a 1 // C o n s t r u i r e a ObjectName c o r e s p u n z a t o r MBean u l u i ObjectName mbeanObjectName = new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=1 ) ; // Crearea MBean u l u i I n t r o mbean = new I n t r o ( ) ; // I n r e g i s t r a r e a MBean u l u i mbs . r e g i s t e r M B e a n ( mbean , mbeanObjectName ) ; // V a r i a n t a 2 mbeanObjectName=new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=2 ) ; mbs . createMBean ( b a s i c . I n t r o , mbeanObjectName ) ; // A s t e p t a r e n e d e f i n i t a System . out . p r i n t l n ( Waiting f o r e v e r . . . ) ; while ( true ) ; } catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } } }

Executarea aplicat iei revine la 1. Intr-o fereastr a DOS se lanseaz a agentul Main prin java -Dcom.sun.manager.jmxremote basic.Main 2. Intr-o alt a fereastr a DOS se lanseaz a jconsole pornind utilitarul jconsole. 3. In fereastra de dialog jconsole:Connect to Agent se d a clic pe Connect. 4. In panoul Tree g asim domeniul dat. Prin clic pe domeniu apar MBeanurile de indice 1 si 2. 5. Prin clic pe unul din aceste MBean-uri, n panoul central avem acces la atributele si la operat iile lor.

292

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Rezultatul unei operat ii apare ntr-o fereastr a de informare (Fig. 13.1).

Figure 13.1: Rezultatele furnizate de jcluster.

13.1.3

Notic ari

Pentru implementarea ret inerii de c atre un agent MBean a notic arilor, clasa ce implementeaz a interfat a MBean-ului trebuie s a extind a clasa NotificationBroadcasterSupport. Modic arile unui atribut se ret in ntr-un obiect de tip Notification si este transmis prin metoda sendNotification(Notification notication )

13.1. STANDARD MBEAN

293

a clasei NotificationBroadcasterSupport. Suplimentar se dene ste metoda public MBeanNotificationInfo[] getNotificationInfo() n care se precizeaz a tipul notic arii - (constant a denit a de clasa AttributeChangeNotification); clasa n care s-a generat noticarea String name = AttributeChangeNotification.class.getName(); o descriere a modic arii. Astfel, introducerea notic arilor presupune familiarizarea cu clasele NoticationBroadcasterSupport Constructori NotificationBroadcasterSupport() Metode void sendNotification(Notification noticare ) Notication Constructori Notification(String type , Object source , long sequenceNumber ) Notification(String type , Object source , long sequenceNumber , long timeStamp ) Notification(String type , Object source , long sequenceNumber , long timeStamp , String mesaj ) Notification(String type , Object source , long sequenceNumber , String mesaj ) Metode public void setUserData(Object userData ) public Object getUserData()

294

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

AttributeChangeNotication extends Notication Constructori AttributeChangeNotification(Object source , long sequenceNumber , long timeStamp , String msg , String attributeName , String attributeType , Object oldValue , Object newValuE ) C ampuri static String ATTRIBUTE CHANGE Semnaleaz a schimbarea atributului Exemplul 13.1.3 Extinderea MBean-ului Intro cu noticarea modic arilor atributelor n jconsole. Implementarea notic arilor n clasa Intro presupune modicarea metodei setCursEuro. Totodat a se adaug a metoda getNoticationInfo, ce furnizeaz a informat ii referitoare la modicarea ap arut a. Codul clasei care implementeaz a interfat a devine
1 2 3 4 5 7 8 9 11 12 13 15 17 19 20 21 22 23 24 25 26 27 28 29 30 31

package ag e nt n ; import j a v a x . management . N o t i f i c a t i o n ; import j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; import j a v a x . management . N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t ; import j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; public c l a s s I nt r oN extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t implements IntroNMBean { private long sequenceNumber =1; // A t r i b u t e private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ; private double c u r s E u r o = 4 . 5 0 ; public S t r i n g g e t L a b e l ( ) { . . . } public double getCursEuro ( ) { . . . } public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) { double oldCursEuro=t h i s . c u r s E u r o ; this . cursEuro = cursEuro ; // System . o u t . p r i n t l n ( Curs de schimb euro : + euro+ ron . ) ; N o t i f i c a t i o n n=new A t t r i b u t e C h a n g e N o t i f i c a t i o n ( this , sequenceNumber++, System . c u r r e n t T i m e M i l l i s ( ) , Schimbarea c u r s u l u i Euro , cursEuro , double , oldCursEuro , cursEuro ) ;

13.1. STANDARD MBEAN

295

32 33 35 36 37 38 39 40 41 42 43 44 46 47 49 50

sendNotification (n ) ; } public M B e a n N o t i f i c a t i o n I n f o [ ] g e t N o t i f i c a t i o n I n f o ( ) { S t r i n g [ ] t y p e s = new S t r i n g [ ] { A t t r i b u t e C h a n g e N o t i f i c a t i o n .ATTRIBUTE CHANGE }; S t r i n g name = A t t r i b u t e C h a n g e N o t i f i c a t i o n . c l a s s . getName ( ) ; S t r i n g d e s c r i p t i o n = An a t t r i b u t e o f t h i s MBean has changed ; MBeanNotificationInfo info = new M B e a n N o t i f i c a t i o n I n f o ( t y p e s , name , d e s c r i p t i o n ) ; return new M B e a n N o t i f i c a t i o n I n f o [ ] { i n f o } ; } // O p e r a t i i public S t r i n g s a y H e l l o ( ) { . . . } public long cmmdc( long m, long n ) { . . . } }

In jconsole pentru noticare, n prealabil este nevoie de subscriere.

13.1.4

Agent MBean

In exemplelele anterioare resursele unui MBean au fost utilizate prin jconsole. Valoricarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se programeaz a prin Exemplul 13.1.4
1 2 3 4 5 6 7 9 10 11 12 13 15 16 17 18 19 20 22 23 24

package a g e n t ; import j a v a . i o . IOException ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanServer ; import j a v a x . management . MBeanServerFactory ; import j a v a x . management . A t t r i b u t e ; import j a v a . u t i l . S c a n n e r ; public c l a s s Agent { public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { // Crearea A g e n t u l u i MBeanServer MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ; // Crearea unui MBean S t r i n g domain = mbs . g e t D e f a u l t D o m a i n ( ) ; S t r i n g className= a g e n t . I n t r o ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; mbs . createMBean ( className , mbeanObjectName ) ; // U t i l i z a r e a MBean u l u i // A p e l a r e a o p e r a t i i l o r S t r i n g o p e r a t i a= s a y H e l l o ;

296

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

25 27 28 29 30 31 32 33 34 35 36 37 39 40 41 43 44 45 46 47 48 49 50 51 52 53 54

mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ; o p e r a t i a=cmmdc ; System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( Primul numar : ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; long n=s c a n n e r . nextLong ( ) ; O b j e c t [ ] param={m, n } ; S t r i n g [ ] s i g n ={ l o n g , l o n g } ; Long r =(Long ) mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ; System . out . p r i n t l n ( cmmdc=+r . t o S t r i n g ( ) ) ; // U t i l i z a r e a A t r i b u t e l o r S t r i n g l a b e l =( S t r i n g ) mbs . g e t A t t r i b u t e ( mbeanObjectName , L a b e l ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i l a b e l : +l a b e l ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; double c u r s E u r o=s c a n n e r . nextDouble ( ) ; A t t r i b u t e c u r s=new A t t r i b u t e ( CursEuro , c u r s E u r o ) ; mbs . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; Double e u r o =(Double ) mbs . g e t A t t r i b u t e ( mbeanObjectName , CursEuro ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i c u r s E u r o : +e u r o ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } } }

13.1.5

Invocarea la distant a

Din punct de vedere al program arii distribuite, cazul interesant este cel n care clasa ce implementeaz a MBean-ul si clientul (agentul MBean) care o utilizeaz a se a a pe calculatoare diferite. In acest caz: Este nevoie de o clasa server (agent) al c arui rol este Instant ierea unui MBeanServer Instant iarea unui server de conexiune, obiect de tip MBeanServerConnection. Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaz a comunicat ia dintre un client si serverul MBeanServer. Serverul de conexiune si serverul MBeanServer apart in aceleia si clase. In cazul utiliz arii tehnologiei RMI rmiregistry si serverul MBeanServer trebuie s a ruleze pe acela si calculator. Utiliz and tehnologia RMI-IIOP, orbd si serverul MBeanServer pot rula pe calculatoare distincte.

13.1. STANDARD MBEAN

297

Lansarea n execut ie a serverului de conexiune. Clientul dispune de interfat a MBean-ului. Interfat a MBeanServerConnection este implementat a de clasa MBeanServer S ablonul de programare pentru instant ierea obiectului de tip MBeanServerConnection si lansarea sa n execut ie poate :
String surl="service:jmx:rmi:///jndi/rmi://host:port/numeServer" // String surl="service:jmx:iiop:///jndi/iiop://host:port/numeServer"; // Crearea unui server-conector JMXServiceURL url = new JMXServiceURL(surl); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url,null,MBeanServer); // // Pornirea server-conectorului cs.start(); System.out.println("Press Enter to finish !"); System.in.read(); cs.stop();

Serverul de conexiune are un nume, numeServer care trebuie cunoscut de c atre client. Lansarea n execut ie a serverului este precedat a de pornirea registrului rmiregistry, respectiv orbd. Exemplul 13.1.5
1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

package s e r v e r ; import j a v a x . management . MBeanServer ; import j a v a x . management . MBeanServerFactory ; import j a v a x . management . remote . JMXServiceURL ; import j a v a x . management . remote . JMXConnectorServer ; import j a v a x . management . remote . JMXConnectorServerFactory ; public c l a s s MBServer { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; // S t r i n g p o r t =1050; i f ( a r g s . l e n g t h ==0){ System . out . p r i n t l n ( The name o f t h e s e r v e r i s r e q u i r e d ) ; System . e x i t ( 0 ) ; } i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ; try { // Crearea MBeanServer MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;

298

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 43 44 45

// Crearea unui s e r v e r c o n e c t o r S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ // h o s t +:+ p o r t +/+ a r g s [ 0 ] ; JMXServiceURL u r l=new JMXServiceURL ( s u r l ) ; JMXConnectorServer c s= JMXConnectorServerFactory . newJMXConnectorServer ( u r l , null , mbs ) ; // P o r n i r e a s e r v e r c o n e c t o r u l u i cs . s tart ( ) ; System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; System . i n . r e a d ( ) ; cs . stop ( ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } } }

Primul argument care trebuie furnizat programului anterior (args[0] ) este numele serverului. Clientul, la r andul lui, este nevoit s a creeze un conector c atre server (agent), prin intermediul c aruia obt ine un obiect ce implementeaz a interfat a MBeanServerConnection. Prin acest obiect, clientul va putea crea MBean-uri - n agent - si le va putea utiliza resursele. S ablonul de programare pentru crearea obiectului MBeanServerConnection poate
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://host:port/numeServer"); JMXConnector jmxc = JMXConnectorFactory.connect(url,null); // Obtinerea obiectului de tip MBeanServerConnection MBeanServerConnection cs = jmxc.getMBeanServerConnection();

Resursele unui MBean se poate invoca prin metoda invoke(mbeanObjectName,operationName,param,sign ) a interfet ei MBeanServerConnection. crearea unui reprezentant local al MBean-ului prin metoda static a mbeanClass proxy = (mbeanClass) MBeanServerInvocationHandler.newProxyInstance( mbeanServerConnection,mbeanObjectName,mbeanClass.class,true); In nal, MBean-ul se sterge din serverul de conexiune, prin cs.unregisterMBean(mbeanObjectName).

13.1. STANDARD MBEAN

299

Exemplul 13.1.6 Client ce utilizeaz a un MBean Intro, denit n Exemplul 13.1.1


1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 41 42 43 45 46 47 48 49 51 52 54 55

package c l i e n t ; import j a v a . u t i l . S c a n n e r ; import j a v a x . management . MBeanServerConnection ; import j a v a x . management . ObjectName ; import j a v a x . management . A t t r i b u t e ; import j a v a x . management . M B e a n S e r v e r I n v o c a t i o n H a n d l e r ; import j a v a x . management . remote . JMXServiceURL ; import j a v a x . management . remote . JMXConnector ; import j a v a x . management . remote . JMXConnectorFactory ; public c l a s s C l i e n t { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; i f ( a r g s . l e n g t h <=1){ System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ; System . e x i t ( 0 ) ; } S t r i n g serverName=a r g s [ 0 ] ; S t r i n g domain=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ; i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 4 ] ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i de t i p M B e a n S e r v e r c s e c t i o n S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ // h o s t +:+ p o r t +/+ a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; // Domeniile a g e n t u l u i s u n t System . out . p r i n t l n ( Domains : ) ; S t r i n g domains [ ] = c s . getDomains ( ) ; f o r ( i n t i = 0 ; i < domains . l e n g t h ; i ++) { System . out . p r i n t l n ( \ tDomain [ + i + ] = + domains [ i ] ) ; } // i a r domeniul i m p l i c i t System . out . p r i n t l n ( DefaultDomain : +c s . g e t D e f a u l t D o m a i n ( ) ) ; System . out . p r i n t l n ( Domain : +domain ) ; // Crearea unui MBean I n t r o S t r i n g className= b a s i c . I n t r o ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; c s . createMBean ( className , mbeanObjectName , null , n u l l ) ; double c u r s E u r o ; long m, n ; // U t i l i z a r e a MBean u l u i // V a r i a n t a 1 de i n v o c a r e p r i n p r o x y

300

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

56 57 58 59 60 61 62 64 65 66 68 69 70 71 72 73 74 76 77 78 79 80 81 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 99 100 101 103 104 105 106 107 108 109 110 111 112 113 114

System . out . p r i n t l n ( V a r i a n t a de i n v o c a r e p r i n p r o x i ) ; IntroMBean proxy= ( IntroMBean ) M B e a n S e r v e r I n v o c a t i o n H a n d l e r . n e w P r o x y I n s t a n c e ( cs , mbeanObjectName , c l i e n t . IntroMBean . c l a s s , true ) ; // U t i l i z a r e a o p e r a t i i l o r // o p e r a t i a s a y H e l l o proxy . s a y H e l l o ( ) ; // o p e r a t i a cmmdc System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; System . out . p r i n t l n ( Primul numar : ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Cmmdc=+proxy . cmmdc(m, n ) ) ; // U t i l i z a r e a a t r i b u t e l o r System . out . p r i n t l n ( Numele : +proxy . g e t L a b e l ( ) ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; c u r s E u r o=s c a n n e r . nextDouble ( ) ; proxy . s e t C u r s E u r o ( c u r s E u r o ) ; System . out . p r i n t l n ( Euro : +proxy . getCursEuro ( ) ) ; // V a r i a n t a 2 de i n v o c a r e p r i n c o n e x i u n e System . out . p r i n t l n ( V a r i a n t a de i n v o c a r e p r i n c o n e x i u n e ) ; // A p e l a r e a o p e r a t i i l o r S t r i n g o p e r a t i a= s a y H e l l o ; c s . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ; o p e r a t i a=cmmdc ; System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ; System . out . p r i n t l n ( Primul numar : ) ; m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Al d o i l e a numar : ) ; n=s c a n n e r . nextLong ( ) ; O b j e c t [ ] param={m, n } ; S t r i n g [ ] s i g n ={ l o n g , l o n g } ; Long r =(Long ) c s . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ; System . out . p r i n t l n ( Cmmdc=+r . t o S t r i n g ( ) ) ; // U t i l i z a r e a A t r i b u t e l o r S t r i n g l a b e l =( S t r i n g ) c s . g e t A t t r i b u t e ( mbeanObjectName , L a b e l ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i l a b e l : +l a b e l ) ; System . out . p r i n t l n ( I n t r o d u c e t i c u r s u l e u r o ) ; c u r s E u r o=s c a n n e r . nextDouble ( ) ; A t t r i b u t e c u r s=new A t t r i b u t e ( CursEuro , c u r s E u r o ) ; c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; Double newEuro=(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , CursEuro ) ; System . out . p r i n t l n ( V a l o a r e a a t r i b u t u l u i e u r o : +newEuro ) ; c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } }

13.1. STANDARD MBEAN

301

115

Inspectarea si valoricarea resurselor unei componente MBean se poate face si prin intermediul metodei
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { System . out . p r i n t l n ( CLASA : \ t + i n f o . getClassName ( ) ) ; System . out . p r i n t l n ( DESCR: \ t + i n f o . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( ATTRIBUTE ) ; MBeanAttributeInfo [ ] a t t r I n f o = i n f o . g e t A t t r i b u t e s ( ) ; i f ( a t t r I n f o . length > 0) { f o r ( i n t i = 0 ; i < a t t r I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + a t t r I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \ tDESC : \ t + a t t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \ tTIP : \ t + a t t r I n f o [ i ] . getType ( ) + READ: + a t t r I n f o [ i ] . i s R e a d a b l e ( ) + WRITE: + a t t r I n f o [ i ] . i s W r i t a b l e ( ) ) ; } } else System . out . p r i n t l n ( \ t F a r a a t r i b u t e ! ) ; System . out . p r i n t l n ( CONSTRUCTORI ) ; MBeanConstructorInfo [ ] c o n s t r I n f o = i n f o . g e t C o n s t r u c t o r s ( ) ; f o r ( i n t i =0; i < c o n s t r I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + c o n s t r I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : \ t + c o n s t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \tPARAM: \ t + c o n s t r I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ; } System . out . p r i n t l n ( OPERATII ) ; MBeanOperationInfo [ ] o p I n f o = i n f o . g e t O p e r a t i o n s ( ) ; i f ( opInfo . length > 0) { f o r ( i n t i = 0 ; i < o p I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: \ t + o p I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : \ t + o p I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; System . out . p r i n t l n ( \tPARAM: \ t + o p I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ; } } else System . out . p r i n t l n ( \ t F a r a o p e r a t i i ) ; System . out . p r i n t l n ( NOTIFICARI ) ; MBeanNotificationInfo [ ] n o t i f I n f o = info . g e t N o t i f i c a t i o n s ( ) ; i f ( n o t i f I n f o . length > 0) { f o r ( i n t i = 0 ; i < n o t i f I n f o . l e n g t h ; i ++) { System . out . p r i n t l n ( \tNUME: + n o t i f I n f o [ i ] . getName ( ) ) ; System . out . p r i n t l n ( \tDESCR : + n o t i f I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ; String notifTypes [ ] = n o t i f I n f o [ i ] . getNotifTypes ( ) ; f o r ( i n t j = 0 ; j < n o t i f T y p e s . l e n g t h ; j ++) { System . out . p r i n t l n ( \ tTIP : + n o t i f T y p e s [ j ] ) ; } } } else System . out . p r i n t l n ( \ t F a r a n o t i f i c a r i ) ; }

Aceast a metod a poate inserat a n oricare din programele agent sau client.

302

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Noticarea la distant a
Noticarea la distant a presupune utilizarea unui MBean posed and aceast a facilitate. Pe partea de client trebuie implementat interfat a NotificationListener care declar a metoda public void handleNotification(Notification notication , Object handback ) Ata sarea si disponibilizarea clasei ce implementeaz a interfat a Notification Listener se obt in prin metodele interfet ei MBeanServerConnection: void addNotificationListener(ObjectName name , NotificationListener listener , NotificationFilter lter , Object handback )throws InstanceNotFoundException, IOException void removeNotificationListener(ObjectName name , ObjectName listener )throws InstanceNotFoundException, ListenerNotFoundException, IOException Exemplul 13.1.7 Folosind exemplul 13.1.6 - dar cu MBean-ul creat pentru 13.1.3 se creaz a un client cu noticare, care sesiseaz a modicarea valoarii atributului cursEuro a MBean-ului IntroN. Implementarea interfet ei NotificationListener este
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17

package c l i e n t ; import j a v a x . management . N o t i f i c a t i o n ; import j a v a x . management . N o t i f i c a t i o n L i s t e n e r ; import j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; public c l a s s C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r { public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n , O b j e c t handback ) { System . out . p r i n t l n ( \ n R e c e i v e d n o t i f i c a t i o n : + n o t i f i c a t i o n ) ; A t t r i b u t e C h a n g e N o t i f i c a t i o n myNotif= ( AttributeChangeNotification ) n o t i f i c a t i o n ; System . out . p r i n t l n ( Curs i n i t i a l : + myNotif . g e tO l d V a l u e ( ) . t o S t r i n g ( ) ) ; System . out . p r i n t l n ( Curs c u r e n t : + myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ; } }

Codul clasei client este


1 2 3 4 5

package c l i e n t ; import j a v a x . management . ObjectName ; import j a v a x . management . MBeanInfo ; import j a v a x . management . M B e a n A t t r i b u t e I n f o ; import j a v a x . management . MBeanConstructorInfo ;

13.1. STANDARD MBEAN

303

6 7 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 40 41 43 44 45 46 47 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

import import import import import import

j a v a x . management . MBeanOperationInfo ; j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; j a v a x . management . MBeanServerConnection ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;

public c l a s s C l i e n t N o t i f { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; i f ( a r g s . l e n g t h <=1){ System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ; System . e x i t ( 0 ) ; } S t r i n g serverName=a r g s [ 0 ] ; S t r i n g domain=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ; i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 3 ] ; C l i e n t N o t i f o b j=new C l i e n t N o t i f ( ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i // de t i p MBeanServerConnection S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBean u l u i IntroN S t r i n g className= b a s i c n . I nt r oN ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ; getMBeanResources ( i n f o ) ; // U t i l i z a r e a n o t i f i c a r i i // Crearea unui a s c u l t a t o r C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ; // A c t i v a r e a n o t i f i c a t o r u l u i c s . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , o b j ) ; Thread . s l e e p ( 5 0 0 ) ; // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; try { System . i n . r e a d ( ) ; } catch ( j a v a . i o . IOException e ) { } c s . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ; // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } }

304

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

66 68

private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . } }

Clasa Client care creaz a MBean-ul trebuie lansat a naintea clasei ClientNotif. Aceste dou a clase pot rula pe calculatoare distincte. Exemplul 13.1.8 O aplicat ie servlet ntret ine un cont. Act iunile ce pot ntreprinse sunt: depunerea unei sume, extragerea unei sume n limita soldului si consultarea contului. Contul este implementat ca un MBean standard. Se cere urm arirea la distant a a modic arilor suferite de cont. Interfat a contului (a MBean-ului) este
1 2 3 4 5 6

public i n t e r f a c e ContMBean { // A t r i b u t e // read w r i t e public double getCont ( ) ; public void s e t C o n t ( double c o n t ) ; }

implementat prin
1 2 3 4 6 7 8 9 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32

import import import import

j a v a x . management . N o t i f i c a t i o n ; j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; j a v a x . management . N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t ; j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ;

public c l a s s Cont extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t implements ContMBean { private long sequenceNumber =1; private double c o n t ; public synchronized double getCont ( ) { return c o n t ; } public synchronized void s e t C o n t ( double c o n t ) { double oldCont=t h i s . c o n t ; t h i s . c o n t=c o n t ; N o t i f i c a t i o n n=new A t t r i b u t e C h a n g e N o t i f i c a t i o n ( this , sequenceNumber++, System . c u r r e n t T i m e M i l l i s ( ) , Schimbarea Cont , cont , double , oldCont , cont ) ; sendNotification (n ) ; } public M B e a n N o t i f i c a t i o n I n f o [ ] g e t N o t i f i c a t i o n I n f o ( ) { S t r i n g [ ] t y p e s = new S t r i n g [ ] { A t t r i b u t e C h a n g e N o t i f i c a t i o n .ATTRIBUTE CHANGE

13.1. STANDARD MBEAN

305

33 34 35 36 37 38 39 40

}; S t r i n g name = A t t r i b u t e C h a n g e N o t i f i c a t i o n . c l a s s . getName ( ) ; S t r i n g d e s c r i p t i o n = An a t t r i b u t e o f t h i s MBean has changed ; MBeanNotificationInfo info = new M B e a n N o t i f i c a t i o n I n f o ( t y p e s , name , d e s c r i p t i o n ) ; return new M B e a n N o t i f i c a t i o n I n f o [ ] { i n f o } ; } }

Codul servlet-ului este


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

import import import import import import import import import import import import import import import

j a v a . i o . IOException ; javax . s e r v l e t . ServletException ; javax . s e r v l e t . http . HttpServlet ; javax . s e r v l e t . http . HttpServletRequest ; javax . s e r v l e t . http . HttpServletResponse ; javax . s e r v l e t . ServletOutputStream ; javax . s e r v l e t . ServletConfig ; j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ; j a v a x . s e r v l e t . a n n o t a t i o n . WebInitParam ; j a v a x . management . ObjectName ; j a v a x . management . A t t r i b u t e ; j a v a x . management . MBeanServerConnection ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;

@WebServlet ( u r l P a t t e r n s = / a p p d e p o z i t , initParams = { @WebInitParam ( name = j m x S e r v e r H o s t , v a l u e = l o c a l h o s t ) } ) public c l a s s D e p o z i t S e r v l e t extends H t t p S e r v l e t { MBeanServerConnection c s=n u l l ; ObjectName mbeanObjectName=n u l l ; String host ; S t r i n g p o r t= 1099 ; S t r i n g s e r v e r= s e r v e r ; public void i n i t ( S e r v l e t C o n f i g c o n f i g ) { try { super . i n i t ( c o n f i g ) ; h o s t=c o n f i g . g e t I n i t P a r a m e t e r ( j m x S e r v e r H o s t ) ; S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +h o s t+ : +p o r t+ / +s e r v e r ; // S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ h o s t +:+ p o r t +/+ s e r v e r ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; c s = jmxc . getMBeanServerConnection ( ) ; S t r i n g domain = c s . g e t D e f a u l t D o m a i n ( ) ; S t r i n g className= Cont ; S t r i n g sObjectName=domain+ : t y p e=+className ; mbeanObjectName = new ObjectName ( sObjectName ) ; c s . createMBean ( className , mbeanObjectName , null , n u l l ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; System . e x i t ( 0 ) ; } }

306

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ; S t r i n g o p e r=r e q . g e t P a r a m e t e r ( o p e r ) ; S t r i n g message= ; double suma=0; i f ( ! o p e r . e q u a l s ( con ) ) { S t r i n g s=r e q . g e t P a r a m e t e r ( suma ) ; suma=Double . p a r s e D o u b l e ( s ) ; } Double o b j V a l u e=n u l l ; try { o b j V a l u e =(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , Cont ) ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } double v a l u e=o b j V a l u e . d o u b l e V a l u e ( ) ; double x ; A t t r i b u t e c u r s=n u l l ; switch ( o p e r ) { case dep : x=v a l u e+suma ; c u r s=new A t t r i b u t e ( Cont , x ) ; try { c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; message=Sa depus suma ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } break ; case e x t : i f ( v a l u e >=suma ) { x=v a l u e suma ; c u r s=new A t t r i b u t e ( Cont , x ) ; try { c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ; message=Sa e x t r a s suma ; } catch ( E x c e p t i o n e ) { message=JMX E r r o r : +e . g e t M e s s a g e ( ) ; } } else { message= C e r e r e a nu p o a t e f i i n d e p l i n i t a ; } break ; case con : message=Suma d i n c o n t e s t e +v a l u e+ u n i t . ; break ; } r e s . setContentType ( t e x t / html ) ; out . p r i n t l n ( <html> ) ; out . p r i n t l n ( <head>< t i t l e >Depozit </ t i t l e ></head> ) ; out . p r i n t l n ( <body> ) ; out . p r i n t l n ( <h1>O p e r a t i u n i Cont </h1> ) ; out . p r i n t l n ( <p> ) ;

13.1. STANDARD MBEAN

307

108 109 110 111 112 114 115 116 117 118

out . out . out . out . }

p r i n t l n ( message ) ; p r i n t l n ( </p> ) ; p r i n t l n ( </body ></html> ) ; close ();

public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s ) throws S e r v l e t E x c e p t i o n , IOException { doGet ( req , r e s ) ; } }

Pagina de apelare a servlet-ului ind (index.html )


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

<html> <head> < t i t l e > S e r v l e t u l H e l l o </ t i t l e > </ head> <body bgcolor=#a a e e a a > <center> <h1> Pagina de &#238; n t r e &#355; i n e r e a d e p o z i t u l u i </ h1> <form method= p o s t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / appcont / a p p d e p o z i t > <p> I n t r o d u c e &#355; i : <p>Opera&#355; i a : < s e l e c t name= o p e r > <option value= dep >Depunere <option value= e x t > E x t r a g e r e <option value= con > C o n s u l t a r e </ s e l e c t> <p> <input type= t e x t name=suma value= 0 > <p> <input type= submit value= Executa > </ form> </ center> </ body> </ html>

Clientlul care urm are ste de la distant a contul are codul


1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19

import import import import import import import import import import import import import

j a v a x . management . ObjectName ; j a v a x . management . MBeanInfo ; j a v a x . management . M B e a n A t t r i b u t e I n f o ; j a v a x . management . MBeanConstructorInfo ; j a v a x . management . MBeanOperationInfo ; j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ; j a v a x . management . MBeanServerConnection ; j a v a x . management . N o t i f i c a t i o n ; j a v a x . management . N o t i f i c a t i o n L i s t e n e r ; j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ; j a v a x . management . remote . JMXServiceURL ; j a v a x . management . remote . JMXConnector ; j a v a x . management . remote . JMXConnectorFactory ;

public c l a s s C l i e n t N o t i f { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g h o s t= l o c a l h o s t ; S t r i n g p o r t= 1099 ; i f ( a r g s . l e n g t h ==0){

308

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 42 43 45 46 47 48 49 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 68 69 71 72 73 74 75 76 77 78

System . out . p r i n t l n ( The S e r v e r name i s r e q u i r e d ) ; System . e x i t ( 0 ) ; } i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ; i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ; C l i e n t N o t i f o b j=new C l i e n t N o t i f ( ) ; try { // Crearea unui c o n e c t o r s i a o b i e c t u l u i de // t i p MBeanServerConnection S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / + h o s t+ : +p o r t+ / +a r g s [ 0 ] ; JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ; JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ; MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ; S t r i n g domain = c s . ge t D e f a u l t D o m a i n ( ) ; System . out . p r i n t l n ( DefaultDomain : +domain ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBean u l u i Cont S t r i n g className= Cont ; S t r i n g sObjectName=domain+ : t y p e=+className ; ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ; MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ; getMBeanResources ( i n f o ) ; // U t i l i z a r e a n o t i f i c a r i i // Crearea unui a s c u l t a t o r C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ; // A c t i v a r e a n o t i f i c a t o r u l u i c s . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , o b j ) ; Thread . s l e e p ( 5 0 0 ) ; // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i System . out . p r i n t l n ( P r e s s Enter t o f i n i s h ! ) ; try { System . i n . r e a d ( ) ; } catch ( j a v a . i o . IOException e ) { } c s . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ; // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ; } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; e . printStackTrace ( ) ; } } private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . } } c l a s s C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r { public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n , O b j e c t handback ) { System . out . p r i n t l n ( \ n R e c e i v e d n o t i f i c a t i o n : + n o t i f i c a t i o n ) ; A t t r i b u t e C h a n g e N o t i f i c a t i o n myNotif= ( AttributeChangeNotification ) n o t i f i c a t i o n ; System . out . p r i n t l n ( S o l d i n i t i a l : + myNotif . g et O l d V a l u e ( ) . t o S t r i n g ( ) ) ;

13.1. STANDARD MBEAN

309

79 80 81 82

System . out . p r i n t l n ( S o l d c u r e n t : + myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ; } }

Serverul MBean este cel prezentat n Exemplul 13.1.5. Serverul MBean este plasat n servlet ( n catalogul WEB-INF/classes al aplicat iei) iar clientul care urm are ste de la distant a se poate aa oriunde. Dup a instalarea servlet-ului se lanseaz a pe ma sina acestuia server-ul MBean. Deoarece noticarea presupune existent a MBean-ului, iar acesta se instant eaz a prin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depun and 0 unit a ti. Dup a aceast a operat ie se lanseaz a n execut ie programul ClientNotif.

Intreb ari recapitulative


1. Ce posibilitate ofer a Java Management Extensions (JMX) ? 2. Care este structute unui MBean standard ? 3. Precizat i cont inutul unui server MBean cu agent i la distant a. 4. Precizat i termenul de noticare n leg atur a cu MBean.

310

CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Partea III ANEXE

311

Anexa A Unelte de dezvoltare


Incepem aceast a sect iune prin a introduce c ateva elemente privind sintaxa unui document xml.

A.1

XML

EXtensible Markup Language (XML) reprezint a un limbaj pentru denirea marcajelor de semantic a, care mpart un document n p art i identicabile n document. Din 1998, XML este un standard World Wide Web Consortium (W3C). Totodat a XML este un meta-limbaj pentru denirea sintaxei de utilizat n alte domenii. XML descrie structura si semantica si nu formatarea. Structura unui document XML este <?xml version="1.0" encoding="tip_codare" [standalone="yes"]?> corpul documentului alcatuit din elemente Prima linie - preambulul - reprezint a declarat ia de document XML. Tipul cod arii poate utf-8, iso-8859-1. Corpul documentului este alc atuit din elemente. Inceputul unui element este indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. Elementele pot cu corp, alc atuit din alte elemente, av and sintaxa <marcaj> corpul elementului </marcaj> 313

314 sau f ar a corp, caz n care sintaxa este <marcaj/>

ANEXA A. UNELTE DE DEZVOLTARE

Un marcaj poate avea atribute date prin sintaxa numeAtribut="valoareAtribut" Valoarea unui atribut este cuprins a ntre ghilimele (). <marcaj numeAtribut="valoareAtribut" . . .> corpul elementului </marcaj> Exist a un singur element r ad acin a. Elementele unui document XML formeaz a un arbore. Fiec arui marcaj de nceput al unui element trebuie s a-i corespund a un marcaj de sf ar sit. Caracterele mari si mici din denumirea unui element sunt distincte (case sensitive ). Elementele ncuib arite (nested )- incluse ntr-un alt element - nu se pot amesteca, adic a un marcaj de sf ar sit corespunde ultimului marcaj de nceput. Un comentariu se indic a prin <!-Text comentariu --> Exemplul A.1.1 Fi sier XML - denumirile elementelor si cont inutul lor permit nt elegerea simpl a a semanticii introduse n document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

<? xml version= 1 . 0 e n c o d i n g= u t f 8 ?> < c u r s u r i> < d i s c i p l i n a f e l = o b l i g a t o r i u > <nume> A n a l i z a numerica </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 1 </ s e m i n a r> < l a b o r a t o r> 1 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > < d i s c i p l i n a f e l = o b l i g a t o r i u > <nume> Programare d i s t r i b u i t a </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 0 </ s e m i n a r> < l a b o r a t o r> 2 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > < d i s c i p l i n a f e l = o b l i g a t o r i u >

A.1. XML

315

20 21 22 23 24 25 26 27

<nume> S o f t matematic </nume> <fond detimp> < c u r s> 2 </ c u r s> < s e m i n a r> 0 </ s e m i n a r> < l a b o r a t o r> 1 </ l a b o r a t o r> </ fond detimp> </ d i s c i p l i n a > </ c u r s u r i >

Un document XML este bine formatat dac a: exist a preambul; ecare element este nchis sau i corespunde un marcaj de inchidere; marcajele ncuib arite nu se amestec a. Un document XML este valid dac a este bine formatat; n cazul c a exist a o referint a c atre XML Schema atunci documentul XML este conform schemei. Un produs informatic accesibil gratuit, care permite vericarea bine format arii si a validit a tii unui document xml, este XML Copy Editor. Pentru validare, dac a sierul XML Schema se a a n alt catalog dec at cel al serului xml atunci acestuia i se asociaz a XML Schema prin XML Associate XML Schema. . . Prelucrarea unui document XML n Java se poate face pe baza interfet elor de programare: Document Object Model - DOM; Simple API for XML - SAX; Stream API for XML - StAX; Java Architecture for XML Binding - JAXB. Amintim faptul c a reprezentarea obiectelor matematice prin elemente XML constituie subiectul a dou a proiecte MathML si OpenMath. Obiectivul limbajului MathML este reprezentarea unui text matematic ntr-un document HTML, n timp ce obiectivul proiectului OpenMath este reprezentarea semantic a a datelor matematice pentru realizarea de aplicat ii cooperante ntre sisteme de calcul simbolic - CAS (Computer Algebra System ).

316

ANEXA A. UNELTE DE DEZVOLTARE

A.2

apache-ant

Utilitarul apache-ant asigur a executarea unui sir de comenzi de operare. Aceste comenzi se nregistreaz a ntr-un sier de tip xml, cu denumirea build.xml. Astfel, apache-ant se substituie unui sier de comenzi bat n Windows sau unui script shell din Linux/Unix. Avantajul obt inut const a n independent a fat a de platforma de calcul (Windows, Linux). Instalarea const a n dezarhivarea sierului desc arcat din Internet. Lansarea n execut ie necesit a xarea variabilei de mediu JAVA HOME, ce cont ine calea la distribut ia Java. Lansarea se poate face prin urm atorul sier de comenzi set JAVA_HOME=. . . set ANT_HOME=. . . %ANT_HOME%\bin\ant.bat %1 Parametrul %1 acestui sier de comenzi reprezint a obiectivul care se dore ste a atins. Dac a se modic a denumirea sau locat ia sierului build.xml atunci sierul de comenzi se invoc a cu opt iunea -buildfile. Un sier build.xml corespunde unui proiect (project), alc atuit din unul sau mai multe obiective (target). Atingerea ecar arui obiectiv const a din ndeplinirea uneia sau mai multor sarcini (task). Apache-ant cont ine o familie predenit a de sarcini. Programatorul are datoria x arii atributelor sarcinilor. Manualul din documentat ia produsului cont ine descrierea atributelor c at si exemple. In general, o sarcin a reprezint a o operat ie executat a uzual n linia de comand a. Atributele se dau, respect and sintaxa XML numeAtribut = valoareAtribut Astfel, un proiect apare sub forma <project name="numeProiect" default="obiectiv" basedir="catalogDeReferinta"> <target name="numeObiectiv"> sarcini </target> . . . . . . . </project>

A.2. APACHE-ANT

317

Dac a la apelarea lui Apache-ant lipse ste parametrul opt ional atunci se va executa obiectivul default. Intr-un proiect se pot deni variabile prin marcajul <property name=numeVariabila value=valoareVariabila /> O variabil a denit a se va utiliza cu sintaxa ${numeVariabila}. Exemplul A.2.1 Fi sierul build pentru execut ia programelor din 1.2.
1 2 4 5 6 8 9 10 11 12 13 14 16 17 18 20 21 22 24 25 26 27

< p r o j e c t name= S o c k e t default= S e r v e r b a s e d i r= . > < d e s c r i p t i o n > S o c l u r i TCP </ d e s c r i p t i o n > < ! s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d > < p r o p e r t y name= b u i l d l o c a t i o n= work /> < p r o p e r t y name= s r c l o c a t i o n= . /> < t a r g e t name= i n i t > < ! C r e a t e t h e time stamp > <tstamp /> < ! C r e a t e t h e b u i l d d i r e c t o r y s t r u c t u r e used by c o m p i l e > < d e l e t e d i r= $ { b u i l d } /> <mkdir d i r= $ { b u i l d } /> </ t a r g e t> < t a r g e t name= Compile depends= i n i t d e s c r i p t i o n= c o m p i l e t h e s o u r c e > < j a v a c s r c d i r= $ { s r c } d e s t d i r= $ { b u i l d } i n c l u d e a n t r u n t i m e= f a l s e /> </ t a r g e t> < t a r g e t name= S e r v e r depends= Compile > < j a v a c l a s s n a m e=MyMServer c l a s s p a t h= $ { b u i l d } f o r k= t r u e /> </ t a r g e t> < t a r g e t name= C l i e n t > < j a v a c l a s s n a m e= VisualCmmdcClient c l a s s p a t h= $ { b u i l d } f o r k= t r u e /> </ t a r g e t> </ p r o j e c t>

Utilizarea lui apache-ant presupune c a toate resursele utilizate, cuprinse uzual n siere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul local. Dac a calculatorul este conectat la Internet, atunci resursele publice pot desc arcate mpreun a cu toate dependint ele si utilizate prin apache-ant, folosind suplimentar apache-ivy 1 . In vederea utiliz arii lui apache-ivy se copiaz a sierul ivy-*.jar din distribut ia apache-ivy n ANT HOME\lib. Fi sierul build.xml cont ine n plus
1

Asem an ator cu maven, un alt produs de dezvoltare.

318

ANEXA A. UNELTE DE DEZVOLTARE

<project name="Proiect" basedir="." default="obiectiv_final" xmlns:ivy="antlib:org.apache.ivy.ant"> . . . <!-- ================================= target: resolve ================================= --> <target name="resolve" depends="init" description="--> retreive dependencies with ivy"> <ivy:retrieve/> </target> <!-- ================================= target: report ================================= --> <target name="report" depends="resolve" description="--> generates a report of dependencies"> <ivy:report todir="${report.dir}"/> </target> . . . </project> la care se adaug a un sier ivy.xml, cu dependint ele necesare aplicat iei care urmeaz a a preluate dintr-unul din depozitele ivy - local, shared, public
<ivy-module version="2.0"> <info organisation="cs.unitbv.ro" module="Biblioteca-Ivy"/> <dependencies> <dependency org="commons-fileupload" name="commons-fileupload" rev="1.2"/> . . . </dependencies> </ivy-module>

A.3

apache-maven

Apache-maven 2 este un alt cadru de dezvoltare si gestiune a proiectelor (Project management framework). Calculatorul pe care se dezvolt a proiectul / aplicat ia trebuie s a e conectat la internet. Resursele necesare ndeplinitii diferitelor sarcini (maven artifacts ) sunt preluate din internet si depuse ntr un depozit local maven (local repository ). In prezent sunt ntret inute depozite
2

Maven acumulator de cuno stiint e (Idi s).

A.3. APACHE-MAVEN

319

publice de resurse soft necesare dezvolt arii de aplicat ii cu maven 3 iar dezvoltatorii de instrumente soft au posibilitatea de a- si promova produsele prin depunerea ntr-un depozit maven. Dintr-un asemenea depozit public resursele necesare sunt desc arcate n depozitul local.

Gestiunea proiectelor cu apache-maven


Instalarea produsului const a n dezarhivarea sierului desc arcat din internet ntr-un catalog MAVEN HOME. Utilizarea produsului necesit a Completarea variabilei de sistem PATH cu calea MAVEN HOME\bin. Declararea variabilei JAVA HOME av and ca valoare calea c atre distribut ia jdk folosit a. In mod obi snuit depozitul local maven este C:\Documents and Settings\client \.m2\repository Locat ia depozitului local se poate modica, introduc and elementul <localRepository>volum:/cale/catalog_depozit</localRepository> n sierul MAVEN HOME\conf\settings.xml. Potrivit principiului separ arii preocup arilor (Separation of Conserns), un proiect maven produce o singur a ie sire. Declararea unui proiect se face printr-un sier pom.xml (Project Object Model). Este sarcina programatorului s a completeze sierul pom.xml, creat la generarea structurii de cataloage ale proiectului, cu specicarea resurselor suplimentare sau a condit ion arilor n efectuarea unor operat ii (de exemplu, prezent a adnot arilor necesit a utilizarea versiunii Java 1.5). Dezvoltarea unei aplicat ii / proiect prin maven presupune generarea unei structuri de cataloage (Standard directory layout for projects). Aceast a structur a de cataloage este specic a tipului / sablonului de aplicat ie (archetype, n limbajul maven ). S abloane uzuale de aplicat ii: Nume sablon Semnicat ia maven-archetype-quickstart aplicat ie simpl a ( sablonul implicit) maven-archetype-webapp aplicat ie Web maven-archetype-j2ee-simple aplicat ie JEE
3

De exemplu repo1.maven.org/maven2.

320

ANEXA A. UNELTE DE DEZVOLTARE

S ablonul se specic a n parametrul -DarchetypeArtifactId al comenzii mvn archetype:create. Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare, testare, etc) se obt in prin comenzi maven. Comenzile maven sunt de dou a tipuri:

Comenzi pentru gestiunea ciclului de viat a al unui proiect (lifecycle commands):

Comanda maven mvn -version

Semnicat ia a seaz a versiunea maven (util a pentru vericarea funct ion arii lui maven ) mvn clean sterge sierele maven generate mvn compile compilarea sursele Java mvn test-compile compileaz a sursele Java care realizeaz a testele junit mvn test execut a testul junit mvn package creaz a o arhiv a jar sau war mvn install depune arhiva jar sau war n depozitul local

Comenzi de operare inserate (plugin commands):

A.3. APACHE-MAVEN

321 Semnicat ia genereaz a structura de cataloage a proiectului


mvn archetype:create \ -DgroupId=numelePachetuluiAplicat iei \ -DartifactId=numeleProiectului \ -DarchetypeArtifactId=numeS ablon

Comanda maven mvn archetype:create

mvn archetype:generate mvn mvn mvn mvn mvn

genereaz a structura de cataloage a proiectului sablonul se alege dintr-o list a clean:clean sterge sierele generate n urma compil arii compiler:compile compilarea sursele Java surefire:test execut a testul junit jar:jar creaz a o arhiv a jar install:install-file depune o arhiv a jar n depozitul local
mvn install:install-file \ -Dfile=numeFi sier \ -DgroupId=numePachet \ -DartifactId=numeProiect \ -Dversion=versiunea \ -Dpackaging=tipArhiv a

mvn exec:java

execut a metoda main a unei clase


mvn exec:java -Dexec.mainClass=clasaMetodeiMain

Astfel comanda
mvn archetype:create -DgroupId=unitbv.cs.calcul -DartifactId=hello -DarchetypeArtifactId=maven-archetype-quickstart

genereaz a arborescent a
hello |--> src | |--> main | | |--> | | | | | | | | | | | | | |--> test | | |--> | | | | | | | | | | | | | pom.xml

java |--> | | | java |--> | | |

unitbv |--> cs | |--> calcul | | | App.java

unitbv |--> cs | |--> calcul | | | AppTest.java

Descrierea proiectului este dat a n sierul pom.xml generat

322

ANEXA A. UNELTE DE DEZVOLTARE

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> u n i t b v . c s . c a l c u l </ g r o u p I d> < a r t i f a c t I d > h e l l o </ a r t i f a c t I d > < p a c k a g i n g> j a r </ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o </name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> </ p r o j e c t>

App.java este programul Java HelloWorld iar AppTest.java este un program de vericare bazat pe junit. Pentru testarea aplicat iei, din catalogul hello se execut a comenzile
mvn compile mvn test

Sarcina programatorul este acela de a nlocui aceste programe cu cele care rezolv a sarcinile proiectului. Pentru orice prelucrare toate dependint ele trebuie s a se g aseasc a n depozitul local maven. Exemplul A.3.1 Dezvoltarea aplicat iei de calcul al celui mai mare divizor comun a dou a numere naturale utiliz and maven. Gener am proiectul maven
mvn archetype:create -DgroupId=simple.app.cmmdc -DartifactId=cmmdc -DarchetypeArtifactId=maven-archetype-quickstart

Inlocuim clasa App cu


1 2 3 4 5 6 7 9 10

package s i m p l e . app . cmmdc ; public c l a s s MyCmmdc{ private long m, n ; MyCmmdc( long m, long n ) { t h i s .m = m; t h i s . n=n ; } public long cmmdc ( ) { . . . } }

si

A.3. APACHE-MAVEN

323

1 2 4 5 6 7 8 9 10 11 12 13 14

package s i m p l e . app . cmmdc ; import j a v a . u t i l . S c a n n e r ; public c l a s s App { public s t a t i c void main ( S t r i n g [ ] a r g s ) { S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; System . out . p r i n t l n ( m = ) ; long m =s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; MyCmmdc o b j=new MyCmmdc(m, n ) ; System . out . p r i n t l n ( cmmdc = +o b j . cmmdc ( ) ) ; } }

iar programul de testare AppTest.java prin


1 2 3 5 6 7 9 10 12 13 14 15 16 17 19 20 21 22 23 24 26 27 28 29

package s i m p l e . app . cmmdc ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s T e s t P r o i e c t { MyCmmdc o b j ; long r e z ; @Before public void setUp ( ) {} @Test public void testCmmdc1 ( ) { o b j=new MyCmmdc( 5 6 , 4 2 ) ; r e z=o b j . cmmdc ( ) ; assertEquals (14 , rez ) ; } @Test public void testCmmdc2 ( ) { o b j=new MyCmmdc( 4 5 , 3 1 ) ; r e z=o b j . cmmdc ( ) ; assertEquals (1 , rez ) ; } public s t a t i c void main ( S t r i n g a r g s [ ] ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( p r o i e c t . T e s t P r o i e c t ) ; } }

Intruc at dorim s a folosim cea mai recent a versiune a produsului junit modic am n sierul pom.xml preciz and versiunea junit c at si versiunea distribut iei jdk utilizat a, care trebuie s a e cel put in 1.5 (restrict ie impus a mai nou de junit ).
1 2 3 4 5

< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n>

324

ANEXA A. UNELTE DE DEZVOLTARE

6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

< g r o u p I d> u n i t b v . p r o i e c t . mycmmdc</ g r o u p I d> < a r t i f a c t I d >cmmdc</ a r t i f a c t I d > < p a c k a g i n g> j a r </ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name>cmmdc</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 4 . 1 1</ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> </ p r o j e c t>

Operarea poate
mvn archetype:create -DgroupId=simple.app.cmmdc -DartifactId=cmmdc cd cmmdc mvn compile mvn test mvn exec:java -Dexec.mainClass="simple.app.cmmdc.App"

maven cu ant
In maven se pot integra sarcini apache-ant pentru orice etap a al evolut iei unei aplicat ii. Utilizarea const a n completarea sierului pom.xml cu
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <phase> <!-- etapa de viata : compile, package, install, test --> </phase> <configuration> <tasks> <!-- Exemplu <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="runtime_classpath" refid="maven.runtime.classpath"/> <property name="test_classpath" refid="maven.test.classpath"/> <property name="plugin_classpath" refid="maven.plugin.classpath"/> <echo message="compile classpath: <echo message="runtime classpath: <echo message="test classpath: <echo message="plugin classpath: --> </tasks> </configuration> <goals> <goal>run</goal> ${compile_classpath}"/> ${runtime_classpath}"/> ${test_classpath}"/> ${plugin_classpath}"/>

A.3. APACHE-MAVEN

325

</goals> </execution> </executions> </plugin> </plugins> </build>

In elementul <tasks> se denesc sarcinile ant care se doresc executate la comanda corespunz atoare prelucr arii etapei din evolut ia proiectului maven compile, package, install, test, etc. Mai precis, elementele <echo> se nlocuiesc cu sarcinile ant care se doresc efectuate. Propriet a tile se denesc n elementul
<properties> <nume.proprietate>valoare</nume.proprietate> . . . </properties>

RMI prin maven


Exemplul A.3.2 Aplicat ia de calcul a celui mai mare divizor comun. Corespunz ator celor trei componente ale unei aplicat ii RMI se genereaz a ntr-un catalog comenzile maven
mvn archetype:create -DgroupId=i.cmmdc -DartifactId=i mvn archetype:create -DgroupId=s.cmmdc -DartifactId=s mvn archetype:create -DgroupId=c.cmmdc -DartifactId=c

Clasa App.java se nlocuie ste cu Catalog Clase i ICmmdc.java s CmmdcImpl.java c CmmdcClient.java Fi sierele pom.xml din s,c se completeaz a cu
<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0.0</version> </dependency>

In catalogul aplicat iei se introduce sierul pom.xml

326

ANEXA A. UNELTE DE DEZVOLTARE

1 2 3 4 5 6 7 8 9 10 11 12 13 14

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < p r o j e c t> < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < a r t i f a c t I d >cmmdc</ a r t i f a c t I d > < g r o u p I d>cmmdc</ g r o u p I d> <version> 1 . 0 . 0 </ version> <name>RMI</name> < p a c k a g i n g>pom</ p a c k a g i n g> <modules> <module> i </ module> <module> s</ module> <module>c</ module> </ modules> </ p r o j e c t>

Se execut a: 1. mvn clean install 2. Din s


set Path=. . .\apache-maven-*\bin;%PATH% set JAVA_HOME=. . . start rmiregistry 1099 mvn -e exec:java -Dexec.mainClass="s.cmmdc.CmmdcImpl"

3. Din c
set Path=. . .\apache-maven-*\bin;%PATH% set JAVA_HOME=. . . mvn exec:java -Dexec.mainClass="c.cmmdc.CmmdcClient"

Dezvoltarea unui servlet prin maven


Dezvoltarea unui servlet prin maven 4 se va exemplica prin aplicat ia n care servletul r aspunde clientului cu mesajul Hi nume client, nume client ind parametru transmis de c atre client la apelarea servlet-ului. Container de servlet i cu care lucreaz a maven este jetty. Dezvoltarea revine la parcurgerea pa silor: 1. Generarea aplicat iei:
mvn archetype:create -DgroupId=hello -DartifactId=helloname -DarchetypeArtifactId=maven-archetype-webapp

Iverson W., Building Web Applications with maven 2, http://www.java.net/author/ will-iverson

A.3. APACHE-MAVEN

327

Se creaz a structura de cataloage si siere


helloname |--> src | |--> main | | |--> | | |--> | | | | | | | | | | pom.xml

resources webapp |--> WEB-INF | | web.xml | index.jsp

unde sierul pom.xml este


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> h e l l o </ g r o u p I d> < a r t i f a c t I d > h e l l o n a m e</ a r t i f a c t I d > < p a c k a g i n g>war</ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o n a m e Maven Webapp</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s> <dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> </ d e p e n d e n c i e s> < b u i l d> < f i n a l N a m e> h e l l o n a m e</ f i n a l N a m e> </ b u i l d> </ p r o j e c t>

2. Completarea aplicat iei. Se completeaz a structura creat a anterior cu


helloname |--> src | |--> main | | |--> | | | | | | | | |--> | | |--> | | | | | | | | | | pom.xml

java |--> hello | | HelloServlet.java resources webapp |--> WEB-INF | | web.xml | index.html

HelloServlet.java este cel utilizat n capitolul Servlet din cursul de Programare distribuit a.

328

ANEXA A. UNELTE DE DEZVOLTARE

Fi sierul web.xml este completat cu elementele specice servlet-ului (servlet si servlet-mapping).


1 2 3 5 6 7 8 9 10 11 12 13 14 15

< !D O C T Y P E webapp PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd > <webapp> < d i s p l a y name> Archetype C r e a t e d Web A p p l i c a t i o n</ d i s p l a y name> < s e r v l e t> < s e r v l e t name> h e l l o </ s e r v l e t name> < s e r v l e t c l a s s > h e l l o . H e l l o S e r v l e t </ s e r v l e t c l a s s > </ s e r v l e t > < s e r v l e t mapping> < s e r v l e t name> h e l l o </ s e r v l e t name> < u r l p a t t e r n>/ h e l l o </ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>

Fi sierul index.jsp se nlocuie ste cu sierul index.html utilizat la 5 servletul ment ionat anterior . Fi sierul pom.xml se completeaz a cu Referint ele la resursele javax.servlet.servlet-api, necesare compil arii.
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency>

Referint ele serverului Web jetty


<plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins>

Codul sierului pom.xml devine


1 2 3 4 5 6 7 8 9 10 11 12

< p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchema i n s t a n c e x s i : s c h e m a L o c a t i o n= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0 h t t p : //maven . apache . o r g /maven v 4 0 0 . xsd > < m o d e l V e r s i o n> 4 . 0 . 0 </ m o d e l V e r s i o n> < g r o u p I d> h e l l o </ g r o u p I d> < a r t i f a c t I d > h e l l o n a m e</ a r t i f a c t I d > < p a c k a g i n g>war</ p a c k a g i n g> <version>1.0 SNAPSHOT </ version> <name> h e l l o n a m e Maven Webapp</name> < u r l> h t t p : //maven . apache . o r g</ u r l> < d e p e n d e n c i e s>

Atent ie la parametri de apelare a servlet-ului, care eventual trebuie adaptat i. Contextul aplicat iei coincide cu parametrul artifactId

A.3. APACHE-MAVEN

329

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

<dependency> < g r o u p I d> j u n i t </ g r o u p I d> < a r t i f a c t I d > j u n i t </ a r t i f a c t I d > <version> 3 . 8 . 1 </ version> < s c o p e> t e s t </ s c o p e> </ dependency> <dependency> < g r o u p I d> j a v a x . s e r v l e t </ g r o u p I d> < a r t i f a c t I d > s e r v l e t a p i</ a r t i f a c t I d > <version> 2 . 5</ version> < s c o p e> p r o v i d e d</ s c o p e> </ dependency> </ d e p e n d e n c i e s> < b u i l d> < f i n a l N a m e> h e l l o n a m e</ f i n a l N a m e> < p l u g i n s> < p l u g i n> < g r o u p I d> o r g . mortbay . j e t t y </ g r o u p I d> < a r t i f a c t I d >maven j e t t y p l u g i n</ a r t i f a c t I d > </ p l u g i n> </ p l u g i n s> </ b u i l d> </ p r o j e c t>

Clauza provided din elementul <scope> implic a ne includerea resursei in arhiva war. 3. Prelucrarea revine la (a) compilare: mvn compile (b) arhivare: mvn package (c) lansarea serverului Web jetty : mvn jetty:run Serverul se opre ste cu Ctrl+C. (d) testarea servlet-ului: ntr-un navigator se deschide pagina http://localhost:8080/helloname. Pentru a utiliza serverul Web apache-tomcat este sucient s a 1. desf a sur am arhiva war: mvn tomcat:deploy 2. lans am serverul Web n lucru: mvn tomcat:run Serverul se opre ste cu Ctrl+C.

Aplicat ie JSP prin maven


Ne propunem s a calcul am cel mai mare divizor comun a dou a numere naturale ntr-o pagin a JSP utiliz and o component a Java pentru calculul propriu-zis (cf. cursului de Programare distribuit a).

330

ANEXA A. UNELTE DE DEZVOLTARE

Deoarece maven produce o singur a ie sire se vor realiza dou a proiecte maven : unul pentru componenta Java, care va arhivat a si depus a n depozitul local iar cel alalt pentru aplicat ia JSP. 1. Realizarea componentei Java. (a) Generarea proiectului maven
mvn archetype:create -DgroupId=cmmdc -DartifactId=cmmdcjsp

Se nlocuie ste clasa App.java cu clasa CmmdcBean (curs Programare distribuit a). (b) Prelucrarea const a din i. mvn compile ii. mvn package iii. mvn install 2. Realizarea aplicat iei JSP. (a) Generarea cadrului:
mvn archetype:create -DgroupId=jsp -DartifactId=cmmdcjsp -DarchetypeArtifactId=maven-archetype-webapp

(b) Dezvoltarea aplicat iei: i. Se completeaz a aplicat ia cu sierele cmmdc.jsp si index.html din cursul Programare distribuit a, desf a surarea ind
cmmdcjsp |--> src | |--> main | | |--> | | |--> | | | | | | | | | | | | | pom.xml

resources webapp |--> WEB-INF | | web.xml index.html cmmdc.jsp

ii. Fi sierul pom.xml se completeaz a cu referint a pentru componenta Java


<dependency> <groupId>cmmdc</groupId> <artifactId>cmmdcjsp</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

si pentru serverul Web jetty


<plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins>

A.3. APACHE-MAVEN

331

(c) Prelucrarea const a din i. mvn package ii. mvn jetty:run

332

ANEXA A. UNELTE DE DEZVOLTARE

Anexa B Testare cu junit


Vericarea / testarea automat a a programelor Java se poate face cu produsul informatic junit. Deseori se formuleaz a probleme de test ale c aror rezultate sunt cunoscute, cu rolul de a verica funct ionarea unui program de rezolvare, pentru depistarea unor gre seli. S-a dezvoltat si o metodologie de lucru Test Driven Development - (TDD) care presupune pentru orice clas a elaborat a realizarea unui program de testare, chiar a priori. Un alt produs care are acela si scop de vericare a rezultatelor este TestNG. junit permite vericarea automat a a rezultatelor furnizate de un program, pentru o mult ime de date de test. Instalarea produsului const a din dezarhivarea sierului desc arcat ntr-un si execut ie, variabila de sistem classpath catalog JUNIT HOME. Pentru compilare trebuie s a cont in a referint a JUNIT HOME\junit-*.jar. Utilizarea produsului ntr-un program Java const a din: 1. Declararea resurselor pachetului junit prin import org.junit.*; import static org.junit.Assert.*; 2. Declararea clasei cu testele junit - uzual n metoda main. org.junit.runner.JUnitCore.main("AppClass "); 3. Eventuale operat ii necesare nainte sau dup a efectuarea testelor se precizeaz a respectiv, n c ate o metod a care a fost declarat a cu adnotarea @org.junit.Before si respectiv, @org.junit.After. 4. Testele se denesc n metode declarate cu adnotarea @org.junit.Test. Clasa Assert posed a metodele de vericare ale unui rezultat: 333

334

ANEXA B. TESTARE CU JUNIT

static void assertEquals(Tip a steptat, Tip actual ) unde Tip poate double, int, long, Object. static void assertEquals(double a steptat, double actual, double delta ) Testul reu se ste dac a |a steptat-actual | < delta. static void assertArrayEquals(Tip[ ] a steptat, Tip[ ] actual ) unde Tip poate byte, char, int, long, short, Object. static void assertTrue(boolean condit ie ) static void assertFalse(boolean condit ie ) static void assertNull(Object object ) static void assertNotNull(Object object ) In cazul exemplului
1 2 4 5 6 8 9 10 12 13 14 15 17 18 19 20

import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s Exemplu { public double r e z u l t a t = 1 . 0 ; public double e p s=1e 6; double g e t V a l u e ( ) { return 1 . 0 0 0 0 0 0 1 ; } @Test public void t e s t ( ) { a s s e r t E q u a l s ( r e z u l t a t , getValue ( ) , eps ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( Exemplu ) ; } }

se obt ine
JUnit version 4.5 . Time: 0.03 OK (1 test)

Exemplul B.0.3 Testarea clasei App ( 2.2.1).

335

1 2 3 5 6 8 9 10 11 13 14 15 16

package s e r v e r ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; public c l a s s TestApp { private App app ; @Before public void i n i t i a l i z a r e ( ) { app=new App ( ) ; } @Test public void t e s t ( ) { a s s e r t E q u a l s ( 8 , app . cmmdc ( 5 6 , 2 4 ) ) ; }

19 20 21 22

public s t a t i c void main ( S t r i n g [ ] a r g s ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( s e r v e r . TestApp ) ; } }

Exemplul B.0.4 Testarea clasei MyMServer ( 2.2.1).


1 2 3 4 5 6 8 9 11 12 13 14 16 17 18 19 20 21 22 24 25 26 27

package s e r v e r . impl ; import s e r v e r . ; import o r g . j u n i t . ; import s t a t i c o r g . j u n i t . A s s e r t . ; import j a v a . n e t . S e r v e r S o c k e t ; import i s e r v e r . IMyMServer ; public c l a s s TestMyMServer { private IMyMServer o b j ; @Before public void i n i t i a l i z a r e ( ) { o b j=new MyMServer ( ) ; } @Test public void t e s t ( ) { i n t p o r t =7999; O b j e c t r e s u l t=o b j . g e t S e r v e r S o c k e t ( p o r t ) ; a s s e r t N o t N u l l ( Must not r e t u r n a n u l l r e s p o n s e , r e s u l t ) ; a s s e r t E q u a l s ( ServerSocket . class , r e s u l t . g e t C l a s s ( ) ) ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { o r g . j u n i t . r u n n e r . JUnitCore . main ( s e r v e r . impl . TestMyMServer ) ; } }

336

ANEXA B. TESTARE CU JUNIT

Anexa C Jurnalizare
Jurnalizarea adic a a sarea / ret inerea rezultatelor sau evenimentelor ntrun sier. Deseori prezint a interes evolut ia procesului de calcul prin prisma In acest sens se pot utiliza: unor rezultate intermediare. pachetul java.util.logging din jdk. apache-log4j-2. slf4j (Simple Logging Facade for Java), (www.QOS.ch, Quality of Open Software). logback (logback.qos.ch).

Jurnalizare prin java.util.logging


S ablonul de programare cu a sarea mesajelor pe ecranul monitorului este
1 3 4 6 7 8 9 10 11

import j a v a . u t i l . l o g g i n g . Logger ; public c l a s s Exemplu { s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . s e v e r e ( SEVERE : H e l l o ) ; l o g g e r . warning ( WARNING : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; } }

Programul a seaz a
Jan 23, 2013 2:34:40 PM Exemplu main SEVERE: SEVERE : Hello Jan 23, 2013 2:34:40 PM Exemplu main

337

338

ANEXA C. JURNALIZARE

WARNING: WARNING : Hello Jan 23, 2013 2:34:40 PM Exemplu main INFO: INFO : Hello

Dac a dorim ca rezultatele s a e nscrise ntr-un sier, de exemplu logging.txt atunci clasa de mai sus se modic a n
1 2 3 4 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22

import import import import

java . java . java . java .

u t i l . l o g g i n g . Logger ; u t i l . logging . FileHandler ; u t i l . l o g g i n g . SimpleFormatter ; i o . IOException ;

public c l a s s Exemplu { s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { try { F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( l o g g i n g . t x t ) ; l o g g i n g F i l e . s e t F o r m a t t e r ( new S i m p l e F o r m a t t e r ( ) ) ; l o g g e r . addHandler ( l o g g i n g F i l e ) ; } catch ( IOException e ) { System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } l o g g e r . s e v e r e ( SEVERE : H e l l o ) ; l o g g e r . warning ( WARNING : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; } }

Jurnalizare prin logback


Jurnalizare cu ret inerea rezultatelor n sier
1 2 3 5 6 7 8 9 10 11 12 13 14

package l o g t e s t ; import o r g . s l f 4 j . Logger ; import o r g . s l f 4 j . L o g g e r F a c t o r y ; public c l a s s Exemplu { s t a t i c Logger l o g g e r=L o g g e r F a c t o r y . g e t L o g g e r ( Exemplu ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . t r a c e ( TRACE : H e l l o ) ; l o g g e r . debug ( DEBUG : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . warn ( WARN : H e l l o ) ; l o g g e r . e r r o r ( ERROR : H e l l o ) ; } }

cu sierul de congurare
1 2 3 4 5 6

< c o n f i g u r a t i o n> < appender name=STDOUT c l a s s= ch . q o s . l o g b a c k . c o r e . ConsoleAppender > < e n c o d e r> < p a t t e r n> %d { HH:mm:ss . SSS } [% t h r e a d ] %5 l e v e l %l o g g e r { 36 } %msg%n </ p a t t e r n>

339

7 8 10 11 12 13 14 15 16 17 19 20 21 22 23 24

</ e n c o d e r> </ appender> < appender name=FILE c l a s s= ch . q o s . l o g b a c k . c o r e . F i l e A p p e n d e r > < f i l e > r e s u l t s . l o g</ f i l e > < e n c o d e r> < p a t t e r n> %d a t e %l e v e l [% t h r e a d ] %l o g g e r { 10 } [% f i l e : %l i n e ] %msg%n </ p a t t e r n> </ e n c o d e r> </ appender> < l o g g e r name= l o g t e s t l e v e l=TRACE /> < r o o t l e v e l= t r a c e > <appender r e f r e f=STDOUT /> <appender r e f r e f=FILE /> </ r o o t> </ c o n f i g u r a t i o n>

Jurnalizare prin apache-log4j-2


Jurnalizare cu ret inerea rezultatelor n sier
1 2 4 5 7 8 9 10 11 12 13

import o r g . apache . l o g g i n g . l o g 4 j . LogManager ; import o r g . apache . l o g g i n g . l o g 4 j . Logger ; public c l a s s Exemplu { s t a t i c Logger l o g g e r = LogManager . g e t L o g g e r ( Exemplu . c l a s s ) ; public s t a t i c void main ( S t r i n g a r g s [ ] ) { l o g g e r . warn ( WARN : H e l l o ) ; l o g g e r . debug ( DEBUG : H e l l o ) ; l o g g e r . i n f o ( INFO : H e l l o ) ; l o g g e r . f a t a l ( FATAL : H e l l o ) ; } }

cu sierul de congurare
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

<? xml version= 1 . 0 e n c o d i n g=UTF8 ?> < c o n f i g u r a t i o n s t a t u s=OFF> < p r o p e r t i e s> < p r o p e r t y name= f i l e n a m e > r e s u l t s . l o g</ p r o p e r t y> </ p r o p e r t i e s > < a p p e n d e r s> < C o n s o l e name= C o n s o l e t a r g e t=SYSTEM OUT> <P a t t e r n L a y o u t p a t t e r n=%d { HH:mm:ss . SSS } [% t ] %5 l e v e l %l o g g e r { 36 } %msg%n /> </ C o n s o l e> < F i l e name= F i l e f i l e N a m e= $ { f i l e n a m e } > <P a t t e r n L a y o u t p a t t e r n=%d { HH:mm:ss . SSS } [% t ] %5 l e v e l %l o g g e r { 36 } %msg%n /> </ F i l e > </ a p p e n d e r s> < l o g g e r s> < r o o t l e v e l= t r a c e > <appender r e f r e f= C o n s o l e />

340
<appender r e f r e f= F i l e /> </ r o o t> </ l o g g e r s > </ c o n f i g u r a t i o n>

ANEXA C. JURNALIZARE

19 20 21 22

Anexa D Component a Java (Java Bean )


O component a Java este o clas a care poate interact iona cu alte componente Java, cu un document jsp, etc. O componenta Java cont ine cel put in Un constructor f ar a nici un argument; O mult ime de c ampuri declarate private; Pentru ecare asemenea c amp private Tip xyz; trebuie denite cel put in una din metodele public void setXyz(Tip xyz){ this.xyz=xyz; } public Tip getXyz(){ return xyz; }

341

342

JAVA ANEXA D. COMPONENTA

Anexa E Adnot ari


O adnotare este o completare, o not a sau o nsemnare care explic a sau ntrege ste un text. O metadat a este o adnotare a unei date. In Java o adnotare (annotation ) este o metadata a unui element de cod (identicator al unei entit a ti din codul Java). O adnotare poate s a- si fac a efectul: asupra codului surs a, naintea compil arii; asupra codului obiect, dup a compilare, dar naintea execut arii; n timpul execut iei codului. Din punctul de vedere al sintaxei intereseaz a denirea unei adnot ari; declararea unei adnot ari; procesarea unei adnot ari.

E.1

Denirea unei adnot ari

Sintaxa utilizat a este import java.lang.annotation.*; modicator @interface NumeAdnotare { declarare Element 1 343

344 declarare Element 2 . . . } unde declarare Element poate : tip numeElement (); tip numeElement () default valoare ; iar tip poate

ANEXA E. ADNOTARI

predenit (int, short, long, byte, char, float, double, boolean); String Class enum adnotare tablou ale c arei elemente sunt de un tip precizat anterior Adnotarea se salveaz a ca sier text, sub numele NumeAdnotare.java. Dup a num arul elementelor declarate ntr-o adnotare, acesta poate 0 - caz n care adnotarea este de tip marker; 1 sau mai multe elemente (single-element / multi-value annotation ).

E.2

Declararea unei adnot ari

O adnotare se poate referi la un pachet, clas a, interfat a , metod a, c amp. Inaintea declar arii elementului asupra c aruia act ioneaz a, adnotarea se indic a prin @NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )

E.3. PROCESAREA UNEI ADNOTARI

345

E.3

Procesarea unei adnot ari


Meta-adnot ari Target Retention Documented Inherited

Java declar a adnot arile Adnot ari regulate Override Deprecated SuppressWarnings

Adnotarea Override
Adnotarea Override precizeaz a faptul c a se suprascrie un element al clasei p arinte.
1 2 3 4 5 6 8 9 10 11 12

import j a v a . u t i l . Date ; public c l a s s T e s t O v e r r i d e extends Date { @Override public S t r i n g t o S t r i n g ( ) { return super . t o S t r i n g ()+ T e s t O v e r r i d e ; } public s t a t i c void main ( S t r i n g [ ] a r g s ) { Date d=new T e s t O v e r r i d e ( ) ; System . out . p r i n t l n ( d . t o S t r i n g ( ) ) ; } }

Dac a n locul liniei 9 se pune Date d=new Date(); atunci nu mai apare mesajul TestOverride.

Adnotarea Deprecated
Adnotarea Deprecated are ca efect a sarea unui mesaj de avertisment n momentul compil arii. Exemplic am cu clasele
1 2 3 4 5 6

public c l a s s MyDeprecated { @Deprecated public void doJob ( ) { System . out . p r i n t l n ( This i s d e p r e c a t e d ) ; } } public c l a s s T e s t D e p r e c a t e d { public s t a t i c void main ( S t r i n g [ ] a r g s ) { MyDeprecated o b j=new MyDeprecated ( ) ; o b j . doJob ( ) ; } }

1 2 3 4 5 6

346 Mesajul de avertisment este


Note: TestDeprecated.java uses or overrides a deprecated API. Note: Recompile with -Xlint:deprecation for details.

ANEXA E. ADNOTARI

Coment and linia adnot arii are ca efect la o nou a compilare disparit ia mesajelor de avertisment.

Adnotarea SuppressWarnings
Adnotarea SuppressWarnings inhib a a sarea mesajelor de avertisment. Relu am exemplul anterior schimb and clasa Test. In urma compil arii nu mai apar mesajele de avertisment ment ionate mai sus.
1 2 4 5 6 7 8

@SuppressWarnings ( d e p r e c a t i o n ) public c l a s s T e s t S u p p r e s s W a r n i n g s { public s t a t i c void main ( S t r i n g [ ] a r g s ) { MyDeprecated o b j=new MyDeprecated ( ) ; o b j . doJob ( ) ; } }

Adnotarea Target
Adnotarea Target precizeaz a elementul asupra c areia act ioneaz a: ElementType.TYPE ElementType.FIELD ElementType.METHOD ElementType.PARAMETER ElementType.CONSTRUCTOR ElementType.LOCAL VARIABLE ElementType.ANNOTATION TYPE

Adnotarea Retention
Adnotarea Retention precizeaz a momentul act iunii adnot arii: RetentionPolicy.SOURCE RetentionPolicy.CLASS RetentionPolicy.RUNTIME

E.3. PROCESAREA UNEI ADNOTARI

347

Adnotarea Documented
Adnotarea Documented are ca efect ment ionarea adnot arii n documentul obt inut prin javadoc. Fie clasele
1 3 4

import j a v a . l a n g . a n n o t a t i o n . Documented ; @Documented public @ i n t e r f a c e MyDocumented {}

si
1 2 3 4 6 7 8 9 10

public c l a s s TestDocumented { public s t a t i c void main ( S t r i n g [ ] a r g s ) { new TestDocumented ( ) . doDocumented ( ) ; } @MyDocumented public void doDocumented ( ) { System . out . p r i n t l n ( Test Documented ) ; } }

javadoc se lanseaz a prin


md docs javadoc -d docs *Documented.java

Procesarea unei adnot ari se refer a n primul r and la reg asirea n momentul execut iei a valorilor elementelor adnot arii. In funct ie de valorile reg asite se pot implementa act iuni specice. Procesarea unei adnot ari se bazeaz a pe metodele interfet ei AnnotationElement, implementat a de clasele Class, Constructor, Field, Method, Package: <T extends Annotation> T getAnnotation(Class<T> annotationClass ) Annotation[] getAnnotations() Annotation[] getDeclaredAnnotations() boolean isAnnotationPresent(Class<? notationClass ) Consider am adnotarea
1 2 3 4 6

extends Annotation> an-

import import import import

java . lang . annotation . Retention ; j a v a . l a n g . a n n o t a t i o n . Tar ge t ; java . lang . annotation . RetentionPolicy ; j a v a . l a n g . a n n o t a t i o n . ElementType ;

@Retention ( R e t e n t i o n P o l i c y .RUNTIME)

348

ANEXA E. ADNOTARI

7 8 9 10 11

@Target ( ElementType .METHOD) public @ i n t e r f a c e MyAnnotation { S t r i n g doAction ( ) default ; i n t i n d e x ( ) default 0 ; }

pe care o utiliz am n clasa


1 3 4 5 6 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

import j a v a . l a n g . r e f l e c t . Method ; public c l a s s T e s t A n n o t a t i o n { public s t a t i c void main ( S t r i n g [ ] a r g s ) { T e s t A n n o t a t i o n o b j=new T e s t A n n o t a t i o n ( ) ; obj . v e r i f ( obj ) ; } @MyAnnotation ( doAction=XYZ , i n d e x =1) public void v e r i f ( O b j e c t o ) { try { C l a s s c l=o . g e t C l a s s ( ) ; Method m =c l . getMethod ( v e r i f , new C l a s s [ ] { ( new O b j e c t ( ) ) . g e t C l a s s ( ) } ) ; i f (m. i s A n n o t a t i o n P r e s e n t ( MyAnnotation . c l a s s ) ) { MyAnnotation a= m. g e t A n n o t a t i o n ( MyAnnotation . c l a s s ) ; i f ( a != n u l l ) { S t r i n g numeElement=a . doAction ( ) ; System . out . p r i n t l n ( numeElement ) ; i n t i n d e x=a . i n d e x ( ) ; System . out . p r i n t l n ( i n d e x ) ; } } } catch ( E x c e p t i o n e ) { System . out . p r i n t l n ( MyEx : +e . g e t M e s s a g e ( ) ) ; } } }

Clasa java.lang.Class furnizeaz a o reprezentare (reectare) a unei clase n timpul execut iei. Metoda public Method getMethod(String name, Class<?>... parameterTypes ) throws NoSuchMethodException, SecurityException furnizeaz a o reprezentare (reectare) a unei metode n timpul execut iei unui program.

Anexa F Utilizarea SGBD n Java


Scopul acestei anexe este prezentarea bazelor utiliz arii unui Sistem de Gestiune a Bazelor de Date (SGBD - Data Bases Management System - DBMS) din Java. Exemplic am modul de operare si utilizare pentru crearea si exploatarea unei baze de date corespunz atoare unei agende de adrese e-mail.

F.1

Derby / Javadb

Instalarea produsului const a n dezarhivarea sierului desc arcat. Utilizarea produsului. Va utilizat a varianta de ret ea bazat a pe un server al SGBD care utilizeaz a implicit portul 1527. Se ntreprind urm atoarele operat ii: 1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% startNetworkServer.bat -h 0.0.0.0

Prezent a opt iunii -h 0.0.0.0 asigur a accesul la serverul SGBD de pe orice calculator. 2. Crearea bazei de date se va face utiliz and utilitarul ij din distribut ia Derby / Javadb. Acesta se lanseaz a prin:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% ij.bat

349

350 Exemplul F.1.1

ANEXA F. UTILIZAREA SGBD IN JAVA

Baza de date AgendaEMail se creaz a execut and run CreateAgendaE.sql; unde sierul CreateAgendaE.sql este
1 2 3 4 5 6 7

connect j d b c : derby : AgendaEMail ; c r e a t e=t r u e ; create table a d r e s e ( i d i n t g e n e r a t e d a l w a y s as i d en t i ty ( s t a r t with 1 , i n c r e m e n t by 1 ) primary key , nume char ( 2 0 ) not null , e m a i l char ( 3 0 ) not n u l l );

si nc arcarea cu date run ValuesAgendaE.sql; cu sierul ValuesAgendaE.sql


1 2 3

i n s e r t into a d r e s e ( nume , e m a i l ) values ( aaa , aaa@yahoo . com ) , ( bbb , bbb@gmail . com ) , ( c c c , cc c@un itb v . r o ) , ( aaa , xyz@unitbv . r o ) ;

F.2

mysql

Instalarea produsului. Pentru instalare s-a desc arcat varianta f ar a instalare automat a mysqll-*.*.*-win*.zip. Acest sier se dezarhiveaz a ntr-un catalog MYSQL HOME. Implicit, serverul mysql utilizeaz a portul 3306, iar sierele bazelor de date vor g azduite n catalogul MYSQL HOME\data. Pentru utilizarea n aplicat ii Java trebuie desc arcat un conector mysqlconnector-java-*.*.*.tar.gz, cont in and sierul mysql-connector-java*.*.*-bin.jar. Utilizarea produsului. Se ntreprind urm atoarele operat ii: 1. Lansarea serverului mysql :
set MYSQL_HOME=. . . set PATH=%MYSQL_HOME%\bin;%PATH% mysqld

F.2. MYSQL

351

2. Accesul de pe orice calculator c atre utilizatorul root din mysql se asigur a prin
grant all on *.* to root@%;

3. Unui utilizator i se poate atasa o parol a, execut and ntr-o sesiune mysql comenzile
set password for root@localhost=password(parola); set password for root@127.0.01=password(parola);

Parola se sterge prin


set password for root@localhost=password(); set password for root@127.0.01=password();

Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va prezent a si opt iunea -p. 4. Exemplul F.2.1 Crearea bazei de date AgendaEMail se va face prin intermediul sierului de comenzi
set MYSQL_HOME=d:\mysql-*-win32\bin set path=%MYSQL_HOME%;%PATH% mysql -u root -p< CreateAgendaE.sql mysql -u root -p< ValuesAgendaE.sql

unde scriptul CreateAgendaE.sql este


1 2 4 5 6 7 8

create d a t a b a s e AgendaEMail ; u s e AgendaEMail ; create table a d r e s e ( i d i n t primary key a u t o i n c r e m e n t not null , nume char ( 2 0 ) not null , e m a i l char ( 3 0 ) not n u l l );

iar scriptul de populare cu date (ValuesAgendaE.sql ) este


1 2 3 4 5

u s e AgendaEMail ; i n s e r t a d r e s e values ( 1 , aaa , aaa@yahoo . com ) ; i n s e r t a d r e s e values ( 2 , bbb , bbb@gmail . com ) ; i n s e r t a d r e s e values ( 3 , c c c , ccc @uni tbv . r o ) ; i n s e r t a d r e s e values ( 1 , aaa , xyz@unitbv . r o ) ;

5. Serverul mysql se opre ste prin


set MYSQL_HOME=d:\mysql-*-win32 set PATH=%MYSQL_HOME%\bin;%PATH% mysqladmin -u root shutdown

352

ANEXA F. UTILIZAREA SGBD IN JAVA

F.3

S ablonul de utilizare a unei baze de date ntr-un program Java

Interact iunea cu baze de date relat ionale implic a: 1. Stabilirea corespondent ei dintre date aate n obiecte si atribute / tabele (object to relational database mapping ). 2. Apelarea act iunilor CRUD (Create, Read, Update, Delete ). Limbajul SQL (Structured Query Language ) este dependent de SGBD utilizat. Dezvoltarea interact iunii dintre un program Java (client) cu o baz a de date dintr-un SGBD s-a n ascut din dorint a de a asigura independent a stratului Java de SGBD. Solut ia g asit a const a n introducerea unui strat suplimentar, ntre Java si SGBD care asigur a corespondent a ntre obiectele Java cu tabelele unei baze de date si permite o congurare simpl a la schimbarea SGBD. Astfel se folose ste terminologia de aplicat ie multistrat. Materializarea acestor idei (Object Relational Mapping - ORM) se a a n interfat a de programare (API) Java Persistence API (JPA); Exist a mai multe implement ari JPA. interfat a de programare (API) Java Data Object (JDO); produsul Hibernate. Hibernate cont ine si o implementare JPA. apache-empire ebean Scopul urm arit este realizarea trecerii de la un SGBD la altul prin modic ari minime n stratul intermediar. In cele ce urmeaz a vom face abstract ie de modelele ment ionate anterior si vom trata n modul cel mai simplu realizarea unei aplicat ii care interact ioneaz a cu o baz a de date gestionat a de un SGBD. Pentru a avea acces la o baz a de date trebuie stabilit a o conexiune la acea baz a de date. In acest sens este necesar cunoa sterea:

F.3. S ABLONUL DE UTILIZARE A UNEI BAZE DE DATE

353

driver-ului de acces la sistemul de gestiune a bazei de date (SGBD) Tip SGBD access mysql derby javadb postgresql hypeqsql oraclexe Driver sun.jdbc.odbc.JdbcOdbcDriver com.mysql.jdbc.Driver org.apache.derby.jdbc.ClientDriver org.postgresql.Driver org.hsqldb.jdbcDriver oracle.jdbc.driver.OracleDriver Fi sierul driver-ului mysql-connector-java-*.*.*-bin.jar (www.mysql.com) derbyclient.jar (distribut ia derby) postgresql-*.*-*.jdbc4.jar hsqldb.jar ojdbc14.jar

Dac a ntr-un servlet se realizeaz a o conexiune la o baz a de date atunci sierul driver-ului trebuie copiat n catalogul lib al aplicat iei. adresa URI a bazei de date (String URIBazaDate ), sub forma Tip SGBD Referint a Baza de Date mysql jdbc:mysql://host:3306/numeBazaDate derby / javadb jdbc:derby://host:1527/numeBazaDate postgresql jdbc:postgresql://host:5432/numeBazaDate hypersql jdbc:hsqldb:hsql://host/numeBazaDate oracle jdbc:oracle:thin:@host:1521:XE S ablonul de prelucrare este String URLBazaDate=. . . Connection con=null; try{ Class.forName(jdbcDriver).newInstance(); con=DriverManager.getConnection(URLBazaDate); ... } catch(ClassNotFoundException e){. . .} catch(SQLException e){. . .} Anumite SGBD asigur a accesul la o baz a de date dac a sunt xat i parametrii username si password. In acest caz se programeaz a con=DriverManager.getConnection(URLBazaDate,username,password); Odat a conexiunea cu baza de date stabilit a se genereaz a un obiect de tip Statement prin intermediul c aruia se execut a interogarea SQL.

354

ANEXA F. UTILIZAREA SGBD IN JAVA

Statement instructiune=con.createStatement(); String sql=. . . //fraza select; Rezultatele interog arii bazei de date se obt ine prin try{ ResultSet rs=instructiune.executeQuery(sql); while(rs.next()){ prelucrarea rezultatului } } catch(SQLException e){...} Exemplul F.3.1 O interogare simpl a a bazei de date AgendaEMail se realizeaz a cu programul
1 2 3 4 5 6 8 9 10 11 12 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

import import import import import import

java . java . java . java . java . java .

s q l . Connection ; s q l . DriverManager ; sql . ResultSet ; s q l . Statement ; u t i l . Scanner ; u t i l . InputMismatchException ;

public c l a s s AgendaE { private s t a t i c S t r i n g jdbcURIDerby = j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ; private s t a t i c S t r i n g j d b c D r i v e r D e r b y = o r g . apache . derby . j d b c . C l i e n t D r i v e r ; private s t a t i c S t r i n g jdbcURIMysql = j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ; private s t a t i c S t r i n g j d b c D r i v e r M y s q l = com . mysql . j d b c . D r i v e r ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { S t r i n g dbms=null , username=null , password=null , jdbcURL=n u l l ; switch ( a r g s . l e n g t h ) { case 0 : System . out . p r i n t l n ( At l e a s t one argument r e q u i r e d ) ; System . out . p r i n t l n ( DBMS username password ) ; System . out . p r i n t l n ( DBMS derby , mysql ) ; System . e x i t ( 0 ) ; break ; case 1 : dbms=a r g s [ 0 ] ; break ; case 2 : dbms=a r g s [ 0 ] ; username=a r g s [ 1 ] ; password= ; break ; default :

F.3. S ABLONUL DE UTILIZARE A UNEI BAZE DE DATE

355

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 62 63 64 65 66 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

dbms=a r g s [ 0 ] ; username=a r g s [ 1 ] ; password=a r g s [ 2 ] ; } C o n n e c t i o n conn = n u l l ; try { switch ( dbms ) { case derby : C l a s s . forName ( j d b c D r i v e r D e r b y ) . n e w I n s t a n c e ( ) ; jdbcURL=jdbcURIDerby ; break ; case mysql : C l a s s . forName ( j d b c D r i v e r M y s q l ) . n e w I n s t a n c e ( ) ; jdbcURL=jdbcURIMysql ; break ; default : System . out . p r i n t l n ( Unknown DBMS . . . ) ; System . e x i t ( 0 ) ; } System . out . p r i n t l n ( jdbcURI=+jdbcURI ) ; i f ( password==n u l l ) conn = DriverManager . g e t C o n n e c t i o n ( jdbcURI ) ; else conn=DriverManager . g e t C o n n e c t i o n ( jdbcURI , username , password ) ; Statement i n s t r u c t i u n e=conn . c r e a t e S t a t e m e n t ( ) ; S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ; i n t p r e l , no ; S t r i n g ch=Y , nume= , e m a i l= , s q l= ; R e s u l t S e t r s=n u l l ; while ( ch . s t a r t s W i t h ( Y ) ) { do { System . out . p r i n t l n ( Continue ? (Y/N) ) ; ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ; } while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ; i f ( ch . s t a r t s W i t h ( Y ) ) { System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ; System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ; do { p r e l =0; try { p r e l=s c a n n e r . n e x t I n t ( ) ; } catch ( InputMismatchException e ) { } } while ( ( p r e l <1)&&( p r e l > 2 ) ) ; switch ( p r e l ) { case 1 : System . out . p r i n t l n ( Numele ) ; nume= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ; s q l= s e l e c t from a d r e s e where nume=+nume ; r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; break ; case 2 : System . out . p r i n t l n ( Email ) ; e m a i l= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ; s q l= s e l e c t from a d r e s e where e m a i l=+e m a i l ;

356

ANEXA F. UTILIZAREA SGBD IN JAVA

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ; break ; default : System . out . p r i n t l n ( Comanda e r o n a t a ) ; } i f ( r s != n u l l ) { System . out . p r i n t l n ( R e s u l t s : ) ; while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( i d= + r s . g e t I n t ( i d ) ) ; System . out . p r i n t l n ( nume= + r s . g e t S t r i n g ( nume ) ) ; System . out . p r i n t l n ( e m a i l= + r s . g e t S t r i n g ( e m a i l ) ) ; System . out . p r i n t l n ( ) ; } } else { System . out . p r i n t l n ( No item found ! ) ; } } } } catch ( E x c e p t i o n e ) { // h a n d l e t h e e x c e p t i o n e . printStackTrace ( ) ; } } }

Fraza select si interogarea se mai putea programa prin String sql="select * from adrese where nume =?"; PreparedStatement prepStmt=con.prepareStatement(sql); prepStmt.setString(1,nume); RezultSet rs=prepStmt.executeQuery(); . . . prepStmt.close(); In acest caz, valoarea variabilei nume este f ar a apostroafe. Compilarea si execut ia programului necesit a declararea n variabila classpath a sierelor Varianta Derby derbyclient.jar din catalogul %DERBY INSTALL%\lib. Varianta mysql %MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar Execut ia programului presupune serverul SGBD activ.

Partea IV TEME DE LABORATOR

357

Anexa G Teme de aplicat ii


G.1 Probleme propuse

1. S a se realizeze conversia temperaturii exprimat a n grade Celsius n grade Fahrenheit si invers. Formula de transformare este tF = 1.8tC + 32o F In RMI, programul server implementeaz a interfat a (la distant a )
package conversie; public interface Grade extends java.rmi.Remote{ public double convert(String tip, double grate) throws java.rmi.RemoteException; }

unde tip este C2F sau F2C. 2. S a se realizeze conversia a unei sume de bani ntre USD, EURO si RON. Programul server (RMI) implementeaz a interfat a
package exchange; public interface IConversie extends java.rmi.Remote{ public double usdToEuro(double usd) throws java.rmi.RemoteException; public double usdToRol(double usd) throws java.rmi.RemoteException; public double euroToUsd(double euro) throws java.rmi.RemoteException; public double euroToRol(double euro) throws java.rmi.RemoteException; public double rolToEuro(double rol)

359

360

ANEXA G. TEME DE APLICAT II

throws java.rmi.RemoteException; public double rolToUsd(double rol) throws java.rmi.RemoteException; }

Rata zilnic a de schimb preia dinamic sub forma unui sier xml, apel and http://www.bnr.ro/nbrfxrates.xml. 3. S a se realizeze conversia unui num ar natural, din cifre arabe n cifre romane si invers. Pentru numere x (3999, 3999999], x = a 1000 + b se va folosi scrierea sub forma (A)B, unde A, B reprezint a conversiile lui a, respectiv b. Exemplu: Conversia num arului 2289463 este (MMCCLXXXIX)CDLXIII. Pentru numere x (4000000, 3999999999], x = a 1000000+ b 1000+ c se va folosi scrierea sub forma [A](B )C, unde A, B, C reprezint a conversiile lui a, b, c. 4. S a se realizeze conversia unui num ar dintr-o baz a n alta. 5. Un server adun a la un num ar (init ializat cu 0) o valoare trimis a de un client return and rezultatul. Exist a o singur a instant a a num arului, acela si pentru orice client. S a se programeze serviciul descris mai sus. 6. Aplicat ia produc ator consumator. Fie un sistem format din dou a procese P1 si P2 , primul produc and ni ste date care apoi vor preluate de cel de al doilea. Comunicarea ntre cele dou a procese se realizeaz a prin intermediul unei zone de memorie tampon, de o anumit a dimensiune, n care procesul P1 introduce informat ii (sub forma unor nregistr ari), pe care apoi P2 le extrage. Procesul P2 nu este nevoit s a a stepte pentru ecare nregistrare n parte, iar P1 nu a stept a p an a ce P2 este gata s a recept ioneze nregistrarea produs a. Procesele evolueaz a independent unul de cel alat, P1 introduc and n tampon nregistrarea produs a, de unde P2 o va extrage la nevoie. Se impun urm atoarele restrict ii: Procesul P1 ncearc a s a introduc a o nregistrare n tampon si constat a c a acesta s-a umplut. In acest caz, el va trebui s a a stepte p an a ce se ive ste un loc n tampon (ceea ce se va nt ampla ca urmare a extrageri unei nregistr ari de c atre P2 ).

G.1. PROBLEME PROPUSE

361

Procesul P2 ncearc a s a extrag a o nregistrare si constat a c a tam ponul este gol. In acest caz el va trebui s a a stepte p an a ce apare o nregistrare ca urmare a introduceri unei nregistr ari n tampon de c atre P1 . Se dene ste interfat a RMI
package iprodcons; public interface IBoundedBuffer extends java.rmi.Remote{ public void put(Object obj) throws java.rmi.RemoteException; public Object get() throws java.rmi.RemoteException; }

Se cere: (a) Implementarea interfet ei IBoundedBuer. (b) Realizarea a dou a programe client Producator, care introduce obiecte n tampon si Consumator pentru extragerea lor. 7. Aplicat ie de e-mail. Un e-mail este denit printr-un ansamblu de 4 variabile de tip String (de la (from), catre (to), subiect (subject), mesaj (body)).

package iemail; import java.io.Serializable; public class Email implements Serializable { public String from = ""; public String subject = ""; public String to = ""; public String body = ""; public Email() {} public Email(String from, String to, String subject, String body) { this.from =from; this.subject =subject; this.to =to; this.body =body; } }

Interfat a aplicat iei RMI IEmailServer este

362

ANEXA G. TEME DE APLICAT II

package iemail; import java.rmi.*; public interface IEmailServer extends Remote { public boolean login(String name, String password) throws RemoteException; public void createUser(String name, String password) throws RemoteException; public void writeEmail(String from, String to, String subject, String body) throws RemoteException, UnknownUserException; public void readEmail(String userName,ICallbackEmail ce) throws RemoteException; }

Un client / utilizator al serviciului sau serverului de e-mail este o instant a a clasei User.
package email; import java.util.*; import iemail.*; public class User implements java.io.Serializable{ String name, password; Vector emails = new Vector(); public User(String name, String password) { this.name = name; this.password = password; } public void addEmail(Email email) { emails.addElement(email); } }

Pentru a putea folosi serverul de e-mail, un client trebuie n prealabil s a se nregistreze (createUser). Un client nregistrat se poate conecta la serverul de e-mail (login) dup a care poate scrie (trimite) sau citi (recept iona) mesaje. Se cere ca la ad agarea unui mesaj (deci naintea apel arii metodei User.addEmail) s a se verice dac a emitentul este conectat si dac a destinatarul este nregistrat. n caz contrar se genereaz a except ia UnknownUserException
package iemail; public class UnknownUserException extends Exception { public UnknownUserException() { super(); }

G.1. PROBLEME PROPUSE

363

public UnknownUserException(String exception) { super(exception); } }

Citirea mesajelor este l asat a la latitudinea client ilor n sensul c a clientul implementeaz a metoda printEmail al interfet ei ICallbackEmail.
package iemail; import java.rmi.*; import java.rmi.server.*; public interface ICallbackEmail extends Remote { public void printEmail(Email email) throws RemoteException; }

Solicitarea recept ion arii mesajelor se realizeaz a de c atre server prin apelarea metodei printEmail pentru ecare mesaj primit de client. Se cere: (a) Implementarea interfet ei IEmailServer. (b) Realizarea a dou a programe client AddClient pentru nregistrarea utilizatorilor si ClientEmail pentru exploatarea serviciului de email. Fiecare din cele dou a programe are ca parametri numele (identicatorul) clientului, parola si referint a serverului. 8. Integrare numeric a. Scopul aplicat iei este calculul unei integrale de un program server cu funct ia de integrat det inut a de c atre client. In cazul aplicat iei RMI, evalu arile funct iei cerute de formula de integrare numeric a se vor realiza prin apel invers. Integrarea numeric a va executat de un server disponibil client ilor prin mecanismul de fabric a de obiecte. Interfat a fabricii de obiecte este
package integ; import java.rmi.*; public interface IFabIntegrator extends Remote{ IIntegrator getIntegrator() throws RemoteException; }

iar interfat a IIntegrator este


package integ; import java.rmi.*; public interface IIntegrator extends Remote{ double adaptiveSimpson(double leftEnd, double rightEnd, double epsilon, int initParam) throws RemoteException; }

364

ANEXA G. TEME DE APLICAT II

declar a o metod a ce calculeaz a un sir (Imk )k p an a n momentul |Imk Imk1 | < . Propunem utilizarea formulei lui Simpson
b a m1 m1

ba f (x)dx Im = [f (a) + 2 6m

f (a2i ) + 4
i=1 i=0

f (a2i+1 ) + f (b)]

a . unde ai = a + i b2 m

S irul (mk )k este denit prin mk = 2k m0 . Semnicat ia parametrilor metodei adaptiveSimpson este leftEnd rightEnd epsilon initParam Interfat a apelului invers este
package integ; import java.rmi.*; double function(double x)throws RemoteException; }

a b m0

Se cere implementarea aplicat iei cu minimizarea num arului de apel ari a metodei function. 9. Agend a telefonic a. Pentru crearea si ntret inerea unei agende telefonice utiliz and RMI consider am: Un ServerCarteTelefon realizeaz a urm atoarele operat ii: adaug a o nregisrare n agenda telefonic a; O nregistrare este alc atuit a dintr-o pereche (nume, num ar).
package itelef; import java.io.Serializable; public class Entry implements Serializable{ public String nume,numar; public Entry(String nume,String numar){ this.nume=nume; this.numar=numar; } }

G.1. PROBLEME PROPUSE

365

sterge nregistrarea corespunz atoare unui nume din agenda telefonic a. interogarea agendei: furnizeaz a num arul de telefon al unui nume; modicarea num arului de telefon corespunz ator unui nume; a sarea nregistr arilor; salvarea nregistr arilor ntr-un sier; restaurarea nregistr arilor dintr-un sier. Interfat a corespunz atoare ICarteTelefon este
package itelef; import java.rmi.*; public interface ICarteTelefon extends Remote{ void addEntry(Entry e)throws RemoteException; String lookupNumber(String p)throws RemoteException; void deleteEntry(Entry e)throws RemoteException; Entry[] list() throws RemoteException; void save(String file)throws RemoteException; void restore(String file)throws RemoteException,ClassNotFoundException; void modifyEntry(Entry e)throws RemoteException; }

Interfat a fabricii de obiecte IFabCarteTelefon este


package itelef; import java.rmi.*; public interface IFabCarteTelefon extends Remote{ ICarteTelefon getCarteTelefon() throws RemoteException; }

Se cere implementarea aplicat iei de creare si ntret inere a agendei telefonice. Se extinde aplicat ia anterioar a cu funct iunea suplimentar a a serverului de a ret ine toate modic arile efectuate de c atre un client si care la solicitare pot a sate. Modic arile se ret in ntr-o variabil a mod de tip Vector. La solicitarea clientului, pentru ecare modicare memorat a, programul server apeleaz a metoda schimbStare declarat a n interfat a
package itelef; import java.rmi.*; public interface IApelInvers extends Remote{ void schimbStare(Entry e) throws RemoteException; }

366

ANEXA G. TEME DE APLICAT II

Metoda schimbStare(Entry e) nu face altceva dec at a seaz a c ampurile variabilei e. Interfat a ICarteTelefon declar a n plus metoda void apelInvers(IApelInvers obj)throws RemoteException; Aceast a metod a va implementat a n programul ServerCarteTelefon.java. Elementelor ret inute n vectorul mod li se aplic a metoda schimbStare(). S a se implementeze acest a funct iune utiliz and tehnica apelului invers. Se poate utiliza baza de date AGENDATELEFONICA format a din tabelul TELEF ID NUME NUMAR 10. S a se determine zodia (chinezeasc a) corespunz atoare unei date calen daristice. Obs. Inceputul anului nou chinezesc nu coincide cu nceputul anului nou calendaristic. Se va crea baza de date AN CHINEZESC alc atuit a din tabelul INCEPUT AN LUNA ZI Se va tine seama de perioada de 12 ani de alternant a a zodiilor. format 11. Se consider a baza de date UNITAT I DE MASUR A a din tabelul CONVERSIE UM SI UM SIMBOL DENUMIRE (ROM) VAL Exemplu: 1 2 3 4 M INCH T ol M FEET (FT) Picior KG UK ONCE Uncie (UK) KG UK POUND Livra (UK) 0.0254 0.3048 0.031103 0.373

G.1. PROBLEME PROPUSE

367

S a se realizeze o aplicat ie pentru conversia unit a tilor de m asur a extinz and cont inutul bazei de date. 12. Se consider a baza de date NORME-DIDACTICE format a din tabelele CADRU-DIDACTIC COD-CADRU-DIDACTIC NUME MATERIA COD-MATERIE DENUMIRE CURSURI COD-CURS COD-CADRU-DIDACTIC COD-MATERIE

S a se elaboreze programe de ntret inere si interogare a bazei de date. 13. Se consider a baza de date APROVIZIONARE format a din tabelele RESURSA FURNIZOR CONTRACT COD-RESURSA COD-FURNIZOR COD-CONTRACT DENUMIRE NUME COD-FURNIZOR COD-RESURSA CANTITATE S a se elaboreze programe de ntret inere si interogare a bazei de date. 14. Se consider a baza de date DESFACERE format a din tabelele PRODUSE BENEFICIAR CONTRACT COD-PRODUS COD-BENEFICIAR COD-CONTRACT DENUMIRE NUME COD-BENEFICIAR COD-PRODUS CANTITATE S a se elaboreze programe de ntret inere si interogare a bazei de date. 15. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie num arul de ordine atribuit de Evident a populat iei unei persoane la na stere, de cet a tenie rom an a, care se nscrie n actele si certicatele de stare civil a si se preia n celelate acte cu caracter ocial.

Structura unui CMP este

368

ANEXA G. TEME DE APLICAT II

S AA LL ZZ JJ ZZZ C | | | | | | |-> cifra de control | | | | | |-> numar de ordine atribuit | | | | |-> codul judetului | | | |-> ziua nasterii | | |-> Luna nasterii | |-> Anul nasterii |-> Cifra sexului (M/F) 1/2 nascuti intre 1 ian 1900 si 31 dec 3/4 nascuti intre 1 ian 1800 si 31 dec 5/6 nascuti intre 1 ian 2000 si 31 dec 7/8 rezidenti

persoanei

1999 1899 2099

Vericarea cifrei de control: Se folose ste cheia de testare 279146358279. Primele 12 cifre ale CNP se nmult esc pe r and de la st anga spre dreapta cu cifra corespunz atoare a cheii de testare. Cele 12 produse se adun a, iar suma se mparte la 11. Dac a restul mp art irii este mai mic dec at 10, atunci acesta va cifra de control. Dac a restul mp art irii este 10 atunci cifra de control este 1. S a se elaboreze un program pentru vericarea CNP. 16. Informat iile unui aeroport civil privind decol arile(plec ari) si ateriz ari(sosiri) pe parcursul unei perioade sunt cuprinse n tabelul activitate al bazei de date aeroport ACTIVITATE ID FEL aterizare/decolare ZI TIMP ora/minut COMPANIE OBSERVATIE de la/spre S a se realizeze o aplicat ie de furnizare a datelor c atre client i (interogarea bazei de date). 17. Se dau n tipuri de monede Mx1 , Mx2 , . . . , Mxn , xi reprezent and valoarea monedei, i = 1, 2, . . . , n. S a se determine variantele de plat a a unei sume S cu un num ar minim de monede din cele disponibile.

G.1. PROBLEME PROPUSE

369

Se vor trata cazurile: (a) Num arul monedelor de ecare tip este nelimitat. (b) Num arul monedelor disponibile este m arginit, respectiv de numerele k1 , k2 , . . . , kn (k1 x1 + . . . + kn xn S ). 18. Globul p am antesc este mp art it n 24 de fuse orare de c ate 15o (24 15 = 360) pornind de la meridianul 0 spre st anga si dreapta. D andu-se longitudinile a 2 puncte de pe glob s a se calculeze diferent a de fus orar. Fix and ora n primul punct s a se indice ora n al doilea punct. 19. S a se calculeze unghiurile unui triunghi dat prin coordonatele v arfurilor. 20. Fix and coecient ii a, b, c, d, e, f ale conicei ax2 + 2bxy + cy 2 + 2dx + 2ey + f = 0 s a se reduc a conica la forma canonic a. 21. S a se calculeze suma multiplilor de 3 sau 5 mai mici dec at un num ar dat n. 22. Fie polinomul trigonometric par () = 0 + se calculeze polinomul P (x) = (arccos x).
n j =1

j cos j, n 10. S a

23. Se d a polinomul P (x) = a0 + a1 x + . . . + an xn , n 10. S a se determine polinomul trigonometri par () = a0 + a1 cos + . . . + an cosn sub forma () = 0 + n j =1 j cos j. 24. Fie p N xat si n N, 0 n 2p 1 cu reprezentarea binar a n = ap1 ap2 . . . a1 a0 2 . S a se determine num arul m care are reprezentarea binar a m = a0 a1 . . . ap2 ap1 2 . De exemplu, pentru p = 6, n = 17 = 0100012 num arul c autat este m = 1000102 = 34. 25. S a se determine num arul de aparit ii al ec arui cuv ant dintr-un text dat.

370

ANEXA G. TEME DE APLICAT II

26. S a se calculeze Bn (Numerele lui Bernoulli) denit prin dac a n=0 1 n1 n + 1 Bn = Bk k=0 k dac a n>0 n+1 Calculele se fac n Q.

Bibliograe
[1] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Ia si. [2] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I., 1998, Limbajul Java. O perspectiv a pragmatic a. Ed. Computer Libris Agora, Cluj-Napoca. [3] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru aplicat ii Web. Ed. Albastr a, Cluj-Napoca. [4] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicat ii. Ed. Albastr a, Cluj-Napoca. [5] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucure sti. [6] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Ia si. [7] COULOURIS G., DOLLIMORE J., KINDBERG T., Distributed Systems. Concepts and Design. Addison Wesley, 2005. I., 2000, Programarea ret [8] JURCA elelor de calculatoare. Ed. de Vest, Timi soara. [9] SCHEIBER E., 2007, Programare concurent a si paralel distribuit a n Java. Ed. Albastr a, Cluj-Napoca. S [10] TANASA ., ANDREI S ., OLARU C., 2011, Java de la 0 la extert. Ed. Polirom, Ia si. S [11] TANASA ., OLARU C., 2005, Dezvoltarea aplicat iilor Web folosind Java. Ed. Polirom, Ia si.

371

S-ar putea să vă placă și