0% au considerat acest document util (0 voturi)
267 vizualizări380 pagini

DISTR1

Încărcat de

paul19900503
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
267 vizualizări380 pagini

DISTR1

Încărcat de

paul19900503
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
Sunteți pe pagina 1/ 380

Universitatea Transilvania din Braov s Facultatea de MatematicInformatic a a

ERNEST SCHEIBER

PROGRAMARE IN DISTRIBUITA JAVA

Braov s

Prefat a
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit programarea aplicatiilor client - server: socluri Java; apelarea metodelor de la distant (Remote Method Invocation - RMI ); a CORBA - Common Object Request Brocker Arhitecture; mesageria Java; servlet; Java Server Pages - JSP; Portlet i Portal; s Accentul cade pe detaliile tehnice de realizare a comunicatiilor i pe arhi s tectura programelor / aplicatiilor care le utilizeaz. Trebuie semnalat faptul a c exemplele date nu incorporeaz aspecte indispensabile unei aplicatii infora a matice la standardele zilei: securitate, autenticare i autorizare; s interfat grac pentru componenta client; a a utilizarea bazelor de date relationale / NoSQL. Metodele i instrumentele de programare vor exemplicate pe problema s foarte simpl de calcul a celui mai mare divizor comun a dou numere naturale. a a Codul metodei de calcul este
1 2 3 4 5

public long cmmdc( long m, long n ) { long r , c ; do{ c=n ; r= %n ; m

6 7 8 9 10 11

m ; =n n=r ; } while ( r ! = 0 ) ; return c ; }

Pentru aplicatiile care utilizeaz o baz de date, sistemul de gestiune a a a bazei de date (SGBD) va una dintre sistemele Derby/Javadb sau mysql. Tiparul de aare poate nvt 1. Se instaleaz toate resursele necesare (Se exemplic la laborator). a a 2. Se execut aplicatia / aplicatiile din curs (Se exemplic la laborator). a a 3. Pentru ecare tehnologie, citind cursul, se programeaz o alt aplicatie. a a Propunem temele: Conversia dintre grade Celsius i grade Fahrenheit (F = 1.8C + 32). s Crearea, ntretinerea i utilizarea unei agende de adrese de e-mail. s Agenda este o baz de date. a 4. nal, se rezolv tema pentru examen. In a Nu de putine ori metodele / tehnologiile utilizate presupun utilizarea unui ablon de programare specic. Din acest punct de vedere, acest curs se dorete s s a un suport metodic.

Produsele informatice utilizate


Pe durata existentei, produsele informatice evolueaz prin versiunile pe care a productorii ni le pun la dispozitie. Nu de putine ori o versiune nou nu este a a compatibil cu versiunea anterioar, fapt care necesit adaptarea programelor a a a client. Lista urmtoare precizeaz versiunile produselor utilizate curs, indicate a a n majoritatea cazurilor prin resursa de instalare. n

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

Versiunile produselor informatice utilizate lucrare n Produsul informatic Resursa/versiunea apache-activemq apache-activemq-5.5.0-bin.zip apache-ant apache.ant-1.8.1-bin.tar.gz apache-commons-logging commons-logging-1.1.1-bin.tar.gz apache-commons-codec commons-codec-1.5-bin.tar.gz apache-commons-io commons-io-1.4-bin.tar.gz apache-commons-leupload commons-leupload-1.2.2-bin.tar.gz apache-ftpserver ftpserver-1.0.6.tar.gz apache-log4j apache-log4j-1.2.16.tar.gz apache-maven apache-maven-3.0.3-bin.tar.gz apache-mina apache-mina-2.0.4-bin.tar.gz apache-java-qpid qpid-java-0.12.tar.gz apache-tomcat apache-tomcat-7.0.23.tar.gz apacheds apacheds-1.5.7.tar.gz google appengine appengine-java-sdk-1.6.0.zip db-derby db-derby-10.8.1.2-bin.tar.gz Freedom for Media in Java (fmj) fmj-20070928-0938.zip hessian hessian-4.0.7.jar httpcomponents-client httpcomponents-client-4.1.2-bin.tar.gz httpcomponents-asyncclient httpcomponents-asyncclient-4.0-alpha3-bin.tar.gz Java (jdk) jdk-7u1-windows-i586.exe jetspeed jetspeed-installer-2.2.2.jar

6
No. 22 23 24 25 26 27 28 Produsul informatic junit mysql mysql-connector OpenDS openmq pluto uPortal Resursa/versiunea junit4.8.2.zip mysql-5.5.15-win32.zip mysql-connector-java-5.1.16.tar.gz OpenDS-2.3.0.zip openmq4 5-binary-WINNT.zip pluto-2.0.3-bundle.tar.gz uPortal-3.2.4-quick-start.tar.gz.gz

Cuprins
1 Introducere 13

TEHNOLOGII PENTRU RETELE LOCALE


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

17
19 19 20 22 26 31 35 39 52 57 59

2 Programare cu socluri Java 2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . . . 2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . . . 2.3 Aplicatie client server cu socluri . . . . . . . . 2.4 Datagrame . . . . . . . . . . . . . . . . . . . . . 2.4.1 Aplicatii client server cu datagrame. . 2.4.2 Multicast vs. Broadcast . . . . . . . . . 2.5 Canale de comunicatie . . . . . . . . . . . . . . 2.6 Apache-MINA . . . . . . . . . . . . . . . . . . . 2.6.1 Mesaje componente Java . . . . . . . . . 2.6.2 Serializare folosind un codec personalizat

3 Regsirea obiectelor prin servicii de nume a 63 3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 63 3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4 Invocarea procedurilor la distant a 4.1 Remote Method Invocation . . . . 4.1.1 Crearea unei aplicatii RMI . 4.1.2 Tipare de programare . . . . 4.1.3 Obiect activabil la distanta 4.2 CORBA . . . . . . . . . . . . . . . 4.2.1 Conexiunea RMI - CORBA 4.2.2 Aplicatie Java prin CORBA 7 73 73 77 83 88 93 94 99

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

8 5 Mesaje Java n 5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . 5.2 Open Message Queue . . . . . . . . . . . . . . . . . . . 5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . 5.4 Elemente de programare - JMS . . . . . . . . . . . . . 5.4.1 Modul programat: Trimiterea unui mesaj . . . . 5.4.2 Receptia sincron a unui mesaj . . . . . . . . . a 5.4.3 Receptia asincron a unui mesaj . . . . . . . . . a 5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . 5.4.5 Subscrierea i receptia mesajelor . . . . . . . . . s 5.4.6 Prin JNDI - declararea obiectelor administrator 5.4.7 Comunicatia prin coad - queue . . . . . . . . . a 5.4.8 Comunicatia pe baz de subiect - topic . . . . . a 5.5 Mesaje SOAP prin Java Message Service . . . . . . . . 5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . 5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . 5.5.3 Ataamente SOAP . . . . . . . . . . . . . . . . s 5.6 Apache-qpid . . . . . . . . . . . . . . . . . . . . . . . 5.7 Protocolul AMQP . . . . . . . . . . . . . . . . . . . . . 5.7.1 Crearea unei cozi . . . . . . . . . . . . . . . . . 5.7.2 Expedierea / publicarea unui mesaj . . . . . . . 5.7.3 Receptionarea mesajelor . . . . . . . . . . . . .

CUPRINS

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

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

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

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

107 . 107 . 109 . 110 . 110 . 111 . 116 . 118 . 119 . 121 . 122 . 124 . 126 . 129 . 129 . 129 . 137 . 145 . 147 . 148 . 150 . 152

II

COMUNICATII PRIN INTERNET

157

6 HyperText Transfer Protocol 159 6.1 Transactie http . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 6.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . 165 6.3 Serverul Web apache-tomcat . . . . . . . . . . . . . . . . . . . . 166 7 Applet - Miniaplicatie Java 167 7.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 7.2 Desfurarea unui applet . . . . . . . . . . . . . . . . . . . . . . 169 as 7.3 Comunicare Java - JavaScript ntr-un applet . . . . . . . . . . . 175 8 Conexiune simpl prin clase din java.net a 177 8.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 177

CUPRINS

9 179 . 180 . 181 . 184 . 191 . 194 . 194 . 200 . 202 . 204 . 206 . 207 . 209 . 211 . 213 . 216 . 221 . 222 . 225 227 . 227 . 232 . 234 . 235 . 236 . 240 . 241 . 246 . 247 . 247 . 251 . 253

9 Servlet 9.1 Marcajul <form> . . . . . . . . . . . . . . . . 9.2 Realizarea unui servlet . . . . . . . . . . . . . 9.2.1 Codul unui servlet . . . . . . . . . . . 9.3 Procesare asincron Java Servlet 3.0 . . . . a n 9.4 Faciliti de programare cu servlet . . . . . . . at 9.4.1 Program client al unui servlet . . . . . 9.4.2 Servlete antuite . . . . . . . . . . . nl 9.4.3 Sesiune de lucru . . . . . . . . . . . . . 9.4.4 Cookie . . . . . . . . . . . . . . . . . . 9.4.5 Autenticare . . . . . . . . . . . . . . 9.4.6 Servlet cu conexiune la o baz de date a 9.4.7 Imagini furnizate de servlet . . . . . . 9.4.8 Servlet cu RMI . . . . . . . . . . . . . 9.4.9 Servlet cu JMS . . . . . . . . . . . . . 9.5 FileUpload . . . . . . . . . . . . . . . . . . . . 9.6 Descrcarea unui ier . . . . . . . . . . . . . a s 9.7 Filtru . . . . . . . . . . . . . . . . . . . . . . 9.8 Server apache-tomcat ncorporat . . . . . . . . 10 Java Server Page JSP 10.1 Tehnologia JSP . . . . . . . . . . . . . . . 10.1.1 Declaratii 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 fr atribute i fr corp. . aa s aa 10.3.2 Marcaje cu atribute i fr corp. . . s aa 10.3.3 Marcaje cu corp. . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11 Extensii servlet 257 11.1 Aplicatii Web prin Hessian . . . . . . . . . . . . . . . . . . . . . 257 11.2 Google App Engine - GAE . . . . . . . . . . . . . . . . . . . . . 260

10 12 Portlet 12.1 Apache-pluto . . . . . . 12.2 Dezvoltarea unui portlet 12.3 Elemente de programare 12.4 Produse Portal . . . . . 12.4.1 uPortal . . . . . 12.4.2 Jetspeed-2 . . . .

CUPRINS

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

267 . 269 . 269 . 273 . 283 . 284 . 287

13 Java Web Start 289 13.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 14 Java Management Extensions 14.1 Standard MBean . . . . . . . . . . . 14.1.1 Crearea unui Standard MBean 14.1.2 Crearea unui MBeanServer . . 14.1.3 Noticri . . . . . . . . . . . a 14.1.4 Agent MBean . . . . . . . . . 14.1.5 Invocarea la distanta . . . . . 297 . 298 . 298 . 300 . 304 . 307 . 308

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

III

ANEXE

321
323 . 323 . 326 . 328 345 349 351 . 351 . 352 . 353 357 . 357 . 359 . 361

A Unelte de dezvoltare A.1 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 apache-ant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 apache-maven . . . . . . . . . . . . . . . . . . . . . . . . . . . B Testare cu junit C Component Java a D Adnotri a D.1 Denirea unei adnotri . . . . . . . . . . . . . . . . . . . . . . a D.2 Declararea unei adnotri . . . . . . . . . . . . . . . . . . . . . a D.3 Procesarea unei adnotri . . . . . . . . . . . . . . . . . . . . . a E Utilizarea SGBD Java n E.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . E.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.3 Sablonul de utilizare a unei baze de date . . . . . . . . . . . .

CUPRINS

11

F Teme de laborator 367 F.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . 367 Bibliograe 379

12

CUPRINS

Capitolul 1 Introducere
Retelele locale, internetul, rspndirea pe o arie geograc a resurselor i a a a a s locatiilor care se petrec actiuni ce in de o activitate bine denit sau sunt n t a urmrite, gestionate din alte locuri au drept consecinta existenta aplicatiilor a distribuite. Termenul distribuit se refer tocmai la faptul c componente ale a a aplicatiei se a pe calculatoare diferite dar a ntre care au loc schimburi de date. Dac prtile unei aplicatii sau resursele utilizate se gsesc pe calculatoare a a a distincte atunci aplicatia se numete distribuit. s a Intre prtile sau resursele unei aplicatii distribuite au loc schimburi de a date, ceea ce se face utiliznd diferite mecanisme la realizarea crora concur a a a sistemul de calcul, sistemul de operare i limbajul de programare. s Astfel se vorbete de programare distribuit ca mijloc de realizare a aplicatiilor s a distribuite. Pe lng algoritm, structuri de date, limbaj de programare, la a a realizarea unei aplicatii distribuite intervin comunicatiile: schimbul de date dintre dou componente aate pe calculatoare diferite. a Punem evidenta dou modele de aplicatii distribuite: n a client-server: Programul server execut cererile clientilor. a O aplicatie client server se compune din: componenta server - alctuit din programe / clase ce asigur una a a a sau mai multe functiuni (servicii), care pot apelate de ctre clienti. a componenta client - alctuit din programe / clase care permit aca a cesul la server i apelarea serviciilor acestuia. s Serverul i clientul (clientii) ruleaz, de obicei, pe calculatoare distincte. s a Un server trebuie s satisfac cererile mai multor clienti. a a 13

14

CAPITOLUL 1. INTRODUCERE

Durata de viata a unei aplicatii client server este dat de durata a functionrii serverului. Aceast durat poate alctuit din intervale a a a a a disjuncte de timp, ntre acele intervale, din diverse motive, serverul este inactiv. Intervalul de timp determinat de conectarea unui client la server i pn s a a aceast perioad, clientul la deconectare poart numele de sesiune. In a a a poate invoca mai multe servicii ale serverului. Un client poate initia mai multe sesiuni. Un client trebuie s-i regseasc datele cadrul unei sesiuni, as a a n ntre sesiuni, pe toat durata de viat a aplicatiei. Astfel se pune problema a a retinerii / persistentei datelor pentru ecare client parte. n Amintim urmtoarele tehnologii Java pentru realizarea aplicatiilor clienta server: Tehnologii destinate retelelor locale, nebazate pe protocolul http. Socluri RMI (Remote Method Invocation) CORBA (Common Object Request Brocker Arhitecture) Comunicatiile utilizeaz porturi care nu trebuie s e a a nchise de eventuale aplicatii de tip rewall. Tehnologii cu comunicatii prin Internet, bazate pe protocolul http. JMS (Java Message Service) Servlet i JSP (Java Server Pages) s Portlet Java Web Start dispecer-lucrtor: Programul dispecer distribuie sarcinile de execua tat lucrtorilor i le coordoneaz activitatea. Exist multe abordri de a s a a a programere a aplicatiilor dispecer-lucrtor. a Exist diferente mari a ntre o aplicatie care ruleaz pe un calculator i o a s 1 aplicatie distribuit a latenta (latency): diferenta timp n ntre o operatie executat pe un cal a culator la distant de executia ei pe calculatorul local. Receptia rezula tatului unei operatii executate pe un calculator la distanta se poate pro grama
Waldo J., Wyant G., Wollrath A., Kendall S., 1994, A Note on Distributed Computing. Sun Microsystems Corporation, Technical report, SMLI TR-94-29.
1

15 sincron de obicei receptia blocheaz rul de executie al apelului a pn la sosirea rezultatului; a a asincron receptia se obtine ntr-un obiect dedicat care se execut a afara rului de executie al apelului. n O preocupare continu este dezvoltarea de tehnologii hard i soft pentru a s micorarea latentei. s accesul la memorie (memory access) Aplicatiile distribuite pot rula pe platforme diferite (de exemplu Java i .NET) iar componentele ei pot s realizate limbaje de programare diferite. Instrumente de programare n cadre de lucru (framework ) care mijlocesc realizarea aplicatiilor asigur a accesul la resursele aate memoria calculatoarelor. n Exist o preocupare pentru produse care asigur interoperabilitatea dina a tre platformele de calcul. prbuirea partial (partial failure) const a s a a n ncetarea functionrii unei a prti a aplicatiei distribuite. Tratarea acestei probleme pare a cea mai a dicil tem a programrii distribuite. a a a Precizm sensul unor notiuni utilizate lucrare: a n protocol - pachet de reguli, ablon utilizat comunicatii, accesarea s n n unor resurse. Exemple de protocoale utilizate sunt: http - HyperText Transfer Protocol este principalul protocol utilizat comunicatiile prin Internet; n https protocol http securizat; le - protocol pentru specicarea ierelor aate pe calculatorul s local; ftp - File Transfer Protocol - protocol pentru transferul ierelor s ntre dou calculatoare; a smtp - Simple Message Transfer Protocol utilizat de pota elecronic. s a host - calculatorul gazd, cel pe care se lucreaz. Acest calculator se a a specic printr-o adres IP (Internet Protocol ) sau printr-un nume. a a port - o adres de memorie cuprins a a ntre 0 i 65535. Porturile cuprinse s ntre 0 i 1023 sunt rezervate sistemului de operare. Dintre acestea amins tim:

16 Port Utilizat de 80 http 443 https 25 smtp

CAPITOLUL 1. INTRODUCERE

Referintele resurselor se indic folosind Uniform Resource Identiers - (URI) a i mai precis Uniform Resource Locator - (URL). URI identic o resurs s a a n timp ce URL desemneaz locatia resursei. URL se consider ca un caz partica a ular de URI. Sintaxa folosit pentru URI este a protocol://host[:port][cale][?cerere]

Partea I TEHNOLOGII PENTRU RETELE LOCALE

17

Capitolul 2 Programare cu socluri Java


Comunicatia bazat pe socluri Java constituie modalitatea de nivelul infe a rior pentru realizarea aplicatiilor distribuite.

2.1

TCP vs. UDP

Calculatoarele ce ruleaz retea comunic a n a ntre ele folosind protocolul TCP (Transmission Control Protocol) sau UDP (User Datagram Protocol). Intr-un program Java se utilizeaz clasele pachetului java.net prin intera mediul crora se acceseaz nivelele deservite de protocoalele TCP sau UDP. a a felul acesta se pot realiza comunicatii independente de platforma de calcul. In Pentru a alege care clas Java s e utilizat trebuie cunoscut diferenta dintre a a a a TCP i UDP. s TCP Cnd dou aplicatii comunic a a a ntre ele se stabilete o conexiune prin s intermediul creia se schimb date. Folosind protocolul TCP, comunicatia a a garanteaz c datele trimise dintr-un capt ajung cellalt capt cu pstrarea a a a n a a a ordinii care au fost trimise. Acest tip de comunicatie seamn cu o convorn a a bire telefonic. TCP furnizeaz un canal sigur de comunicatie a a ntre aplicatii. UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date numite datagrame de la o aplicatie la alta fr s se asigure faptul aa a c datagramele ajung la destinatie i nici ordinea lor de sosire. Acest tip de a s comunicatie seamn cu trimiterea scrisorilor prin pot. a a sa 19

20

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.2

Soclu TCP

Pentru a comunica utiliznd TCP programul client i programul server a s stabilesc o conexiune sigur. Fiecare program se leag la conexiune printr-un a a soclu (socket). Un soclu este captul unei ci de comunicatie bidirectional a a ntre dou programe ce ruleaz retea. Un soclu este legat de un port prin a a n care nivelul TCP poate identica aplicatia creia sunt transmise datele. a i Pentru a comunica att clientul ct i serverul citesc date de la i scriu date a a s s la soclul legat la conexiunea dintre ele. pachetul java.net clasele Socket i ServerSocket implementeaz un In s a soclu din partea clientului i respectiv din partea serverului. s Clientul cunoate numele calculatorului pe care ruleaz serverul ct i pors a a s tul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearc a un rendez-vous cu serverul de pe maina serverului i la portul serverului. Dac s s a totul decurge bine, serverul accept conexiunea. Dup acceptare, serverul a a creaz pentru client un nou soclu legat la un alt port aa fel at asa n s nc cultarea cererilor la soclul initial s poat continua timp ce sunt satisfcute a a n a cererile clientului conectat. Din partea clientului, dup acceptarea conexiunii a soclul este creat i este utilizat pentru comunicatia cu serverul. s

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

2.2. SOCLU TCP

21

public OutputStream getOutputStream() throws IOException Returneaz un ux de ieire ataat soclului, pentru scrierea (transmiterea) a s s informatiilor la soclu. public synchronized void close() throws IOException nchide soclul de referinta.

Clasa java.net.ServerSocket
Resursele clasei ServerSocket sunt destinate serverului. Constructori public ServerSocket(int port) throws IOException Creaz un soclu la portul specicat. Dac port=0, atunci va utilizat a a orice port disponibil. Capacitatea irului (tamponului) de ateptare pens s tru cererile de conectare se zeaz la valoarea implicit 50. Cererile a a n exces vor refuzate. public ServerSocket(int port, int lung) throws IOException plus xeaz lungimea irului (tamponului) de ateptare. In a s s public ServerSocket(int port, int lung, InetAddress adr ) throws IOException Se specic plus calculatorul de la care se ateapt cereri. Dac a n s a a adr =null, atunci se accept cereri de la orice calculator. a Metode public Socket accept() throws IOException Metoda blocheaz procesul (rul de executie) apelant pn la sosirea a a a unei cereri de conectare i creaz un soclu client prin care se va desfura s a as comunicarea cu solicitantul acceptat. public synchronized void close() throws IOException nchide soclul de referinta.

22

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.3

Aplicatie client server cu socluri

Serverul trebuie s satisfac simultan solicitrile mai multor clienti. Fiecare a a a client apeleaz programul server la acelai port i consecinta cererile de a s s n conectare sunt receptionate de acelai ServerSocket. Serverul receptioneaz s a apelurile secvential. La un apel, se creaz de partea severului un soclu prin a care se va face schimbul de date cu clientul. Cererile clientilor pot satisface concurent/paralel, utiliznd re de executie ce implementeaz serviciul oferit a a sau secvential - cazul unor servicii de durat scurt. n a a Exemplul 2.3.1 Sistem client - server pentru calculul celui mai mare divizor comun a dou numere naturale. Portul obiectului de tip ServerSocket este a 7999. Programul client CmmdcClient se conecteaz la server, transmite serverua lui cele dou numere naturale i receptioneaz rezultatul pe care apoi aeaz. a s a l s a esent orice program client trebuie s execute: In a a 1. Deschide/creaz un soclu. a 2. Deschide/creaz uxuri de date pentru comunicatia cu serverul. a 3. Transmite i receptioneaz date potrivit specicului aplicatiei (protos a colului serverului). Acest pas variaz de la un program client la altul. a 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

package c l i e n t ; import j a v a . i o . ; import j a v a . n e t . ; 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 ) throws IOException { 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 c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ;

2.3. APLICATIE CLIENT SERVER CU SOCLURI

23

20 21 22 23 24 25 26 27 28 29 30 31 32 33

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 ( ) ) ; } } }

Se presupune c programul server ruleaz pe calculatorul local i utilizeaz a a s a portul 7999. Dac aceti parametri se modic - de exemplu serverul ruleaz a s a a retea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem n aceti parametri prin java CmmdcClient atlantis 8200 s Partea server este alctuit din mai multe clase: a a Clasa MyMServer, independent de un serviciu anume, preia apelurile a clientilor i lanseaz satisfacerea cererii. s a
1 2 3 4 6 7 8 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

package s e r v e r . impl ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; } } }

ciclul while, la receptia unei solicitri de conexiune se creaz i In a a s se lanseaz un r de executie a crei metod run contine actiunile ce a a a

24 rspund solicitrii. a a

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa AppTread - r de executie responsabil de preluarea datelor i de s transmitere a rezultatului.


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

package s e r v e r ; import j a v a . n e t . ; import j a v a . i o . ; 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 ( 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 n . readLong ( ) ; =i 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 corespunztoare calcului celui mai mare divizor comul a dou a a numere naturale.
1 2 3

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

Rularea programelor. Se pornete la s nceput programul server MyMServer iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator al retelei. Dac programul client se execut pe alt calculator dect cel pe care a a a ruleaz programul server, atunci la apelarea clientului trebuie precizat numele a calculatorului server i eventual portul utilizat. s O alt arhitectur a aplicatiei este dezvoltat continuare. Aceast arhia a a n a tectur este mai bun sensul c poate utilizat alte cadre de lucru / de a a n a a n dezvoltare (de exemplu OSGi, Junit). Aplicatia se va compune din:

2.3. APLICATIE CLIENT SERVER CU SOCLURI

25

Aplicatia server alctuit din: a a 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 ) ; }

Implementarea interfetei
1 2 3 4 5 6 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

package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 de lansare a serverului a
1 2 3 4

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 ;

26

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

6 7 8 9 10 11 12 13 14 15

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 ) ; } }

Aplicatia client este nemodicat. a

2.4

Datagrame

Pentru utilizarea datagramelor pachetul java.net pune la dispozitie clasele DatagramSocket DatagramPacket MulticastSocket O aplicatie trimite i receptioneaz pachete DatagramPacket prin inter s a mediul unui DatagramSocket. Un pachet DatagramPacket poate trimis la mai multi destinatari prin intermediul unui MulticastSocket. Reamintim c o datagram este un mesaj trimis prin retea a crei sosire a a a nu este garantat iar momentul de sosire este neprecizat. a

Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesit crearea unui obiect a DatagramPacket care contine corpul mesajului i adresa destinatiei. Apoi s acest obiect DatagramPacket poate pus retea vederea trimiterii sale. n n Primirea unui pachet UDP necesit crearea unui obiect DatagramPacket i a s apoi acceptarea unui pachet UDP din retea. Dup primire, se poate extrage a din obiectul DatagramPacket adresa surs i continutul mesajului. as Constructori Exist doi constructori pentru datagrame UDP. Primul constructor este a folosit pentru primirea de pachete i necesit doar furnizarea unei memorii s a tampon, iar cellalt este folosit pentru trimiterea de pachete i necesit specia s a carea adresei destinatarului.

2.4. DATAGRAME

27

DatagramPacket(byte[ ] buer ,int lung) Acest contructor este folosit pentru primirea pachetelor. Un pachet se memoreaz tamponul buer avnd lung octeti. Dac lungimea paa n a a chetului depete aceast lungime, atunci pachetul este trunchiat iar as s a octetii plus se pierd. n DatagramPacket(byte[ ] buer ,int lung ,InetAddress adresa ,int port) Acest constructor este folosit pentru crearea unui pachet vederea exn pedierii. Corpul pachetului este continut tamponul buer avnd lung n a octeti. Pachetul va trimis ctre adresa i portul specicat. Trebuie s a s a existe un server UDP care ascult la portul specicat pentru trimiterea a pachetelor. Un server UDP poate coexista cu un server TCP care ascult a acelai port. s Metode InetAddress getAddress() returneaz adresa IP a expeditorului. a int getPort() returneaz portul expeditorului. a byte[] getData() returneaz continutul pachetului. a int getLength() returneaz lungimea pachetului. a void setAddress(InetAddress adresa) xeaz adresa IP a pachetului. a void setPort(int port) xeaz portul. a void setData(byte[] buer ) xeaz continutul pachetului. a void setLength(int lung) xeaz lungimea pachetului. a

28

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa java.net.DatagramSocket
Aceast clas se folosete att pentru trimiterea, ct i pentru primirea a a s a a s obiectelor DatagramPacket. Un obiect DatagramSocket ascult la un port a cuprins ntre 1 i 65535 (porturile cuprinse s ntre 1 i 1023 sunt rezervate pentru s aplicatiile sistem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect DatagramSocket pentru trimiterea pachetelor ctre diferite a destinatii i primirea pachetelor de la diferite surse. s Constructori DatagramSocket() throws SocketException Creaz un obiect DatagramSocket cu un numr de port aleator; a a DatagramSocket(int port) throws SocketException Creaz un obiect DatagramSocket cu numrul de port specicat; a a DatagramSocket(int port, InetAddress adres ) throws SocketException a Creaz un obiect DatagramSocket la adresa i portul specicat. a s Metode Clasa DatagramSocket contine metode pentru trimiterea i primirea de s obiecte DatagramPacket, nchiderea soclului, determinarea informatiilor adre sei locale i setarea timpului de primire. s void send(DatagramPacket pachet) throws IOException Trimite pachetul prin retea. Dac se trimit pachete la o destinatie ne a cunoscut sau care nu ascult, cele din urm se genereaz o exceptie a a n a a IOException. void receive(DatagramPacket pachet) throws IOException Metoda primete un singur pachet UDP obiectul pachet specicat. s n Apoi, pachetul poate inspectat pentru determinarea adresei IP surs, a portul surs i lungimea mesajului. Executia metodei este blocat pn as a a a cnd se primete cu succes un pachet sau se scurge timpul de ateptare. a s s InetAddress getLocalAddress() Returneaz adresa local ctre care este legat acest DatagramSocket; a a a int getLocalPort() Returneaz numrul de port unde ascult DatagramSocket. a a a

2.4. DATAGRAME

29

void close() Inchide DatagramSocket. void setSoTimeout(int timpDeAteptere) throws SocketException s Metoda xeaz timpul de ateptare ( milisecunde) a soclului. Metoda a s n receive() se va bloca pentru timpul de ateptare specicat pentru prims irea unui pachet UDP, dup care va arunca o exceptie Interrupted a Exception. Dac valoarea parametrului este 0, atunci soclul este bloa cat. int getSoTimeout() throws SocketException Returneaz timpul de ateptare. a s void setSendBufferSize(int lungime) throws SocketException Fixeaz lungimea tamponului de trimitere a soclului la valoarea specia cat. Nu poate trimis mesaj UDP de lungime mai mare de aceast a a valoare. int getSendBufferSize() throws SocketException Returneaz lungimea tamponului de trimitere a soclului. a void setReceiveBufferSize(int lungime) throws SocketException Fixeaz lungimea tamponului de primire a soclului la valoarea specia cat. Nu poate primit un mesaj UDP de lungime mai mare de aceast a a valoare. int getReceiveBufferSize() throws SocketException Returneaz lungimea tamponului de primire a soclului. a void connect(InetAddress adresa, int port) throws SocketException Conecteaz soclul la adresa i portul specicat. Aceast metod nu este a s a a cerut pentru operatiile uzuale UDP. a void disconnect() Deconecteaz soclul conectat. a InetAddress getInetAddress() Returneaz obiectul InetAddress ctre care este conectat soclul sau a a null dac acesta nu este conectat. a

30 int getPort()

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Returneaz portul la care este conectat soclul sau -1 dac acesta nu este a a conectat.

Clasa java.net.InetAddress
Datele pot trimise prin retea indicnd adresa IP corespunztoare mainii a a s destinatie. Clasa InetAddress furnizeaz acces la adresele IP. a Nu exist constructori pentru aceast clas. Instantele trebuie create folosind a a a metodele statice: InetAddress getLocalHost() throws UnknownHostException Returneaz un obiect InetAddress corespunztor mainii locale. a a s InetAddress getByName(String host) throws UnknownHostException Returneaz un obiect InetAddress corespunztor mainii host, parametru a a s care poate specicat prin nume (de exemplu atlantis) sau prin adresa IP (168.192.0.1). InetAddress [ ]getAllByName(String host) throws UnknownHostException Returneaz un ir de obiecte InetAddress corespunztor ecrei adrese a s a a IP a mainii host. s Metodele clasei InetAddress byte [ ] getAddress() Returneaz irul de octeti corespunztor obiectului InetAddress de referint. as a a String getHostName() Returneaz numele mainii gazd. a s a String getHostAddress() Returneaz adresa IP a mainii gazd. a s a boolean isMulticastAddress() Returneaz true dac obiectul InetAddress reprezint o adres IP mula a a a ticast (cuprins ntre 224.0.0.0 i 239.255.255.255). s

2.4. DATAGRAME

31

Exemplul urmtor aeaz numele i adresa calculatorului gazd ct i a s a s a a s acela al calculatoarelor ale cror nume este transmis programului ca parametru. a Exemplul 2.4.1

1 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

import j a v a . n e t . ; 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.4.1

Aplicatii client server cu datagrame.

Un pachet de tip DatagramPacket este alctuit dintr-un ir de octeti. Este a s datoria programatorului s transforme datele (mesajul) iruri de octeti la a n s expediere i la receptie. s Transformarea unui obiect serializabil ntr-un ir de octeti i invers se poate s s realiza cu schema

32

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Object ObjectOutputStream ByteArrayOutputStream output - DatagramPacket


? ? ? ?

Object ObjectInputStream ByteArrayInputStream input - DatagramPacket


6 6 6 6

Fie socket un obiect de tip DatagramSocket prin intermediul cruia se a execut expedierea / receptionarea pachetelor de tip DatagramPacket. a principiu expedierea i transformarea obiectului obj In s ntr-un ir de octeti s se poate realiza cu secventa 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 i port sunt adresa i portul destinatarului. Dac packet este un s s a obiect DatagramPacket receptionat atunci metodele getAddress() i getPort() s furnizeaz adresa i portul expeditorului a s Receptionarea i transformarea invers este s a 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 mesajul este un obiect String atunci el se transform a a ntr-un ir de s octeti cu metoda byte[] String.getByte() i invers, el se obtine prin new s String(bin) sau new String(packet.getData()). Exemplul 2.4.2 Programm serviciul calculului celui mai mare divizor coa mun a dou numere. a

2.4. DATAGRAME

33

vederea transportului denim clasa In


1 2 4 5 6 7 8 9 10

package s e r v e r ; import j a v a . i o . ; 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 contine datele problemei i va s receptiona un obiect de acelai tip cu rezultatul (cel mai mare divizor comun) s primul cmp al obiectului. Aceasta clasa este disponibil att serverului ct n a a a a i clientului. s Se va utiliza arhitectura de aplicatie dezvoltat nalul sectiunii ante a n rioare. Aplicatia se va compune din: Aplicatia server alctuit din: a a 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 interfetei
1 2 3 4 5 6 8 10 11 12 13 14 15 16 17 18 19 20 21 22

package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . i o . ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; 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 ; }

34

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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 53

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 de lansare a serverului a


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 ) ; } }

Aplicatia client
1 2 3 4 5

package c l i e n t ; import j a v a . n e t . ; import j a v a . i o . ; 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 ;

2.4. DATAGRAME

35

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

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.4.2

Multicast vs. Broadcast

Clasa java.net.MulticastSocket
Prin intermediul unui soclu de tip MulticastSocket se pot receptiona datagrame expediate de un server ctre toti clientii cu un asemenea soclu. a Constructori MulticastSocket(int port) throws SocketException Metode void joinGroup(InetAddress adres ) throws SocketException a

36

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Soclul se conecteaz la grupul denit de adresa IP (de tip D, adic a a cuprins ntre 224.0.0.0 i 239.255.255.255). s void leaveGroup(InetAddress adres ) throws SocketException a Soclul se deconecteaz la grupul denit de adresa IP. a void close() Pregtirea clientului vederea receptionrii datagramelor printr-un soclu a n a de tip MulticastSocket const din a MulticastSocket socket= new MulticastSocket(port); InetAddress adresa=InetAddress.getByName("230.0.0.1"); socket.joinGroup(adresa); nal, clientul se deconecteaz i In a s nchide soclul. socket.leaveGroup(adresa); socket.close(); Pachetele trimise de programul server trebuie s se adreseze grupului, idena ticat prin adresa IP de tip D. Astfel prin multicast serverul trimite pachete la o adres de grup i la un a s port xat. Pachetele emise de server sunt receptionate de orice client ce creaz a un soclu de tip MulticastSocket pentru portul la care emite serverul i care s se altur grupului. a a Prin broadcast serverul emite datagrame ctre orice calculator al retelei a locale la un anumit port. Faptul c emiterea datagramelor este de tip broadcast a se indic prin a DatagramSocket.setBroadcast(true) Orice client care si creaz un soclu la portul la care emite serverul receptioneaz a a datagramele trimise de server. Adresa utilizat de server la crearea dataa gramelor trebuie s identice reteaua. a Observatie. cazul unui calculator izolat este nevoie de instalarea In driverului Microsoft Loopback Adapter, care simuleaz existenta unei plci de a a retea active. Exemplul 2.4.3 Multicast i Broadcast: programele server emit din cinci s n cinci secunde ora exact. Un client va receptiona cte cinci datagrame. a a Codurile sunt date Fig. 2.1 i Fig. 2.2, respectiv pentru partea de server n s i cea de client. s

2.4. DATAGRAME

37

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.

38

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.5. CANALE DE COMUNICATIE

39

2.5

Canale de comunicatie

Odat cu versiunea j2sdk1.4 apar clase noi pentru operatii de intrare - ieire a s pachetele java.nio i java.nio.channels. Pachetul java.nio.channels n s contine clase pentru comunicatia retea, i anume canalele de comunicatie. n s Utilizm clasele java.nio.channels.SocketChannel, java.nio.channel. a DatagramChannel. Informatia transportat aceste canale de comunicatie a n trebuie nglobat obiecte container de tip Buffer. a n

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 contine date de tipul specicat de denumirea clasei. Un obiect de tip Buffer este caracterizat de capacitate (capacity) numrul elementelor care pot a nmagazitate n tampon; limit (limit) marginea superior a indicelui; a a indice (position) valoarea curent a indicelui, ce corespunde unui cursor a 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 e re arcat. Fixeaz a nc a limita = capacitate i indice = 0. s ip() pregtete obiectul de tip Buffer pentru consultare (citire). Fixa s eaz limita =numrul elementelor din tampon i indice = 0. a a s rewind() pregtete obiectul de tip Buffer pentru re-citire. a s

40

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa java.nio.ByteBuffer
Instantierea unui obiect se obtine prin metoda static a static ByteBuffer allocate(capacitate) Introducerea i extragerea datelor din tampon se poate face mod s n relativ - implic modicarea indicelui tamponului; a absolut - far modicarea indicelui. a Metode Introducerea datelor mod relativ: n ByteBuffer put(byte b) ByteBuffer putTip(tip x ) Extragerea datelor mod relativ: n byte get() tip getTip() Introducerea datelor mod absolut: n ByteBuffer put(int index ,byte b) ByteBuffer putTip(int index ,tip x ) Extragerea datelor mod absolut: n byte get(int index ) tip getTip(int index ) unde tip poate char, short, int, long, float, double. Alte metode public final boolean hasRemaining() Dac indicele nu este egal cu limita atunci returneaz true, semnalnd a a a existenta tampon a unor octeti. n static ByteBuffer wrap(byte[] array)

2.5. CANALE DE COMUNICATIE

41

public static ByteBuffer wrap(byte[] array,int oset,int length) Convertete irul de octeti s s ntr-un obiect Bytebuffer. public final byte[] array() Transformarea invers, obiectul ByteBuffer este convertit a ntr-un ir de s octeti. 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();

Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress i s ncapsuleaz a adresa unui calculator din Internet mpreun cu un port vederea legrii la a n a 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 prin a static ServerSocketChannel open() throws IOException Unui asemenea obiect i se asociaz un ServerSocket prin metoda a ServerSocket socket() throws IOException. Obiectul de tip ServerSocket trebuie leagat la un port de comunicatie prin metoda void bind(InetSocketAddress endpoint) throws IOException. Sablonul de utilizare este

42

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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 genereze un obiect de tip Socket a Channel prin care se vor derula comunicatiile cu clientul. Acest canal de comunicatie se obtine cu metoda accept().

Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaz prin a 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 i se receptioneaz prin metoda s a int read(ByteBuffer destinatie) Valoarea returnat de cele dou metode reprezint numrul octetilor trimii a a a a s / receptionati. Doar octetii unui obiect de tip ByteBuffer cuprini s ntre indice i limit s a sunt transmii prin canal. Astfel, dup arcarea unui obiectului ByteBuffer s a nc cu metode relative trebuie apelat metoda flip(). a Canalul se nchide cu metoda close(). Exemplul 2.5.1 Calculul celui mai mare divizor comun a dou numere nata urale. Aplicatie client-server bazat pe canale de comunicatie prin socluri se com pune din: Aplicatia server alctuit din: a a

2.5. CANALE DE COMUNICATIE

43

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 interfetei
1 2 3 4 5 6 7 8 10 12 13 14 15 16 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

package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . n i o . ; 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 . ; 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

package s e r v e r ; import j a v a . n e t . ; import j a v a . i o . ;

44

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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 32 33 34 35 36 37 38 39 40

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 . ; 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 ; } 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 b . g e t ( 0 ) ; =l // 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 de lansare a serverului a


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 ) ; } }

Aplicatia client

2.5. CANALE DE COMUNICATIE

45

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 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 . i o . ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . ; 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= 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 c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } }

46
}

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

59

Varianta comentat corespunde cazului care se utilizear clasa acoperitoare a n a LongBuffer.

Clasa java.nio.channels.DatagramChannel
Sablonul de programare pentru instantierea 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); } catch(Exception e){. . .} unde port este portul folosit de DatagramChannel. Dac port=0 atunci se a alege aleator un port disponibil. Transmiterea unui obiect ByteBuffer se face cu metoda public int send(ByteBuffer src, SocketAddress target) throws IOException Metoda returneaz numrul de octeti expediati. Receptia unui ByteBuffer se a a obtine cu metoda public SocketAddress receive(ByteBuffer dst) throws IOException Obiectul returnat reprezint adresa expeditorului. a Exemplul 2.5.2 Calculul celui mai mare divizor comun a dou numere nata urale. Aplicatia server este alctuit din: a a 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 ) ; }

2.5. CANALE DE COMUNICATIE

47

Implementarea interfetei
1 2 3 4 5 6 7 8 10 12 13 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

package s e r v e r . impl ; import s e r v e r . ; import i s e r v e r . IMyMServer ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . DatagramChannel ; import j a v a . u t i l . c o n c u r r e n t . ; 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 ) ; } 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; 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 ) { 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 b . g e t ( 0 ) ; =l // 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 ( ) ) ; } } } }

48

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clas de lansare a serverului a


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 ) ; } }

Aplicatia client
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 37 38

package c l i e n t ; import j a v a . i o . ; import j a v a . n e t . ; import j a v a . n i o . ; import j a v a . n i o . c h a n n e l s . ; 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 ) 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 ) ;

2.5. CANALE DE COMUNICATIE

49

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

System . out . p r i n t l n ( m ) ; = m c a n n e r . nextLong ( ) ; =s 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 // 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 ( ) ; } } }

Clasa java.nio.channels.FileChannel
Clasa FileChannel simplic copierea pe un calculator a unui ier dintr-o a s locatie alta i are posibilitatea de a alimenta / de a alimentat de un alt n s a tip de canal. Durata acestor operatii este mai mic dect cazul programrii a a n a cu clasele pachetului java.io. O instanta a clasei FileChannel se poate obtine cu metoda FileChannel getChannel() a claselor FileInputStream, FileOutputStream. Fluxul de octeti este directionat spre, respectiv din, obiectul de tip FileChannel instantiat. Transferul octetilor din ux spre / dintr-un SocketChannel se face uti liznd ablonul a s long fileSize=fileChannel.size(); fileChannel.transferTo(0,fileSize,socketChannel); respectiv fileChannel.transferFrom(0,fileSize,socketChannel);

50

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

caz care valoarea variabilei leSize trebuie stabilit pe alt cale. n a a Exemplul 2.5.3 Aplicatie de transfer a unui ier de la server la client. s Codul clasei server este
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 32 33 34 35 37 38 39 40 41 42 44 45 46 47 48 49 51 52

import import import import import import import import import import

java . io . F i l e ; java . io . FileInputStream ; j a v a . i o . IOException ; java . net . InetSocketAddress ; java . net . ServerSocket ; java . nio . ByteBuffer ; java . nio . LongBuffer ; java . nio . channels . FileChannel ; java . nio . channels . ServerSocketChannel ; java . nio . channels . SocketChannel ;

public c l a s s S e r v e r { public s t a t i c void main ( S t r i n g [ ] a r g s ) { int port = 7999; ServerSocketChannel s s c = null ; try { s s c = 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 ) ; ServerSocket ss = ssc . socket ( ) ; 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 . 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 . . . ) ; while ( true ) { serviciu ( ssc ); } } private s t a t i c void s e r v i c i u ( S e r v e r S o c k e t C h a n n e l s s c ) { S t r i n g f i l e = xmlp i c . j p g ; 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 ) ; String pathToFiles = f i l e s ; SocketChannel sc = null ; try { sc = ssc . accept ( ) ; F i l e i n p u t F i l e = new F i l e ( p a t h T o F i l e s + f s + f i l e ) ; F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( i n p u t F i l e ) ; FileChannel f i l e C h a n n e l = f i s . getChannel ( ) ; // T r i m i t dimensiunea f i s i e r u l u i c a t r e c l i e n t long f i l e S i z e = f i l e C h a n n e l . s i z e ( ) ; 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 ( Long . SIZE / 8 ) ; L o n g B u f f e r b u f = bb . a s L o n g B u f f e r ( ) ; b u f . put ( f i l e S i z e ) ; s c . w r i t e ( bb ) ; // T r a n s f e r f i s i e r u l c a t r e c l i e n t fileChannel . transferTo (0 , f i l e S i z e , sc ) ;

2.5. CANALE DE COMUNICATIE

51

54 55 56 57 58 59 60

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

iar codul clientului este


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

import import import import import import import

java . io . F i l e ; java . i o . FileOutputStream ; j a v a . i o . IOException ; java . net . InetSocketAddress ; java . nio . ByteBuffer ; java . nio . channels . FileChannel ; java . nio . channels . SocketChannel ;

public c l a s s C l i e n t { private s t a t i c S t r i n g path = r e p o s i t o r y ; private s t a t i c S t r i n g f i l e = xmlp i c . j p g ; 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 ] ) ; SocketChannel sc = null ; 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 ) ; 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 ( ho st , 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 ) ; // Se p r e i a dimensiunea f i s i e r u l u i ( p e n t r u v e r i f i c a r e ) 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 ( Long . SIZE / 8 ) ; s c . r e a d ( bb ) ; long f i l e S i z e = bb . getLong ( 0 ) ; // D e s c h i d c a n a l u l S t r i n g fileOutName = path + f s + f i l e ; F i l e f i l e P a t h = new F i l e ( path ) ; if (! filePath . exists ()) { f i l e P a t h . mkdirs ( ) ; } F i l e O u t p u t S t r e a m f o s = new F i l e O u t p u t S t r e a m (new F i l e ( fileOutName ) ) ; FileChannel f c = f o s . getChannel ( ) ; f c . t r a n s f e r F r o m ( sc , 0 , f i l e S i z e ) ; System . out . p r i n t l n ( F i s i e r r e c e p t i o n a t + f i l e + de + fileSize + octeti ); sc . clos e ( ) ; fos . close (); fc . close (); } catch ( IOException e ) {

52

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

49 50 51 52

System . out . 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 ( ) ) ; } } }

2.6

Apache-MINA

Apache-MINA: Multiporpose Infrastructure for Network Applications denete o interfata de programare (API: Application Programming Interface) s pentru utilizarea mai multor protocoale de transport TCP, UDP, etc., oferind o performant sporit. a a Instalarea produsului se face prin dezarhivarea resursei binare descrcate. a Utilizarea necesit includerea variabila de sistem classpath a ierului a n s mina-core-*.*.*.jar. Suplimentar, sunt necesare slf4j-api-*.*.*.jar, slf4j-jdk14-*.*.*.jar din pachetul slf4j, Simple Logging Faade for Java. c Modelul de programare MINA este diferentiat pe partea de server i pe s partea de client, dar esent const din: n a a 1. Denirea unui adaptor/conector al operatiilor de intrare/ieire; s 2. Denirea ltrului care transform irul de octeti al datelor serializate as n obiecte / tipuri predenite sau invers; 3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei; 4. Conectarea. Vom urmrii aceti pai pentru a s s Exemplul 2.6.1 Calculul celui mai mare divizor comun a dou numere nata urale. Clientul trimite datele sub forma unui ir de caractere alcatuit din cele s dou numere separate printr-un spatiu. Serverul trimite rspunsul ca String. a a

Aplicatia server
Aplicatia server se compune din clasele: CmmdcServer - ndeplinete sarcinile MINA; s

2.6. APACHE-MINA

53

CmmdcHandler - manipulatorul prtii server; a App - contine metoda de calcul a celui mai mare divizor comun. Manip ulatorul va instantia un obiect de tip App. Sarcinile MINA se programeaz prin a 1. Denirea unui adaptor pentru protocolul TCP al operatiilor de intrare/ieire: s IoAcceptor acceptor = new NioSocketAcceptor(); Pentru protocolului UDP se utilizeaz clasa NioDatagramAcceptor. a 2. Denirea ltrului care transform irul de octeti al datelor serializate as n cazul care datele sunt iruri obiecte / tipuri predenite sau invers. In n s de carctere (String), codul este acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); 3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei: CmmdcHandler handler=new CmmdcHandler(); acceptor.setHandler(handler); 4. Conectarea: acceptor.bind(new InetSocketAddress(PORT) ); Codul complet al clasei CmmdcServer este
1 2 4 5 6 7 8 10 11 13

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 r s e t . C h a r s e t ; import o r g . apache . mina . c o r e . s e r v i c e . I o A c c e p t o r ; import o r g . apache . mina . f i l t e r . c o d e c . P r o t o c o l C o d e c F i l t e r ; import o r g . apache . mina . f i l t e r . c o d e c . t e x t l i n e . TextLineCodecFactory ; import o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . N i o S o c k e t A c c e p t o r ; // i m p o r t o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . NioDatagramAcceptor ; public c l a s s CmmdcServer{ private s t a t i c f i n a l i n t PORT = 8 9 9 9 ; public s t a t i c void main ( S t r i n g [ ] a r g s ) throws Throwable {

54

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

14 15 16 17 18 20 21 22 23 24 25

I o A c c e p t o r a c c e p t o r = new N i o S o c k e t A c c e p t o r ( ) ; // I o A c c e p t o r a c c e p t o r = new NioDatagramAcceptor ( ) ; a c c e p t o r . g e t F i l t e r C h a i n ( ) . addLast ( c o d e c , new P r o t o c o l C o d e c F i l t e r ( new TextLineCodecFactory ( C h a r s e t . forName ( UTF8 ) ) ) ) ; CmmdcHandler h a n d l e r=new CmmdcHandler ( ) ; acceptor . setHandler ( handler ) ; System . out . p r i n t l n ( S e r v e r r e a d y on p o r t + PORT) ; a c c e p t o r . bind (new I n e t S o c k e t A d d r e s s (PORT) ) ; } }

Clasa manipulatorului extinde clasa IoHandlerAdapter. Sarcina programatorului const suprascrierea unora din metodele: a n public void sessionOpened(IoSession session)throws Exception public void sessionCreated(IoSession session)throws Exception public void sessionClosed(IoSession session)throws Exception public void sessionIdle(IoSession session,IdleStatus status)throws Exception public void exceptionCaught(IoSession session,Throwable cause)throws Exception public void messageReceived(IoSession session,Object message)throws Exception public void messageSent(IoSession session,Object message)throws Exception Codul clasei CmmdcHandler este
1 2 4 5 6 7 8 9 11 12 13 14 15

import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcHandler extends I o H a n d l e r A d a p t e r { @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) throws E x c e p t i o n { cause . printStackTrace ( ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) throws E x c e p t i o n { S t r i n g l s=System . g e t P r o p e r t y ( l i n e . s e p a r a t o r ) ; S t r i n g s t r = message . t o S t r i n g ( ) . t r i m ( ) ;

2.6. APACHE-MINA

55

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

String [ ] pieces = str . s p l i t ( ) ; i f ( p i e c e s . l e n g t h <2){ session . write ( l s ) ; s e s s i o n . w r i t e ( Numar i n s u f i c i e n t de p a r a m e t r i ) ; session . write ( l s ) ; } else { try { long var1 , v a r 2 ; v a r 1 = Long . par se Lon g ( p i e c e s [ 0 ] ) ; v a r 2 = Long . par se Lon g ( p i e c e s [ 1 ] ) ; session . write ( l s ) ; App o b j=new App ( ) ; s e s s i o n . w r i t e ( o b j . cmmdc( var1 , v a r 2 ) ) ; session . write ( l s ) ; } catch ( NumberFormatException ex ) { session . write ( l s ) ; s e s s i o n . w r i t e ( Date i n c o r e c t e nu s u n t numere ) ; session . write ( l s ) ; } } } }

Aplicatia client
Aplicatia client se compune din clasele: CmmdcClient - ndeplinete sarcinile MINA; s CmmdcClientHandler - manipulatorul prtii client; a Sarcinile MINA se programeaz prin a 1. Denirea unui adaptor pentru protocolul TCP al operatiilor de intrare/ieire: s IoAcceptor acceptor = new NioSocketAcceptor(); Pentru protocolului UDP se utilizeaz clasa NioDatagramAcceptor. a 2. Denirea ltrului care transform irul de octeti al datelor serializate as n cazul care datele sunt iruri obiecte / tipuri predenite sau invers. In n s de carctere (String), codul este acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));

56

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

3. Ataarea manipulatorului datelor vehiculate, obiectul care implementeaz s a logica aplicatiei: CmmdcClientHandler handler=new CmmdcClientHandler(); acceptor.setHandler(handler); 4. Conectarea: acceptor.bind(new InetSocketAddress(PORT) ); Codul complet al clasei CmmdcClient este
1 2 3 4 5 6 7 9 10 11 12 14 15 16 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

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 o r g . apache . mina . c o r e . R unti meIoE xcep tion ; import o r g . apache . mina . c o r e . f u t u r e . ConnectFuture ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; import o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . N i o S o c k e t C o n n e c t o r ; // i m p o r t o r g . apache . mina . t r a n s p o r t . s o c k e t . n i o . NioDatagramConnector ; import o r g . apache . mina . c o r e . s e r v i c e . I o C o n n e c t o r ; import import import import o r g . apache . mina . f i l t e r . c o d e c . P r o t o c o l C o d e c F i l t e r ; o r g . apache . mina . f i l t e r . c o d e c . t e x t l i n e . TextLineCodecFactory ; java . nio . c h a r s e t . Charset ; 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 ) throws Throwable { 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 =8999; 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 ] ) ; 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 c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; n=s c a n n e r . nextLong ( ) ; I o C o n n e c t o r c o n n e c t o r = new N i o S o c k e t C o n n e c t o r ( ) ; // IoConnector c o n n e c t o r = new NioDatagramConnector ( ) ; c o n n e c t o r . g e t F i l t e r C h a i n ( ) . addLast ( c o d e c , new P r o t o c o l C o d e c F i l t e r ( new TextLineCodecFactory ( C h a r s e t . forName ( UTF8 ) ) ) ) ; c o n n e c t o r . s e t H a n d l e r (new CmmdcClientHandler (m, n ) ) ; I o S e s s i o n s e s s i o n = null ; try { ConnectFuture f u t u r e = c o n n e c t o r . c o n n e c t (new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ) ; future . awaitUninterruptibly ( ) ; session = future . getSession ( ) ; } catch ( R unti meIoE xcep tion e ) { System . out . p r i n t l n ( C o n e c t a r e e s u a t a ) ;

2.6. APACHE-MINA

57

44 45 46 47 48 49

System . e x i t ( 0 ) ; } s e s s i o n . getCloseFuture ( ) . awaitUninterruptibly ( ) ; connector . dispose ( ) ; } }

Codul clasei CmmdcClientHandler este


1 2 4 5 7 8 9 10 12 13 14 15 16 17 19 20 21 22 23 24 25 26 28 29 30 31 32

import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcClientHandler extends I o H a n d l e r A d a p t e r { private long m, n ; public CmmdcClientHandler ( long m, long n ) { t h i s .m = m; this . n = n ; } @Override public void s e s s i o n O p e n e d ( I o S e s s i o n s e s s i o n ) { S t r i n g message = m + + n ; System . out . p r i n t l n ( M e s a j u l t r i m i s : +message ) ; s e s s i o n . w r i t e ( message ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) { S t r i n g r e s u l t = message . t o S t r i n g ( ) ; i f ( r e s u l t . l e n g t h () >0) { System . out . p r i n t l n ( R e z u l t a t u l e s t e : +r e s u l t ) ; s e s s i o n . c l o s e ( true ) ; } } @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) { s e s s i o n . c l o s e ( true ) ; } }

2.6.1

Mesaje componente Java

Inlocuim forma de transmitere a datelor din String componenta Java n (Bean)


1 2 3 4 6 7 8 9

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 CmmdcMessage implements S e r i a l i z a b l e { private long m, n ; private long r e s u l t ; public long getM ( ) { return m; } public void setM ( long m) {

58

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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

t h i s .m = m; } public long getN ( ) { return n ; } public void setN ( long n ) { this . n = n ; } public long g e t R e s u l t ( ) { return r e s u l t ; } public void s e t R e s u l t ( long r e s u l t ) { t h i s . r e s u l t=r e s u l t ; } public S t r i n g t o S t r i n g ( ) { return CmmdcMessage ( + + , +n+ ) ; m } }

Filtrul care transform irul de octeti al datelor serializate obiecte i invers as n s va acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new ObjectSerializationCodecFactory())); Codurile celor dou clase manipulatoare devin a CmmdcHandler
1 2 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22

import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcHandler extends I o H a n d l e r A d a p t e r { @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) throws E x c e p t i o n { cause . printStackTrace ( ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) throws E x c e p t i o n { i f ( message instanceof CmmdcMessage ) { CmmdcMessage msg = ( CmmdcMessage ) message ; App o b j=new App ( ) ; long r e z = o b j . cmmdc( msg . getM ( ) , msg . getN ( ) ) ; msg . s e t R e s u l t ( r e z ) ; s e s s i o n . w r i t e ( msg ) ; } } }

2.6. APACHE-MINA

59

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

import o r g . apache . mina . c o r e . s e r v i c e . I o H a n d l e r A d a p t e r ; import o r g . apache . mina . c o r e . s e s s i o n . I o S e s s i o n ; public c l a s s CmmdcClientHandler extends I o H a n d l e r A d a p t e r { private long m, n ; public CmmdcClientHandler ( long m, long n ) { t h i s .m = m; this . n = n ; } @Override public void s e s s i o n O p e n e d ( I o S e s s i o n s e s s i o n ) { CmmdcMessage message = new CmmdcMessage ( ) ; message . setM (m) ; message . setN ( n ) ; System . out . p r i n t l n ( M e s a j u l t r i m i s : +message . t o S t r i n g ( ) ) ; s e s s i o n . w r i t e ( message ) ; } @Override public void m e s s a g e R e c e i v e d ( I o S e s s i o n s e s s i o n , O b j e c t message ) { i f ( message instanceof CmmdcMessage ) { CmmdcMessage mesaj = ( CmmdcMessage ) message ; System . out . p r i n t l n ( R e z u l t a t u l e s t e : +mesaj . g e t R e s u l t ( ) ) ; s e s s i o n . c l o s e ( true ) ; } } @Override public void e x c e p t i o n C a u g h t ( I o S e s s i o n s e s s i o n , Throwable c a u s e ) { s e s s i o n . c l o s e ( true ) ; } }

2.6.2

Serializare folosind un codec personalizat

Stergnd serializarea din codul clasei CmmdcMessage suntem obligati s a a denim o clas care realizeaz serializarea, CmmdcMessageCodecFactory a a
1 2 3 4 6 7 8 10 11 12 13 15

import import import import

o r g . apache . mina . o r g . apache . mina . o r g . apache . mina . o r g . apache . mina .

f i l t e r . codec . ProtocolCodecFactory ; f i l t e r . codec . ProtocolEncoder ; f i l t e r . codec . ProtocolDecoder ; core . session . IoSession ;

public c l a s s CmmdcMessageCodecFactory implements P r o t o c o l C o d e c F a c t o r y { private P r o t o c o l E n c o d e r e n c o d e r ; private P r o t o c o l D e c o d e r d e c o d e r ; public CmmdcMessageCodecFactory ( ) { e n c o d e r = new CmmdcMessageEncoder ( ) ; d e c o d e r = new CmmdcMessageDecoder ( ) ; } public P r o t o c o l E n c o d e r g e t E n c o d e r ( I o S e s s i o n i o S e s s i o n ) throws E x c e p t i o n {

60

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

16 17 19 20 21 22

return e n c o d e r ; } public P r o t o c o l D e c o d e r g e t D e c o d e r ( I o S e s s i o n i o S e s s i o n ) throws E x c e p t i o n { return d e c o d e r ; } }

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

import import import import

o r g . apache . mina . o r g . apache . mina . o r g . apache . mina . o r g . apache . mina .

core . buffer . IoBuffer ; core . session . IoSession ; f i l t e r . codec . ProtocolEncoderAdapter ; f i l t e r . codec . ProtocolEncoderOutput ;

public c l a s s CmmdcMessageEncoder extends P r o t o c o l E n c o d e r A d a p t e r { public void en c ode ( I o S e s s i o n s e s s i o n , O b j e c t message , P r o t o c o l E n c o d e r O u t p u t out ) throws E x c e p t i o n { i f ( ( message instanceof CmmdcMessage ) == f a l s e ) return ; CmmdcMessage msg = ( CmmdcMessage ) message ; IoBuffer buffer = IoBuffer . a l l o c a t e (24 , false ) ; b u f f e r . putLong ( msg . getM ( ) ) ; b u f f e r . putLong ( msg . getN ( ) ) ; b u f f e r . putLong ( msg . g e t R e s u l t ( ) ) ; buffer . f l i p (); out . w r i t e ( b u f f e r ) ; } }

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

import import import import

o r g . apache . mina . o r g . apache . mina . o r g . apache . mina . o r g . apache . mina .

core . buffer . IoBuffer ; core . session . IoSession ; f i l t e r . codec . CumulativeProtocolDecoder ; f i l t e r . codec . ProtocolDecoderOutput ;

public c l a s s CmmdcMessageDecoder extends C u m u l a t i v e P r o t o c o l D e c o d e r { protected boolean doDecode ( I o S e s s i o n s e s s i o n , I o B u f f e r in , P r o t o c o l D e c o d e r O u t p u t out ) throws E x c e p t i o n { i f ( i n . r e m a i n i n g ( ) >= 2 4 ) { long m = i n . getLong ( ) ; long n = i n . getLong ( ) ; long r e s u l t = i n . getLong ( ) ; CmmdcMessage msg = new CmmdcMessage ( ) ; msg . setM (m) ; msg . setN ( n ) ; msg . s e t R e s u l t ( r e s u l t ) ; out . w r i t e ( msg ) ; return true ; } else { return f a l s e ; } } }

2.6. APACHE-MINA

61

Filtrul care transform irul de octeti al datelor serializate obiecte i invers as n s va acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new CmmdcMessageCodecFactory()));

62

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Capitolul 3 Regsirea obiectelor prin a servicii de nume


Oricrui obiect sunt asociate un nume i o referinta. Regsirea / cutarea a i s a a obiectului se face pornind de la numele obiectului, prin referinta se ajunge la obiect. Exemple date prin ablonul (Nume Referinta Obiect) s 1. Accesul la o carte ntr-o bibliotec: a Titlul crtii Referint crtii din bibliotec Carte a a a a 2. Contactul telefonic cu o persoana: Nume persoan Numr telefon Persoan a a a Un serviciu de nume contine asocieri dintre nume de obiecte i obiecte i s s poate oferi faciliti de regsire a obiectelor. at a

3.1

Java Naming and Directory Interface

Java Naming and Directory Interface - JNDI este o interfata de programare (Application Programming Interface - API ) care descrie functionalitatea unui serviciu de nume. Cuvntul servici este utilizat sens comun, entitate care pune la dispozitie a n faciliti de folosire. at Alturi de interfata JNDI, arhitectura JNDI mai contine interfata Service a Provider Interface - SPI. Implementarea interfetei SPI de un furnizor de ser vicii JNDI are ca efect independenta programului Java de furnizorul de servicii JNDI. 63

64

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

JNDI este implementat de serviciile de nume: Filesystem are ca obiect asocierea dintre numele de ier sau catalog cu s obiectul corespunztor. a DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu adresa IP. RMI registry utilizat aplicatii RMI, din Java. Are ca obiect asocierea n ntre un nume de serviciu de invocare ale obiectelor la distant cu un a delegat al serviciului (stub). COS - Common Object Service Naming utilizat aplicatii CORBA. Are n ca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor la distanta cu referinta la serviciu. LDAP - Lightweight Directory Access Protocol denete un protocol pens tru accesarea datelor retinute ntr-un catalog LDAP (LDAP directory, information directory). Un catalog LDAP permite retinerea i regsirea s a referintelor obiectelor denite pe un calculator.

Interfata javax.naming.Context
Printr-un context se va elege o multime de asocieri nume - obiect. Corent spunztor unui context, JNDI denete interfata Context, cu metodele a s 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 lista cu nume obiectelor a mpreuna cu tipul lor. NamingEnumeration listBindings(String nume) Returneaz lista cu nume obiectelor a mpreuna cu tipul i locatia acestora. s Specicatiile JNDI prevd denirea unui context initial, implementat prin a clasa javax.naming.InitialContext, clas ce implementeaz interfata Context. a a Constructori.

3.1. JAVA NAMING AND DIRECTORY INTERFACE

65

public InitialContext() throws NamingException public void InitialContext(Hashtable<?,?> environment)throws NamingException Pentru crearea contextului initial trebuie specicata clasa care creaz con a textul initial prin parametrul java.naming.factory.initial sau constanta Context.INITIAL CONTEXT FACTORY. Acest parametru se poate da mai multe moduri: n Includerea obiectul Hashtable care apare constructorul clasei InitalContext. n n 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 interiorul programului prin n System.setProperty("java.naming.factory.initial",...); sau System.setProperty(Context.INITIAL_CONTEXT_FACTORY,...); Atribut ierul de proprieti jndi.properties. n s at aceste ultime dou cazuri, contextul initial se creaz prin In a a Context ctx=new InitialContext();

66

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Functie de serviciul de nume, clasa care creaz contextul initial este dat a 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 Utiliznd serviciul JNDI Filesystem se creaz un context a a prin intermediul creia se aeaz continutul unui catalog indicat de client. a s a
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 33 34 35 36 37 38 39

import import import import

j a v a x . naming . ; 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 ( ) ; } 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 ( ) ) ; }

3.1. JAVA NAMING AND DIRECTORY INTERFACE

67

41 42 43 44 45 46 48 49 50 51 52 53 55 56 57 58 59 60 61 62 63 64 65 66 67

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, varianta dat, const din n a a


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

sau
java Lookup

caz, care, catalogul curent se gsete ierul jndi.properties cu continutul n n a s s


java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory

Serviciul de nume Filesystem este dat de ierele: fscontext.jar i s s providerutil.jar.

3.1.1

LDAP

LDAP poate privit ca un sistem de gestiune a unei baze de date (ne relational). Baza de date este alctuit din atribute ale cror nume este pre a a a cizat de protocolul LDAP. Punctele de intrare (rdcinile) sunt date de DN (Distinguished Name). a a Uzual DN se denete printr-una din variantele s 1. o=organization,c=country

68

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

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 i are s acces la LDAP prin precizarea simultan a atributelor DN i cn. a s Implementri gratuite LDAP sunt: a OpenDS (Open Directory Service); ApacheDS (Apache Directory Service). Apache Directory Studio incorporeaz i ofer interfata grac pentru ApacheDS. as a a Vom utiliza produsul OpenDS. Instalarea const din: a 1. dezarhivarea distributiei; 2. se completeaz sursa ierului OpenDS-*\setup.bat cu a s set OPENDS JAVA HOME=... ca prima linie; 3. se execut OpenDS-*\setup.bat. Prin intermediul unei interfete grace a se xeaz a o parola pentru cn=Directory Manager. Fie 1q2w3e aceast parol. a a un punct de intrare, e acesta DN: dc=example,dc=com. Implicit, serverul OpenDS utilizeaz portul 389. a Operatiile de congurare se fac utiliznd interfata grac a componentei a a OpenDS Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . . set OpenDS_HOME=. . .\OpenDS-* %OpenDS_HOME%\bat\control-panel.bat

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 i Reset User Password. s

3.1. JAVA NAMING AND DIRECTORY INTERFACE

69

Prin aceast component se poate porni i opri serverul OpenDS, ambele a a s operatii putnd executate i apelnd start-ds, stop-ds din catalogul a s a OpenDS HOME\bat. Actiunile care pot ntreprinse de un client care interactioneaz cu serverul a constau n autenticare: datele necesare sunt DN i parola; s conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea implic crearea unui punct de intrare precizat prin cn; a cutarea / localizarea (lookup) unui punct de intrare precizat prin cn. a Exemplul 3.1.2 Program pentru nregistrarea i tergerea referintei unui obiect s s 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 32 33 34 35 36 37

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 ; 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 ( ) ;

70

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

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

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 regsit pe baza referintei a din serverul LDAP.
1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21

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 ( ) ; 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 ) ;

3.1. JAVA NAMING AND DIRECTORY INTERFACE

71

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

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 ) ) ; } } catch ( NamingException e ) { System . out . p r i n t l n ( LDAPClientCmmdc : +e . g e t M e s s a g e ( ) ) ; } } }

72

CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Capitolul 4 Invocarea procedurilor la distant a


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

4.1

Remote Method Invocation

Regsirea obiectelor la distant. Ideea gsirii unui obiect la distant a a a a este c serverul a nscrie un reprezentant al su numit stub (ciot) a ntr-un obiect registry - registru. Acest obiect se creaz cu programul rmiregistry.exe a din distributia java i se lanseaz executie prin s a n start rmiregistry [port] unde valoarea implicit a portului este 1099. Comanda start apartine sisa temului de operare. rmiregistry este un serviciu de nume JNDI. 73

74

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Un client obtine din registry stub-ul serverului, prin intermediul cruia a realizeaz comunicatia cu programul server. a Cnd un obiect al clientului apeleaz o metod a unui obiect aat la a a a distanta, se va face, de fapt, un apel de metod a unui obiect care reprezint a a serverul. Acesta este stub-ul, aat pe aceai main cu clientul. s s a Rolul acestui obiect este s a mpacheteze (marshalling) parametrii de apel ai metodei ntr-un mesaj ce va transferat prin retea. Impachetarea se face ntr-o manier independent de calculator, mai precis irurile de caractere i a a s s obiecte sunt transmise ntr-un format care nu se bazeaz pe referinte. Pentru a obiecte se utilizeaz serializarea obiectelor Java. a Serializarea datelor reprezint transformarea acestora din tipuri de date a diferite ntr-un ir de octeti care va transportat prin retea fr interpretare, s aa dar care pstreaz informatiile despre structura initial a datelor. a a a Deserializarea este procesul invers de refacere a structurilor trimise prin retea. Mesajul asamblat este transmis ctre server, care tie s desfac mesajul a s a a receptionat invocnd mod corespunztor metoda referit de client. a n a a Atunci cnd clientul face apel la o metod aat pe o alt main, este a a a a s a invocat stub-ul client, care ncepe conversatia cu serverul. Acest lucru este complet transparent utilizatorului, care are impresia c invoc o metod local. a a a a Metodele apelate la distanta trebuie declarate ca apartinnd unei interfete a ce extinde interfata java.rmi.Remote. Fiecare asemenea metod trebuie s a a arunce o exceptie java.rmi.RemoteException. Obiectele care circul prin a retea trebuie s implementeze interfata java.io.Serializable. a Structura unei aplicatii RMI. O aplicatie RMI este alctuit din trei a a componente: 1. O interfata la distanta (remote) care se declar serviciile puse la n a dispozitie de server; 2. Aplicatia server care poate implementa serviciile interfetei la distant i a s nscrie registry stub-ul corespunztor; n a 3. Aplicatia client ce apeleaz unul sau mai multe servicii ale serverului. a Aplicatia server trebuie s aib acces la clasele interfetei i a celor care a a s o implementeaz. Locatia acestor clase se xeaz prin atributul de nume a a java.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unul din protocoalele http, ftp, file. Utiliznd protocoalele http sau ftp arhiva interfetei i a claselor care o a s implementeaz se depun a ntr-un server Web (Microsoft Internet Interchange

4.1. REMOTE METHOD INVOCATION

75

Server (IIS), apache-tomcat, respectiv ntr-un server ftp (apache-ftp). moIn mentul lansrii aplicatiei server, serverul http / ftp trebuie s e activ. a a Dac se indic prin protocolul file calea ctre cataloagele care contin a a a clasele interfetei i ale implementrii lor atunci ultimul caracter al cii este /. s a a Din punctul de vedere al executiei sunt implicate componentele: Serviciul de nume rmiregistry; Aplicatia server; Aplicatia client. Aplicatia server i rmiregistry trebuie s ruleze pe acelai calculator. s a s Registrul rmiregistry implementeaz interfata java.rmi.registry.Registry1 . a Metodele oferite sunt: void bind(String numeServiciu, Remote obj )throws RemoteException, AlreadyBoundException, AccessException Inregistreaz registry obiectul obj ce implementeaz interfata Remote a n a sub numele numeServiciu. void rebind(String numeServiciu, Remote obj )throws RemoteException, AccessException Re nregistreaz registry obiectul obj ce implementeaz interfata Remote a n a sub numele numeServiciu. Aceast metod poate apelat doar dac programul care face a a a a nregistrarea se a pe aceai main ca registrul registry. a s s a String[] list()throws RemoteException, AccessException Returneaz o list a tuturor serviciilor a a nregistrate registry. n Remote lookup(String numeServiciu)throws RemoteException, NotBoundException, AccessException Returneaz stub-ul serviciului a nregistrat sub numele numeServiciu. void unbind(String numeServiciu)throws RemoteException, NotBoundException, AccessException Sterge din registru serviciul.
1

Varianta direct, fr a folosi facilitile JNDI pentru rmiregistry. a aa at

76

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Localizarea registrului se obtine utiliznd metoda static getRegistry a a 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 un registru la portul specicat pe calculaa torul local. Ansamblul (rmiregistry, port) determin mod univoc o aplicatie / servia n ciu. Interfata Remote servete la marcarea interfetelor ale cror metode urmeaz s a a a apelate de pe alt main virtual Java. a s a a Un obiect de tip java.rmi.server.UnicastRemoteObject mijlocete transs miterea obiectelor i servete la generarea unui stub unui serviciu. Generarea s s stub-ului unui serviciu se obtine prin intermediul metodei statice static Remote UnicastRemoteObject.exportObject(Remote obj ,int port) Inregistrarea stub-ului unui serviciu descris de interfata IService i im s plementat de clasa ServiceImpl registry se face prin n 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

77

"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 dorete s foloseasc trebuie s cunoasc : s a a a a calculatorul pe care se gsete obiectul registry i portul la care ascult a s s a serviciul; numele sub care serviciul s-a nregistrat registry; n metodele puse la dispozitie de serviciu.

4.1.1

Crearea unei aplicatii RMI

Exemplicm construirea unei aplicatii RMI care serviciul asigurat de a n server este calculul celui mai mare divizor comun a dou numere naturale. a 2 Pentru exemplele care urmeaz, presupunem c textele surs se retin a a a subcataloage ale unui catalog src, la care are acces doar programatorul, n iar clasele obtinute prin compilare se depun subcataloagele unui catalog n public\classes, accesibil prin retea. Dezvoltarea unei aplicatii se va face pe un calculator. acest sens, celor In 3 componente li se asociaz cataloagele \i - pentru interfata la distanta, \s a pentru componenta server i \c - pentru componenta client. Pai necesari coms s pilrii i desfurrii componentelor aplicatiei se vor realiza prin intermediul a s as a lui ant. Pentru ecare component se vor executa succesiv obiectivele: a 1. Install - creaz o structur de cataloage src i public\classes. a a s 2. Init - creaz structura de cataloage specic aplicatiei. a a 3. Compile - compileaz programele surs. a a Dezvoltarea unei aplicatii RMI const din parcurgerea urmtorilor pai: a a s 1. Denitea interfetei la distanta.

Sistemul de operare utilizat este Windows

78

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

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 interfetei retine textul surs a ICmmdc.java catalogul \i\src\cmmdc. n 2. Compilarea i arhivarea interfetei se poate realiza ierul ant-build s s
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 interfetei remote prin construirea aplicatiei server.

1 3 4 5 6 7 8

package s e r v e r ; import cmmdc . ; import j a v a . rmi . ; import j a v a . rmi . s e r v e r . ; // V a r i a n t a d i r e c t a // i m p o r t j a v a . rmi . r e g i s t r y . ; // V a r i a n t a JNDI

4.1. REMOTE METHOD INVOCATION

79

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 . ; 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 al programului server CmmdcImpl.java se retine catalogul a n \s\src\server 4. (a) Compilarea programului server; (b) Crearea obiectului registry; (c) Lansarea serverului lucru n se obtin 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

/>

80

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

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 57 58 59 60 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 } /> </ java> </ target>

4.1. REMOTE METHOD INVOCATION

81

70

</ project>

Obiectivele Rmi i Server se lanseaz ferestre dos distincte care rmn s a n a a active pe durata de viata a aplicatiei server. Obiectivul Archive creaz arhiva jar necesar desfurrii interfetei i a a as a s a claselor care o implementeaz a ntr-un server http / ftp. Aa cum s s-a amintit mai sus, acest arhiv este preluat de aplicatia server, la a a a lansare, prin atributul java.rmi.server.codebase. 5. Realizarea programului client

1 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 36 38 39 40 41 42

package c l i e n t ; import cmmdc . ; import j a v a . u t i l . S c a n n e r ; // V a r i a n t a d i r e c t a // i m p o r t j a v a . rmi . r e g i s t r y . ; // V a r i a n t a JNDI import j a v a x . naming . ; 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 =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 Lon g ( 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 ( ) ) ;

82
} } }

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

43 44 45

Sursa programului client CmmdcClient.java apartine catalogului \c\src\client 6. Compilarea programului client i lansarea acestuia executie. s n
1 2 4 6 7 8 9 10 11 12 14 15 16 17 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

<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 /> <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. REMOTE METHOD INVOCATION

83

4.1.2

Tipare de programare

Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamic a unui server. Prin a aceea schem, se va crea o clas - fabrica de obiecte - care implementeaz cte a a a a o metod get, ce returneaz o instanta de server. Aceste metode sunt declarate a a ntr-o interfata la distanta. Un client, apelnd o asemenea metod, va instantia serverul dorit i va a a s obtine stub-ul corespunztor. a felul acesta se vor putea utiliza o multime de aplicatii distincte prin In intermediul unui singur rmiregistry. Fiecrei aplicatii corespunde un server, a i instantiat la apelul clientului de metoda get corespunztoare. a Programarea unui server care poate lansat dinamic trebuie s satisfac a a restrictiile: Clasa serverului extinde clasa UnicastRemoteObject. Exist un constructor fr argumente ce arunc exceptia java.rmi.Remote a aa a Exception. Pentru exemplicarea tehnicii de lucru relum aplicatia pentru calculul a celui mai mare divizor comun a dou numere naturale, considernd interfata a a
1 2 3 4 5

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

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

package cmmdc0 ; im po rt j a v a . rmi . ; 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 Remote{ p u b l i c ICmmdc0 getCmmdc ( ) throws RemoteException ; }

Codurile claselor ServerCmmdc i FabObiecte sunt s


1 2 3 4 5

package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . i o . ; im po rt j a v a . u t i l . ;

84

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

7 9 11 12 13 14

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 6 8 9 10 11 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . rmi . 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 ] ; 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 ( ) ) ; } } }

Aplicatia client se compune din dou clase a 1. RemoteClient Clientul obtine stub-ul serviciului, prin intermediul cruia apeleaz metada a a getCmmdc() a fabricii de obiecte, obtinnd un obiect remote de tip a ServerCmmdc, ce implementeaz interfata la distanta ICmmdc0. a
1 2 3 4 6 8

package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . rmi . 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 ;

4.1. REMOTE METHOD INVOCATION

85

10 12 13 14 15 16 17 18 19 20 21 22 23

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 metoda compute a obiectului remote. a


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

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 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 ) ; = l o n g m c a n n e r . nextLong ( ) ; =s 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 numete apel invers apelarea de ctre programul server a unei metode s a a clientului. RMI realizarea unui apel invers presupune: In

86

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

1. denirea unei interfete la distanta ce va implementat de programul client; 2. programul client ce implementeaz interfata extinde clasa UnicastRemote a Object i are un constructor ce arunc o exceptie java.rmi.RemoteException. s a Extindem aplicatia anterioar cu posibilitatea suplimentar a serverului a a (ServerCmmdc) de a alege metoda de calcul a celui mai mare divizor comun dintre varianta nerecursiv i cea recursiv a algorimului lui Euclid. as a Extindem interfata ICmmdc0 cu metoda public void setMethod(ICallbackCmmdc obj)throws RemoteException;
1 2 3 4 5 6

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

unde ICallbackCmmdc este interfata


1 2 3 4 5

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

ce va implementat clasa RemoteClient. a n Programul ServerCmmdc devine


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

package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . i o . ; 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 ( ) ; }

4.1. REMOTE METHOD INVOCATION

87

25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 43 44 45 46

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= %n ; m m ; =n n=r ; } while ( r !=0); return c ; } }

Dup obtinerea stub-ului, clientul apeleaz metoda setMethod a serverului a a remote, care, prin apel invers, apeleaz metoda getMethod din RemoteClient. a Clientul stabilete metoda de calcul i apeleaz metoda compute a lui remote. s s a Programele client devin
1 2 3 4 5 7 8 9 11 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29

package cmmdc0 ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . s e r v e r . ; im po rt j a v a . rmi . 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 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 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 ner 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 {

88

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

30 31 32 33 34 35 36 37 38

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 ( ) ) ; } } }

i s
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

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 ) ; = l o n g m c a n n e r . nextLong ( ) ; =s 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 instanta a clasei UnicastRemoteObject reprezint un obiect la distanta a care ruleaz permanent, folosind resursele mainii server. a n a s Incepnd cu versiunea JDK 1.2, prin a ntroducerea clasei java.rmi.activation.Activatable i a programului rmid (...\jdk...\bin\rmid.exe) se pot crea s programe care nregistreaz informatii despre obiecte la distant ce vor create a a i executate la cerere. s Invocarea de la distant a unei metode apartinnd unui asemenea obiect a a are ca efect activarea obiectului.

4.1. REMOTE METHOD INVOCATION

89

Pe ecare main virtual Java exist un grup de activare (activation s a a a group), care realizeaz activarea. Activarea este fcut de un activator. Un a a a activator contine o tabel care face legtura dintre clasa obiectului cu URL-ul a a acestuia i eventual, cu date necesare initializrii obiectului. Atunci cnd actis a a vatorul constat c nu exist un obiect referit, face apel la grupul de activare a a a care va produce activarea obiectului. Din punctul de vedere al clientului utilizarea mecanismului de activare la distanta nu implic modicri. Modicrile intervin numai din punctul de a a a vedere al serverului i al s nregistrrii sale. a Relum aplicatia dezvoltat la a a nceputul capitolului, privind calculul celui mai mare divizor comun a dou numere naturale. a Aplicatia server este compus din dou clase a a 1. o clasa ce implementeaz interfata ICmmdc : CmmdcActivabil; a 2. clasa Setup, cu metoda main, care face posibil mecanismul de activare a i s nscrie serviciul registry. Aceast clas este preluat din tutorialul n a a a dedicat activrii a documentatiei ce ete distributia Java. a nsot s Clasa ce implementeaz interfata la distanta trebuie a 1. s extind clasa Activatable; a a 2. s aib un constructor ce are doi parametrii a a (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 initializare a obiec cazul nostru, acest parametru nu va folosit. tului activabil. In Codul surs al clasei CmmdcActivabil este a
1 2 3 4 6 7 9 10 11 12 14 15

package acmmdc ; im po rt j a v a . rmi . ; im po rt j a v a . rmi . a c t i v a t i o n . ; im po rt cmmdc . ; 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 ) { . . . } }

90

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Clasa Setup necesit o serie de date furnizare ca proprieti: a at 1. drepturile de securitate ale grupului de activare myactivation.policy=group.policy; cu continutul
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 din classpath-ul a local; 3. localizarea (URL) clasei ce implementeaz interfata a myactivation.impl.codebase; 4. localizarea unui ier cu date de initializare a obiectului activabil s myactivation.file; 5. numele sub care nregistreaz serviciul registry a n myactivation.name. Programul Setup realizeaz: a 1. Construirea unui descriptor al grupului de activare. Grupul de activare este un container ce gestioneaz obiectele activabile continute. a 2. Inregistrarea descriptorului grupului de activare i obtinerea unui idens ticator al grupului de activare. 3. Construirea descriptorului de activare. Trebuie cunoscute idendicatorul grupului de activare; numele clasei ce implementeaz interfata la distanta; a localizarea (URL) clasei ce implementeaz interfata la distanta; a

4.1. REMOTE METHOD INVOCATION

91

obiectul de tip MarshalledObject, cu datele de initializare a obiec tului activabil. 4. Inregistrarea descriptorului de activare, urma creia se obtine stub-ul n a obiectului activabil. 5. Inregistrarea stub-ului mpreun cu numele serviciului registry. a n Codul clasei setup este
1 3 4 5 6 8 10 12 14 15 16 17 18 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

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 > ) ; 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 ( ) ) {

92

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

47 48 50 51 53 54 55 57 58 59 60 61 62

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 programe CmmdcActivabil.java i respectiv Setup.java a s sunt catalogul \c\src\acmmdc. n Lansarea serverului executie const din n a 1. Pornirea demon-ului rmid start rmid -J-Djava.security.policy=rmid.policy -J-Dmyactivation.policy=group.policy unde rmid.policy este
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

4.2. CORBA

93

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) interfetei la distanta se precizeaz prin a java.rmi.server.codebase; Drept client se utilizeaz programul realizat sectiunea 4.1. a n

4.2

CORBA

Retelele de calculatoare sunt eterogene timp ce majoritatea interfetelor n de programare a aplicatiilor sunt orientate spre platforme omogene. Pentru a facilita integrarea unor sisteme dezvoltate separat, ntr-un singur mediu distribuit eterogen, OMG (Object Management Group consortiu cuprinznd peste 800 de rme) a elaborat standardul CORBA (Common Oba ject Request Broker Arhitecture): un cadru de dezvoltare a aplicatiilor dis tribuite medii eterogene. n La CORBA au aderat toate marile rme de software - cu exceptia Microsoft, rm care a dezvoltat propriul su model DCOM (Distributed Component a a Object Model), incompatibil CORBA. Aplicatia server se nregistreaz a ntr-un Object Request Broker (ORB) sub un nume simbolic - nume servici. Pe baza acestui nume de servici, un client accesnd ORB va avea acces la functiile oferite de aplicatia server. a ORB este un pachet de servicii, independent de aplicatii, dar care permit aplicatiilor s interactioneze prin retea. ORB face parte din middleware un a intermediar ntre softul de retea i cel de aplicatie. s 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. Distributia jdk ofer un ORB utilizabil Java sub forma unui servici a n JNDI.

94

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

CORBA face o separare ntre interfata unui obiect i implementarea sa i s s folosete un limbaj neutru pentru denirea interfetelor: IDL -- Interface s Definition Language. IDL permite realizarea descrierii de interfete independent de limbajul de programare i de sistemul de operare folosit. O interfat IDL denete legtura s a s a dintre client i server. s

4.2.1

Conexiunea RMI - CORBA

Firma Oracle - Sun Microsystems a dezvoltat o solutie prin care interfetele RMI pot implementate pentru a putea accesate ca obiecte CORBA. Aceasta este cunoscut sub numele de solutia RMI-IIOP, concretizat printr-o serie de a a acest fel nu mai este necesar utilizarea limbapachete din distributia jdk. In jului IDL pentru descrierea interfetelor la distanta. Instrumente necesare utilizrii solutiei RMI-IIOP: a compilatorul rmic Optiunea -iiop genereaza stub-ul i legtura (tie) din partea serverului. s a Cu optiunea -d se specic catalogul care aceste iere sunt scrise. a n s serviciul ORB care asigur regsirea resurselor CORBA. Acest server se a a lanseaz executie prin a n start orbd -ORBInitialPort [port] Programele orbd, rmic sunt distributia jdk. n

Dezvoltarea unei aplicatii RMI-IIOP


Exemplicm prin aplicatia care implementeaz un serviciu de calcul a celui a a mai mare divizor comun a dou numere naturale. Etapele realizrii aplicatiei a a sunt: 1. Elaborarea interfetei este identic cu cea a aplicatiei RMI. a 2. Implementarea interfetei
1 2 3 4

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 . ; im po rt j a v a . rmi . ;

4.2. CORBA

95

6 7 9 10 11 13 14

// 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

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 ;

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

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 ) ; 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 i CmmdcServer.java. s 5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunztor interfetei a ICmmdc i a ierului Tie cmmdciiop. CmmdcImpl Tie.class corespunztor s s a clasei CmmdcImpl. Acestea se obtin rulnd utilitarul rmic - din distrubutia a Java cu optiunea -iiop rmic -iiop cmmdciiop.CmmdcImpl

96

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

6. Pornirea serverului CORBA de regsire a serviciilor a start orbd -ORBInitialPort 1050 7. Lansarea serverului executie. n Activitile legate de server se obtin prin ant cu ierul build at s
1 2 4 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22 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

<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 /> <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 >

4.2. CORBA

97

51 52 53 55 56 57 58 59 60 61 62 63 64

<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 i aplicatia server se pot aa pe calculatoare distincte. s 8. Editarea programului client.

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

package cmmdciiop ; import j a v a . rmi . ; import j a v a x . rmi . ; import j a v a . n e t . MalformedURLException ; import j a v a x . naming . ; import j a v a . u t i l . S c a n n e r ; import cmmdc . ; 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 ; 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 Lon g ( 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 ) ;

98

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

38 39 40 41 42 43 44 45

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 i lansarea clientului executie. Clientul trebuie s dispun s n a a de ierul stub (cmmdc. ICmmdc Stub.class) i bine eles de interfata s s nt ICmmdc.jar. Fiierul buildle pentru executarea clientului: s
1 2 4 6 7 8 9 10 11 12 13 14 15 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

<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 stubl 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= stubc 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 /> <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 stubl o c a t i o n } i n c l u d e s= ${ stubc 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 />

4.2. CORBA

99

43 45 46 47 48 49 50 52 53 54 55 56 57 58 59 60 61

</ 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

Aplicatie Java prin CORBA

Scopul acestei sectiuni este prezentarea dezvoltrii unei aplicatii pe baza a unei interfete bazat pe IDL. Pentru dezvoltarea aplicatiilor limbajul de programare Java, translatarea n interfetei IDL Java se realizeaz cu utilitarul idlj din distributia jdk. n a Corespondenta ntre entitile IDL i Java este dat Tabelul 4.1 at s a n Legarea cererii unui client de codul serviciului care satisface cererea utilizeaz componenta CORBA Portable Object Adapter (POA). a

Model cu server temporal


Exemplicm dezvoltarea unei aplicatii distribuite CORBA cazul care a n n serviciul pus la dispozitie de server este calculul celui mai mare divizor comun a dou numere naturale. a Dezvoltarea unei aplicatii distribuite CORBA cu mediul nativ Java pre supune parcurgerea urmtoarelor pai: a s 1. Realizarea interfetei IDL care nseamn a (a) Editarea programului de interfata:
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 ) ; }; };

100

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

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: Entiti IDL i Java at s

Salvm acest text a ntr-un ier denumit Cmmdc.idl. s Cmmdc va numele interfetei utilizat de un client i implementat s de server. Serviciul contine o singur metod cmmdc. a a (b) Translatarea interfetei Java n idlj -fall Cmmdc.idl Programul idlj creaz un subcatalog CmmdcApp cu un pachet Java CmmdcApp a continnd ierele: a s Cmmdc.java CmmdcPOA.java ; CmmdcOperations.java; CmmdcStub.java; CmmdcHelper.java;

4.2. CORBA

101

CmmdcHolder.java. 2. Realizarea programelor server. Punem evidenta programul servant n CmmdcImpl.java ce implementeaz interfata Cmmdc. a
1 2 4 5 7 8 9 11 12

im po rt CmmdcApp . ; im po rt o r g . omg .CORBA. ; 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 ) { . . . } }

i programul CmmdcServer.java, care s nscrie registrul ORB referintele n servantului. Activitile ce trebuie at ntreprinse sunt declarate prin comentarii textul surs al programului n a
1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 22 23 24 26 27 28 29 31 32 33 34

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

CmmdcApp . ; o r g . omg . CosNaming . ; o r g . omg . CosNaming . NamingContextPackage . ; o r g . omg .CORBA. ; o r g . omg . P o r t a b l e S e r v e r . ;

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 ) ;

102

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

36 38 39 40 41 42 43 44 45 46

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 clas corespunde unui ablon de programare adaptat exemplului a a s acest caz numele serviciului inregistrat ORB va Cmmdctratat. In n Service. Evidenta numelor serviciilor CORBA nregistrate ORB este n fcut de serviciul NameService. a a 3. Realizarea programului client CmmdcClient.java:
1 2 3 4 5 7 8 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

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

CmmdcApp . ; o r g . omg . CosNaming . ; o r g . omg . CosNaming . NamingContextPackage . ; o r g . omg .CORBA. ; 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 ; 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 c a n n e r . nextLong ( ) ; =s 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 ) ; }

4.2. CORBA

103

39 40

} }

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

Model cu server persistent


Se consider aceai interfata Cmmdc.idl. a s Partea de server este alctuit din clasa servant CmmdcImpl.java care ima a plementeaz interfata Cmmdc -prezentat sectiunea anterioar i clasa Pera n as sistentServer care asigur a legtura cu serviciile ORB; a accesul la clasa servantului.
1 2 3 4 6 7 8

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

java . u t i l . Properties ; o r g . omg .CORBA. ; o r g . omg . CosNaming . ; o r g . omg . P o r t a b l e S e r v e r . ;

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 ( ) ;

104

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

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

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 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 4 6 7 8

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

java . u t i l . Properties ; o r g . omg .CORBA. ; o r g . omg . CosNaming . ; o r g . omg . P o r t a b l e S e r v e r .POA;

im po rt CmmdcApp . CmmdcHelper ; im po rt CmmdcApp . Cmmdc ; im po rt j a v a . u t i l . S c a n n e r ;

4.2. CORBA

105

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

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 canner . nextInt ( ) ; =s 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 ) ) ; } 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 e pe acelai calculator pe care ruleaz orbd. Exea s a cutarea aplicatiei presupune: 1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din distributia jdk. orbd -ORBInitialPort 1050 -serverPollingTime 200 2. Activarea serverului: (a) Se lanseaz utilitarul servertool a servertool -ORBInitialPort 1050 (b) Se nregistreaz serverul a mpreun cu numele serviciului pe care a l ndeplinete: s

106

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

servertool > register -server PersistentServer -applicationName PersistentCmmdcServer -classpath cale_catre_fisierele_server\ Indeplinirea actiunii de nregistrare a serverului este indicat printr-un mesaj de forma server registered (serverid=257). Alte comenzi servertool Comanda servertool> servertool> servertool> servertool> Semnicatie shutdown -serverid 257 Oprirea serviciului unregister -serverid 257 Stergerea serviciului quit Inchiderea utilitarului help

Observatie 4.2.1 Dac se utilizeaz referinta a a c:\Program Files\Java\jdk1.7.0 *\bin n variabila de sistem PATH (n loc de c:\Progra 1\Java\jdk1.7.0 *\bin) atunci apelarea serviciilor orbd i servertool se va face prin s
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]]

Capitolul 5 Mesaje Java n


Comunicatia prin apelul la distanta - inclusiv RMI - este sincron: pro gramul apelant se blocheaz i ateapt ca metoda apelat s se termine i s as s a a a s a furnizeze rezultatul cerut. Cu alte cuvinte apelul de procedur la distanta cere a att clientului ct i serverului s e simultan disponibile. a a s a Comunicatiile asincrone ntre programe permit realizarea unor sisteme de programe cu un grad mult mai sczut de cuplare. Asemenea aplicatii se pot a realiza prin comunicatii de mesaje, mesaje care sunt retinute de un intermediar (serviciu de mesagerie, server, broker, messaging middleware). prezent protocolul pentru realizarea aplicatiilor bazate pe comunicatii In de mesaje este Advanced Message Queue Protocol - AMQP. AMQP este un protocol dezvoltat de mai multe rme bazat pe standardele World Wide Web Consortium (W3C) i Internet Engineering Task Force (IETF) pentru comus nicare cu mesaje prin intermediul unui serviciu de mesagerie i care se dorete s s independent de limbajul de programare. Modelul AMQP nglobeaz standardul Java Message Service - JMS, deza voltat de Oracle - Sun Microsystems. Comunicatia se realizeaz prin socluri TCP. a

5.1

Java Message Service (JMS)

JMS denete un cadru de programare Java (API) pentru realizarea aplicatiilor s bazate pe comunicatii asincrone. Exist mai multe implementri JMS, dintre a a care semnalm: a Open Message Queue a rmei Oracle. Numele anterior al produsului a fost Java Message Queue 107

108 ActiveMQ realizat de fundatia apache. a qpid realizat de fundatia apache. a O aplicatie JMS este alctuit din a a

CAPITOLUL 5. MESAJE JAVA IN

un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeaz specicatiile JMS; a client JMS : aplicatie Java care trimite i receptioneaz mesaje; s a mesaje : obiecte utilizate schimbul de informatii de clienti JMS; n obiecte administrator : obiecte (resurse) create de administrator pentru a utilizate de clientii JMS, precum fabrica de conexiuni, obiectele destinatie mpreun cu resursele lor. a Modele de comunicatie: Comunicatii punctuale : Un mesaj este generat de un productor (exped a itor) i la care va avea acces un singur consumator (destinatar). Mesajul s este depus ntr-o coad, de unde este preluat de ctre consumatorul care a a s-a legat de coad. Dac de coad nu se leag nici un consumator, atunci a a a a mesajul este pstrat coad. a n a Comunicatii axate pe subiect (topic) : Mesajele sunt depuse (publicate) destinatii specice subiectului. Consumatorii ce au subscris la acel n subiect au acces la mesajele respective. Mai multi productori pot genera a mesaje specice unui subiect, mesaje care pot accesate de consumatorii care au subscris subiectului. Structura unui mesaj Un mesaj este alctuit din a Antet (header) : contine informatii pentru identicarea destinatiei ct i a s pentru identicarea mesajului. Proprieti : au caracter optional i sunt sub forma (nume, valoare). at s Proprietile ajut consumatorii s selecteze mesajele. at a a Corpul mesajului : optional. Potrivit specicatiilor JMS exist 6 tipuri a de mesaje. Message : mesaj fr corp; aa

5.2. OPEN MESSAGE QUEUE

109

StreamMessage : corpul mesajului contine un ux Java de date de tip predenit; ByteMessage : MapMessage : corpul mesajului contine o familie de perechi (nume, valoare); TextMessage : corpul mesajului contine un string; ObjectMessage : corpul mesajului contine un obiect serializat.

5.2

Open Message Queue

Instalarea. Functie de resursa descrcat, mediul Windows, instalarea a a n const din a Se dezarhiveaz ierul openmq* *-installer-WINNT.zip i se lanseaz a s s a n executie programul de instalare. s a Se dezarhiveaz ierul openmq* *-binary-WINNT.zip i se xeaz atributele a s ierului etc\mq\imqenv.conf. s Lansarea serviciului JMS. Orice aplicatie JMS necesit functionarea a serviciului JMS. Serviciul JMS se instaleaz prin a imqbrokerd -tty Optiunea -tty are ca efect aarea mesajelor pe ecran. Functionarea corect s a este indicat prin mesajul a imqbroker@hostname:7676 ready Dac se dorete schimbarea portului atunci se folosete optiunea -port a s s port. Pe un calculator pot coexista mai multe servicii JMS doar dac folosesc a acest caz, lansarea unui nou serviciu porturi distincte i au nume diferite. In s se face prin imqbrokerd -tty -port port -name name Cu utilitarul imqsvcadmin putem dezinstala : imqsvcadmin remove verica : imqsvcadmin query instala : imqsvcadmin install

110

CAPITOLUL 5. MESAJE JAVA IN

serviciul JMS ca serviciu Windows. Dezinstalarea i instalarea are efect odat s a cu repornirea calculatorului. Compilarea i executarea unui program necesit completarea variabilei s a sistem classpath cu ierele s JMS HOME\lib\jms.jar JMS HOME\lib\imq.jar

5.3

Apache ActiveMQ

Instalarea se face dezarhivnd ierul descrcat a s a ntr-un catalog ACTIVEMQ HOME. Acest ier este specic sistemului de operare utilizat, Windows sau Linux. s Lansarea serverului JMS se obtine prin
set JAVA_HOME=. . . set ACTIVEMQ_HOME=. . . %ACTIVEMQ_HOME%\bin\activemq

cazul unui calculator izolat este nevoie de instalarea driver-ului Microsoft In Loopback Adaptor care simuleaz existenta functionrii unei plci de retea a a a active. Distributia apache-activemq-5.*.* contine, ca exemplu, clasa Embedded Broker.java care lanseaz serverul JMS lucru. a n Compilarea unui program necesit prezenta variabila de sistem classpath a n a referintei ctre ierul ACTIVEMQ HOME\activemq-all-*.*.*.jar. Pentru a s executie, variabila de sistem classpath nevoie s contin referintele ctre a a a ierele jar din catalogul ACTIVEMQ HOME\lib. s

5.4

Elemente de programare - JMS

Semnalm dou modaliti de programare / generare / regsire a obiectelor a a at a administrator: Programat: obiectele administrator se instantiaz prin API-ul oferit de a produsul informatic; Prin JNDI. Codul surs al programelor este independent de furnizorul a de servicii de mesagerie. Elementele specice se declar iere de a n s proprieti. at

5.4. ELEMENTE DE PROGRAMARE - JMS

111

5.4.1

Modul programat: Trimiterea unui mesaj

Trimiterea unui mesaj necesit: a 1. Generarea unei fabrici de conexiuni. Fabrica de conexiuni este un obiect administrator. Aceast operatie este specic distributiei JMS. a a cazul de fata folosim obiectele create prin MessageQueue. In Se poate obtine prin ConnectionFactory cf= new com.sun.messaging.ConnectionFactory(); Clasa com.sun.messaging.ConnectionFactory contine metoda setProperty( String name, String value) prin intermediul creia a se precizeaz calculatorul i portul furnizorului de servicii JMS, a s xnd atributele "imqBrokerHostName" i respectiv "imqBrokerHostPort". a s Utiliznd apache-activemq, fabrica de conexiuni se obtine prin a org.apache.activemq.ActiveMQConnectionFactory cf= new org.apache.activemq.ActiveMQConnectionFactory ("tcp://host:61616"); 2. Generarea conexiunii. Se realizeaz prin a Connection conn=cf.createConnection(); Pentru realizarea acestui obiectiv se utilizeaz metoda createConnection, a dup caz, dintr-una din clasele a class ConnectionFactory{ Connection createConnection() throws JMSException; Connection createConnection(String userName,String password) throws JMSException; } class QueueConnectionFactory{ QueueConnection createQueueConnection() throws JMSException; QueueConnection createQueueConnection(String userName, String password) throws JMSException; }

112

CAPITOLUL 5. MESAJE JAVA IN

class TopicConnectionFactory{ TopicConnection createTopicConnection() throws JMSException; TopicConnection createTopicConnection(String userName, String password) throws JMSException; } unde Connection, QueueConnection, TopicConnection sunt interfete din javax.jms. Amintim urmtoarele metode ale unei interfete Connection a interface Connection{ Session createSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } interface QueueConnection{ QueueSession createQueueSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } interface TopicConnection{ TopicSession createTopicSession(boolean transacted, int acknowledgeMode) throws JMSException; void start() throws JMSException; void close() throws JMSException; } Un obiect ce implementeaz interfata Connection asigur legtura cliena a a tului cu furnizorul JMS. Acest obiect este creat de fabrica de conexiuni. Un client JMS trebuie s a nchid conexiunile create. a Metoda start() asigur pornirea sau repornirea conexiunii vederea a n receptionrii mesajelor sosite. a 3. Crearea unei sesiuni de lucru se face cu o metod createSession(). a Session session=conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

5.4. ELEMENTE DE PROGRAMARE - JMS

113

Primul argument asigur (true) sau nu (false) caracterul indivizibil al a unitii de lucru, adic al unei sesiuni. at a Al doilea argument indic modul de conrmare al receptrii mesajului. a a Un obiect de tip Session denete un context format dintr-un singur r s de executie care are loc producerea i consumul de mesaje. n s Sunt denite interface Session{ | MessageProducer createProducer(Destination destination); | MessageConsumer createConsumer(Destination destination); | Message createMessage(); | TextMessage createTextMessage(); | TextMessage createTextMessage(String s); | StreamMessage createStreamMessage(); | MapMessage createMapMessage(); | ObjectMessage createObjectMessage(); | ObjectMessage createObjectMessage(Serializable object); | BytesMessage createBytesMessage(); | } |->interface QueueSession{ | QueueSender createQueueSender(Queue queue); | QueueReceiver createQueueReceiver(Queue queue); | } |->interface TopicSession{ TopicPublisher createPublisher(Topic topic); TopicSubscriber createSubscriber(Topic topic); TopicSubscriber createDurableSubscriber(Topic topic, String name); } 4. Generarea obiectului destinatie. cazul comunicatiilor punctuale obiectul destinatie este de tip Queue, In iar crearea se face prin Destination numeDestinatie=sesssion.createQueue(String numeCoada) iar pentru comunicatii axate pe subiect obiectul destinatie, de tip Topic se instantiaz prin a

114

CAPITOLUL 5. MESAJE JAVA IN

Destination numeDestinatie=sesssion.createTopic(String numeSubiect) Sunt denite arborescentele: interface Destination | |->interface Queue | |->interface Topic class Destination implements Destination | |->class Queue implements Destination, Queue, Serializable | |->class Topic implements Destination, Topic, Serializable Utiliznd Oracle-Open Message Queue obiecte de tip Queue sau Topic a se pot crea i prin s Queue q=new com.sun.messaging.Queue(String numeCoada); Topic t=new com.sun.messaging.Topic(String numeSubiect); 5. Generarea productorului de mesaje. Se realizeaz prin a a MessageProducer producer=session.createProducer(obiectDestinatie); Sunt denite interfetele interface MessageProducer{ void send(Message mesaj); } interface QueueSender{ void send(Message mesaj); } interface TopicPublisher{ void publish(Message mesaj); } 6. Generarea mesajelor. Un mesaj de tip TextMessage se poate crea prin

5.4. ELEMENTE DE PROGRAMARE - JMS

115

TextMessage m=session.createTextMessage(); m.setText(string); 7. Expedierea mesajelor se face cu metoda send(...) a productorului de a mesaje. Exemplul 5.4.1 Clasa urmtoare genereaz ntr-un r de executie, un numr a a a de mesaje de tip TextMessage ntr-o comunicatie punctual. Sfritul expe a a s dierii mesajelor se indic prin generarea unui mesaj de tip Message. Numrul a a mesajelor este indicat de un parametru al constructorului.
1 3 4 5 7 8 9 10 12 13 14 15 16 18 19 20 21 22 23 25 26 27 28 29 30 32 34 36 37 38 39 40 41 42 43

import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i // com . sun . m e s s a g i n g . QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu a i n t e r f e t e i 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e 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 q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ; 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 ( q ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( H e l l o +i ) ; p r o d u c e r . send (m) ; } // indicam s f a r s i t u l t r i m i t e r i i m e s a j e l o r p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close ();

116

CAPITOLUL 5. MESAJE JAVA IN

44 45 46 47 48 49 50 51

conn . 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.4.2

Receptia sincron a unui mesaj a

Primele patru actiuni sunt identice cu cele de la trimiterea unui mesaj, adic a 1. Generarea unei fabrici de conexiuni. 2. Generarea conexiunii. 3. Crearea unei sesiuni de lucru. 4. Generarea obiectului destinatie. 5. Generarea consumatorului de mesaje. Se realizeaz prin a MessageConsumer consumer=session.createConsumer(q); q desemnnd obiectul destinatie. a Sunt denite interfetele interface MessageConsumer{ | Message receive(); | Message receive(long timeout); | Message receiveNoWait(); | } |-> interface QueueReceiver | |-> interface TopicSubscriber 6. Receptia mesajelor se face cu una din metodele consumatorului de mesaje: Message receive() Message receive(long timeout)

5.4. ELEMENTE DE PROGRAMARE - JMS

117

Message receiveNoWait() Exemplul 5.4.2 Receptia de tip sincron a mesajelor ntr-un r de executie este efectuat de clasa urmtoare: a
1 3 4 6 7 8 10 11 12 13 14 15 16 17 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

import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu e s t e a i n t e r f e t e i . // 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e 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 q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ; MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ; conn . s t a r t ( ) ; 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 ; } session . close (); conn . 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.4.3 Trimiterea i receptia mesajelor se face prin aplicatia s

118

CAPITOLUL 5. MESAJE JAVA IN

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.4.3

Receptia asincron a unui mesaj a

Receptia asincron a mesajelor presupune implementarea interfetei a MessageListener ce contine o singur metod a a public void onMessage(Message mesaj); care xeaz prelucrarea mesajului. a Metoda MessageConsumer.setMessageListener(MessageListener obj ) xeaz obiectul ce implementeaz interfata Messagelistener. a a Astfel, caracterul asincron const din faptul c mesajele sunt preluate de a a asculttor - adic obiectul ce implementeaz interfata MessageListener i nu a a a s de clientul JMS. Exemplul 5.4.4 In ideea exemplelor anterioare, un consumator de tip asincron al mesajelor este dat n clasa urmtoare: a
1 2 3 5 6 7 9 10 11 12 13 14 15 16 17

import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ( ) ; // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory // ce i m p l e m e n t e a z a i n t e r f a t a QueueConnectionFactory // dar nu e s t e a i n t e r f e t e i . // c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;

5.4. ELEMENTE DE PROGRAMARE - JMS

119

18 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 6 ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e 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 q==s e s s i o n . c r e a t e Q u e u e ( queueName ) ; MessageConsumer consumer=s e s s i o n . 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 ) ; conn . s t a r t ( ) ; t e x t L i s t e n e r . run ( ) ; conn . 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 cu asculttorul a a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21

import j a v a x . jms . ; 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 { System . out . p r i n t l n (m. g e t T e x t ( ) ) ; } 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 ( ) { while ( ! s f a r s i t ) ; } }

5.4.4

Publicarea mesajelor

Publicarea mesajelor corespunztoare unui subiect se face asemntor cu a a a transmiterea mesajelor comunicatia punctual, dar folosind instante ale n a claselor dedicate acestui tip de comunicatie. Exemplul 5.4.5

120

CAPITOLUL 5. MESAJE JAVA IN

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

import j a v a x . jms . ; 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 ) { 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 { // V a r i a n t a OracleOpen Message Queue 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 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 ( ) ; TopicSession session = 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 t = session . createTopic ( subiect ) ; 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 ) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ; // T o p i c P u b l i s h e r p u b l i s h e r=s e s s i o n . c r e a t e P u b l i s h e r ( t ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( Despre +s u b i e c t+ +i ) ; p r o d u c e r . send (m) ; // p u b l i s h e r . p u b l i s h (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; // p u b l i s h e r . p u b l i s h ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ) ; } }

Varianta comentat este o solutie specic implementrii Oracle-Open Mesa a a sage Queue.

5.4. ELEMENTE DE PROGRAMARE - JMS

121

5.4.5

Subscrierea i receptia mesajelor s

Dac t este obiectul de tip Destination, clientii se aboneaz - subscriu a a unui subiect prin TopicSubscriber consumer=session.createSubscriber((Topic)t); Subscrierea este valabil atta timp ct clientul este activ. Pentru a primi a a a toate mesajele specice subiectului, chiar i cnd clientul este inactiv, acesta s a trebuie s e durabil, adic crearea consumatorului s se fac prin a a a a conn.setClientID("myID"); TopicSubscriber consumer= session.createDurableSubscriber((Topic)t,"nameClient"); ambele cazuri, clientul primete doar mesajele publicate din momentul subIn s scrierii. Exemplul 5.4.6
1 3 4 5 6 8 9 10 11 12 14 15 16 17 18 19 20 22 23 24 25 27 28 29 30 31 32

import j a v a x . jms . ; 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 { // V a r i a n t a OracleOpen Message Queue 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 ) ; // 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 ( t c p : / / l o c a l h o s t : 6 1 6 1 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 t = session . createTopic ( subiect ) ; T o p i c S u b s c r i b e r consumer=

122

CAPITOLUL 5. MESAJE JAVA IN

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

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 , c l i e n t N a m e ) ; conn . s t a r t ( ) ; 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 : + g e t T e x t ( ) ) ; m. } else break ; } session . close (); conn . 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 ( ) ) ; } } }

Apelarea celor dou activiti se face prin a at Exemplul 5.4.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.4.6

Prin JNDI - declararea obiectelor administrator

Obiectele administrator coada sau topic, care retin mesajele corespunztoare a se precizeaz iere de proprieti - jndi.properties. Aceste iere sunt specia n s at s ce produsului de mesagerie folosit (Oracle - Open Message Queue, apache ActiveMQ, qpid, etc.) Varianta Oracle-Open Message Queue
1 2 3

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

5.4. ELEMENTE DE PROGRAMARE - JMS

123

5 7 8 9 11 12 13

# 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

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

s e t PATH : \mq\ b i n ;%PATH =d % 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 ierul de comenzi: s


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

s e t PATH : \mq\ b i n ;%PATH =d % 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

Varianta ActiveMQ
1 2 4 5 7 8 9

j a v a . naming . f a c t o r y . i n i t i a l = o r g . apache . a c t i v e m q . j n d i . A c t i v e M Q I n i t i a l C o n t e x t F a c t o r y # 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 j a v a . naming . p r o v i d e r . u r l = t c p : // l o c a l h o s t : 6 1 6 1 6 # 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

124

CAPITOLUL 5. MESAJE JAVA IN

11 12 13

# 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

Varianta qpid :
1 2 4 5 6 7 9 10 11 13 14

j a v a . naming . f a c t o r y . i n i t i a l = o r g . apache . q p i d . j n d i . P r o p e r t i e s F i l e I n i t i a l C o n t e x t F a c t o r y # r e g i s t e r some c o n n e c t i o n f a c t o r i e s # c o n n e c t i o n f a c t o r y . [ jndiname ] = [ ConnectionURL ] c o n n e c t i o n f a c t o r y . ConnectionFactory = amqp: // g u e s t : g u e s t @ c l i e n t i d / t e s t ? b r o k e r l i s t= t c p : // l o c a l h o s t : 5 6 7 2 # 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 # t o p i c . [ jndiName ] = [ physicalName ] t o p i c . t o p i c = mytopic

Relum aplicatiile anterioare privind transmiterea / receptia unui mesaj a prin comunicatie punctual utiliznd o coad i publicarea i receptionarea a a a s s unui mesaj prin comunicatie bazat pe subiect a ntr-o variant independentent a a de suportul middleware de serviciu de mesagerie folosit. Regsirea resurselor a gestionate de serviciul de mesagerie sa va face utiliznd JNDI. 1 . a

5.4.7

Comunicatia prin coad - queue a

Aplicatia este alctuit din clasele MsgHelloT, MsgSenderT, SyncMsgRe a a ceiverT, AsyncMsgReceiverT, TextListener. Fat de versiunea prezentat se a a modic doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT. a clasa MsgHelloT cmpul queueName reprezint numele JNDI al cozii. In a a Clasa MsgSenderT
1 2 3 4 6 7 8 9 10 12 13 14 15

import import import import

j a v a x . jms . ; j a v a x . naming . ; java . u t i l . Properties ; java . io . ;

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 ; }

Aplicatiile pot executate utiliznd oricare din implementrile JMS, schimbnd doar a a a ierul jndi.properties. s

5.4. ELEMENTE DE PROGRAMARE - JMS

125

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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 62 63 64 65 66 67 68 69 70

public void run ( ) { try { setupJNDI ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e 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 q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; 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 ( q ) ; TextMessage m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( H e l l o +i ) ; p r o d u c e r . send (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ( ) { // S e t t h e p r o p e r t i e s . . . 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 ( JNDIP 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 ( ) ) ; } // C r e a t e t h e i n i t i a l c o n t e x t 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 ( ) ; } 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

import j a v a x . jms . ;

126
import j a v a x . naming . ; import j a v a . u t i l . P r o p e r t i e s ; import j a v a . i o . ;

CAPITOLUL 5. MESAJE JAVA IN

2 3 4 6 7 8 9 11 12 13 15 16 17 18 19 20 21 22 23 24 26 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 50 52

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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y QueueConnectionFactory c f= ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ; C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ; S e s s i o n s e s s i o n=conn . c r e a t e 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 q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ; closeJNDI ( ) ; MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ; conn . s t a r t ( ) ; 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 ; } } session . close (); conn . 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.4.8

Comunicatia pe baz de subiect - topic a

Aplicatia este alctuit din clasele MsgPS, MsgPublisherT, MsgSubscrib a a erT. Fat de versiunea prezentat se modic doar clasele MsgPublisherT, a a a

5.4. ELEMENTE DE PROGRAMARE - JMS

127

MsgSubscriberT. clasa MsgPS cmpul subiect reprezint numele JNDI ataat topic-ului. In a a s Clasa MsgPublisherT
1 2 3 4 6 7 8 9 10 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 45 47 49

import import import import

j a v a x . jms . ; j a v a x . naming . ; java . u t i l . Properties ; java . io . ;

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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y 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 ) ; 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 t =( D e s t i n a t i o n ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; 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 m e s s i o n . c r e a t e T e x t M e s s a g e ( ) ; =s f o r ( i n t i =0; i <n ; i ++){ m. s e t T e x t ( Despre JMS+ +i ) ; p r o d u c e r . send (m) ; } p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ; session . close (); conn . 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 ( ) { . . . } }

Clasa MsgSubscriberT
1 2 3

j a v a x . jms . ; import j a v a x . naming . ; import j a v a . u t i l . P r o p e r t i e s ;

128
import j a v a . i o . ;

CAPITOLUL 5. MESAJE JAVA IN

4 6 7 8 9 10 11 13 14 15 16 17 19 20 21 22 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 54 56 58

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 ( ) ; // l o o k u p t h e c o n n e c t i o n f a c t o r y 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 ) ; 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 =( D e s t i n a t i o n ) c t x . l o o k u p (TOPIC JNDI NAME ) ; closeJNDI ( ) ; // 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 , c l i e n t N a m e ) ; 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 ) t ) ; conn . s t a r t ( ) ; 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 : + g e t T e x t ( ) ) ; m. } else break ; } session . close (); conn . 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.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

129

5.5

Mesaje SOAP prin Java Message Service

Rezultatele acestei sectiuni sunt valabile doar cazul pachetului Oracle n Open Message Queue.

5.5.1

SOAP

SOAP - Simple Object Access Protocol - este un protocol de comunicatii prezent SOAP este protocolul standard pentru servicii Web ntre aplicatii. In prin Internet. SOAP este independent de platforma de calcul i de limbajul s de programare. SOAP se bazeaz pe XML (eXtensible Markup Language) i este un stana s dard W3C (World Wide Web Consortium).

5.5.2

Mesaje SOAP

Un mesaj SOAP este un document XML constnd din a o nvelitoare (envelope) care poate contine un numr arbitrar de antete (header ); a un corp (body); un numr variabil de obiecte ataate (attachments) MIME (Multipurpose a s Internet Mail Exchange). Astfel un mesaj SOAP apare sub forma documentului XML <?xml version="1.0" encoding="UTF-8"?> <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> <Header/> <Body> <Fault/> </Body> </Envelope> Facilitile Java de manipulare a mesajelor SOAP sunt continute paat n chetul javax.xml.soap, din distributia jdk. acest sectiune vom crea mesaje SOAP, le transformm mesaje JMS In a a n pe care le trimitem furnizorului JMS, de unde un client le receptioneaz, dup a a care transform mesajul JMS mesaj SOAP i regsete datele expediate. a n s a s Solutia este specic implementrii Oracle-Open Message Queue. a a

130 Crearea unui mesaj SOAP

CAPITOLUL 5. MESAJE JAVA IN

MessageFactory mf=MessageFactory.newInstance(); SOAPMessage soapMsg=mf.createMessage(); Mesajul creat are denit structura de baz a mesajului SOAP: invelia a toarea, un antet i corp. Aceste elemente pot accesate prin s SOAPPart part=soapMsg.getSOAPPart(); SOAPEnvelope envelope=part.getEnvelope(); SOAPHeader header=envelope.getHeader(); SOAPBody body=envelope.getBody(); Completarea corpului unui mesaj SOAP Generm numele elementului, e1 cazul exemplului, a n Name n1=envelope.createName("e1"); body un element se poate include, pe baza numelui creat prin In SOAPElement e1=body.addBodyElement(n1); general, un element se include elementul printe, care pote chiar i In n a s body, prin metoda clasei SOAPElement SOAPElement addChildElement(Name name) Completm elementul e1 cu un text: primul, prin a e1.addTextNode("primul"); Exemplul 5.5.1 Mesajul SOAP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

<SOAPENV:Envelope xmlns:SOAPENV= h t t p : // schemas . x m l s o a p . o r g / s o a p / e n v e l o p e / > <SOAPENV:Header /> <SOAPENV:Body> <e1> primul <e11> al treilea </ e11> </ e1> <e2> al doilea </ e2> </SOAPENV:Body> </SOAPENV:Envelope>

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

131

se obtine cu programul
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

import j a v a x . xml . soap . ; import j a v a . i o . ; public c l a s s MsgSOAP{ public s t a t i c void main ( S t r i n g [ ] a r g s ) { Name name=n u l l ; try { Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ; SOAPPart p a r t=soapMsg . getSOAPPart ( ) ; SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; SOAPBody body=e n v e l o p e . getBody ( ) ; Name n1=e n v e l o p e . createName ( e1 ) ; SOAPElement e1=body . addBodyElement ( n1 ) ; e1 . addTextNode ( p r i m u l ) ; Name n2=e n v e l o p e . createName ( e2 ) ; SOAPElement e2=body . addBodyElement ( n2 ) ; e2 . addTextNode ( a l d o i l e a ) ; Name n11 =e n v e l o p e . createName ( e11 ) ; SOAPElement e11=e1 . addChildElement ( n11 ) ; e11 . addTextNode ( a l t r e i l e a ) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; } 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 ( ) ) ; } } }

Un mesaj SOAP se poate salva ntr-un ier text cu s FileOutputStream f=new FileOutputStream(. . .); soapMsg.writeTo(f); Transformarea unui mesaj SOAP mesaj JMS n SOAPMessage soapMsg=. . . Message msg= MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session); Transformarea unui mesaj JMS mesaj SOAP n MessageFactory mf=. . . Message msg=. . . SOAPMessage soapMsg = MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);

132

CAPITOLUL 5. MESAJE JAVA IN

Preluarea elementelor din corpul unui mesaj SOAP SOAPBody body=. . . SOAPBodyElement element=null; Iterator iterator=body.getChildElements(); while(iterator.hasNext()){ element=(SOAPBodyElement)iterator.next(); String name=element.getElementName(); if(name.getLocalName().equals("numeCamp")){ String s=element.getValue(); . . . } } Exemplul 5.5.2 Un client introduce ntr-un mesaj SOAP dou numere ntregi, a transmite mesajul altui program care calculeaz cel mai mare divizor comun al a celor dou numere i transmite clientului rezultatul tot sub forma unui mesaj a s SOAP. Activitatea clientului este se compune din Transmiterea ctre server a cererii. Mesajul este alctuit din cele dou a a a numere i un topic, indicativ dup care se va gsi rspunsul. s a a a
1 2 3 4 6 8 9 10 12 13 14 15 16 17 18 19 20 21 22 24 25 26

import import import import

j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . u t i l . ; MsgSOAPClientSender {

public c l a s s

long a , b ; String topicResult ; S t r i n g c l i e n t I D , clientName ; MsgSOAPClientSender ( 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 . 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 : ) ; a=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 n : ) ; b=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 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 ( ) { Me ss ag eFa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ;

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

133

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 73 74 75 76 77 78 79 80 81 82

SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPElement elem=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 ) ; TopicSession session = 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 ) ; 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 ( tDate ) ; mf=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ; soapMsg=mf . c r e a t e M e s s a g e ( ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; name=e n v e l o p e . createName ( n1 ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( a ) ) . t o S t r i n g ( ) ) ; name=e n v e l o p e . createName ( n2 ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( b ) ) . t o S t r i n g ( ) ) ; name=e n v e l o p e . createName ( t o p i c ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( t o p i c R e s u l t ) ; 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 R e s u l t ) ; 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 ) ; Message m = M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; p r o d u c e r . send (m) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; conn . 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 ( ) ) ; } System . out . p r i n t l n ( Sen de 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 ) { 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 MsgSOAPClientSender c l i e n t I D c l i e n t N a m e ) ; System . e x i t ( 0 ) ; } MsgSOAPClientSender c l i e n t=new MsgSOAPClientSender ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }

Receptionarea rspunsului. a

134

CAPITOLUL 5. MESAJE JAVA IN

1 2 3 4 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

import import import import

j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . u t i l . ; MsgSOAPClientReceiver {

public c l a s s

String topicResult ; S t r i n g c l i e n t I D , clientName ; MsgSOAPClientReceiver ( 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 . 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 ( ) { Me ss ag eFa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ; SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPBodyElement e l e m e n t=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 R e s u l t ) ; 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 ) ; mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; conn . s t a r t ( ) ; Message msg=consumer . r e c e i v e ( ) ; soapMsg=Me s sa ge T ra n sf o rm er . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( C l i e n t Mesaj SOAP r e c e p t i o n a t ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ; S t r i n g s= ; while ( i t e r a t o r . hasNext ( ) ) { e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ; name=e l e m e n t . getElementName ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( cmmdc ) ) s=e l e m e n t . g e t V a l u e ( ) ; } System . out . p r i n t l n ( Cmmdc : +s ) ; conn . c l o s e ( ) ; } catch ( E x c e p t i o n e ) {

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

135

59 60 61 62 64 65 66 67 68 69 70 71 72 73

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 ( R e c e i 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 ) { 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 ) ; } MsgSOAPClientReceiver c l i e n t=new MsgSOAPClientReceiver ( a r g s [ 0 ] , a r g s [ 1 ] ) ; client . service (); } }

Programul server este


1 2 3 4 6 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 36 37 38 39 40

import import import import

j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . u t i l . I t e r a t o r ; MsgSOAPCmmdcServer{

public c l a s s

long cmmdc( long m, long n ) { . . . } public void s e r v i c e ( ) { Me ss age Fa ct ory mf=n u l l ; SOAPMessage soapMsg=n u l l ; SOAPPart p a r t=n u l l ; SOAPEnvelope e n v e l o p e=n u l l ; SOAPBody body=n u l l ; SOAPBodyElement e l e m e n t=n u l l ; SOAPElement elem=n u l l ; Name name=n u l l ; 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 , a t l a n t i s ) ; // 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 ( ) ; Message msg=n u l l ; mf=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ; while ( true ) { msg=consumer . r e c e i v e ( ) ; soapMsg=Me s sa ge T ra n sf o rm er . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( S e r v e r Mesaj SOAP r e c e p t i o n a t ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ; S t r i n g sn1= , sn2= , t o p i c R e s u l t= ;

136

CAPITOLUL 5. MESAJE JAVA IN

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 72 73 75 76 77 78 79

while ( i t e r a t o r . hasNext ( ) ) { e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ; name=e l e m e n t . getElementName ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( n1 ) ) sn1=e l e m e n t . g e t V a l u e ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( n2 ) ) sn2=e l e m e n t . g e t V a l u e ( ) ; i f ( name . getLocalName ( ) . e q u a l s ( t o p i c ) ) t o p i c R e s u l t=e l e m e n t . g e t V a l u e ( ) ; } System . out . p r i n t l n ( sn1+ : +sn2+ : +t o p i c R e s u l t ) ; long a=Long . par se Lon g ( sn1 ) ; long b=Long . pa rs eL ong ( sn2 ) ; long c=cmmdc( a , b ) ; soapMsg=mf . c r e a t e M e s s a g e ( ) ; p a r t=soapMsg . getSOAPPart ( ) ; e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; body=e n v e l o p e . getBody ( ) ; name=e n v e l o p e . createName ( cmmdc ) ; elem=body . addChildElement ( name ) ; elem . addTextNode ( (new Long ( c ) ) . t o S t r i n g ( ) ) ; Message m = M es s ag e Tr an s fo rm e r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; 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 R e s u l t ) ; 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 ) ; p r o d u c e r . send (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 ( ) ) ; } 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 ) { MsgSOAPCmmdcServer s e r v e r=new MsgSOAPCmmdcServer ( ) ; server . service (); } }

Mesajul SOAP utilizat de client, pentru n1 = 45, n2 = 35 i topic = nume s este <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header/> <soap-env:Body> <n1>45</n1> <n2>35</n2> <topic>nume</topic> </soap-env:Body> </soap-env:Envelope>

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

137

5.5.3

Ataamente SOAP s

Crearea ataamentelor s 1. Crearea mesajului SOAP MessageFactory mf=MessageFactory.newInstance(); SOAPMessage soapMsg=mf.createMessage(); 2. Ataament text s (a) Crearea unui obiect de tip AttachmentPart AttachmentPart attachment=soapMsg.createAttachmentPart(); (b) Completarea continutului String stringContent=. . . attachment.setContent(stringContent, "text/plain"); Continutului i se poate ataa un cod de identicare s attachment.setContentId("Text1"); Ataament imagine jpeg/png s (a) Crearea unui obiect de tip AttachmentPart cu arcarea imagnc inii. URL url=new URL("file://localhost/c:\\. . .\\***.jpg"); DataHandler dataHandler = new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); attachment.setContentId("Imagine1"); Ataament cu sunet format mp3. s n (a) Crearea unui obiect de tip AttachmentPart cu arcarea ierului nc s mp3. URL url=new URL("file://localhost/c:\\. . .\\***.mp3"); DataHandler dataHandler=new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); attachment.setContentId("attached_mp3"); Ataament video. s (a) Fiierele video au de obicei dimensiuni mari. Pentru a putea s include asemenea iere trebuie mrit dimensiunea maxim a s a a a unui ataament prin includerea setrii s a imq.autocreate.destination.maxBytesPerMsg=35M ierul mq\lib\props\broker\install.properties. n s

138

CAPITOLUL 5. MESAJE JAVA IN

(b) Crearea unui obiect de tip AttachmentPart cu arcarea ierului nc s cu continut video. String video_location="c:\\. . .; URL url=new URL("file://"+video_location); dataHandler= new DataHandler(url); AttachmentPart attachment = soapMsg.createAttachmentPart(dataHandler); (c) Pentru redarea continutului video vom avem nevoie de tipul continutului video, informatie dat de extensia ierului video. a s Aceat dat este furnizat prin metoda setContentId. a a a File videoFile = new File(video_location); String fileName = videoFile.getName(); int index=fileName.lastIndexOf("."); String ext=fileName.substring(index+1); attachment.setContentId("attached_video"+ext); 3. Includerea ataamentului mesajul SOAP s n soapMsg.addAttachmentPart(attachment); Extragerea ataamentelor s Tipul unui ataament se poate deduce din rezultatul metodei getContentId s sau getContentType a clasei AttachmentPart. Iterator iterator = soapMsg.getAttachments(); while (iterator.hasNext()) { AttachmentPart attached = (AttachmentPart)iterator.next(); // Codul de identificare String id = attached.getContentId(); // Tipul atasamentului String type = attached.getContentType(); // Preluarea unui string if (type.equals("text/plain")) { Object content = attached.getContent(); . . . }

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

139

// Preluarea unei imagini if (type.equals("image/jpeg")){ Image image=(Image)attached.getContent(); . . . } // Preluarea unei inregistrari mp3 if(type.equals("audio/x-wav")){ System.out.println("Play MP3"); MP3Player mp3Player=new MP3Player(attached.getRawContent()); mp3Player.play(); } // Preluarea continutului video if(id.startsWith("attached_video")){ String videoFileName = "videoFile."+id.substring(14); // Salvarea continutului video intr-un fisier local InputStream inputStream = attached.getRawContent(); File f=new File(videoFileName); OutputStream out=new FileOutputStream(f); byte buf[]=new byte[1024]; int len; while((len=inputStream.read(buf))>0) out.write(buf,0,len); out.close(); // Redarea continutului video utilizand FMJ String[]arguments = new String[1]; arguments[0]=URLUtils.createUrlStr(f); System.out.println("Video show"); FmjStudio.main(arguments); }

Valoarea rezultat din metoda getContentType cazul unui ataament video a n s difer de tipul acesteia. Astfel pentru tipul avi valoarea retunat este application/x-troff-msvideo a a iar pentru wmv se obtine content/unknown. Redarea continutului video se face utiliznd produsul Freedom for Media in Java - FMJ. a Exemplul 5.5.3 Crearea unui mesaj SOAP cu ataamente text, imagine, muzic s a mp3 i video. Textul, imaginea, muzica mp3 i continutul video sunt continute s s iere. Cile ctre aceste iere se vor da ca proprieti. n s a a s at

140

CAPITOLUL 5. MESAJE JAVA IN

1 2 3 4 5 6 8 10 11 12 13 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 31 33 34 35 36 37 38 39 40 42 44 46 47 49 50 51 52 53 54 55 57 58

import import import import import import

j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . io . ; j a v a x . a c t i v a t i o n . DataHandler ; j a v a . n e t .URL; MsgSOAPPublisher extends Thread {

public c l a s s

String f i l e l o c a t i o n , image location , mp3 location , v i d e o l o c a t i o n ; MsgSOAPPublisher ( S t r i n g f i l e l o c a t i o n , S t r i n g i m a g e l o c a t i o n , String mp3 location , String v i d e o l o c a t i o n ){ this . f i l e l o c a t i o n=f i l e l o c a t i o n ; t h i s . i m a g e l o c a t i o n=i m a g e l o c a t i o n ; t h i s . m p 3 l o c a t i o n=m p 3 l o c a t i o n ; t h i s . v i d e o l o c a t i o n=v i d e o l o c a t i o n ; } 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 , a t l a n t i s ) ; // 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) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( Date ) ; // T o p i c P u b l i s h e r p u b l i s h e r=s e s s i o n . c r e a t e P u b l i s h e r ( t ) ; 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 ( Date ) ; 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 ) ; Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ; SOAPPart p a r t=soapMsg . getSOAPPart ( ) ; SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ; SOAPBody body=e n v e l o p e . getBody ( ) ; Name bodyName=e n v e l o p e . createName ( v e r i f ) ; SOAPElement e l e m e n t=body . addBodyElement ( bodyName ) ; e l e m e n t . addTextNode ( MyAttachment ) ; // Crearea a t a s a m e n t u l u i de t i p t e x t AttachmentPart attachment1=soapMsg . c r e a t e A t t a c h m e n t P a r t ( ) ; F i l e R e a d e r f r = new F i l e R e a d e r (new F i l e ( f i l e l o c a t i o 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 ( f r ) ; S t r i n g stringContent = ; S t r i n g l i n e = br . r e a d L i n e ( ) ; while ( l i n e != n u l l ) { stringContent = stringContent . concat ( l i n e ) ; s t r i n g C o n t e n t = s t r i n g C o n t e n t . c o n c a t ( \n ) ; l i n e = br . r e a d L i n e ( ) ; } attachment1 . s e t C o n t e n t ( s t r i n g C o n t e n t , t e x t / p l a i n ) ; attachment1 . s e t C o n t e n t I d ( a t t a c h e d t e x t ) ;

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

141

59 61 62 63 64 65 67 68 70 71 72 73 74 76 77 79 80 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99 100 101 102 103 104

soapMsg . addAttachmentPart ( attachment1 ) ; // Crearea a t a s a m e n t u l u i de t i p imagine URL u r l = new URL( f i l e : / / +i m a g e l o c a t i o n ) ; DataHandler d a t a H a n d l e r = new DataHandler ( u r l ) ; AttachmentPart attachment2 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; attachment2 . s e t C o n t e n t I d ( a t t a c h e d i m a g e ) ; soapMsg . addAttachmentPart ( attachment2 ) ; // Crearea unui atasament de t i p mp3 u r l=new URL( f i l e : / / +m p 3 l o c a t i o n ) ; d a t a H a n d l e r= new DataHandler ( u r l ) ; AttachmentPart attachment3 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; attachment3 . s e t C o n t e n t I d ( attached mp3 ) ; soapMsg . addAttachmentPart ( attachment3 ) ; // Crearea unui atasament v i d e o u r l=new URL( f i l e : / / +v i d e o l o c a t i o n ) ; d a t a H a n d l e r= new DataHandler ( u r l ) ; AttachmentPart attachment4 = soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ; F i l e v i d e o F i l e = new F i l e ( v i d e o l o c a t i o n ) ; S t r i n g f i l e N a m e = v i d e o F i l e . getName ( ) ; i n t i n d e x=f i l e N a m e . l a s t I n d e x O f ( . ) ; S t r i n g e x t=f i l e N a m e . s u b s t r i n g ( i n d e x +1); attachment4 . s e t C o n t e n t I d ( a t t a c h e d v i d e o +e x t ) ; soapMsg . addAttachmentPart ( attachment4 ) ; Message m = M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ; // p u b l i s h e r . p u b l i s h (m) ; p r o d u c e r . send (m) ; F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( MySOAPMessage . xml ) ; soapMsg . w r i t e T o ( f ) ; conn . 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 ( ) ) ; } System . out . p r i n t l n ( P u b l i s h e r f i n i s e d ) ; } }

Exemplul 5.5.4 Consumarea unui mesaj SOAP cu ataamente s


1 2 3 4 5 6 7 8

import import import import import import import import

j a v a x . jms . ; j a v a x . xml . soap . ; com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ; java . u t i l . I t e r a t o r ; java . io . ; j a v a . awt . ; n e t . s f . fmj . u t i l i t y . URLUtils ; n e t . s f . fmj . u i . FmjStudio ;

142

CAPITOLUL 5. MESAJE JAVA IN

10 12 13 14 15 16 17 18 19 20 21 22 23 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

public c l a s s

MsgSOAPSubscriber extends Thread {

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 , a t l a n t i s ) ; // 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) ; // Topic t=new com . sun . m e s s a g i n g . Topic ( Date ) ; 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 ( Date ) ; 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 ) t ) ; conn . s t a r t ( ) ; Message msg=n u l l ; Me ss ag eFa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ; while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) { SOAPMessage soapMsg = M es s ag e Tr an s fo rm e r . SOAPMessageFromJMSMessage ( msg , mf ) ; System . out . p r i n t l n ( Mesaj SOAP r e c e p t i o n a t ) ; // E x t r a g e r e a a t a s a m e n t e l o r I t e r a t o r i t e r a t o r = soapMsg . g e t A t t a c h m e n t s ( ) ; while ( i t e r a t o r . hasNext ( ) ) { AttachmentPart a t t a c h e d =(AttachmentPart ) i t e r a t o r . n e x t ( ) ; String id = attached . getContentId ( ) ; S t r i n g t y p e = a t t a c h e d . getContentType ( ) ; System . out . p r i n t l n ( Attachment + i d + has c o n t e n t t y p e + t y p e ) ; i f ( type . e q u a l s ( t e x t / p l a i n ) ) { S t r i n g content = ( S t r i n g ) attached . getContent ( ) ; System . out . p r i n t l n ( Attachment c o n t a i n s : \ n + c o n t e n t ) ; } i f ( t y p e . e q u a l s ( image / j p e g ) ) { Image image=(Image ) a t t a c h e d . g e t C o n t e n t ( ) ; ShowImage s=new ShowImage ( image ) ; s . show ( ) ; } i f ( t y p e . e q u a l s ( a u d i o /xwav ) ) { System . out . p r i n t l n ( Play MP3 ) ; MP3Player mp3Player=new MP3Player ( a t t a c h e d . getRawContent ( ) ) ; mp3Player . s t a r t ( ) ; } i f ( id . startsWith ( attached video )){ S t r i n g vi d e o Fi l e N a m e = v i d e o F i l e . +i d . s u b s t r i n g ( 1 4 ) ; InputStream i n p u t S t r e a m = a t t a c h e d . getRawContent ( ) ; F i l e f=new F i l e ( v i de o F i l eN a m e ) ; OutputStream out=new F i l e O u t p u t S t r e a m ( f ) ; byte b u f [ ] =new byte [ 1 0 2 4 ] ; int l e n ; while ( ( l e n=i n p u t S t r e a m . r e a d ( b u f )) >0) out . w r i t e ( buf , 0 , l e n ) ; out . c l o s e ( ) ; S t r i n g [ ] arguments = new S t r i n g [ 1 ] ; arguments [ 0 ] = URLUtils . c r e a t e U r l S t r ( f ) ; System . out . p r i n t l n ( P r e s s Enter t o c o n t i n u e ! ) ; System . i n . r e a d ( ) ; System . out . p r i n t l n ( Video show ) ;

5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE

143

68 69 70 71 72 73 74 75 76 77 78 79

FmjStudio . main ( arguments ) ; } } } conn . 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 ( ) ) ; } 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 re de executie se face prin a


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

import j a v a . u t i l . ; c l a s s MsgAttach { 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 f i l e l o c a t i o n =System . g e t P r o p e r t y ( f i l e l o c a t i o n ) ; S t r i n g i m a g e l o c a t i o n=System . g e t P r o p e r t y ( i m a g e l o c a t i o n ) ; S t r i n g m p 3 l o c a t i o n=System . g e t P r o p e r t y ( m p 3 l o c a t i o n ) ; S t r i n g v i d e o l o c a t i o n=System . g e t P r o p e r t y ( v i d e o l o c a t i o n ) ; MsgSOAPPublisher p u b l i s h e r=new MsgSOAPPublisher ( f i l e l o c a t i o n , image location , mp3 location , v i d e o l o c a t i o n ) ; MsgSOAPSubscriber s u b s c r i b e r=new MsgSOAPSubscriber ( ) ; publisher . start ( ) ; subscriber . start (); } }

Utilizarea aplicatiei se face prin ant pe structura initial de cataloage i iere a s s


app |--> | |--> | | | | | | | resources | resursele text, imagine, mp3, video src | MsgAttach.java | MsgSOAPPublisher.java | MsgSOAPSubscriber.java | MP3Player.java | ShowImage.java logging.properties (din FMJ) build.xml

i cu ierul build.xml s s
1 2 3 4 5 7 8 9 10 11 12 13

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <p r o j e c t default= run b a s e d i r= . > <p r o p e r t y name=mq . home v a l u e= d : /mq /> <p r o p e r t y name= r e s o u r c e s . home l o c a t i o n= ${ b a s e d i r }/ r e s o u r c e s /> <p r o p e r t y name= fmj . home l o c a t i o n= d : /JavaApp/ fmj /> <path i d= c l a s s p a t h > <p a t h e l e m e n t path= b u i l d / c l a s s e s /> <p a t h e l e m e n t path= ${ fmj . home}/ fmj . j a r /> < f i l e s e t d i r= ${mq . home}/ l i b > <i n c l u d e name= . j a r /> </ f < i l e s e t> < f i l e s e t d i r= ${ fmj . home}/ l i b >

144
<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 > <mkdir d i r= b u i l d /> <mkdir d i r= b u i l d / c l a s s e s /> </ 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 s r c d i r= s r c c l a s s p a t h r e f= c l a s s p a t h d e s t d i r= b u i l d / c l a s s e s debug= y e s /> </ t a r g e t>

CAPITOLUL 5. MESAJE JAVA IN

14 15 16 18 19 20 21 23 24 25 26 28 29 30 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48

<t a r g e t name= s e r v e r > <e x e c e x e c u t a b l e= ${mq . home}/ b i n / imqbrokerd . e x e d i r= ${mq . home}/ b i n /> </ t a r g e t> <t a r g e t name= run depends= c o m p i l e > <j a v a c l a s s n a m e= MsgAttach c l a s s p a t h r e f= c l a s s p a t h f o r k= y e s f a i l o n e r r o r= y e s > <s y s p r o p e r t y key= f i l e l o c a t i o n v a l u e= ${ r e s o u r c e s . home}/ c a p i t o l . t x t /> <s y s p r o p e r t y key= i m a g e l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ xmlp i c . j p g /> <s y s p r o p e r t y key= m p 3 l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ Tomjones . mp3 /> <s y s p r o p e r t y key= v i d e o l o c a t i o n v a l u e= l o c a l h o s t /${ r e s o u r c e s . home}/ c l o c k . a v i /> <s y s p r o p e r t y key= j a v a . l i b r a r y . path v a l u e= ${ fmj . home}/ n a t i v e / win32x86 /> </ j a v a> </ t a r g e t> </ p r o j e c t>

Programul de aare a imaginii s


1 2 3 4 5 6 8 9 11 12 13 15 16 17 18 20

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

j a v a . awt . ; j a v a . awt . image . ; j a v a x . swing . ; java . io . ; j a v a x . i m a g e i o . ImageIO ; java . net . ;

c l a s s MyCanvas e x t e n d s Canvas { Image image=n u l l ; MyCanvas ( Image image ) { t h i s . image=image ; } p u b l i c void paint ( Graphics g ){ g . drawImage ( image , 0 , 0 , t h i s ) ; } } p u b l i c c l a s s ShowImage{

5.6.

APACHE-QPID

145

21 23 24 25 27 28 29 30 31 32 33 34 35 36 37

MyCanvas mc=n u l l ; ShowImage ( Image image ) { mc=new MyCanvas ( image ) ; } p u b l i c v o i d show ( ) { // I n t e r f a t a swing JFrame j f r a m e = new JFrame ( The r e c e i v e d image ) ; jframe . addNotify ( ) ; j f r a m e . getContentPane ( ) . s e t L a y o u t ( new BorderLayout ( ) ) ; j f r a m e . getContentPane ( ) . add (mc , BorderLayout .CENTER) ; j f r a m e . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; jframe . s e t S i z e (200 ,200); jframe . s e t V i s i b l e ( true ) ; } }

Programul pentru redarea continutului unui ier mp3 necesit prezenta s a resursei jl1.0.jar din pachetul JLayer1.0, descrcabil din internet. Un program a de redare este
1 2 4 5 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27

im po rt j a v a . i o . ; im po rt javazoom . j l . p l a y e r . P l a y e r ; p u b l i c c l a s s MP3Player e x t e n d s Thread { private Player player ; p u b l i c MP3Player ( InputStream i s ) { try { B u f f e r e d I n p u t S t r e a m b i s=new B u f f e r e d I n p u t S t r e a m ( i s ) ; p l a y e r=new P l a y e r ( b i s ) ; } catch ( Exception 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 ( 1 ) ; } } p u b l i c v o i d run ( ) { try { player . play ( ) ; } catch ( Exception e ){ System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ; } i f ( p l a y e r != n u l l ) p l a y e r . c l o s e ( ) ; } }

5.6

Apache-qpid

apache-qpid reprezint o implementare a protocolului AMQP care poate a folosit de clienti Java, C++, C#, Pyton, Ruby. Programele dezvoltate uti-

146

CAPITOLUL 5. MESAJE JAVA IN

liznd Oracle-Open Message Queue sau apache-ActiveMQ prin JNDI ruleaz a a fr modicri. aa a Instalarea serviciului de mesagerie revine la 1. Dezarhivarea ierului descrcat; s a 2. Generarea unei semnturi. a Catalogul QPID HOME\bin contine ierul create-example-ssl-stores.bat, s care se adapteaz corespunztor iar semntura generat se depune cata a a a n alogul QPID HOME\etc. O adaptare a ierului create-example-ssl-stores.bat este dat urmtorul s a n a exemplu.
1 2 3 4 5 6 8 9 10 11 13 14 15 17 18 19 21 22

@REM @REM @REM @REM @REM @REM

C r e a t e example k e y s t o r e f o r b r o k e r and t r u s t s t o r e f o r c l i e n t /management c o n s o l e . Use g e n e r a t e d q p i d . k e y s t o r e a s t h e b r o k e r s k e y s t o r e Use g e n e r a t e d q p i d . t r u s t s t o r e a s c l i e n t / c o n s o l e s t r u s t s t o r e A l l p a s s w o r d s have v a l u e : password

@REM C r e a t e Broker K e y s t o r e : k e y t o o l genkey a l i a s q p i d B r o k e r k e y a l g RSA v a l i d i t y 365 k e y s t o r e q p i d . k e y s t o r e s t o r e p a s s password k e y p a s s password dname CN=unitbv , OU =cs , O=Org , L=Bv , C=R @REM Export S e l f S i g n e d C e r t : k e y t o o l e x p o r t a l i a s q p i d B r o k e r k e y s t o r e q p i d . k e y s t o r e f i l e q p i d B r o k e r . c e r s t o r e p a s s password @REM Import Broker Cert I n t o MC T r u s t S t o r e : k e y t o o l im po rt a l i a s q p i d B r o k e r C e r t f i l e q p i d B r o k e r . c e r k e y s t o r e q p i d . t r u s t s t o r e s t o r e p a s s password noprompt @REM D e l e t e t h e c e r t del qpidBroker . cer

Lansnd executie acest ier de comenzi se creaz semntura dat de ierul a n s a a a s qpid.keystore. Eventual trebuie xat locatia ierului qpid.keystore elementul keyStorePath a s n din ierul QPID HOME\etc\config.xml. s Serviciul de mesagerie se lanseaz prin a
1 2 3 4

s e t JAVA HOME=. . . s e t QPID HOME=. . . s e t QPID WORK=. . . %QPID HOME%\b i n \ qpids e r v e r . bat

Catalogul QPID WORK este utilizat de serviciul de mesagerie pentru consemnarea (logging) evenimentelor, catalog ind prezent un ier de congn s urare log4j.xml.

5.7. PROTOCOLUL AMQP

147

5.7

Protocolul AMQP

Punem evidenta un alt model de aplicatie, specic protocolului AMQP. n Modelul prevede existenta a trei entiti: at exchange Dispecer de directionare ce primete mesaje de la un pro s ductor de mesaje i le distribuie unor cozi pe baza unui criteriu; a s message queue coad care se pstreaz mesaje pn ce acestea sunt a n a a a a consumate de o aplicatie client. Proprietile unei cozi sunt: at numele, alctuit din litere, cifre, caracterul de subliniere, cel mult a 255 de caractere. persistenta mesajului cazul n ncetrii functionrii serverului (durable a a message queue, temporary message queue). modul de tergere a mesajelor dup consumarea acestora (autos a delete). binding criteriul dup care un mesaj este distribuit de dispecerul de a directionare unei cozi. O coad comunic dispecerului de directionare o cheie denumit cheie de a a a legare (binding key) K, timp ce orice mesaj va contine o cheie de rutare n (routing key) R. AMPQ denete trei criterii de distribuire a mesajelor de ctre dispecerul s a de directionare: distribuirea direct realizeaz o distribuire 1:1 a mesajelor: a a 1. o coad se leag de dispecerul de directionare cu cheia de legare K; a a 2. un mesaj contine cheia de rutare R; 3. dispecerul de directionare trimite mesajul ctre toate cozile care a satisfac conditia R = K. distribuirea fanout realizeaz o distribuire 1:N a mesajelor: a 1. o coad se leag de dispecerul de directionare fr cheie de legare; a a aa 2. un mesaj nu contine cheie de rutare (eventual cheia de rutare este neglijat); a

148

CAPITOLUL 5. MESAJE JAVA IN

3. dispecerul de directionare trimite neconditional mesajul ctre toate a cozile nregistrate. distribuirea publicare-abonare 1. o coad se leag de dispecerul de directionare cu cheia de legare K; a a 2. un mesaj contine cheia de rutare R; 3. dispecerul de directionare trimite mesajul ctre toate cozile a cror a a cheie de legare se potrivete cu cheia de rutare. s Cheia de legare este alctuit din mai multe cuvinte (token) sepaa a rate de caracterul . (punct). Cheia de rutare poate contine carac terele # - va presupune potrivirea cu un cuvnt sau nu. a * - va presupune potrivirea cu cel putin un cuvnt. a Astfel *.abc se potrivete cu x.abc dar nu se potrivete cu abc, s s n timp ce #.abc se potrivete cu x.abc i abc. s s Corespunztor celor trei criterii de distribuire a mesajelor, serverul AMQP a contine dispecerii de directionare amq.direct amq.fanout amq.topic Un mesaj este expediat de client ctre un dispecer de directionare aat pe a un server AMQP. Preluarea unui mesaj dintr-o coad de ctre un client are ca a a urmare tergerea mesajului coad. s n a Resursele necesare apartin pachetului org.apache.qpid.transport.

5.7.1

Crearea unei cozi

Crearea unei cozi const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii

5.7. PROTOCOLUL AMQP

149

Session session = con.createSession(0); 3. Declararea cozii session.queueDeclare(numeCoada, null, null); session.exchangeBind(numeCoada, dispecerulDeDirectionare, binding_key, null); 4. Ateptarea conrmrii actiunii de realizare a cozii s a session.sync(); 5. Inchiderea sesiunii i a conexiunii s session.close(); con.close(); Exemplul 5.7.1 Crearea unei cozi care s primeasc mesaje prin distribuire a a direct i fanout. as
1 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 20 21 23 24 25 27 28

import o r g . apache . q p i d . t r a n s p o r t . ; public c l a s s DeclareQueue { 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 <5){ System . out . p r i n t l n ( Usage j a v a DeclareQueue b r o k e r + p o r t queueName exchange bindingKey ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t 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 t r i n g queueName=a r g s [ 2 ] ; S t r i n g exchange=a r g s [ 3 ] ; S t r i n g bindingKey=a r g s [ 4 ] ; // Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // D e c l a r a r e a c o z i i s e s s i o n . q u e u e D e c l a r e ( queueName , null , n u l l ) ; s e s s i o n . exchangeBind ( queueName , exchange , bindingKey , n u l l ) ; // Confirmarea c r e e r i i c o z i i s e s s i o n . sync ( ) ;

150

CAPITOLUL 5. MESAJE JAVA IN

30 31 32 33 34

// I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i session . close (); con . c l o s e ( ) ; } }

5.7.2

Expedierea / publicarea unui mesaj

Expedierea / publicarea unui mesaj const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii Session session = con.createSession(0); 3. Precizarea (dac este nevoie) a cheii de rutare a DeliveryProperties deliveryProps = new DeliveryProperties(); deliveryProps.setRoutingKey(routing_key); 4. Crearea i expedierea mesajului s session.messageTransfer(dispecerulDeDirectionare, MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, new Header(deliveryProps), mesaj_text); 5. Ateptarea conrmrii receptiei mesajului dectre serverul AMQP s a a session.sync(); 6. Inchiderea sesiunii i a conexiunii s session.close(); con.close();

5.7. PROTOCOLUL AMQP

151

Exemplul 5.7.2 Expedierea unui numr de mesaje cu continut text, urmat a de un mesaj fr continut, fapt care marcheaz sfritul trimiterii de date. a a a a s

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

import o r g . apache . q p i d . t r a n s p o r t . ; public c l a s s Se nde r { 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 <5){ System . out . p r i n t l n ( Usage j a v a S en der b r o k e r p o r t + exchange r o u t i n g K e y messagesNumber ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t 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 t r i n g exchange=a r g s [ 2 ] ; S t r i n g r o u t i n g K e y=a r g s [ 3 ] ; i n t n=I n t e g e r . p a r s e I n t ( a r g s [ 4 ] ) ; // Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // P r e c i z a r e a ( daca e s t e n e v o i e ) a c h e i i de r u t a r e D e l i v e r y P r o p e r t i e s d e l i v e r y P r o p s = new D e l i v e r y P r o p e r t i e s ( ) ; d e l i v e r y P r o p s . s etR ou ti ngK ey ( r o u t i n g K e y ) ; // Formarea s i e x p e d i e r e a m e s a j e l o r f o r ( i n t i =0; i <n ; i ++){ s e s s i o n . m e s s a g e T r a n s f e r ( exchange , MessageAcceptMode . EXPLICIT , MessageAcquireMode . PRE ACQUIRED, new Header ( d e l i v e r y P r o p s ) , Message + i ) ; } s e s s i o n . m e s s a g e T r a n s f e r ( exchange , MessageAcceptMode . EXPLICIT , MessageAcquireMode . PRE ACQUIRED, new Header ( d e l i v e r y P r o p s ) , ) ; // Confirmarea r e c e p t i e i m e s a j e l o r s e s s i o n . sync ( ) ; // I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i session . close (); con . c l o s e ( ) ; } }

152

CAPITOLUL 5. MESAJE JAVA IN

5.7.3

Receptionarea mesajelor

Mesaje se receptioneaz asincron, adic de o clas asculttoare care imple a a a a menteaz interfata SessionListener. a Interfata SessionListener declar metodele: a public public public public public void void void void void opened(Session session) resumed(Session session) message(Session session, MessageTransfer xfr) exception(Session session, SessionException e) closed(Session session)

Receptionarea de mesaje const din a 1. Realizarea conexiunii cu serverul AMQP Connection con = new Connection(); con.connect(broker,port,login,passworg,clientId,false); 2. Instantierea sesiunii Session session = con.createSession(0); 3. Precizarea asculttorului de mesaje (Fie Listener o clasa care implea menteaz interfata SessionListener) a Listener listener = new Listener(); session.setSessionListener(listener); 4. Crearea abonatului care urmeaz s receptioneaze mesaje. Asculttorul a a a va caracterizat de un nume - listener destination. session.messageSubscribe(numeCoada, "listener_destination", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, null, 0, null); session.messageFlow("listener_destination", MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT); session.messageFlow("listener_destination", MessageCreditUnit.MESSAGE, 11);

5.7. PROTOCOLUL AMQP

153

5. Ateptarea conrmrii trimiterii tuturor mesajelor disponibile de ctre s a a serverul AMQP session.sync(); 6. Oprirea asculttorului a session.messageCancel("listener_destination"); 7. Inchiderea sesiunii i a conexiunii s session.close(); con.close(); Exemplul 5.7.3 Receptia mesajelor expediate n clasa Sender, creata ante rior. Programul se va termina n momentul n care asculttorul primete un a s mesaj fr continut. a a
1 3 4 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 23 24 25 26 27 28 29 30 31

import o r g . apache . q p i d . t r a n s p o r t . ; c l a s s L i s t e n e r implements S e s s i o n L i s t e n e r { boolean s f a r s i t =f a l s e ; public void opened ( S e s s i o n s e s s i o n ) { } public void resumed ( S e s s i o n s e s s i o n ) { } public void message ( S e s s i o n s e s s i o n , M e s s a g e T r a n s f e r x f r ) { System . out . p r i n t l n ( Message : + x f r ) ; S t r i n g sMsg=x f r . t o S t r i n g ( ) ; i f ( sMsg . endsWith ( body=\\ ) ) s f a r s i t =true ; } public void e x c e p t i o n ( S e s s i o n ssn , S e s s i o n E x c e p t i o n e ) { System . out . p r i n t l n ( S e s s i o n L i s t e n e r E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ; } public void c l o s e d ( S e s s i o n s e s s i o n ) {} public void run ( ) { while ( ! s f a r s i t ) ; } } public c l a s s R e c e i v e r { public s t a t i c void main ( S t r i n g [ ] a r g s ) throws I n t e r r u p t e d E x c e p t i o n { i f ( a r g s . l e n g t h <3){ System . out . p r i n t l n ( Usage j a v a S en der b r o k e r p o r t queueName ) ; System . e x i t ( 1 ) ; } S t r i n g b r o k e r=a r g s [ 0 ] ; i n t 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 t r i n g queueName=a r g s [ 2 ] ;

154

CAPITOLUL 5. MESAJE JAVA IN

33 34 35 37 38 40 41 42 44 45 46 47 48 49 50 51 52 53 55 56 58 59 61 62 63 65 66 67 68 69

// Crearea c o n e x i u n i i C o n n e c t i o n con = new C o n n e c t i o n ( ) ; con . c o n n e c t ( b r o k e r , p o r t , t e s t , g u e s t , g u e s t , f a l s e ) ; // Crearea s e s i u n i i S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ; // Generarea u n e i i n s t a n t e a a s c u l t a t o r u l u i L i s t e n e r l i s t e n e r = new L i s t e n e r ( ) ; session . setSessionListener ( listener ); // Crearea a b o n a t u l u i c a r e r e c e p t i o n e a z e m e s a j e l e s e s s i o n . m e s s a g e S u b s c r i b e ( queueName , listener destination , MessageAcceptMode .NONE, MessageAcquireMode . PRE ACQUIRED, null , 0 , n u l l ) ; s e s s i o n . messageFlow ( l i s t e n e r d e s t i n a t i o n , M e s s a g e C r e d i t U n i t .BYTE, S e s s i o n . UNLIMITED CREDIT ) ; s e s s i o n . messageFlow ( l i s t e n e r d e s t i n a t i o n , M e s s a g e C r e d i t U n i t .MESSAGE, 1 1 ) ; // Confirmarea t e r m i n a r i i t r a n s m i t e r i i m e s a j e l o r s e s s i o n . sync ( ) ; // A b o n a t u l a s t e a p t a r e c e p t i o n a r e a t u t u r o r m e s a j e l o l i s t e n e r . run ( ) ; // O p r i r e a a s c u l t a t o r u l u i System . out . p r i n t l n ( S h u t t i n g down l i s t e n e r f o r l i s t e n e r d e s t i n a t i o n ) ; s e s s i o n . messageCancel ( l i s t e n e r d e s t i n a t i o n ) ; // I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i session . close (); con . c l o s e ( ) ; } }

Utiliznd clasele prezentate mai sus, prin xarea convenabil a parametrilor a a i a ordinii de lansare a programelor se poate exemplica specicul celor trei s dispeceri de directionare: Codurile pentru executie prin ant sunt Distribuirea direct: a
<target name="run" depends="compile"> <java classname="DeclareQueue" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 message_queue amq.direct routing_key"/> </java> <sleep seconds="15" /> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.direct routing_key 5"/> </java> <sleep seconds="5" />

5.7. PROTOCOLUL AMQP

155

<java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 message_queue"/> </java> </target>

Distribuirea fanout:
<target name="queue"> <java classname="DeclareQueue" fork="yes" <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q1 amq.fanout </java> <java classname="DeclareQueue" fork="yes" <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2 amq.fanout </java> </target> maxmemory="100M"> xxx"/> maxmemory="100M"> yyy"/>

<target name="sender"> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.fanout zzz 2"/> </java> </target> <target name="receiver"> <sleep seconds="5" /> <parallel> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q1"/> </java> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2"/> </java> </parallel> </target>

Distribuirea bazat pe publicare-abonare: a


<target name="queue"> <java classname="DeclareQueue" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q1 amq.topic unitbv.#.topic"/> </java> <java classname="DeclareQueue" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2 amq.topic unitbv.cs.*"/> </java> </target> <target name="receiver"> <parallel> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" />

156

CAPITOLUL 5. MESAJE JAVA IN

<arg line="localhost 5672 q1"/> </java> <java classname="Receiver" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 q2"/> </java> </parallel> </target> <target name="sender"> <java classname="Sender" fork="yes" maxmemory="100M"> <classpath refid="qpid.classpath" /> <arg line="localhost 5672 amq.topic unitbv.cs.topic 5"/> </java> </target>

cazul distribuirii fanout i a celei bazate pe publicare-abonare sunt lansate In s ordine dou cozi cu cte un receptor de mesaje (Receiver ) urmat de pron a a ductorul de mesaje (Sender ). a

Partea II TEHNOLOGII CU COMUNICATII PRIN INTERNET

157

Capitolul 6 HyperText Transfer Protocol


Protocolul http- HyperText Transfer Protocol (http) este destinal schimburilor de informatii Internet. n vederea schimburilor dintre calculatoare prin Internet, reprezentarea In datelor se face utiliznd principal: a n 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 de a asemenea din SGML.

6.1

Transactie http

Protocolul http este de tip client-server: Navigatoarele Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, Opera, Apple Safari sunt aplicatii client uzuale. Informatiile sunt gzduite / generate de servere Web de ctre site-uri a a i servicii Web. Exemple de servere Web sunt apache HTTP Server, s Microsoft Internet Interchange Server. O categorie aparte - esential a pentru platforma Java - este dat de servere Web container de servlet i a s JSP (Java Server Pages). Clientul 159

160

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

1. stabilete o conexiune cu serverul Web; s 2. trimite o cerere ctre serverul Web; a 3. receptioneaz rspunsul dat de serverul Web; a a 4. nchide conexiunea. Acest ciclu de actiuni se numete tranzactie http. s Serverul nu retine informatii ntre dou tranzactii http. Acest comportaa ment se exprim prin terminologia: protocolul http este fr stare - stateless. a a a Transmisia datelor se realizeaz utiliznd de obicei protocolul TCP. a a Referintele resurselor se indic folosind URI / URL. a Cererile i rspunsurile sunt reprezentate ca linii de text separate de cars a acterul <CR><LF>, avnd structura a 1. preambul - format dintr-o linie; 2. antete (header ) - 0 sau mai multe atribute (nume:valoare); 3. o linie goal; a 4. corpul mesajului - optional. Preambulul unei cereri contine: 1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE, OPTIONS}; 2. referinta resursei (URL); 3. Versiunea protocolului http. Preambulul unui rspuns contine: a 1. Versiunea protocolului http; 2. codul rspunsului: numr natural format din trei cifre cu semnicatiile a a Categoria 1** 2** 3** 4** 5** Indic a mesaj de informare mesaj de succes redirectare ctre alt URL a eroare in mesajul clientului eroare din partea serverului

Categoria este dat de prima cifr. a a

6.1. TRANSACTIE HTTP

161

3. String explicitnd codul rspunsului. a a Un antet (header ) este un atribut, adic o pereche (nume:valoare). Proa tocolul http denete o palet larg de atribute. Exemple de antete sunt date s a a in tabelul urmator: Antet Semnicatie Exemplu host Gazda i portul serverului Web s 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 limb pentru elegerea a a nt continutului 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 continutul este a imagine, cod binar, etc., atunci acesta este codicat text. n Codul Multipurpose Internet Mail Exchange (MIME) precizeaz natura a continutului unei resurse: text/plain text/html text/xml image/png image/jpg application/octet-stream application/x-www-form-urlencoded Ne prounem s punem evident mesajele http. a n a

162

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Mesaj cerere http


Dintr-un navigator se va lansa prin intermediul unui document html o cerere ctre un ipotetic servlet dintr-un server Web. Cererea este interceptat a a de o clas Java cu un soclu TCP, ServerSocket, care preia mesajele pe portul a 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 36 37 38

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 ( ) ) ; } } }

Rezultatul cererii depinde de metoda GET sau POST utilizat formulaa n rul 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

6.1. TRANSACTIE HTTP

163

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

Mesaj rspuns http a


Un servlet (apphello) este activ ntr-un server Web. O clas Java lanseaz a a o cerere http ctre acel servlet - chiar unul din mesajele obtinute mai sus a dup care receptioneaz rspunsul dat de servlet. a a a Codul clasei Java
1 2 3 4 5 6 7

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 ;

164

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

import j a v a . u t i l . S c a n n e r ; 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 : keepa l i v e \ r \n+ UserAgent : 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+ AcceptEncoding : g z i p , d e f l a t e , sdch \ r \n+ AcceptLanguage : enUS , en ; q =0.8\ r \n+ AcceptC h a r s e t : ISO88591, 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 : keepa l i v e \ r \n+ ContentLength : 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+ UserAgent : 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+ ContentType : a p p l i c a t i o n /xwww formu 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+ AcceptEncoding : g z i p , d e f l a t e , sdch \ r \n+ AcceptLanguage : enUS , en ; q =0.8\ r \n+ AcceptC h a r s e t : ISO88591, 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 ) ; 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 ) ; }

6.2. SERVER WEB - CONTAINER DE SERVLET

165

67 68 69 70 71 72 73 74 75 76 77 78 79

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 rspuns este a


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

prezent sunt disponibile mai multe servere Web care poate instalat In n un servlet i un ier JSP Java Server Pages. Despre un asemenea server Web s s se spune ca este container de servlet i JSP. Dintre produsele gratuite amintim s apache-tomcat jetty glasssh Acest server Web este utilizat Glassshv3 - o implementare JEE (Java n Enterprise Edition) de la Oracle. JBoss Geronimo, o alta implementare JEE dezvoltat de fundatia apache, poate a utiliza containerul apache-tomcat sau jetty. Serverul Apache HTTP Server i Windows Internet Information Server nu s sunt servere Web containere se servlet i JSP. s

166

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

6.3

Serverul Web apache-tomcat

continuare se va folosi serverul Web apache-tomcat, pe scurt tomcat. In Serverul Web tomcat este distribuit gratuit, putnd descrcat de la adresa a a www.apache.org. Instalarea serverului mediul Windows revine la dezarhivarea ierului n s descrcat apache-tomcat-***, a ntr-un catalog TOMCAT HOME. Utilizarea serverului necesit xarea a doi parametri sistem: a CATALINA HOME= calea la catalogul care s-a instalat produsul - TOMCAT HOME; n JAVA HOME=calea la distributia Java utilizat. a Pachetul contine cataloagele1 : bin, common, conf, logs, server, shared, temp, webapps, work. Serverul se lanseaz prin comanda a TOMCAT HOME\bin\startup i se oprete cu comanda s s TOMCAT HOME\bin\shutdown Din catalogul TOMCAT HOME, lansarea se poate obtine cu ajutorul ierului s de comenzi (*.bat) set CATALINA_HOME=. . . set JAVA_HOME=. . . bin\startup Optional se poate instala / activa managerul / administatorul serverului Web tomcat. Vericarea functionrii serverului Web tomcat se face apelnd dintr-un nav a a igator pagina http://host:port unde host este numele calculatorului pe care ruleaz tomcat; a Portul implicit este 8080. Reuita este ilustrat de imaginea motanului s a

Numele i numrul cataloagelor este dependent de distributia apache-tomcat. s a

Capitolul 7 Applet - Miniaplicatie Java


O categorie deosebit de programe Java reprezint miniaplicatiile (apa l a plet-uri), care se execut prin intermediul unui program de navigare WWW a n (World Wide Web) browser (Mozilla Firefox, Google Chrome, Microsoft InternetExplorer, Opera, Apple Safari. La aparitia limbajului de programare Java, acest tip de aplicatie a reprezentat unul din factorii de impact prin nou tatea i simplitatea solutiei oferite. s Applet-ul este o resurs program, depus a a ntr-o zona public, accesibil a a prin Internet (server Web.) Un program de navigare preia codul applet-ului i s execut. Apelarea unui applet se face dintr-un ier html. l a s O aplicatie applet nu este o aplicatie de tip client server dar este prin modul de utilizare este o aplicatie distribuit. a Datorit acestui mod de folosire, applet-urile au o structur special i a a a s sunt supuse la reguli stricte de securitate, printre care acela de a nu putea scrie informatii pe calculatorul pe care se execut - calculatorul clientului. a Metoda actual de apelare a unui applet se face prin intermediul unei a resurse Deployment Toolkit(DT) - o bibliotec de functii javascript. Resursa a DT este apelabil la adresa http://java.com/js/deployJava.js iar codul a se poate consulta la www.java.com/js/deployJava.js. DT utilizeaz protocolul Java Network Launching Protocol (jnlp) i evit a s a problemele de compatibilitate cu programul navigator. Aceast resurs rea a alizeaz descrcarea applet-ului ct i lansarea executie. Pe calculatorul a a a s n client, adic pe care ruleaz applet-ul, trebuie s e instalat jre - Java Runa a a time Environment - versiunea pe 32 biti. 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. 167

168

CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

Interfata grac, cazul extinderii clasei Applet, va utiliza controlurile a n apartinnd interfetei de programare AWT (Abstract Window Toolkit), iar a n cazul extinderii clasei JApplet se vor utiliza controluri Swing.

7.1

Clasa Applet

Structura unui applet este import java.applet.*; import java.awt.*; public classNumeClas extends Applet{ a public void init(){ Actiuni efectuate la instantierea clasei applet-ului. } public void start(){ Actiuni efectuate la lansarea applet-ului n executie sau la rentoarcerea n pagina applet-ului. } public void paint(Graphics g){ Actiuni efectuate ori de cte ori este necesar re a a desenarea ferestrei applet-ului. } public void stop(){ Actiuni efectuate la oprirea applet-ului, ca urmare a nchiderii ferestrei corespunztoare applet-ului. a } public void destroy(){ Actiuni efectuate la distrugerea applet-ului, ce au loc cnd navigatorul prsete documentul html din care s-a a a a s apelat applet-ul. } } Executarea applet-ului este controlat de programul navigator i revine la s apelarea metodelor init, start, stop. Acest fenomen se numete invers sarea controlului.

7.2. DESFASURAREA UNUI APPLET

169

7.2

Desfurarea unui applet as

Prin desfurarea (deployment) unei aplicatii se elege realizarea strucas nt turilor de cataloage i iere dar i a operatiilor care trebuie s s s ntreprinse n vederea functionrii unei aplicatii distribuite. a Desfurarea unui applet se poate face mai multe feluri: as n Varianta 1 1. Arhivarea ierelor class ale applet-ului. s 2. Editarea ierului html de apelare a applet-ului. Sablonul specic apelrii s a 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>

3. Cele dou iere se depun a s ntr-un catalog al unui server Web, asigurnd a vizibilitatea aplicatiei Internet. n Vericarea aplicatiei se poate face, dintr-un program navigator, prin sim pla apelare a ierului html. acest caz, calculatorul trebuie s e s In a conectat la internet. Dac dispunem de deployJava.js atunci acest ier se altur celorlalte a s a a dou resurse, iar atributul src al elementului script va src="deployJava.js". a Exemplul 7.2.1 Hello +nume. Numele se transmite miniaplicatiei ca parametru. Codul applet-ului este:

170

CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

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 ) ; } }

Fiierul html de apelare (inceput.html ) s


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

< T L H M> < E D HA> <TITLE H e l l o </TITLE > > </H A > E D <O Y B D> <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> </B D > O Y </H M > T L

Varianta 2 Pe aceast cale se va edita un ier de congurare cu extensia jnlp. Rea s alizarea applet-ului const din: a 1. Arhivarea ierelor class ale applet-ului. s 2. Editarea unui ier de congurare jnlp. Structura acestui ier este s s <?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"

7.2. DESFASURAREA UNUI APPLET

171

max-heap-size="128m" /> <jar href="numele_arhivei_jar" main="true" /> </resources> <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> 3. Editarea ierului html de apelare a applet-ului. Sablonul specic apelrii s a 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>

4. Cele trei iere (eventual patru cu deployJava.js) se depun s ntr-un catalog al unui server Web, asigurnd vizibilitatea aplicatiei Internet. a n Exemplul 7.2.2 Calculul celui mai mare divizor comun a dou naturale. a Introducerea datelor exterioare se face prin intermediul unei interfete grace. Applet-ul extinznd clasa Applet are codul a
1 2 3 5 6 8 9 10

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 ) ;

172

CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

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

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 cazul extinderii clasei JApplet n


1 2 3 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

import j a v a . awt . ; import j a v a x . swing . ; import j a v a . awt . e v e n t . ; public c l a s s VisualCmmdc extends JApplet implements A c t i o n L i s t e n e r { J 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 ( ) ; content . setBackground ( Color . yellow ) ; s e t L a y o u t (new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ) ; J L a b e l lm=new J L a b e l ( Primul numar : ) ; c o n t e n t . add ( lm ) ; tm=new J T e x t F i e l d ( 1 , 5 ) ; c o n t e n t . add ( tm ) ; J L a b e l l n=new J L a b e l ( Al d o i l e a numar : ) ; c o n t e n t . add ( l n ) ; tn=new J T e x t F i e l d ( 1 , 5 ) ; c o n t e n t . add ( tn ) ; JButton compute=new JButton ( 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 ) ; c o n t e n t . add ( compute ) ; r e z=new J T e x t F i e l d ( 1 , 5 ) ; rez . setEditable ( false ) ;

7.2. DESFASURAREA UNUI APPLET

173

25 26 27 29 30 31 32 33 34 35 36 38 39 40 42 43

c o n t e n t . add ( r e z ) ; s e t V i s i b l e ( true ) ; } 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 Lon g ( 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 ) { . . . } }

Fiierul de congurare jnlp (cmmdc.jnlp) este s


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

<?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 t t p : // l o c a l h o s t : 8 0 8 0 /cmmdc 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 maxheaps 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> <a p p l e t d e s c name=VisualCmmdc Applet mainc 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

<html> <body b g c o l o r=# AAEEAA> <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= 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>

174

CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

14

</ html>

sau cu descrcarea ierului jnlp. a s


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

<HTML > <BODY BGCOLOR =# AAEEAA> <CENTER > < ! <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> d e p l o y J a v a . l a u n c h ( cmmdc . j n l p ) ; </ s c r i p t> > <a h r e f= h t t p : // l o c a l h o s t : 8 0 8 0 /cmmdc/cmmdc . j n l p > App CMMDC </ a> </CENTER > </BODY > </HTML >

O alternativ (depit) la modurile de apelare al applet-ului descrise ana as a terior este prin utilizarea elementului html <applet>. Atributele obligatorii ale unui element applet sunt code Valoarea atributului este numele clasei applet-ului. width Valoarea atributului este limea ferestrei atribuit de navigator appletat a ului la aarea documentului html. s height Valoarea atributului este altimea ferestrei atribuit de navigator appletn a ului la aarea documentului html. s Atribute optionale sunt codebase Valoarea atributului este adresa URL ( Universal Resource Locator) sau calea la ierul cu clasa applet-ului. lipsa acestui parametru, cutarea s In a clasei are loc catalogul din care a fost arcat sursa html. n nc a vspace Valoarea atributului este lungimea, exprimat pixeli, care se las liber a n a a deasupra i dedesuptul ferestrei miniaplicatiei. s

7.3. COMUNICARE JAVA - JAVASCRIPT INTR-UN APPLET

175

hspace Valoarea parametrului este lungimea, exprimat pixeli, care se las a n a liber la stnga i la dreapta ferestrei applet-ului. a a s marcajul <applet> prin intermediul elementului <param> pot inIn clui parametri ce pot preluati de applet. Un parametru se denete prin s s atributele: name Valoarea atributului este numele variabilei recunoscut applet. a n value Valoarea atributului este valoarea receptionat de applet i este de tip a s String. Preluarea se realizeaz cu metoda a public String getParameter(String name) Documentul html de apelare al applet-ului Inceput este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14

< T L H M> < E D HA> <TITLE H e l l o > </H A > E D <O Y B D> < CENTER > < APPLET code = width = height = </APPLET > </CENTER > </B D > O Y </H M > T L

</TITLE >

Inceput . c l a s s 500 300 >

Dac ierul class al applet-ului nu se a acelai catalog cu documentul a s a n s html atunci localizarea clasei se face cu valoarea atributului codebase = "file://host/calea ctre catalogul clasei applet-ului" a Pentru testare, locul navigatorului se poate folosi programul appletviewer.exe n din distributia jdk.

7.3

Comunicare Java - JavaScript ntr-un applet

Se pot apela functii JavaScript denite documentul html din care se n apeleaz applet-ul. a

176

CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

Prin intermediul unui obiect de tip netscape.javascript.JSObject, creat prin static JSObject getWindow(java.applet.Applet applet) se apeleaz metoda a call(String numeFunctieJavaScript, java.lang.Object[] args). Sablonul de utilizare este import netscape.javascript.*; public void init(){ . . . JSObject window=JSObject.getWindow(null); window.call("numeFunctieJavaScript",args); . . . } Pachetul netscape.javascript se a distributia jdk catalogul JAVA HOME\ a n n jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie s contin aceast referinta. a a a

Capitolul 8 Conexiune simpl prin clase din a java.net


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

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 un obiect URL legat de resursa specicat de spec, care trebuie s a a a e o referint URL valid. a a Metode InputStream openStream() throws IOException Returneaz uxul de intrare pentru citirea resursei. a URLConnection openConnection() throws IOException Returneaz o instanta a conexiunii cu obiectul denit de URL. a
1

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

177

178

CAPITOLUL 8. CONEXIUNE SIMPLA PRIN CLASE DIN JAVA.NET

Exemplul 8.1.1 Pe baza referintei ctre un ier html dintr-un catalog vizibil a s al unui server Web, s se aeze continutul ierului. a s s codul reprodus mai jos, ierul Hello.html se a pe serverul apacheIn s a tomcat, catalogul webapps\url. n
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

im po rt j a v a . n e t . ; im po rt j a v a . i o . ; 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 ( ) ) ; } } }

cazul care resursa - exemplul dat reprezentat de ierul Hello.html In n n s - este accesibil doar urma autenticrii basic sau digest (Cap. Servlet, n a Autenticare, 9.4.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()); } });

Nici acest caz nu putem vorbi de o aplicatie client-server. n Un exemplu privind utilizarea clasei java.net.HttpURLConnection este dat capitolul Servlet. n

Capitolul 9 Servlet
Printre aplicatiile distribuite de tip client-server, care comunicatiile se n bazeaz pe protocolul http, se disting a Aplicatii Web (site): Cererea adresat serverului este lansat de o per a a soan utiliznd un program navigator: Google Chrome, Mozilla Firefox, a a Microsoft InternetExplorer, Opera, Apple Safari, etc. Servicii Web: Cererea ctre server se face de un program. Aplicatia a server i client se programeaz utiliznd interfete de programare specice. s a a Un servlet este un program Java care se excut pe un server Web, compatibil; a gestionat de serverul Web; capabil s receptioneze i s rpund cererilor formulate de clienti. a s a a a De asemenea vom utiliza termenul servlet i pentru aplicatia Web corespunztoare. s a Pe platforma de programare Java, servlet-ul este componenta care st la a baza dezvoltrii aplicatiile i serviciile Web. a s Programarea i utilizarea unui servlet necesit: s a Cunoaterea marcajului html <form> pentru realizarea formularelor de s introducere a datelor; Utilizarea unui server Web, container de servleti. 179

180

CAPITOLUL 9. SERVLET

9.1

Marcajul <form>

Intr-un document html introducerea datelor se poate obtine utiliznd mar a cajul <form> ...</form> . Atribute ale marcajului <form> . Reamintim c atributele se prezint a a ca perechi (nume, valoare) i se scriu antetul marcajului sub forma nume = s n valoare. Nume action method Valoare adresa tip URL GET Semnicatia valorii Resursa care prelucreaz formularul. a Mesajul trimis serverului Web contine dup a adresa URL numele i valorile parametrilor s introdui. Adugarea se face potrivit sintaxei s a ?numeParam1=valoare&numeParam2=valoare. . . Lungimea mesajului nu poate depi 255 caractere. as Transmisia datelor se face uxuri de date. n Permite transferul unor iere de pe maina s s clientului pe maina serverului. s Parametru de identicare a formularului (optional). Nume atribuit formularului (optional). Metod JavaScript executat a a naintea apelrii a serverului Web (optional).

POST

id name onSubmit

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

9.2. REALIZAREA UNUI SERVLET

181

Nume type

Valoare Semnicatie text Se ateapt introducerea unui text s a password Se ateapt introducerea unei parole s a submit Se marcheaz sfritul completrii formularului a as a reset Se reinitializeaz formularul a file Permite selectarea unui ier s hidden Transmite mai departe un atribut fr vizualizarea lui aa name numele controlului value valoarea (initial) a controlului a size numrul caracterelor ataat controlului a s cazul marcajului < select> utilizarea este In <select name="nume"> <option value="valoare"> Valoare . . . . . . . . . . . . . . . . </select> Valoarea atributului nume este dat de valoarea selectat. a a

9.2

Realizarea unui servlet

Interfata de programare (API) pentru servlet a ajuns la versiunea 3, versi une pe care o vom utiliza cele ce urmeaz. Aceast interfata de programare n a a nu face parte din JDK, ind implementat de ecare productor de server Web a container de servlet. Structura minimal a unui servlet este a catalogAppServlet |--> WEB-INF | |--> classes | | | *.class | |--> lib | | | *.jar | index.html Catalogul classes contine ierele class ale aplicatiei servlet. s Catalogul lib este optional i va contine resursele jar suplimentare cerute s de clasele servlet-ului. Prin intermediul ierului index.html se apeleaz aplicatia servlet. Adresa s a de apelare (URL - Universal Resource Locator ) a aplicatiei servlet este

182 http://host:port/catalogAppServlet

CAPITOLUL 9. SERVLET

Dac loc de index ierul html de apelare are alt nume, de exemplu xyz.html a n s atunci adresa de apelare va http://host:port/catalogAppServlet/xyz.html host este numele calculatorului pe care ruleaz serverul Web - gazda aplicatiei a servlet. Portul implicit utilizat de un server Web container de servlet este 8080. Catalogul aplicatiei este denumit context-ul servlet-ului. Apelarea servlet-ului se poate face: din meniul File/Open al unui navigator; ca referinta 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. Legtura cu clasa servlet-ului se poate realiza a programat prin adnotri codul servlet-ului; a n descriptiv catalogul WEB-INF se editeaz ierul web.xml. n a s versiunile anterioare ale interfetei de programare servlet aceasta a fost In unica optiune. Trebuie demarcat diferenta dintre apelarea / lansarea executie a clasei a n servlet de apelarea aplicatiei Web. Modul programat se bazeaz pe adnotarea javax.servlet.annotation.WebServlet a cu elementele: String name String[ ] urlPatterns @WebInitParams[ ] initParams boolean asyncSupported long asyncTimeout ierul web.xml apar elementele Modul descriptiv In s 1. <servlet> leag numele servlet-ului denit elementul <servlet-name> a n de clasa servlet-ului dat elementul <servlet-class> . n

9.2. REALIZAREA UNUI SERVLET

183

2. <servlet-mapping> denete numele sub care servlet-ul identicat prin s <servlet-name>nume servlet< /servlet-name> se invoc din prograa mul navigator. Acest identicator - numeApel - se xeaz elementul a n <url-pattern> . Identicatorul are ca prex caracterul / (slash). Structura unui ier web.xml este s
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/XMLSchemai 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> pot corespunde mai multe elemente <servlet-mapping>, i prin utilizarea de numeApel diferite. Optional web.xml poate contine elementul
<welcome-file-list> <welcome-file> fisier.html sau jsp </welcome-file> </welcome-file-list>

cu precizarea ierelor html sau jsp care apeleaz aplicatia Web. Declaratia s a ierului index.html este implicit. s a Compilarea clasei servlet necesit completarea variabilei de mediu classpath a cu ierul TOMCAT HOME\lib\servlet-api.jar. s Odat completat structura de cataloage i iere ale aplicatiei servlet a a s s aceast structur trebuie copiat catalogul TOMCAT HOME\webapps. Aceast a a a n a operatie se numete desfurarea (deployment) sau instalarea servlet-ului. s as Copierea se poate executa i cu serverul Web pornit. s Pentru instalarea unui servlet exist mai multe alternative: a Din catalogul catalogAppServlet se realizeaz arhiva catalogAppServlet.war a

184

CAPITOLUL 9. SERVLET

jar cfv catAppServlet.war WEB-INF\ index.html care se copiaz catalogul TOMCAT HOME\webapps. a n Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este instalat. Aceast instalare se numete instalare dinamic - hot deployment. a s a Dac ierul war este creat, atunci locul copierii, instalarea se poate a s n face prin componenta manager a lui tomcat. O alt posibilitate de instalare a unui servlet serverul web tomcat a n este prin intermediul produsului apache-tomcat-deployer. apache-tomcatdeployer permite instalarea unui servlet de la distanta ct i instalarea a s comandat dintr-un program. a
apache-tomcat-*.*.*-deployer se instaleaz prin dezarhivarea ierului apache-tomcat-*.*.*-deployer. a s Posibilitile oferite de apache-tomcat-*.*.*-deployer se obtin rulnd ant cu un ierul build.xml at a s din distributia produsului. Obiectivele care pot atinse sunt compilarea unui servlet - compile instalarea unui servlet - deploy dezinstalarea unui servlet - undeploy prealabil trebuie completat ierul de proprieti deployer.properties cu In s at build=catalogul care va contine rezultatul compilrii i al arhivrii. a s a webapp=catalogul cu sursa servlet-ului. path=/catalog-ul servlet-ului. url=url-ul aplicatiei manager din Tomcat http://host:8080/manager username=numele de acces manager-ul din Tomcat. n password=parola pentru manager-ul din Tomcat.

9.2.1

Codul unui servlet

Un servlet implementeaz interfata Servlet sau extinde una din clasele a GenericServlet sau HttpServlet. GenericServlet implementeaz interfata a Servlet, iar HttpServlet extinde clasa GenericServlet. Extinznd clasa a GenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte ale intrefetei Servlet. Metodele interfetei Servlet sunt abstract public void init(ServletConfig cong) Se apeleaz o singur dat la lansarea servlet-ului. a a a

9.2. REALIZAREA UNUI SERVLET

185

abstract public void service(ServletRequest req, ServletResponse res)throws ServletException,IOException Metoda este apelat de serverul Web pentru rezolvarea cererii unui client. a abstract public void destroy() Se apeleaz o singur dat la distrugerea servlet-ului. a a a public String getServletInfo() public ServletConfig getServletConfig() cele ce urmeaz o clasa servlet va o clas care extinde clasa HttpServlet. In a a locul metodei service(...), programatorul suprascrie metodele doGet(...) In sau doPost(...), functie de metoda utilizat de client la lansarea cererii. n a Practic, un servlet const din scrierea metodelor a void init(ServletConfig cong) Aceast metod este optional. a a a public void init(ServletConfig config) throws ServletException{ super.init(config); // cod de initializare } Obiectul cong are o metod String getInitParameter(String nua meParam) cu ajutorul creia se pot recupera parametri de initializare a asociati servlet-ului i care se dau e prin adnotarea WebInitParam prin s ablonul s import javax.servlet.annotation.WebInitParam; @WebServlet(urlPatterns = "/numeApel", initParams = { @WebInitParam(name = "numeParam", value = "valoareParam"), . . . } ) e ierul web.xml prin elementele n s

186

CAPITOLUL 9. SERVLET

<init-param> <param-name> NumeleParametrului </param-name> <param-value> Valoare </param-value> </init-param> cuprinse elementul <servlet>. n protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException Trateaz o cerere trimis cu metoda GET (vezi marcajul <form>). a a protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException Trateaz o cerere trimis cu metoda POST (vezi marcajul <form>). a a Activitile de at ntreprins ntr-o metod doGet() sau doPost() sunt a 1. Stabilirea naturii rspunsului: a res.setContentType(String tip) unde tip specic tipul MIME - Multipurpose Internet Mail Extensions a al rspunsului: a "text/html" - pagin html; a "text/xml" - document xml; "text/plain" - text; "image/jpg" - imagine gif; "image/gif" - imagine jpg. 2. Se obtine o referinta ctre un obiect care realizeaza transmisia datelor a ctre navigatorul clientului: a ServletOutputStream out = res.getOutputStream(); sau PrintWriter out=res.getWriter(); 3. Se preiau datele cererii cu una din metodele: String getParameter(String numeParapetru) java.util.Enumeration getParameterNames() 4. Rezolv cererea clientului; a

9.2. REALIZAREA UNUI SERVLET

187

5. Formeaz i scrie rspunsul; as a 6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor ctre navigatorul clientului prin out.close(). a Un utilizator lanseaz o cerere ctre servlet. De obicei acest lucru se rea a alizeaz prin completarea unui formular al unui document html. Programul a navigator trimite cererea serverului Web prin intermediul cruia este lansat a servlet-ul actiune. n Ciclul de viat al unui servlet. Cnd un servlet este apelat prima a a dat de ctre serverul Web se execut metoda init. Dup aceasta, ecrei a a a a a cereri lansate de un utilizator i se asociaz un r de executie care se apea n leaz metoda service. Metoda service apeleaz apoi metodele doGet(), a a doPost(). Exemplul 9.2.1 Servlet-ul Hello: Clientul transmite numele servet-ului care rspunde cu mesajul de salut Hi + nume!. i a 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

<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 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 > </form> </ center> </body> </html>

modul programat servlet-ului are codul In


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

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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> ) ;

188

CAPITOLUL 9. SERVLET

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

out . out . out . out . out . out . out . out . 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> ) ; p r i n t l n ( <body> ) ; p r i n t l n ( <h1>H e l l o S e r v l e t </h1> ) ; p r i n t l n ( <p> ) ; p r i n t l n ( Hi + nume+ ! ) ; p r i n t l n ( </p> ) ; p r i n t l n ( </body> ) ; p r i n t l n ( </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 ) ; } }

modul descriptiv, locul liniilor de cod 4-6 va folosit ierul web.xml In n s


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/XMLSchemai 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 i arhivarea servlet-ului o vom realiza prin intermediul lui s acest scop se creaz structura: apache-ant. In a
hello | |---> src | | | HelloServlet.java | |---> lib | |---> web | | | web.xml | |---> web-files | | | index.html | build.xml

i se utilizeaz ierul build.xml s a s


1 2 3 4 5 7 8 9 10 11

<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= . . . / apachetomcat . . /> <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 r o p e r t y name= d i s t . d i r v a l u e= d i s t /> <p r o p e r t y name= b u i l d . d i r v a l u e= b u i l d /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r= 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 />

9.2. REALIZAREA UNUI SERVLET

189

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

</ 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 } /> <mkdir d i r= ${ b u i l d . d i r } /> <mkdir d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ l i b /> </ 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= ${ b a s e d i r }/ s r c d e s t d i r= ${ b u i l d . d i r }/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> <t a r g e t name= g e n e r a t e . war depends= c o m p i l e > <copy t o d i r= ${ b u i l d . d i r } > < f i l e s e t d i r= ${ b a s e d i r }/web f i l e s > <i n c l u d e name= . html /> </ f i l e s e t> </ copy> <copy t o d i r= ${ b u i l d . d i r }/WEB INF f i l e = ${ b a s e d i r }/web/web . xml /> <copy t o d i r= ${ b u i l d . d i r }/WEB INF/ l i b > < f i l e s e t d i r= ${ b a s e d i r }/ l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> </ copy> <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= ${ b u i l d . d i r } /> </ t a r g e t> </ p r o j e c t>

Observatie. Valoarea parametrului dist.name denete parametrul catalo s gAppServlet. Se lanseaz executie serverul Web tomcat, se a n ncarc servlet-ul serverul a n Web i dintr-un navigator se deschide pagina http://localhost:8080/apphello s Exemplul 9.2.2 Servlet pentru calculul celui mai mare divizor comun a dou a numere.
1 2 3 4 6 7 9 11 12 13

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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 ) 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 ) ;

190

CAPITOLUL 9. SERVLET

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

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 27 28 29 30

<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 sm=document . cmmdc .m. value ; var sn=document . cmmdc . n . value ; i f (sm== ) { a l e r t ( L i p s e s t e p r i m u l numar ! ) ; return f a l s e ; } i f ( sn== ) { a l e r t ( L i p s e s t e a l d o i l e a numar ! ) ; return f a l s e ; } i f ( ! IsNumeric (sm ) ) { a l e r t ( Primul numar e s t e g r e s i t i n t r o d u s ! ) ; return f a l s e ; } i f ( ! IsNumeric ( sn ) ) { a l e r t ( Al d o i l e a numar e s t e g r e s i t i n t r o d u s ! ) ; return f a l s e ; } return true ; } f u n c t i o n IsNumeric ( s T e x t ) { // J e f f Anderson // A j a v a s c r i p t v a l i d a t i o n f u n c t i o n t o c h e c k w h e t h e r t h e d e t a i l s // e n t e r e d by a u s e r a r e numeric ( 2 0 0 2 )

IN 9.3. PROCESARE ASINCRONA JAVA SERVLET 3.0

191

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

var var var for

ValidChars = 0123456789. ; IsNumber=t r u e ; Char ; ( i = 0 ; i < sText . l e n g t h && IsNumber == t r u e ; i ++){ Char = sText . charAt ( i ) ; i f ( V a l i d C h a r s . i n d e x O f ( Char ) == 1){ IsNumber = f a l s e ; }

} r e t u r n IsNumber ; } // > </ s c r i p t> < 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 name=cmmdc onSubmit= r e t u r n c h e c k I t ( ) > <p>Primul numar e s t e <input type= t e x t name=m 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 s i z e=5> <p><input type= submit value= C a l c u l e a z a > <input type= h id de n name= t i p value= t e x t / html > </form> </ center> </body> </html>

Pentru xarea naturii rspunsului text/html sau text/plain s-a introdus a variabila tip, care ierul de invocare index.html primete pe ascuns valoarea n s s cazul care vom apela servlet-ul dintr-un program, va text/html. In n avantajos s primim rspunsul ca text/plain. a a

9.3

Procesare asincron Java Servlet 3.0 a n

Rezolvarea unei cereri adresat de un client unui servlet se execut de ctre a a serverul Web ntr-un r de executie. Aceast executie este sincron sensul a a n care trecerea la instructiunea urmtoare are loc doar la incheierea executiei n a instructiunii curente. Interfata de programare Servlet 3.0 ofer posibilitatea unui executii asin a crone. Acest mod de executie se indic prin adnotarea a @WebServlet(urlPaterns="/numeApel " ,asyncSupported=true) Suportul asincron necesit un context, obiect de tip AsyncContext a AsyncContext asyncCtx=req.startAsync(req,res); Activitile ce trebuie at ndeplinite pentru satisfacerea cererii clientului se lanseaz a ntr-un r de executie, obiect care este parte a unei familii gestionate de o clas ce implementeaz interfata Executor: a a

192

CAPITOLUL 9. SERVLET

public ScheduledThreadPoolExecutor(int corePoolSize) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) Interfata AsyncListener permite noticarea evenimentelor void onComplete(AsyncEvent ae) void onTimeout(AsyncEvent ae) void onError(AsyncEvent ae) void onStartAsync(AsyncEvent ae) Obiectul de tip AsyncEvent este creat momentul satisfacerii cererii clientun lui, depirii timpului alocat sau producerii unei erori. as Exemplul 9.3.1 Varianta asincrona a servlet-ului de calcul a celui mare divizor comun.
1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 17 18 19 21 22 23 24 25

package m y s e r v l e t ; 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 ; import j a v a . u t i l . c o n c u r r e n t . ; import j a v a . i o . IOException ; import l i s t e n e r s . ; @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 ThreadPoolExecutor ( 1 0 , 1 0 , 5 0 0 0 0 , TimeUnit . MILLISECONDS, new LinkedBlockingQueue<Runnable > ( 1 0 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 executie responsabil cu ndeplinirea cererii clientului este

IN 9.3. PROCESARE ASINCRONA JAVA SERVLET 3.0

193

1 2 3 4 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 34 35 36 38 39

package m y s e r v l e t ; 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 . i o . ; public c l a s s AsyncWebService implements Runnable { AsyncContext asyncCtx ; public AsyncWebService ( AsyncContext asyncCtx ) { t h i s . asyncCtx=asyncCtx ; } public void run ( ) { 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 interfata AsyncListener a


1 2 3 4 6 8 10 11 12 13 14 16 17

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 ( ) ;

194

CAPITOLUL 9. SERVLET

18 19 20 22 23 24 25 26 28 29 30 31 32 33

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 ) ; 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
9.4.1

Faciliti de programare cu servlet at


Program client al unui servlet

Apelarea unui servlet dintr-un program Java adic lansarea unei cereri i a s receptionarea rspunsului furnizat de servlet se poate obtine a sincron cu produsul httpcomponents-client, asincron cu produsul httpcomponents-asyncclient. Ambele produse sunt dezvoltat de apache. Caracterul sincron / asincron const faptul c receptia i prelucrarea a n a s rspunsului oferit de servlet are loc metoda din care s-a lansat cererea, a n respectiv ntr-un alt obiect. Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos ca rspunsul servlet-ului e text/plain, loc de text/html. a n Cazul sincron Catalogul lib din httpcomponents-client contine, printre altele, ierele s httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar. Pentru compilare trebuie declarat variabila de sistem classpath referinta a n ctre httpclient-*.jar i httpcore-*.jar dar pentru executie este nevoie i de a s s referinta ctre commons-logging-*.jar. a Dezvoltarea unui client presupune: 1. Crearea unui obiect de tip org.apache.http.client.HttpClient:

9.4. FACILITATI DE PROGRAMARE CU SERVLET

195

HttpClient client=new DefaultHttpClient(); DefaultHttpClient apartine pachetului org.apache.http.impl.client. 2. Declararea metodei de transmitere a datelor get, post. 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 solutie mai elegent este a 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(. . .){. . .}

196 cu uri=http://host:port/catalog/numeApel.

CAPITOLUL 9. SERVLET

Clasele HttpGet, HttpPost apartin pachetului org.apache.http.client.methods. 3. Lansarea cererii. HttpResponse response=httpclient.execute(httpget); respectiv HttpResponse response=httpclient.execute(httppost); 4. Preluarea rspunsului. a 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.4.1 Dezvoltm un program client pentru servlet-ul CmmdcServlet a (post).
1 2 3 5 6 7 8 9 10 11 12 14 16 17 19 20 21

import j a v a . u t i l . S c a n n e r ; import j a v a . u t i l . L i s t ; import j a v a . u t i l . A r r a y L i s t ; import import import import import import import import o r g . apache . h t t p . H t t p E n t i t y ; o r g . apache . h t t p . HttpResponse ; o r g . apache . h t t p . c l i e n t . 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 . impl . c l i e n t . D e f a u l t H t t p C l i e n t ; o r g . apache . h t t p . NameValuePair ; o r g . apache . h t t p . message . BasicNameValuePair ; 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 ) ; =

9.4. FACILITATI DE PROGRAMARE CU SERVLET

197

22 23 24 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

S t r i n g m canner . nextLine ( ) . trim ( ) ; =s 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 ( ) ; // C r e a t e an i n s t a n c e o f H t t p C l i e n t . H t t p C l i e n t h t t p c l i e n t = new D e f a u l t H t t p C l i e n t ( ) ; // C r e a t e a method i n s t a n c e . 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 ) ) ; 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 ) ; HttpResponse 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 solutie elementar bazat pe clasa java.net.HttpURLConnection este a a


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

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 c a n n e r . nextLong ( ) ; =s 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 =+ +&n=+n+&t i p=t e x t / p l a i n ; m 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 ;

198
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 ( ) ;

CAPITOLUL 9. SERVLET

26 27 28 29 30 31 32 33 34 35 36 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

} 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 ; 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 ( ContentType , a p p l i c a t i o n /xwww formu 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 contine referentele ctre erele jar aate catalogul a s n lib din httpcomponent-asyncclient. Programarea const din a 1. Crearea unei instante a clasei org.apache.http.nio.client.HttpAsyncClient HttpAsyncClient httpclient = new DefaultHttpAsyncClient(); httpclient.start(); 2. Lansarea unei cereri apelnd o metod execute: a a <T> Future<T> execute(

9.4. FACILITATI DE PROGRAMARE CU SERVLET

199

org.apache.http.nio.protocol.HttpAsyncRequestProducer requestProducer, org.apache.http.nio.protocol.HttpAsyncResponseConsumer<T> responseConsumer, org.apache.http.concurrent.FutureCallback<T> callback ) O instanta de tip HttpAsyncRequestProducer se obtine prin HttpAsyncMethods.createGet(uri) Drept instanta a clasei HttpAsyncResponseConsumer poate o clas ce a extinde clasa org.apache.http.nio.client.methods.AsyncCharConsumer. Exemplul 9.4.2
1 3 4 5 6 7 8 9 11 12 13 15 16 18 19 20 21 22 23 24 26 27 28 29 30 31 32 33 34 35 36 37 38

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 . D e f a u l t 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 . n i o . c l i e n t . 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 . 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 . ; 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 ) ; = S t r i n g m canner . nextLine ( ) . trim ( ) ; =s 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 =+ +&n=+n+&t i p=t e x t / p l a i n ; m H t t p A s y n c C l i e n t h t t p c l i e n t = new D e f a u l t H t t p A s y n c C l i e n 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 ) ; }

200

CAPITOLUL 9. SERVLET

39 40 41 42 43 44 45 47 48 49 50 52 53 54 55 56 57 58 59 61 62 63 65 66 67 68 69 70

System . out . p r i n t l n ( S h u t t i n g down ) ; } finally { h t t p c l i e n t . shutdown ( ) ; } 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 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.4.2

Servlete antuite nl

Un servlet apeleaz la un moment dat alt servlet. Sablonul de lucru este a RequestDispatcher dispatcher= getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat"); if(dispatcher!=null) dispatcher.include(request,response); Exemplul 9.4.3 Un servlet VerifServlet veric parametri cererii. Pentru a problema calculului celui mai mare divizor comun a dou numere, dac cei doi a a parametri sunt numere ntregi, atunci se apeleaz servlet-ul ComputeServlet, a altfel se formeaz un mesaj de eroare. a Codurile celor dou servlete sunt: a VerifServlet.java

9.4. FACILITATI DE PROGRAMARE CU SERVLET

201

1 2 3 4 5 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 52 54 55 56 57 58

package cmmdc ; 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 = / 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 ) 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 ) ; } }

202 ComputeServlet.java
1 2 3 4 5 7 8 10 12 13 14 15 16 17 18 20 21 22 23 24

CAPITOLUL 9. SERVLET

package cmmdc ; 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 = / 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.4.3

Sesiune de lucru

cazul protocolului HTTP, de ecare dat cnd un client deschide sau In a a revine la o pagin Web se deschide o nou conexiune cu serverul Web iar acesta a a nu retine informatiile referitoare la client pe perioada conexiunii respective. Perioada de timp ct un client este conexiune cu o pagin Web se numete a n a s sesiune. Exist posibilitatea pstrrii unor informatii pe durata unei sesiuni (prin a a a mecanismul denumit Session Tracking). Inaintea satisfacerii unei cereri, servlet-ul veric existenta unui obiect a HttpSession. Acest obiect se creaz la prima apelare de ctre un client a a a servlet-ului prin HttpSession sesiune=request.getSession(true); Un obiect HttpSession poate retine atribute, adic perechi de forma (nume, a valoare). Introducerea unui atribut se realizeaz prin a void setAttribute(String nume, Object valoare) iar extragerea valorii unui atribut se obtine prin Object getAttribute(String nume)

9.4. FACILITATI DE PROGRAMARE CU SERVLET

203

Metoda String nume[ ] getValueNames() returneaz numele tuturor a atributelor denite. Un atribut se elimin cu metoda void removeAttribute(String nume). a Exemplul 9.4.4 Exemplul urmtor numr de cte ori se apeleaz servleta a a a a ul ntr-o sesiune. Se denete un atribut noAcces, care la prima apelare este s initializat iar apoi este mrit cu cte o unitate la ecare nou apelare a servlet a a a ului.
1 2 3 4 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 33 34 35 36 37

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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

<html> <head> < t i t l e> S e s i u n e </ t i t l e> </head> <body> <h1> Formular de a c c e s </h1>

204

CAPITOLUL 9. SERVLET

7 8 9 10 11 12

<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> </body> </html>

9.4.4

Cookie

Un Cookie este un ier de dimensiune mic trimis de ctre programul s a a server clientului ca parte a header-ului Http. Acesta contine informatii despre sesiunea curent care salvate pe disc vor a putea accesate sesiuni ulterioare. Cnd un navigator emite o cerere ctre n a a un server, cookie-urile anterioare primite de ctre client de la serverul respectiv a sunt trimise din nou serverului ca parte a cererii formulat de client. a Cookie-urile sunt sterse automat momentul expirrii. n a acest caz, clientul este Unii clienti nu permit memorarea cookie-urilor. In informat c acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale a / accesrii paginii Web. Implicit, durata de viata a unui cookie este sesiunea a curent a navigatorului (pn se a a a nchide navigatorul). Clasa Cookie Contructor Cookie(String nume, String valoare) Metode void setDomain(String model ) Domeniul este o adres URL ce restrictioneaz accesul cookie-urilor la a a acel domeniu. model trebuie s contin cel putin dou caractere .. a a a void setMaxAge(int durat ) Fixeaz durata de existenta a cookie-ului a a - secunde. Valoarea implicit este -1, adic cookie-ul exist pn la n a a a a a nchiderea programului navigator. void setComment(String comentariu) void setSecure(boolean ag) Valoarea implicit este false. a

9.4. FACILITATI DE PROGRAMARE CU SERVLET

205

Trimiterea unui cookie clientului: public void HttpServletResponse.addCookie(Cookie cookie) Recunoaterea cookie-urilor de ctre servlet: s a 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 9.4.5 In exemplul urmtor se numr de cte ori se apeleaz servleta a a a a ul pe durata de viat a cookie-ului. a

1 2 3 4 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 33 34 35

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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 = / a p e l a r i ) 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 , 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 ( ) ; Cookie myCookie=n u l l ; i n t c o n t o r =1; Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ; 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 ) ) { 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 ! ; } } } else { mesaj= S a l u t ! ; } 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 ( ) ) ; 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 ) ;

206

CAPITOLUL 9. SERVLET

36 37 38 40 41 42 43 44

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.4.5

Autenticare

Serverul Web apache-tomcat poate executa autenticrile basic i digest. a s Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password). Aceste informatii sunt retinute serverul Web, ierul conf\tomcat-users.xml n n s 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 cerinta de autenticare solicitat a unui client se precizeaz ierul web.xml a n s
<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> <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>

Optional poate denit un domeniu (realm). cazul apelrii dintr-un program Java a unui servlet, la care accesul preIn a supune autenticare, aceasta se realizeaz prin intermediul claselor pachetului a httpcomponents-client:

9.4. FACILITATI DE PROGRAMARE CU SERVLET

207

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); . . .

9.4.6

Servlet cu conexiune la o baz de date a

Folosind Anexa C considerm a Exemplul 9.4.6 Consultarea unei agende de adrese e-mail. Se utilizeaz o a baz de date AgendaEMail alctuit dintr-un singur tabel adrese (id int, nume a a a varchar(20), email varchar(30)). Utiliznd SGBD derby servlet-ul este a
1 2 3 4 5 6 8 9 10 11 13 14 15 16 17 18 20 21 22 23 24

import import import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; java . s q l . ; java . net . ; 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 = / 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 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 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 { 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 ) {

208

CAPITOLUL 9. SERVLET

25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 41 42 44 45 46 47 48 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 79 80 81 82 83

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 ( ) ; 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 ) ; } }

9.4. FACILITATI DE PROGRAMARE CU SERVLET

209

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= h t t p : / / l o c a l h o s t : 8 0 8 0 / agendae / 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 aplicatiei presupune: 1. Realizarea bazei de date: 2. Testarea servlet-ului: (a) Pornirea serverului bazei de date. (b) Se veric prezenta catalogul servlet-ului ...\WEB-INF\lib a a n ierului derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar. s (c) Pornirea serverului tomcat sau re arcarea servlet-ului. nc (d) Apelarea servlet-ului din pagina Web.

9.4.7

Imagini furnizate de servlet

Indicm dou modaliti prin care un client obtine o imagine furnizat de a a at a un servlet. Imaginea poate proveni dintr-un ier extern sau poate creat s a de servlet. Imaginea este transmis direct clientului uxul de ieire de tip a n s ServletOutputStream, tipul MIME al rspunsului ind a response.setContentType("image/ext"); ext {gif, jpg, png, . . .}. Textul surs al servlet-ului este: a

210

CAPITOLUL 9. SERVLET

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

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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 = / 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 { r e s . setContentType ( image / g i f ) ; S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ; // R e f e r i n t a l a f i s i e r u l g r a f i c String f = d : \ \ apachetomcat . . \ \ webapps \\ m y s e r v l e t \\WEB INF\\ + c l a s s e s \\ w a l k i n g s a n t a . g i f ; // T r a n f e r a r e a f i s i e r u l u i g r a f i c F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f ) ; B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ; byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ; i n t nread = 0 ; while (1 != ( nread = b i s . r e a d ( b y t e s ) ) ) { out . w r i t e ( b y t e s , 0 , nread ) ; } bis . close ( ); f i s . close (); out . c l o s e ( ) ; } }

Pe calculatorul serverului Web, imaginea se salveaz a ntr-un ier grac, s dup care servlet-ul scrie uxul de ieire un document html cu o a n s legtur (link) ctre ierul cu imaginea creat anterior. Navigatorul a a a s a clientului va descrca i vizualiza imaginea. a s Dac tipul ierului grac este jpg sau png atunci textul surs al servleta s a ului este:

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

mport j a v a . i o . ; import j a v a . awt . ; 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 . i m a g e i o . ; import j a v a . awt . image . ; import j a v a x . i m a g e i o . stream . ; import j a v a . u t i l . ; 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 = / 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 { r e s . setContentType ( t e x t / html ) ;

9.4. FACILITATI DE PROGRAMARE CU SERVLET

211

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

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 f i l e R e f=d : \ \ apachetomcat 6 . 0 . 2 0 \ \ webapps \\ m y s e r v l e t \\ ; 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 ; 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 tipul ierului grac va gif atunci linia 34 se a s nlocuiete cu s


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

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

9.4.8

Servlet cu RMI

Un servlet poate client al unei aplicatii RMI. Interfata la diatant se a depune catalogul WEB-INF\lib al servlet-ului. Apelarea programului server n RMI se face prin

212

CAPITOLUL 9. SERVLET

InterfataDistanta obj=(InterfataDistanta) Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI"); Exemplul 9.4.7 Client servlet pentru aplicatia RMI de calcul al celui mai mare divizor comun a dou numere naturale. a

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.4. FACILITATI DE PROGRAMARE CU SERVLET

213

9.4.9

Servlet cu JMS

De data aceasta cererea clientului se rezolva asincron: In prima faz se apeleaz un servlet care apeleaz un server JMS. Solutia a a a este retinut de furnizorul serviciului de mesagerie pe o destinatie cu un a subiect furnizat de client. Pentru regsirea rezultatului, servlet-ul creaz a a clientului un abonament durabil, functie de numele subiectului. faza a doua, clientul apeleaz un alt servlet, a crei functie este preIn a a luarea rezultatului. Clientul trebuie sa furnizeze subiectul destinatiei rezultatului. Exemplul 9.4.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

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 OracleSun 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 ) ;

214

CAPITOLUL 9. SERVLET

38 39 40 41 42 43 44 45 46 47 48 49 50 51 53 54 55 56 57

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 ( ) ) ; 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

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 ( ) ; S t r i n g m e q . g e t P a r a m e t e r ( m ) ; =r 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 OracleSun 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=

9.4. FACILITATI DE PROGRAMARE CU SERVLET

215

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

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= + +n+ +t o p i c ; m 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

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 OracleSun 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 ( ) ;

216

CAPITOLUL 9. SERVLET

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

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= 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 ) ; } }

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

9.5

FileUpload

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

9.5. FILEUPLOAD

217

commons-leupload-*.*.jar commons-io-*.*.jar se depun catalogul lib al servlet-ului. n Transferarea unui ier, din partea clientului nu ridic nici o problem. s a a In ierul html de apelare, se denete un formular s s <form action=. . . enctype="multipart/form-data" method="post"> iar un ier de arcat se xeaz prin intermediul marcajului s nc a <input type="file" name=. . . size=. . .> Programul navigator aeaz o fereastr de cutare, prin care clientul ses a a a lecteaz ierul pe care dorete s-l a s s a ncarce. Dac partea de client este un program, atunci se utilizeaz commonsa a httpclient, 9.4.1 De partea serverului, programarea arcrii revine la nc a 1. Crearea unei fabrici pentru manipularea ierelor pe disc s FileItemFactory factory = new DiskFileItemFactory(); 2. Crearea unei unelte de arcare nc ServletFileUpload upload = new ServletFileUpload(factory);

3. Analiza (parsarea) mesajului furnizat de client List fileItems = upload.parseRequest(req); Fiecare element al listei implementeaz interfata FileItem. a Se pot xa parametrii dimensiunea zonei de pe disc destinat datelor de arcat a nc DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemorySize);

218

CAPITOLUL 9. SERVLET

catalogul temporar de retinere a datelor de arcat nc factory.setRepositoryPath(tempDirectory); sau direct DiskFileItemFactory factory = new DiskFileItemFactory( maxMemorySize, tempDirectory); dimensiunea maxim a unui ier a s upload.setSizeMax(maxRequestSize); 4. Prelucrarea elementelor arcate nc 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. cazul unui element care nu este de tip ier putem obtine numele i In s s valoarea atributului furnizat de client String name = item.getFieldName(); String value = item.getString(); 6. cazul unui ier putem aa numele cmpului input, numele ierului, In s a s dimensiunea ierului s String fieldName = item.getFieldName(); String fileName = item.getName(); long sizeInBytes = item.getSize(); 7. Dac dorim s salvm ierul pe calculatorul server atunci prelucrarea a a a s este

9.5. FILEUPLOAD

219

File uploadedFile = new File(...); item.write(uploadedFile); 8. Dac datele ierului se a s ncarc memoria calculatorului atunci prelua n crarea este InputStream in = item.getInputStream(); //preluarea datelor din fluxul in . . . in.close(); Alternativ, datele se pot retine ca un ir de octeti prin s byte[] data = item.get(); Exemplul 9.5.1 S se obtin n memoria serverului matricea continut ntra a a s un ier text. In ierul text, ecare linie contine o linie a matricei, iar eles mentele sunt separate prin spatii. Metoda getMatrix utilizat reface matricea din datele ierului. a s
1 2 3 4 5 6 7 8 9 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

package u pl oa d ; 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 . u t i l . ; import o r g . apache . commons . f i l e u p l o a d . d i s k . ; import o r g . apache . commons . f i l e u p l o a d . s e r v l e t . ; import o r g . apache . commons . f i l e u p l o a d . ; 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 = / u pl oa d ) 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 { boolean i s M u l t i p a r t = S e r v l e t F i l e U p l o a d . i s M u l t i p a r t C o n t e n t ( r e q ) ; 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 oad . 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 ) ;

220

CAPITOLUL 9. SERVLET

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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

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 < i ++){ m; 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 ) ) ; } } } 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 < i ++){ m; 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 ;

9.6. DESCARCAREA UNUI FISIER

221

89 90

} }

Pentru compilare se completeaz variabila de sistem classpath cu referinta a ctre ierul commons-fileupload-*.*.jar. a s 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 / formdata 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>

9.6

Descrcarea unui ier a s

Considerm cazul: a Exemplul 9.6.1 Fiierul ales de client dintr-o lista disponibil este descrcat s a a ind transmis navigatorului.
1 2 3 4 6 7 8

import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; 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 = / 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 )

222

CAPITOLUL 9. SERVLET

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

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 ) ; S t r i n g c a l e= webapps / download / r e s o u r c e s / ; try { F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( c a l e+ f i l e ) ; B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ; byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ; r e s . setContentType ( A p p l i c a t i o n / Octetstream ) ; r e s . addHeader ( ContentD i s p o s i t i o n , attachment ; f i l e n a m e=+ f i l e ) ; b i s . read ( bytes ) ; out . w r i t e ( b y t e s ) ; bis . close ( ); f i s . close (); out . c l o s e ( ) ; } 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 dv 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 ) ; } }

Rndul 18 are ca efect pstrarea numelui i a extensiei pentru ierul selectat a a s s a se descrca. a

9.7

Filtru

Un ltru se asemean unui servlet, dar activitatea a ntreprins vizeaz uzual a a contextul, adic ansamblul servletilor care fac parte din aplicatia Web. a Un ltru se declar ierul web.xml prin a n s <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> . . .

9.7. FILTRU

223

</web-app> Clasa ltrului implementeaz interfata Filter, adic metodele a a public void init(FilterConfig lterCong) throws ServletException public void destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain lterChain) throws IOException, ServletException Exemplul 9.7.1 Contextul myservlet contine doi servleti HelloServlet i Cm s mdcServlet, apelabili respectiv din hello.html, cmmdc.html. S se programeze a un ltru care Redirecteaz solicitarea /myservlet/hello ctre /cmmdc.html. a a Dac se cere ca natura rspunsului s e text/xml atunci invalideaz a a a a cererea. Servletii HelloServlet i CmmdcServlet sunt cei dezvoltati la s nceputul acestui capitol. Filtrul are codul
1 2 3 5 6 8 9 10 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27

import j a v a . i o . IOException ; 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 . ; 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 ( ) ; 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 ) ;

224

CAPITOLUL 9. SERVLET

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

} 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 ) ; } } } }

Fiierul web.xml este s


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

<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp O T P 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> < 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 elegerea aplicatiei prezentm i codul ierului cmmdc.html nt a s s


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

<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

9.8. SERVER APACHE-TOMCAT INCORPORAT

225

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

<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>

9.8

Server apache-tomcat ncorporat

Intr-o clas Java se poate a ncorpora un server tomcat care pot instalate n una sau mai multi serveti. Resursele necesare sunt continute apache-tomcat n *-embedded, iar ierele jar continute trebuie declarate variabila de sistem s n classpath. Sablonul 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 ( ) ; } } }

226

CAPITOLUL 9. SERVLET

Capitolul 10 Java Server Page JSP


10.1 Tehnologia JSP

Tipul tehnologiei JSP este denumit procesare de abloane (template ens gine). JSP este o tehnologie similar cu PHP, ASP.NET, apache-velocity, etc. a 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 prin a meniul File/Open a unui navigator, cu http://host:port/cale/doc.jsp referinta 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 elege calea de la catalogul webapps pn la catalogul ce nt a a contine ierul jsp. s Vom depozita ierele JSP s 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 care cale=JSPApp/jsp. n Astfel, schimbnd numele ierului Hello.html a s


1 2 3 4 5

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

Hello.jsp i plasndu-l catalogul jsp se obtine acelai efect, dar prelun s a n s crarea paginilor / documentelor este diferit. Fiierul html este prelucrat doar a s de programul navigator i poate deschis ca ier, timp ce ierul JSP este s s n s prelucrat de serverul Web cu aarea prin intermediul navigatorului. Prelus crarea efectuat de serverul Web const din transformarea paginii / documena a tului JSP ntr-un servlet, care este compilat i lansat executie. Din aceastr s n a cauz prima invocare a paginii / documentului JSP dureaz mai mult dect a a a apelrile ulterioare. a Fiierul JSP poate construit pe un document xhtml, avnd preambulul s a <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> sau document html 5. acest caz preambulul este In <!doctype html> Apelarea paginii / documentului JSP se face prin http://localhost:8080/JSPApp/jsp/Hello.jsp Exist dou moduri de a include elemente JSP a a ntr-un text html: prin elemente specice JSP. Fiierul are extensia jsp i se numete pagin JSP. s s s a prin elemente xml apartinnd spatiului de nume a http://java.sun.com/JSP/Page Fiierul poate avea extensia jsp sau jspx i se numete document JSP. s s s Comentariile JSP se scriu de forma <%-- Comentariu --%>

10.1. TEHNOLOGIA JSP

229

Considerm urmtorul exemplu introductiv: a a Exemplul 10.1.1 Putem aa valoarea unei variabile Java (de exemplu data s calendaristic) prin a 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 se utilizeaz operatorul de aare = atunci dup expresia de aat a a s a s nu se pune ;. Variabila predenit out este de tip javax.servlet.jsp.JspWriter. a 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 inglobat ntr-un text html se numete scriptlet. Sintaxa utis lizat este a 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 denete intervalul s de timp, de existenta al unui obiect, ind denit prin valorile: Valoare page request Domeniu de valabilitate pagina curent a pagina curent, n a paginile incluse i n s paginile ctre care se face o redirectare n a session sesiunea curent n a application pe durata rulrii aplicatiei a orice pagin In a Variabila out request response session page pageContext application exception Astfel String request.getParameter(String numeParametru) furnizeaz valoarea parametrului numeParametru dintr-un formular html. a Exemplul 10.1.2 Pagina JSP Hello: Clientul transmite numele paginii care i rspunde cu mesajul de salut Hi + nume + !. a 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= h t t p : / / l o c a l h o s t : 8 0 8 0 / j s p h e l l o / 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 i arhivarea servlet-ului o vom realiza prin intermediul lui s acest scop se creaz structura: apache-ant. In a
jsphello | |--> jsp | | | hello.jsp | |--> lib | |--> src | |--> web | | | web.xml | |--> web-files | | | index.html | build.xml

Fiierul web.xml este simplu s


1 3 4 5 7 8 9 10 11 12

<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp O T P 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> <welcomef i l e l i s t> <welcome f i l e >i n d e x . html</ welcome f i l e > <welcome f i l e >i n d e x . j s p</ welcome f i l e > </ welcomef i l e l i s t> </webapp>

232

CAPITOLUL 10. JAVA SERVER PAGE JSP

Fiierul build.xml prelucrat de apache-ant este s


1 2 3 4 6 7 8 9 10 12 13 14 15 16 17 18 19 20 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

<project b a s e d i r= . d e f a u l t= g e n e r a t e . war > <property name= d i s t . name v a l u e= j s p h e l l o /> <property name= d i s t . d i r v a l u e= d i s t /> <property name= b u i l d . d i r v a l u e= b u i l d /> <path i d= m y c l a s s p a t h > < f i l e s e t d i r= l i b > <include name= . j a r /> </ f i l e s e t> </path> <target name= i n i t > <delete d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r } /> <mkdir d i r= ${ d i s t . d i r } /> <mkdir d i r= ${ b u i l d . d i r }/ j s p /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> <mkdir d i r= ${ b u i l d . d i r }/WEB INF/ l i b /> </ target> <target name= c o m p i l e depends= i n i t > <javac 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= ${ b a s e d i r }/ s r c i n c l u d e a n t r u n t i m e= f a l s e d e s t d i r= ${ b u i l d . d i r }/WEB INF/ c l a s s e s /> </ target> <target name= g e n e r a t e . war depends= c o m p i l e > <copy t o d i r= ${ b u i l d . d i r } > < f i l e s e t d i r= ${ b a s e d i r }/web f i l e s > <include name= . html /> </ f i l e s e t> </copy> <copy t o d i r= ${ b u i l d . d i r }/ j s p > < f i l e s e t d i r= ${ b a s e d i r }/ j s p > <include name= . j s p /> <include name= . j s p x /> </ f i l e s e t> </copy> <copy t o d i r= ${ b u i l d . d i r }/WEB INF f i l e = ${ b a s e d i r }/web/web . xml / > <copy t o d i r= ${ b u i l d . d i r }/WEB INF/ l i b > < f i l e s e t d i r= ${ b a s e d i r }/ l i b > <include name= . j a r /> </ f i l e s e t> </copy> <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= ${ b u i l d . d i r } /> </ target> </ project>

10.1.1

Declaratii JSP

Printr-o declaratie JSP, putem deni cmpuri(variabile) i metode Java ce a s pot apoi folosite, respectiv apelate documentul respectiv. O declaratie n

10.1. TEHNOLOGIA JSP

233

JSP se denete printr-un marcaj s <%! . . . %> sau, format XML n <jsp:declaration> . . . </jsp:declaration> Exemplul 10.1.3 Calculul celui mai mare divizor comun a dou numere nata urale cu metoda de calcul este denit ntr-o declaratie JSP. a Pagina JSP a aplicatiei 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


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= h t t p : / / l o c a l h o s t : 8 0 8 0 / JSPApp/ 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 dou metode jspInit() i jspDestroy() care dac sunt declarate a a s a de programator atunci sunt executate la nceputul i la sfritul ciclului de s as viata a paginii / documentului JSP.

234

CAPITOLUL 10. JAVA SERVER PAGE JSP

Exemplul 10.1.4 Metoda jspInit initializeaz un numr cu 0 iar metoda a a jspDestroy aeaz numrul pe calculatorul serverului. Un client introduce s a a un numr care este adunat la cel retinut de pagina JSP. a Efectul metodei jspDestroy are loc urma opririi aplicatiei JSP. n 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>

10.1.2

Directive JSP

Directivele JSP xeaz informatii pentru tot documentul jsp. O directiv a a jsp se indic prin marcajul a <%@ directiv atribut1 atribut2 . . . %> a sau format XML n <jsp:directive.directiva atribut1 atribut2 . . . /> unde ecare atribut are sintaxa nume=valoare. Directivele pot : page, include, taglib. Directiva page. Mentionm atributele a

10.1. TEHNOLOGIA JSP

235

list de pachete separate prin , a text Informatia se poate regsi apelnd metoda a a getServletInfo() errorPage= adresa url a paginii ce trateaz exceptia a isErrorPage= "true | false" import= info= Directiva include permite includerea unor iere .html sau .jsp docus n ment <%@ include file=ier html, jsp %> s Includerea are loc locul care apare directiva. n n Referinta la ierul html sau jsp se face relativ la catalogul paginii JSP s initiale (adic cea care apare directiva). a n Directiva taglib indic bibliotecile de marcaje utilizate documentul a n jsp, avnd atributele a uri= uri - Universal Resource Identier - a bibliotecii de marcaje prefix= prexul marcajului

10.1.3

Marcaje JSP predenite

Un marcaj JSP denete o actiune care se execut timpul procesrii s a n a paginii jsp. Sintaxa marcajelor JSP seamn cu cea a marcajelor html sau a a xml <prefix : marcaj atribute />

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

Prelucrarea care urmeaz va cea din ierul mentional. Diferenta dintre a s cele dou elemente const faptul c include prevede revenirea a a n a n pagina JSP initial iar forward nu. a Referinta la ierul html sau jsp se face relativ la catalogul paginii JSP s initiale.

236

CAPITOLUL 10. JAVA SERVER PAGE JSP

cazul marcajelor <jsp: include>, <jsp: forward> se pot transIn mite parametri prin marcajele incluse <jsp:param name="nume" value=valoare "/> sau <jsp:params> <jsp:param name="nume" value=valoare "/> . . . . . . </jsp:params> <jsp : useBean id=numeComponentJava a class=numeClasa scope=domeniu />

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

Acest marcaj este echivalent cu codul Java numeComponentJava.setNumeProp(valoare). a <jsp : setProperty name=numeComponentJava property="*" /> a vizeaz toate proprietile componentei Java, xarea valorilor fcndua at a a se cu datele unui formular. Numele parametrilor din formularele de introducere a datelor trebuie s coincid cu identicatorii cmpurilor din a a a componenta Java corespunztoare. a <jsp : getProperty name=numeComponentJava a property=numeProp/>

Preia i aeaz valoarea cmpului numeComponentJava.numeProp. s s a a a

10.1.4

Pagini JSP cu componente Java

Clasa componentei Java care se va utiliza ntr-o pagin JSP trebuie inclus a a ntr-un pachet. Relum exemplul 10.1.2 cu o component Java corespunztoare numelui a a a din formularul index.html.

10.1. TEHNOLOGIA JSP

237

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 ; } }

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


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 pagina JSP, bine eles tergndu-l n nt s a din ierul html: s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

<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> <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>

238

CAPITOLUL 10. JAVA SERVER PAGE JSP

vederea generrii cu ant a arhivei war, desfurarea aplicatiei va In a as


jsphello | |---> jsp | | | hello.jsp | |---> lib | |---> src | | |---> jsp | | | | HelloBean.java | |---> web | | | web.xml | |---> web-files | | | index.html | build.xml

Exemplul 10.1.6 Pagin JSP pentru calculul celui mai mare divizor comun a cu metoda de calcul denit ntr-o component Java. a a Utiliznd documentului html din Exemplul 10.1.3 se denete componenta a s 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 ) { . . . } }

Instantiem o componenta Java i xm proprietile (adic transmitem s i a at a i parametri problemei) dup care apelm metoda ce calculeaz rezultatul dorit a a a pagina JSP: n
1 2

<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= />

10.1. TEHNOLOGIA JSP

239

3 4 5 6 7 8 9 10

<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 ( ) % s i < > %=o b j . getN ( ) % > este < %=o b j . getCmmdc ( ) % > </body> </html>

Exemplul 10.1.7 Generarea unei exceptii (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 t i f a c u t a l e g e r e a c o r e c t a ) ; a } % > </body> </html>

cu pagina de tratare a exceptiei (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 apachetomcat 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>

apelate prin

240

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

<html> <body> <form method=p o s 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 / 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>

10.2

JSP Standard Tag Library JSTL

JSTL este o familie de biblioteci de marcaje ce ofer o serie de faciliti a at activitii de realizare a paginilor Web. JSTL ajut la separarea activitii de at a at programare de aceea a proiectare (design) a paginii Web. JSTL este alctuit din 5 biblioteci: a a 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 functii ajuttoare a Instalarea bibliotecilor. Bibliotecile sunt livrate mpreun cu apachea tomcat-* catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin n ierele jstl.jar i standard.jar. s s Utilizarea bibliotecilor. vederea utilizrii, cele dou iere trebuie In a a s copiate catalogul lib al aplicatiei care utilizeaz bibliotecile. n a pagina / documentul JSP, o bibliotec utilizat trebuie declarat printrIn a a a o directiv taglib. a

10.2. JSP STANDARD TAG LIBRARY JSTL

241

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 o valoare a ntr-o variabil. a Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce va stoca valoarea expresiei. value optional Expresia care va evaluat i atribuit as a variabilei scope optional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application. Referirea la o variabil se face prin sintaxa ${numeVariabil } a a Referirea la valoarea unui cmp dintr-un formular se face prin a ${param.numeCmp} a Alturi de obiectul param, alte obiecte predenite sunt cookie, header, a initParam, pageContext. Se pot deni variabile cu acelai nume dar avnd domenii de valabilitate s a diferit. Referirea se face prin ${pageScope.numeVariabil }, a a ${requestScope.numeVariabil }, ${sessionScope.numeVariabil }, a a ${applicationScope.numeVariabil }. a Plasnd clauza empty a naintea unei variabile, ${empty numeVariabil }, a se obtine false sau true dup cum variabila are sau nu atribuit o a a valoare. c:remove Sterge o variabil. a Atribute ale marcajului: Atribut Fel Descriere var obligatoriu Numele variabilei ce se terge. s scope optional Domeniul de valabilitate al variabilei. Unul din valorile: page, request, session, application.

242 c:out Aeaz o valoare. s a Atribute ale marcajului: Atribut value default

CAPITOLUL 10. JAVA SERVER PAGE JSP

Fel Descriere obligatoriu Valoarea ce se evalueaz i se aeaz. as s a optional Cea ce se aeaz cazul care s a n n expresia nu poate evaluat. a escapeXml optional true / false. Valoarea implicit este true. a Pe false interpreteaz caracterele din value a ca i cod html. s c:if Test, vericarea unei conditii. Atribute ale marcajului: Atribut Fel Descriere test obligatoriu Conditia de test. var optional Numele variabilei ce va stoca valoarea testului. scope optional Domeniul de valabilitate al variabilei denit anterior. a cazul care conditia are valoarea true se prelucreaz corpul marcaIn n a jului, caz contrar, acesta este ignorat. n Exemplul 10.2.1 Preluarea datelor unui formular cu cmpurile de ina trare nume, prenume i email se face prin pagina JSP s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

< T L H M> <% 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 % @ > <O Y B D> <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 >

10.2. JSP STANDARD TAG LIBRARY JSTL

243

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 D > O Y </H M > T L

c:choose Marcajul de selectie poate contine oricte marcaje c:when a i cel mult un marcaj c:otherwise. Fiecare marcaj c:when contine s obligatoriu atributul test. Dac a ntr-un marcaj c:when conditia are valoarea true, atunci se prelucreaz corpul acelui marcaj. cazul care a In n toate marcajele c:when au fost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcaj fr atribute). aa c:forEach Ciclu. Atribute ale marcajului: Atribut items var Fel Descriere optional Colectia care se parcurge. optional Numele variabilei care se stocheaz n a valoarea elementului curent. begin optional Valoarea initial a variabilei var. a end optional Valoarea nal a variabilei var. a step optional Valoarea pasului de iterare. Implicit este 1. varStatus optional Informatii despre elementul curent. Variabila varStatus are cmpurile: a index valoarea curent a elementului dup care se realizeaz cia a a clarea; count numrul iteratiei curente; a first are valoarea true dac este primul element al ciclului; a last are valoarea true dac este ultimul element al ciclului; a Exemplul 10.2.2 Lista parametrilor formularului de apelare a exemplului anterior se aeaz prin: s a
<h2> Lista parametrilor din formular </h2> <ul> <c:forEach items="${param}" var="p"> <li> <c:out value="${p}" />

244

CAPITOLUL 10. JAVA SERVER PAGE JSP

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

Exemplul 10.2.3 Lista parametrilor unui header se aeaz prin: s a

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

Exemplul 10.2.4 Evidentierea 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 aceai functionalitate ca i clasei java.util.String a s s Tokenizer. Atribute ale marcajului: Atribut value Fel Descriere obligatoriu Valoarea ce se evalueaz i se aeaz. as s a expresiei. default optional Cea ce se aeaz cazul care s a n n expresia nu poate evaluat. a escapeXml optional true / false. Valoarea implicit este true. a Pe false interpreteaz caracterele din value a ca i cod html. s c:import Permite includerea altor pagini JSP pagina curent. n a Atribute ale marcajului:

10.2. JSP STANDARD TAG LIBRARY JSTL

245

Atribut Fel Descriere url obligatoriu Adresa documentului importat. context optional Context-ul paginii / documentului importat. Simbolul /, urmat de numele unei aplicatii de pe acelai server. s var optional Numele variabilei care va stocat n documentul importat. scope optional 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 atribute name i value. Acesti parametri se a s transmit cu metoda get. c:redirect Redirectarea activitatea ctre o alt pagin. a a a Atribute ale marcajului: Atribut Fel Descriere url obligatoriu Adresa paginii ctre care se face redirectarea. a context optional Context-ul paginii ctre care se face redirectarea. a Simbolul /, urmat de numele unei aplicatii de pe acelai server. s Prin redirectare, parametrii nu sunt retransmii automat mai departe. s c:url Retine adrese URL. Atribute ale marcajului: Atribut Fel Descriere value obligatoriu Adresa documentului de retinut. context optional Context-ul documentului. Simbolul /, urmat de numele unei aplicatii de pe acelai server. s var optional Numele variabilei care va stocat n a adresa documentului. scope optional Domeniul de valabilitate al variabilei var. Unul din valorile: page, request, session, application.

246

CAPITOLUL 10. JAVA SERVER PAGE JSP

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 referinta la baza de date. a Atribute ale marcajului: Atribut dataSource driver url username password var scope Fel optional optional optional optional optional optional optional Descriere Referinta 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 referinta 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 optional optional optional obligatoriu optional Descriere Fraza sql Referinta la baza de date Linia de la care se ncepe interogarea Numrul maxim de rezultate acceptate a Variabila cu rezultatele interogrii a 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 optional Referinta la baza de date Exemplul 10.2.5 S se aeze lista din agenda de adrese e-mail creat n a s a exemplul din Cap. Servlet.

10.3. MARCAJE JSP PERSONALE

247

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

< T L H M> <% 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 % @ > <O Y B D> <p> <s q l : s e t D a t a S o u r c e 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 D > O Y </H M > T L

10.3

Marcaje JSP personale

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

10.3.1

Marcaje fr atribute i fr corp. a a s a a

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

248

CAPITOLUL 10. JAVA SERVER PAGE JSP

2. Descriptorul de bibliotec de marcaje JSP, care leag clasa de denitie a a a marcajului cu identicatorul bibliotecii de marcaje. 3. Marcajul taglib a ierului web.xml, care permite serverului Web s s a gseasc descriptorul bibliotecii de marcaje. a a 4. Fiierul JSP ce utilizeaz marcajul JSP (clientul). s a Exemplicm acest tehnologie prin a a Exemplul 10.3.1 S se realizeze un marcaj dateTag, a crui efect s e a a a aarea datei calendaristice. s 1. Clasa de denitie a comportamentului marcajului. Programul const a din: (a) Importul pachetelor import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; Aceste pachete se gsesc ierul jsp-api.jar. a n s (b) Un marcaj fr atribute i fr corp trebuie s extind clasa TagSupport aa s aa a a i s suprascrie metoda doStartTag, care denete activitatea ins a s treprins cnd este alnit marcajul a a nt ntr-un document jsp. Metoda trebuie s returneze constanta SKIP BODY. a public class NumeClasa extends TagSupport{ public int doStartTag(){ . . . return SKIP_BODY; } } (c) Scrierea uxul de ieire se face cu un obiect JspWriter, care se n s obtine cu pageContext.getOut(). Metoda print a clasei JspWriter poate genera o exceptie IOException. Textul surs al clasei de denitie a comportamentului marcajului dateTag a este:

10.3. MARCAJE JSP PERSONALE

249

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 . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; import j a v a . u t i l . ; 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 de marcaje JSP este dependent de versiunea a tomcat folosit. Acest ier trebuie s aib extensia tld (Taglib Lana s a a guage Denition). Localizarea acestui ier este denit elementul s a n taglib din web.xml. cazul unei distributii apache-tomcat-5.*, In acest ier este (mylibtag.tld): s
<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E t a g l i b O T P 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 /webj 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> <tagc l a s s> j s p . DateTag </ tagc 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 contine identicatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib. Pentru ecare marcaj propriu se completeaz un marcaj tag. Pentru un a marcaj propriu fr atribute elementele acestui marcaj sunt aa (a) name Numele simbolic al marcajului.

250

CAPITOLUL 10. JAVA SERVER PAGE JSP

(b) tag-class Referinta la ierul class al clasei de denitie a compor s tamentului marcajului propriu. Referinta se face relativ la catalogul ...\WEB-INF\classes (c) description Descrierea marcajului propriu. (d) body-content cazul nostru are valoarea EMPTY. cazul unui In In marcaj cu corp se d valoarea JSP. a 3. Marcajul taglib din ierul web.xml s
<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 Locatia ierului descriptor de bibliotec de mar s a caje (numele calicat al ierului, adic alctuit din cale plus numele s a a ierului). s Astfel elementele constitutive se vor gsi a n: webapps |--> mytag | |--> WEB-INF | | |--> classes | | | |--> jsp | | | | |--> DateTag.class | | | web.xml | | | mylibtag.tld | |--> jsp | | | dateTag.jsp 4. Marcajele proprii se utilizeaz cu sintaxa a <prex : NumeMarcaj />

10.3. MARCAJE JSP PERSONALE

251

Referinta la catalogul cu toate componentele necesare marcajului i pre s xul se xeaz directiva taglib. a n Un ier jsp care utilizeaz marcajul realizat este (dateTag.jsp): s a

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>

10.3.2

Marcaje cu atribute i fr corp. s a a

Realizm un marcaj ziuaTag cu un atribut ziua care va aat momentul a s n prelucrrii marcajului. a 1. Pentru ecare atribut clasa ce denete actiunea marcajului trebuie s s a contin o metod a a public void setNumeAtribut(String value){...} care preia valoarea atributului dat de parametrul value. a Exemplul 10.3.2 Pentru exemplul enuntat aceast clas este a a

1 2 3 4 6 7 9

package j s p ; import j a v a x . s e r v l e t . j s p . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; 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 ) {

252

CAPITOLUL 10. JAVA SERVER PAGE JSP

10 11 13 14 15 16 17 18 19 20 21 22 23

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. descriptorul bibliotecii de marcaje pentru ecare atribut se denete In s un marcaj <attribute>...< /attribute> avnd incluse marcajele a Nume marcaj Semnicatie name numele atributului required true | false dup cum atributul e a obligatoriu sau nu rtexprvalue true | false dup cum atributul a se poate utiliza ntr-o expresie < %= numeAtribut % > Fel obligatoriu obligatoriu optional

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>

3. Utilizarea acestui marcaj este exemplicat n

1 2 3 4 5 6 7

<html> <body> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ 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

10.3. MARCAJE JSP PERSONALE

253

8 9 10 11 12 13 14 15 16 17 18

<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 at a > 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.

metoda doStartTag valoarea returnat trebuie s e EVAL BODY INCLUDE, In a a loc de SKIP BODY. n descriptorul bibliotecii de marcaje apare In <body-content> JSP </body-content> loc de EMPTY. n Dac se dorete ca marcajul s execute actiuni dup interpretarea corpului, a s a a atunci acele activiti sunt denite metoda doEndTag. Aceast metod at n a a returneaz valoarea EVAL PAGE sau SKIP PAGE dup cum se dorete sau nu a a s continuarea procesrii paginii jsp. a Exemplul 10.3.3 Fie marcajul modTag care modica un text n caractere mari sau mici dup valoarea atributului trans. Acest marcaj poate include ale a elemente.

254

CAPITOLUL 10. JAVA SERVER PAGE JSP

Codul clasei ce prelucreaz marcajul este a


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 . ; import j a v a x . s e r v l e t . j s p . t a g e x t . ; import j a v a . i o . ; 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 cu a


<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> <name> trans </name> <required> true </required> <rtexprvalue> true </rtexprvalue> </attribute> </tag>

O pagin de utilizare a marcajului modTag cu un corp nevid este a


1

<html>

10.3. MARCAJE JSP PERSONALE

255

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

<body> <form method= g e t action= h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ 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 cu modtextTag.jsp a
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>

256

CAPITOLUL 10. JAVA SERVER PAGE JSP

Capitolul 11 Extensii servlet


11.1 Aplicatii Web prin Hessian

Protocolul de serializare Hessian


Dezvoltat de rma Caucho Technologies i lansat in 2007 Hessian este s un protocol pentru serializare / deserealizare bazat pe reprezentarea binar a a datelor: Reprezentarea serializat a ncepe cu o liter (cod ASCII, 1 octet) i este a s urmat de reprezentarea binar a continutului. a cazul colectiilor (List, Map), se concateneaz reprezentrile compoIn a a nentelor, iar sfritul este indicat prin caracterul z. as Tip boolean int long double java.util.Date String xml java.util.List java.util.Map null Reprezentare T, F Ireprezentarea binar pe 4 octeti a Lreprezentarea binar pe 8 octeti a Dreprezentarea binar pe 8 octeti a dreprezentarea binar pe 8 octeti a Sreprezentarea codicat UTF8 a Xreprezentarea codicat UTF8 a Vreprezentare binar z a Mreprezentare binar z a N 257

258

CAPITOLUL 11. EXTENSII SERVLET

Aplicatii distribuite prin Hessian


Dezvoltarea unei aplicatii distribuite bazate pe protocolul de serializare Hessian se bazeaz pe extinderea clasei com.caucho.hessian.server.HessianServlet. a acest scop In 1. Se denete o interfata POJO (denumit de exemplu MyService); s 2. Se implementeaz interfata a ntr-o clas ce extinde HessianServlet a import com.caucho.hessian.server.HessianServlet; public class MyServiceImpl extends HessianServlet implements MyService{ implementarea metodelor interfetei } 3. Se lanseaz servlet-ul MyServiceImpl prin intermediul unui server Web a ncorporat. Utiliznd apache-tomcat-embedded codul poate a
1 2 3 5 6 7 8 9 10 12 13 15 16 18 19 20 21 22 23 24 25

mport 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 H e s s i a n S e r v l e t { 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 ) ; 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 , s e r v l e t N a m e , new MyServiceImpl ( ) ) ; c t x t . a d d S e r v l e t M a p p i n g ( /numeApel , s e r v l e t N a m e ) ; 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 ( ) ; } } }

4. Se realizeaz un program client, utiliznd ablonul de apelare a a s

11.1. APLICATII WEB PRIN HESSIAN

259

String url = "http://host:port/numeApel"; HessianProxyFactory factory = new HessianProxyFactory(); MyService myService = (MyService) factory.create(MyService.class, url); . . . apelarea metodelor interfetei MyService Metoda POST este utilizat pentru transmiterea datelor. a Exemplul 11.1.1 Aplicatie Web bazat pe protocolul Hessian pentru metodele sayHello i pentru calculul celui mai mare divizor comun a dou numere nats a urale. Implementarea interfetei
1 3 4 5 6

package h e s s i a n a p p ; public i n t e r f a c e MyService { String sayHello ( String str ) ; long cmmdc( long m, long n ) ; }

este clasa
1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21

package h e s s i a n a p p ; import com . caucho . h e s s i a n . s e r v e r . H e s s i a n S e r v l e t ; public c l a s s MyServiceImpl extends H e s s i a n S e r v l e t implements MyService { public long cmmdc( long m, long n ) { long r , c ; do{ c=n ; r= %n ; m m ; =n n=r ; } while ( r ! = 0 ) ; return c ; } public S t r i n g s a y H e l l o ( S t r i n g s t r ) { return Hi + s t r+ ! ; } }

Codul clientului poate


1 2 3 4 6

package h e s s i a n c l i e n t ; import com . caucho . h e s s i a n . c l i e n t . H e s s i a n P r o x y F a c t o r y ; import h e s s i a n a p p . MyService ; import j a v a . u t i l . S c a n n e r ; public c l a s s C l i e n t {

260

CAPITOLUL 11. EXTENSII SERVLET

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

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 t r i n g u r l = http :// l o c a l h o s t :9090/ h e s s i a n s e r v i c e ; H e s s i a n P r o x y F a c t o r y f a c t o r y = new H e s s i a n P r o x y F a c t o r y ( ) ; MyService m y S e r v i c e = ( MyService ) f a c t o r y . c r e a t e ( MyService . c l a s s , u r 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 ) ; System . out . p r i n t l n ( A p e l a r e a m e t o d e i s a y H e l l o \n ) ; System . out . p r i n t l n ( I n t r o d u c e t i numele : ) ; S t r i n g nume=s c a n n e r . n e x t ( ) ; System . out . p r i n t l n ( Raspuns : +m y S e r v i c e . s a y H e l l o ( nume ) ) ; System . out . p r i n t l n ( A p e l a r e a m e t o d e i cmmdc\n ) ; System . out . p r i n t l n ( m ) ; = long m c a n n e r . nextLong ( ) ; =s System . out . p r i n t l n ( n= ) ; long n=s c a n n e r . nextLong ( ) ; System . out . p r i n t l n ( Raspuns : +m y S e r v i c e . cmmdc(m, n ) ) ; } }

11.2

Google App Engine - GAE

Prezentm o modalitate de desfurare a unei aplicatii Web a as ntr-un produs sau platform de cloud computing. a Dintre produsele de cloud computing disponibile prezent amintim: n Amazons Elastic Compute Cloud -(EC2) produs de referint, dar coma ercial; Google App Engine; Microsoft Azure; cele urmeaz se va utiliza Google App Engine. In a GAE permite: arcarea unei aplicatii Web pe un simulator local al platformei de Cloud nc Computing; arcarea unei aplicatii Web pe platforma Google de Cloud Computing. nc prezent, pe platforma GAE se pot arca aplicatii realizate Java, In nc n Python i Go, alturi de care care pot aprea iere http, css, js. Exist cte s a a s a a o distributie distinct pentru ecare din aceste limbaje de programare. a Prezentm numai arcarea pe simulatorul local al platformei GAE, a nc n versiunea Java construit peste serverul Web jetty.

11.2. GOOGLE APP ENGINE - GAE

261

Instalarea produsului const din dezarhivarea ierului appengine-javaa s sdk-*. Utilizarea. vederea arcrii unui servlet pe simulatorul local se creaz In nc a a structura de cataloage i iere s s
www |--> | | | | | | | WEB-INF |--> classes | | *.class |--> lib | | *.jar | web.xml | appengine-web.xml index.html

Singurul ier specic GAE este appengine-web.xml. Codul acestui er este s s


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 ierului web.xml corespund servlet-ului, iar prin ierul index.html se s s apeleaz aplicatia Web. Parametrul action al elementului form are forma sima plicat action=/numeApel, unde numeApel coincide cu valoarea atributului a urlPattern. Dac aplicatia se a ncarc pe platforma Google de Cloud Computing atunci a trebuie completat elementul <application>. Lansarea simulatorului i arcarea se poate face prin comenzile s nc
set GAE\_HOME=. . .\appengine-java-sdk-* %GAE\_HOME%\bin\dev_appserver www

lansate ntr-o fereast DOS, catalogul care-l contine pe www. Aplicatia a n se apeleaz prin http://localhost:8080. Dac loc de index.html se utia a n lizeaz alt nume, atunci apelarea aplicatiei este http://localhost:8080/fiier.html. a s O aplicatie JSP se trateaz asemntor. a a a Distributia GAE pentru Java contine ablonul unei aplicatii s mpreun cu a un ier build.xml (appengine-java-sdk-*\demos\new project template) s prin intermediul cruia, cu ajutorul lui ant, se construiete catalogul www a s descris anterior. Exemplul 11.2.1 Servlet-ul CmmdcServlet instalat n platforma Google App Engine de Cloud Computing.

262

CAPITOLUL 11. EXTENSII SERVLET

Sablonul se copiaz zona de lucru sub numele appcmmdc i se com a n s pleteaz cu ierele servlet-ului (CmmdcServlet.java, cmmdc.html ) rezultnd: a s a
appcmmdc |--> html | | cmmdc.html |--> src | |--> WEB-INF | | | appengine-web.xml | | | web.xml | | CmmdcServlet.java | build.xml

Se execut cu ant obiectivul implicit din build.xml, urmat de lansarea simua latorului din interiorul catalogului appcmmdc. Deoarece numele ierului html s difer de index, aplicatia se apeleaz prin a a http://localhost:8080/cmmdc.html. Alternativ, aplicatia se poate construi cu Eclipse folosind o component a (plug-in) specic. a

Serviciul UserService
Serviciul permite utilizarea autenticrii i autorizrii Google. Aplicatia va a s a contine catalogul www\WEB-INF\lib ierul appengine-api-1.0-sdk-*.jar. n s Sablonul de utilizare const din a . . . import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; public class XXX extends HttpServlet{ public void doGet(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{ UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { String param=req.getParameter("param"); if(tip==null){ res.sendRedirect("/index.html"); } else{ . . . }

11.2. GOOGLE APP ENGINE - GAE

263

} else{ res.sendRedirect(userService.createLoginURL(req.getRequestURI())); } } } Exemplul 11.2.2 Aplicatia de calcul a celui mai mare divizor comun are co dul:
1 2 3 4 5 6 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

import import import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; com . g o o g l e . a p p e n g i n e . a p i . u s e r s . User ; com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e ; com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e F a c t o r y ;

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 ) throws S e r v l e t E x c e p t i o n , IOException { UserService userService = UserServiceFactory . getUserService ( ) ; User u s e r = u s e r S e r v i c e . g e t C u r r e n t U s e r ( ) ; i f ( u s e r != n u l l ) { 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==n u l l ) { r e s . s e n d R e d i r e c t ( /cmmdc . html ) ; } else { 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=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 =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 ( <p/> ) ; out . p r i n t l n ( <a h r e f =\/cmmdc . html\> R e l u a r e </a> ) ; out . p r i n t l n ( <p/> ) ; S t r i n g s i gn Ou t=u s e r S e r v i c e . createLogoutURL ( r e q . getRequestURI ( ) ) ; out . p r i n t l n ( <a h r e f =\+si g nO u t+\> S i g n out </a> ) ; 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 ( ) ;

264

CAPITOLUL 11. EXTENSII SERVLET

45 46 47 48 49 50 52 53 54 55 56

} } else { r e s . s e n d R e d i r e c t ( u s e r S e r v i c e . createLoginURL ( r e q . getRequestURI ( ) ) ) ; } } 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 ) ; } }

Varianta care n nlocuim servlet-ul i pagina de apelare cu o pagin JSP s a este


1 2 3 4 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 36 37 38 39 40 41 42 43

<% @ <% @ <% @ <% @

page page page page

contentType= t e x t / html ; c h a r s e t=UTF8 l a n g u a g e= j a v a % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . User % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e % > imp ort=com . g o o g l e . a p p e n g i n e . a p i . u s e r s . U s e r S e r v i c e F a c t o r y % >

<html> <body> <%! p u b l i c l o n g cmmdc( l o n g m, l o n g n ) { . . . }

% >

<% UserService userService = UserServiceFactory . getUserService ( ) ; User u s e r = u s e r S e r v i c e . g e t C u r r e n t U s e r ( ) ; i f ( u s e r != n u l l ) { % > <h1> C a l c u l u l CMMDC </h1> <p> I n t r o d u c e &#355; i : <form method= p o s t > <table border= 1 > <tr> <td> Primul num&#259; r </td> <td><input type= t e x t name=m s i z e= 20 value= 1 /><td> </ tr> <tr> <td> Al d o i l e a num&#259; r </td> <td><input type= t e x t name=n s i z e= 20 value= 1 /><td> </ tr> <tr> <td> <input type= submit value= C a l c u l e a z a /></td> <% String sm=r e q u e s t . g e t P a r a m e t e r ( m ) , sn=r e q u e s t . g e t P a r a m e t e r ( n ) ; l o n g x =0; i f ( sm==n u l l ) { sm= 1 ; sn= 1 ; } long m =Long . pa rse Lo ng ( sm ) , n=Long . pa rse Lo ng ( sn ) ; x=cmmdc(m, n ) ; % > <td> (< %=sm% ,< > %=sn% >)=< %=x% </td> > </ tr> </ table> </form>

11.2. GOOGLE APP ENGINE - GAE

265

45 46 47 48 49 50 51 52 53 54 55 56 57 58

<p> <a href=<%= u s e r S e r v i c e . createLogoutURL ( r e q u e s t . getRequestURI ( ) ) % >> S i g n out</a> <% } else{ % > <a href=<%= u s e r S e r v i c e . createLoginURL ( r e q u e s t . getRequestURI ( ) ) % >> S i g n i n</a> <% } % > </body> </html>

266

CAPITOLUL 11. EXTENSII SERVLET

Capitolul 12 Portlet
Prezentarea termenului de portlet se face mpreun cu cea de portal. Pora talul ca i portletul sunt aplicatii Web. Practic, un portal accesat aeaz s s a portlete ferestre distincte, portletele ind aplicatii pe care clientul le poate n folosi (Fig. 12.1, Fig. 12.2).

Figure 12.1: Portal - Portlet. O aplicatie portlet ndeplinete standardele JSR (Java Specication Res quest) 168 i JSR 286. s Portalul este o aplicatie Web cu functionalitile: at Container de portleti. Containerul este responsabil de initializarea i dis s trugerea portletilor, de transmiterea cererilor ctre portleti i de colectarea a s rspunsurilor. a Agregarea continuturilor (Content aggregator). Permite aarea i ges s s tionarea mai multor portlete. 267

268

CAPITOLUL 12. PORTLET

Figure 12.2: Aparitia portlet-etelor ntr-o pagin a unui portal. a

Asigur servicii dintre care amintim: a acces la portal pe baz de autenticare i autorizare. Odat autora s a izat, un client are acces la orice portlet. posibilitatea personalizrii portletelor de ctre clienti. a a Varietatea serviciilor variaz de la un portal la altul. a Portletul este o aplicatie Web care se aseamn cu servletul prin: a a Se instaleaz a ntr-un container. Genereaz continut dinamic. a Ciclul de viat este gestionat de container. a Interactioneaz cu clientul prin modelul request/reply. a Deosebirile unui portlet fata de un servlet sunt: Portletul posed mai multe variante de tratare a cererilor. a

12.1. APACHE-PLUTO

269

Prin conceptul de mod (mode) se specic variante distincte prin care a portletul reactioneaz. Sunt denite modurile VIEW, EDIT, HELP. a Actiunile corespunztoare sunt denite metodele doView, doEdit, a n doHelp. Prin WindowState se xeaz spatiul utilizat de portlet. Valorile varia abilei WindowState sunt NORMAL, MAXIMIZED, MINIMIZED. varianta In MAXIMIZED portletul ocup a ntreaga fereastr, timp ce varianta a n n MINIMIZED portletul apare ntr-o bar de titluri. a

12.1

Apache-pluto

Pentru dezvoltarea unui portlet vom folosi produsul Apache-pluto care genereaz un portal care se pot instala / dezinstala uor portlete. a n s Instalarea produsului. Dac se descarc varianta a a ncorporat serverul a n Web apache-tomcat, denumit pluto-bundle, atunci instalarea la dezarhivarea a ierului descrcat. s a Utilizarea produsului. Dintr-un navigator, portalul se apeleaz prin a http://host:8080/pluto/portal Accesul se face cu User name = password = pluto. Instalarea unui portlet se face 2 pai: n s 1. Desfurarea portlet-ului: Fiierul arhivat al portletului, avnd extenas s a sia war, se depune catalogul PlutoDomain. Apelnd managerul lui n a apache-tomcat din componenta Pluto admin se obtine instalarea portle tului. Alternativ, desfurarea portlet-lui se va obtine cu apache-ant cu utias lizarea unui ier build.xml dedicat. s 2. Publicarea portlet-ului se face prin componenta Pluto admin.

12.2

Dezvoltarea unui portlet

Compilarea i arhivarea unui portlet vederea desfurrii se va face s n as a rulnd ant cu ierul build.xml: a s

270

CAPITOLUL 12. PORTLET

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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <p r o j e c t name= p o r t l e t b u i l d default= d e p l o y b a s e d i r= . > <p r o p e r t y e n v i ro n m e nt= env /> < ! S e t CATALINA HOME or u s e D p l u t o . home=/p a t h / t o / tomcatw i t h p l u t o on command l i n e > <p r o p e r t y name= p l u t o . home v a l u e= ${ env .CATALINA HOME} /> <p r o p e r t y f i l e = b u i l d . p r o p e r t i e s /> < ! A l l j a r s used by your p o r t l e t need t o be i n l i b i n a d d i t i o n t o t h e p l u t o antt a s k s j a r > <path i d= p r o j e c t . c l a s s p a t h > < f i l e s e t d i r= l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> < f i l e s e t d i r= ${ p l u t o . home}/ l i b > <i n c l u d e name= . j a r /> </ f i l e s e t> </ path> <t a s k d e f name= a s s e m b l e c l a s s n a m e= o r g . apache . p l u t o . ant . AssembleTask c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h /> <t a r g e t name= a s s e m b l e > <a s s e m b l e webxml= ${webi n f . d i r }/web . xml p o r t l e t x m l= ${webi n f . d i r }/ p o r t l e t . xml d e s t f i l e = ${ b u i l d . d i r }/web . xml /> </ t a r g e t> <t a r g e t name= i n i t d e s c r i p t i o n= C r e a t e s b u i l d d i r s > <echo message=Ant v e r s i o n = ${ ant . v e r s i o n } /> <mkdir d e s c r i p t i o n= C r e a t e s b u i l d d i r e c t o r y i f needed d i r= ${ b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s war d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r }/WEB INF /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF/ c l a s s e s d i r e c t o r y i f needed d i r= ${ c l a s s b u i l d . d i r } /> <mkdir d e s c r i p t i o n= C r e a t e s WEB INF/ l i b d i r e c t o r y i f needed d i r= ${ w e b b u i l d . d i r }/WEB INF/ l i b /> </ 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 d e s c r i p t i o n= Compiles s o u r c e > <j a v a c c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h f o r k= y e s debug= t r u e d e b u g l e v e l= l i n e s , v a r s , s o u r c e d e s t d i r= ${ c l a s s b u i l d . d i r }

12.2. DEZVOLTAREA UNUI PORTLET

271

59 60 62 63 64 65 66 68 69 70 71 72 73 74 75 76 77 78 80 82 83 84 85 86 88 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 113 115 116 117

s r c d i r= ${ j a v a . s r c . d i r } /> </ t a r g e t> <t a r g e t name= war depends= c o m p i l e > < ! Move web f i l e s e x c l u d i n g web . xml > <copy t o d i r= ${ w e b b u i l d . d i r }/ > < f i l e s e t d i r= ${web . d i r } e x c l u d e s= / web . xml /> </ copy> < ! Move o t h e r n e c c e s s a r y l i b r a r i e s > <copy t o d i r= ${ w e b b u i l d . d i r }/WEB INF/ l i b / > < f i l e s e t d i r= ${ l i b . d i r } > <i n c l u d e name= / . j a r /> <e x c l u d e name= c a s t o r . j a r /> <e x c l u d e name= p l u t o . j a r /> <e x c l u d e name= p o r t l e t . j a r /> <e x c l u d e name= s e r v l e t . j a r /> <e x c l u d e name= j u n i t . j a r /> </ f i l e s e t> </ copy> < a n t c a l l t a r g e t= a s s e m b l e /> < ! C r e a t e war i n d e p l o y m e n t d i r e c t o r y > <war b a s e d i r= ${ w e b b u i l d . d i r } update= f a l s e w a r f i l e= ${ app . name } . war webxml= ${ b u i l d . d i r }/web . xml /> </ t a r g e t> <t a r g e t name= b u i l d depends= c l e a n , war /> <t a r g e t name= d e p l o y depends= b u i l d > <echo message= D e p l o y i n g t o p l u t o . home=${ p l u t o . home} /> < ! Remove former d e p l o y m e n t b e c a u s e sometimes tomcat d o e s n o t f u l l y r e d e p l o y a war > <d e l e t e d i r= ${ p l u t o . home}/ webapps /${ app . name} f a i l o n e r r o r= t r u e /> < ! Deploy war f i l e > <copy f i l e = ${ app . name } . war t o d i r= ${ p l u t o . home}/ PlutoDomain o v e r w r i t e= t r u e /> < ! Deploy c o n t e x t d e p l o y m e n t d e s c r i p t o r f o r Tomcat > <copy f i l e = ${ c o n f . d i r }/${ app . name } . xml t o d i r= ${ p l u t o . home}/ c o n f / C a t a l i n a / l o c a l h o s t o v e r w r i t e= f a l s e /> </ t a r g e t> <t a r g e t name= c l e a n d e s c r i p t i o n= C l e a n s b u i l d > <d e l e t e d i r= ${ b u i l d . d i r } f a i l o n e r r o r= f a l s e /> </ t a r g e t>

272

CAPITOLUL 12. PORTLET

119

</ p r o j e c t>

Fiierul de proprieti build.properties este s at


1 2 4 5 7 8 9 11 12 14 15 16 17 19 20 22 23 25 26 28 29

#b u i l d . p r o p e r t i e s #Standard p r o p e r t i e s f o r Ant b u i l d o f a P l u t o 1 . 1 p o r t l e t #module name app . name=NumePortlet #D i r e c t o r y t h a t h o l d s s o u r c e code s r c . d i r = s r c / main j a v a . s r c . d i r = ${ s r c . d i r }/ j a v a #D i r e c t o r y t h a t h o l d s documentation doc . d i r = d o c s #D i r e c t o r y t h a t h o l d s f i l e s t o be b u i l t i n t o a j a r , war o r e a r build . dir = build w e b b u i l d . d i r = ${ b u i l d . d i r }/ webapp c l a s s b u i l d . d i r = ${ w e b b u i l d . d i r }/WEB INF/ c l a s s e s #D i r e c t o r y t h a t h o l d s c o n f i g u r a t i o n c o n f . d i r = ${ s r c . d i r }/ r e s o u r c e files

#D i r e c t o r y t h a t h o l d s l i b r a r i e s r e q u i r e d t o b u i l d and run t h e c l a s s e s lib . dir = lib #D i r e c t o r y t h a t h o l d s webapp f i l e s web . d i r = ${ s r c . d i r }/ webapp # WEB INF d i r e c t o r y webi n f . d i r = ${web . d i r }/WEB INF

32 33

#D i r e c t o r y t h a t h o l d s f i l e s t o b u i l d d i s t r i b u t i o n d i s t . d i r = ${ b u i l d . d i r }/ d i s t

Pentru utilizarea acestui build.xml este nevoie de structura urmtoare de a cataloage NumePortlet |--> lib | | castor-1.1.1.jar | | commons-logging-1.0.4.jar | | pluto-ant-tasks-2.0.*.jar | | pluto-descriptor-api-1.1.6.jar | | pluto-descriptor-impl-1.1.6.jar | | pluto-util-2.0.*.jar | | pluto-container-2.0.0.jar | | jaxb-api-2.1.jar | | jaxb-impl-2.1.9.jar

12.3. ELEMENTE DE PROGRAMARE

273

|--> | | | | | | | | | | |

src |--> | | | | | | | | | |

main |--> | |--> | |--> | | | | |

java |--> pachetul portletului resource | NumePortlet.xml webapp |--> jsp | | fisierele jsp ale portletului |--> WEB-INF | | portlet.xml | | web.xml

Fiierele castor.1.1.1.jar, pluto-descriptor-api-*.jar, pluto-descriptor-impl-*.jar, s portlet-container-*.jar se copiaz din catalogul PLUTO HOME\shared\lib. a Fiierul web.xml de mai sus este s
2 4 5 6 7 8 10

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp xmlns= h t t p : // j a v a . sun . com/xml/ ns / j 2 e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / j 2 e e h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /weba p p 2 4 . xsd version= 2 . 4 > </webapp>

Continutul nal al acestui ier rezult urma obiectivului ant assemple, s a n care se preiau date din ierul de congurare al portletului portlet.xml. n s Editarea ierului portlet.xml este sarcina programatorului. s Fiierul NumePortlet.xml este utilizat la desfurarea aplicatie, ind copiat s as catalogul conf\Catalina\localhost al lui apache-tomcat sau Apache-pluto. n Acest ier are continutul: s
1 2

<Context path= NumePortlet docBase= . . \ PlutoDomain \ NumePortlet . war c r o s s C o n t e x t= t r u e />

12.3

Elemente de programare

Orice portlet implementeaz interfata Portlet. Interfata Portlet declar a a 4 metode public interface Portlet{

274

CAPITOLUL 12. PORTLET

public void init(PortletConfig config) throws PortletException; public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException; public void render(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException; public void destroy(); } Metoda processAction prelucreaz cererea emis de containerul de portlete. a a La solicitarea containerului, metoda render regenereaz continutul unui porta let. Clasa GenericPortlet este implementarea initial a interfetei Portlet. a Extinznd clasa GenericPortlet, sarcina programatorului este s suprascrie a a metodele doView pentru tratarea modului VIEW; protected void doView(RenderRequest req,RenderResponse res) throws PortletException, IOException doEdit pentru tratarea modului EDIT; protected void doEdit(RenderRequest req,RenderResponse res) throws PortletException, IOException doHelp pentru tratarea modului HELP; protected void doHelp(RenderRequest req,RenderResponse res) throws PortletException, IOException init, destroy pentru initializarea, respectiv oprirea portletului. void init() throws PortletException void init(PortletConfig cong) throws PortletException void destroy() i eventual, s deneasc continutul metodei s a a public void processAction(ActionRequest request,ActionResponse response) throws PortletException, java.io.IOException;

12.3. ELEMENTE DE PROGRAMARE

275

Metoda processAction este apelat containerul portlet-ului vederea satisa n facerii unei actiuni (redirectare, schimbarea modului, a spatiului alocat portlet ului, etc.). Exemplul 12.3.1 Portletul HelloWorld.
1 2 3 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 22 23

package h e l l o ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s H e l l o W o r l d P o r t l e t extends G e n e r i c P o r t l e t { protected void doView ( RenderRequest r e q u e s t , RenderResponse r e s p o n s e ) throws P o r t l e t E x c e p t i o n , IOException { r e s p o n s e . setContentType ( t e x t / html ) ; r e s p o n s e . g e t W r i t e r ( ) . p r i n t l n ( H e l l o World ! ) ; } // A l t a v a r i a n t a de programare / p u b l i c v o i d doView ( RenderRequest req , RenderResponse r e s ) t h r o w s P o r t l e t E x c e p t i o n , IOException { r e s . s e t C o n t e n t T y p e ( t e x t / html ) ; P r i n t W r i t e r o u t=r e s . g e t W r i t e r ( ) ; o u t . p r i n t l n (<h2 >); o u t . p r i n t l n ( H e l l o World ! ) ; o u t . p r i n t l n (</h2 >); } / }

Fiierul portlet.xml este s


1 2 3 4 5 6 7 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 ?> <p o r t l e t app xmlns= h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 2 0 . xsd version= 1 . 0 x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd > < p o r t l e t> <d e s c r i p t i o n>H e l l o World a s a p o r t l e t app</ d e s c r i p t i o n> <p o r t l e t name>H e l l o W o r l d P o r t l e t</ p o r t l e t name> <d i s p l a y name>H e l l o World P o r t l e t</ d i s p l a y name> <p o r t l e t c l a s s> h e l l o . H e l l o W o r l d P o r t l e t</ p o r t l e t c l a s s> <s u p p o r t s> <mimet y p e>t e x t / html</mimet y p e> <p o r t l e t mode>VIEW p o r t l e t mode> </ </ s u p p o r t s> <p o r t l e t i n f o> < t i t l e>H e l l o World P o r t l e t</ t i t l e> </ p o r t l e t i n f o> </ p o r t l e t> </ p o r t l e t app>

276

CAPITOLUL 12. PORTLET

Exemplul 12.3.2 Evidentierea modurilor VIEW, EDIT i HELP. s

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

package h e l l o p l u t o ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s H e l l o P l u t o P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <s t r o n g >H e l l o P l u t o i n view mode</s t r o n g > ) ; } public void doEdit ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <i >H e l l o P l u t o i n e d i t mode</i > ) ; } public void doHelp ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <u>H e l l o P l u t o i n h e l p mode</u> ) ; } }

Fiierul portlet.xml este s


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

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?> <p o r t l e t app xmlns= h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 2 0 . xsd v e r s i o n= 1 . 0 xmlns : x s i= h t t p : / /www. w3 . o r g /2001/XMLSchemai 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 : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t a p p 1 0 . xsd > <p o r t l e t > <d e s c r i p t i o n >H e l l o P l u t o a s a p o r t l e t app</ d e s c r i p t i o n > <p o r t l e t name>H e l l o P l u t o P o r t l e t </ p o r t l e t name> <d i s p l a y name>H e l l o Pluto </ d i s p l a y name> <p o r t l e t c l a s s >h e l l o p l u t o . H e l l o P l u t o P o r t l e t </ p o r t l e t c l a s s > <s u p p o r t s > <mimetype>t e x t / html</mimetype> <p o r t l e t mode>VIEW</ p o r t l e t mode> <p o r t l e t mode>EDIT</ p o r t l e t mode> <p o r t l e t mode>HELP</ p o r t l e t mode> </s u p p o r t s > <p o r t l e t i n f o > < t i t l e >H e l l o P l u t o P o r t l e t </ t i t l e > </ p o r t l e t i n f o > </ p o r t l e t > </ p o r t l e t app>

12.3. ELEMENTE DE PROGRAMARE

277

Exemplul 12.3.3 Portletul Hello. Portletul aeaz o zon text de introducs a a ere a unui nume i un buton. Odat introdus numele, la apsarea butonului se s a a aaez textul Hello nume i un buton de reluare. s a s
1 3 4 5 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 34 35 36 37 38 39 40 41 42 43 44

package h e l l o n a m e ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; import j a v a . u t i l . Enumeration ; public c l a s s H e l l o N a m e P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t 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 nume=( S t r i n g ) r e q . g e t P a r a m e t e r ( name ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; i f ( nume==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / i n p u t . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { // V a r i a n t a cu a f i s a r e p r i n View / Writer o u t=r e s . g e t W r i t e r ( ) ; o u t . w r i t e ( H e l l o + nume ) ; PortletURL renderURL=r e s . createRenderURL ( ) ; renderURL . s e t P o r t l e t M o d e ( P o r t l e t M o d e .VIEW) ; renderURL . setWindowState ( WindowState .NORMAL) ; o u t . w r i t e (<p><a h r e f =\+renderURL . t o S t r i n g ()+\> R e l u a r e </a >); / // V a r i a n t a cu a f i s a r e p r i n t r un f i s i e r j s p prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / ou tp ut . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a Enumeration params=r e q . getParameterNames ( ) ; while ( params . hasMoreElements ( ) ) { S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ; S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ; r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ; } } }

Fiierele input.jsp i output.jsp au codurile s s


1 2 3 4 5 6

<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <div a l i g n= c e n t e r > I n t r o d u c e &#355; i numele : <br/> <form action=< p o r t l e t : actionURL />

278

CAPITOLUL 12. PORTLET

7 8 9 10 11 12 13

method=POST> <br> <input type= t e x t name=name /> <br> <input type= submit name= submitButton value=Apasama /> </form> </ div>

i respectiv s
1 2 3 4 5 6 7 8 9 10

<% t a g l i b u r i= h t t p : // j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <p> <% S t r i n g r e s u l t= H e l l o +r e n d e r R e q u e s t . g e t P a r a m e t e r ( name)+ ! ; out . p r i n t l n ( r e s u l t ) ; % > <p><a h r e f=<p o r t l e t : r e n d e r U R L p o r t l e t M o d e= view windowState= normal />> Reluare </ a> .

Exemplul 12.3.4 Cel mai mare divizor comun a dou numere naturale ntra un portlet. Variant care calculul este programat portlet. a n n
1 3 4 5 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 27 28 29 30 31

package cmmdc ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; import j a v a . u t i l . Enumeration ; public c l a s s CmmdcPortlet extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; S t r i n g r e z=r e q . g e t P a r a m e t e r ( r e z ) ; i f ( r e z==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / i n p u t . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p / ou tp ut . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a 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 ) ; long n=Long . p ars eL ong ( sn ) ; long c=cmmdc(m, n ) ;

12.3. ELEMENTE DE PROGRAMARE

279

32 33 35 37

r e s . s e t R e n d e r P a r a m e t e r ( r e z , (new Long ( c ) ) . t o S t r i n g ( ) ) ; } private long cmmdc( long m, long n ) { . . . } }

Fiierele inputCmmdc.jsp i outputCmmdc.jsp au codurile s s


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

<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <div a l i g n= c e n t e r > <form action=< p o r t l e t : actionURL /> method=POST> <table border= 1 > <tr> <td> Primul num&#259; r </td> <td> <input type= t e x t name=m /> </td> </ tr> <tr> <td> Al d o i l e a num&#259; r </td> <td> <input type= t e x t name=n /> </td> </ tr> <tr> <td> <input type= submit name= submitButton value= C a l c u l e a z a /> </td> </ tr> </ table> </form> </ div>

i respectiv s
1 2 4 5 6 7 8 10 11 12 13

<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > < p o r t l e t : d e f i n e O b j e c t s /> <P > <% String r e s u l t=Cmmdc +r e n d e r R e q u e s t . g e t P a r a m e t e r ( r e z )+ ! ; out . p r i n t l n ( r e s u l t ) ; % > <P > <a href=< p o r t l e t : renderURL p o r t l e t M o d e= view windowState= normal />> Reluare </a>

Variant care calculul este programat a n ntr-o component Java a (bean) i care este apelat pagina jsp de aare a rezultatului. s n s
1 3 4 5 7

package cmmdc ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; import j a v a . u t i l . Enumeration ; public c l a s s CmmdcPortlet extends G e n e r i c P o r t l e t {

280

CAPITOLUL 12. PORTLET

9 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

public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { r e s . setContentType ( t e x t / html ) ; P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ; S t r i n g sb=r e q . g e t P a r a m e t e r ( submitButton ) ; i f ( sb==n u l l ) { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p /inputCmmdc . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } else { prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( / j s p /outputCmmdc . j s p ) ; prd . i n c l u d e ( req , r e s ) ; } } public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s ) throws IOException , P o r t l e t E x c e p t i o n { // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a Enumeration params=r e q . getParameterNames ( ) ; while ( params . hasMoreElements ( ) ) { S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ; S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ; System . out . p r i n t l n ( >> parameterName = + parameterName + <=> p a r a m e t e r V a l u e = + p a r a m e t e r V a l u e ) ; r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ; } } }

Codul componentei Java


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

public c l a s s CmmdcBean{ private S t r i n g m ; = private S t r i n g n= ; 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 cmmdc ( ) { long m0=Long . pa rs eL ong (m) ; long n0=Long . pa rse Lo ng ( n ) ; long c , r ; do{ c=n0 ; r=m0%n0 ; m0=n0 ; n0=r ; }

12.3. ELEMENTE DE PROGRAMARE

281

28 29 30 31

while ( r ! = 0 ) ; return (new Long ( c ) ) . t o S t r i n g ( ) ; } }

Pagina outputCmmdc.jsp
1 2 3 5 7 8 9 10 11 12 13 14 15

<% t a g l i b u r i= h t t p : / / j a v a . sun . com/ p o r t l e t p r e f i x= p o r t l e t % @ > <j s p : useBean id=myCmmdcBean c l a s s=cmmdc . CmmdcBean scope= s e s s i o n /> <j s p : s e t P r o p e r t y name=myCmmdcBean p r o p e r t y= /> < p o r t l e t : d e f i n e O b j e c t s /> <P > <% String r e s u l t=Cmmdc +myCmmdcBean . cmmdc ( ) ; out . p r i n t l n ( r e s u l t ) ; % > <P > <a href=< p o r t l e t : renderURL p o r t l e t M o d e= view windowState= normal />> Reluare </a>

Variant care care calculul este programat a n ntr-un servlet. Servletul utilizat este cel prezentat capitolul Servlet, (9.2.2), dar inclus pachetul n n portlet-ului. Fiierul inputCmmdc.jsp are plus linia s n
<input type="hidden" name="tip" value="text/html"/>

iar codul clasei CmmdcPortlet, locul liniei n n


prd=getPortletContext().getRequestDispatcher("/jsp/outputCmmdc.jsp");

apare
prd=getPortletContext().getRequestDispatcher("/cmmdc");

adic locul invocrii paginii JSP, dispecerul apeleaz servletul. servlet a n a a In este esential furnizarea rezultatului format html. Pagina html generat se a n a ncarc fereastra portlet-ului. a n Fiierul web.xml, s naintea completrii prin ant, este a
1 3 4 5 6 7 9 10 11 12 14 15 16 17 18

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?> <webapp xmlns= h t t p : // j a v a . sun . com/xml/ ns / j 2 e e x m l n s : x s i= h t t p : //www. w3 . o r g /2001/XMLSchemai 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 : // j a v a . sun . com/xml/ ns / j 2 e e h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /weba p p 2 4 . xsd version= 2 . 4 > < s e r v l e t> <s e r v l e t name>CmmdcServlet</ s e r v l e t name> <s e r v l e t c l a s s>cmmdc . CmmdcServlet</ 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>CmmdcServlet</ s e r v l e t name> <u r l p a t t e r n>/cmmdc</ u r l p a t t e r n> </ s e r v l e t mapping> </webapp>

282

CAPITOLUL 12. PORTLET

Interfata PortletPreferences
Atribute, adic perechi de tip String (nume,valoare) denite ierul a n s portlet.xml prin <portlet-preferences> <preference> <name>nume_atribut</name> <value>valoare_atribut</value> <read-only>true|false</read-only> </preference> . . . </portlet-preferences> se transmit metodelor doView, doEdit i doHelp. Suportul este oferit prin s interfata PortletPreferences. Metode String getValue(String key, String def ) Returneaz valoarea primului atribut avnd numele key. lipsa atribua a In tului sau a valorii returneaz valoarea def. a String[] getValues(String key, String[] def ) Returneaz toate valorile atributului key. a Enumeration<String> getNames() Suport pentru acces la numele atributelor care au valoare. Map<String,String[]> getMap() Suport pentru acces la atribute. Un obiect care implementeaz interfata PortletPreferences se obtine a prin metoda getPreferences() a clasei RenderRequest. Exemplul 12.3.5 Portlet n care se preiau i se aeaz valori ale atributelor. s s a Codul portletului este

12.4. PRODUSE PORTAL

283

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

package p r e f ; import j a v a . i o . ; import j a v a x . p o r t l e t . ; public c l a s s P r e f P o r t l e t extends G e n e r i c P o r t l e t { public void doView ( RenderRequest req , RenderResponse r e s ) throws P o r t l e t E x c e p t i o n , IOException { P o r t l e t P r e f e r e n c e s p r e f s = req . g e tP r e f e re n c e s ( ) ; S t r i n g a t t r 1 = p r e f s . g e t V a l u e ( ATTR1 , a t t r 1 ) ; S t r i n g a t t r 2 = p r e f s . g e t V a l u e ( ATTR2 , a t t r 2 ) ; r e s . setContentType ( t e x t / html ) ; W r i t e r out=r e s . g e t W r i t e r ( ) ; out . w r i t e ( <s t r o n g >+a t t r 1+ <> +a t t r 2+</s t r o n g > ) ; } }

iar atributele din ierul portlet.xml sunt s


<portlet-preferences> <preference> <name>ATTR1</name> <value>Programare distribuita</value> <read-only>true</read-only> </preference> <preference> <name>ATTR2</name> <!-<value>Analiza numerica</value> --> <read-only>true</read-only> </preference> </portlet-preferences>

Al doilea atribut nu are valoare.Portletul aeaz textul Programare distribuita s a <> attr2.

12.4

Produse Portal

Termenul portal va desemna aplicatia informatic prin care o institutie comunic cu lumea exterioar a a a produsul informatic care realizeaz aplicatia amintit la pct. anterior a a cele ce urmeaz ne vom referi doar la produse portal care sunt containere In a de portlete. Dezvoltarea unui portal al unei organizatii se face pe produse specializate acestui scop. Dintre asemenea produsele gratuite amintim:

284 uPortal; jetspeed-2;

CAPITOLUL 12. PORTLET

care vor prezentate continuare. apache-pluto este ideal pentru testarea n portlet-elor.

12.4.1

uPortal

uPortal este un portal cadru, dezvoltat de JA-SIG (Java Architecture Special Interest Group) i a fost utilizat de mai multe universiti ca suport s at n constructia portalului specic. Instalarea produsului. Distributia produsului se face dou variante n a uPortal-*.*.* - uPortal-only; uPortal-*.*.*-quick-start care nglobeaz toate resursele necesare functionrii a a (apache-ant, apache-tomcat, apache-maven, HypersonicSQLDB). cele ce urmeaz utilizm varianta uPortal-quick-start. Instalarea produsului In a a revine la dezarhivarea ierului descrcat. s a urma dezarhivrii, catalogul uPortal HOME Lansarea portalului. In a n se gsete un ier build.xml, ale crei obiective asigur lansarea portalului1 . a s s a a Se completeaz ierul ant.bat cu referinta set JAVA HOME=... a s Lansarea portalului const executarea comenzii a n ant start De fapt se pornete SGBD HypersonicSQLDB i serverul Web apache-tomcat. s s Oprirea portalului se face prin executarea comenzii ant stop Dintr-un navigator, portalul se acceseaz prin a http://host:8080/uPortal
La prima executare a unei operatii asupra portalului, calculatorul trebuie s e conectat a la internet, deoarece mai multe resurse sunt descrcate prin apache-maven. Aceste resurse a se depun c:\Documents and Settings\adminName\.m2\repository. n
1

12.4. PRODUSE PORTAL

285

Accesarea portalului se poate face doar de detintorii unui cont (User a Name, Password). Administratorul (UserName=Password=admin) poate crea conturi noi. Instalarea unui portlet const desfurarea i publicarea lui. a n as s Compilarea i arhivarea portletului se poate face cu apache-ant acest s In scop se creaz structura a
|--> | |--> | | | | | | | | lib | portlet-api-1.0.jar pachetul portlet-ului |--> jsp | | *.jsp |--> WEB-INF | |--> classes | | | *.java | | web.xml | | portlet.xml build.xml

cu ierele *.java, *.jsp i portlet.xml corespunztoare portletului iar web.xml s s a este generic
1 2 3 4 5 6

<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?> < !D C Y E webapp PUBLIC O T P //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> </webapp>

Fiierul build.xml, compilare i arhivare este s s


1 3 4 5 7 8 9 10 11 13 14 15 16 17 18 19 21 22 23 24 25

<p r o j e c t name= p o r t l e t b u i l d default= war b a s e d i r= . > <p r o p e r t y name= package v a l u e= h e l l o /> <p r o p e r t y name= p o r t l e t . name v a l u e= H e l l o N a m e P o r t l e t /> <p r o p e r t y name= b u i l d . d i r v a l u e= b u i l d /> <path i d= p r o j e c t . c l a s s p a t h > < f i l e s e t d i r= 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= ${ package }/${ b u i l d . d i r } /> <mkdir d i r= ${ package }/${ b u i l d . d i r } /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/ j s p /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/WEB INF /> <mkdir d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ c l a s s e s /> </ 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 d e s c r i p t i o n= Compiles s o u r c e > <j a v a c c l a s s p a t h r e f= p r o j e c t . c l a s s p a t h d e s t d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ c l a s s e s s r c d i r= ${ package }/WEB INF/ c l a s s e s /> </ t a r g e t>

286

CAPITOLUL 12. PORTLET

27 28 29 30 31 32 33 34 36 37 38 39 41 43 44 45 47

<t a r g e t name= war depends= c o m p i l e > <copy t o d i r= ${ package }/${ b u i l d . d i r }/WEB INF/ f i l e = ${ package }/WEB INF/ p o r t l e t . xml /> <copy t o d i r= ${ package }/${ b u i l d . d i r }/ j s p > < f i l e s e t d i r= ${ package }/ j s p > <i n c l u d e name= . j s p /> </ f i l e s e t> </ copy> <war b a s e d i r= ${ package }/${ b u i l d . d i r } update= f a l s e w a r f i l e= ${ p o r t l e t . name } . war webxml= ${ package }/WEB INF/web . xml /> </ t a r g e t> <t a r g e t name= b u i l d depends= c l e a n , war /> <t a r g e t name= c l e a n d e s c r i p t i o n= C l e a n s b u i l d > <d e l e t e d i r= ${ b u i l d . d i r } f a i l o n e r r o r= f a l s e /> </ t a r g e t> </ p r o j e c t>

Desfurarea portlet-ului se face cu apache-ant utiliznd ierul build.xml as a s din uPortal HOME\uPortal-*.*.* prin ant deployPortletApp -DportletApp=arhiva portlet-ului.war urma acestei operatii, portlet-ul se dezarhiveaz uPortal HOME\apacheIn a n tomcat-*.*.*\webapps iar ierul web.xml este actualizat. s Publicarea portlet-ului se face cu rolul de administrator. Dup conectare a la uPortal 1. Clic Portlet Manager. 2. Click Register New Portlet. 3. Se selecteaz Portlet, clic Next. a 4. Se selecteaz portlet-ul care se dorete publicat. a s 5. Se completeaz Channel Functional Name. a 6. Din meniul Select Categories se alege cel putin o categorie. 7. Din meniul Select People and Groups se alege cel putin un membru. Astfel se xeaz cine are dreptul s utilizeze portletul. Portal System a a corespunde administratorului. 8. Din meniul Lifecycle Management se alege Published.

12.4. PRODUSE PORTAL

287

9. Clic Save. Un membru/grup selectat aeaz portlet-ul prin clic pe butonul Add Content s a urmat de selectarea categoriei i a portlet-ului. s Administratorul aeaz portletul prin s a 1. Clic pe butonul Customize 2. Clic pe un buton Add Channel corespunztor locului unde vrem s e a a pozitionat portlet-ul. 3. Steps for adding a new channel se selecteaz categoria, portletul i In a s este urmat de clic pe butonul Add Channel. Un client elimin un portlet prin clic pe butonul Remove din fereastra a portlet-ului. Administratorul portalului ntrerupe publicarea unui portlet prin clic pe butonul Portlet Manager, urmat de selectarea portletului i clic pe Removes Portlet.

12.4.2

Jetspeed-2

Jetspeed-2 este un portal cadru dezvoltat de apache. Instalarea se execut rulnd distributia jetspeed-installer-2.*.jar, cu Ina a stalation Type: Demo i Pipeline Type: JetUI. s Versiunea instalat a platformei jetspeed este construit peste o distributie a a apache-tomcat-*. Astfel, lansarea se face apelnd bin\startup.bat. a Portalul se acceseaz, dintr-un navigator, prin a http://localhost:8080/jetspeed Desfurarea unui portlet const copierea arhivei war corespunztoare, as a n a realizat 12.4.1, catalogul n n Jetspeed HOME \webapps\jetspeed\WEB-INF\deploy Pe rol de admin (acces cu valorile initiale username=password=admin), publicarea portlet-ului presupune 1. Clic pe icon-ul butonului Portlets. 2. Se caut portlet-ul dup numele declarat elementul <display-name> a a n din portlet.xml; 3. Clic pe butonul Add. Pentru a terge un portlet se apas butonul de s a nchidere al portlet-ului.

288

CAPITOLUL 12. PORTLET

Capitolul 13 Java Web Start


13.1 Java Web Start

O aplicatie Java destinat a utilizat pe un calculator poate valoricat a a a i s ntr-o retea, pe baza protocolului Java Network Launching Protocol - JNLP. Tehnologia poart numele de Java Web Start. a Aplicatia Java trebuie s satisfac o serie de restrictii: a a Aplicatia trebuie arhivat cu jar; a Eventualele date necesare aplicatiei se introduc prin intermediul unei interfete grace (swing, SWT, apache-pivot); Acces limitat la proprietile i resursele sistemului client. at s Aplicatiei i se ataeaz un ier xml, dar cu extensia jnlp, care se va apela s a s dintr-un navigator. Pentru acest ier folosim terminologia de ier jnlp. s s Fiierul jnlp xeaz: s a referinta URL a aplicatie (prin atributul codebase); arhivele jar utilizate (prin atributul href); clasa cu metoda main (prin atributul main-class). Ansamblul de resurse formeaz o aplicatie Web care poate desfurat a as a ntr-un server Web (Microsoft Internet Information Service (IIS), Apache) sau poate incorporat ntr-un servlet, caz care desfurarea va n as ntr-un server Web container de servlet. Artm activitile care trebuie aa at ntreprinse cazul unui exemplu simplu n dat de clasa VisualCmmdc.java. 289

290

CAPITOLUL 13. 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 ;

Interfata grac a programului este ilustrat Fig. 13.1 a a n

Figure 13.1: Interfata grac pentru rezolvarea ecuatiei algebrice. a

13.1. JAVA WEB START

291

Instalare ntr-un server Web


Pentru instalarea aplicatiei ntr-un server Web, se parcurg paii: s 1. Se arhiveaz aplicatia a jar cfv cmmdc.jar *.class 2. Se editeaz ierul launch.jnlp a s
1 2 3 4 5 6 7 8 9 10 11 12 13

<?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 /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> <a p p l i c a t i o n d e s c mainc l a s s=VisualCmmdc /> </ j n l p>

host se nlocuiete cu numele calculatorului care gzduiete serverul Web. s a s 3. Se creaz ier de apelare a aplicatiei (cmmdc.html ) a s
1 2 3 4 5 6 7 8 9

<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> <a href= h t t p : / / h o s t /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>

4. Ansamblul
cmmdc | cmmdc.jar | cmmdc.html | launch.jnlp

se copiaz serverul Web1 ( cazul IIS acest loc este catalogul a n n InetPub\wwwroot, iar cazul serverului Web Apache catalogul este n Apache Software Foundation\Apache*\htdocs).
1

Functioneaz pe un sistem cu procesor pe 32 biti i cu sistemul de operare Windows XP. a s

292

CAPITOLUL 13. JAVA WEB START

Dintr-un navigator, apelarea aplicatiei este http://host/cmmdc/cmmdc. html.

Aplicatia Java ca servlet


Pentru includerea aplicatie Java ntr-un servlet, primii trei pai prezentati s mai sus coincid. Singura diferent const continutul referintelor, dup host a a n a va apare portul utilizat de serverul Web container de servlet, uzual host:8080. 4. Intr-un catalog de lucru se creaz structura de cataloage i iere: a s s
app |--- cmmdc.jar |--- launch.jnlp WEB-INF |--- lib | |--- jnlp-servlet.jar |--- web.xml cmmdc.html

Fiierul jnlp-servlet.jar se preia din distributia JDK, din catalogul s sample/jnlp/servlet. Fiierul web.xml este s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

? xml v e r s i o n= 1 . 0 e n c o d i n g= i s o 88591?> < !D C Y E webapp O T P 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 ) > <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. Continutul catalogului de lucru se arhiveaz a ntr-un ier war. s jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html

13.1. JAVA WEB START

293

6. Utiliznd apache-tomcat sau jetty, de exemplu, ierul war se copiaz a s a n catalogul webapps al serverului web. Dintr-un navigator, apelarea aplicatiei se obtine prin http://host:8080/cmmdc/cmmdc.html. Dac aplicatia Java utilizeaz imagini grace acestea trebuie arhivate a a mpreun a cu aplicatia, de exemplu ntr-un catalog images. arcarea i aarea unei imagini programndu-se prin Inc s s a ClassLoader cl=this.getClass().getClassLoader(); URL file=cl.getResource("images/pic1.jpg"); Image img=Toolkit.getDefaultToolkit().getImage(file); graphics.drawImage(img,x,y,this); Dac aplicatia Java utilizeaz resurse externe date prin iere jar atunci: a a s 1. Toate ierele jar se certic. s a Certicarea resurselor se realizeaz rulnd succesiv a a (a) keytool -genkey -keystore myKeystore -alias myself (b) keytool -selfcert -alias myself -keystore myKeystore (c) jarsigner -keystore myKeystore resource.jar myself keytool.exe i jarsigner.exe se gsesc distributia jdk. s a n Primele dou actiuni au ca rezultat obtinerea certicatului myKeystore a iar ultima actiune reprezint a nglobarea certicrii arhiva resource.jar. a n Toate ierele jar trebuie s poarte aceai certicare. s a s 2. Fiierele jar certicate se depun catalogul app\lib. s n 3. ierul jnlp, elementul resources, pentru ecare ier jar utilizat In s n s se introduce declaratia <jar href=lib/resource.jar/> 4. plus, ierul jnlp ataat aplicatiei contine elementele In s s <security> <all-permissions /> </security>

294

CAPITOLUL 13. JAVA WEB START

Dac arhiva jar a aplicatiei Java este executabil atunci, ierul jnlp, a a n s elementul application-desc poate lipsi. Intr-o arhiv jar executabil, ierul MANIFEST.MF indic clasa cu metoda a a s a main i eventualele resurse externe utilizate (iere jar) prin proprietile s s at
Main-class: numeClasa Class-path: lib/resursa1.jar lib/resursa2.jar . . .

Pentru a obtine ierul MANIFEST.MF cu aceste proprieti se editeaz un s at a ier text cu continutul de mai sus, denumit de exemplu myManifest.mf, i s s se arhiveaz prin a
jar cfvm numeArhiva.jar myManifest.mf *.class lib

Aplicatie cu baz de date a


Sistemul de gestiune a bazei de date este de tip embedded - Derby n cazul de fat. Baza de date este creat pe calculatorul clientului la prima a a apelare a aplicatiei, ind regsit la apelrile ulterioare ale aplicatiei. Struc a a a tura aplicatiei corespunde unui servlet. Arhiva aplicatiei i ierul derby.jar s s trebuie s aib aceai semntur. a a s a a Exemplul 13.1.1 Aplicatie de interogare a agendei de adrese email.
1 2 4 5 7 8 9 10 11 12 13 14 16 18 19 20 21 22 23 24 25

package agendae ; import j a v a . s q l . ; public c l a s s GuiCmmdc extends j a v a x . swing . JFrame { Statement s t a t e m e n t=n u l l ; public GuiCmmdc ( ) { initComponents ( ) ; S t r i n g d r i v e r= o r g . apache . derby . j d b c . EmbeddedDriver ; S t r i n g dbName= a g e n d a e m a i l ; S t r i n g connURL ; C o n n e c t i o n conn=n u l l ; try { C l a s s . forName ( d r i v e r ) ; connURL= j d b c : derby : +dbName+ ; c r e a t e=t r u e ; conn=DriverManager . g e t C o n n e c t i o n ( connURL ) ; s t a t e m e n t=conn . c r e a t e S t a t e m e n t ( ) ; S t r i n g createDB= c r e a t e t a b l e 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 a s i d e n t i t y + ( s t a r t with 1 , i n c r e m e n t by 1 ) primary key , + nume c h a r ( 2 0 ) not n u l l , + e m a i l c h a r ( 3 0 ) not n u l l ) ; s t a t e m e n t . e x e c u t e ( createDB ) ;

13.1. JAVA WEB START

295

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 55 56 57 58 59 60 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

S t r i n g i n s e r t D B= i n s e r t i n t o a d r e s e ( nume , e m a i l ) v a l u e s + ( aaa , aaa@yahoo . com ) , + ( bbb , bbb@gmail . com ) , + ( c c c , c cc@u nit bv . r o ) , + ( aaa , xyz@unitbv . r o ) ; statement . executeUpdate ( insertDB ) ; } catch ( ClassNotFoundException e ) { System . out . p r i n t l n ( ClassNotFoundException : +e . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } catch ( SQLException e ) { connURL= j d b c : derby : +dbName ; try { conn=DriverManager . g e t C o n n e c t i o n ( connURL ) ; s t a t e m e n t=conn . c r e a t e S t a t e m e n t ( ) ; } catch ( E x c e p t i o n ex ) { System . out . p r i n t l n ( E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ; System . e x i t ( 1 ) ; } } 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 . e x i t ( 1 ) ; } } @SuppressWarnings ( unchecked ) 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 p e n t r u i n t e r f a t a g r a f i c a . . . } private void jBu ttonE xecMo useCl icke d ( j a v a . awt . e v e n t . MouseEvent e v t ) { i n t p r e l=jComboBoxTip . g e t S e l e c t e d I n d e x ( ) ; S t r i n g e n t i t= \ +j T e x t F i e l d E n t i t . g e t T e x t ( ) . t r i m ()+ \ ; String sql ; R e s u l t S e t r s=n u l l ; jTextAreaDB . s e t T e x t ( ) ; 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 ( 1 0 0 ) ; try { switch ( p r e l ) { case 0 : s q l= s e l e c t from a d r e s e where nume=+e n t i t ; r s=s t a t e m e n t . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) { while ( r s . n e x t ( ) ) { sb . append ( 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 )+ \n ) ; } } else { sb . append ( Fara a d r e s a de em a i l ! ) ; } break ; case 1 : s q l= s e l e c t from a d r e s e where e m a i l=+e n t i t ;

296

CAPITOLUL 13. JAVA WEB START

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 103 104 105 106 107 108 110 111 112 113 114 115 116 117 118 119 120 121 122

r s=s t a t e m e n t . e x e c u t e Q u e r y ( s q l ) ; i f ( r s != n u l l ) { while ( r s . n e x t ( ) ) { sb . append ( 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 )+ \n ) ; } } } } catch ( SQLException e ) { System . out . p r i n t l n ( Query DB 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 ( 1 ) ; } jTextAreaDB . i n s e r t ( sb . t o S t r i n g ( ) , 0 ) ; jTextAreaDB . s e t V i s i b l e ( true ) ; } private void formWindowClosed ( j a v a . awt . e v e n t . WindowEvent e v t ) { try { DriverManager . g e t C o n n e c t i o n ( j d b c : derby : ; shutdown=t r u e ) ; } catch ( SQLException e ) { } } public s t a t i c void main ( S t r i n g a r g s [ ] ) { j a v a . awt . EventQueue . i n v o k e L a t e r (new Runnable ( ) { public void run ( ) { new GuiCmmdc ( ) . s e t V i s i b l e ( true ) ; } }); } private j a v a x . swing . JButton jButtonExec ; private j a v a x . swing . JComboBox jComboBoxTip ; private j a v a x . swing . J S c r o l l P a n e j S c r o l l P a n e 1 ; private j a v a x . swing . JTextArea jTextAreaDB ; private j a v a x . swing . J T e x t F i e l d j T e x t F i e l d E n t i t ; }

Fiierul jnlp este s


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

<?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 : // l o c a l h o s t : 8 0 8 0 / agendae / app > <i n f o r m a t i o n> < t i t l e>AgendaEMail</ t i t l e> <vendor> xyz </ vendor> <d e s c r i p t i o n>Derby DB d e s c r i p t i o n> </ </ i n f o r m a t i o n> <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> <r e s o u r c e s> <j 2 s e version= 1.2+ /> <j a r h r e f= agendae . j a r /> <j a r h r e f= l i b / derby . j a r /> </ r e s o u r c e s> <a p p l i c a t i o n d e s c mainc l a s s= agendae . GuiCmmdc /> </ j n l p>

Capitolul 14 Java Management Extensions


Java Management Extensions (JMX) face posibil ca un obiect Java s a a permit gestionarea metodelor i a anumitor cmpuri de ctre alte obiecte. a s a a Obiectele Java care si expun astfel resursele se numesc MBean - uri i formeaz s a temelia cadrului de lucru JMX. Exist mai multe tipuri de MBean-uri: a Standard MBean; Dynamic MBean; Open MBean; Model MBean; MXBean; Un obiect care gestioneaz resursele unui MBean se numete agent sau server a s MBean. Agentul dispune de mijloace care interactioneaz cu un MBean, a permitandu-i: accesul la valorile unui cmp i la modicarea lor; a s invocarea metodelor. general, un agent poate denit ca In autorul unei actiuni; factor care provoac actiuni; a reprezentant al unei institutii arcinat cu ns ndeplinirea unor actiuni. 297

298

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

Terminologia server MBean se justic prin faptul c poate invocat de un a a aceast ipostaz, serverul MBean are rolul unui container program client. In a a de MBean-uri i de gestionare i executie a apelurilor clientilor. s s Structura unei aplicatii JMX contine dou nivele: a componentele MBean; agentul (serverul MBean).

14.1
14.1.1

Standard MBean
Crearea unui Standard MBean

O component MBean este alctuit dintr-o interfat i o clas care implea a a a s a menteaz interfata satisfcnd urmtoarele restrictii: a a a a 1. interfata are numele clasei care o implementeaz avnd plus suxul a a n MBean; 2. Interfata i clasa care o implementeaz apartin aceluiai pachet; s a s 3. constructorii i metodele expuse trebuie s e publice. s a continuare cmpurile i metodele destinate expunerii se vor denumi In a s atribute, respectiv operatii. Fiecrui atribut xxx i se ataeaz cel putin una a s a din metodele public void setXxx(tip xxx){ this.xxx=xxx; } i / sau s public tip getXxx(){ return xxx; } Un atribut se precizeaz doar prin aceste metode, fr denirea / declararea a aa cmpului corespunztor. Cmpul se denete clasa ce implementeaz interfata a a a s n a MBean-ului. Astfel, un MBean este caracterizat de

14.1. STANDARD MBEAN

299

atribute care pot consultate (citite), modicate (scrise) sau cu ambele optiuni. operatii noticri a cu evidenta modicrilor suferite de atribute. a Exemplul 14.1.1 Construim un MBean cu atributele label ce poate numai citit; cursEuro care poate consultat i modicat; s operatiile public String sayHello() aeaz un mesaj; s a public long cmmdc(long m, long n); de calcul a celui mai mare divizor comun a dou numere naturale. a Interfata 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 // reado n l y public S t r i n g g e t L a b e l ( ) ; // readw 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

300

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

1 2 4 6 7 8 10 11 12 14 15 16 18 19 20 22 23 24 25 26 27 29 30

package b a s i c ; import j a v a x . management . ; 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 = 3 . 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 ) { . . . } }

acest caz nu s-a implementat posibilitatea noticrilor atributului cursEuro. In a

14.1.2

Crearea unui MBeanServer

Un agent sau MBean server implementeaz interfata MBeanServer. Un a asemenea obiect se obtine printr-una din metodele statice static MBeanServer ManagementFactory.getPlatformMBeanServer() Utilitarul jconsole permite conectarea la serverul MBean. static MBeanServer MBeanServerFactory.createMBeanServer() agent se In nregistreaz componente MBean. Un obiect MBean este cara acterizat de un nume, un obiect de tip ObjectName. Inregistrarea i / sau s crearea unei componente MBean necesit denirea prealabil a acestui nume. a n Structura unei nume este domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . . unde

14.1. STANDARD MBEAN

301

domeniu este un nume simbolic (String). Dac domeniul este stringul vid atunci a se consider valoarea implicit DefaultDomain. a a atribute uzuale: type=numele MBean-ului index=numr de identicare a MBean-ului a Cel putin un atribut este obligatoriu. Clasa ObjectName Constructori ObjectName(String nume) Parametrul nume are structura descris mai sus. a ObjectName(String domeniu, Hashtable<String,String> tabel ) ObjectName(String domeniu, String numeAtribut, String valAtribut) Metode static ObjectName getInstance(String nume) Inregistrarea i utilizarea MBean-ului face apel la metodele interfetei MBeanServer. s ObjectInstance Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblului alctuit de un obiect ObjectName asociat unui MBean i numele clasei a s corespunztoare. a Interfata MBeanServer Metode ObjectInstance registerMBean(Object obj , ObjectName nume) Inregistreaz pe platform, instanta obj a unui MBean avnd numele a a a nume.

302

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

void unregister(ObjectName nume) ObjectInstance createMBean(String numeClas , ObjectName nume) a Creaz i a s nregistreaz un MBean de clas numeClas i de nume nume. a a as ObjectInstance createMBean(String numeClas , ObjectName nume, a Object[] param, String[] sign) plus, irul param contine parametri constructorului, de tip, respectiv In s sign. String getDefaultDomain() Object invoke(ObjectName mbeanName, String operationName, Object[] param, String[] paramTip) Se invoc operatia operationName a MBean-ului mbeanName. Parametri a necesari operatiei mpreun cu tipurile corespunztoare sunt dati varia a n abilele param i respectiv paramTip. s Object getAttribute(ObjectName mbeanName,String atribut) Returneaz valoarea atributului atribut a mbean-ului mbeanName. a void setAttribute(ObjectName mbeanName,Attribute atribut) Fixeaz valoarea atributului atribut a MBean-ului mbeanName. Retinem a doar constructorul clasei Attribute prin Attribute(String nume, Object valoare) MBeanInfo getMBeanInfo(ObjectName mbeanName) Returneaz un obiect de tip MBeanInfo util inspectrii resurselor unui a a MBean. Exist mai multe abloane de programare a a s nregistrrii unei componente a MBean. Exemplul 14.1.2 Se creaz dou componente MBean de tip Intro care vor a a inspectate prin intermediul utilitarului jconsole1 - distributia jdk . Utilitarul jconsole permite apelarea operatiilor, modicarea atributelor i s semnaleaz noticrile. a a
In acest caz, este nevoie ca variabilele de tip clas acoperitoare Double, Long s e a a nlocuite prin tipuri predenite.
1

14.1. STANDARD MBEAN

303

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

package b a s i c ; import j a v a . l a n g . management . ; import j a v a x . management . ; 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 MBeanu l u i ObjectName mbeanObjectName = new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=1 ) ; // Crearea MBeanu 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 MBeanu 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 aplicatiei revine la 1. Intr-o fereastr DOS se lanseaz agentul Main prin a a java -Dcom.sun.manager.jmxremote basic.Main 2. Intr-o alt fereastr DOS se lanseaz a a a jconsole pornind utilitarul jconsole. 3. fereastra de dialog jconsole:Connect to Agent se d clic pe Connect. In a 4. panoul Tree gsim domeniul dat. Prin clic pe domeniu apar MBeanIn a urile de indice 1 i 2. s 5. Prin clic pe unul din aceste MBean-uri, panoul central avem acces la n atributele i la operatiile lor. s

304

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

Rezultatul unei operatii apare ntr-o fereastr de informare (Fig. 14.1). a

Figure 14.1: Rezultatele furnizate de jcluster.

14.1.3

Noticri a

Pentru implementarea retinerii de ctre un agent MBean a noticrilor, a a clasa ce implementeaz interfata MBean-ului trebuie s extind clasa Notificationa a a BroadcasterSupport. Modicrile unui atribut se retin a ntr-un obiect de tip Notification i este s transmis prin metoda sendNotification(Notification notication)

14.1. STANDARD MBEAN

305

a clasei NotificationBroadcasterSupport. Suplimentar se denete metoda s public MBeanNotificationInfo[] getNotificationInfo() care se precizeaz n a tipul noticrii - (constant denit de clasa AttributeChangeNotification); a a a clasa care s-a generat noticarea n String name = AttributeChangeNotification.class.getName(); o descriere a modicrii. a Astfel, introducerea noticrilor presupune familiarizarea cu clasele a 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()

306

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

AttributeChangeNotication extends Notication Constructori AttributeChangeNotification(Object source, long sequenceNumber , long timeStamp, String msg, String attributeName, String attributeType, Object oldValue, Object newValuE ) Cmpuri a static String ATTRIBUTE CHANGE Semnaleaz schimbarea atributului a Exemplul 14.1.3 Extinderea MBean-ului Intro cu noticarea modicrilor a atributelor n jconsole. Implementarea noticrilor clasa Intro presupune modicarea metodei a n setCursEuro. Totodat se adaug metoda getNoticationInfo, ce furnizeaz a a a informatii referitoare la modicarea aprut. Codul clasei care implementeaz a a a interfata devine
1 2 4 5 6 8 9 10 12 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

package ag e nt n ; import j a v a x . management . ; 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 = 3 . 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 ) ; sendNotification (n ) ; }

14.1. STANDARD MBEAN

307

32 33 34 35 36 37 38 39 40 41 43 44 46 47

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 ) { . . . } }

jconsole pentru noticare, prealabil este nevoie de subscriere. In n

14.1.4

Agent MBean

exemplelele anterioare resursele unui MBean au fost utilizate prin jconIn sole. Valoricarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se programeaz prin a Exemplul 14.1.4
1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 18 20 21 22 23 25 26 27

package a g e n t ; import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 MBeanu 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 ; 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 ) ;

308

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

28 29 30 31 32 33 34 35 37 38 39 41 42 43 44 45 46 47 48 49 50 51 52

System . out . p r i n t l n ( Primul numar : ) ; long m c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } } }

14.1.5

Invocarea la distant a

Din punct de vedere al programrii distribuite, cazul interesant este cel a care clasa ce implementeaz MBean-ul i clientul (agentul MBean) care o n a s utilizeaz se a pe calculatoare diferite. a a acest caz: In Este nevoie de o clasa server (agent) al crui rol este a Instantierea unui MBeanServer Instantiarea unui server de conexiune, obiect de tip MBeanServerConnection. Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaz a comunicatia dintre un client i serverul MBeanServer. Serverul de s conexiune i serverul MBeanServer apartin aceleiai clase. s s cazul utilizrii tehnologiei RMI rmiregistry i serverul MBeanServer In a s trebuie s ruleze pe acelai calculator. a s Utiliznd tehnologia RMI-IIOP, orbd serverul MBeanServer pot a s rula pe calculatoare distincte. Lansarea executie a serverului de conexiune. n Clientul dispune de interfata MBean-ului.

14.1. STANDARD MBEAN

309

Interfata MBeanServerConnection este implementat de clasa MBeanServer a Sablonul de programare pentru instantierea obiectului de tip MBeanServerConnection i lansarea sa executie poate : s n
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 ctre a client. Lansarea executie a serverului este precedat de pornirea registrului n a rmiregistry, respectiv orbd. Exemplul 14.1.5
1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29

package s e r v e r ; import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 ( ) ; // 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=

310

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

30 32 33 34 35 36 37 38 39 40 41 42 43

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 rndul lui, este nevoit s creeze un conector ctre server (agent), a a a prin intermediul cruia obtine un obiect ce implementeaz interfata MBeanServerConnection. a a Prin acest obiect, clientul va putea crea MBean-uri - agent - i le va putea n s utiliza resursele. Sablonul 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 interfetei MBeanServerConnection. crearea unui reprezentant local al MBean-ului prin metoda static a mbeanClass proxy = (mbeanClass)MBeanServerInvocationHandler.newProxyInstance( mbeanServerConnection,mbeanObjectName,mbeanClass.class,true); nal, MBean-ul se terge din serverul de conexiune, prin In s cs.unregisterMBean(mbeanObjectName). Exemplul 14.1.6 Client ce utilizeaz un MBean Intro, denit n Exemplul a 14.1.1

14.1. STANDARD MBEAN

311

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

package c l i e n t ; import j a v a . i o . IOException ; import j a v a . u t i l . ; import j a v a x . management . ; import j a v a x . management . remote . ; 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 MBeanu 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 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 ) ;

312

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

60 61 62 64 65 66 67 68 69 70 72 73 74 75 76 77 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 95 96 97 99 100 101 102 103 104 105 106 107 108 109 110 111

// 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 c a n n e r . nextLong ( ) ; =s 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 c a n n e r . nextLong ( ) ; =s 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 ( ) ) ; } } }

Inspectarea i valoricarea resurselor unei componente MBean se s poate face i prin intermediul metodei s
1 2

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 ( ) ) ;

14.1. STANDARD MBEAN

313

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

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 metod poate inserat oricare din programele agent sau client. a a a n

Noticarea la distant a
Noticarea la distanta presupune utilizarea unui MBean posednd aceast a a facilitate. Pe partea de client trebuie implementat interfata NotificationListener

314 care declar metoda a

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

public void handleNotification(Notification notication, Object handback ) Ataarea i disponibilizarea clasei ce implementeaz interfata Notification s s a Listener se obtin prin metodele interfetei 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 14.1.7 Folosind exemplul 14.1.6 - dar cu MBean-ul creat pentru 14.1.3 se creaz un client cu noticare, care sesiseaz modicarea valoarii a a atributului cursEuro a MBean-ului IntroN. Implementarea interfetei 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 6 7 8 9 10

package c l i e n t ; import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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){

14.1. STANDARD MBEAN

315

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

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 MBeanu 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 ( ) ; } } private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . } }

Clasa Client care creaz MBean-ul trebuie lansat a a naintea clasei ClientNotif. Aceste dou clase pot rula pe calculatoare distincte. a Exemplul 14.1.8 O aplicatie servlet ntretine un cont. Actiunile ce pot ntreprinse sunt: depunerea unei sume, extragerea unei sume n limita soldului

316

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

i consultarea contului. Contul este implementat ca un MBean standard. Se s cere urmrirea la distanta a modicrilor suferite de cont. a a Interfata 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 // readw r i t e public double getCont ( ) ; public void s e t C o n t ( double c o n t ) ; }

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

import j a v a x . management . ; 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 }; 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

import import import import import

java . io . ; javax . s e r v l e t . ; javax . s e r v l e t . http . ; j a v a x . management . ; j a v a x . management . remote . ;

14.1. STANDARD MBEAN

317

6 7 9 10 11 12 13 14 15 16 17 18 19 21 22 23 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 52 53 54 55 56 57 58 59 60 61 62 63 64

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 x . s e r v l e t . a n n o t a t i o n . WebInitParam ; @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 ) ; } } 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 r r o r : +e . g e t M e s s a g e ( ) ; 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 ;

318

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

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 106 107 108 109 110

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 r r o r : +e . g e t M e s s a g e ( ) ; 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 r r o r : +e . g e t M e s s a g e ( ) ; 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> ) ; out . p r i n t l n ( message ) ; out . p r i n t l n ( </p> ) ; 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 ) ; } }

Pagina de apelare a servlet-ului ind (index.html )


1 2 3 4 5 6 7 8 9 10

<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 :

14.1. STANDARD MBEAN

319

11 12 13 14 15 16 17 18 19 20 21 22 23

<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 urmrete de la distanta contul are codul a s


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

import j a v a . i o . IOException ; import j a v a x . management . ; import j a v a x . management . remote . ; 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){ 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 . 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 ( DefaultDomain : +domain ) ; // Crearea o b i e c t u l u i OBjectName a t a s a t MBeanu 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 ! ) ;

320

CAPITOLUL 14. JAVA MANAGEMENT EXTENSIONS

44 45 46 47 48 49 50 51 52 53 54 55 56 58 59 61 62 63 64 65 66 67 68 69 70 71 72

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 ( ) ) ; 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 Exemplul 14.1.5. n Serverul MBean este plasat servlet ( catalogul WEB-INF/classes al n n aplicatiei) iar clientul care urmrete de la distanta se poate aa oriunde. a s Dup instalarea servlet-ului se lanseaz pe maina acestuia server-ul MBean. a a s Deoarece noticarea presupune existenta MBean-ului, iar acesta se instanteaz a prin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depunnd a 0 uniti. Dup aceast operatie se lanseaz executie programul ClientNotif. at a a a n

Partea III ANEXE

321

Anexa A Unelte de dezvoltare


Incepem aceast sectiune prin a introduce cteva elemente privind sintaxa a a unui document xml.

A.1

XML

EXtensible Markup Language (XML) reprezint un limbaj pentru denirea a marcajelor de semantic, care a mpart un document prti identicabile n a n document. Din 1998, XML este un standard World Wide Web Consortium (W3C). Totodat XML este un meta-limbaj pentru denirea sintaxei de utilizat a n alte domenii. XML descrie structura i semantica i nu formatarea. s s Structura unui document XML este <?xml version="1.0" encoding="tip_codare" [standalone="yes"]?> corpul documentului alcatuit din elemente Prima linie - preambulul - reprezint declaratia de document XML. Tipul a codrii poate utf-8, iso-8859-1. a Corpul documentului este alctuit din elemente. a Inceputul unui element este indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. Elementele pot cu corp, alctuit din alte elemente, avnd sintaxa a a <marcaj> corpul elementului </marcaj> 323

324 sau fr corp, caz care sintaxa este aa n <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 un singur element rdcin. Elementele unui document XML formeaz a a a a a un arbore. Fiecrui marcaj de a nceput al unui element trebuie s-i corespund a a un marcaj de sfrit. Caracterele mari i mici din denumirea unui element sunt as s distincte (case sensitive). Elementele ncuibrite (nested )- incluse a ntr-un alt element - nu se pot amesteca, adic un marcaj de sfrit corespunde ultimului marcaj de a as nceput. Un comentariu se indic prin a <!-Text comentariu --> Exemplul A.1.1 Fiier XML - denumirile elementelor i continutul lor permit s s ntelegerea simpl a semanticii introduse n document. a
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> <fonddetimp> <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> </ fonddetimp> </ 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> <fonddetimp> <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> </ fonddetimp> </ 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

325

20 21 22 23 24 25 26 27

<nume> S o f t matematic </nume> <fonddetimp> <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> </ fonddetimp> </ 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 preambul; a ecare element este nchis sau corespunde un marcaj de inchidere; i marcajele ncuibrite nu se amestec. a a Un document XML este valid dac a este bine formatat; cazul c exist o referinta ctre XML Schema atunci documentul XML n a a a este conform schemei. Un produs informatic accesibil gratuit, care permite vericarea bine formatrii i a validitii unui document xml, este XML Copy Editor. a s at Pentru validare, dac ierul XML Schema se a alt catalog dect cel al a s a n a erului xml atunci acestuia i se asociaz XML Schema prin XML Associate s a XML Schema. . . Prelucrarea unui document XML Java se poate face pe baza interfetelor n de programare: Document Object Model - DOM; Simple API for XML - SAX; Stream API for XML - StAX; Java Architecture for XML Binding - JAXB. Se recomand utilizarea interfetelor de programare StAX i JAXB. a s Amintim faptul c reprezentarea obiectelor matematice prin elemente XML a constituie subiectul a dou proiecte MathML i OpenMath. Obiectivul limbajua s lui MathML este reprezentarea unui text matematic ntr-un document HTML, timp ce obiectivul proiectului OpenMath este reprezentarea semantic a n a datelor matematice pentru realizarea de aplicatii cooperante ntre sisteme de calcul simbolic - CAS (Computer Algebra System).

326

ANEXA A. UNELTE DE DEZVOLTARE

A.2

apache-ant

Utilitarul apache-ant asigur executarea unui ir de comenzi de operare. a s Aceste comenzi se nregistreaz a ntr-un ier de tip xml, cu denumirea build.xml. s Astfel, apache-ant se substituie unui ier de comenzi bat Windows sau unui s n script shell din Linux/Unix. Avantajul obtinut const independenta fata de a n platforma de calcul (Windows, Linux). Instalarea const dezarhivarea ierului descrcat din Internet. a n s a Lansarea executie necesit xarea variabilei de mediu JAVA HOME, ce n a contine calea la distributia Java. Lansarea se poate face prin urmtorul ier a s de comenzi set JAVA_HOME=. . . set ANT_HOME=. . . %ANT_HOME%\bin\ant.bat %1 Parametrul %1 acestui ier de comenzi reprezint obiectivul care se dorete s a s a atins. Dac se modic denumirea sau locatia ierului build.xml atunci a a s ierul de comenzi se invoc cu optiunea -buildfile. s a Un ier build.xml corespunde unui proiect (project), alctuit din unul s a sau mai multe obiective (target). Atingerea ecarrui obiectiv const din a a ndeplinirea uneia sau mai multor sarcini (task). Apache-ant contine o familie predenit de sarcini. Programatorul are datoria xrii atributelor sarcinilor. a a Manualul din documentatia produsului contine descrierea atributelor ct i a s exemple. general, o sarcin reprezint o operatie executat uzual linia In a a a n de comand. a Atributele se dau, respectnd sintaxa XML a 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

327

Dac la apelarea lui Apache-ant lipsete parametrul optional atunci se va a s executa obiectivul default. Intr-un proiect se pot deni variabile prin marcajul <property name=numeVariabila value=valoareVariabila /> O variabil denit se va utiliza cu sintaxa ${numeVariabila}. a a Exemplul A.2.1 Fiierul build pentru executia programelor din 1.2. s
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 toate resursele utilizate, cuprinse a uzual iere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul n s local. Dac calculatorul este conectat la Internet, atunci resursele publice a pot descrcate a mpreun cu toate dependintele i utilizate prin apache-ant, a s folosind suplimentar apache-ivy 1 . In vederea utilizrii lui apache-ivy se copiaz ierul ivy-*.jar din distributia a a s apache-ivy ANT HOME\lib. n Fiierul build.xml contine plus s n
1

Asemntor cu maven, un alt produs de dezvoltare. a a

328

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 un ier ivy.xml, cu dependintele necesare aplicatiei care a s urmeaz a preluate dintr-unul din depozitele ivy - local, shared, public a
<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 i gestiune a proiectelor s (Project management framework). Calculatorul pe care se dezvolt proiectul a / aplicatia trebuie s e conectat la internet. Resursele necesare a ndeplinitii diferitelor sarcini (maven artifacts) sunt preluate din internet i depuse s ntr prezent sunt un depozit local maven (local repository). In ntretinute depozite
2

Maven acumulator de cunotiinte (Idi). s s

A.3. APACHE-MAVEN

329

publice de resurse soft necesare dezvoltrii de aplicatii cu maven 3 iar deza voltatorii de instrumente soft au posibilitatea de a-i promova produsele prin s depunerea ntr-un depozit maven. Dintr-un asemenea depozit public resursele necesare sunt descrcate depozitul local. a n

Gestiunea proiectelor cu apache-maven


Instalarea produsului const dezarhivarea ierului descrcat din ina n s a ternet ntr-un catalog MAVEN HOME. Utilizarea produsului necesit a Completarea variabilei de sistem PATH cu calea MAVEN HOME\bin. Declararea variabilei JAVA HOME avnd ca valoare calea ctre distributia a a jdk folosit. a mod obinuit depozitul local maven este In s C:\Documents and Settings\client\.m2\repository Locatia depozitului local se poate modica, introducnd elementul a <localRepository>volum:/cale/catalog_depozit</localRepository> ierul MAVEN HOME\conf\settings.xml. n s Potrivit principiului separrii preocuprilor (Separation of Conserns), un a a proiect maven produce o singur ieire. a s Declararea unui proiect se face printr-un ier pom.xml (Project Object s Model). Este sarcina programatorului s completeze ierul pom.xml, creat a s la generarea structurii de cataloage ale proiectului, cu specicarea resurselor suplimentare sau a conditionrilor efectuarea unor operatii (de exemplu, a n prezenta adnotrilor necesit utilizarea versiunii Java 1.5). a a Dezvoltarea unei aplicatii / proiect prin maven presupune generarea unei structuri de cataloage (Standard directory layout for projects). Aceast struca tur de cataloage este specic tipului / ablonului de aplicatie (archetype, a a s n limbajul maven). Sabloane uzuale de aplicatii: Nume ablon s Semnicatia maven-archetype-quickstart aplicatie simpl a (ablonul implicit) s maven-archetype-webapp aplicatie Web maven-archetype-j2ee-simple aplicatie JEE
3

De exemplu repo1.maven.org/maven2.

330

ANEXA A. UNELTE DE DEZVOLTARE

Sablonul se specic parametrul -DarchetypeArtifactId al comenzii a n mvn archetype:create. Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare, testare, etc) se obtin prin comenzi maven. Comenzile maven sunt de dou tipuri: a

Comenzi pentru gestiunea ciclului de viat al unui proiect (lifecycle coma mands):

Comanda maven mvn -version

Semnicatia aeaz versiunea maven s a (util pentru vericarea functionrii lui maven) a a mvn clean terge ierele maven generate s s mvn compile compilarea sursele Java mvn test-compile compileaz sursele Java care a realizeaz testele junit a mvn test execut testul junit a mvn package creaz o arhiv jar sau war a a mvn install depune arhiva jar sau war depozitul local n

Comenzi de operare inserate (plugin commands):

A.3. APACHE-MAVEN

331 Semnicatia genereaz structura de cataloage a proiectului a


mvn archetype:create \ -DgroupId=numelePachetuluiAplicatiei \ -DartifactId=numeleProiectului \ -DarchetypeArtifactId=numeSablon

Comanda maven mvn archetype:create

mvn archetype:generate mvn mvn mvn mvn mvn

genereaz structura de cataloage a proiectului a ablonul se alege dintr-o list s a clean:clean terge ierele generate urma compilrii s s n a compiler:compile compilarea sursele Java surefire:test execut testul junit a jar:jar creaz o arhiv jar a a install:install-file depune o arhiv jar depozitul local a n
mvn install:install-file \ -Dfile=numeFiier \ s -DgroupId=numePachet \ -DartifactId=numeProiect \ -Dversion=versiunea \ -Dpackaging=tipArhiv a

mvn exec:java

execut metoda main a unei clase a


mvn exec:java -Dexec.mainClass=clasaMetodeiMain

Astfel comanda
mvn archetype:create -DgroupId=unitbv.cs.calcul -DartifactId=hello

genereaz arborescenta a
hello |--> src | |--> main | | |--> | | | | | | | | | | | | | |--> test | | |--> | | | | | | | | | | | | | pom.xml

java |--> | | | java |--> | | |

unitbv |--> cs | |--> calcul | | | App.java

unitbv |--> cs | |--> calcul | | | AppTest.java

Descrierea proiectului este dat ierul pom.xml generat a n s

332

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/XMLSchemai 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 /mavenv 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 aplicatiei, din catalogul hello se execut comenzile a
mvn compile mvn test

Sarcina programatorul este acela de a nlocui aceste programe cu cele care rezolv sarcinile proiectului. Pentru orice prelucrare toate dependintele trebuie a s se gseasc depozitul local maven. a a a n Exemplul A.3.1 Dezvoltarea aplicatiei de calcul al celui mai mare divizor comun a dou numere naturale utiliznd maven. a a Generm proiectul maven a
mvn archetype:create -DgroupId=unitbv.proiect.mycmmdc -DartifactId=cmmdc

Inlocuim clasa App cu


1 2 3 4 5 6 7 9 10

package u n i t b v . p r o i e c t . mycmmdc ; 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 ( ) { . . . } }

i s

A.3. APACHE-MAVEN

333

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

package u n i t b v . p r o i e c t . mycmmdc ; 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 c a n n e r . nextLong ( ) ; =s 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 u n i t b v . p r o i e c t . mycmmdc ; 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 ) ; } }

Intruct vom folosi versiunea 4.8.2 a produsului junit modicm ierul a a n s pom.xml versiunea acestui produs i precizm versiunea distributiei jdk utis a lizat, care trebuie s e cel putin 1.5 (restrictie impus de junit-4.8.2). a a a
1 2 3 4 5 6 7

<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/XMLSchemai 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 /mavenv 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 . 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>

334

ANEXA A. UNELTE DE DEZVOLTARE

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

<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 . 8 . 2</ 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> <p l u g i n s> <p l u g i n> <g r o u p I d>o r g . apache . maven . p l u g i n s</ g r o u p I d> < a r t i f a c t I d>mavenc o m p i l e r p l u g i n</ a r t i f a c t I d> <version>2 . 0</ version> <c o n f i g u r a t i o n> <s o u r c e>1 . 7</ s o u r c e> <t a r g e t>1 . 7</ t a r g e t> </ c o n f i g u r a t i o n> </ 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>

Operarea poate
mvn archetype:create -DgroupId=unitbv.proiect.mycmmdc -DartifactId=cmmdc cd cmmdc mvn compile mvn test mvn exec:java -Dexec.mainClass="unitbv.proiect.mycmmdc.MyCmmdc"

maven cu ant
maven se pot integra sarcini apache-ant pentru orice etap al evolutiei In a unei aplicatii. Utilizarea const completarea ierului pom.xml cu a n s
<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"/>

A.3. APACHE-MAVEN

335

<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> </goals> </execution> </executions> </plugin> </plugins> </build> ${compile_classpath}"/> ${runtime_classpath}"/> ${test_classpath}"/> ${plugin_classpath}"/>

elementul <tasks> se denesc sarcinile ant care se doresc executate la In comanda corespunztoare prelucrrii etapei din evolutia proiectului maven a a compile, package, install, test, etc. Mai precis, elementele <echo> se nlocuiesc cu sarcinile ant care se doresc efectuate. Proprietile se denesc elementul at n
<properties> <nume.proprietate>valoare</nume.proprietate> . . . </properties>

RMI prin maven


Restrictia esential pentru pornirea serverului unei aplicatii RMI const a a n utilizarea unui depozit local maven a cei cale numele cataloagelor nu contin n a spatii (ca depozitul local standard C:\Documents and Settings\client\.m2\repository). n Aplicatia RMI va consta din 3 proiecte maven corespunztoare componen a telor unei aplicatii RMI. Textele surs ale tuturor claselor suferua doar modicri minore - se schimb a a a denumirile pachetelor, care implic modicarea unor importuri. a Dezvoltarea interfetei 1. Generarea proiectului
mvn archetype:create -DgroupId=i.cmmdc -DartifactId=icmmdc

2. Completarea cu resursele java

336

ANEXA A. UNELTE DE DEZVOLTARE

icmmdc |--> src | |--> main | | |--> | | | | | | | | | | pom.xml

java |--> i | |--> cmmdc | | ICmmdc.java

3.

mvn compile mvn package mvn install

Dezvoltarea componentei server 1. Generarea proiectului


mvn archetype:create -DgroupId=s.cmmdc -DartifactId=cmmdcimpl

2. Completarea cu resursele java


cmmdcimpl |--> src | |--> main | | |--> | | | | | | | | | | pom.xml

java |--> s | |--> cmmdc | | CmmdcImpl.java

3. Completarea ierului pom.xml cu s


<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

4.

mvn compile

5. Pornirea registrului rmiregistry


start rmiregistry

6.

mvn exec:java -Dexec.mainClass="s.cmmdc.CmmdcImpl"

A.3. APACHE-MAVEN

337

Dezvoltarea componentei client 1. Generarea proiectului


mvn archetype:create -DgroupId=c.cmmdc -DartifactId=cmmdcclient

2. Completarea cu resursele java


cmmdcclient |--> src | |--> main | | |--> | | | | | | | | | | pom.xml

java |--> c | |--> cmmdc | | CmmdcClient.java

3. Completarea ierului pom.xml cu s


<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

4.

mvn compile mvn exec:java -Dexec.mainClass="c.cmmdc.CmmdcClient"

Dezvoltarea unei aplicatii RMI-IIOP prin maven


Se utilizeaz interfata dezvoltat pentru aplicatia RMI. a a a Generarea stub-ului i.cmmdc. ICmmdc Stub.class corespunztor interfetei ICmmdc i a ierului Tie s.iiop.cmmdc. CmmdcImpl Tie.class corespunztor s s a clasei CmmdcImpl se obtin rulnd utilitarul rmic - din distrubutia Java cu a optiunea -iiop. Vom integra maven aceast sarcina ( n a mpreun cu arhivarea ierului a s i.cmmdc. ICmmdc Stub.class) din apache-ant. Dezvoltarea componentei server 1. Generarea proiectului
mvn archetype:create -DgroupId=s.iiop.cmmdc -DartifactId=cmmdciiopimpl

2. Completarea cu resursele java

338

ANEXA A. UNELTE DE DEZVOLTARE

cmmdciiopimpl |--> src | |--> main | | |--> | | | | | | | | | | | | | | | | pom.xml

java |--> | | | |

s |--> | | |

iiop |--> cmmdc | | CmmdcImpl.java | | CmmdcServer.java

3. Completarea ierului pom.xml, care devine s


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

<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/XMLSchemai 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 /mavenv 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>s . i i o p . cmmdc</ g r o u p I d> < a r t i f a c t I d>cmmdciiopimpl</ 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>cmmdciiopimpl</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> <dependency> <g r o u p I d> i . cmmdc</ g r o u p I d> < a r t i f a c t I d>icmmdc</ a r t i f a c t I d> <version>1.0 SNAPSHOT version> </ </ dependency> </ d e p e n d e n c i e s> <b u i l d> <p l u g i n s> <p l u g i n> <g r o u p I d>o r g . apache . maven . p l u g i n s</ g r o u p I d> < a r t i f a c t I d>mavenantrunp l u g i n</ a r t i f a c t I d> <d e p e n d e n c i e s> <dependency> <g r o u p I d>sun</ g r o u p I d> < a r t i f a c t I d> t o o l s</ a r t i f a c t I d> <version>1 . 0</ version> <s c o p e>system</ s c o p e> <systemPath>${ j a v a . home } / . . / l i b / t o o l s . j a r</ systemPath> </ dependency> </ d e p e n d e n c i e s> <e x e c u t i o n s> <e x e c u t i o n> <i d>c o m p i l e</ i d> <phase>c o m p i l e</ phase> <c o n f i g u r a t i o n> <t a s k s> <p r o p e r t y name= c o m p i l e c l a s s p a t h r e f i d=maven . c o m p i l e . c l a s s p a t h />

A.3. APACHE-MAVEN

339

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

<rmic c l a s s n a m e= s . i i o p . cmmdc . CmmdcImpl s o u r c e b a s e= s r c i i o p= y e s b a s e= t a r g e t \ c l a s s e s c l a s s p a t h= ${ c o m p i l e c l a s s p a t h } /> <j a r b a s e d i r= t a r g e t \ c l a s s e s d e s t f i l e = cmmdciiopstub . j a r e x c l u d e s= s / /> </ t a s k s> </ c o n f i g u r a t i o n> <g o a l s> <g o a l>run</ g o a l> </ g o a l s> </ e x e c u t i o n> </ e x e c u t i o n s> </ 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>

4.

mvn compile

5. Pornirea serviciului ORB


start orbd -ORBInitialPort 1050 -ORBInitialHost localhost

6. Instalarea ierului i.cmmdc. ICmmdc Stub.class arhivat cu jar des n pozitul maven local
mvn install:install-file -Dfile=cmmdciiopstub.jar -DgroupId=i.cmmdc -DartifactId=cmmdciiopstub -Dversion=1.0-SNAPSHOT -Dpackaging=jar

7.

mvn exec:java -Dexec.mainClass="s.iiop.cmmdc.CmmdcServer"

Dezvoltarea componentei client 1. Generarea proiectului


mvn archetype:create -DgroupId=c.iiop.cmmdc -DartifactId=cmmdcclient

2. Completarea cu resursele java


cmmdcclient |--> src | |--> main | | |--> | | | | | | | | | | | | | pom.xml

java |--> | | |

c |--> iiop | |--> cmmdc | | | CmmdcClient.java

3. Completarea ierului pom.xml cu s

340

ANEXA A. UNELTE DE DEZVOLTARE

<dependency> <groupId>i.cmmdc</groupId> <artifactId>icmmdc</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>i.cmmdc</groupId> <artifactId>cmmdciiopstub</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

4.

mvn compile mvn exec:java -Dexec.mainClass="c.iiop.cmmdc.CmmdcClient"

Dezvoltarea unui servlet prin maven


Dezvoltarea unui servlet prin maven 4 se va exemplica prin aplicatia n care servletul rspunde clientului cu mesajul Hi nume client, nume client a ind parametru transmis de ctre client la apelarea servlet-ului. a Container de servleti cu care lucreaz maven este jetty. a Dezvoltarea revine la parcurgerea pailor: s 1. Generarea aplicatiei:
mvn archetype:create -DgroupId=hello -DartifactId=helloname -DarchetypeArtifactId=maven-archetype-webapp

Se creaz structura de cataloage i iere a s s


helloname |--> src | |--> main | | |--> | | |--> | | | | | | | | | | pom.xml

resources webapp |--> WEB-INF | | web.xml | index.jsp

unde ierul pom.xml este s


1 2 3 4 5 6

<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/XMLSchemai 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 /mavenv 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>

Iverson W., Building Web Applications with maven 2, http://www.java.net/author/ will-iverson

A.3. APACHE-MAVEN

341

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

< 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 aplicatiei. Se completeaz structura creat anterior cu a a


helloname |--> src | |--> main | | |--> | | | | | | | | |--> | | |--> | | | | | | | | | | pom.xml

java |--> hello | | HelloServlet.java resources webapp |--> WEB-INF | | web.xml | index.html

HelloServlet.java este cel utilizat capitolul Servlet din cursul de n Programare distribuit. a Fiierul web.xml este completat cu elementele specice servlet-ului s (servlet i servlet-mapping). s
1 2 3 5 6 7 8 9 10 11 12 13 14 15

< !D C Y E webapp PUBLIC O T P //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>

342

ANEXA A. UNELTE DE DEZVOLTARE

Fiierul index.jsp se s nlocuiete cu ierul index.html utilizat la s s 5 servletul mentionat anterior . Fiierul pom.xml se completeaz cu s a Referintele la resursele javax.servlet.servlet-api, nece sare compilrii. a
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency>

Referintele serverului Web jetty


<plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins>

Codul ierului pom.xml devine s


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

<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/XMLSchemai 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 /mavenv 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> <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>mavenj 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>

Atentie la parametri de apelare a servlet-ului, care eventual trebuie adaptati. Contextul aplicatiei coincide cu parametrul artifactId

A.3. APACHE-MAVEN

343

33 34 35

</ 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 ne includerea a 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 oprete cu Ctrl+C. s (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. desfurm arhiva war: mvn tomcat:deploy as a 2. lansm serverul Web lucru: mvn tomcat:run a n Serverul se oprete cu Ctrl+C. s

Aplicatie JSP prin maven


Ne propunem s calculm cel mai mare divizor comun a dou numere natua a a rale ntr-o pagin JSP utiliznd o component Java pentru calculul propriu-zis a a a (cf. cursului de Programare distribuit). a Deoarece maven produce o singur ieire se vor realiza dou proiecte maven: a s a unul pentru componenta Java, care va arhivat i depus depozitul local as a n iar cellalt pentru aplicatia JSP. a 1. Realizarea componentei Java. (a) Generarea proiectului maven
mvn archetype:create -DgroupId=cmmdc -DartifactId=cmmdcjsp

Se nlocuiete clasa App.java cu clasa CmmdcBean (curs Programare s distribuit). a (b) Prelucrarea const din a i. mvn compile

344 ii. mvn package iii. mvn install 2. Realizarea aplicatiei JSP. (a) Generarea cadrului:

ANEXA A. UNELTE DE DEZVOLTARE

mvn archetype:create -DgroupId=jsp -DartifactId=cmmdcjsp -DarchetypeArtifactId=maven-archetype-webapp

(b) Dezvoltarea aplicatiei: i. Se completeaz aplicatia cu ierele cmmdc.jsp i index.html a s s din cursul Programare distribuit, desfurarea ind a as
cmmdcjsp |--> src | |--> main | | |--> | | |--> | | | | | | | | | | | | | pom.xml

resources webapp |--> WEB-INF | | web.xml index.html cmmdc.jsp

ii. Fiierul pom.xml se completeaz cu referinta pentru compos a nenta Java


<dependency> <groupId>cmmdc</groupId> <artifactId>cmmdcjsp</artifactId> <version>1.0-SNAPSHOT</version> </dependency>

i pentru serverul Web jetty s


<plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins>

(c) Prelucrarea const din a i. mvn package ii. mvn jetty:run

Anexa B Testare cu junit


Vericarea / testarea automat a programelor Java se poate face cu proa dusul informatic junit. Deseori se formuleaz probleme de test ale cror rezula a tate sunt cunoscute, cu rolul de a verica functionarea unui program de re zolvare, pentru depistarea unor greeli. s S-a dezvoltat i o metodologie de lucru Test Development Design - (TDD) s care presupune pentru orice clas elaborat realizarea unui program de testare, a a chiar a priori. Un alt produs care are acelai scop de vericare a rezultatelor este TestNG. s junit permite vericarea automat a rezultatelor furnizate de un program, a pentru o multime de date de test. Instalarea produsului const din dezarhivarea ierului descrcat a s a ntr-un s catalog JUNIT HOME. Pentru compilare i executie, variabila de sistem classpath trebuie s contin referinta JUNIT HOME\junit-*.jar. a a Utilizarea produsului ntr-un program Java const din: a 1. Declararea resurselor pachetului junit prin import org.junit.*; import static org.junit.Assert.*; 2. Declararea clasei cu testele junit - uzual metoda main. n org.junit.runner.JUnitCore.main("AppClass"); 3. Eventuale operatii necesare nainte sau dup efectuarea testelor se prea cizeaz respectiv, cte o metod care a fost declarat cu adnotarea a n a a a @org.junit.Before i respectiv, @org.junit.After. s 4. Testele se denesc metode declarate cu adnotarea @org.junit.Test. n Clasa Assert posed metodele de vericare ale unui rezultat: a 345

346

ANEXA B. TESTARE CU JUNIT

static void assertEquals(Tip ateptat, Tip actual ) s unde Tip poate double, int, long, Object. static void assertEquals(double ateptat, double actual, double s delta) Testul reuete dac |ateptat-actual | < delta. s s a s static void assertArrayEquals(Tip[ ] ateptat, Tip[ ] actual ) s unde Tip poate byte, char, int, long, short, Object. static void assertTrue(boolean conditie) static void assertFalse(boolean conditie) static void assertNull(Object object) static void assertNotNull(Object object) cazul exemplului In
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 obtine
JUnit version 4.5 . Time: 0.03 OK (1 test)

Exemplul B.0.2 Testarea clasei App ( 2.3).

347

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.3 Testarea clasei MyMServer ( 2.3).


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 ) ; } }

348

ANEXA B. TESTARE CU JUNIT

Anexa C Component Java (Java Bean) a


O component Java este o clas care poate interactiona cu alte componente a a Java, cu un document jsp, etc. O componenta Java contine cel putin Un constructor fr nici un argument; aa O multime de cmpuri declarate private; a Pentru ecare asemenea cmp a private Tip xyz; trebuie denite cel putin una din metodele public void setXyz(Tip xyz){ this.xyz=xyz; } public Tip getXyz(){ return xyz; }

349

350

ANEXA C. COMPONENTA JAVA

Anexa D Adnotri a
O adnotare este o completare, o not sau o a nsemnare care explic sau a ntregete un text. s O metadat este o adnotare a unei date. a Java o adnotare (annotation) este o metadata a unui element de cod In (identicator al unei entiti din codul Java). at O adnotare poate s-i fac efectul: as a asupra codului surs, a naintea compilrii; a asupra codului obiect, dup compilare, dar a naintea executrii; a timpul executiei codului. n Din punctul de vedere al sintaxei intereseaz a denirea unei adnotri; a declararea unei adnotri; a procesarea unei adnotri. a

D.1

Denirea unei adnotri a

Sintaxa utilizat este a import java.lang.annotation.*; modicator @interface NumeAdnotare{ declarare Element 1 351

352 declarare Element 2 . . . } unde declarare Element poate : tip numeElement(); tip numeElement() default valoare; iar tip poate

ANEXA D. ADNOTARI

predenit (int, short, long, byte, char, float, double, boolean); String Class enum adnotare tablou ale crei elemente sunt de un tip precizat anterior a Adnotarea se salveaz ca ier text, sub numele NumeAdnotare.java. a s Dup numrul elementelor declarate a a ntr-o adnotare, acesta poate 0 - caz care adnotarea este de tip marker; n 1 sau mai multe elemente (single-element / multi-value annotation).

D.2

Declararea unei adnotri a

O adnotare se poate referi la un pachet, clas, interfata, metod, cmp. a a a Inaintea declarrii elementului asupra cruia actioneaz, adnotarea se ina a a dic prin a @NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )

D.3. PROCESAREA UNEI ADNOTARI

353

D.3

Procesarea unei adnotri a


Meta-adnotri a Target Retention Documented Inherited

Java declar adnotrile a a Adnotri regulate a Override Deprecated SuppressWarnings

Adnotarea Override
Adnotarea Override precizeaz faptul c se suprascrie un element al clasei a a printe. a
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 locul liniei 9 se pune Date d=new Date(); atunci nu mai apare a n mesajul TestOverride.

Adnotarea Deprecated
Adnotarea Deprecated are ca efect aarea unui mesaj de avertisment s n momentul compilrii. a Exemplicm cu clasele a
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

354 Mesajul de avertisment este


Note: TestDeprecated.java uses or overrides a deprecated API. Note: Recompile with -Xlint:deprecation for details.

ANEXA D. ADNOTARI

Comentnd linia adnotrii are ca efect la o nou compilare disparitia mesajelor a a a de avertisment.

Adnotarea SuppressWarnings
Adnotarea SuppressWarnings inhib aarea mesajelor de avertisment. a s Relum exemplul anterior schimbnd clasa Test. urma compilrii nu mai a a In a apar mesajele de avertisment mentionate 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 elementul asupra creia actioneaz: a a a ElementType.TYPE ElementType.FIELD ElementType.METHOD ElementType.PARAMETER ElementType.CONSTRUCTOR ElementType.LOCAL VARIABLE ElementType.ANNOTATION TYPE

Adnotarea Retention
Adnotarea Retention precizeaz momentul actiunii adnotrii: a a RetentionPolicy.SOURCE RetentionPolicy.CLASS RetentionPolicy.RUNTIME

D.3. PROCESAREA UNEI ADNOTARI

355

Adnotarea Documented
Adnotarea Documented are ca efect mentionarea adnotrii documentul a n obtinut 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 public @ i n t e r f a c e MyDocumented{}

i s
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 prin a


md docs javadoc -d docs *Documented.java

Procesarea unei adnotri se refer primul rnd la regsirea momentul a a n a a n executiei a valorilor elementelor adnotrii. functie de valorile regsite se pot a In a implementa actiuni specice. Procesarea unei adnotri se bazeaz pe metodele interfetei AnnotationElement, a a implementat de clasele Class, Constructor, Field, Method, Package: a <T extends Annotation> T getAnnotation(Class<T> annotationClass) Annotation[] getAnnotations() Annotation[] getDeclaredAnnotations() boolean isAnnotationPresent(Class<? notationClass) Considerm adnotarea a
1 2 3 4 5 6 7

extends Annotation> an-

import j a v a . l a n g . a n n o t a t i o n . ; @Retention ( R e t e n t i o n P o l i c y .RUNTIME) @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 ; }

356 pe care o utilizm clasa a n


1 2 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

ANEXA D. ADNOTARI

import j a v a . l a n g . a n n o t a t i o n . ; import j a v a . l a n g . r e f l e c t . ; 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 l . getMethod ( v e r i f , =c 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= g e t A n n o t a t i o n ( MyAnnotation . c l a s s ) ; m. 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 ( ) ) ; } } }

Anexa E Utilizarea SGBD Java n


Scopul acestei anexe este prezentarea bazelor utilizrii unui Sistem de a Gestiune a Bazelor de Date (SGBD - Data Bases Management System - DBMS) din Java. Exemplicm modul de operare i utilizare pentru crearea i exa s s ploatarea unei baze de date corespunztoare unei agende de adrese e-mail. a

E.1

Derby / Javadb

Instalarea produsului const dezarhivarea ierului descrcat. a n s a Utilizarea produsului. Va utilizat varianta de retea bazat pe un a a server al SGBD care utilizeaz implicit portul 1527. a Se ntreprind urmtoarele operatii: a 1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% startNetworkServer.bat

2. Crearea bazei de date se va face utiliznd utilitarul ij din distributia a Derby / Javadb. Acesta se lanseaz prin: a
set JAVA_HOME=. . . set DB_HOME=. . . set PATH=%DB_HOME%\bin;%PATH% ij.bat

Exemplul E.1.1 357

358

ANEXA E. UTILIZAREA SGBD JAVA IN

Baza de date AgendaEMail se creaz executnd a a run CreateAgendaE.sql; unde ierul CreateAgendaE.sql este s
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 );

i arcarea cu date s nc run ValuesAgendaE.sql; cu ierul ValuesAgendaE.sql s


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 ) ;

Putem crea tabele i le arca cu valori prin ant. acest caz, prealabil s nc In n trebuie creat baza de date prin intermediul utilitarului ij: a
connect jdbc:derby:AgendaEMail;create=true;

Fiierul build.xml are codul s


<?xml version="1.0"?> <project name="db" basedir="." default="usage"> <property file="build.properties"/> <path id="master-classpath"> <pathelement path="${db}"/> </path> <target name="createTables"> <echo message="CREATE TABLES USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue" src="${createTable}"> <classpath refid="master-classpath"/> </sql> </target> <target name="dropTables"> <echo message="DROP TABLES USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}"

E.2. MYSQL

359

url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue"> <classpath refid="master-classpath"/> DROP TABLE adrese; </sql> </target> <target name="loadData"> <echo message="LOAD DATA USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue" src="${valuesTable}"> <classpath refid="master-classpath"/> </sql> </target> <target name="printData"> <echo message="PRINT DATA USING: ${db.driver} ${db.url}"/> <sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue" print="true"> <classpath refid="master-classpath"/> SELECT * FROM adrese; </sql> </target> </project>

Resursele externe utilizate se xeaz ierul de proprieti build.properties a n s at


db.driver=org.apache.derby.jdbc.ClientDriver db.url=jdbc:derby://localhost:1527/AgendaEMail db.user=. . . db.pw=. . . createTable=AntCreateAdrese.sql valuesTable=ValuesAgendaE.sql db=. . ./db-derby-10.*.*.*-bin/lib/derbyclient.jar

E.2

mysql

Instalarea produsului. Pentru instalare s-a descrcat varianta fr ina aa stalare automat mysqll-*.*.*-win*.zip. Acest ier se dezarhiveaz a s a ntr-un catalog MYSQL HOME.

360

ANEXA E. UTILIZAREA SGBD JAVA IN

Implicit, serverul mysql utilizeaz portul 3306, iar ierele bazelor de date a s vor gzduite catalogul MYSQL HOME\data. a n Pentru utilizarea aplicatii Java trebuie descrcat un conector mysqln a connector-java-*.*.*.tar.gz, continnd ierul mysql-connector-java a s *.*.*-bin.jar. Utilizarea produsului. Se ntreprind urmtoarele operatii: a 1. Lansarea serverului mysql :
set MYSQL_HOME=. . . set PATH=%MYSQL_HOME%\bin;%PATH% mysqld

2. Unui utilizator i se poate atasa o parol, executnd a a ntr-o sesiune mysql comenzile
set password for root@localhost=password(parola); set password for [email protected]=password(parola);

Parola se terge prin s


set password for root@localhost=password(); set password for [email protected]=password();

Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va prezent i optiunea -p. as 3. Exemplul E.2.1 Crearea bazei de date AgendaEMail se va face prin intermediul ierului s 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 );

E.3. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE

361

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 ) ;

4. Serverul mysql se oprete prin s


set MYSQL_HOME=d:\mysql-*-win32 set PATH=%MYSQL_HOME%\bin;%PATH% mysqladmin -u root shutdown

E.3

Sablonul de utilizare a unei baze de date ntr-un program Java

Interactiunea cu baze de date relationale implic: a 1. Stabilirea corespondentei dintre date aate obiecte i atribute / tabele n s (object to relational database mapping). 2. Apelarea actiunilor CRUD (Create, Read, Update, Delete). Pentru realizarea acestor activiti se utilizeaz modelul Data Access Object at a DAO Limbajul SQL (Structured Query Language) este dependent de SGBD utilizat. Dezvoltarea interactiunii dintre un program Java (client) cu o baz de a date dintr-un SGBD s-a nscut din dorinta de a asigura independenta stratului a Java de SGBD. Solutia gsit const introducerea unui strat suplimentar, a a a n ntre Java i SGBD care asigur corespondenta s a ntre obiectele Java cu tabelele unei baze de date i permite o congurare simpl la schimbarea SGBD. Astfel s a se folosete terminologia de aplicatie multistrat. s Materializarea acestor idei (Object Relational Mapping - ORM) se a a n interfata de programare (API) Java Persistence API (JPA); Exist mai multe implementri JPA. a a interfata de programare (API) Java Data Object (JDO); produsul Hibernate. Hibernate contine i o implementare JPA. s

362

ANEXA E. UTILIZAREA SGBD JAVA IN

Scopul urmrit este realizarea trecerii de la un SGBD la altul prin modicri a a minime stratul intermediar. n Pentru nceput vom face abstractie de modelele mentionate anterior i vom s trata modul cel mai simplu realizarea unei aplicatii care interactioneaz cu n a o baz de date gestionat de un SGBD. a a Pentru a avea acces la o baz de date trebuie stabilit o conexiune la acea a a acest sens este necesar cunoaterea: baz de date. In a s 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 Fiierul s driver-ului mysql-connector-java-*.*.*-bin.jar (www.mysql.com) derbyclient.jar (distributia derby) postgresql-*.*-*.jdbc4.jar hsqldb.jar ojdbc14.jar

org.postgresql.Driver org.hsqldb.jdbcDriver oracle.jdbc.driver.OracleDriver

Dac a ntr-un servlet se realizeaz o conexiune la o baz de date atunci a a ierul driver-ului trebuie copiat catalogul lib al aplicatiei. s n adresa URL a bazei de date (String URLBazaDate), sub forma Tip SGBD Referinta 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 Sablonul de prelucrare este String URLBazaDate=. . . Connection con=null; try{ Class.forName(jdbcDriver).newInstance(); con=DriverManager.getConnection(URLBazaDate); ... } catch(ClassNotFoundException e){. . .} catch(SQLException e){. . .}

E.3. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE

363

Anumite SGBD asigur accesul la o baz de date dac sunt xati parametrii a a a acest caz se programeaz username i password. In s a con=DriverManager.getConnection(URLBazaDate,username,password); Odat conexiunea cu baza de date stabilit se genereaz un obiect de tip a a a Statement prin intermediul cruia se execut interogarea SQL. a a Statement instructiune=con.createStatement(); String sql=. . . //fraza select; Rezultatele interogrii bazei de date se obtine prin a try{ ResultSet rs=instructiune.executeQuery(sql); while(rs.next()){ prelucrarea rezultatului } } catch(SQLException e){...} Exemplul E.3.1 O interogare simpl a bazei de date AgendaEMail se realizeaz cu programul a a
1 2 3 4 6 7 9 10 11 12 14 15 16 18 19 20 21 22 23 24 25

import import import import

java . io . ; java . s q l . ; java . net . ; java . u t i l . ;

public c l a s s AgendaE { Statement i n s t r u c t i u n e=n u l l ; public void i n i t ( S t r i n g username , S t r i n g password ) { // 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 ; C o n n e c t i o n con=n u l l ; 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 ( ) ; i f ( username != n u l l ) con = DriverManager . g e t C o n n e c t i o n ( URLBazaDate , username , password ) ; else 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 ( ) ;

364

ANEXA E. UTILIZAREA SGBD JAVA IN

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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

} 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 s t a t i c void main ( S t r i n g [ ] a r g s ) { AgendaE agenda=new AgendaE ( ) ; i f ( a r g s . l e n g t h >1) agenda . i n i t ( a r g s [ 0 ] , a r g s [ 1 ] ) ; else agenda . i n i t ( null , n u l 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 ) ; 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 ; 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 ()+ \ ; s q l= s e l e c t from a d r e s e where nume=+nume ; r s=agenda . 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 ) ; i f ( r s != n u l l ) { System . out . p r i n t l n ( Sau g a s i t a d r e s e l e de em a i l : ) ; while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( r s . g e t S t r i n g ( e m a i l ) ) ; } } else { System . out . p r i n t l n ( Fara a d r e s a de em 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 ()+ \ ; 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 ; r s=agenda . 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 ) ; i f ( r s != n u l l ) {

E.3. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE

365

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

System . out . p r i n t l n ( Sa g a s i t numele + :); while ( r s . n e x t ( ) ) { System . out . p r i n t l n ( r s . g e t S t r i n g ( nume ) ) ; } } else { System . out . p r i n t l n ( Numar i n e x i s t e n t ! ) ; } 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 ) { 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 ( ) ) ; } } }

Fraza select i interogarea se mai putea programa prin s String sql="select * from adrese where nume =?"; PreparedStatement prepStmt=con.prepareStatement(sql); prepStmt.setString(1,nume); RezultSet rs=prepStmt.executeQuery(); . . . prepStmt.close(); acest caz, valoarea variabilei nume este fr apostroafe. In aa Compilarea i executia programului necesit declararea variabila classpath s a n a ierelor s Varianta Derby derbyclient.jar din catalogul %DERBY INSTALL%\lib. Varianta mysql %MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar Executia programului presupune serverul SGBD activ.

366

ANEXA E. UTILIZAREA SGBD JAVA IN

Anexa F Teme de laborator


F.1 Probleme propuse

1. S se realizeze conversia temperaturii exprimat grade Celsius grade a a n n Fahrenheit i invers. Formula de transformare este s tF = 1.8tC + 32o F RMI, programul server implementeaz interfata (la distanta) In 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 se realizeze conversia a unei sume de bani a ntre USD, EURO i RON. s Programul server (RMI) implementeaz interfata 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)

367

368

ANEXA F. TEME DE LABORATOR

throws java.rmi.RemoteException; public double rolToUsd(double rol) throws java.rmi.RemoteException; }

Rata zilnic de schimb preia dinamic sub forma unui ier xml, apelnd a s a http://www.bnr.ro/nbrfxrates.xml. 3. S se realizeze conversia unui numr natural, din cifre arabe cifre a a n romane i invers. s Pentru numere x (3999, 3999999], x = a 1000 + b se va folosi scrierea sub forma (A)B, unde A, B reprezint conversiile lui a, respectiv b. a Exemplu: Conversia numrului 2289463 este (MMCCLXXXIX)CDLXIII. a Pentru numere x (4000000, 3999999999], x = a1000000+b1000+c se va folosi scrierea sub forma [A](B)C, unde A, B, C reprezint conversiile a lui a, b, c. 4. S se realizeze conversia unui numr dintr-o baz alta. a a a n 5. Un server adun la un numr (initializat cu 0) o valoare trimis de a a a un client returnnd rezultatul. Exist o singur instanta a numrului, a a a a acelai pentru orice client. s S se programeze serviciul descris mai sus. a 6. Aplicatia productor consumator. a Fie un sistem format din dou procese P1 i P2 , primul producnd nite a s a s date care apoi vor preluate de cel de al doilea. Comunicarea ntre cele dou procese se realizeaz prin intermediul unei zone de memorie a a tampon, de o anumit dimensiune, care procesul P1 introduce a n informatii (sub forma unor nregistrri), pe care apoi P2 le extrage. a Procesul P2 nu este nevoit s atepte pentru ecare a s nregistrare parte, n iar P1 nu atept pn ce P2 este gata s receptioneze s a a a a nregistrarea produs. Procesele evolueaz independent unul de cellat, P1 introducnd a a a a tampon n nregistrarea produs, de unde P2 o va extrage la nevoie. a Se impun urmtoarele restrictii: a Procesul P1 ncearc s introduc o a a a nregistrare tampon i conn s stat c acesta s-a umplut. acest caz, el va trebui s atepte pn a a In a s a a ce se ivete un loc tampon (ceea ce se va ampla ca urmare a s n nt extrageri unei nregistrri de ctre P2 ). a a

F.1. PROBLEME PROPUSE

369

Procesul P2 ncearc s extrag o a a a nregistrare i constat c tams a a acest caz el va trebui s atepte pn ce apare o ponul este gol. In a s a a nregistrare ca urmare a introduceri unei nregistrri tampon de a n ctre P1 . a Se denete interfata RMI s
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 interfetei IBoundedBuer. (b) Realizarea a dou programe client Producator, care introduce obiecte a tampon i Consumator pentru extragerea lor. n s 7. Aplicatie 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; } }

Interfata aplicatiei RMI IEmailServer este

370

ANEXA F. TEME DE LABORATOR

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 prealabil s n a se nregistreze (createUser). Un client nregistrat se poate conecta la serverul de e-mail (login) dup a care poate scrie (trimite) sau citi (receptiona) mesaje. Se cere ca la adgarea unui mesaj (deci a naintea apelrii metodei User.addEmail) a s se verice dac emitentul este conectat i dac destinatarul este a a s a nregistrat. caz contrar se genereaz exceptia UnknownUserException n a
package iemail; public class UnknownUserException extends Exception { public UnknownUserException() { super(); }

F.1. PROBLEME PROPUSE

371

public UnknownUserException(String exception) { super(exception); } }

Citirea mesajelor este lsat la latitudinea clientilor sensul c clientul a a n a implementeaz metoda printEmail al interfetei ICallbackEmail. a
package iemail; import java.rmi.*; import java.rmi.server.*; public interface ICallbackEmail extends Remote { public void printEmail(Email email) throws RemoteException; }

Solicitarea receptionrii mesajelor se realizeaz de ctre server prin apelarea a a a metodei printEmail pentru ecare mesaj primit de client. Se cere: (a) Implementarea interfetei IEmailServer. (b) Realizarea a dou programe client AddClient pentru a nregistrarea utilizatorilor i ClientEmail pentru exploatarea serviciului de es mail. Fiecare din cele dou programe are ca parametri numele a (identicatorul) clientului, parola i referinta serverului. s 8. Integrare numeric. a Scopul aplicatiei este calculul unei integrale de un program server cu functia de integrat detinut de ctre client. cazul aplicatiei RMI, a a In evalurile functiei cerute de formula de integrare numeric se vor reala a iza prin apel invers. Integrarea numeric va executat de un server a disponibil clientilor prin mecanismul de fabric de obiecte. a Interfata fabricii de obiecte este
package integ; import java.rmi.*; public interface IFabIntegrator extends Remote{ IIntegrator getIntegrator() throws RemoteException; }

iar interfata IIntegrator este


package integ; import java.rmi.*; public interface IIntegrator extends Remote{ double adaptiveSimpson(double leftEnd, double rightEnd, double epsilon, int initParam) throws RemoteException; }

372

ANEXA F. TEME DE LABORATOR

declar o metod ce calculeaz un ir (Imk )k pn momentul |Imk a a a s a a n Imk1 | < . Propunem utilizarea formulei lui Simpson
b a m1 m1 ba f (x)dx Im = [f (a) + 2 f (a2i ) + 4 f (a2i+1 ) + f (b)] 6m i=1 i=0

unde ai = a + i ba . 2m Sirul (mk )k este denit prin mk = 2k m0 . Semnicatia parametrilor metodei adaptiveSimpson este leftEnd rightEnd epsilon initParam Interfata apelului invers este
package integ; import java.rmi.*; double function(double x)throws RemoteException; }

a b m0

Se cere implementarea aplicatiei cu minimizarea numrului de apelri a a a metodei function. 9. Agend telefonic. a a Pentru crearea i s ntretinerea unei agende telefonice utiliznd RMI con a siderm: a Un ServerCarteTelefon realizeaz urmtoarele operatii: a a adaug o a nregisrare agenda telefonic; n a O nregistrare este alctuit dintr-o pereche (nume, numr). a a a
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; } }

F.1. PROBLEME PROPUSE

373

sterge nregistrarea corespunztoare unui nume din agenda telea fonic. a interogarea agendei: furnizeaz numrul de telefon al unui nume; a a modicarea numrului de telefon corespunztor unui nume; a a aarea s nregistrrilor; a salvarea nregistrrilor a ntr-un ier; s restaurarea nregistrrilor dintr-un ier. a s Interfata corespunztoare ICarteTelefon este a
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; }

Interfata fabricii de obiecte IFabCarteTelefon este


package itelef; import java.rmi.*; public interface IFabCarteTelefon extends Remote{ ICarteTelefon getCarteTelefon() throws RemoteException; }

Se cere implementarea aplicatiei de creare i s ntretinere a agendei tele fonice. Se extinde aplicatia anterioar cu functiunea suplimentar a serverului de a a a retine toate modicrile efectuate de ctre un client i care la solicitare a a s pot aate. s Modicrile se retin a ntr-o variabil mod de tip Vector. La solicitarea a clientului, pentru ecare modicare memorat, programul server apea leaz metoda schimbStare declarat interfata a a n
package itelef; import java.rmi.*; public interface IApelInvers extends Remote{ void schimbStare(Entry e) throws RemoteException; }

374

ANEXA F. TEME DE LABORATOR

Metoda schimbStare(Entry e) nu face altceva dect aeaz cmpurile a s a a variabilei e. Interfata ICarteTelefon declar plus metoda a n void apelInvers(IApelInvers obj)throws RemoteException; Aceast metod va implementat programul ServerCarteTelefon.java. a a a n Elementelor retinute vectorul mod li se aplic metoda schimbStare(). n a S se implementeze acest functiune utiliznd tehnica apelului invers. a a a Se poate utiliza baza de date AGENDATELEFONICA format din tabelul a TELEF ID NUME NUMAR 10. S se realizeze programe client avnd o interfat grac. Recomandm a a a a a utilizarea produsului NetBeans. R. Exemplu de client pentru problema calculului celui mai mare divizor comun a dou numere cu soclu TCP. a
import java.net.*; import java.io.*; public class VisualCmmdcClient extends javax.swing.JFrame { public VisualCmmdcClient() { initComponents(); } private void initComponents(){ // cod generat de Netbeans } private void jButton1MouseClicked(java.awt.event.MouseEvent evt){ long m=(new Long(jTextField1.getText())).longValue(); long n=(new Long(jTextField2.getText())).longValue(); String host=jTextField4.getText(); int port=(new Integer(jTextField5.getText())).intValue(); Socket cmmdcSocket = null; DataInputStream in=null; DataOutputStream out=null; try { cmmdcSocket = new Socket(host, port); out=new DataOutputStream(cmmdcSocket.getOutputStream()); in=new DataInputStream(cmmdcSocket.getInputStream()); }

F.1. PROBLEME PROPUSE

375

catch(UnknownHostException e) { System.err.println("Server necunoscut: "+host); System.exit(1); } catch (IOException e) { System.err.println("Eroare I/O : "+host+" la portul "+port); System.exit(1); } try{ out.writeLong(m); out.writeLong(n); long r=in.readLong(); jTextField3.setText(new Long(r).toString()); out.close(); in.close(); cmmdcSocket.close(); } catch(IOException e){ System.err.println("Imposibilitate de comunicare"); } } private void exitForm(java.awt.event.WindowEvent evt) { System.exit(0); } public static void main(String args[]) { new VisualCmmdcClient().setVisible(true); } private private private private private private private private private private } javax.swing.JButton jButton1; javax.swing.JLabel jLabel1; javax.swing.JLabel jLabel2; javax.swing.JLabel jLabel3; javax.swing.JLabel jLabel4; javax.swing.JTextField jTextField1; javax.swing.JTextField jTextField2; javax.swing.JTextField jTextField3; javax.swing.JTextField jTextField4; javax.swing.JTextField jTextField5;

11. S se determine zodia (chinezeasc) corespunztoare unei date calena a a daristice. Obs. Inceputul anului nou chinezesc nu coincide cu nceputul anului nou calendaristic. a a Se va crea baza de date AN CHINEZESC alctuit din tabelul INCEPUT AN LUNA ZI 12. Se consider baza de date UNITATI DE MASURA format din tabelul a a

376 CONVERSIE UM SI UM SIMBOL DENUMIRE (ROM) VAL Exemplu: 1 2 3 4 M INCH Tol M FEET (FT) Picior KG UK ONCE Uncie (UK) KG UK POUND Livra (UK)

ANEXA F. TEME DE LABORATOR

0.0254 0.3048 0.031103 0.373

S se realizeze o aplicatie pentru conversia unitilor de msur extinznd a at a a a continutul bazei de date. 13. Se consider baza de date NORME-DIDACTICE format din tabelele a a CADRU-DIDACTIC COD-CADRU-DIDACTIC NUME MATERIA COD-MATERIE DENUMIRE CURSURI COD-CURS COD-CADRU-DIDACTIC COD-MATERIE

S se elaboreze programe de a ntretinere i interogare a bazei de date. s 14. Se consider baza de date APROVIZIONARE format din tabelele a a RESURSA FURNIZOR CONTRACT COD-RESURSA COD-FURNIZOR COD-CONTRACT DENUMIRE NUME COD-FURNIZOR CANTITATE COD-RESURSA CANTITATE S se elaboreze programe de a ntretinere i interogare a bazei de date. s 15. Se consider baza de date DESFACERE format din tabelele a a PRODUSE BENEFICIAR CONTRACT COD-PRODUS COD-BENEFICIAR COD-CONTRACT DENUMIRE NUME COD-BENEFICIAR CANTITATE COD-PRODUS CANTITATE

F.1. PROBLEME PROPUSE

377

S se elaboreze programe de a ntretinere i interogare a bazei de date. s 16. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie numrul de ordine atribuit de a Evidenta populatiei unei persoane la natere, de cetenie romn, care se s at a a nscrie actele i certicatele de stare civil i se preia celelate acte cu n s a s n caracter ocial.

Structura unui CMP este

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 folosete cheia de testare 279146358279. s Primele 12 cifre ale CNP se nmultesc pe rnd de la stnga spre dreapta a a cu cifra corespunztoare a cheii de testare. Cele 12 produse se adun, a a iar suma se mparte la 11. Dac restul artirii este mai mic dect 10, a mp a atunci acesta va cifra de control. Dac restul artirii este 10 atunci a mp cifra de control este 1. S se elaboreze un program pentru vericarea CNP. a 17. Informatiile unui aeroport civil privind decolrile(plecri) i aterizri(sosiri) a a s a pe parcursul unei perioade sunt cuprinse tabelul activitate al bazei de n date aeroport

378 ACTIVITATE ID FEL aterizare/decolare ZI TIMP ora/minut COMPANIE OBSERVATIE de la/spre

ANEXA F. TEME DE LABORATOR

S se realizeze o aplicatie de furnizare a datelor ctre clienti (interogarea a a bazei de date).

Bibliograe
[1] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I., 1998, Limbajul Java. O perspectiv pragmatic. Ed. Computer Libris a a Agora, Cluj-Napoca. [2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru aplicatii Web. Ed. Albastr, Cluj-Napoca. a [3] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicatii. Ed. Al bastr, Cluj-Napoca. a [4] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucureti. s [5] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Iai. s [6] JURCA I., 2000, Programarea retelelor de calculatoare. Ed. de Vest, Timioara. s [7] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming. OReilly. [8] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iai. s [9] SCHEIBER E., 2007, Programare concurent i paralel distribuit n Java. as a Ed. Albastr, Cluj-Napoca. a [10] TANASA S., ANDREI S., OLARU C., 2011, Java de la 0 la extert. Ed. Polirom, Iai. s [11] TANASA S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosind Java. Ed. Polirom, Iai. s [12] * * * , Java 2 SDK /docs/, Sun Microsystems. [13] * * * , JavaWS Tutorial 1.*, Sun Microsystems. 379

380 [14] * * * , J2EE Tutorial, Sun Microsystems. [15] * * * , Java 2 Tutorial, Sun Microsystems.

BIBLIOGRAFIE

S-ar putea să vă placă și