0% au considerat acest document util (0 voturi)
455 vizualizări

ProgramareDistribuitaJava PDF

Încărcat de

scheiber
Drepturi de autor
© © All Rights Reserved
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)
455 vizualizări

ProgramareDistribuitaJava PDF

Încărcat de

scheiber
Drepturi de autor
© © All Rights Reserved
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/ 709

ERNEST SCHEIBER

PROGRAMARE
IN JAVA
DISTRIBUITA
Volumul I

Brasov

Prefat
a
Scopul acestui curs este prezentarea tehnologiilor de programare Java care
permit realizarea aplicatiilor client - server:
socluri Java;
apelarea metodelor de la distanta
Remote Method Invocation - RMI ;
Common Object Request Brocker Arhitecture - CORBA;
mesageria Java;
servlet;
Java Server Pages - JSP;
Java Web Start;
WebSocket;
Enterprise Java Bean.
Accentul cade pe detaliile tehnice de realizare a comunicatiilor si pe arhitectura programelor / aplicatiilor care le utilizeaza. Trebuie semnalat faptul
ca exemplele date nu ncorporeaza aspecte indispensabile unei aplicatii informatice la standardele zilei:
securitate, autentificare si autorizare;
interfata grafica pentru componenta client;
utilizarea bazelor de date relationale / orientate obiect / NoSQL.
3

4
Metodele si instrumentele de programare vor fi exemplificate, de cele mai
multe ori, pe problema foarte simpla de calcul a celui mai mare divizor comun
a doua numere naturale. Codul acestei metode de calcul poate fi
Varianta imperativ
a ca metod
a
1
2
3
4
5
6
7
8
9
10
11

public long cmmdc( long m, long n ) {


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

care se poate transforma ntr-o lambda expresie


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

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

Varianta declarativ
a / recursiv
a
1
2
3
4
5
6
7
8
9

public long cmmdc( long m, long n ) {


i f (m==n )
return m;
else
i f (m>n )
return cmmdc(mn , n ) ;
else
return cmmdc(m, nm) ;
}

Guava: Google Core Libraries for Java poseda o metoda de calcul a celui mai
mare divizor a doua numere naturale com.google.common.math.LongMath.
gcd(...).
Pentru aplicatiile care utilizeaza o baza de date, sistemul de gestiune a
bazei de date (SGBD) va fi una dintre sistemele Derby/Javadb sau mysql.
Tiparul de nv
atare propus este
1. Se instaleaza toate resursele necesare (Se exemplifica la laborator).

5
2. Se executa aplicatia / aplicatiile din curs (Se exemplifica la laborator).
3. Pentru fiecare tehnologie, pe suportul oferit de curs, se programeaza o
alta aplicatie.
Propunem urmatoarele teme:
Conversia dintre grade Celsius si grade Fahrenheit (F = 1.8C + 32).
Crearea, ntretinerea si utilizarea unei agende de adrese de e-mail.
Agenda este o baza de date.
4. In final, se rezolva tema pentru examen.
Nu de putine ori metodele / tehnologiile utilizate presupun utilizarea unui
sablon de programare specific. Din acest punct de vedere, acest curs se doreste
a fi un suport metodic.
Utilizand sistemul de operare MS Windows propunem utilizarea urmatoarelor
produse informatice auxiliare:
Google Chrome Navigator
Notepad++ Editor de fisiere
MultiCommander Gestionar de fisiere
Sursele programele din curs sunt disponibile prin git:
https://github.com/e-scheiber/DistributedProgramming1.git
Probleme:
http2
Docker, Vagrant, Kubernetes
JSR 371 mvc

Produsele informatice utilizate


Pe durata existentei, produsele informatice evolueaza prin versiunile pe care
producatorii ni le pun la dispozitie. Nu de putine ori o versiune noua nu este
compatibila cu versiunea anterioara, fapt care necesita adaptarea programelor
la modificarile operate.
Lista urmatoare precizeaza versiunile produselor utilizate n curs, indicate
n majoritatea cazurilor prin resursa de instalare.

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

Versiunile produselor informatice utilizate n lucrare


Produsul informatic
Resursa/versiunea
apache-ant
apache.ant-1.9.7-bin.tar.gz
apache-commons-fileupload
commons-fileupload-1.3.1-bin.tar.gz
apache-ftpserver
ftpserver-1.0.6.tar.gz
apache-maven
apache-maven-3.3.9-bin.tar.gz
apache-shiro
apache-shiro-1.2.4
apache-tomcat
apache-tomcat-8.0.33.tar.gz
apacheds
apacheds-2.0.0-M21.tar.gz
glassfish
java ee sdk 7u2.zip, glassfish-4.1.1.zip
gradle
gradle-2.12-all.zip
google appengine
appengine-java-sdk-1.9.34.zip
db-derby
db-derby-10.12.1.1-bin.tar.gz
httpcomponents-client
httpcomponents-client-4.5.1-bin.tar.gz
httpcomponents-asyncclient httpcomponents-asyncclient-4.1.1-bin.tar.gz
Java (jdk)
jdk-8u91-windows-{i586;x64}.exe
junit
junit4.12.zip
mysql
mysql-5.7.10-win{32;x64}.zip
mysql-connector
mysql-connector-java-5.1.37.tar.gz
openmq
openmq5 1 1-binary-windows.zip

Cuprins
1 Introducere

15

21

TEHNOLOGII PENTRU RET


ELE LOCALE

2 Programare cu socluri Java


2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . .
2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . .
2.2.1 Aplicatie client server cu socluri . . .
2.2.2 Streaming . . . . . . . . . . . . . . . .
2.3 Datagrame . . . . . . . . . . . . . . . . . . . .
2.3.1 Aplicatii client server cu datagrame.
2.3.2 Multicast vs. Broadcast . . . . . . . .
2.4 Canale de comunicatie . . . . . . . . . . . . .
2.4.1 SocketChannel & DatagramChannel .
2.4.2 Receptie cu Selector . . . . . . . . .
2.4.3 Comunicatii asincrone prin canale . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

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

3 Reg
asirea obiectelor prin servicii de nume
69
3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 69
3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
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
9

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

77
77
81
87
93
98
98
104

10

CUPRINS

5 Mesaje n Java
5.1 Java Message Service (JMS) . . . . . . . . . . . .
5.2 Open Message Queue 5 . . . . . . . . . . . . . . .
5.3 Elemente de programare - JMS-2 . . . . . . . . .
5.3.1 Modul programat: Trimiterea unui mesaj .
5.3.2 Receptia sincrona a unui mesaj . . . . . .
5.3.3 Receptia asincrona a unui mesaj . . . . . .
5.3.4 Publicarea mesajelor . . . . . . . . . . . .
5.3.5 Abonare si receptia mesajelor . . . . . . .
5.3.6 Cazul abonatului partajat . . . . . . . . .
5.3.7 Obiecte administrator prin JNDI . . . . .
5.3.8 Comunicatia prin coada - queue . . . . . .
5.3.9 Comunicatia pe baza de subiect - topic . .
5.3.10 Utilizarea mesajelor de tip StreamMessage
5.3.11 Aplicatie JMS slab cuplata . . . . . . . . .
5.3.12 Programare JMS prin glassfish . . . . . . .

II

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

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

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

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

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

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

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

COMUNICAT
II PRIN INTERNET

6 HyperText Transfer Protocol


6.1 Transactie http . . . . . . . . . .
6.2 Server Web - container de servlet
6.3 Serverul Web apache-tomcat . . .
6.4 Glassfish . . . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

113
. 113
. 115
. 116
. 117
. 119
. 120
. 122
. 123
. 124
. 127
. 128
. 131
. 133
. 136
. 139

143
.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

145
. 145
. 152
. 153
. 155

7 Conexiune simpl
a prin clase din java.net
157
7.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 157
8 Servlet
8.1 Marcajul <form> . . . . . . . . . . . . . . . .
8.2 Realizarea unui servlet . . . . . . . . . . . . .
8.2.1 Codul unui servlet . . . . . . . . . . .
8.3 Procesare asincrona n servlet . . . . . . . . .
8.4 Dezvoltari n servlet-api 3.1 . . . . . . . . . .
8.4.1 Procesare asincrona neblocanta . . . .
8.4.2 Modificarea protocolului http: upgrade
8.5 Facilitati de programare cu servlet . . . . . . .
8.5.1 Program client al unui servlet . . . . .
8.5.2 Servlete nlantuite . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

159
. 160
. 162
. 164
. 171
. 177
. 177
. 179
. 185
. 185
. 194

11

CUPRINS

8.5.3 Sesiune de lucru . . . . . . . . . . . . .


8.5.4 Cookie . . . . . . . . . . . . . . . . . .
8.5.5 Gestiunea butoanelor - TimerServlet .
8.5.6 Autentificare . . . . . . . . . . . . . .
8.5.7 Servlet cu conexiune la o baza de date
8.5.8 Imagini furnizate de servlet . . . . . .
8.5.9 Servlet cu RMI . . . . . . . . . . . . .
8.5.10 Servlet cu JMS . . . . . . . . . . . . .
8.5.11 Servlet cu jurnalizare . . . . . . . . . .
8.6 FileUpload . . . . . . . . . . . . . . . . . . . .
8.7 Descarcarea unui fisier . . . . . . . . . . . . .
8.8 Filtru . . . . . . . . . . . . . . . . . . . . . .
8.9 Eveniment si auditor . . . . . . . . . . . . . .
8.10 Server apache-tomcat ncorporat . . . . . . . .

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

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

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

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

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

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

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

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

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

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

196
197
200
203
205
207
209
211
213
214
219
220
223
225

9 Java Server Page JSP


9.1 Tehnologia JSP . . . . . . . . . . . . . . .
9.1.1 Declaratii JSP . . . . . . . . . . . .
9.1.2 Directive JSP . . . . . . . . . . . .
9.1.3 Marcaje JSP predefinite . . . . . .
9.1.4 Pagini JSP cu componente Java . .
9.2 JSP Standard Tag Library JSTL . . . . .
9.2.1 Biblioteca de baza . . . . . . . . .
9.2.2 Biblioteca de lucru cu baze de date
9.3 Marcaje JSP personale . . . . . . . . . . .
9.3.1 Marcaje fara atribute si fara corp. .
9.3.2 Marcaje cu atribute si fara corp. . .
9.3.3 Marcaje cu corp. . . . . . . . . . .
9.4 Autentificare si autorizare cu apache-shiro

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

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

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

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

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

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

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

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

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

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

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

227
. 227
. 232
. 234
. 235
. 236
. 239
. 240
. 245
. 246
. 247
. 250
. 252
. 254

10 Desf
asurarea n nor
10.1 Servlet si JSP n Google App
10.2 Heroku . . . . . . . . . . . .
10.2.1 JSP n Heroku . . .
10.2.2 Servlet n Heroku . .
10.3 OpenShift . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

Engine
. . . . .
. . . . .
. . . . .
. . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

263
264
266
267
270
273

11 Java Web Start


277
11.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 277

12

CUPRINS

12 WebSocket
12.1 Protocolul WebSocket . . . . . . . . . . . . . . . . . .
12.2 Interfata de programare HTML5 de client WebSocket .
12.3 WebSocket n Java . . . . . . . . . . . . . . . . . . . .
12.3.1 Programare prin adnotari . . . . . . . . . . . .
12.3.2 Programare fara adnotari . . . . . . . . . . . .
12.3.3 Client Java pentru WebSocket . . . . . . . . . .
12.3.4 Transmiterea datelor prin adnotarea PathParam
12.3.5 Conversie si deconversie prin JSON / XML . . .
12.3.6 Streaming . . . . . . . . . . . . . . . . . . . . .
13 Enterprise Java Beans
13.1 Session EJB . . . . . . . . . . . . . . . . .
13.1.1 Componenta EJB sesiune stateless
13.1.2 Componenta cu metode asincrone .
13.1.3 Aplicatie JEE cu module EJB, Web
13.1.4 Componenta EJB sesiune singleton
13.1.5 Componenta EJB sesiune stateful .
13.2 Componenta EJB MessageDriven . . . . .
13.3 Componenta EJB Entity . . . . . . . . . .

.
.
.
.
.
.
.
.
.

283
. 283
. 284
. 285
. 286
. 291
. 293
. 294
. 297
. 304

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

311
. 312
. 313
. 316
. 317
. 319
. 321
. 324
. 327

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

14 Aplicatie pe nivele
333
14.1 Nivelele unei variante de rezolvare . . . . . . . . . . . . . . . . . 334

III

ANEXE

A Unelte de dezvoltare
A.1 XML . . . . . . . .
A.2 apache-ant . . . . .
A.3 apache-maven . . .
A.4 Gradle pentru Java

339
.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

341
. 341
. 344
. 346
. 359

B Fir de executie prin -expresie

365

C Testare cu junit

369

D Jurnalizare

373

E Component
a Java

377

CUPRINS

13

F Serializare f
ar
a XML
379
F.1 YAML Aint Markup Language - YAML . . . . . . . . . . . . . 380
F.2 JavaScript Object Notation - JSON . . . . . . . . . . . . . . . . 382
G Adnot
ari
G.1 Definirea unei adnotari . . . . . . . . . . . . . . . . . . . . . .
G.2 Declararea unei adnotari . . . . . . . . . . . . . . . . . . . . .
G.3 Procesarea unei adnotari . . . . . . . . . . . . . . . . . . . . .

389
. 389
. 390
. 391

H Utilizarea SGBD n Java


H.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . .
H.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
H.3 Sablonul de utilizare a unei baze de date . . . . . . . . . . . .

395
. 395
. 396
. 398

Injectarea dependintelor
405
I.1 Weld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405

IV

TEME DE LABORATOR

409

J Teme de aplicatii
411
J.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Bibliografie

419

14

CUPRINS

Capitolul 1
Introducere
Retelele locale, internetul, raspandirea pe o arie geografica a resurselor si a
locatiilor n care se petrec actiuni ce tin de o activitate bine definita sau sunt
urmarite, gestionate din alte locuri au drept consecinta existenta aplicatiilor
distribuite. Termenul distribuit se refera tocmai la faptul ca componente ale
aplicatiei se afla pe calculatoare diferite dar ntre care au loc schimburi de
date. Daca partile unei aplicatii sau resursele utilizate se gasesc pe calculatoare
distincte atunci aplicatia se numeste distribuita.
Intre partile sau resursele unei aplicatii distribuite au loc schimburi de
date, ceea ce se face utilizand diferite mecanisme la realizarea carora concura
sistemul de calcul, sistemul de operare si limbajul de programare.
Astfel se vorbeste de programare distribuita ca mijloc de realizare a aplicatiilor
distribuite. Pe langa algoritm, structuri de date, limbaj de programare, la
realizarea unei aplicatii distribuite intervin comunicatiile: schimbul de date
dintre doua componente aflate pe calculatoare diferite.
Transmisia datelor poate fi:
discreta - numarul datelor transmise este fixat;
n flux (streaming) - se transmit un volum de date n mod continuu.
In cadrul comunicatiilor, transmisia de date presupune transformarea acestora din formatul tipizat n sir de octeti si invers - serializarea datelor. In acest
scop tehnologiile de programare utilizeaza modalitati diverse, de la atribuirea
acestei sarcini catre programator pana la asigurarea unui cadru fix de realizare
a serializarii.
Punem n evidenta doua modele de aplicatii distribuite:
client-server: Programul server executa cererile clientilor.
15

16

CAPITOLUL 1. INTRODUCERE

O aplicatie client server se compune din:


componenta server - alcatuita din programe / clase ce asigura una
sau mai multe functiuni (servicii), care pot fi apelate de catre clienti.
componenta client - alcatuita din programe / clase care permit accesul la server si apelarea serviciilor acestuia.
Serverul si clientul (clientii) ruleaza, de obicei, pe calculatoare distincte.
Un server trebuie sa satisfaca cererile mai multor clienti.
Aplicatia server se va gasi (desfasura) ntr-o aplicatie de tip server de
aplicatie, server Web. Aceste aplicatii au de multe ori un caracter integrator n sensul ca nglobeaza resursele necesare diverselor tehnologii de
programare distribuita. Tendinta curenta consta din gazduirea aplicatiilor
server n nor (cloud ).
Durata de viata a unei aplicatii client server este data de durata
functionarii serverului. Aceasta durata poate fi alcatuita din intervale
disjuncte de timp, ntre acele intervale, din diverse motive, serverul este
inactiv.
Intervalul de timp determinat de conectarea unui client la server si pana
la deconectare poarta numele de sesiune. In aceasta perioada, clientul
poate invoca mai multe servicii ale serverului. Un client poate initia mai
multe sesiuni.
Un client trebuie sa-si regaseasca datele n cadrul unei sesiuni, ntre sesiuni, pe toata durata de viata a aplicatiei. Astfel se pune problema
retinerii / persistentei datelor pentru fiecare client n parte.
Amintim urmatoarele tehnologii Java pentru realizarea aplicatiilor clientserver:
Tehnologii destinate retelelor locale, nebazate pe protocolul http.

Socluri
Remote Method Invocation (RMI)
Common Object Request Brocker Arhitecture (CORBA)
Java Message Service (JMS)

Comunicatiile utilizeaza porturi care nu trebuie sa fie nchise de


eventuale aplicatii de tip firewall.
Tehnologii cu comunicatii prin Internet, bazate pe protocolul http.

17
Servlet si Java Server Pages (JSP)
Java Web Start
WebSocket
dispecer-lucr
ator: Programul dispecer distribuie sarcinile de executat lucratorilor si le coordoneaza activitatea. Exista multe abordari de
programere a aplicatiilor dispecer-lucrator.
Exista diferente mari ntre o aplicatie care ruleaza pe un calculator si o
aplicatie distribuita1 :
latenta (latency) - exista mai multe definitii:
diferenta n timp ntre o operatie executata pe un calculator la
distanta de executia ei pe calculatorul local.
diferenta n timp ntre momentul receptionarii raspunsului la o
cerere si momentul lansarii ei.
diferenta n timp ntre momentul receptionarii unei cereri si momentul transmiterii raspunsului.
Receptia rezultatului unei operatii executate pe un calculator la distanta
se poate programa
sincron de obicei receptia blocheaza firul de executie al apelului
pana la sosirea rezultatului;
asincron concept care are mai multe materializari:
receptia se obtine ntr-un obiect dedicat care se executa n afara
firului de executie al apelului.
(JMS, servlet)
rezultatul solicitarii este un obiect de tip Future< T > si a
carui procesare se poate face dupa instantierea obiectului T.
(socluri cu canale de comunicatii, client servlet)
O preocupare continua este dezvoltarea de tehnologii hard si soft pentru
micsorarea latentei.
accesul la memorie (memory access). Instrumente de programare - cadre
de lucru (framework ) care mijlocesc realizarea aplicatiilor asigura accesul
la resursele aflate n memoria calculatoarelor (read, write, send, receive).
1

Waldo J., Wyant G., Wollrath A., Kendall S., 1994, A Note on Distributed Computing.
Sun Microsystems Corporation, Technical report, SMLI TR-94-29.

18

CAPITOLUL 1. INTRODUCERE

interoperabilitate. Aplicatiile distribuite pot rula pe platforme diferite


(de exemplu Linux si Windows sau Java si .NET) iar componentele ei
pot fi realizate n limbaje de programare diferite.
Exista o preocupare pentru produse care asigura interoperabilitatea dintre platformele de calcul.
prabusirea partiala (partial failure) consta n ncetarea functionarii unei
parti a aplicatiei distribuite, dar care continua sa fie accesibila. Tratarea
acestei probleme pare a fi cea mai dificila tema a programarii distribuite.
Teorema CAP (Eric Brewer, 2000) trateaza legatura dintre prabusirea
partiala, disponibilitatea aplicatiei si consistenta datelor.
Precizam sensul unor notiuni utilizate n lucrare:
protocol - pachet de reguli, sablon utilizat n comunicatii, n accesarea
unor resurse. Exemple de protocoale utilizate sunt:
http - HyperText Transfer Protocol este principalul protocol utilizat
n comunicatiile prin Internet;
https protocol http securizat;
file - protocol pentru specificarea fisierelor aflate pe calculatorul
local;
ftp - File Transfer Protocol - protocol pentru transferul fisierelor
ntre doua calculatoare;
smtp - Simple Message Transfer Protocol utilizat de posta elecronica.
host - calculatorul gazda, cel pe care se lucreaza. Acest calculator se
specifica printr-o adresa IP (Internet Protocol ) sau printr-un nume.
port - un numar care identifica aplicatia responsabila de prelucrarea solicitarii. Implicit, anumitor protocoale le sunt asociate porturi. Dintre
acestea amintim:
Port Utilizat de
80
http
443
https
25
smtp
Referintele resurselor se indica folosind Uniform Resource Identifiers - (URI)
si mai precis Uniform Resource Locator - (URL). URI identifica o resursa n
timp ce URL desemneaza locatia resursei. URL se considera ca un caz particular de URI. Sintaxa folosita pentru URI este

19
protocol://host[:port][cale][?cerere]
Un rol important n dezvoltarea tehnologiilor legate de limbajul Java revine
organizatiilor de standardizare:
Java Community Process JCP;
Organization for the Advancement of Structured Information Standards
OASIS;
The Internet Engineering Task Force IETF.

Intreb
ari recapitulative
1. Explicati notiunea de latenta.
2. Explicati termenul de protocol si dati exemple de protocoale de comunicatie.
3. Explicati notiunea de prabusire partiala.
4. Ce desemneaza denumirea Java Community Process?
5. Precizati sintaxa unui URI.

20

CAPITOLUL 1. INTRODUCERE

Partea I
TEHNOLOGII PENTRU
RET
ELE LOCALE

21

Capitolul 2
Programare cu socluri Java
Comunicatia bazata pe socluri Java constituie modalitatea de nivelul inferior pentru realizarea aplicatiilor distribuite. Din punct de vedere fizic un
soclu este o interfata de conectare la procesor. Soclurile se afla pe placa de
baza. Notiunea de soclu dintr-un mediu de programare este diferita de soclul
fizic. In cele ce urmeaza ne intereseaza soclul n mediul Java.

2.1

TCP vs. UDP

Calculatoarele ce ruleaza n retea comunica ntre ele folosind protocolul


TCP (Transmission Control Protocol) sau UDP (User Datagram Protocol).
Intr-un program Java se utilizeaza clasele pachetului java.net prin intermediul carora se acceseaza nivelele deservite de protocoalele TCP sau UDP.
In felul acesta se pot realiza comunicatii independente de platforma de calcul.
Pentru a alege clasa Java care sa fie utilizata trebuie cunoscuta diferenta dintre
TCP si UDP.
TCP Cand doua aplicatii comunica ntre ele se stabileste o conexiune prin
intermediul careia se schimba date. Folosind protocolul TCP, comunicatia
garanteaza ca datele trimise dintr-un capat ajung n celalalt capat cu pastrarea
ordinii n care au fost trimise. Acest tip de comunicatie seamana cu o convorbire telefonica. TCP furnizeaza un canal sigur de comunicatie ntre aplicatii.
UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de
date numite datagrame de la o aplicatie la alta fara sa se asigure faptul
ca datagramele ajung la destinatie si nici ordinea lor de sosire. Acest tip de
comunicatie seamana cu trimiterea scrisorilor prin posta.
23

24

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.2

Soclu TCP

Pentru a comunica utilizand TCP programul client si programul server


stabilesc o conexiune sigura. Fiecare program se leaga la conexiune printr-un
soclu (socket). Un soclu este capatul unei cai de comunicatie bidirectional
ntre doua programe ce ruleaza n retea. Un soclu este legat de un port prin
care nivelul TCP poate identifica aplicatia careia i sunt transmise datele.
Pentru a comunica atat clientul cat si serverul citesc date de la si scriu date
la soclul legat la conexiunea dintre ele.
In pachetul java.net clasele Socket si ServerSocket implementeaza un
soclu din partea clientului si respectiv din partea serverului.
Clientul cunoaste numele calculatorului pe care ruleaza serverul cat si portul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ncearca
un rendez-vous cu serverul de pe masina serverului si la portul serverului. Daca
totul decurge bine, serverul accepta conexiunea. Dupa acceptare, serverul
creaza pentru client un nou soclu legat la un alt port n asa fel ncat ascultarea cererilor la soclul initial sa poata continua n timp ce sunt satisfacute
cererile clientului conectat. Din partea clientului, dupa acceptarea conexiunii
soclul este creat si este utilizat pentru comunicatia cu serverul.

Clasa java.net.Socket
Resursele clasei Socket sunt destinate clientului.
Constructori
public Socket(String host, int port) throws UnknownHostException,
IOException
Creaza un soclu conectat la calculatorul cu portul specificat.
public Socket(InetAddress host, int port) throws IOException
Creaza un soclu conectat la calculatorul cu portul specificat.
Metode
public InputStream getInputStream() throws IOException
Returneaza un flux de intrare atasat soclului, pentru citirea (preluarea)
informatiilor de la soclu.

2.2. SOCLU TCP

25

public OutputStream getOutputStream() throws IOException


Returneaza un flux de iesire atasat soclului, pentru scrierea (transmiterea)
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
Creaza un soclu la portul specificat. Daca port=0, atunci va fi utilizat
orice port disponibil. Capacitatea sirului (tamponului) de asteptare pentru cererile de conectare se fixeaza la valoarea implicita 50. Cererile n
exces vor fi refuzate.
public ServerSocket(int port, int lung) throws IOException
In plus fixeaza lungimea sirului (tamponului) de asteptare.
Metode
public Socket accept() throws IOException
Metoda blocheaza procesul (firul de executie) apelant pana la sosirea
unei cereri de conectare si creaza un soclu client prin care se va desfasura
comunicarea cu solicitantul acceptat.
public synchronized void close() throws IOException
nchide soclul de referinta.

2.2.1

Aplicatie client server cu socluri

Serverul trebuie sa satisfaca simultan solicitarile mai multor clienti. Fiecare


client apeleaza programul server la acelasi port si n consecinta cererile de
conectare sunt receptionate de acelasi ServerSocket. Serverul receptioneaza
apelurile secvential. La un apel, se creaza de partea severului un soclu prin
care se va face schimbul de date cu clientul. Cererile clientilor pot fi satisface
concurent/paralel, utilizand fire de executie ce implementeaza serviciul oferit
sau secvential - n cazul unor servicii de durata scurta.

26

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.2.1 Sistem client - server pentru calculul celui mai mare divizor
comun a doua numere naturale. Portul obiectului de tip ServerSocket este
7999.
Programul client CmmdcClient se conecteaza la server, transmite serverului cele doua numere naturale si receptioneaza rezultatul pe care apoi l afiseaza.
In esenta orice program client trebuie sa execute:
1. Deschide/creaza un soclu.
2. Deschide/creaza fluxuri de date pentru comunicatia cu serverul.
3. Transmite si receptioneaza date potrivit specificului aplicatiei (protocolului serverului). Acest pas variaza de la un program client la altul.
4. Inchiderea fluxurilor de date.
5. Inchiderea soclului.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

import
import
import
import

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

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

2.2. SOCLU TCP

27

Se presupune ca programul server ruleaza pe calculatorul local si utilizeaza


portul 7999. Daca acesti parametri se modifica - de exemplu serverul ruleaza
n retea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem
acesti parametri prin java CmmdcClient atlantis 8200
Partea server este alcatuita din mai multe clase:
Clasa MyMServer, independenta de un serviciu anume, preia apelurile
clientilor si lanseaza satisfacerea cererii.
1
2
3
4
6
7
8

import
import
import
import

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 ) {
i n t p o r t =7999;
boolean l i s t e n i n g=true ;
AppThread appThread=new AppThread ( ) ;
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 ) {
e x e c . e x e c u t e ( appThread . a c t i o n . s e r v i c e ( s e r v e r S o c k e t . a c c e p t ( ) ) ) ;
}
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
}

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

java . net . ServerSocket ;


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

In ciclul while, la receptia unei solicitari de conexiune se creaza si


se lanseaza un fir de executie a carei metoda run contine actiunile ce
raspund solicitarii.
Clasa AppThread - fir de executie responsabil de preluarea datelor si de
transmitere a rezultatului.
1
2
3
4
6
7
8
9
10
12
13
14

import
import
import
import

java . net . Socket ;


j a v a . i o . DataInputStream ;
j a v a . i o . DataOutputStream ;
j a v a . i o . IOException ;

public c l a s s AppThread{
// F i r u l de e x e c u t i e l a n s a t de s e r v e r
interface ServerSocketAction {
Thread s e r v i c e ( S o c k e t s o c k e t ) ;
}
s t a t i c S e r v e r S o c k e t A c t i o n a c t i o n =( S o c k e t s o c k e t )>{
return new Thread (()>{
try ( DataOutputStream out =

28

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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 ;
m=i n . readLong ( ) ;
n=i n . readLong ( ) ;
App app=new App ( ) ;
r=app . cmmdcService . cmmdc(m, n ) ;
out . w r i t e L o n g ( r ) ;
socket . close ( ) ;

15
16
17
18
19
20
21
22
23
24

}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
});

25
26
27
28
29

};

30
31

Clasa App corespunzatoare calcului celui mai mare divizor comul a doua
numere naturale.
1
2
3
4
5

public c l a s s App{
// F u n c t i a i n d e p l i n i t a de s e r v e r
i n t e r f a c e CmmdcService {
long cmmdc( long m, long n ) ;
}
s t a t i c CmmdcService cmmdcService=(long m, long n ) > { . . . }

7
9

Rularea programelor. Se porneste la nceput programul server MyMServer


iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator
al retelei. Daca programul client se executa pe alt calculator decat cel pe care
ruleaza programul server, atunci la apelarea clientului trebuie precizat numele
calculatorului server si eventual portul utilizat.
O alta arhitectura a aplicatiei este dezvoltata n continuare. Aceasta arhitectura este mai buna n sensul ca ofera o flexibilitate mai mare.
Aplicatia distribuita se va compune din:
Aplicatia server alcatuita din:
Interfata
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 {
ServerSocket g e t S e r v e r S o c k e t ( int port ) ;
void myAction ( S e r v e r S o c k e t s e r v e r S o c k e t ) ;
}

2.2. SOCLU TCP

29

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

package s e r v e r . impl ;
import i s e r v e r . IMyMServer ;
import j a v a . n e t . S e r v e r S o c k e t ;
import j a v a . i o . IOException ;
import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ;
import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ;
public c l a s s MyMServer implements IMyMServer {
public S e r v e r S o c k e t g e t S e r v e r S o c k e t ( f i n a l 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 ( f i n a l S e r v e r S o c k e t s e r v e r S o c k e t ) {
int nthreads = 8192;
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 ( n t h r e a d s ) ;
AppThread appThread = new AppThread ( ) ;
while ( true ) {
try {
e x e c . e x e c u t e ( appThread . a c t i o n . s e r v i c e ( s e r v e r S o c k e t . a c c e p t ( ) ) ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
}
}

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

Clasele AppThread, App sunt cele utilizate anterior.


Clasa de lansare a serverului
1
2
3
4
6
7
8
9
10
11
12
13
14
15

package s e r v e r ;
import j a v a . n e t . S e r v e r S o c k e t ;
import s e r v e r . impl . MyMServer ;
import i s e r v e r . IMyMServer ;
public c l a s s AppServer {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
int port = 7999;
i f ( args . length > 0)
port = Integer . parseInt ( args [ 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 nemodificata.

30

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.2.2

Streaming

Prin socluri se pot transmite fluxuri de date (streaming). Modul de programare depinde de natura datelor ce trebuie vehiculate (text, sunet, grafica).
Exemplul 2.2.2 Clientul solicita serverului transmisia unui fisier text, cerere
care va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe care le poate
trimite serverul.
Structura aplicatiei este:
Client StreamClient.java
Server MyMServer.java
AppThread.java
Clasa StreamClient
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

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

Clasa AppThread
1
2

package s t r e a m i n g t e x t ;
import j a v a . n e t . S o c k e t ;

31

2.2. SOCLU TCP

3
4
5
6
7
8
10
11

import
import
import
import
import
import

io
io
io
io
io
io

. DataInputStream ;
. DataOutputStream ;
. File ;
. FileReader ;
. BufferedReader ;
. IOException ;

public c l a s s AppThread extends Thread {


S o c k e t s o c k e t=n u l l ;
public AppThread ( S o c k e t s o c k e t ) {
t h i s . s o c k e t=s o c k e t ;
}

13
14
15

public void run ( ) {


S t r i n g path= . . / r e s o u r c e s / t e x t / ;
try ( DataInputStream i n =
new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ;
DataOutputStream out=
new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ) {
i n t n o F i l e=i n . r e a d I n t ( ) ;
S t r i n g f i l e N a m e= ;
i f ( n o F i l e ==1)
f i l e N a m e= c a p i t o l . t x t ;
else
f i l e N a m e= j u n i t . t e x ;
F i l e i n p u t F i l e=new F i l e ( path+f i l e N a m e ) ;
F i l e R e a d e r f r=new F i l e R e a d e r ( i n p u t F i l e ) ;
B u f f e r e d R e a d e r br= new B u f f e r e d R e a d e r ( f r ) ;

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

String s ;
while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) out . writeUTF ( s ) ;
out . writeUTF ( e n d O F f i l e ) ;
out . f l u s h ( ) ;
br . c l o s e ( ) ;
fr . close ();
System . out . p r i n t l n ( A c t i v i t y F i n i s h e d ! ) ;
socket . close ( ) ;

33
34
35
36
37
38
39
40

}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}

41
42
43
44

45
46

java .
java .
java .
java .
java .
java .

Exemplul 2.2.3 Clientul solicita serverului transmisia unui fisier grafic, cerere
care va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe care le poate
trimite serverul.
Pe aceasi structura codurile claselor sunt
Clasa StreamClient
1
2
3
4

package s t r e a m i n g i m a g e ;
import j a v a . i o . DataOutputStream ;
import j a v a . i o . InputStream ;
import j a v a . awt . image . B u f f e r e d I m a g e ;

32

5
6
7
8
9
11
12
13
14
15
16
17
18
19

import
import
import
import
import

java . net . Socket ;


j a v a . i o . IOException ;
j a v a x . i m a g e i o . ImageIO ;
j a v a . awt . Image ;
java . u t i l . Scanner ;

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

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

34
35

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa ShowImage afiseaza imaginea descarcata.


Clasa AppThread.java
1
2
3
4
5
6
7
8
9
10
11
13
14
16
17
18
20
21
22
23
24

package s t r e a m i n g i m a g e ;
import j a v a . n e t . S o c k e t ;
import j a v a . i o . InputStream ;
import j a v a . i o . OutputStream ;
import j a v a x . i m a g e i o . stream . FileImageOutputStream ;
import j a v a . i o . DataInputStream ;
import j a v a x . i m a g e i o . ImageIO ;
import j a v a . i o . IOException ;
import j a v a . i o . F i l e ;
import j a v a . awt . image . B u f f e r e d I m a g e ;
import j a v a . awt . Image ;
public c l a s s AppThread extends Thread {
S o c k e t s o c k e t=n u l l ;
public AppThread ( S o c k e t s o c k e t ) {
t h i s . s o c k e t=s o c k e t ;
}
public void run ( ) {
S t r i n g path= . . / r e s o u r c e s / images / ;
try ( OutputStream out=s o c k e t . getOutputStream ( ) ;
DataInputStream i n=
new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ) {

2.3. DATAGRAME

25

i n t n o F i l e=i n . r e a d I n t ( ) ;

27

S t r i n g f i l e N a m e= ;
i f ( n o F i l e ==1)
f i l e N a m e=xmlp i c . j p g ;
else
f i l e N a m e= b r a s o v . j p g ;
F i l e f i l e =new F i l e ( path+f i l e N a m e ) ;
B u f f e r e d I m a g e b i=ImageIO . r e a d ( f i l e ) ;
ImageIO . w r i t e ( bi , j p g , out ) ;
out . f l u s h ( ) ;
socket . close ( ) ;

28
29
30
31
32
33
34
35
36

}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

37
38
39
40

41
42

33

2.3

Datagrame

Pentru utilizarea datagramelor pachetul java.net pune la dispozitie clasele


java.net.DatagramSocket
java.net.DatagramPacket
java.net.MulticastSocket
O aplicatie trimite si receptioneaza pachete DatagramPacket prin intermediul unui DatagramSocket. Un pachet DatagramPacket poate fi trimis la
mai multi destinatari prin intermediul unui MulticastSocket.
Reamintim ca o datagrama este un mesaj trimis prin retea a carei sosire
nu este garantata iar momentul de sosire este neprecizat.

Clasa java.net.DatagramPacket.
Trimiterea unui pachet UDP necesita crearea unui obiect
DatagramPacket care contine corpul mesajului si adresa destinatiei. Apoi
acest obiect DatagramPacket poate fi pus n retea n vederea trimiterii sale.
Primirea unui pachet UDP necesita crearea unui obiect DatagramPacket si
apoi acceptarea unui pachet UDP din retea. Dupa primire, se poate extrage
din obiectul DatagramPacket adresa sursa si continutul mesajului.
Constructori
Exista doi constructori pentru datagrame UDP. Primul constructor este
folosit pentru primirea de pachete si necesita doar furnizarea unei memorii

34

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

tampon, iar celalalt este folosit pentru trimiterea de pachete si necesita specificarea adresei destinatarului.
DatagramPacket(byte[ ] buffer ,int lung)
Acest contructor este folosit pentru primirea pachetelor. Un pachet se
memoreaza n tamponul buffer avand lung octeti. Daca lungimea pachetului depaseste aceasta lungime, atunci pachetul este trunchiat iar
octetii n plus se pierd.
DatagramPacket(byte[ ] buffer ,int lung ,InetAddress adresa ,int
port)
Acest constructor este folosit pentru crearea unui pachet n vederea expedierii. Corpul pachetului este continut n tamponul buffer avand lung
octeti. Pachetul va fi trimis catre adresa si portul specificat. Trebuie sa
existe un server UDP care asculta la portul specificat pentru trimiterea
pachetelor. Un server UDP poate coexista cu un server TCP care asculta
acelasi port.
Metode
InetAddress getAddress()
returneaza adresa IP a expeditorului.
int getPort()
returneaza portul expeditorului.
byte[] getData()
returneaza continutul pachetului.
int getLength()
returneaza lungimea pachetului.
void setAddress(InetAddress adresa)
fixeaza adresa IP a pachetului.
void setPort(int port)
fixeaza portul.
void setData(byte[] buffer )
fixeaza continutul pachetului.

2.3. DATAGRAME

35

void setLength(int lung)


fixeaza lungimea pachetului.

Clasa java.net.DatagramSocket
Aceasta clasa se foloseste atat pentru trimiterea, cat si pentru primirea
obiectelor DatagramPacket. Un obiect DatagramSocket asculta la un port
cuprins ntre 1 si 65535 (porturile cuprinse ntre 1 si 1023 sunt rezervate pentru
aplicatiile sistem). Deoarece UDP nu este orientat pe conexiune, se va crea
un singur obiect DatagramSocket pentru trimiterea pachetelor catre diferite
destinatii si primirea pachetelor de la diferite surse.
Constructori
DatagramSocket() throws SocketException
Creaza un obiect DatagramSocket cu un numar de port aleator;
DatagramSocket(int port) throws SocketException
Creaza un obiect DatagramSocket cu numarul de port specificat;
Metode
Clasa DatagramSocket contine metode pentru trimiterea si primirea de
obiecte DatagramPacket, nchiderea soclului, determinarea informatiilor adresei locale si setarea timpului de primire.
void send(DatagramPacket pachet) throws IOException
Trimite pachetul prin retea. Daca se trimit pachete la o destinatie necunoscuta sau care nu asculta, n cele din urma se genereaza o exceptie
IOException.
void receive(DatagramPacket pachet) throws IOException
Metoda primeste un singur pachet UDP n obiectul pachet specificat.
Apoi, pachetul poate fi inspectat pentru determinarea adresei IP sursa,
portul sursa si lungimea mesajului. Executia metodei este blocata pana
cand se primeste cu succes un pachet sau se scurge timpul de asteptare.
InetAddress getLocalAddress()
Returneaza adresa locala catre care este legat acest DatagramSocket;
int getLocalPort()
Returneaza numarul de port unde asculta DatagramSocket.

36

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

void close()
Inchide DatagramSocket.
void setSoTimeout(int timpDeAsteptere) throws SocketException
Metoda fixeaza timpul de asteptare (n milisecunde) a soclului. Metoda
receive() se va bloca pentru timpul de asteptare specificat pentru primirea unui pachet UDP, dupa care va arunca o exceptie Interrupted
Exception. Daca valoarea parametrului este 0, atunci soclul este blocat.
int getSoTimeout() throws SocketException
Returneaza timpul de asteptare.
void setSendBufferSize(int lungime) throws SocketException
Fixeaza lungimea tamponului de trimitere a soclului la valoarea specificata. Nu poate fi trimis mesaj UDP de lungime mai mare de aceasta
valoare.
int getSendBufferSize() throws SocketException
Returneaza lungimea tamponului de trimitere a soclului.
void setReceiveBufferSize(int lungime) throws SocketException
Fixeaza lungimea tamponului de primire a soclului la valoarea specificata. Nu poate fi primit un mesaj UDP de lungime mai mare de aceasta
valoare.
int getReceiveBufferSize() throws SocketException
Returneaza lungimea tamponului de primire a soclului.
void disconnect()
Deconecteaza soclul conectat.
InetAddress getInetAddress()
Returneaza obiectul InetAddress catre care este conectat soclul sau
null daca acesta nu este conectat.
int getPort()
Returneaza portul la care este conectat soclul sau -1 daca acesta nu este
conectat.

2.3. DATAGRAME

37

Clasa java.net.InetAddress
Datele pot fi trimise prin retea indicand adresa IP corespunzatoare masinii
destinatie. Clasa InetAddress furnizeaza acces la adresele IP.
Nu exista constructori pentru aceasta clasa. Instantele trebuie create folosind
metodele statice:
InetAddress getLocalHost() throws UnknownHostException
Returneaza un obiect InetAddress corespunzator masinii locale.
InetAddress getByName(String host) throws UnknownHostException
Returneaza un obiect InetAddress corespunzator masinii host, parametru
care poate fi specificat prin nume (de exemplu atlantis) sau prin adresa
IP (168.192.0.1).
InetAddress [ ]getAllByName(String host)
throws UnknownHostException
Returneaza un sir de obiecte InetAddress corespunzator fiecarei adrese
IP a masinii host.
Metodele clasei InetAddress
byte [ ] getAddress()
Returneaza sirul de octeti corespunzator obiectului InetAddress de referinta.
String getHostName()
Returneaza numele masinii gazda.
String getHostAddress()
Returneaza adresa IP a masinii gazda.
boolean isMulticastAddress()
Returneaza true daca obiectul InetAddress reprezinta o adresa IP multicast (cuprins ntre 224.0.0.0 si 239.255.255.255).
Exemplul urmator afiseaza numele si adresa calculatorului gazda cat si
acela al calculatoarelor ale caror nume este transmis programului ca parametru.
Exemplul 2.3.1

38

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

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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

2.3.1

Aplicatii client server cu datagrame.

Un pachet de tip DatagramPacket este alcatuit dintr-un sir de octeti. Este


datoria programatorului sa transforme datele (mesajul) n siruri de octeti la
expediere si la receptie.
Transformarea unui obiect serializabil ntr-un sir de octeti si invers se poate
realiza cu schema

39

2.3. DATAGRAME

Object

Object

ObjectInputStream

ByteArrayInputStream

input - DatagramPacket

ObjectOutputStream
ByteArrayOutputStream
output - DatagramPacket
?

6
6
6
6

Fie socket un obiect de tip DatagramSocket prin intermediul caruia se


executa expedierea / receptionarea pachetelor de tip DatagramPacket.
In principiu expedierea si transformarea obiectului obj ntr-un sir de octeti
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 si port sunt adresa si portul destinatarului. Daca packet este un
obiect DatagramPacket receptionat atunci metodele getAddress() si getPort()
furnizeaza adresa si portul expeditorului
Receptionarea si transformarea inversa este
byte[] bin=new byte[256];
packet=new DatagramPacket(bin,bin.length);
socket.receive(packet);
ByteArrayInputStream bais=new ByteArrayInputStream(bin);
ObjectInputStream in=new ObjectInputStream(bais);
obj=in.readObject();
Daca mesajul este un obiect String atunci el se transforma ntr-un sir de
octeti cu metoda byte[] String.getByte() si invers, el se obtine prin new
String(bin) sau new String(packet.getData()).
Exemplul 2.3.2 Programam aplicatia de calculul a celui mai mare divizor
comun a doua numere naturale.

40

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

In vederea transportului definim clasa


1
2
4
5
6
7
8
9
10

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

Clientul va trimite un obiect Protocol, care va contine datele problemei si va


receptiona un obiect de acelasi tip cu rezultatul (cel mai mare divizor comun)
n primul camp al obiectului. Aceasta clasa este disponibila atat serverului cat
si clientului.
Se va utiliza arhitectura de aplicatie dezvoltata n finalul sectiunii anterioare. Aplicatia se va compune din:
Aplicatia server alcatuita din:
Interfata
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
7
8
9
10
11
13
14
15
16
18
19
20
21
22

package s e r v e r . impl ;
import s e r v e r . P r o t o c o l ;
import i s e r v e r . IMyMServer ;
import j a v a . n e t . DatagramSocket ;
import j a v a . n e t . DatagramPacket ;
import j a v a . n e t . I n e t A d d r e s s ;
import j a v a . i o . IOException ;
import j a v a . i o . ByteArrayInputStream ;
import j a v a . i o . ByteArrayOutputStream ;
import j a v a . i o . O b j e c t I n p u t S t r e a m ;
import j a v a . i o . ObjectOutputStream ;
public c l a s s MyMServer implements IMyMServer {
i n t e r f a c e ServerDatagramAct ion {
void s e r v i c e ( DatagramSocket s o c k e t ) ;
}
s t a t i c ServerDatagramActi on a c t i o n =
( DatagramSocket datagramSocket)>{
DatagramPacket p a c k e t=n u l l ;
P r o t o c o l p=n u l l ;
try {

41

2.3. DATAGRAME

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 ( ) ;
App app=new App ( ) ;
p . x=app . cmmdcService . 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 ) ;

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

40
41
42
43
44

};

46

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 ) {
e . printStackTrace ( ) ;
}
System . out . p r i n t l n ( DatagramSocket i s r e a d y . . . ) ;
return datagramSocket ;
}

47
48
49
50
51
52
53
54
55
56

public void myAction ( DatagramSocket datagramSocket ) {


while ( true ) {
a c t i o n . s e r v i c e ( datagramSocket ) ;
}
}

58
59
60
61
62
63

Clasa de lansare a serverului


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

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

42

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

16

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

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

2.3. DATAGRAME

2.3.2

43

Multicast vs. Broadcast

Clasa java.net.MulticastSocket
Prin intermediul unui soclu de tip MulticastSocket se pot receptiona
datagrame expediate de un server catre toti clientii cu un asemenea soclu.
Constructori
MulticastSocket(int port) throws SocketException
Metode
void joinGroup(InetAddress adresa ) throws SocketException
Soclul se conecteaza la grupul definit de adresa IP (de tip D, adica
cuprins ntre 224.0.0.0 si 239.255.255.255).
void leaveGroup(InetAddress adresa ) throws SocketException
Soclul se deconecteaza la grupul definit de adresa IP.
void close()
Pregatirea clientului n vederea receptionarii datagramelor printr-un soclu
de tip MulticastSocket consta din
MulticastSocket socket= new MulticastSocket(port);
InetAddress adresa=InetAddress.getByName("230.0.0.1");
socket.joinGroup(adresa);
In final, clientul se deconecteaza si nchide soclul.
socket.leaveGroup(adresa);
socket.close();
Pachetele trimise de programul server trebuie sa se adreseze grupului, identificat prin adresa IP de tip D.
Astfel prin multicast serverul trimite pachete la o adresa de grup si la un
port fixat. Pachetele emise de server sunt receptionate de orice client ce creaza
un soclu de tip MulticastSocket pentru portul la care emite serverul si care
se alatura grupului.
Prin broadcast serverul emite datagrame catre orice calculator al retelei
locale la un anumit port. Faptul ca emiterea datagramelor este de tip broadcast
se indica prin

44

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

DatagramSocket.setBroadcast(true)
Orice client care si creaza un soclu la portul la care emite serverul receptioneaza
datagramele trimise de server. Adresa utilizata de server la crearea datagramelor trebuie sa identifice reteaua.
Observatie. In cazul unui calculator izolat este nevoie de instalarea
driverului Microsoft Loopback Adapter, care simuleaza existenta unei placi de
retea active.
Exemplul 2.3.3 Multicast
si Broadcast: programele server emit din cinci
n cinci secunde ora exacta. Un client va receptiona cate cinci datagrame.
Codurile sunt date n Fig. 2.1 si Fig. 2.2, respectiv pentru partea de server
si cea de client.

2.4

Canale de comunicatie

Odata cu versiunea j2sdk1.4 apar clase noi pentru operatii de intrare - iesire
n pachetele java.nio si java.nio.channels. Pachetul java.nio.channels
contine clase pentru comunicatia n retea, si anume canalele de comunicatie.

2.4.1

SocketChannel & DatagramChannel

Utilizam clasele java.nio.channels.SocketChannel, java.nio.channel.


DatagramChannel. Informatia transportata n aceste canale de comunicatie
trebuie nglobata n obiecte container de tip Buffer.

Clasa java.nio.Buffer
Ierarhia claselor Buffer
abstract Buffer
ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer

45

2.4. CANALE DE COMUNICAT


IE

MulticastServer
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.DateFormat;

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

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

socket.send(packet);
// sleep for a while
Thread.sleep(FIVE_SECONDS);
}

Thread.sleep(FIVE_SECONDS);
}

}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}

}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}

Table 2.1: Clasele server.

46

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

MulticastClient
import java.io.*;
import java.net.*;

BroadcastClient
import java.io.*;
import java.net.*;

public class MulticastClient {

public class BroadcastClient {

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

public static void main(String[] args)


throws IOException {
DatagramPacket packet;
byte[] buf = new byte[256];
int clientPort=7001;
DatagramSocket socket=
new DatagramSocket(clientPort);

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

Table 2.2: Clasele client.

2.4. CANALE DE COMUNICAT


IE

47

Un obiect de tip typeBuffer este un tampon (container) care contine date


de tipul specificat de denumirea clasei.
Un obiect de tip Buffer este caracterizat de
capacitate (capacity) numarul elementelor care pot fi nmagazitate n
tampon;
limita (limit) marginea superiora a indicelui;
indice (position) valoarea curenta a indicelui, ce corespunde unui cursor
ce indica nceputul zonei unde se introduc sau de unde se extrag date
din tampon.
Metode generale
clear() permite unui obiect de tip Buffer sa fie rencarcat. Fixeaza
limita = capacitate si indice = 0.
flip() pregateste obiectul de tip Buffer pentru consultare (citire).
Fixeaza limita =numarul elementelor din tampon si indice = 0.
rewind() pregateste obiectul de tip Buffer pentru re-citire.
remaining() returneaza numaul octetilor cuprinsi ntre valoarea indicelui
si limita.

Clasa java.nio.ByteBuffer
Instantierea unui obiect se obtine prin metoda statica
static ByteBuffer allocate(capacitate)
Introducerea si extragerea datelor din tampon se poate face n mod
relativ - implica modificarea indicelui tamponului;
absolut - fara modificarea indicelui.
Metode
Introducerea datelor n mod relativ:
ByteBuffer put(byte b)

48

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

ByteBuffer putTip(tip x )
Extragerea datelor n mod relativ:
byte get()
tip getTip()
Introducerea datelor n mod absolut:
ByteBuffer put(int index ,byte b)
ByteBuffer putTip(int index ,tip x )
Extragerea datelor n mod absolut:
byte get(int index )
tip getTip(int index )
unde tip poate fi char, short, int, long, float, double.
Alte metode
public final boolean hasRemaining()
Daca indicele nu este egal cu limita atunci returneaza true, semnaland
existenta n tampon a unor octeti.
static ByteBuffer wrap(byte[] array)
public static ByteBuffer wrap(byte[] array,int offset,int length)
Converteste sirul de octeti ntr-un obiect ByteBuffer.
public final byte[] array()
Transformarea inversa, obiectul ByteBuffer este convertit ntr-un sir de
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();

2.4. CANALE DE COMUNICAT


IE

49

Clasa java.net.InetSocketAddress
Clasa InetSocketAddress extinde clasa SocketAddress si ncapsuleaza
adresa unui calculator din Internet mpreuna cu un port n vederea legarii la
un ServerSocket.
Constructori:
InetSocketAddress(InetAddress addr ,int port)
InetSocketAddress(String numeCalculator ,int port)
InetSocketAddress(int port)

Clasa java.nio.channels.ServerSocketChannel
Crearea unui obiect de tip ServerSocketChannel se realizeaza prin
static ServerSocketChannel open() throws IOException
Unui asemenea obiect i se asociaza un ServerSocket prin metoda
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
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 sa genereze un obiect de tip Socket
Channel prin care se vor derula comunicatiile cu clientul. Acest canal de
comunicatie se obtine cu metoda accept().

50

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa java.nio.channels.SocketChannel
Crearea unui obiect de tip SocketChannel se realizeaza prin
static SocketChannel open() throws IOException
Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului
cu metoda connect(InetSocketAddress addr ).
Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datele
se transmit prin metoda
int write(ByteBuffer sursa )
si se receptioneaza prin metoda
int read(ByteBuffer destinatie)
Valoarea returnata de cele doua metode reprezinta numarul octetilor trimisi
/ receptionati.
Doar octetii unui obiect de tip ByteBuffer cuprinsi ntre indice si limita
sunt transmisi prin canal. Astfel, dupa ncarcarea unui obiectului ByteBuffer
cu metode relative trebuie apelata metoda flip().
Canalul se nchide cu metoda close().
Exemplul 2.4.1 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatie client-server bazat pe canale de comunicatie prin socluri se compune din:
Aplicatia server alcatuita din:
Interfata
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
Clasa MyMServer

2.4. CANALE DE COMUNICAT


IE

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

package s e r v e r . impl ;
import i s e r v e r . IMyMServer ;
import j a v a . n e t . I n e t S o c k e t A d d r e s s ;
import j a v a . n e t . S e r v e r S o c k e t ;
import j a v a . n i o . c h a n n e l s . S e r v e r S o c k e t C h a n n e l ;
import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ;
import j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ;
import j a v a . i o . IOException ;
public c l a s s MyMServer implements IMyMServer {
public S e r v e r S o c k e t C h a n n e l g e t S e r v e r S o c k e t C h a n n e l ( i n t p o r t ) {
S e r v e r S o c k e t C h a n n e l s e r v e r S o c k e t C h a n n e l=n u l l ;
try {
s e r v e r S o c k e t C h a n n e l = S e r v e r S o c k e t C h a n n e l . open ( ) ;
I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( p o r t ) ;
S e r v e r S o c k e t s s=s e r v e r S o c k e t C h a n n e l . s o c k e t ( ) ;
s s . bind ( i s a ) ;
}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
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;
AppThread appThread=new AppThread ( ) ;
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 {
e x e c . e x e c u t e ( appThread .
action . s e r v i c e ( serverSocketChannel . accept ( ) ) ) ;
}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
}
}

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

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

package s e r v e r . impl ;
import j a v a . i o . IOException ;
import j a v a . n i o . c h a n n e l s . S o c k e t C h a n n e l ;
import j a v a . n i o . B y t e B u f f e r ;
public c l a s s AppThread{
interface ServerSocketChannelAction {
Thread s e r v i c e ( S o c k e t C h a n n e l s o c k e t ) ;
}
static ServerSocketChannelAction action =
( 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 )>{
return new Thread (()>{
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 ) ;

51

52

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

// L o n g B u f f e r l b = bb . a s L o n g B u f f e r ( ) ;
s o c k e t C h a n n e l . r e a d ( bb ) ;
// V a r i a n t a 1
long m=bb . getLong ( 0 ) ;
long n=bb . getLong ( 8 ) ;
// V a r i a n t a 2
// l o n g m=l b . g e t ( 0 ) ;
// l o n g n=l b . g e t ( 1 ) ;
App app=new App ( ) ;
long r=app . cmmdcService . 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 ( ) ;

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
});

33
34
35
36
37

};

38
39

Clasa de lansare a serverului


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

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

Aplicatia client
1
2
3
4
5
6
7
9
10
11
12

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

2.4. CANALE DE COMUNICAT


IE

i f ( a r g s . l e n g t h >0)
h o s t=a r g s [ 0 ] ;
i f ( a r g s . l e n g t h >1)
p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
S o c k e t C h a n n e l s c=n u l l ;
try {
I n e t S o c k e t A d d r e s s i s a=new I n e t S o c k e t A d d r e s s ( hos t , p o r t ) ;
s c=S o c k e t C h a n n e l . open ( ) ;
sc . connect ( i s a ) ;
}
catch ( UnknownHostException e ) {
System . e r r . p r i n t l n ( S e r v e r n e c u n o s c u t : +h o s t+ +e . g e t M e s s a g e ( ) ) ;
System . e x i t ( 1 ) ;
}
catch ( IOException e ) {
System . e r r . p r i n t l n ( C o n e c t a r e i m p o s i b i l a l a : +
h o s t+ pe p o r t u l +p o r t+ +e . g e t M e s s a g e ( ) ) ;
System . e x i t ( 1 ) ;
}
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
long m, n , r ;
System . out . p r i n t l n ( m= ) ;
m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
n=s c a n n e r . nextLong ( ) ;

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

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

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

59
60

53

Varianta comentata corespunde cazului n care se utilizeara clasa acoperitoare


LongBuffer.
Alternativ, se poate lucra cu obiecte. Pentru exemplul dat, utilizand clasa
Protocol, introdusa n sectiunea dedicata datagramelor, codul privind trimiterea si receptia datelor din clasele AppThread si CmmdcClient va fi
1
2

. . .
B y t e B u f f e r bb = B y t e B u f f e r . a l l o c a t e ( 1 0 2 4 ) ;

54

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

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

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

. . .

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

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

Clasa java.nio.channels.DatagramChannel
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){. . .}

2.4. CANALE DE COMUNICAT


IE

55

unde port este portul folosit de DatagramChannel. Daca port=0 atunci se


alege aleator un port disponibil.
Transmiterea unui obiect ByteBuffer se face cu metoda
public int send(ByteBuffer src, SocketAddress target) throws
IOException
Metoda returneaza numarul de octeti expediati. Receptia unui ByteBuffer se
obtine cu metoda
public SocketAddress receive(ByteBuffer dst) throws IOException
Obiectul returnat reprezinta adresa expeditorului.
Exemplul 2.4.2 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatia server este alcatuita din:
Interfata
1
2
3
4
5
6

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

Implementarea interfetei
1
2
3
4
5
6
7
8
10
12
13
14
16
17
18
19
20
21
22
23

package s e r v e r . impl ;
import i s e r v e r . IMyMServer ;
import j a v a . n e t . DatagramSocket ;
import j a v a . n e t . I n e t S o c k e t A d d r e s s ;
import j a v a . n e t . S o c k e t A d d r e s s ;
import j a v a . n i o . c h a n n e l s . DatagramChannel ;
import j a v a . n i o . B y t e B u f f e r ;
import j a v a . i o . IOException ;
public c l a s s MyMServer implements IMyMServer {
i n t e r f a c e ServerDatagramChannelAction {
void s e r v i c e ( DatagramChannel datagramChannel ) ;
}
s t a t i c ServerDatagramChannelAction a c t i o n =
( DatagramChannel datagramChannel)>{
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 ) ;

56

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

long n=bb . getLong ( 8 ) ;


// V a r i a n t a 2
// l o n g m=l b . g e t ( 0 ) ;
// l o n g n=l b . g e t ( 1 ) ;
App app=new App ( ) ;
long r=app . cmmdcService . 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 ) ;

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

}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

36
37
38
39
40

};

42

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

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

public void myAction ( DatagramChannel datagramChannel ) {


while ( true ) {
a c t i o n . s e r v i c e ( datagramChannel ) ;
}
}

58
59
60
61
62
63

Clasa de lansare a serverului


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

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

2.4. CANALE DE COMUNICAT


IE

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

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

57

58

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

// r=l b . g e t ( 0 ) ;
System . out . p r i n t l n ( Cmmdc = +r ) ;

59
60

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

61
62
63
64
65
66
67

68
69

2.4.2

Receptie cu Selector

Programarea receptiei cererilor clientilor fara utilizarea firelor de executie


se poate face utilizand clasele
java.nio.channel.Selector
Gestioneaza obiectele SocketChannel nregistrate si transmite cererile
care trebuie satisfacute.
java.nio.channel.SelectionKey
Obiect utilizat de selector pentru sortarea cererilor. O cheie identifica
un client si tipul cererii.
1

Figura 2.1 prezinta structura unei aplicatii.

Clasa java.nio.channel.Selector
Metode
public static Selector open() throws IOException
Instatiaza un obiect de tip Selector.
public Set<SelectionKey> selectedKeys()
Returneaza cheile inregistrate de selector.
public int select() throws IOException
Metoda blocanta pana la selectarea unui canal.
1

Imaginea este preluat


a din Naccarato G.,
http://www.onjava.com, 2002.

Introducing Nonblocking Sockets,

2.4. CANALE DE COMUNICAT


IE

59

Figure 2.1: Structura unei aplicatii.


Inregistrarea selectorului se face de catre obiectiul SocketChannel sau
ServerSocketChannel prin metoda
public final SelectionKey register(Selector selector, int ops) throws
ClosedChannelException
Operatiile pot fi
SelectionKey.OP CONNECT
SelectionKey.OP ACCEPT
SelectionKey.OP READ
SelectionKey.OP WRITE
Canalul se configureaza pe modul ne-blocant prin
configureBlocking(false) throws IOException
Clasa java.nio.channel.SelectionKey
Metode
public final boolean isConnectable()
public final boolean isReadable()
public final boolean isWritable()
public final boolean isAcceptable()
public void cancel()

60

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.4.3 Aplicatia server pentru aplicatia de calcul a celui mai mare
divizor comun.
Aplicatia server va fi formata de clasele AppServer si App, cea utilizata n
acest capitol.
1
2
3
4
5
6
7
8
9
10
11
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

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

2.4. CANALE DE COMUNICAT


IE

buffer . clear ();


b u f f e r . putLong ( 0 , r ) ;
c l i e n t . write ( buffer ) ;
buffer . clear ();
client . close ();
key . c a n c e l ( ) ;

53
54
55
56
57
58

59

60

61

62

}
catch ( E x c e p t i o n e ) {
System . e r r . p r i n t l n ( B u f f e r O p E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
finally {
try {
serverSocketChannel . 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 ( C l o s e E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
}

63
64
65
66
67
68
69
70
71
72
73
74

75
76

61

Aplicatia client nu sufera nici o modificare.

2.4.3

Comunicatii asincrone prin canale

Utilizarea canalelor asincrone, introduse n Java 7, face apel la metode


neblocante.
Astfel sunt introduse clasele:
java.nio.channels.AsynchronousServerSocketChannel si
java.nio.channels.AsynchronousSocketChannel.
Tehnicile de programare utilizate se bazeaza pe utilizarea claselor:
java.util.concurrent.Future

Interfata java.util.concurrent.Future<V>
Metode
V get()
boolean isDone()
Valoarea true rezulta daca s-a obtinut / generat obiectul de tip V.

62

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Un obiect de tip V care rezulta n urma apelarii metodei cu semnatura


Future<V> metoda(. . . )
se va utiliza doar dupa verificarea generarii ei, de exemplu cu metoda isDone().

Clasa AsynchronousServerSocketChannel
Un obiect de tip AsynchronousServerSocketChannel se obtine cu metoda
statica open().
Metode
static AsynchronousServerSocketChannel open() throws IOException
AsynchronousServerSocketChannel bind(SocketAddress addr )
Se precizeaza portul la care se leaga canalul asincron. Clasa InetSocketAddress
este extinde clasa SocketAddress.
public Future<AsynchronousSocketChannel> accept()
Metoda neblocanta genereaza un soclu prin care se realizeaza conexiunea
din partea serverului cu un client.

Clasa AsynchronousSocketChannel
Metodei
public static AsynchronousSocketChannel open() throws IOException
public abstract Future<Void> connect(SocketAddress remote)
public Future<Integer> read(ByteBuffer dst)
Metoda returneaza numarul octetilor ncarcati n dst.
public Future<Integer> write(ByteBuffer src)
Metoda returneaza numarul octetilor expediati din src.
Exemplul 2.4.4
Utilizam modelul aplicatiei dezvoltata pe baza clasei ServerSocketChannel:
1. IMyMServer.java

2.4. CANALE DE COMUNICAT


IE

1
2
3
4
5
6
7
8

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

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

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

63

64

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

48

3. AppThread
1
2
3
4
5
7
8
9
10

package s e r v e r . impl ;
import j a v a . n i o . c h a n n e l s . AsynchronousSocketChannel ;
import j a v a . n i o . B y t e B u f f e r ;
import j a v a . u t i l . c o n c u r r e n t . Future ;
import j a v a . i o . IOException ;
public c l a s s AppThread{
interface ServerSocketAction {
Thread s e r v i c e ( AsynchronousSocketChannel a s c ) ;
}
s t a t i c S e r v e r S o c k e t A c t i o n a c t i o n =( AsynchronousSocketChannel a s c )>{
return new Thread (()>{
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 ( ) ;
Future<I n t e g e r > f r=a s c . r e a d ( bb ) ;
while ( ! f r . i s D o n e ( ) ) ;
// V a r i a n t a 1
long m=bb . getLong ( 0 ) ;
long n=bb . getLong ( 8 ) ;
// V a r i a n t a 2
// l o n g m=l b . g e t ( 0 ) ;
// l o n g n=l b . g e t ( 1 ) ;
App app=new App ( ) ;
System . out . p r i n t l n (m+ <> +n ) ;
long r=app . cmmdcService . 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 ) ;
Future<I n t e g e r > fw=a s c . w r i t e ( bb ) ;
while ( ! fw . i s D o n e ( ) ) ;
asc . c l o s e ( ) ;
}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
});
};

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

4. AppServer.java
1
2
3
4
6
7
8

package s e r v e r ;
import j a v a . n i o . c h a n n e l s . A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ;
import s e r v e r . impl . MyMServer ;
import i s e r v e r . IMyMServer ;
public c l a s s AppServer {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
i n t p o r t =7999;

2.4. CANALE DE COMUNICAT


IE

i f ( a r g s . l e n g t h >0)
p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ;
IMyMServer myMServer=new MyMServer ( ) ;
AsynchronousServerSocketChannel asynchronousServerSocketChannel =
myMServer . g e t A s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ( p o r t ) ;
myMServer . myAction ( a s y n c h r o n o u s S e r v e r S o c k e t C h a n n e l ) ;

9
10
11
12
13
14

15
16

65

5. CmmdcClient.java
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
34
35
36
37
38
39
41
42
43
44
45
46
47

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

66

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

while ( ! f r . i s D o n e ( ) ) ;
r=bb . getLong ( 0 ) ;
System . out . p r i n t l n ( Cmmdc : +r ) ;
asc . c l o s e ( ) ;

48
49
50
51

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

52
53
54
55

56
57

Comentarii
Tehnologiile prezentate sunt incluse n distributia Java standard, oferita de
Oracle.
S-au dezvoltat instrumente de programare cu scopul eficientizarii din diverse puncte de vedere a comunicatiilor bazate pe socluri:

apache-mina

netty

LMAX Disruptor

Comparare
Pe doua calculatoare

1. Intel Core2 Duo T6600 2.20GHz, Windows 7

2. Intel I7-4700MQ 2.40 GHz, Windows 8.1

67

2.4. CANALE DE COMUNICAT


IE

un client solicitand 8192 conexiuni si folosind aplicatiile prezentate mai sus,


durata evaluata pe server a fost
1
Tehnologia
Timp (ms)
Socket
20264
SocketChannel
26551
Selector
19422
Datagram
10015
DatagramChannel
16692
LMAX Disruptor
22994

2
Rang Timp (ms)
4
2235
6
5735
3
2437
1
1812
2
1047
5
2344

Rang
3
6
5
2
1
4

Durata a fost evaluata prin utilizarea metodei System.currentTimeMillis().

Intreb
ari recapitulative
1. Precizati termenul socket (soclu).
2. Precizati clasele Java necesare unei aplicatii client-server cu socluri (socket).
3. Precizati diferenta de simetrie privind instantierea dintre un obiect de
tip Socket si unul de tip ServerSocket.
4. Care este rolul unui obiect de tip ServerSocket si cum se utilizeaza?
5. Precizati metodele unui obiect Socket, necesare n transmiterea si receptia
datelor.
6. Precizati termenul multicast.
7. In ce consta participarea serverului la transmisie multicast ?
8. In ce consta participarea unui client la receptia multicast ?
9. Precizati termenul broadcast.
10. In ce consta participarea serverului la transmisie broadcast ?
11. In ce consta participarea unui client la receptia broadcast ?
12. Care este rolul unui obiect de tip DatagramPacket ?

68

CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

13. Precizati metodele clasei DatagramSocket utilizate la expedierea si la


receptia unui datagram.
14. Ce parametri caracterizeaza un obiect de tip Buffer ?
15. Ce asemanare exista ntre comunicatia bazata de datagrame si cea prin
intermediul canalelor ?
16. Care este rolul unui obiect de tip ByteBuffer?

Probleme
1. Aplicatia cu AsyncronousSocketChannel nu functioneaza corect cu multi
clienti.
2. Rezolvarea solicitarii unui numa (foarte) mare de clienti (> 8192.)

Capitolul 3
Reg
asirea obiectelor prin
servicii de nume
Oricarui obiect i sunt asociate un nume si o referinta. Regasirea / cautarea
obiectului se face pornind de la numele obiectului, prin referinta se ajunge la
obiect.
Exemple date prin sablonul (Nume Referinta Obiect)
1. Accesul la o carte ntr-o biblioteca:
Titlul cartii Referinta cartii din biblioteca Carte
2. Contactul telefonic cu o persoana:
Nume persoana Numar telefon Persoana
Un serviciu de nume contine asocieri dintre nume de obiecte si obiecte si
poate oferi facilitati de regasire a obiectelor.

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.
Cuvantul servici este utilizat n sens comun, entitate care pune la dispozitie
facilitati de folosire.
Alaturi de interfata JNDI, arhitectura JNDI mai contine interfata Service
Provider Interface - SPI. Implementarea interfetei SPI de un furnizor de servicii JNDI are ca efect independenta programului Java de furnizorul de servicii
JNDI.
69

70

CAPITOLUL 3. REGASIREA
OBIECTELOR PRIN SERVICII DE NUME

JNDI este implementat de serviciile de nume:


Filesystem are ca obiect asocierea dintre numele de fisier sau catalog cu
obiectul corespunzator.
DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu adresa IP.
RMI registry utilizat n aplicatii RMI, din Java. Are ca obiect asocierea
ntre un nume de serviciu de invocare ale obiectelor la distanta cu un
delegat al serviciului (stub).
COS - Common Object Service Naming utilizat n aplicatii CORBA. Are
ca obiect asocierea ntre numele unui serviciu de invocare ale obiectelor
la distanta cu referinta la serviciu.
LDAP - Lightweight Directory Access Protocol defineste un protocol pentru accesarea datelor retinute ntr-un catalog LDAP (LDAP directory,
information directory). Un catalog LDAP permite retinerea si regasirea
referintelor obiectelor definite pe un calculator.

Interfata javax.naming.Context
Printr-un context se va ntelege o multime de asocieri nume - obiect. Corespunzator unui context, JNDI defineste interfata Context, cu metodele
void bind(String nume,Object object)
void rebind(String nume,Object object)
void unbind(String nume)
Object lookup(String nume)
NamingEnumeration list(String nume)
Returneaza lista cu nume obiectelor mpreuna cu tipul lor.
NamingEnumeration listBindings(String nume)
Returneaza lista cu nume obiectelor mpreuna cu tipul si locatia acestora.
Specificatiile JNDI prevad definirea unui context initial, implementat prin
clasa javax.naming.InitialContext, clasa ce implementeaza interfata Context.
Constructori.

3.1. JAVA NAMING AND DIRECTORY INTERFACE

71

public InitialContext() throws NamingException


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

72

CAPITOLUL 3. REGASIREA
OBIECTELOR PRIN SERVICII DE NUME

Functie de serviciul de nume, clasa care creaza contextul initial este dat n
tabelul
Serviciul de nume
Filesystem
COS
RMI
DNS
LDAP

Clasa
com.sun.jndi.fscontext.RefFSContextFactory
com.sun.jndi.cosnaming.CNCtxFactory
com.sun.jndi.rmi.registry.RegistryContextFactory
com.sun.jndi.dns.DnsContextFactory
com.sun.jndi.ldap.LdapCtxFactory

Exemplul 3.1.1 Utilizand serviciul JNDI Filesystem se creaza un context


prin intermediul careia se afiseaza continutul unui catalog indicat de client.
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
38
39
40

import
import
import
import
import
import
import
import
import

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

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

3.1. JAVA NAMING AND DIRECTORY INTERFACE

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

41
42
43
44

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

46
47
48
49
50
51

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

53
54
55
56
57
58

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

60
61
62
63
64
65
66

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

67
68
69
70

71
72

73

Apelarea clasei, n varianta data, consta din


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

sau
java

Lookup

caz, n care, n catalogul curent se gaseste fisierul jndi.properties cu continutul


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

Serviciul de nume Filesystem este dat de fisierul fscontext-*.jar (Unele


distributii sunt alcatuite din fisierele fscontext.jar si providerutil.jar ).

3.1.1

LDAP

LDAP poate fi privit ca un sistem de gestiune a unei baze de date (ne


relational). Baza de date este alcatuita din atribute ale caror nume este precizat de protocolul LDAP.
Punctele de intrare (radacinile) sunt date de DN (Distinguished Name).
Uzual DN se defineste printr-una din variantele

74

CAPITOLUL 3. REGASIREA
OBIECTELOR PRIN SERVICII DE NUME

1. o=organization,c=country
2. o=organization
3. dc=domain content 1,dc=domain content 2
De exemplu, dc=example,dc=com
4. uid=user id ,ou=organization unit
De exemplu, uid=admin,ou=system
Un utilizator este caracterizat prin atributul cn - common name si are
acces la LDAP prin precizarea simultana a atributelor DN si cn.
Vom utiliza ApacheDS (Apache Directory Service)1 . Produse pentru administrarea serverului prin intermediul unei interfete grafice sunt:
Apache Directory Studio;
jxplorer.
Instalarea consta din dezarhivarea fisierului descarcat din Internet.
Serverul utilizeaza portul 10389 si se instaleaza cu urmatoarele valori implicite:
Context.PROVIDER URL
ldap://localhost:10389/uid=admin,
ou=system
Context.SECURITY PRINCIPAL
uid=admin,ou=system
Context.SECURITY CREDENTIALS secret
Lansarea serverului se realizeaza prin apelarea fisierului apacheds.bat
din catalogul apacheds-*\bin.
Pentru oprire se tasteaza Ctrl+C.
Actiunile care pot fi ntreprinse de un client care interactioneaza cu serverul
constau n
autentificare: datele necesare sunt DN si parola;
conectare (bind) / deconectare (unbind) la un punct de intrare. Conectarea
implica crearea unui punct de intrare precizat prin cn;
cautarea / localizarea (lookup) unui punct de intrare precizat prin cn.
Exemplul 3.1.2 Program pentru nregistrarea si stergerea referintei unui obiect
de tip Cmmdc.
1

http://en.wikipedia.org/wiki/List_of_LDAP_software.

3.1. JAVA NAMING AND DIRECTORY INTERFACE

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
39
40
41

import
import
import
import
import
import

75

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

Codul clasei Cmmdc este


1
2
3

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 ) { . . . }
}

Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc regasit pe baza referintei
din serverul LDAP.
1
2
3
4

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 ;

76

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

CAPITOLUL 3. REGASIREA
OBIECTELOR PRIN SERVICII DE NUME

import 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 ;
import j a v a . u t i l . S c a n n e r ;
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 ) {
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 ) ;
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 ) {
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 v a l o a r e a a t r i b u t u l u i \ cn \ +
a o b i e c t u l u i Cmmdc ) ;
System . out . p r i n t l n ( cn= ) ;
S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ;
O b j e c t o b j e c t = c t x . l o o k u p ( cn=+cmmdcObj ) ;
System . out . p r i n t l n ( Primul numar ) ;
long a=s c a n n e r . n e x t I n t ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar ) ;
long b=s c a n n e r . n e x t I n t ( ) ;
Cmmdc o b j =(Cmmdc) o b j e c t ;
System . out . p r i n t l n ( R e z u l t a t u l cmmdc e s t e : +o b j . cmmdc( a , b ) ) ;
ctx . c l o s e ( ) ;
}
}
catch ( NamingException e ) {
System . out . p r i n t l n ( LDAPClientCmmdc : +e . g e t M e s s a g e ( ) ) ;
}
}
}

Intreb
ari recapitulative
1. Care este rolul unui serviciu JNDI?
2. Ce nseamna abrevierea JNDI?
3. Care sunt tehnologiile care au utilizat servicii JNDI?

Capitolul 4
Invocarea procedurilor la
distant
a
Invocarea procedurilor la distanta (Remote Procedure Call RPC ) nseamna
apelarea unei metode a unui obiect aflat pe un alt calculator ca si cum acesta
s-ar afla pe calculatorul local.
Se vor prezenta doua cazuri:
Invocarea procedurilor la distanta n cazul mediului omogen Java. Denumirea tehnologiei n acest caz este Invocarea metodei la distanta Remote
Method Invocation (RMI). Prin mediu omogen se ntelege faptul ca atat
compontenta server cat si componenta client sunt programate n acelasi
limbaj de programare, Java n cazul de fata.
Invocarea procedurilor la distanta n cazul medii neomogene. Solutia
n acest caz este dat de Common Object Request Broker Arhitecture
(CORBA).

4.1

Remote Method Invocation

Reg
asirea obiectelor la distant
a. Ideea gasirii unui obiect la distanta
este ca serverul nscrie un reprezentant al sau numit stub (ciot) ntr-un
obiect registry - registru. Acest obiect se creaza cu programul rmiregistry.exe
din distributia java si se lanseaza n executie prin
start rmiregistry [port]
unde valoarea implicita a portului este 1099. Comanda start apartine sistemului de operare. rmiregistry este un serviciu de nume JNDI.
77

78

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Un client obtine din registry stub-ul serverului, prin intermediul caruia


realizeaza comunicatia cu programul server.
Cand un obiect al clientului apeleaza o metoda a unui obiect aflat la
distanta, se va face, de fapt, un apel de metoda a unui obiect care reprezinta
serverul. Acesta este stub-ul, aflat pe aceasi masina cu clientul.
Rolul acestui obiect este sa mpacheteze (marshalling) parametrii de apel
ai metodei ntr-un mesaj ce va fi transferat prin retea. Impachetarea se face
ntr-o maniera independenta de calculator, mai precis sirurile de caractere si
obiecte sunt transmise ntr-un format care nu se bazeaza pe referinte. Pentru
obiecte se utilizeaza serializarea obiectelor Java.
Serializarea datelor reprezinta transformarea acestora din tipuri de date
diferite ntr-un sir de octeti care va fi transportat prin retea fara interpretare,
dar care pastreaza informatiile despre structura initiala a datelor.
Deserializarea este procesul invers de refacere a structurilor trimise prin
retea.
Mesajul asamblat este transmis catre server, care stie sa desfaca mesajul
receptionat invocand n mod corespunzator metoda referita de client.
Atunci cand clientul face apel la o metoda aflata pe o alta masina, este
invocat stub-ul client, care ncepe conversatia cu serverul. Acest lucru este
complet transparent utilizatorului, care are impresia ca invoca o metoda locala.
Metodele apelate la distanta trebuie declarate ca apartinand unei interfete
ce extinde interfata java.rmi.Remote. Fiecare asemenea metoda trebuie sa
arunce o exceptie java.rmi.RemoteException. Obiectele care circula prin
retea trebuie sa implementeze interfata java.io.Serializable.
Structura unei aplicatii RMI. O aplicatie RMI este alcatuita din trei
componente:
1. O interfata la distanta (remote) n care se declara serviciile puse la
dispozitie de server;
2. Aplicatia server care poate implementa serviciile interfetei la distanta si
nscrie n registry stub-ul corespunzator;
3. Aplicatia client ce apeleaza unul sau mai multe servicii ale serverului.
Aplicatia server trebuie sa aiba acces la clasele interfetei si a celor care
o implementeaza. Locatia acestor clase se fixeaza prin atributul de nume
java.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unul
din protocoalele http, ftp, file.
Utilizand protocoalele http sau ftp arhiva interfetei si a claselor care o
implementeaza se depun ntr-un server Web (Microsoft Internet Interchange

4.1. REMOTE METHOD INVOCATION

79

Server (IIS), apache-tomcat, respectiv ntr-un server ftp (apache-ftp). In momentul lansarii aplicatiei server, serverul http / ftp trebuie sa fie activ.
Daca se indica prin protocolul file calea catre cataloagele care contin
clasele interfetei si ale implementarii lor atunci ultimul caracter al caii este /.
Din punctul de vedere al executiei sunt implicate componentele:
Serviciul de nume rmiregistry;
Aplicatia server;
Aplicatia client.
Aplicatia server si rmiregistry trebuie s
a ruleze pe acelasi calculator.
Registrul rmiregistry implementeaza interfata java.rmi.registry.Registry1 .
Metodele oferite sunt:
void bind(String numeServiciu, Remote obj )throws
RemoteException, AlreadyBoundException, AccessException
Inregistreaza n registry obiectul obj ce implementeaza interfata Remote
sub numele numeServiciu.
void rebind(String numeServiciu, Remote obj )throws
RemoteException, AccessException
Renregistreaza n registry obiectul obj ce implementeaza interfata Remote
sub numele numeServiciu.
Aceasta metoda poate fi apelata doar daca programul care face nregistrarea
se afla pe aceasi masina ca registrul registry.
String[] list()throws RemoteException, AccessException
Returneaza o lista a tuturor serviciilor nregistrate n registry.
Remote lookup(String numeServiciu)throws
RemoteException, NotBoundException, AccessException
Returneaza stub-ul serviciului nregistrat sub numele numeServiciu.
void unbind(String numeServiciu)throws
RemoteException, NotBoundException, AccessException
Sterge din registru serviciul.
1

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

80

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Localizarea registrului se obtine utilizand metoda statica getRegistry a


clasei java.rmi.registry.LocateRegistry.
public static Registry getRegistry() throws RemoteException
public static Registry getRegistry(String host)
throws RemoteException
public static Registry getRegistry(int port)
throws RemoteException
public static Registry getRegistry(String host,int port)
throws RemoteException
Metoda public static Registry createRegistry(int port)
throws RemoteException a clasei LocateRegistry creaza un registru la portul specificat pe calculatorul local.
Ansamblul (rmiregistry, port) determina n mod univoc o aplicatie / serviciu.
Interfata Remote serveste la marcarea interfetelor ale caror metode urmeaza
a fi apelate de pe alta masina virtuala Java.
Un obiect de tip java.rmi.server.UnicastRemoteObject mijloceste transmiterea obiectelor si serveste la generarea unui stub unui serviciu. Generarea
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 si implementat de clasa ServiceImpl n registry se face prin
ServiceImpl obj=new ServiceImpl();
IService stub=(IService)UnicastRemoteObject.exportObject(obj,0);
// Varianta cu apel rmiregistry direct
/*
Registry registry=LocateRegistry.getRegistry(host,port);
registry.bind("MyServiceName",stub);
*/
// Varianta JNDI
String sPort=(new Integer(port)).toString();
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,

4.1. REMOTE METHOD INVOCATION

81

"com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL,"rmi://"+host+":"+sPort);
Context ctx=new InitialContext();
ctx.bind("MyServiceName",stub);
Un client care doreste sa foloseasca trebuie sa cunoasca :
calculatorul pe care se gaseste obiectul registry si portul la care asculta
serviciul;
numele sub care serviciul s-a nregistrat n registry;
metodele puse la dispozitie de serviciu.

4.1.1

Crearea unei aplicatii RMI

Exemplificam construirea unei aplicatii RMI n care serviciul asigurat de


server este calculul celui mai mare divizor comun a doua numere naturale.
Pentru exemplele2 care urmeaza, presupunem ca textele sursa se retin
n subcataloage ale unui catalog src, la care are acces doar programatorul,
iar clasele obtinute prin compilare se depun n subcataloagele unui catalog
public\classes, accesibil prin retea.
Dezvoltarea unei aplicatii se va face pe un calculator. In acest sens, celor
3 componente li se asociaza cataloagele \i - pentru interfata la distanta, \s pentru componenta server si \c - pentru componenta client. Pasi necesari compilarii si desfasurarii componentelor aplicatiei se vor realiza prin intermediul
lui ant.
Pentru fiecare componenta se vor executa succesiv obiectivele:
1. Install - creaza o structura de cataloage src si public\classes.
2. Init - creaza structura de cataloage specifica aplicatiei.
3. Compile - compileaza programele sursa.
Dezvoltarea unei aplicatii RMI consta din parcurgerea urmatorilor pasi:
1. Definitea interfetei la distanta.

Sistemul de operare utilizat este Windows

82

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

1
2
3
4

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

Presupunem ca programatorul interfetei retine textul sursa


ICmmdc.java n catalogul \i\src\cmmdc.
2. Compilarea si arhivarea interfetei se poate realiza fisierul ant-build
1
2
3

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

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

<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
2
3
4
5
6
7
8

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

4.1. REMOTE METHOD INVOCATION

9
11

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

implements ICmmdc{

13

public long cmmdc( long a , long b ) { . . . }

15

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

16
17
18
19
20
21
22
23
24

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

26
27
28
29
30

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

32
33
34
35
36
37
38

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

40
41
42
43
44

45
46

83

Textul sursa al programului server CmmdcImpl.java se retine n catalogul


\s\src\server
4. (a) Compilarea programului server;
(b) Crearea obiectului registry;
(c) Lansarea serverului n lucru
se obtin cu ant cu
1
2

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

7
8

84

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

9
10
11
12
13
15
16
17
18
19
20
21
22
23
24
25
27
28
29
30
31
33
34
35
36
37
38
39
40
42
43
44
45
46
47
49
50
51
52
53
54
56
57
58
60
61
63
64
65
66
67

<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 />
<property name= p o r t v a l u e= 1099 />
<property name= hostRMIRegistry v a l u e= l o c a l h o s t />
<property name= h o s t C o d e b a s e 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 >
<env key= c l a s s p a t h v a l u e= p u b l i c / c l a s s e s />
<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 C o d e b a s e } : 8 0 8 0 / rmi /cmmdc . j a r />
>

4.1. REMOTE METHOD INVOCATION

68
69
70
71
72
73
74
75
76

85

< !
<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 C o d e b a s e } : 2 1 2 1 / rmi /cmmdc . j a r />
>
<arg l i n e= ${ hostRMIRegistry } ${ p o r t } />
</ java>
</ target>
</ project>

Obiectivele Rmi si Server se lanseaza n ferestre dos distincte care raman


active pe durata de viata a aplicatiei server.
Obiectivul Archive creaza arhiva jar necesara desfasurarii interfetei si
a claselor care o implementeaza ntr-un server http / ftp. Asa cum
s-a amintit mai sus, acesta arhiva este preluata de aplicatia server, la
lansare, prin atributul java.rmi.server.codebase.
Server ftp
Utilizam serverul ftp apache-ftpserver. Instalarea consta din dezarhivarea
arhivei descarcate. Lansarea serverului se obtine prin
set FTP_SERVER_HOME=. . .
set JAVA_HOME=. . .
%FTP_SERVER_HOME%\bin\ftpd.bat res/conf/ftpd-typical.xml

Resursele / fisierele puse la dispozitie de serverul ftp sunt puse n catalogul FTP SERVER HOME\res\home.
Serverul RMI cu server ftp. Se creaza arhiva cmmdc.jar cu continutul
cmmdc
|
ICmmdc.class
server
|
CmmdcImpl.class

care se depune n serverul ftp, n catalogul rmi.


5. Realizarea programului client

1
2
3
4
5

package c l i e n t ;
import cmmdc . ICmmdc ;
import j a v a . u t i l . S c a n n e r ;
// V a r i a n t a cu a p e l r m i r e g i s t r y d i r e c t
import j a v a . rmi . r e g i s t r y . R e g i s t r y ;

86

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

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

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

39
40

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

41
42
43
44

45
46

Sursa programului client CmmdcClient.java apartine catalogului


\c\src\client
6. Compilarea programului client si lansarea acestuia n executie.
1
2

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

7
8
9
10
11

4.1. REMOTE METHOD INVOCATION

12

<property name= c l i e n t c l a s s v a l u e= CmmdcClient />

14

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

15
16
17
18
19
20

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

22
23
24
25
26
27
28

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

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

87

<target name=Run depends= Compile


description= S t a r t t h r c l i e n t >
<java c l a s s n a m e= ${ package } . $ { c l i e n t c l a s s } f o r k= t r u e >
<classpath>
<pathelement l oc a t io n= c l a s s e s /${ j a r f i l e } />
<pathelement path= c l a s s e s />
</ classpath>
<arg l i n e= ${ h o s t } ${ p o r t } />
</ java>
</ target>
</ project>

4.1.2

Tipare de programare

Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamica a unui server. Prin
aceea schema, se va crea o clasa - fabrica de obiecte - care implementeaza cate
o metoda get, ce returneaza o instanta de server. Aceste metode sunt declarate
ntr-o interfata la distanta.
Un client, apeland o asemenea metoda, va instantia serverul dorit si va
obtine stub-ul corespunzator.
In felul acesta se vor putea utiliza o multime de aplicatii distincte prin
intermediul unui singur rmiregistry. Fiecarei aplicatii i corespunde un server,
instantiat la apelul clientului de metoda get corespunzatoare.

88

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Programarea unui server care poate fi lansat dinamic trebuie sa satisfaca


restrictiile:
Clasa serverului extinde clasa UnicastRemoteObject.
Exista un constructor fara argumente ce arunca exceptia java.rmi.Remote
Exception.
Pentru exemplificarea tehnicii de lucru reluam aplicatia pentru calculul
celui mai mare divizor comun a doua numere naturale, considerand interfata
1
2
3
4

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

Aceasa interfata va fi implementata de clasa ServerCmmdc. Metoda compute este o metoda de calcul a celui mai mare divizor comun a doua numere.
Obiecte de tip ServerCmmdc se creaza, de la distanta prin fabrica de obiecte
FabObiecte, o clasa ce implementeaza interfata
1
2
3
4

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

Codurile claselor ServerCmmdc si FabObiecte sunt


3

package cmmdc0 ;
im po rt j a v a . rmi . RemoteException ;
im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ;

p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject implements ICmmdc0{

1
2

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 {


. . .
}

10
11
12

respectiv

package cmmdc0 ;
im po rt j a v a . rmi . RemoteException ;
im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ;
im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ;
im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ;

p u b l i c c l a s s FabObiecte implements I F a b O b i e c t e {

1
2
3
4

9
10
11

p u b l i c ICmmdc0 getCmmdc ( ) throws RemoteException {


ServerCmmdc cmmdc=new ServerCmmdc ( ) ;
r e t u r n cmmdc ;

4.1. REMOTE METHOD INVOCATION

12

14

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

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

89

Aplicatia client se compune din doua clase


1. RemoteClient
Clientul obtine stub-ul serviciului, prin intermediul caruia apeleaza metada
getCmmdc() a fabricii de obiecte, obtinand un obiect remote de tip
ServerCmmdc, ce implementeaza interfata la distanta ICmmdc0.

package cmmdc0 ;
im po rt j a v a . rmi . RemoteException ;
im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ;
im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ;
im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ;

p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject {

1
2
3
4

ICmmdc0 remote=n u l l ;

9
11

p u b l i c RemoteClient ( ) throws RemoteException {}

13

p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException {


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

14
15
16
17
18
19
20
21
22
23

2. ClientCmmdc0
Apeleaza metoda compute a obiectului remote.

90

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

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

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

Apelul invers Callback


Se numeste apel invers apelarea de catre programul server a unei metode
a clientului.
In RMI realizarea unui apel invers presupune:
1. definirea unei interfete la distanta ce va fi implementat de programul
client;
2. programul client ce implementeaza interfata extinde clasa UnicastRemote
Object si are un constructor ce arunca o exceptie java.rmi.RemoteException.
Extindem aplicatia anterioara cu posibilitatea suplimentara a serverului
(ServerCmmdc) de a alege metoda de calcul a celui mai mare divizor comun
dintre varianta imperativa si cea recursiva.
Extindem interfata ICmmdc0 cu metoda
public void setMethod(ICallbackCmmdc obj)throws RemoteException;

4.1. REMOTE METHOD INVOCATION

1
2
3
4
5

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

unde ICallbackCmmdc este interfata


1
2
3
4

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

ce va fi implementata n clasa RemoteClient.


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

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

91

92

return c ;

43

44
45

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Dupa obtinerea stub-ului, clientul apeleaza metoda setMethod a serverului


remote, care, prin apel invers, apeleaza metoda getMethod din RemoteClient.
Clientul stabileste metoda de calcul si apeleaza metoda compute a lui remote.
Programele client devin
1
2
3
4
5
6
8
9
10

package cmmdc0 ;
im po rt j a v a . rmi . RemoteException ;
im po rt j a v a . rmi . s e r v e r . UnicastRemoteObject ;
im po rt j a v a . rmi . r e g i s t r y . R e g i s t r y ;
im po rt j a v a . rmi . r e g i s t r y . L o c a t e R e g i s t r y ;
im po rt j a v a . u t i l . S c a n n e r ;
p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject
implements ICallbackCmmdc {
ICmmdc0 remote=n u l l ;

12

p u b l i c RemoteClient ( ) throws RemoteException {}

14

p u b l i c S t r i n g getMethod ( ) {
S c a n n e r s c a n n e r=new S ca n n e r ( System . i n ) ;
System . out . p r i n t l n ( A l e g e t i v a r i a n t a a l g o r i t m u l u i l u i E u c l i d ) ;
System . out . p r i n t l n ( 1 a l g o r i t m u l 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 ;
}

15
16
17
18
19
20
21
22
23
24
25
26

p u b l i c RemoteClient ( S t r i n g hos t , i n t p o r t ) throws RemoteException {


try {
R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h os t , p o r t ) ;
I F a b O b i e c t e o b j =( I F a b O b i e c t e ) r e g i s t r y . l o o k u p ( O b j e c t F a c t o r y ) ;
remote=o b j . getCmmdc ( ) ;
}
catch ( Exception e ){
System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
}

28
29
30
31
32
33
34
35
36
37
38

si
1
2
4
5
6
7
8

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)

4.1. REMOTE METHOD INVOCATION

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 ) ;
c t . remote . setMethod ( c t ) ;
System . out . p r i n t l n ( m= ) ;
l o n g m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
l o n g n=s c a n n e r . nextLong ( ) ;
l o n g x=c t . remote . compute (m, n ) ;
System . out . p r i n t l n ( Cmmdc=+x ) ;
}
catch ( Exception e ){
System . out . p r i n t l n ( C l i e n t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
System . e x i t ( 0 ) ;

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

27
28

93

4.1.3

Obiect activabil la distant


a

O instanta a clasei UnicastRemoteObject reprezinta un obiect la distanta


care ruleaza n permanenta, folosind resursele masinii server.
Incepand cu versiunea JDK 1.2, prin ntroducerea clasei java.rmi.activation.Activatable si a programului rmid (...\jdk...\bin\rmid.exe) se pot crea
programe care nregistreaza informatii despre obiecte la distanta ce vor fi create
si executate la cerere.
Invocarea de la distanta a unei metode apartinand unui asemenea obiect
are ca efect activarea obiectului.
Pe fiecare masina virtuala Java exista un grup de activare (activation
group), care realizeaza activarea. Activarea este facuta de un activator. Un
activator contine o tabela care face legatura dintre clasa obiectului cu URL-ul
acestuia si eventual, cu date necesare initializarii obiectului. Atunci cand activatorul constata ca nu exista un obiect referit, face apel la grupul de activare
care va produce activarea obiectului.
Din punctul de vedere al clientului utilizarea mecanismului de activare la
distanta nu implica modificari. Modificarile intervin numai din punctul de
vedere al serverului si al nregistrarii sale.
Reluam aplicatia dezvoltata la nceputul capitolului, privind calculul celui
mai mare divizor comun a doua numere naturale.
Aplicatia server este compusa din doua clase
1. o clasa ce implementeaza interfata ICmmdc : CmmdcActivabil;

94

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

2. clasa Setup, cu metoda main, care face posibila mecanismul de activare


si nscrie serviciul n registry. Aceasta clasa este preluata din tutorialul
dedicat activarii a documentatiei ce nsoteste distributia Java.
Clasa ce implementeaza interfata la distanta trebuie
1. sa extinda clasa Activatable;
2. sa aiba un constructor ce are doi parametrii
(a) un identificator al grupului de activare, de tip ActivationID, utilizat
de demonul de activare rmid;
(b) un obiect de tip MarshalledObject cu date de initializare a obiectului activabil. In cazul nostru, acest parametru nu va fi folosit.
Codul sursa al clasei CmmdcActivabil este
1
2
3
4
5
6
8
9

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

11
12
13
14

p u b l i c l o n g cmmdc( l o n g m, l o n g n ) { . . . }

16
17

Clasa Setup necesita o serie de date furnizare ca proprietati:


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

4.1. REMOTE METHOD INVOCATION

95

2. java.class.path=no.classpath
ceea ce previne grupul de activare sa ncarce o clasa din classpath-ul
local;
3. localizarea (URL) clasei ce implementeaza interfata
myactivation.impl.codebase;
4. localizarea unui fisier cu date de initializare a obiectului activabil
myactivation.file;
5. numele sub care nregistreaza serviciul n registry
myactivation.name.
Programul Setup realizeaza:
1. Construirea unui descriptor al grupului de activare, instanta a clasei
ActivationGroupDesc. Grupul de activare este un container ce gestioneaza obiectele activabile continute.
2. Inregistrarea descriptorului grupului de activare, instanta a clasei ActivationDesc si obtinerea unui identificator al grupului de activare, instanta
a clasei ActivationGroupID.
3. Construirea descriptorului de activare. Trebuie cunoscute
idendificatorul grupului de activare;
numele clasei ce implementeaza interfata la distanta;
localizarea (URL) clasei ce implementeaza interfata la distanta;
obiectul de tip MarshalledObject, cu datele de initializare a obiectului activabil.
4. Inregistrarea descriptorului de activare, n urma careia se obtine stub-ul
obiectului activabil.
5. Inregistrarea stub-ului mpreuna cu numele serviciului n registry.
Codul clasei setup este

96

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

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 j a v a . rmi . r e g i s t r y . ;
im po rt j a v a . u t i l . P r o p e r t i e s ;
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 ] acmmdc . 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 implCodebase=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 ) ;

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

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

35
36
37
38
39

// C o n s t r u i r e a d e s c r i p t o r u l u i de a c t i v a r e
M a r s h a l l e d O b j e c t data = n u l l ;
i f ( filename != n u l l && ! filename . equals ( ) ) {
data = new M a r s h a l l e d O b j e c t ( filename ) ;
}

41
42
43
44
45

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

47
48

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

50
51
52

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

54
55
56
57
58

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

4.1. REMOTE METHOD INVOCATION

59

97

Sursele celor doua programe CmmdcActivabil.java si respectiv Setup.java


sunt n catalogul \c\src\acmmdc.
Lansarea serverului n executie consta din
1. Pornirea registry-ului
start rmiregistry
2. 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";
};

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

98

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Localizarea (URL) interfetei la distanta se precizeaza prin


java.rmi.server.codebase;
Drept client se utilizeaza programul realizat n sectiunea 4.1.

4.2

CORBA

Retelele de calculatoare sunt eterogene n timp ce majoritatea interfetelor


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
cuprinzand peste 800 de firme) a elaborat standardul CORBA (Common Object Request Broker Arhitecture): un cadru de dezvoltare a aplicatiilor distribuite n medii eterogene.
La CORBA au aderat toate marile firme de software - cu exceptia Microsoft,
firma care a dezvoltat propriul sau model DCOM (Distributed Component
Object Model), incompatibil CORBA.
Aplicatia server se nregistreaza ntr-un Object Request Broker (ORB)
sub un nume simbolic - nume serviciu. Pe baza acestui nume de serviciu, un
client accesand ORB va avea acces la functiile oferite de aplicatia server.
ORB este un pachet de servicii, independent de aplicatii, dar care permit
aplicatiilor sa interactioneze prin retea. ORB face parte din middleware un
intermediar ntre softul de retea si cel de aplicatie.
Un ORB se poate executa local pe un singur calculator sau poate fi conectat
cu oricare alt ORB din Internet, folosind protocolul IIOP -- Internet Inter
ORB Protocol, definit de CORBA 2.
Distributia jdk ofera un ORB utilizabil n Java sub forma unui serviciu
JNDI.
CORBA face o separare ntre interfata unui obiect si implementarea sa si
foloseste un limbaj neutru pentru definirea interfetelor: IDL -- Interface
Definition Language.
IDL permite realizarea descrierii de interfete independent de limbajul de
programare si de sistemul de operare folosit. O interfata IDL defineste legatura
dintre client si server.

4.2.1

Conexiunea RMI - CORBA

Firma Oracle - Sun Microsystems a dezvoltat o solutie prin care interfetele


RMI pot fi implementate pentru a putea fi accesate ca obiecte CORBA. Aceasta

4.2. CORBA

99

este cunoscuta sub numele de solutia RMI-IIOP, concretizata printr-o serie de


pachete din distributia jdk. In acest fel nu mai este necesar utilizarea limbajului IDL pentru descrierea interfetelor la distanta.
Instrumente necesare utilizarii solutiei RMI-IIOP:
compilatorul rmic
Optiunea -iiop genereaza stub-ul si legatura (tie) din partea serverului.
Cu optiunea -d se specifica catalogul n care aceste fisiere sunt scrise.
serviciul ORB care asigura regasirea resurselor CORBA. Acest server se
lanseaza n executie prin
start orbd -ORBInitialPort [port]
Programele orbd, rmic sunt n distributia jdk.

Dezvoltarea unei aplicatii RMI-IIOP


Exemplificam prin aplicatia care implementeaza un serviciu de calcul a celui
mai mare divizor comun a doua numere naturale. Etapele realizarii aplicatiei
sunt:
1. Elaborarea interfetei este identica cu cea a aplicatiei RMI.
2. Implementarea interfetei
1
2
3
4
6
7
9
10
11

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

13
14

3. Realizarea programului server.

100

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

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

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

17
18
19
20
21
22
23
24
25

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

26
27
28
29

30
31

4. Compilarea programelor CmmdcImpl.java si CmmdcServer.java.


5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunzator interfetei
ICmmdc si a fisierului Tie cmmdciiop. CmmdcImpl Tie.class corespunzator
clasei CmmdcImpl. Acestea se obtin ruland utilitarul rmic - din distrubutia
Java cu optiunea -iiop
rmic -iiop cmmdciiop.CmmdcImpl
6. Pornirea serverului CORBA de regasire a serviciilor
start orbd -ORBInitialPort 1050
7. Lansarea serverului n executie.
Activitatile legate de server se obtin prin ant cu fisierul build

101

4.2. CORBA

1
2

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

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
51
52
53
55
56
57
58

/>

<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 /METAINF />
</ target>
<target name= Compile depends= I n i t
description= c o m p i l e t h e s o u r c e >
<javac s r c d i r= s r c d e s t d i r= p u b l i c / c l a s s e s
i n c l u d e s= ${ package }\
classpath= p u b l i c \ c l a s s e s \${ j a r f i l e }
i n c l u d e a n t r u n t i m e= f a l s e />
<rmic c l a s s n a m e= ${ package } . $ { i m p l e m e n t a t i o n c l a s s }
s o u r c e b a s e= s r c
i i o p= y e s
b a s e= p u b l i c / c l a s s e s
classpath= p u b l i c / c l a s s e s />
</ target>
<target name=Orb>
<exec e x e c u t a b l e= orbd >
<arg l i n e=O R B I n i t i a l P o r t ${ p o r t } O R B I n i t i a l H o s t ${ h o s t } />
</ exec>
</ target>
<target name= S e r v e r description= S t a r t t h r s e r v e r >
<java c l a s s n a m e= ${ package } . $ { s e r v i c e c l a s s } f o r k= t r u e >
<classpath>
<pathelement l oc a t io n= p u b l i c / c l a s s e s /${ j a r f i l e } />

102

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

59
60
61
62
63
64

<pathelement path= p u b l i c / c l a s s e s />


</ classpath>
<arg l i n e= ${ h o s t } ${ p o r t } />
</ java>
</ target>
</ project>

orbd si aplicatia server se pot afla pe calculatoare distincte.


8. Editarea programului client.

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

package cmmdciiop ;
import j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ;
import j a v a x . naming . Context ;
import j a v a x . naming . I n i t i a l C o n t e x t ;
import j a v a . u t i l . S c a n n e r ;
import cmmdc . ICmmdc ;
public c l a s s CmmdcClient {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1050 ;
i f ( a r g s . l e n g t h >0)
h o s t=a r g s [ 0 ] ;
i f ( a r g s . l e n g t h >1)
p o r t=a r g s [ 1 ] ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( Primul numar : ) ;
long m=Long . par se Lo ng ( s c a n n e r . n e x t ( ) ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ;
try {
System . s e t P r o p e r t y ( j a v a . naming . f a c t o r y . i n i t i a l ,
com . sun . j n d i . cosnaming . CNCtxFactory ) ;
System . s e t P r o p e r t y ( j a v a . naming . p r o v i d e r . u r l ,
i i o p : / / +h o s t+ : +p o r t ) ;
Context c t x = new I n i t i a l C o n t e x t ( ) ;

17
18
19
20
21
22
23
24
25
26
27

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

29
30
31
32

// STEP 2 : Narrow t h e o b j e c t r e f e r e n c e t o t h e c o n c r e t e t y p e and


// i n v o k e t h e method .
ICmmdc o b j =(ICmmdc) P o r t a b l e R e m o t e O b j e c t . narrow ( o b j r e f , ICmmdc . c l a s s ) ;
long x=o b j . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc=+x ) ;

34
35
36
37
38

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

39
40
41
42

43
44

4.2. CORBA

103

9. Compilarea si lansarea clientului n executie. Clientul trebuie sa dispuna


de fisierul stub (cmmdc. ICmmdc Stub.class) si binenteles de interfata
ICmmdc.jar.
Fisierul buildfile pentru executarea clientului:
1
2

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

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
43
45
46
47
48
49
50
52
53

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

104

54
55
56
57
58
59
60
61

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

<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 dezvoltarii unei aplicatii pe baza


unei interfete bazat pe IDL.
Pentru dezvoltarea aplicatiilor n limbajul de programare Java, translatarea
interfetei IDL n Java se realizeaza cu utilitarul idlj din distributia jdk.
Corespondenta ntre entitatile IDL si Java este data n Tabelul 4.1
Tip IDL
module
boolean
char, wchar
octet
string, wstring
short, unsigned short
long, unsigned long
long long, unsigned long long
float
double
fixed
enum, struct, union
sequence, array
interface (non-abstract)

Any

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

Table 4.1: Entitati IDL si Java

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

105

4.2. CORBA

Model cu server temporal


Exemplificam dezvoltarea unei aplicatii distribuite CORBA n cazul n care
serviciul pus la dispozitie de server este calculul celui mai mare divizor comun
a doua numere naturale.
Dezvoltarea unei aplicatii distribuite CORBA cu mediul nativ Java presupune parcurgerea urmatoarelor pasi:
1. Realizarea interfetei IDL care nseamna
(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 ) ;
};
};

Salvam acest text ntr-un fisier denumit Cmmdc.idl.


Cmmdc va fi numele interfetei utilizat de un client si implementat
de server. Serviciul contine o singura metoda cmmdc.
(b) Translatarea interfetei n Java
idlj -fall Cmmdc.idl
Programul idlj creaza un subcatalog CmmdcApp cu un pachet Java CmmdcApp
continand fisierele:
Cmmdc.java
CmmdcPOA.java ;
CmmdcOperations.java;
CmmdcStub.java;
CmmdcHelper.java;
CmmdcHolder.java.
2. Realizarea programelor server. Punem n evidenta programul servant
CmmdcImpl.java ce implementeaza interfata Cmmdc.
1
2
4
5

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

106

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

p u b l i c CmmdcImpl (ORB orb ) {


t h i s . orb = orb ;
}

7
8
9

p u b l i c l o n g cmmdc( l o n g a , l o n g b ) { . . . }

11
12

si programul CmmdcServer.java, care nscrie n registrul ORB referintele


servantului. Activitatile ce trebuie ntreprinse sunt declarate prin comentarii n textul sursa al programului
1
2
3
4
5
6
7
9
10
11
12
13
15
16
17
18
19
21
22
24
25
26
28
29
30
31

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

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

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

36

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

38

System . out . p r i n t l n ( CmmdcServer r e a d y and w a i t i n g

40

// Gata p e n t r u s a t i s f a c e r e a
orb . run ( ) ;

33
34
35

41
42
43
44
45
46

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

. . . );

107

4.2. CORBA

47
48

Aceasta clasa corespunde unui sablon de programare adaptat exemplului


tratat. In acest caz numele serviciului inregistrat n ORB va fi CmmdcService. Evidenta numelor serviciilor CORBA nregistrate n ORB este
facuta de serviciul NameService.
3. Realizarea programului client CmmdcClient.java:
1
2
3
4
5
7
8

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

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

10
11
12
13

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

15
16
17
18
19

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

21
22
23

System . out . p r i n t l n ( Obtained a h a n d l e on s e r v e r o b j e c t : +


cmmdc ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
l o n g m, n ;
System . out . p r i n t l n ( m= ) ;
m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
n=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Cmmdc=+cmmdc . cmmdc(m, n ) ) ;

25
26
27
28
29
30
31
32
33

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

34
35
36
37
38

39
40

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

Din nou clasa client contine sablonul de accesare a unui serviciu CORBA.
Programele se compileaza

108

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


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 considera aceasi interfata Cmmdc.idl.
Partea de server este alcatuita din clasa servant CmmdcImpl.java care implementeaza interfata Cmmdc -prezentat n sectiunea anterioara si clasa PersistentServer care asigura
legatura cu serviciile ORB;
accesul la clasa servantului.
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17

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

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

public class PersistentServer {


p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
P r o p e r t i e s p r o p e r t i e s = System . g e t P r o p e r t i e s ( ) ;
p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l H o s t , l o c a l h o s t ) ;
p r o p e r t i e s . put ( o r g . omg .CORBA. O R B I n i t i a l P o r t , 1050 ) ;
try {
// Pas 1 : C r e a s e s i i n i t i a l i z a r e ORB

109

4.2. CORBA

18

ORB orb = ORB. i n i t ( a r g s , p r o p e r t i e s ) ;

20

// Pas 2 : C r e a r e a unui s e r v a n t
CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ;

21

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

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

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

39
40

// Pas 5 :
//
// Numele
// Numele

42
43
44
45

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

47
48
49
50
51

// Pas 6 : Gata p e n t r u s a t i s f a c e r e a
orb . run ( ) ;

53
54

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

55
56
57
58
59

60
61

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

Programul client
1
2
3
5
6
7
8
9
10
11
12

im po rt CmmdcApp . ;
im po rt o r g . omg .CORBA.ORB;
im po rt j a v a . u t i l . S c a n n e r ;
public class PersistentClient {
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1050 ;
i f ( a r g s . l e n g t h >0)
h o s t=a r g s [ 0 ] ;
i f ( a r g s . l e n g t h >1)
p o r t=a r g s [ 1 ] ;

110

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

13
14
15

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

17
18
19
20
21
22
23

// Pas 3 : U t i l i z a r e a s e r v i c i u l u i
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( C a l l i n g P e r s i s t e n t S e r v e r . . ) ;
i n t m, n , r ;
System . out . p r i n t l n ( m= ) ;
m=s c a n n e r . n e x t I n t ( ) ;
System . out . p r i n t l n ( n= ) ;
n=s c a n n e r . n e x t I n t ( ) ;
System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ;

25
26
27
28
29
30
31
32
33

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

34
35
36
37
38

39
40

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

Serverul trebuie sa fie pe acelasi calculator pe care ruleaza orbd. Executarea 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 lanseaza utilitarul servertool
servertool -ORBInitialPort 1050
(b) Se nregistreaza serverul mpreuna cu numele serviciului pe care l
ndeplineste:
servertool > register -server PersistentServer
-applicationName PersistentCmmdcServer
-classpath cale_catre_fisierele_server\

111

4.2. CORBA

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>

Semnificatie
shutdown -serverid 257
Oprirea serviciului
unregister -serverid 257 Stergerea serviciului
Inchiderea utilitarului
quit
help

Observatie 4.2.1 Daca se utilizeaza referinta


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 si servertool se va face prin
c:\Progra~1\Java\jdk1.7.0_*\bin\orbd -ORBInitialPort 1050 -serverPollingTime 200
c:\Progra~1\Java\jdk1.7.0_*\bin\servertool -ORBInitialPort 1050

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

Intreb
ari recapitulative
1. Precizati abrevierea RMI.
2. Care sunt componentele unei aplicatii client-server bazat pe RMI?
3. Cate si care sunt entitatile care participa la executia unei aplicatii clientserver bazat pe RMI?
4. Care este rolul ndeplinit de (rmi)registry?
5. Ce asigura sablonul de programare Fabrica de obiecte n RMI?
6. Ce asigura sablonul de programare Callback n RMI?
7. Explicati caracterul sincron al comunicarii n RMI.

112

CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANT


A

8. Care sunt activitatile pe care un server RMI le are de indeplinit ?


9. Care sunt componentele unei aplicatii client server bazat pe CORBA?
10. Cate si care sunt entitatile care participa la executia unei aplicatii clientserver bazat pe CORBA?
11. Care este ideea solutiei CORBA pentru asigurarea interoperabilitatii
ntre client si server realizate n limbaje de programare diferite.
12. Explicati caracterul sincron al comunicarii n CORBA.
13. Ce ofera RMI-IIOP ?
14. Precizati modelele de aplicatii CORBA prezentate n curs si diferenta
dintre ele din punctul de vedere al executiei.

Capitolul 5
Mesaje n Java
Comunicatia prin apelul la distanta - inclusiv RMI - este sincron: programul apelant se blocheaza si asteapta ca metoda apelata sa se termine si sa
furnizeze rezultatul cerut. Cu alte cuvinte apelul de procedura la distanta cere
atat clientului cat si serverului sa fie simultan disponibile.
Comunicatiile asincrone1 ntre programe permit realizarea unor sisteme de
programe cu un grad mult mai scazut de cuplare, n sensul ca lansarea unei
cereri si receptionarea rezultatului se pot executa n momente diferite de timp.
Asemenea aplicatii se pot realiza prin comunicatii de mesaje, mesaje care sunt
retinute de un intermediar (serviciu de mesagerie, server, broker, messaging
middleware).

5.1

Java Message Service (JMS)

JMS defineste un cadru de programare Java (API) pentru realizarea aplicatiilor


bazate pe comunicatii asincrone.
Prezentarea se bazeaza pe interfata de programare (API) JMS-2 implementata de
Open Message Queue 5.* implementarea de referinta, Oracle.
hornetq-*, RedHat-jboss.
Pentru interfata de programare (API) JMS-1, exista mai multe implementari JMS, dintre care semnalam:
Open Message Queue *
1

In acceptiunea din acest capitol.

113

114

CAPITOLUL 5. MESAJE IN JAVA

apache ActiveMQ
apache qpid
Aceste produse implementeaza una sau mai multe protocoale privind reprezentarea datelor unui mesaj si detalii privind transmiterea lor. Advanced Message Queue Protocol (AMQP), Streaming Text Oriented Messaging Protocol
(STOMP) sunt exemple de asemenea protocoale. Scopul unui protocolul este
asigurarea interoperabilitatii ntre aplicatii de mesagerie realizate n diferite
limbaje de programare, produse sau platforme de calcul.
O aplicatie JMS este alcatuita din
un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementeaza specificatiile JMS;
client JMS : aplicatie Java care trimite si receptioneaza mesaje;
mesaje : obiecte utilizate n schimbul de informatii de clienti JMS;
obiecte administrator - obiecte (resurse) create de administrator pentru
a fi utilizate de clientii JMS, precum
fabrica de conexiuni,
obiectele destinatie pentru retinerea mesajelor.
Aplicatiile dezvoltate pe baza JMS 1/JMS 1.1 functioneaza si n cazul utilizarii unui furnizor de servicii realizat pentru JMS-2. In esenta, JMS-2 simplifica programarea fata de JMS-1.
Modele de comunicatie:
Comunicatii punctuale : Un mesaj este generat de un producator (expeditor) si la care va avea acces un singur consumator (destinatar). Mesajul
este depus ntr-o coada, de unde este preluat de catre consumatorul care
s-a legat de coada. Daca de coada nu se leaga nici un consumator, atunci
mesajul este pastrat n coada.
Comunicatii axate pe subiect (topic) : Mesajele sunt depuse (publicate)
n destinatii specifice subiectului. Consumatorii ce au subscris la acel
subiect au acces la mesajele respective. Mai multi producatori pot genera
mesaje specifice unui subiect, mesaje care pot fi accesate de consumatorii
care au subscris subiectului.
Consumatorii abonati pe un subiect pot fi

5.2. OPEN MESSAGE QUEUE 5

115

abonat simplu - valabi, adica are acces la mesajele emise dupa momentul abonarii, pe durata conexiunii la furnizorul de servicii JMS;
abonat permanent - valabil si dupa o ntrerupere a conexiunii la
furnizorul de servicii JMS;
abonat partajat - mai multi abonati utilizeaza aceasi conexiune;
abonat partajat si permanent.
Structura unui mesaj Un mesaj este alcatuit din
Antet (header) : contine informatii pentru identificarea destinatiei cat si
pentru identificarea mesajului.
Proprietati : au caracter optional si sunt sub forma (nume, valoare).
Proprietatile ajuta consumatorii sa selecteze mesajele.
Corpul mesajului : optional. Potrivit specificatiilor JMS exista 6 tipuri
de mesaje.
javax.jms.Message : mesaj fara corp;
javax.jms.StreamMessage : corpul mesajului contine un flux Java
de date de tip predefinit;
javax.jms.ByteMessage :
javax.jms.MapMessage : corpul mesajului contine o familie de
perechi (nume, valoare);
javax.jms.TextMessage : corpul mesajului contine un string;
javax.jms.ObjectMessage : corpul mesajului contine un obiect
serializat.
Atasament (optional).

5.2

Open Message Queue 5

Instalarea variantei de sine st


at
atoare. In mediul Windows, n functie
de resursa descarcata instalarea consta din:
Se dezarhiveaza fisierul openmq*-binary-Windows.zip
Se fixeaza atributele fisierului etc\mq\imqenv.conf.

116

CAPITOLUL 5. MESAJE IN JAVA

Lansarea serviciului JMS. Orice aplicatie JMS necesita functionarea


serviciului JMS. Serviciul JMS se instaleaza prin
imqbrokerd
Functionarea corecta este indicata prin mesajul
imqbroker@hostname:7676 ready
Daca se doreste schimbarea portului atunci se foloseste optiunea -port
port.
Pe un calculator pot coexista mai multe servicii JMS doar daca folosesc
porturi distincte si au nume diferite. In acest caz, lansarea unui nou serviciu
se face prin
imqbrokerd -port port -name name
Cu utilitarul imqsvcadmin putem
dezinstala : imqsvcadmin remove
verifica : imqsvcadmin query
instala : imqsvcadmin install
serviciul JMS ca serviciu Windows. Dezinstalarea si instalarea are efect odata
cu repornirea calculatorului.
Compilarea si executarea unui program necesita completarea variabilei
sistem classpath cu fisierele
JMS HOME\lib\jms.jar
JMS HOME\lib\imq.jar

5.3

Elemente de programare - JMS-2

Semnalam doua modalitati de programare / generare / regasire a obiectelor


administrator:
Programat: obiectele administrator se instantiaza prin API-ul oferit de
produsul informatic;
Prin JNDI. Codul sursa al programelor este independent de furnizorul
de servicii de mesagerie. Elementele specifice se declara n fisiere de
proprietati.

5.3. ELEMENTE DE PROGRAMARE - JMS-2

5.3.1

117

Modul programat: Trimiterea unui mesaj

Trimiterea unui mesaj necesita:


1. Generarea obiectelor administrator
(a) Fabrici de conexiuni.
com.sun.messaging.ConnectionFactory cf=
new com.sun.messaging.ConnectionFactory();
Clasa com.sun.messaging.ConnectionFactory are descendentii:
QueueConnectionFactory
TopicConnectionFactory
(b) Obiectul destinatie. In cazul comunicatiilor punctuale obiectul destinatie
este de tip javax.jms.Queue, iar crearea se face prin
Queue q=new com.sun.messaging.Queue(numeCoada);
Pentru comunicatii axate pe subiect, obiectul destinatie, de tip
javax.jms.Topic se instantiaza prin
Topic t=new com.sun.messaging.Topic(subiect);
2. Instantierea unui obiect de tip javax.jms.JMSContext
JMSContext ctx=cf.createContext();
In final, contextul se nchide
ctx.close();
Prin intermediul unui obiect de tip JMSContext se obtin producatorii de
mesaje, de tip javax.jms.JMSProducer, dar si consumatorii de mesaje,
de tip javax.jms.JMSConsumer.
3. Instantierea unui producator de mesaje
JMSProducer producer=ctx.createProducer();
Crearea si expedierea mesajelor se realizeaza cu metodele clasei
JMSProducer

118

CAPITOLUL 5. MESAJE IN JAVA

JMSProducer send(Destination destination, byte[] body)


JMSProducer send(Destination destination, Serializable body)
JMSProducer send(Destination destination, Map<String,Object>
body)
JMSProducer send(Destination destination, String body)
JMSProducer send(Destination destination, Message message)
Un obiect care implementeaza interfata javax.jms.Message se obtine
prin ctx.createMessage().
Exemplul 5.3.1 Clasa urmatoare genereaza ntr-un fir de executie, un numar
de mesaje de tip TextMessage ntr-o comunicatie punctuala. Sfarsitul expedierii mesajelor se indica prin generarea unui mesaj de tip Message. Numarul
mesajelor este indicat de un parametru al constructorului.
1
2
3
5
6
7

import j a v a x . jms . Queue ;


import j a v a x . jms . JMSContext ;
import j a v a x . jms . JMSProducer ;
public c l a s s MsgSenderT extends Thread {
int n ;
S t r i n g queueName ;
MsgSenderT ( S t r i n g queueName , i n t n ) {
t h i s . queueName=queueName ;
t h i s . n=n ;
}

9
10
11
12

public void run ( ) {


try {
com . sun . m e s s a g i n g . QueueConnectionFactory c f=
new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ;

14
15
16
17
18
19
20
21
22

f o r ( i n t i =0; i <n ; i ++){


p r o d u c e r . send ( q , H e l l o +i ) ;
}
p r o d u c e r . send ( q , c t x . c r e a t e M e s s a g e ( ) ) ;
ctx . c l o s e ( ) ;

24
25
26
27
28

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

29
30
31
32
33

34
35

5.3. ELEMENTE DE PROGRAMARE - JMS-2

5.3.2

119

Receptia sincron
a a unui mesaj

Primele doua actiuni sunt identice cu cele de la trimiterea unui mesaj:


1. Generarea obiectelor administrator.
2. Instantierea unui obiect de tip javax.jms.JMSContext.
3. Instantierea unui consumator de mesaje
JMSConsumer consumer = ctx.createConsumer(q);
Receptia unui mesaj se obtine cu una din metode
Message receive()
Receptie blocanta.
Message receive(long timeout)
Receptie ntr-un interval de timp.
Message receiveNoWait()
Receptie neblocanta.
Exemplul 5.3.2 Receptia de tip sincron a mesajelor ntr-un fir de executie
este efectuat de clasa urmatoare:
1
2
3
4
5
7
8
10
11
12
14
15
16
17
18
19
20
21
22
23
24

import
import
import
import
import

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

public c l a s s SyncMsgReceiverT extends Thread {


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

120

CAPITOLUL 5. MESAJE IN JAVA

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 ;

25
26
27
28
29
30

}
ctx . c l o s e ( ) ;

31
32

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

33
34
35
36
37

38
39

Exemplul 5.3.3 Trimiterea si receptia mesajelor se face prin aplicatia


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

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

5.3.3

Receptia asincron
a a unui mesaj

Receptia asincrona a mesajelor presupune implementarea interfetei


MessageListener ce contine o singura metoda
public void onMessage(Message mesaj);
care fixeaza prelucrarea mesajului.
Metoda setMessageListener(MessageListener obj ) a clasei
JMSConsumer fixeaza obiectul ce implementeaza interfata Messagelistener.
Astfel, caracterul asincron consta din faptul ca mesajele sunt preluate de
ascultator - adica obiectul ce implementeaza interfata MessageListener si nu
de clientul JMS.
ideea exemplelor anterioare, un consumator de tip asinExemplul 5.3.4 In
cron al mesajelor este dat n clasa urmatoare:

5.3. ELEMENTE DE PROGRAMARE - JMS-2

1
2
3
4
6
7

import
import
import
import

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

9
10
11

public void run ( ) {


try {
com . sun . m e s s a g i n g . QueueConnectionFactory c f=
new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Queue q=new com . sun . m e s s a g i n g . Queue ( queueName ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
JMSConsumer consumer = c t x . createConsumer ( q ) ;

13
14
15
16
17
18
19
20
21

T e x t L i s t e n e r t e x t L i s t e n e r=new T e x t L i s t e n e r ( ) ;
consumer . s e t M e s s a g e L i s t e n e r ( t e x t L i s t e n e r ) ;
t e x t L i s t e n e r . run ( ) ;
ctx . c l o s e ( ) ;

23
24
25
26

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

27
28
29
30
31

32
33

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

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

import
import
import
import

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

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

121

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

24
25
26
27
28
29

30
31

CAPITOLUL 5. MESAJE IN JAVA

5.3.4

Publicarea mesajelor

Publicarea mesajelor corespunzatoare unui subiect se face asemanator cu


transmiterea mesajelor n comunicatia punctuala, dar folosind instante ale
claselor dedicate acestui tip de comunicatie.
Exemplul 5.3.5
1
2
3
5
6
7

import j a v a x . jms . Topic ;


import j a v a x . jms . JMSContext ;
import j a v a x . jms . JMSProducer ;
public c l a s s MsgPublisherT extends Thread {
int n ;
String subiect ;
MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) {
super ( ) ;
t h i s . n=n ;
t h i s . s u b i e c t=s u b i e c t ;
}

9
10
11
12
13

public void run ( ) {


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

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

5.3. ELEMENTE DE PROGRAMARE - JMS-2

5.3.5

123

Abonare si receptia mesajelor

Daca t este obiectul de tip Topic, clientii se aboneaza - subscriu - unui


subiect prin
JMSConsumer consumer = ctx.createConsumer(t);
Subscrierea este valabila atata timp cat clientul este activ. Pentru a primi
toate mesajele specifice subiectului, chiar si cand clientul este inactiv, acesta
trebuie sa fie durabil, adica crearea consumatorului sa se faca prin
ctx.setClientID(clientID);
JMSConsumer consumer = ctx.createDurableConsumer(t,clientName);
In ambele cazuri, clientul primeste doar mesajele publicate din momentul subscrierii.
Exemplul 5.3.6
1
2
3
4
5
7
8
9
10
12
13
14
15
16
18
19
20
21
22
23
24
25
26
27
29
30
31
32
33
34

import
import
import
import
import

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

public c l a s s MsgSubscriberT extends Thread {


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

124

CAPITOLUL 5. MESAJE IN JAVA

else
break ;

35
36

}
ctx . c l o s e ( ) ;

37
38

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

39
40
41
42
43

44
45

Apelarea celor doua activitati se face prin


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

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

5.3.6

Cazul abonatului partajat

Mai multi client JMS folosesc aceasi conexiune iar abonamentul se identifica
printr-un nume (String). Dintre acesi clienti doar unul receptioneaza mesajele
care sunt emise dupa momentul abonarii.
Exemplul 5.3.8
Fata de exemplul anterior se vor expedia mai multe mesaje de tip Message.
1
2
3
5
6
7

import j a v a x . jms . Topic ;


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

5.3. ELEMENTE DE PROGRAMARE - JMS-2

MsgPublisherT ( S t r i n g s u b i e c t , i n t n ) {
super ( ) ;
t h i s . n=n ;
t h i s . s u b i e c t=s u b i e c t ;
}

9
10
11
12
13

public void run ( ) {


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

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

125

Pentru a folosi aceasi conexiune receptia mesajelor este programata n doua


clase :
Se instantiaza o fabrica de conexiuni si un numar de clienti care vor
utiliza aceasi conexiune. Fiecare client este un fir de executie care este
gestionat de o cuva (pool ) de fire de executie.
1
2
3
4
5
6
7
9
10
11
12
13
15
16
17
18
19
20
22
23

import
import
import
import
import
import
import

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

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

126

CAPITOLUL 5. MESAJE IN JAVA

try {
c f=new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;

25
26
27
28

f o r ( i n t i =0; i <noAbonati ; i ++){


S t r i n g c l i e n t N a m e= C l i e n t +i ;
MsgSubscriberT t=new MsgSubscriberT ( c f , s u b i e c t ,
sharedSubscriptionName , clientName ) ;
exec . execute ( t ) ;
}
e x e c . shutdownNow ( ) ;

30
31
32
33
34
35
36

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

37
38
39

}
System . out . p r i n t l n ( R e c e i v e r s f i n i s h e d ) ;

41
42

43
44

Clientii JMS propriu-zisi


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

import
import
import
import
import

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

public c l a s s MsgSubscriberT extends Thread {


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

5.3. ELEMENTE DE PROGRAMARE - JMS-2

}
else
break ;

35
36
37

}
ctx . c l o s e ( ) ;

38
39

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

40
41
42
43
44

45
46

127

Aplicatia este condusa de clasa


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

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

5.3.7

Obiecte administrator prin JNDI

Obiectele administrator, fabrica de conexiuni si obiectul destinatie, se precizeaza ntr-un fisier de proprietati - jndi.properties.
Pentru Open Message Queue acest fisier este
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

# 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

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

128

CAPITOLUL 5. MESAJE IN JAVA

In acest caz este nevoie de crearea n prealabil a obiectelor corespunzatoare


conexiunii, a cozii (queue) si a subiectului (topic). Aceaste obiecte se creaza
cu utilitarul imqobjmgr din distributia Oracle-Open Message Queue.
Obiectele se pot crea cu fisierul de comenzi:
1
2
3
4
5
6
7
8
9
10
11
12
13

s e t PATH=d : \mq\ b i n ;%PATH%


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

. RefFSContextFactory

. RefFSContextFactory

. RefFSContextFactory

. RefFSContextFactory

Obiectele se pot sterge cu fisierul de comenzi:


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

s e t PATH=d : \mq\ b i n ;%PATH%


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

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

f s c o n t e x t . RefFSContextFactory

Reluam aplicatiile anterioare privind transmiterea / receptia unui mesaj


prin comunicatie punctuala utilizand o coada si publicarea si receptionarea
unui mesaj prin comunicatie bazata pe subiect ntr-o varianta independententa
de suportul middleware de serviciu de mesagerie folosit. Regasirea resurselor
gestionate de serviciul de mesagerie se va face utilizand JNDI.

5.3.8

Comunicatia prin coad


a - queue

Aplicatia este alcatuita din clasele MsgHelloT, MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT, TextListener. Fata de versiunea prezentata anterior se modifica doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT.
In clasa MsgHelloT campul queueName reprezinta numele JNDI al cozii.
Clasa MsgSenderT
1
2

import j a v a x . jms . QueueConnectionFactory ;


import j a v a x . jms . Queue ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

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

import
import
import
import
import
import

129

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

public c l a s s MsgSenderT extends Thread {


f i n a l S t r i n g CONNECTION JNDI NAME = C o n n e c t i o n F a c t o r y ;
S t r i n g QUEUE JNDI NAME = queue ;
private I n i t i a l C o n t e x t c t x ;
private i n t n ;
MsgSenderT ( S t r i n g queueName , i n t n ) {
QUEUE JNDI NAME=queueName ;
t h i s . n=n ;
}
public void run ( ) {
try {
setupJNDI ( ) ;
QueueConnectionFactory c f=
( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ;
Queue q=(Queue ) c t x . l o o k u p (QUEUE JNDI NAME ) ;
closeJNDI ( ) ;
JMSContext j m s c t x=c f . c r e a t e C o n t e x t ( ) ;
JMSProducer p r o d u c e r=j m s c t x . c r e a t e P r o d u c e r ( ) ;
f o r ( i n t i =0; i <n ; i ++){
p r o d u c e r . send ( q , H e l l o +i ) ;
}
p r o d u c e r . send ( q , j m s c t x . c r e a t e M e s s a g e ( ) ) ;
jmsctx . c l o s e ( ) ;

29
30
31
32
33
34
35

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

36
37
38
39
40
41

43

private void setupJNDI ( ) {


P r o p e r t i e s p r o p e r t i e s = new P r o p e r t i e s ( ) ;
try {
p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream ( j n d i . p r o p e r t i e s ) ) ;
}
catch ( IOException e ) {
System . out . p r i n t l n ( 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 ( ) ) ;
}
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 ) ;
}
}

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

private void c l o s e J N D I ( ) {
try {
ctx . c l o s e ( ) ;

130

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

62
63
64
65

66
67

CAPITOLUL 5. MESAJE IN JAVA

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

import
import
import
import
import
import
import
import
import
import

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

public c l a s s SyncMsgReceiverT extends Thread {


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

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

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

41
42
43
44
45
46

48

private void setupJNDI ( ) { . . . }

50

private void c l o s e J N D I ( ) { . . . }

5.3. ELEMENTE DE PROGRAMARE - JMS-2

51

131

5.3.9

Comunicatia pe baz
a de subiect - topic

Aplicatia este alcatuita din clasele MsgPS, MsgPublisherT, MsgSubscriberT. Fata de versiunea prezentata anterior se modifica doar clasele MsgPublisherT si MsgSubscriberT.
In clasa MsgPS campul subiect reprezinta numele JNDI atasat topic-ului.
Clasa MsgPublisherT
1
2
3
4
5
6
7
8
10
11
12
13
14
16
17
18
19
21
22
23
24
25
26
27

import
import
import
import
import
import
import
import

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

public c l a s s MsgPublisherT extends Thread {


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

29
30
31
32
33
34
35

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

36
37
38
39
40
41

43

private void setupJNDI ( ) { . . . }

45

private void c l o s e J N D I ( ) { . . . }

132

46

CAPITOLUL 5. MESAJE IN JAVA

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

import
import
import
import
import
import
import
import
import
import

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

public c l a s s MsgSubscriberT extends Thread {


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

36
37
38
39
40
41
42
43
44
45

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

46
47
48
49
50
51

53

private void setupJNDI ( ) { . . . }

55

private void c l o s e J N D I ( ) { . . . }

5.3. ELEMENTE DE PROGRAMARE - JMS-2

56

133

5.3.10

Utilizarea mesajelor de tip StreamMessage

Fisiere grafice (jpg, png), audio (mp3), video pot fi procesate prin mesaje
de tip StreamMessage
Exemplul 5.3.9 Aplicatie JMS cu clasa pentru publicarea si consumarea unui
mesaj care incorporeaza o imagine jpg.
Clasa MsgPublisherT
1
2
3
4
5
6
7
8
9
11
12
14
15
16
18
19
20
21
22
23
24
25
27
28
29
30
31
32
33
34
36
37

import
import
import
import
import
import
import
import
import

j a v a x . jms . Topic ;
j a v a x . jms . JMSContext ;
j a v a x . jms . StreamMessage ;
j a v a x . jms . BytesMessage ;
j a v a x . jms . JMSProducer ;
java . io . F i l e ;
j a v a . i o . ByteArrayOutputStream ;
j a v a . awt . image . B u f f e r e d I m a g e ;
j a v a x . i m a g e i o . ImageIO ;

public c l a s s MsgPublisherT extends Thread {


String subiect ;
MsgPublisherT ( S t r i n g s u b i e c t ) {
t h i s . s u b i e c t=s u b i e c t ;
}
public void run ( ) {
try {
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f=
new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
F i l e f i l e = new F i l e ( myimage . j p g ) ;
B u f f e r e d I m a g e img = ImageIO . r e a d ( f i l e ) ;
ByteArrayOutputStream baos=new ByteArrayOutputStream ( ) ;
ImageIO . w r i t e ( img , j p g , baos ) ;
baos . f l u s h ( ) ;
byte [ ] b y t e s=baos . toByteArray ( ) ;
System . out . p r i n t l n ( b y t e s . l e n g t h ) ;
baos . c l o s e ( ) ;
StreamMessage msg=c t x . c r e a t e S t r e a m M e s s a g e ( ) ;
msg . w r i t e B y t e s ( b y t e s ) ;

40

JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ;
p r o d u c e r . send ( t , msg ) ;

42

ctx . c l o s e ( ) ;

39

134

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

43
44
45
46
47

48
49

CAPITOLUL 5. MESAJE IN JAVA

Clasa MsgSubscriberT
1
2
3
4
5
6
7
8
9
10
12
13
14
15
17
18
19
20
21
23
24
25
26
27
28
29
30
31
32

import
import
import
import
import
import
import
import
import
import

public c l a s s MsgSubscriberT extends Thread {


String subiect ;
String clientID ;
S t r i n g clientName ;
MsgSubscriberT ( S t r i n g s u b i e c t , S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) {
t h i s . s u b i e c t=s u b i e c t ;
t h i s . c l i e n t I D=c l i e n t I D ;
t h i s . c l i e n t N a m e=c l i e n t N a m e ;
}
public void run ( ) {
try {
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f=
new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
ctx . setClientID ( c l i e n t I D ) ;
JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ;
Message msg=n u l l ;
while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
i f ( msg instanceof StreamMessage ) {
StreamMessage m=(StreamMessage ) msg ;
m. r e s e t ( ) ;
byte [ ] b y t e s =(byte [ ] ) m. r e a d O b j e c t ( ) ;
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 : +b y t e s . l e n g t h ) ;
InputStream i n = new ByteArrayInputStream ( b y t e s ) ;
B u f f e r e d I m a g e b i = ImageIO . r e a d ( i n ) ;
ShowImage showImage=new ShowImage ( b i ) ;
showImage . show ( ) ;
break ;
}
}
ctx . c l o s e ( ) ;

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

j a v a x . jms . Message ;
j a v a x . jms . Topic ;
j a v a x . jms . JMSContext ;
j a v a x . jms . JMSConsumer ;
j a v a x . jms . StreamMessage ;
j a v a x . jms . BytesMessage ;
j a v a . awt . image . B u f f e r e d I m a g e ;
j a v a x . i m a g e i o . ImageIO ;
j a v a . i o . ByteArrayInputStream ;
j a v a . i o . InputStream ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

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

50
51
52
53

54
55

Clasa ShowImage afiseaza imaginea pe monitor.


1
2
3
4
5
7
8

import
import
import
import
import

j a v a . awt . Canvas ;
j a v a . awt . Image ;
j a v a . awt . G r a p h i c s ;
j a v a . awt . BorderLayout ;
j a v a x . swing . JFrame ;

c l a s s MyCanvas extends Canvas {


Image image=n u l l ;
MyCanvas ( Image image ) {
t h i s . image=image ;
}

10
11
12

public void p a i n t ( G r a p h i c s g ) {
g . drawImage ( image , 0 , 0 , t h i s ) ;
}

14
15
16
17

19

public c l a s s ShowImage{
MyCanvas mc=n u l l ;

20

ShowImage ( Image image ) {


mc=new MyCanvas ( image ) ;
}

22
23
24

public void show ( ) {


// I n t e r f a t a s w i n g
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 ( j f r a m e . EXIT ON CLOSE ) ;
jframe . s e t S i z e (600 ,600);
j f r a m e . s e t V i s i b l e ( true ) ;
}

26
27
28
29
30
31
32
33
34
35
36

Producatorul si consumatorului se lanseaza din


1
2
3
4
5
6
7
8
10
11

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= s t r e a m i n g ;
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 ] ;
MsgSubscriberT abonat=new MsgSubscriberT ( s u b i e c t , myID , myName ) ;
MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t ) ;
abonat . s t a r t ( ) ;
try {
Thread . s l e e p ( 1 0 0 0 ) ;

135

136
}
catch ( I n t e r r u p t e d E x c e p t i o n e ) { }

12
13

publisher . start ( ) ;

15

16
17

CAPITOLUL 5. MESAJE IN JAVA

5.3.11

Aplicatie JMS slab cuplat


a

Posibilitatea de a crea obiecte destinatie n mod dinamic permite realizarea


unei aplicatii n care clientul declara n momentul lansarii unei solicitari destinatia
obiectului n care doreste sa primeasca rsspunsul. Clientul va prelua raspunsul
ntr-un moment ulterior.
O asemenea aplicatie este denumita aplicatie slab cuplata.
Aplicatia va fi alcatuita din trei clienti:
Client care preia si rezolva cererile iar raspunsurile sunt trimise solicitantului ntr-un mesaj pe un subiect indicat de acesta. Acest client preia
mesajele corespunzatoare unui subiect public.
Client care lanseaza cererea. Acest client va crea un abonat durabil pe
subiectul pe care se va prelua raspunsul. Subiectul face parte din cerere.
Client care preia raspunsul.
Exemplul 5.3.10 Calculul celui mai mare divizor comun a doua numere naturale.
Clasa MsgCmmdcServer

import
import
import
import
import
import

public c l a s s

1
2
3
4
5

10
11
12
13
15
16
17
18
19

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

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ;
server . service ();
}
private void s e r v i c e ( ) {
try {
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f=
new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
JMSConsumer consumer = c t x . c r e a t e S h a r e d C o n s u m e r ( t , Cmmdc ) ;
JMSProducer p r o d u c e r = c t x . c r e a t e P r o d u c e r ( ) ;
while ( true ) {
Message msg=n u l l ;
while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
i f ( msg instanceof TextMessage ) {
TextMessage tm=(TextMessage ) msg ;
S t r i n g s=tm . g e t T e x t ( ) ;
S t r i n g [ ] s s=s . s p l i t ( ) ;
long m=Long . par se Lon g ( s s [ 0 ] ) ;
long n=Long . p ars eL ong ( s s [ 1 ] ) ;
S t r i n g t o p i c=s s [ 2 ] ;
long c=cmmdc(m, n ) ;
Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c ) ;
p r o d u c e r . send ( t1 , ( new Long ( c ) ) . t o S t r i n g ( ) ) ;
System . out . p r i n t l n ( S e r v e r s e n t +c+ t o +t o p i c ) ;
}
}
}

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

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

43
44
45
46

47

private long cmmdc( long m, long n ) { . . . }

49
50

Clasa MsgClientSender
1
2
3
4
5
7
8

import
import
import
import
import

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

public c l a s s
MsgClientSender {
private S t r i n g msg , c l i e n t I D , clientName , t o p i c R e s u l t ;

23

MsgClientSender ( S t r i n g c l i e n t I D , S t r i n g clientName ){
t h i s . c l i e n t I D=c l i e n t I D ;
t h i s . c l i e n t N a m e=c l i e n t N a m e ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( I n t r o d u c e t i m : ) ;
long m=s c a n n e r . nextLong ( ) ;
S t r i n g sm=new Long (m) . t o S t r i n g ( ) ;
System . out . p r i n t l n ( I n t r o d u c e t i n : ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ;
System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ;
t o p i c R e s u l t=s c a n n e r . n e x t ( ) ;
msg=sm+ +sn+ +t o p i c R e s u l t ;
}

25

private void s e r v i c e ( ) {

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

137

138

CAPITOLUL 5. MESAJE IN JAVA

try {
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f=
new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;

26
27
28
29
30
31
32

Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ;


ctx . setClientID ( c l i e n t I D ) ;
JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t1 , c l i e n t N a m e ) ;
JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ;
p r o d u c e r . send ( t , msg ) ;
ctx . c l o s e ( ) ;

34
35
36
37
38
39

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

40
41
42
43
44

46

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


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

47
48
49
50
51
52
53
54
55

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

import
import
import
import
import
import

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

public c l a s s
MsgClientReceiver {
private S t r i n g t o p i c R e s u l t , c l i e n t I D , c l i e n t N a m e ;
MsgClientReceiver ( S t r i n g c l i e n t I D , S t r i n g clientName ){
t h i s . c l i e n t I D=c l i e n t I D ;
t h i s . c l i e n t N a m e=c l i e n t N a m e ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( I n t r o d u c e t i Topic u l r a s p u n s u l u i ) ;
t o p i c R e s u l t=s c a n n e r . n e x t ( ) ;
}
public void s e r v i c e ( ) {
try {
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f=
new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( t o p i c R e s u l t ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;

5.3. ELEMENTE DE PROGRAMARE - JMS-2

ctx . setClientID ( c l i e n t I D ) ;
JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ;
Message msg=n u l l ;
while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
i f ( msg instanceof TextMessage ) {
TextMessage m=(TextMessage ) msg ;
System . out . p r i n t l n ( Cmmdc : +m. g e t T e x t ( ) ) ;
break ;
}
}
ctx . c l o s e ( ) ;

27
28
29
30
31
32
33
34
35
36
37

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

38
39
40
41
42

44

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


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

45
46
47
48
49
50
51
52
53

5.3.12

Programare JMS prin glassfish

Diferenta fata de versiunile amintite mai sus constau n


obiectele administrator,
fabrica de conexiuni,
obiectul / sursa destinatie
care se creaza de administratorul glassfish.
1. Se lanseaz
a serverul de aplicatii glassfish
set GLASSFISH_HOME=. . .\glassfish*
set PATH=%GLASSFISH_HOME%\bin;%PATH%
asadmin start-domain domain1
Lansarea serverului de aplicatie implic
a pornirea serverului JMS.
2. Dintr-un navigator se apeleaz
a administratorul http://localhost:4848.
3.

Resources JMS Resources Destination Resources


Se creaz
a c
ate un obiect destinatie cu datele:
JNDI Name
myQueue
myTopic
Physical Name myQueue
myTopic
Resource Type javax.jms.Queue
javax.jms.Topic

139

140

CAPITOLUL 5. MESAJE IN JAVA

Resources JMS Resources Connection Factories


Se creaz
a c
ate o fabric
a de conexiuni cu datele:
JNDI Name
myQueueConnectionFactory, respectiv
myTopicConnectionFactory
Resource Type javax.jms.QueueConnectionFactory, respectiv
javax.jms.TopicConnectionFactory

Aceste obiecte se injecteaza ntr-o clasa utiliznd adnotarea javax.annotation.


Resource
import javax.annotation.Resource;
. . .
public class . . .
@Resource(lookup="myQueueConnectionFactory")
private static QueueConnectionFactory cf;
@Resource(lookup="myQueue")
private static Queue q;
O aplicatie se arhiveaza cu jar cu indicarea clasei cu metoda main si
se lanseaza prin intermediul procedurii acoperitoare glassfish\bin\
appclient.bat
appclient -client numeArhiva.jar

[-targetserver host:3700]

Exemplul 5.3.11 Aplicatie cu comunicatie punctuala.


Clasa expeditorului
1
2
3
4
5
7
8
9
10
11
12
14
15
16
17
18
19
20
21
22

import
import
import
import
import

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

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

5.3. ELEMENTE DE PROGRAMARE - JMS-2

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

23
24
25
26
27
28

29
30

Clasa unui client sincron


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

import
import
import
import
import
import
import

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

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

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

Intreb
ari recapitulative
1. Explicati caracterul de cuplare slaba al unei aplicatii bazat pe JMS.
2. Care este rolul furnizorului (provider) JMS?
3. Precizati si explicati modelele de comunicatii cu mesaje n JMS.

141

142

CAPITOLUL 5. MESAJE IN JAVA

4. Precizati modelele de programare al unui client JMS prezentate n curs.

Partea II
TEHNOLOGII CU
COMUNICAT
II PRIN
INTERNET

143

Capitolul 6
HyperText Transfer Protocol
Protocolul http- HyperText Transfer Protocol (http) este destinat schimburilor de informatii n Internet.
Protocolul http a ajuns la versiunea 2 (HTTP/2), versiunea anterioara fiind 1.1 (HTTP/1.1). Scopul lui HTTP/2 este reducerea latentei prin utilizarea
mai eficienta a retelei. Diferenta dintre HTTP/2 si HTTP/1.1 este la nivelul
de transport, adica a modului n care bitii sunt schimbati prin retea. HTTP/2
pastreaza structura mesajului din HTTP/1.1.
In vederea schimburilor dintre calculatoare prin Internet, reprezentarea
datelor se face utilizand n principal:
eXtensible Markup Language (XML) - subset al limbajului Standard
Generalized Markup Language (SGML);
JavaScript Object Notation (JSON).
HyperText Markup Language (HTML), XHTML, HTML 5 sunt principalele
limbaje pentru publicarea informatiilor pe Web. Aceste limbaje deriva de
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 gazduite / generate de servere Web de catre site-uri
si servicii Web. Exemple de servere Web sunt apache HTTP Server,
145

146

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Microsoft Internet Interchange Server. O categorie aparte - esentiala


pentru platforma Java - este data de servere Web container de servlet si
Java Server Pages (JSP).
Transmiterea unui mesaj (cerere) conform protocolului http 1.1 consta din
1. Cautare DNS: Clientul ncearca sa determine adresa IP a serverului Web:
(a) Se lanseaza o cerere DNS catre serverul DNS al furnizorului de
servicii Internet;
(b) Serverul DNS raspunde cu adresa IP a serverului Web.
2. Stabilirea unei conexiuni catre serverul Web;
3. Expedierea mesajului cerere;
4. Se asteapta raspunsul la cererea emisa;
5. Se receptioneaza si se ncarca mesajul de raspuns;
6. Inchiderea conexiunii.
Acest ciclu de actiuni se numeste tranzactie http. Pasi 3-4-5 se pot repeta.
Un mesaj de tip cerere difera de un mesaj de tip raspuns prin structura unor
elemente constitutive.
Serverul nu retine informatii ntre doua tranzactii http. Acest comportament se exprima prin terminologia: protocolul http este fara stare - stateless.
Transmisia datelor se realizeaza utilizand de obicei protocolul TCP.
Referintele resurselor se indica folosind URI / URL.
Cererile si raspunsurile sunt reprezentate ca linii de text separate de caracterul <CR><LF>, avand structura
1. preambul - format dintr-o linie;
2. antete (header ) - 0 sau mai multe atribute (nume:valoare);
3. o linie goala;
4. corpul mesajului - optional.
Preambulul unei cereri contine:
1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE,
OPTIONS};

6.1. TRANSACT
IE HTTP

147

2. referinta resursei (URL);

3. Versiunea protocolului http.

Preambulul unui r
aspuns contine:

1. Versiunea protocolului http;

2. codul raspunsului: numar natural format din trei cifre cu semnificatiile


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

Indica
mesaj de informare
mesaj de succes
redirectare catre alt URL
eroare in mesajul clientului
eroare din partea serverului

Categoria este data de prima cifra.

3. String explicitand codul raspunsului.

Un antet (header ) este un atribut, adica o pereche (nume:valoare). Protocolul http defineste o paleta larga de atribute. Exemple de antete sunt date
n tabelul urmator:

148

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Antet

Semnificatie
Exemplu
host
Gazda si portul serverului Web
localhost:8080
user-agent
Navigatorul care a lansat cererea
Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/535.2 (KHTML, like Gecko)
Chrome/15.0.874.106 Safari/535.2
referer
URL-ul cererii
http://localhost:8080/apphello/
accept-encoding Tipuri de arhive acceptate
gzip,deflate,sdch
accept-charset Tipuri de codificare acceptate
ISO-8859-1,utf-8;q=0.7,*;q=0.3
accept-language Cea mai potrivita limba pentru ntelegerea
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
Upgrade
Solicitare / Acord schimbare protocol
websocket
Corpul mesajului este reprezentat printr-un text. Daca continutul este
imagine, cod binar, etc., atunci acesta este codificat n text.
Codul Multipurpose Internet Mail Exchange (MIME) precizeaza natura
continutului unei resurse:
text/plain
text/html
text/xml
image/png
image/jpg
application/octet-stream
application/x-www-form-urlencoded
Ne propunem sa punem n evidenta mesajele http.

6.1. TRANSACT
IE HTTP

149

Mesaj cerere http


Dintr-un navigator se va lansa prin intermediul unui document html o
cerere catre un ipotetic servlet dintr-un server Web. Cererea este interceptata
de o clasa Java cu un soclu TCP, ServerSocket, care preia mesajele pe portul
serverului Web.
Codul clasei Java este
1
2
3
4
5
6
7
8
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 utilizata n formularul html folosit.
Pentru metoda GET cererea http este
GET /apphello/hello?name=mk&tip=text%2Fhtml HTTP/1.1
Host: localhost:8080
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/535.2 (KHTML, like Gecko)
Chrome/15.0.874.106 Safari/535.2

150

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

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 r
aspuns http
Un servlet (apphello) este activ ntr-un server Web. O clasa Java lanseaza
o cerere http catre acel servlet - chiar unul din mesajele obtinute mai sus dupa care receptioneaza raspunsul dat de servlet.
Codul clasei Java
1
2
3
4
5

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 ;

6.1. TRANSACT
IE HTTP

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

151

import j a v a . i o . F i l e W r i t e r ;
import j a v a . i o . P r i n t W r i t e r ;
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 /xwwwformu 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

152

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

pw . p r i n t l n ( reqPOST ) ;
}
for ( ; ; ) {
S t r i n g s=br . r e a d L i n e ( ) ;
i f ( s==n u l l ) break ;
System . out . p r i n t l n ( s ) ;
bw . w r i t e ( s ) ;
bw . newLine ( ) ;
bw . f l u s h ( ) ;
}

65
66
67
68
69
70
71
72
73
74

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

75
76
77
78

79
80

Indiferent de metoda cererii, mesajul http de raspuns este


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

6.2

Server Web - container de servlet

In prezent sunt disponibile mai multe servere Web n care poate fi instalat
un servlet si un fisier JSP Java Server Pages. Despre un asemenea server Web
se spune ca este container de servlet si JSP. Dintre produsele gratuite amintim
apache-tomcat
jetty
glassfish
Acest server Web este utilizat n java ee sdk - o implementare JEE (Java
Enterprise Edition) de la Oracle.
apache-tomee este construit peste apache-tomcat si integreaza o serie de
tehnologii JEE

6.3. SERVERUL WEB APACHE-TOMCAT

153

weblogic (Oracle)
jboss application server (RedHat)
Geronimo, o alta implementare JEE dezvoltata de fundatia apache, poate
utiliza containerul apache-tomcat sau jetty.
Serverul Apache HTTP Server si Windows Internet Information Server nu
sunt servere Web containere de servlet si JSP.

6.3

Serverul Web apache-tomcat

Serverul Web apache-tomcat, (pe scurt tomcat) este distribuit gratuit si


poate fi descarcat pornind de la adresa www.apache.org.
Instalarea serverului n mediul Windows revine la dezarhivarea fisierului
descarcat apache-tomcat-***, ntr-un catalog TOMCAT HOME. Utilizarea serverului necesita fixarea a doi parametri sistem:
CATALINA HOME= calea la catalogul n care s-a instalat produsul - TOMCAT HOME;
JAVA HOME=calea la distributia Java utilizata.
Pachetul contine cataloagele1 : bin, common, conf, logs, server, shared,
temp, webapps, work.
Serverul se lanseaza prin comanda
TOMCAT HOME\bin\startup
si se opreste cu comanda
TOMCAT HOME\bin\shutdown
Din catalogul TOMCAT HOME, lansarea se poate obtine cu ajutorul fisierului
de comenzi (*.bat)
set CATALINA_HOME=. . .
set JAVA_HOME=. . .
bin\startup
Optional se poate instala / activa managerul / administatorul serverului Web
tomcat.
Verificarea functionarii serverului Web tomcat se face apeland dintr-un navigator pagina http://host:port unde
1

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

154

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

host este numele calculatorului pe care ruleaza tomcat;


Portul implicit este 8080.
Reusita este ilustrata de imaginea motanului

Toate aplicatiile se depun n catalogul TOMCAT HOME\webapps.


Asemanator se procedeaza si n cazul serverului Web jetty. Nu este nevoie
de nici o configurare suplimentara, lansarea facandu-se prin
cd . . .\jetty-distribution-*
java -jar start.jar
Din nou aplicatiile se depun n catalogul \jetty-distribution-*\webapps.

Secure Socket Layer n tomcat


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

Parametrul keystore fixeaza locatia si denumirea fisierului certificatului


de securitate.
Se definesc doua parole
keypass parola certificatului de securitate;
storepass parola de protectie a locatiei certificatului de securitate.
Parametrul cale desemneaza calea catre catalogul unde n care se creaza
fisierul tomcatKeystore - certificatul de securitate. Uzual, certificatul de
securitate se muta n catalogul TOMCAT HOME\conf.

155

6.4. GLASSFISH

2. Modificarea fisierului apache-tomcat-*\conf\server.xml


Se decomenteaza elementul
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />

Acest element Connector se completeaza cu atributele


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

3. Serverul Web se apeleaza prin


https://localhost:8443

6.4

Glassfish

Instalarea si lansarea serverului. Instalarea consta din dezarhivarea


arhivei descarcate.
Este recomandat includerea n fisierul GLASSFISH HOME\grassfish\config\
asenv.bat a liniei
set AS_JAVA=c:\Progra~1\Java\jdk1.*
Utilizarea paginilor JSP necesita aceasta setare.
Prin intermediul paginii de administrare se poate schimba parola administratorului (admin).
Containerele n care se depun aplicatiile se afla ntr-un domeniu. Implicit,
n catalogul glassfish\domain se creaza domeniul cu numele domain1:
GLASSFISH HOME\glassfish\domains\domain1.
Lansarea serverului se poate face prin:
Din GLASSFISH HOME\glassfish\bin se comanda
asadmin start-domain domain1
Oprirea serverului se poate face prin:
asadmin stop-domain domain1
Administrarea serverului se face prin
pagina Web http://localhost:4848

156

CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

utilitarul GLASSFISH HOME\bin\asadmin.bat


Administratorul serverului are posibilitatea sa creeze domenii noi: Astfel crearea
unui domeniu nou, avand numele numeDomeniu, situat n catalogul dirDomeniu se obtine prin
asadmin create-domain --adminport 4848 --domaindir dirDomeniu numeDomeniu
Stergerea domeniului se obtine prin
asadmin delete-domain --domaindir dirDomeniu numeDomeniu
Lansarea si oprirea serverului glassfish se comanda prin
asadmin start-domain --domaindir dirDomeniu numeDomeniu
asadmin stop-domain --domaindir dirDomeniu numeDomeniu

Capitolul 7
Conexiune simpl
a prin clase din
java.net
Pachetul java.net ofera, prin intermediul claselor URL, URLConnection,
HttpURLConnection, HttpsURLConnection, JarURLConnection o posibilitate elementara de acces a unor resurse din Internet.

7.1

Clasa java.net.URL

Clasa java.net.URL permite realizarea unei conexiuni cu un server Web1


potrivit protocolurilor http, https, ftp, file, jar.
Constructori
URL(String spec) throws MalformedURLException
Creaza un obiect URL legat de resursa specificata de spec, care trebuie sa
fie o referinta URL valida.
Metode
InputStream openStream() throws IOException
Returneaza fluxul de intrare pentru citirea resursei.
URLConnection openConnection() throws IOException
Returneaza o instanta a conexiunii cu obiectul definit de URL.
1

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

157

158

PRIN CLASE DIN JAVA.NET


CAPITOLUL 7. CONEXIUNE SIMPLA

Exemplul 7.1.1 Pe baza referintei catre un fisier html dintr-un catalog vizibil
al unui server Web, sa se afiseze continutul fisierului.
In codul reprodus mai jos, fisierul Hello.html se afla pe serverul apachetomcat, n catalogul webapps\url.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

import
import
import
import

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

public c l a s s ReadHTTP{
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 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 . p r o x y H o s t , 1 0 . 3 . 5 . 1 3 3 ) ;
// System . s e t P r o p e r t y ( h t t p . p r o x y P o r t , 3 1 2 8 ) ;
URL u r l=n u l l ;
try {
u r l=new URL( adr ) ;
}
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 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 ) ;
}
while ( s != 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 ( ) ) ;
}
}
}

In cazul n care resursa - n exemplul dat reprezentat de fisierul Hello.html


- este accesibil doar n urma autentificarii basic sau digest (Cap. Servlet,
Autentificare, 8.5.6) atunci codul de mai sus trebuie completat cu
final String username = "digest";
final String password = "digest";
Authenticator.setDefault(new Authenticator(){
@Override
protected PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(username,password.toCharArray());
}
});

Un exemplu privind utilizarea clasei java.net.HttpURLConnection este


dat n capitolul Servlet.

Capitolul 8
Servlet
Printre aplicatiile distribuite de tip client-server, n care comunicatiile se
bazeaza pe protocolul http, se disting:
Aplicatii Web (site): Cererea adresata serverului este lansata uzual de
o persoana utilizand un program navigator: Google Chrome, Mozilla
Firefox, Microsoft InternetExplorer, Opera, Apple Safari, etc.
Servicii Web: Cererea catre server se face de un program. Aplicatia
server si client se programeaza utilizand interfete de programare specifice.
Componenta server a unei aplicatii Web
contine o clasa Java care se excuta de un server Web, compatibil;
este gestionata de serverul Web;
este capabila sa receptioneze si sa rapunda cererilor formulate de clienti.
Structura minimala a unei aplicatii Web este
catalogAplicatiei
|--> WEB-INF
|
|--> classes
|
|
|
*.class
|
|--> lib
|
|
|
*.jar
|
index.html
159

160

CAPITOLUL 8. SERVLET

Catalogul classes contine fisierele class ale aplicatiei Web.


Catalogul lib este optional si va contine resursele jar suplimentare cerute
de clasele aplicatiei Web.
Prin intermediul fisierului index.html se apeleaza aplicatia Web. Acest
fisier este totodata si client Web. Adresa de apelare (URL - Universal Resource
Locator ) a aplicatiei servlet este

http://host:port/catalogAplicatieiWeb
Daca n loc de index fisierul html de apelare are alt nume, de exemplu xyz.html
atunci adresa de apelare va fi

http://host:port/catalogAplicatieiWeb/xyz.html
host este numele calculatorului pe care ruleaza serverul Web - gazda aplicatiei
Web. Portul implicit utilizat de un server Web container de servlet este 8080.
Catalogul aplicatiei este denumit context-ul aplicatiei Web.
Programarea si utilizarea unei aplicatii Web necesita:
Cunoasterea elementului (marcaj, tag) html <form> pentru realizarea
formularelor de introducere a datelor;
Utilizarea unui server Web, container de servleti. Dintre produsele gratuite amintim: apache-tomcat, jetty, glassfish.

8.1

Marcajul <form>

Intr-un document html introducerea datelor se poate obtine utilizand marcajul <form> ...</form> .
Atribute ale marcajului <form> . Reamintim ca atributele se prezinta
ca perechi (nume, valoare) si se scriu n antetul marcajului sub forma nume =
valoare.

161

8.1. MARCAJUL <FORM>

Nume
action

Valoare
adresa tip URL

method

GET

POST

id
name
onSubmit

Semnificatia valorii
Resursa care prelucreaza formularul, cel putin
/context/numeApel
Mesajul trimis serverului Web contine dupa
adresa URL numele si valorile parametrilor
introdusi. Adaugarea se face potrivit sintaxei
?numeParam1=valoare&numeParam2=valoare. . .
Lungimea mesajului nu poate depasi 255 caractere.
Transmisia datelor se face n fluxuri de date.
Permite transferul unor fisiere de pe masina
clientului pe masina serverului.
Parametru de identificare a formularului (optional).
Nume atribuit formularului (optional).
Metoda JavaScript executata naintea apelarii
serverului Web (optional).

In continutul marcajului <form> putem include elemente de control


prin marcajele
<input>
<option>
<select>
<textarea>
Atributele marcajului < input> sunt:
Nume
type

Valoare
Semnificatie
text
Se asteapta introducerea unui text
number
Se asteapta introducerea unui numar ntreg
date
Se asteapta introducerea unei date calendaristice
password
Se asteapta introducerea unei parole
submit
Se marcheaza sfarsitul completarii formularului
reset
Se reinitializeaza formularul
file
Permite selectarea unui fisier
hidden
Transmite mai departe un atribut fara vizualizarea lui
name
numele controlului
value
valoarea (initiala) a controlului
size
numarul caracterelor atasat controlului

162

CAPITOLUL 8. SERVLET

In cazul marcajului < select> utilizarea este


<select name="nume">
<option value="valoare"> Valoare
. . . . . . . . . . . . . . . .
</select>
Valoarea atributului nume este data de valoarea selectata.

8.2

Realizarea unui servlet

Pe platforma de programare Java, servlet-ul este componenta care sta la


baza majoritatii cadrelor de dezvoltare (framework ) pentru aplicatii si servicii
Web.1
Termenul servlet se utilizeaza atat pentru aplicatie cat si pentru clasa gestionata de serverul Web.
Interfata de programare (API) pentru servlet nu face parte din JDK, fiind
implementat de fiecare producator de server Web container de servlet.
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.
Plasand fisierul de apelare al aplicatiei servlet ntr-un server Web (apachehttpd, Microsoft-IIS) si aplicatia servlet ntr-un servlet Web compatibil, servletul se va apela prin
http://host/. . . /xyz.html
iar clasa servlet se va apela din xyz.html.
Prin Asynchronous JavaScript And Xml - AJAX un servlet se poate apela
dintr-o functie Javascript.
Legatura cu clasa servlet-ului se poate realiza
1

vert.x, Play sunt cadre de lucru care dezvolta n Java aplicatii distribuite fara sa se
bazeze pe servlet.

8.2. REALIZAREA UNUI SERVLET

163

programat prin adnotari n codul servlet-ului;


descriptiv n catalogul WEB-INF se editeaza fisierul web.xml.
In versiunile anterioare ale interfetei de programare servlet aceasta a fost
unica optiune.
Trebuie demarcata diferenta dintre apelarea / lansarea n executie a clasei
servlet de apelarea aplicatiei Web.
Modul programat se bazeaza pe adnotarea javax.servlet.annotation.
WebServlet cu elementele:
String
name
String[ ]
urlPatterns
@WebInitParams[ ] initParams
boolean
asyncSupported
long
asyncTimeout

Modul descriptiv In fisierul web.xml apar elementele


1. <servlet> leaga numele servlet-ului definit n elementul <servlet-name>
de clasa servlet-ului dat n elementul <servlet-class> .
2. <servlet-mapping> defineste numele sub care servlet-ul identificat prin
<servlet-name>nume servlet< /servlet-name> se invoca din programul navigator. Acest identificator - numeApel - se fixeaza n elementul
<url-pattern> . Identificatorul are ca prefix caracterul / (slash).
Structura unui fisier web.xml este
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e
x m l n s : x s i= h t t p : //www. w3 . o r g /2001/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>

164

CAPITOLUL 8. SERVLET

Unui element <servlet> i pot corespunde mai multe elemente <servlet-mapping>,


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 fisierelor html sau jsp care apeleaza aplicatia Web. Declaratia
fisierului index.html este implicita.
Compilarea clasei servlet necesita completarea variabilei de mediu classpath
cu fisierul TOMCAT HOME\lib\servlet-api.jar.
Odata completata structura de cataloage si fisiere ale aplicatiei servlet
aceasta structura trebuie copiata n catalogul TOMCAT HOME\webapps. Aceasta
operatie se numeste desf
asurarea (deployment) sau instalarea servlet-ului.
Copierea se poate executa si cu serverul Web pornit.
Pentru instalarea unui servlet exista mai multe alternative:
Din catalogul catalogAppServlet se realizeaza arhiva catalogAppServlet.war
jar cfv catAppServlet.war WEB-INF\ index.html
care se copiaza n catalogul TOMCAT HOME\webapps.
Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este instalat.
Aceasta instalare se numeste instalare dinamica - hot deployment.
Daca fisierul war este creat, atunci n locul copierii, instalarea se poate
face prin componenta manager a lui tomcat.
O aplicatie servlet arhivata war se poate instala de la distata prin produsele:
apache-tomcat-deployer
cargo

8.2.1

Codul unui servlet

Un servlet implementeaza interfata Servlet sau extinde una din clasele


GenericServlet sau HttpServlet. GenericServlet implementeaza interfata
Servlet, iar HttpServlet extinde clasa GenericServlet. Extinzand clasa

8.2. REALIZAREA UNUI SERVLET

165

GenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte ale


interfetei Servlet.
Metodele interfetei Servlet sunt:
abstract public void init(ServletConfig config)
Se apeleaza o singura data la lansarea servlet-ului.
abstract public void service(ServletRequest req, ServletResponse
res)throws ServletException,IOException
Metoda este apelata de serverul Web pentru rezolvarea cererii unui client.
abstract public void destroy()
Se apeleaza o singura data la distrugerea servlet-ului.
public String getServletInfo()
public ServletConfig getServletConfig()
In cele ce urmeaza o clasa servlet va fi o clasa care extinde clasa HttpServlet.
In locul metodei service(...), programatorul suprascrie metodele doGet(...)
sau doPost(...), n functie de metoda utilizata de client la lansarea cererii.
Practic, un servlet consta din scrierea metodelor
void init(ServletConfig config)
Aceasta metoda este optionala.
public void init(ServletConfig config) throws ServletException{
super.init(config);
// cod de initializare
}
Obiectul config are o metoda String getInitParameter(String numeParam) cu ajutorul careia se pot recupera parametri de initializare
asociati servlet-ului si care se dau fie prin adnotarea WebInitParam prin
sablonul
import javax.servlet.annotation.WebInitParam;
@WebServlet(urlPatterns = "/numeApel",
initParams = {

166

CAPITOLUL 8. SERVLET

@WebInitParam(name = "numeParam", value = "valoareParam"),


. . .
}
)
fie n fisierul web.xml prin elementele
<init-param>
<param-name> NumeleParametrului </param-name>
<param-value> Valoare </param-value>
</init-param>
cuprinse n elementul <servlet>.
protected void doGet(HttpServletRequest req, HttpServletResponse
res) throws IOException, ServletException
Trateaza o cerere trimisa cu metoda GET (vezi marcajul <form>).
protected void doPost(HttpServletRequest req, HttpServletResponse
res) throws IOException, ServletException
Trateaza o cerere trimisa cu metoda POST (vezi marcajul <form>).
Activitatile de ntreprins ntr-o metoda doGet() sau doPost() sunt
1. Stabilirea naturii raspunsului:
res.setContentType(String tip)
unde tip specifica tipul MIME - Multipurpose Internet Mail Extensions
al raspunsului:
"text/html" - pagina html;
"text/xml" - document xml;
"text/plain" - text;
"image/jpg" - imagine jpg;
"image/gif" - imagine gif;
"application/json" - date codificate JSON.

8.2. REALIZAREA UNUI SERVLET

167

2. Se obtine o referinta catre un obiect care realizeaza transmisia datelor


catre navigatorul clientului:
ServletOutputStream out = res.getOutputStream();
sau
PrintWriter out=res.getWriter();
3. Se preiau datele cererii cu una din metodele interfetei HttpServletRequest:
String getParameter(String numeParametru)
java.util.Enumeration getParameterNames()
Aditional se pot afla
calculatorul cu serverul web: getServerName();
portul: getServerPort();
catalogul servlet-ului: getContextPath().
4. Rezolva cererea clientului;
5. Formeaza si scrie raspunsul;
6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelor
catre navigatorul clientului prin out.close().
Un camp (global) declarat n clasa servletului este comun fiecarei instante
a servletului.
Un utilizator lanseaza o cerere catre servlet. De obicei acest lucru se realizeaza prin completarea unui formular al unui document html. Programul
navigator trimite cererea serverului Web prin intermediul caruia este lansat
servlet-ul n actiune.
Ciclul de viat
a al unui servlet. Cand un servlet este apelat prima
data de catre serverul Web se executa metoda init. Dupa aceasta, fiecarei
cereri lansate de un utilizator i se asociaza un fir de executie n care se apeleaza metoda service. Metoda service apeleaza apoi metodele doGet(),
doPost().
Exemplul 8.2.1 Servlet-ul Hello: Clientul transmite numele servlet-ului care
i raspunde cu mesajul de salut Hi + nume!.
Formularul html prin care clientul introduce numele este (index.html )

168

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

CAPITOLUL 8. SERVLET

< ! doctype html>


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

apphelloP corespunde contextului aplicatiei.


In modul programat servlet-ului are codul
1
2
3
4
5
6
7
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

import
import
import
import
import
import
import

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

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

8.2. REALIZAREA UNUI SERVLET

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

28
29
30
31
32

169

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


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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp version= 3 . 0 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e
x m l n s : x s i= h t t p : //www. w3 . o r g /2001/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 si arhivarea servlet-ului o vom realiza prin intermediul lui


apache-ant. In acest scop se creaza structura:
hello
|
|
|
|
|
|
|
|
|

|---> src
|
|
HelloServlet.java
|---> web
|
|---> WEB-INF
|
|
|---> classes
|
|
|---> lib
|
|
|
web.xml
|
|
index.html
build.xml

si se utilizeaza fisierul build.xml


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

<p r o j e c t b a s e d i r= . default= g e n e r a t e . war >


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

170

CAPITOLUL 8. SERVLET

i n c l u d e a n t r u n t i m e= f a l s e
s r c d i r= ${ b a s e d i r }/ s r c
d e s t d i r=web/WEBINF/ c l a s s e s />

22
23
24
25
27
28
29
30

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

Observatie. Valoarea parametrului dist.name defineste catalogul aplicatiei


(contextul) catalogAppServlet.
Se lanseaza n executie serverul Web tomcat, se desfasoara servlet-ul n
serverul Web si dintr-un navigator se deschide pagina http://localhost:8080/apphelloP
Exemplul 8.2.2 Servlet pentru calculul celui mai mare divizor comun a dou
a
numere.
1
2
3
4
5
6
7
9
10

import
import
import
import
import
import
import

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

@WebServlet ( u r l P a t t e r n s = /cmmdc )
public c l a s s CmmdcServlet extends H t t p S e r v l e t {

12

public long cmmdc( long m, long n ) { . . . }

14

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

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

IN SERVLET
8.3. PROCESARE ASINCRONA

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

38
39
40
41
42

171

apelabil prin documentul html (index.html )


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

< ! doctype html>


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

Pentru fixarea naturii raspunsului text/html sau text/plain s-a introdus


variabila tip, care n fisierul de invocare index.html primeste pe ascuns valoarea
text/html. In cazul n care vom apela servlet-ul dintr-un program, va fi
avantajos sa primim raspunsul ca text/plain.

8.3

Procesare asincron
a n servlet

Rezolvarea unei cereri adresat de un client unui servlet (metoda doGet /


doPost) se executa de catre serverul Web ntr-un fir de executie. Firul de

172

CAPITOLUL 8. SERVLET

executie este creat si lansat de serverul Web.


Interfata de programare Servlet 3.0 ofera posibilitatea unui executii asincrone: satisfacerea cererii clientului se face ntr-un fir de executie lansat de
clasa servlet-ului. Terminarea activitatii clasei servlet nu mai este legata de
rezolvarea cererii clientului si de trimiterea raspunsului.
Acest mod de executie se indica prin adnotarea
@WebServlet(urlPaterns="/numeApel " ,asyncSupported=true)
Suportul asincron necesita un context, obiect de tip javax.servlet.Async
Context. Acest obiect se obtine prin
AsyncContext asyncCtx=req.startAsync();
AsyncContext asyncCtx=req.startAsync(req,res);
Activitatile ce trebuie ndeplinite pentru satisfacerea cererii clientului se lanseaza
ntr-un fir de executie prin
asyncCtx.start(Runnable fir);
Metoda void complete() a clasei javax.servlet.AsyncContext finalizeaza ndeplinirea activitatii asincrone.
Interfata AsyncListener permite notificarea evenimentelor n serverul Web
void onComplete(AsyncEvent ae)
void onTimeout(AsyncEvent ae)
void onError(AsyncEvent ae)
void onStartAsync(AsyncEvent ae)
Obiectul de tip AsyncEvent este creat n momentul satisfacerii cererii clientului, depasirii timpului alocat sau producerii unei erori.
Exemplul 8.3.1 Varianta asincrona a servlet-ului de calcul a celui mare divizor comun.
Codul servlet-ului (AsyncServlet) este independent de activitatile ce satisfac cererea clientului. Acele activitati sunt programate n clasa AsyncAction
prin -expresii.
Clasa AsyncServlet
1
2

package m y s e r v l e t ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;

IN SERVLET
8.3. PROCESARE ASINCRONA

3
4
5
6
7
8
9
11
12

import
import
import
import
import
import
import

@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 {
f i n a l AsyncContext asyncCtx=r e q . s t a r t A s y n c ( req , r e s ) ;
AsyncAction a s y n c A c t i o n=new AsyncAction ( ) ;
asyncCtx . a d d L i s t e n e r (new MyAsyncListener ( ) ) ;
asyncCtx . s t a r t ( a s y n c A c t i o n . f . s e r v i c e ( asyncCtx ) ) ;
}

14
15
16
17
18
19
20

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

22
23
24
25
26

javax . s e r v l e t . http . HttpServlet ;


javax . s e r v l e t . http . HttpServletRequest ;
javax . s e r v l e t . http . HttpServletResponse ;
j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
j a v a x . s e r v l e t . AsyncContext ;
j a v a . i o . IOException ;
l i s t e n e r s . MyAsyncListener ;

Clasa AsyncAction

package m y s e r v l e t ;
import j a v a x . s e r v l e t . AsyncContext ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . S e r v l e t R e s p o n s e ;
import j a v a . i o . IOException ;

c l a s s AsyncAction {

1
2
3
4
5

12

i n t e r f a c e CmmdcService {
long cmmdc( long m, long n ) ;
}

14

s t a t i c CmmdcService cmmdcService=(long m, long n ) >{. . . }

16

interface IAsyncAction {
Thread s e r v i c e ( AsyncContext asyncCtx ) ;
}

10
11

17
18
20
21
22
23
24
25
26
27
28
29
30
31

I A s y n c A c t i o n f =(AsyncContext asyncCtx)>{
return new Thread (()>{
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=cmmdcService . 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 ( ) ;
System . out . p r i n t l n ( x ) ;
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 ( ) ;

173

174

CAPITOLUL 8. SERVLET

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

32
33
34
35
36
37
38
39
40

}
catch ( IOException e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}
asyncCtx . c o m p l e t e ( ) ;
});

41
42
43
44
45
46

};

47
48

Clasa MyAsyncListener implementeaza interfata AsyncListener

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 {

1
2
3

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

10
11
12
13
14

public void onTimeout ( AsyncEvent ae ) {


S e r v l e t R e q u e s t r e q=ae . getAsyncContext ( ) . g e t R e q u e s t ( ) ;
S t r i n g r=r e q . g e t P a r a m e t e r ( m)+ <> +r e q . g e t P a r a m e t e r ( n ) ;
System . out . p r i n t l n ( A s y n c L i s t e n e r : onTimeout f o r r e q u e s t : +r ) ;
}

16
17
18
19
20

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

22
23
24
25
26

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

28
29
30
31
32
33

Serverul de aplicatie glassfish ofera facilitati pentru implementarea aplicatiei


servlet:

IN SERVLET
8.3. PROCESARE ASINCRONA

175

Firul de executie va apartine unui bazin de fire de executie al serverului


de aplicatie. Exista un bazin initial (implicit) pe care-l vom folosi.
Un bazin propriu se creaz
a execut
and
Resources -> Concurrent Resources -> Managed Executor Services
1. New
2. Se completeaz
a
JNDI Name: executorService
Core Size: 10
3. OK

Resursa se indica prin adnotarea


import javax.annotation.Resource;
@Resource
private ManagedExecutorService executorService;

Includerea firului de executie se programeaza cu metoda


Future<?> submit(Runnable task )
Codul complet este
Exemplul 8.3.2
1
2
3
4
5
6
7
8
9
10
11
13
14

package m y s e r v l e t ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
import j a v a x . s e r v l e t . AsyncContext ;
import j a v a . i o . IOException ;
import j a v a x . e n t e r p r i s e . c o n c u r r e n t . M a n a g e d E x e c u t o r S e r v i c e ;
import j a v a x . a n n o t a t i o n . R e s o u r c e ;
import j a v a . i o . P r i n t W r i t e r ;
@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 {

16

@Resource private M a n a g e d E x e c u t o r S e r v i c e e x e c u t o r S e r v i c e ;

18

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 {
f i n a l AsyncContext asyncCtx=r e q . s t a r t A s y n c ( ) ;
e x e c u t o r S e r v i c e . submit (()>{
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 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 ) ;
try {

19
20
21
22
23
24
25
26
27

176

CAPITOLUL 8. SERVLET

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 ( </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 ( ) ;
asyncCtx . c o m p l e t e ( ) ;

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

}
catch ( IOException e ) { }
});

45
46
47
48

50

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

51
52
53

public long cmmdc( long m, long n ) { . . . }

55
56

Actiunea firului de executie poate fi inclusa ntr-o componenta Java care


va fi instantiata si injectata de serverul de aplicatie.
Injectarea este indicata prin
import javax.inject.Inject;
@Inject
private CmmdcAction obj;

Clasa CmmdcAction nu contine decat metoda cmmdc din codul de mai


sus.
In plus este nevoie fisierul beans.xml
1
2
3
4
5
6
7
8

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<beans
xmlns= h t t p : // xmlns . j c p . o r g /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
x s i : s c h e m a L o c a t i o n= h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e / b e a n s 1 1 . xsd
beand i s c o v e r y mode= a l l >
</ beans>

plasat n catalogul WEB-INF.


IN SERVLET-API 3.1
8.4. DEZVOLTARI

8.4

177

Dezvolt
ari n servlet-api 3.1

Implementarea de referinta a interfetei de programare (API) servlet-api 3.1


este continuta n produsul glassfish4.

8.4.1

Procesare asincron
a neblocant
a

Diferenta majora consta n faptul ca solicitarea clientului este trimisa nemijlocit si ndeplinita de o clasa tip listener.
Clasa javax.servlet.ServletInputStream
Metode
public int readLine(byte[] b, int off, int len) throws IOException
public void setReadListener(ReadListenerreadListener )
Interfata javax.servlet.ReadListener declara metodele
void onDataAvailable() throws IOException
void onAllDataRead() throws IOException)
void onError(Throwable t)
Clasa care implementeaza aceasta interfata satisface cererea clientului.
Se va mai utiliza interfata javax.servlet.WriteListener care declara
metodele
void onWritePossible() throws java.io.IOException
void onError(java.lang.Throwable throwable)
Exemplul 8.4.1

11

import j a v a . i o . IOException ;
// i m p o r t j a v a . i o . P r i n t W r i t e r ;
import j a v a . n e t .URL;
import j a v a x . s e r v l e t . AsyncContext ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . S e r v l e t I n p u t S t r e a m ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;

13

@WebServlet ( u r l P a t t e r n s = { / n o n b l o c k } , a s y n c S u p p o r t e d=true )

1
2
3
4
5
6
7
8
9
10

178

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

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

33
34
35
36
37
38

CAPITOLUL 8. SERVLET

mpreuna cu clasa care ndeplineste cererea clientului

import
import
import
import
import
import
import

public c l a s s CmmdcListener implements R e a d L i s t e n e r , W r i t e L i s t e n e r {

1
2
3
4
5
6

11
12
13
14
15
16
18
19
20
21
22
23
24
25
27
28
29
30
31

j a v a . i o . IOException ;
j a v a x . s e r v l e t . AsyncContext ;
javax . s e r v l e t . ReadListener ;
javax . s e r v l e t . ServletOutputStream ;
javax . s e r v l e t . WriteListener ;
javax . s e r v l e t . ServletInputStream ;
j a v a . i o . IOException ;

private
private
private
private
private
private

ServletInputStream input = null ;


AsyncContext c o n t e x t = n u l l ;
S e r v l e t O u t p u t S t r e a m out = n u l l ;
boolean r e a d F i n i s h e d=f a l s e ;
S t r i n g r e z=n u l l ;
S t r i n g data=n u l l ;

public CmmdcListener ( S e r v l e t I n p u t S t r e a m in ,
AsyncContext ac , S e r v l e t O u t p u t S t r e a m o ut pu t ) {
input = in ;
c o n t e x t = ac ;
out = ou tp ut ;
in . setReadListener ( this ) ;
out . s e t W r i t e L i s t e n e r ( t h i s ) ;
}
@Override
public void o n D a t a A v a i l a b l e ( ) {
try {
int l e n = 0 ;
byte b [ ] = new byte [ 1 0 2 4 ] ;


IN SERVLET-API 3.1
8.4. DEZVOLTARI

while ( i n p u t . i s R e a d y ( ) && ( l e n >1)) {


l e n=i n p u t . r e a d ( b ) ;
}
data = new S t r i n g ( b , 0 , l e n ) ;
System . out . p r i n t l n ( data ) ;

32
33
34
35
36

}
catch ( IOException e ) {
System . out . p r i n t l n ( o n A v a i l a b l e E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}

37
38
39
40
41

43

@Override
public void onAllDataRead ( ) throws IOException {
System . out . p r i n t l n ( onAllDataRead ) ;
r e a d F i n i s h e d=true ;
System . out . p r i n t l n ( data ) ;
r e z=s o l v e r ( data ) ;
context . complete ( ) ;
onWritePossible ( ) ;
}

44
45
46
47
48
49
50
51

@Override
public void o n W r i t e P o s s i b l e ( ) throws IOException {
while ( ! r e a d F i n i s h e d ) ;
out . p r i n t l n ( <p> ) ;
out . p r i n t l n ( r e z ) ;
}

53
54
55
56
57
58

@Override
public void o n E r r o r ( Throwable t ) {
t . printStackTrace ( ) ;
context . complete ( ) ;
}

60
61
62
63
64

private S t r i n g s o l v e r ( S t r i n g data ) {
S t r i n g [ ] s=data . s p l i t ( & ) ;
S t r i n g [ ] s 0=s [ 0 ] . s p l i t ( = ) ;
long m=Long . par se Lon g ( s 0 [ 1 ] ) ;
S t r i n g [ ] s 1=s [ 1 ] . s p l i t ( = ) ;
long n=Long . p ars eL ong ( s 1 [ 1 ] ) ;
S t r i n g r =(new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ;
return Cmmdc : +r ;
}

66
67
68
69
70
71
72
73
74

private long cmmdc( long m, long n ) { . . . }

76
77

179

8.4.2

Modificarea protocolului http: upgrade

Schema este utilizata deja n protocolului websocket.


In apelul http trebuie inserat antetul (header ) Upgrade. Odata aceast
antet recunoscut, solicitarea clientului este rezolvata ntr-o clasa care implementeaza interfata javax.servlet.http.HttpUpgradeHandler.
Interfata declara metodele:

180

CAPITOLUL 8. SERVLET

void init(WebConnection wc)


void destroy()
Interfata javax.servlet.http.WebConnection
Metode
ServletInputStream getInputStream() throws IOException
ServletOutputStream getOutputStream() throws IOException
Clasa care implementeaza interfata HttpUpgradeHandler se declara n
servlet prin metoda upgrade a interfetei HttpServletRequest
<T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
throws IOException, ServletException
In principiu clasa servlet-ului este independenta de specificul aplicatiei.

import
import
import
import
import

@WebServlet ( u r l P a t t e r n s = { / upgrade } )

public c l a s s U p g r a d e S e r v l e t extends H t t p S e r v l e t {

1
2
3
4

servlet
servlet
servlet
servlet
servlet

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

public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )


throws S e r v l e t E x c e p t i o n , IOException {
i f ( upgrade . e q u a l s ( r e q . g e t H e a d e r ( Upgrade ) ) ) {
res . setStatus (101);
r e s . s e t H e a d e r ( Upgrade , upgrade ) ;
r e s . s e t H e a d e r ( C o n n e c t i o n , Upgrade ) ;
res . flushBuffer () ;
System . out . p r i n t l n ( Upgrade OK +r e q . g e t H e a d e r ( Upgrade ) ) ;
MyHttpUpgradeHandler h a n d l e r = r e q . upgrade ( MyHttpUpgradeHandler . c l a s s ) ;
}
else {
System . out . p r i n t l n ( No upgrade : ) ;
}
}

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

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

26
27
28
29
30

javax .
javax .
javax .
javax .
javax .

Pentru problema calculului celui mai mare divizor comun a doua numere
naturale clasa MyHttpUpgradeHandler este


IN SERVLET-API 3.1
8.4. DEZVOLTARI

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
34
35
36
37
38
39
40
41
42
44
45
46
47
48
49
50
51
52
53
54
55
56
57

import
import
import
import

javax .
javax .
javax .
javax .

servlet
servlet
servlet
servlet

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

public c l a s s MyHttpUpgradeHandler implements HttpUpgradeHandler {


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

181

182
private long cmmdc( long m, long n ) { . . . }

59
60

CAPITOLUL 8. SERVLET

Problema care ramane de rezolvat este inserarea antetului Update. Rezolvarea consta n generarea unui mesaj http care se va transmite printr-un
soclu TCP. Mesajul http foloseste metoda post, iar datele din corpul mesajului sunt preluate prin interfata HttpInputStream.
Lansarea aplicatiei se face dintr-un program client, n care se genereaza
mesajul http cu anterul Upgrade, mesaj expediat printr-un soclu TCP.
Client Java
1
2
3
4
5
6
7
9
10
11
12
13
14
15
16
17
18
19
20
21
23
24
25
26
27
28
29
30
31
32
33
34
36
37
38
39
40
41
42
43
44
45

import
import
import
import
import
import
import

java . net . Socket ;


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

public c l a s s J C l i e n t {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
S t r i n g sm=new Long (m) . t o S t r i n g ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ;
S t r i n g data=sm+ +sn ;
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 8080 ;
S t r i n g c o n t e x t R o o t= / upgrade ;
S t r i n g CRLF = \ r \n ;
S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ;
r e q S t r += UserAgent : Java / 1 . 7 + CRLF ;
r e q S t r += Host : + h o s t + : + p o r t + CRLF ;
r e q S t r += Accept : t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 +
CRLF ;
r e q S t r += Upgrade : upgrade + CRLF ;
r e q S t r += C o n n e c t i o n : Upgrade + CRLF ;
r e q S t r += Contentt y p e : a p p l i c a t i o n /xwwwformu r l e n c o d e d + CRLF ;
r e q S t r += T r a n s f e r Encoding : chunked + CRLF ;
r e q S t r += CRLF ;
r e q S t r += data + CRLF ;
S o c k e t s o c k e t=n u l l ;
try {
s o c k e t=new S o c k e t ( hos t , I n t e g e r . p a r s e I n t ( p o r t ) ) ;
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}
try (
OutputStream out=s o c k e t . getOutputStream ( ) ;
InputStream i n=s o c k e t . g e t I n p u t S t r e a m ( ) ;


IN SERVLET-API 3.1
8.4. DEZVOLTARI

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

46
47

){

48

out . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ;
out . f l u s h ( ) ;
String s ;
while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) {
System . out . p r i n t l n ( s ) ;
};
socket . close ( ) ;
// System . e x i t ( 0 ) ;

49
50
51
52
53
54
55
56

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

57
58
59
60

61
62

Client servlet
1
2
3
4
5
6
7
9
10
11
12
13
15
16
18
19
20
21
23
24
26
27
28
29
30
31
32
33
34
35
36
37
38
39

import
import
import
import
import
import
import

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

import
import
import
import
import

javax .
javax .
javax .
javax .
javax .

servlet
servlet
servlet
servlet
servlet

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

@WebServlet ( u r l P a t t e r n s = { / c l i e n t } )
public c l a s s C l i e n t S e r v l e t extends H t t p S e r v l e t {
protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g m=r e q . g e t P a r a m e t e r ( m ) ;
S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ;
r e s . setContentType ( t e x t / html ; c h a r s e t=UTF8 ) ;
P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
f i n a l S t r i n g CRLF = \ r \n ;
f i n a l S t r i n g h o s t = r e q . getServerName ( ) ; // l o c a l h o s t ;
f i n a l i n t p o r t = r e q . g e t S e r v e r P o r t ( ) ; // 8 0 8 0 ;
f i n a l S t r i n g c o n t e x t R o o t = / upgrade ;
f i n a l S t r i n g data = m+ +n ;
InputStream i n p u t = n u l l ;
OutputStream o ut pu t = n u l l ;
BufferedReader r e a d e r = null ;
Socket s = null ;
try {
out . p r i n t l n ( <html> ) ;
out . p r i n t l n ( <head> ) ;
out . p r i n t l n ( < t i t l e >S e r v l e t C l i e n t T e s t </ t i t l e > ) ;
out . p r i n t l n ( </head> ) ;

183

184

40
41
43
44
45
46
47
48
49
50
51
52
53
54
56
57
58
59
60
62
63
64

CAPITOLUL 8. SERVLET

out . p r i n t l n ( <body> ) ;
out . p r i n t l n ( <h1>Http Upgrade P r o c e s s </h1> ) ;
// S e t t i n g t h e HTTP u p g r a d e r e q h e a d e r
S t r i n g r e q S t r = POST + c o n t e x t R o o t + / upgrade HTTP/ 1 . 1 + CRLF ;
r e q S t r += UserAgent : Java / 1 . 7 + CRLF ;
r e q S t r += Host : + h o s t + : + p o r t + CRLF ;
r e q S t r += Accept :
t e x t / html , image / g i f , image / j p e g , ; q = . 2 , / ; q =.2 + CRLF ;
r e q S t r += Upgrade : upgrade + CRLF ;
r e q S t r += C o n n e c t i o n : Upgrade + CRLF ;
r e q S t r += Contentt y p e : a p p l i c a t i o n /xwwwformu r l e n c o d e d + CRLF ;
r e q S t r += T r a n s f e r Encoding : chunked + CRLF ;
r e q S t r += CRLF ;
r e q S t r += data + CRLF ;
s = new S o c k e t ( hos t , p o r t ) ;
input = s . getInputStream ( ) ;
ou tp ut = s . getOutputStream ( ) ;
ou tp ut . w r i t e ( r e q S t r . g e t B y t e s ( ) ) ;
ou tp ut . f l u s h ( ) ;
out . p r i n t l n ( <h2>S e n d i n g upgrade r e q t o s e r v e r . . . . . . < / h2> ) ;
out . p r i n t l n ( <h3>Request h e a d e r with data : </h3> ) ;
out . p r i n t l n ( ) ;

69

S t r i n g r e q S t r D i s p l a y = r e q S t r . r e p l a c e A l l ( \ r \n , </br> ) ;
out . p r i n t l n ( r e q S t r D i s p l a y ) ;
out . p r i n t l n ( </br></br> ) ;
out . f l u s h ( ) ;

71

r e a d e r = new B u f f e r e d R e a d e r (new InputStreamReader ( i n p u t ) ) ;

73

out . p r i n t l n ( <h2>S e r v e r a c c e p t upgrade req , send back t h e r e s : </h2> ) ;


out . p r i n t l n ( <h3>Response h e a d e r : </h3> ) ;
out . p r i n t l n ( ) ;

66
67
68

74
75
77
78
79
80
82
83
85
86
88
89
90
91
92
93
94
95
96
97
98

// Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r


p r i n t H e a d e r ( r e a d e r , out ) ;
out . p r i n t l n ( </br></br> ) ;
out . f l u s h ( ) ;
out . p r i n t l n ( <h2>S e r v e r send back t h e r e s with new p r o t o c o l and data : </h2> ) ;
out . p r i n t l n ( <h3>Response h e a d e r with data : </h3> ) ;
// Reading t h e r e s , and d i s p l a y i n g t h e h e a d e r from s e r v e r
p r i n t H e a d e r ( r e a d e r , out ) ;
// Reading t h e echo d a t a
S t r i n g dataOutput ;
i f ( ( dataOutput = r e a d e r . r e a d L i n e ( ) ) != n u l l ) {
// P r i n t o u t t h e d a t a a f t e r h e a d e r
out . p r i n t l n ( </br> + dataOutput + </br> ) ;
out . p r i n t l n ( </br></br> ) ;
out . p r i n t l n ( <h2>C o n n e c t i o n with new p r o t o c o l e s t a b l i s h e d </h2> ) ;
}
out . f l u s h ( ) ;
out . p r i n t l n ( </body> ) ;
out . p r i n t l n ( </html> ) ;

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

}
catch ( IOException e ) {
System . out . p r i n t l n ( C l i e n t S e r v l e t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
finally {
i f ( r e a d e r != n u l l ) {
reader . close ( ) ;
}
i f ( ou tp ut != n u l l ) {
o ut pu t . c l o s e ( ) ;
}
i f ( i n p u t != n u l l ) {
input . c l o s e ( ) ;
}
i f ( s != n u l l ) {
s . close ();
}
}

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

119

protected void p r i n t H e a d e r ( B u f f e r e d R e a d e r r e a d e r , P r i n t W r i t e r out )


throws IOException {
f o r ( S t r i n g l i n e ; ( l i n e = r e a d e r . r e a d L i n e ( ) ) != n u l l ; ) {
i f ( l i n e . isEmpty ( ) ) {
break ;
}
out . p r i n t l n ( l i n e + </br> ) ;
}
}

120
121
122
123
124
125
126
127

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

129
130
131
132
133
134

185

8.5
8.5.1

Facilit
ati de programare cu servlet
Program client al unui servlet

Apelarea unui servlet dintr-un program Java adica lansarea unei cereri si
receptionarea raspunsului furnizat de servlet se poate obtine
sincron cu produsul httpcomponents-client,
asincron cu unul din produsele
httpcomponents-client,
httpcomponents-asyncclient.

186

CAPITOLUL 8. SERVLET

Ambele produse sunt dezvoltate de apache.


Caracterul sincron / asincron consta n faptul ca receptia si prelucrarea
raspunsului oferit de servlet are loc n metoda din care s-a lansat cererea,
respectiv ntr-un alt obiect.
Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajos
ca raspunsul servlet-ului fie text/plain, n loc de text/html.
Cazul sincron
Catalogul lib din httpcomponents-client contine, printre altele, fisierele
httpcore-*.jar, httpclient-*.jar, commons-logging-*.jar.
Pentru compilare trebuie declarata n variabila de sistem classpath referinta
catre httpclient-*.jar si httpcore-*.jar dar pentru executie este nevoie si de
referinta catre commons-logging-*.jar.
Dezvoltarea unui client presupune:
1. Crearea unui obiect de tip org.apache.http.client.CloseableHttpClient:
CloseableHttpClient httpclient = HttpClients.createDefault();
2. Declararea metodei de transmitere a datelor get, post cu inserarea datelor
din cerere.
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 eleganta este
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/catalog/numeApel",URLEncodedUtils.format(qparams,"UTF-8"),
null);
HttpGet httpget = new HttpGet(uri);
. . .

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

187

}
catch(. . .){. . .}
POST
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
UrlEncodedFormEntity params=new UrlEncodedFormEntity(qparams,
"UTF-8");
HttpPost httppost=new HttpPost(uri);
httppost.setEntity(params);
. . .
}
catch(. . .){. . .}
cu uri=http://host:port/catalog/numeApel.
Clasele HttpGet, HttpPost apartin pachetului org.apache.http.client.
methods.
3. Lansarea cererii.
HttpResponse response=httpclient.execute(httpget);
respectiv
HttpResponse response=httpclient.execute(httppost);
4. Preluarea raspunsului.
HttpEntity entity=response.getEntity();
if(entity!=null){
InputStream is=entity.getContent();
int l;
byte[] tmp=new byte[2048];
while((l=is.read(tmp))!=-1){}
. . .
}

188

CAPITOLUL 8. SERVLET

Exemplul 8.5.1 Dezvoltam un program client pentru servlet-ul CmmdcServlet


(post).
1
2
4
5
6
7
8
9
10
11
13
14
16
17

import j a v a . u t i l . S c a n n e r ;
import o r g . apache . h t t p . H t t p E n t i t y ;
import
import
import
import
import
import
import
import

import o r g . apache . h t t p . c l i e n t . e n t i t y . UrlEncodedFormEntity ;


import j a v a . i o . ;
public c l a s s ClientCmmdcServlet {
s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
S t r i n g m=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;
System . out . p r i n t l n ( n= ) ;
S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;

19
20
21
22
23
24

CloseableHttpClient httpclient = HttpClients . createDefault ( ) ;


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

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

48
49

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

Varianta fluenta
1
2
3

import j a v a . u t i l . S c a n n e r ;
import o r g . apache . h t t p . c l i e n t . f l u e n t . Form ;
import o r g . apache . h t t p . c l i e n t . f l u e n t . Request ;

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

5
6

public c l a s s ClientCmmdcServlet1 {
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= ) ;
S t r i n g m=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;
System . out . p r i n t l n ( n= ) ;
S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;

8
9
10
11
12
13

System . out . p r i n t l n ( Post method r e q u e s t ) ;


try {
S t r i n g r e s u l t=Request . Post ( u r i )
. bodyForm ( Form . form ( )
. add ( m ,m)
. add ( n , n )
. add ( t i p , t e x t / p l a i n )
. build ())
. execute ( ) . returnContent ( ) . asString ( ) ;
System . out . p r i n t l n ( Cmmdc = +r e s u l t ) ;
}
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 ( ) ) ;
}

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

System . out . p r i n t l n ( Get method r e q u e s t ) ;


S t r i n g data= ?m=+m+&n=+n+&t i p=t e x t / p l a i n ;
try {
S t r i n g r e s u l t=Request . Get ( u r i+data )
. execute ( ) . returnContent ( ) . asString ( ) ;
System . out . p r i n t l n ( Cmmdc = +r e s u l t ) ;
}
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 ( ) ) ;
}

30
31
32
33
34
35
36
37
38
39

40
41

189

O solutie elementara bazata pe clasa java.net.HttpURLConnection este


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

import
import
import
import
import
import

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

public c l a s s CmmdcClient {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g msg=m=+m+&n=+n+&t i p=t e x t / p l a i n ;
System . out . p r i n t l n ( HttpURLConnection cu metoda GET ) ;
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 ;

190

CAPITOLUL 8. SERVLET

URL u r l=new URL( urlGET ) ;


HttpURLConnection conn=(HttpURLConnection ) u r l . op enConne ction ( ) ;
conn . setRequestMethod ( GET ) ;
System . out . p r i n t l n ( conn . getResponseCode ( ) ) ;
System . out . p r i n t l n ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ;
B u f f e r e d R e a d e r br=
new B u f f e r e d R e a d e r (new InputStreamReader ( conn . g e t I n p u t S t r e a m ( ) ) ) ;
String s ;
while ( ( s=br . r e a d L i n e ( ) ) ! = n u l l ) {
System . out . p r i n t l n ( s ) ;
}
br . c l o s e ( ) ;
conn . d i s c o n n e c t ( ) ;

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

}
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 ( HttpURLConnection cu metoda POST ) ;
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 /xwwwformu 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 ( ) ) ;

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

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

48
49
50
51
52
53
54
55
56
57
58
59
60

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

61
62
63
64

65
66

Cazul asincron
1. httpcomponent-client
1
2
3
4

import
import
import
import

java . u t i l . Scanner ;
o r g . apache . h t t p . c l i e n t . f l u e n t . Form ;
o r g . apache . h t t p . c l i e n t . f l u e n t . Request ;
o r g . apache . h t t p . c l i e n t . f l u e n t . Async ;

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

5
6
7
8
9
11
12

import
import
import
import
import

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 ) {
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=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;
System . out . p r i n t l n ( n= ) ;
S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;

14
15
16
17
18
19

E x e c u t o r S e r v i c e t h r e a d p o o l = E x e c u t o r s . newFixedThreadPool ( 2 ) ;
Async a s y n c = Async . n e w I n s t a n c e ( ) . u s e ( t h r e a d p o o l ) ;

21
22

System . out . p r i n t l n ( Post method r e q u e s t ) ;


try {
Request r e q u e s t=Request . Post ( u r i )
. bodyForm ( Form . form ( )
. add ( m ,m)
. add ( n , n )
. add ( t i p , t e x t / p l a i n )
. build ( ) ) ;

24
25
26
27
28
29
30
31

// V a r i a n t a 1
/
Future<Content> f u t u r e=async . e x e c u t e ( r e q u e s t ) ;
w h i l e ( ! f u t u r e . isDone ( ) ) { ; }
System . o u t . p r i n t l n (Cmmdc = + f u t u r e . g e t ( ) . a s S t r i n g ( ) ) ;
/

33
34
35
36
37
38

// V a r i a n t a 2
Future<Content> f u t u r e=a s y n c . e x e c u t e ( r e q u e s t ,
new F u t u r e C a l l b a c k <Content >(){
@Override
public void c o m p l e t e d ( f i n a l Content c o n t e n t ) {
System . out . p r i n t l n ( Cmmdc : +c o n t e n t . a s S t r i n g ( ) ) ;
}
@Override
public void f a i l e d ( f i n a l 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 ( ) + : + r e q u e s t ) ;
}
@Override
public void c a n c e l l e d ( ) {}
});
while ( ! f u t u r e . i s D o n e ( ) ) { ; }

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

t h r e a d p o o l . shutdown ( ) ;
}
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 ( ) ) ;
}

56
57
58
59
60

61
62

o r g . apache . h t t p . c l i e n t . f l u e n t . Content ;
java . u t i l . concurrent . ExecutorService ;
java . u t i l . concurrent . Executors ;
j a v a . u t i l . c o n c u r r e n t . Future ;
o r g . apache . h t t p . c o n c u r r e n t . F u t u r e C a l l b a c k ; // HttpCore

191

192

CAPITOLUL 8. SERVLET

2. httpcomponent-asyncclient
Variabila classpath contine referentele catre fiserele jar aflate n catalogul lib din httpcomponent-asyncclient.
Programarea consta din
(a) Crearea unei instante a clasei
org.apache.http.impl.nio.client.CloseableHttpAsyncClient
CloseableHttpAsyncClient httpclient =
HttpAsyncClients.createDefault();
httpclient.start();
(b) Lansarea unei cereri apeland o metoda execute:
<T> Future<T> execute(
org.apache.http.nio.protocol.HttpAsyncRequestProducer
requestProducer,
org.apache.http.nio.protocol.HttpAsyncResponseConsumer<T>
responseConsumer,
org.apache.http.concurrent.FutureCallback<T> callback )
O instanta de tip HttpAsyncRequestProducer se obtine prin
HttpAsyncMethods.createGet(uri)
Drept instanta a clasei HttpAsyncResponseConsumer poate fi o
clasa ce extinde clasa org.apache.http.nio.client.methods.AsyncChar
Consumer.
Exemplul 8.5.2
1

import j a v a . u t i l . S c a n n e r ;

import
import
import
import
import
import
import

4
5
6
7
8
9
11
12
13
15
16

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 . H t t p A s y n c C l i e n t s ;
o r g . apache . h t t p . n i o . IOControl ;
o r g . apache . h t t p . impl . n i o . c l i e n t . C l o s e a b l e H t t p A s y n c C l i e n t ;
o r g . apache . h t t p . n i o . c l i e n t . methods . AsyncCharConsumer ;
o r g . apache . h t t p . n i o . c l i e n t . methods . HttpAsyncMethods ;
o r g . apache . h t t p . p r o t o c o l . HttpContext ;

import j a v a . n i o . C h a r B u f f e r ;
import j a v a . i o . IOException ;
import j a v a . u t i l . c o n c u r r e n t . Future ;
public c l a s s AsyncClientCmmdcServlet {
s t a t i c S t r i n g u r i= h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc ;

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

193

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=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;
System . out . p r i n t l n ( n= ) ;
S t r i n g n=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;
S t r i n g r e q u e s t D a t a= ?m=+m+&n=+n+&t i p=t e x t / p l a i n ;
System . out . p r i n t l n ( r e q u e s t D a t a ) ;
// C r e a t e an i n s t a n c e o f H t t p A s y n c C l i e n t .

18
19
20
21
22
23
24
25
26

CloseableHttpAsyncClient h t t p c l i e n t =
HttpAsyncClients . c r e a t e D e f a u l t ( ) ;
httpclient . start ();
try {
Future<Boolean> f u t u r e = h t t p c l i e n t . e x e c u t e (
HttpAsyncMethods . c r e a t e G e t ( u r i+r e q u e s t D a t a ) ,
new MyResponseConsumer ( ) , n u l l ) ;
Boolean r e s u l t = f u t u r e . g e t ( ) ;
i f ( r e s u l t != n u l l && r e s u l t . b o o l e a n V a l u e ( ) ) {
System . out . p r i n t l n ( Request s u c c e s s f u l l y e x e c u t e d ) ;
}
else {
System . out . p r i n t l n ( Request f a i l e d ) ;
}
System . out . p r i n t l n ( S h u t t i n g down ) ;
}
finally {
httpclient . close ();
}
System . out . p r i n t l n ( Done ) ;

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

50

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

51
52

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

54
55
56
57
58
59
60
61

@Override
protected void r e l e a s e R e s o u r c e s ( ) {}

63
64

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

66
67
68
69

70
71

194

8.5.2

CAPITOLUL 8. SERVLET

Servlete nl
antuite

Un servlet apeleaza la un moment dat alt servlet. Sablonul de lucru este


RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher("/url_pattern_servlet_apelat");
if(dispatcher!=null)
dispatcher.include(request,response);
Exemplul 8.5.3 Un servlet VerifServlet verifica parametri cererii. Pentru
problema calculului celui mai mare divizor comun a doua numere, daca cei doi
parametri sunt numere ntregi, atunci se apeleaza servlet-ul ComputeServlet,
altfel se formeaza un mesaj de eroare.
Codurile celor doua servlete sunt:
VerifServlet.java
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

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

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

catch ( NumberFormatException e ) {
message=Nu e s t e numar ;
}

38
39
40

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

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

58

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

59
60
61
62

ComputeServlet.java
1
2
3
4
5
6
7
8
10
11

package cmmdc ;
import j a v a . i o . IOException ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . 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 {

13

public long cmmdc( long m, long n ) { . . . }

15

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

16
17
18
19
20
21

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

23
24
25
26
27

195

196

8.5.3

CAPITOLUL 8. SERVLET

Sesiune de lucru

In cazul protocolului HTTP, de fiecare data cand un client deschide sau


revine la o pagina Web se deschide o noua conexiune cu serverul Web iar acesta
nu retine informatiile referitoare la client pe perioada conexiunii respective.
Perioada de timp cat un client este n conexiune cu o pagina Web se numeste
sesiune.
Exista posibilitatea pastrarii unor informatii pe durata unei sesiuni prin
intermediul unui obiect de tip javax.servlet.http.HttpSession.
Inaintea satisfacerii unei cereri, servlet-ul verifica existenta unui obiect
HttpSession. Acest obiect se creaza la prima apelare de catre un client a
servlet-ului prin
HttpSession sesiune=request.getSession(true);
Un obiect HttpSession poate retine atribute, adica perechi de forma (nume,
valoare). Introducerea unui atribut se realizeaza prin
void setAttribute(String nume, Object valoare)
iar extragerea valorii unui atribut se obtine prin
Object getAttribute(String nume)
Metoda String nume[ ] getValueNames() returneaza numele tuturor
atributelor definite.
Un atribut se elimina cu metoda void removeAttribute(String nume).
Exemplul 8.5.4 Exemplul urmator numara de cate ori se apeleaza servletul ntr-o sesiune. Se defineste un atribut noAcces, care la prima apelare este
initializat iar apoi este marit cu cate o unitate la fiecare noua apelare a servletului.
1
2
3
4
5
6
7
8
10
11
13

import
import
import
import
import
import
import
import

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

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

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

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

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

37

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

38
39
40
41

197

Apelarea servlet-ului se face din


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

< ! doctype html>


<head>
<meta charset= u t f 8>
<l i n k r e l= s t y l e s h e e t href= mycss . c s s >
</head>
<body>
<center>
<h1> Formular de a c c e s </h1>
<form method= g e t
action= / m y s e r v l e t / s e s i u n e >
<p>
<input type= submit value= A c c e s e a z a >
</form>
</ center>
</body>
</html>

8.5.4

Cookie

Un Cookie este un fisier de dimensiune mica trimis de catre programul


server clientului ca parte a header-ului Http.
Acesta contine informatii despre sesiunea curenta care salvate pe disc vor
putea fi accesate n sesiuni ulterioare. Cand un navigator emite o cerere catre

198

CAPITOLUL 8. SERVLET

un server, cookie-urile anterioare primite de catre client de la serverul respectiv


sunt trimise din nou serverului ca parte a cererii formulata de client.
Cookie-urile sunt sterse automat n momentul expirarii.
Unii clienti nu permit memorarea cookie-urilor. In acest caz, clientul este
informat ca acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale
/ accesarii paginii Web. Implicit, durata de viata a unui cookie este sesiunea
curenta a navigatorului (pana se nchide navigatorul).
Clasa Cookie
Contructor
Cookie(String nume, String valoare)
Metode
void setDomain(String model )
Domeniul este o adresa URL ce restrictioneaza accesul cookie-urilor la
acel domeniu. model trebuie sa contina cel putin doua caractere ..
void setMaxAge(int durata ) Fixeaza durata de existenta a cookie-ului
- n secunde. Valoarea implicita este -1, adica cookie-ul exista pana la
nchiderea programului navigator.
void setComment(String comentariu)
void setSecure(boolean flag)
Valoarea implicita este false.
Trimiterea unui cookie clientului:
public void HttpServletResponse.addCookie(Cookie cookie)
Recunoasterea cookie-urilor de catre servlet:
Cookie [ ] cookies=request.getCookies();
if(cookies!=null){
for(int i=0;i<cookies.length;i++){
String name=cookies[i].getName();
String valoare=cookies[i].getValue();
. . .
}
exemplul urmator se numara de cate ori se apeleaza servletExemplul 8.5.5 In
ul pe durata de viata a cookie-ului.

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

1
2
3
4
5
6
7
8
9

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

11

@WebServlet ( u r l P a t t e r n s = / c o o k i e )

13

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 {

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

public void doGet ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse res )
throws S e r v l e t E x c e p t i o n , IOException {
r e s . setContentType ( t e x t / html ) ;
S t r i n g mesaj= ;
P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
Cookie myCookie=n u l l ;
i n t c o n t o r =0;
Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ;
boolean sw=f a l s e ;
i f ( c o o k i e s != n u l l ) {
f o r ( i n t i =0; i <c o o k i e s . l e n g t h ; i ++){
S t r i n g name=c o o k i e s [ i ] . getName ( ) ;
i f ( name . e q u a l s ( u r m a r i r e ) ) {
sw=true ;
c o n t o r=I n t e g e r . p a r s e I n t ( c o o k i e s [ i ] . g e t V a l u e ( ) ) ;
c o n t o r ++;
mesaj= Bine a t i r e v e n i t ! ;
System . out . p r i n t l n ( G a s i t +c o n t o r ) ;
}
}
}
i f ( sw ) {
myCookie=new Cookie ( u r m a r i r e , (new I n t e g e r ( c o n t o r ) ) . t o S t r i n g ( ) ) ;
}
else {
myCookie=new Cookie ( u r m a r i r e , (new I n t e g e r ( 1 ) ) . t o S t r i n g ( ) ) ;
c o n t o r =1;
mesaj= S a l u t ! ;
}
myCookie . setMaxAge ( 1 0 0 0 0 0 0 ) ;
r e s . addCookie ( myCookie ) ;
out . p r i n t l n ( <html><body> ) ;
out . p r i n t l n ( <h1>+mesaj+</h1> ) ;
out . p r i n t l n ( Numarul de a c c e s a r i a l a c e a s t e i p a g i n i e s t e +c o n t o r ) ;
out . p r i n t l n ( </body></html> ) ;
out . c l o s e ( ) ;
}
public void doPost ( H t t p S e r v l e t R e q u e s t req ,
HttpServletResponse res )
throws S e r v l e t E x c e p t i o n , IOException {
doGet ( req , r e s ) ;
}

199

200

59

CAPITOLUL 8. SERVLET

8.5.5

Gestiunea butoanelor - TimerServlet

Intr-o pagina html de apelare a unui servlet pot fi mai multe butoane
<input type="submit" value="text" name="numeBtn"/>
Ultimul atribut permite determinarea butonului accesat.
Sablonul de programare este
String button="";
for (Enumeration<String> e = req.getParameterNames(); e.hasMoreElements();){
button=e.nextElement();
switch(button){
case "numeBtn1":
. . .
break;
case "numeBtn2":
. . .
break;
. . .
}
}

Exemplul 8.5.6 Un servlet va executa sarcini la intervale de n (dat ca parametru)


secunde. Cate un buton permite declansarea, oprirea si aflarea starii curente.
Programarea unor activitat care se vor repeta se poate realiza utilizand
clasele java.util.Timer si java.util.TimerTask.
Clasa java.util.Timer
Constructori
public Timer()
Metode
public void schedule(TimerTask task,long delay,long period )
public void cancel()
Sarcina de executat se defineste ntr-o clasa ce extinde java.util.TimerTask.
Programatorul trebuie sa realizeze metoda void run().
In acest exemplu, sarcina consta n retinerea momentului (ora : minut :
secunda).

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

1
2
3
4
5
6
7
8
9

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

11

@WebServlet ( u r l P a t t e r n s = / t i m e r )

13

public c l a s s T i m e r S e r v l e t extends H t t p S e r v l e t {
private s t a t i c MyTimer myTimer ;

14

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 b ut to n= ;
f o r ( Enumeration<S t r i n g >e=r e q . getParameterNames ( ) ; e . hasMoreElements ( ) ; ) {
b utton=e . nextElement ( ) ;
switch ( bu tt on ) {
case s t a r t :
S t r i n g s s=r e q . g e t P a r a m e t e r ( s e c o n d s ) ;
i n t s e c o n d s=I n t e g e r . p a r s e I n t ( s s ) ;
S t r i n g B u f f e r sb=new S t r i n g B u f f e r ( 1 0 0 0 ) ;
myTimer=new MyTimer ( s e c o n d s , out , sb ) ;
break ;
case s t o p :
myTimer . t i m e r S t o p p e d ( ) ;
break ;
case s t a t e :
out . p r i n t l n ( <html> ) ;
out . p r i n t l n ( <body> ) ;
out . p r i n t l n ( <h1>T i m e r S e r v l e t </h1> ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( myTimer . getSb ( ) ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( <a h r e f =\ i n d e x . html\> S t a r t Page</a> ) ;
out . p r i n t l n ( </body> ) ;
out . p r i n t l n ( </html> ) ;
break ;
}
}
out . c l o s e ( ) ;
}

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

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

49
50
51
52
53

unde clasa MyTimer are codul


1
2
3

package t i m e r ;
import j a v a . u t i l . Timer ;
import j a v a . u t i l . TimerTask ;

201

202

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

CAPITOLUL 8. SERVLET

import j a v a . i o . P r i n t W r i t e r ;
import j a v a . u t i l . C a l e n d a r ;
public c l a s s MyTimer{
private Timer t i m e r ;
private P r i n t W r i t e r out ;
private S t r i n g B u f f e r sb ;
public MyTimer ( i n t s e c o n d s , P r i n t W r i t e r out , S t r i n g B u f f e r sb ) {
t h i s . out=out ;
t h i s . sb=sb ;
t i m e r=new Timer ( ) ;
long ms=1000;
t i m e r . s c h e d u l e A t F i x e d R a t e (new MyTask ( ) , 0 ms , s e c o n d s ms ) ;
C a l e n d a r c a l e n d a r=C a l e n d a r . g e t I n s t a n c e ( ) ;
S t r i n g time = c a l e n d a r . g e t ( C a l e n d a r .HOUR OF DAY)+ : +
c a l e n d a r . g e t ( C a l e n d a r .MINUTE)+
: +c a l e n d a r . g e t ( C a l e n d a r .SECOND) ;
System . out . p r i n t l n ( Timer i s s t a r t e d : +time ) ;
sb . append ( <br/> ) ;
sb . append ( Timer i s s t a r t e d : +time ) ;
out . p r i n t l n ( <html> ) ;
out . p r i n t l n ( <body> ) ;
out . p r i n t l n ( <h1>T i m e r S e r v l e t </h1> ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( sb . t o S t r i n g ( ) ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( <a h r e f =\ i n d e x . html\> S t a r t Page</a> ) ;
out . p r i n t l n ( </body> ) ;
out . p r i n t l n ( </html> ) ;
}
public void t i m e r S t o p p e d ( ) {
timer . cancel ( ) ;
C a l e n d a r c a l e n d a r=C a l e n d a r . g e t I n s t a n c e ( ) ;
S t r i n g time = c a l e n d a r . g e t ( C a l e n d a r .HOUR OF DAY)+ : +
c a l e n d a r . g e t ( C a l e n d a r .MINUTE)+
: +c a l e n d a r . g e t ( C a l e n d a r .SECOND) ;
System . out . p r i n t l n ( Timer i s s t o p p e d : +time ) ;
sb . append ( <br/> ) ;
sb . append ( Timer i s s t o p p e d : +time ) ;
out . p r i n t l n ( <html> ) ;
out . p r i n t l n ( <body> ) ;
out . p r i n t l n ( <h1>T i m e r S e r v l e t </h1> ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( sb . t o S t r i n g ( ) ) ;
out . p r i n t l n ( <p/> ) ;
out . p r i n t l n ( <a h r e f =\ i n d e x . html\> S t a r t Page</a> ) ;
out . p r i n t l n ( </body> ) ;
out . p r i n t l n ( </html> ) ;
}
public S t r i n g getSb ( ) {
return sb . t o S t r i n g ( ) ;
}
c l a s s MyTask extends TimerTask {
@Override
public void run ( ) {

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

C a l e n d a r c a l e n d a r=C a l e n d a r . g e t I n s t a n c e ( ) ;
S t r i n g time = c a l e n d a r . g e t ( C a l e n d a r .HOUR OF DAY)+ : +
c a l e n d a r . g e t ( C a l e n d a r .MINUTE)+
: +c a l e n d a r . g e t ( C a l e n d a r .SECOND) ;
sb . append ( <br/> ) ;
sb . append ( C u r r e n t time : +time ) ;

63
64
65
66
67
68

69

70
71

203

Apelarea - clientul Web - 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

< ! doctype html>


<body>
<center>
<h1> Timer </h1>
<form method= p o s t
action= / t i m e r / t i m e r >
<table>
<tr>
<td><l a b e l>Durata ( s e c u n d e )</ l a b e l></td>
<td>
<input type=number name= s e c o n d s s i z e= 5 >
</td>
<td>
<input type= submit value= S t a r t t i m e r name= s t a r t />
</td>
<td>
<input type= submit value= C u r r e n t s t a t e name= s t a t e />
</td>
<td>
<input type= submit value= Stop t i m e r name= s t o p />
</td>
</ tr>
</ table>
</form>
</ center>
</body>
</html>

8.5.6

Autentificare

Serverul Web apache-tomcat poate executa autentificarile basic si digest.


Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password).
Aceste informatii sunt retinute n serverul Web, n fisierul conf\tomcat-users.xml
fiind 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 autentificare solicitata


unui client se precizeaza n fisierul web.xml

204

CAPITOLUL 8. SERVLET

<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 fi definit un domeniu (realm).


In cazul apelarii dintr-un program Java a unui servlet, la care accesul presupune autentificare, aceasta se realizeaza prin intermediul claselor pachetului
httpcomponents-client:
import
import
import
import

org.apache.http.auth.AuthScope;
org.apache.http.auth.UsernamePasswordCredentials;
org.apache.http.impl.auth.BasicScheme;
org.apache.http.protocol.BasicHttpContext;

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

In cazul autentificarii digest, datele de identificare sunt criptate iar in cazul


autentificarii basic se utilizeaza codarea base64.

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

8.5.7

205

Servlet cu conexiune la o baz


a de date

Folosind Anexa H consideram


Exemplul 8.5.7 Consultarea unei agende de adrese e-mail. Se utilizeaza o
baza de date AgendaEMail alcatuita dintr-un singur tabel adrese (id int, nume
varchar(20), email varchar(30)).
Utilizand SGBD derby servlet-ul este
1
2
3
4
5
6
7
8
9
10
11
12
13
15
16
17
18
20
21
22
23
24
25
26
27

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

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

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

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

45

public void d e s t r o y ( ) {
try {
i f ( con != n u l l ) con . c l o s e ( ) ;

46
47

206

CAPITOLUL 8. SERVLET

}
catch ( SQLException e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}

48
49
50
51
52

54

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

55
56
57
58

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

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

89

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

90
91
92
93

Apelarea servlet-ului se face din


1
2
3
4
5
6
7
8
9
10

<html>
<body>
<h1> Cautare i n baza de d a t e AgendaEMail</h1>
<form method= g e t
action= / 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>

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

11
12
13
14
15
16
17

207

<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 verifica prezenta n catalogul servlet-ului ...\WEB-INF\lib a
fisierului derbyclient.jar sau mysql-connector-java-*-bin.jar.
(c) Pornirea serverului tomcat sau rencarcarea servlet-ului.
(d) Apelarea servlet-ului din pagina Web.

8.5.8

Imagini furnizate de servlet

Indicam doua modalitati prin care un client obtine o imagine furnizata de


un servlet. Imaginea poate proveni dintr-un fisier extern sau poate fi creata
de servlet.
Imaginea este transmisa direct clientului n fluxul de iesire de tip
ServletOutputStream, tipul MIME al raspunsului fiind
response.setContentType("image/ext");
ext {gif, jpg, png, . . .}.
Textul sursa al servlet-ului este:

1
2
3
4
5
6
7
8
10

package g r a p h g i f ;
import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
import j a v a . n i o . f i l e . Path ;

208

CAPITOLUL 8. SERVLET

12

import j a v a . n i o . f i l e . Paths ;
import j a v a . n i o . f i l e . F i l e s ;

14

@WebServlet ( u r l P a t t e r n s = / g r a p h g i f )

16

public c l a s s MyGraphG extends H t t p S e r v l e t {


public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;
S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
/
S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ;
S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ;
Path p a t h=Paths . g e t ( pathTomcat+f s +webapps+ f s+
c o n t e x t P a t h+f s + w a l k i n g s a n t a . g i f ) ;
/
S t r i n g pathApp=
r e q . g e t S e s s i o n ( ) . g e t S e r v l e t C o n t e x t ( ) . g e t R e a l P a t h ( / )+ f s ;
Path path=Paths . g e t ( pathApp+ w a l k i n g s a n t a . g i f ) ;
try {
r e s . setContentType ( image / g i f ) ;
F i l e s . copy ( path , out ) ;
}
catch ( E x c e p t i o n e ) {
r e s . setContentType ( t e x t / p l a i n ) ;
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
out . p r i n t l n ( C e r e r e a 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 ( ) ;
}
}

11

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

Pe calculatorul serverului Web, imaginea se salveaza ntr-un fisier grafic,


dupa care servlet-ul scrie n fluxul de iesire un document html cu o
legatura (link) catre fisierul cu imaginea creata anterior. Navigatorul
clientului va descarca si vizualiza imaginea.

1
2
3
4
5
6
7
8

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

15

import
import
import
import
import
import

17

@WebServlet ( u r l P a t t e r n s = / g r a p h j p g )

10
11
12
13
14

j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
j a v a x . i m a g e i o . ImageIO ;
j a v a . awt . Frame ;
j a v a . awt . Font ;
j a v a . awt . G r a p h i c s ;
j a v a . awt . image . B u f f e r e d I m a g e ;

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

19

public c l a s s MyGraphP extends H t t p S e r v l e t {


public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;
r e s . setContentType ( t e x t / html ) ;
P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
S t r i n g pathTomcat = new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ;
S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ;

21
22
23
24
25
26
27

S t r i n g f i l e R e f=pathTomcat+f s+ webapps +f s+c o n t e x t P a t h+f s ;


S t r i n g numeFis= d e s e n ;
S t r i n g e x t= j p g ;
// sau png , g i f
// 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 ) ;

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
46

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

48

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 , ext , f ) ;

49

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

51
52
53
54
55
56
57
58

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

59
60
61
62
63
64

65
66

209

8.5.9

Servlet cu RMI

Un servlet poate fi client al unei aplicatii RMI. Interfata la diatanta se


depune n catalogul WEB-INF\lib al servlet-ului. Apelarea programului server
RMI se face prin

210

CAPITOLUL 8. SERVLET

import java.rmi.Naming;
. . .
InterfataDistanta obj=(InterfataDistanta)
Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");
Exemplul 8.5.8 Client servlet pentru aplicatia RMI de calcul al celui mai
mare divizor comun a doua numere naturale.
1
2
3
4
5
6
7
8
9
11
12
14
15
16
17

import
import
import
import
import
import
import
import
import

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

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

19
20
21

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

23
24
25

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

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

45

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

46
47
48

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

49

211

8.5.10

Servlet cu JMS

De data aceasta cererea clientului se rezolva asincron:


In prima faza se apeleaza un servlet care apeleaza un server JMS. Solutia
este retinuta de furnizorul serviciului de mesagerie pe o destinatie cu un
subiect furnizat de client. Pentru regasirea rezultatului, servlet-ul creaza
clientului un abonament durabil, functie de numele subiectului.
In faza a doua, clientul apeleaza un alt servlet, a carei functie este preluarea rezultatului. Clientul trebuie sa furnizeze subiectul destinatiei
rezultatului.
Exemplul 8.5.9
Serverului JMS al aplicatiei este dat de clasa MsgCmmdcServer prezentat
n 5.3.11.
Codul servlet-ului care transmite datele problemei serverului JMS

12

package jms ;
import j a v a x . jms . Topic ;
import j a v a x . jms . JMSContext ;
import j a v a x . jms . JMSProducer ;
import j a v a x . jms . JMSConsumer ;
import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

14

@WebServlet ( u r l P a t t e r n s = / s e n d e r )

16

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 {

1
2
3
4
5
6
7
8
9
10
11

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

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=r e q . g e t P a r a m e t e r ( m ) ;
S t r i n g n=r e q . g e t P a r a m e t e r ( n ) ;
S t r i n g t o p i c=r e q . g e t P a r a m e t e r ( t o p i c ) ;
S t r i n g c l i e n t I D=r e q . g e t P a r a m e t e r ( c l i e n t I D ) ;
S t r i n g c l i e n t N a m e=r e q . g e t P a r a m e t e r ( c l i e n t N a m e ) ;
S t r i n g msg=m+ +n+ +t o p i c ;
try {
// V a r i a n t a OracleSun Message Topic
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 =

212

CAPITOLUL 8. SERVLET

new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;


// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( Cmmdc ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;

31
32
33
34
35

Topic t 1=new com . sun . m e s s a g i n g . Topic ( t o p i c ) ;


ctx . setClientID ( c l i e n t I D ) ;
JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t1 , c l i e n t N a m e ) ;

37
38
39

JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ;
p r o d u c e r . send ( t , msg ) ;

41
42

ctx .
out .
out .
out .
out .
out .

44
45
46
47
48
49

close ();
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 > ) ;
p r i n t l n ( <h1> JSP Cmmdc </h1> ) ;
p r i n t l n ( <p> ) ;
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 ) ;
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 ) ;

50
51
52
53
54
55
56

58

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

59
60
61
62

Codul servlet-ului care preia rezultatul

12

package jms ;
import j a v a x . jms . Topic ;
import j a v a x . jms . JMSContext ;
import j a v a x . jms . JMSConsumer ;
import j a v a x . jms . TextMessage ;
import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

14

@WebServlet ( u r l P a t t e r n s = / r e c e i v e r )

16

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 {

1
2
3
4
5
6
7
8
9
10
11

18
19
20
21
22
23
24

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

I DE PROGRAMARE CU SERVLET
8.5. FACILITAT

// S t r i n g c l i e n t I D =JMSCmmdc ;
// S t r i n g c l i e n t N a m e=JMSCmmdc ;
try {
// V a r i a n t a OracleSun Message Topic
com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y c f
= new com . sun . m e s s a g i n g . T o p i c C o n n e c t i o n F a c t o r y ( ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostName , h o s t ) ;
// c f . s e t P r o p e r t y ( imqBrokerHostPort , 7 6 7 6 ) ;
Topic t=new com . sun . m e s s a g i n g . Topic ( t o p i c ) ;
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
ctx . setClientID ( c l i e n t I D ) ;
JMSConsumer consumer = c t x . c r e a t e D u r a b l e C o n s u m e r ( t , c l i e n t N a m e ) ;
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 ( ) ;
ctx . 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 ) ;

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

54
55
56
57

213

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

8.5.11

Servlet cu jurnalizare

Exemplul 8.5.10 Servlet cu jurnalizare. Fisierul log se va afla n catalogul


aplicatiei si va fi oferit clientului spre consultare.

11

package l o g t e s t ;
import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import j a v a . u t i l . l o g g i n g . Logger ;
import j a v a . u t i l . l o g g i n g . F i l e H a n d l e r ;
import j a v a . u t i l . l o g g i n g . S i m p l e F o r m a t t e r ;

13

import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;

1
2
3
4
5
6
7
8
9
10

214

CAPITOLUL 8. SERVLET

15

@WebServlet ( u r l P a t t e r n s = / l o g g i n g )

17

public c l a s s L o g g e r S e r v l e t extends H t t p S e r v l e t {
private s t a t i c Logger l o g g e r=Logger . g e t L o g g e r ( l o g t e s t . L o g g e r S e r v l e t ) ;

18

public void i n i t ( ) {
try {
F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( webapps / l o g g e r / r e s u l t s . l o g ) ;
l o g g i n g F i l e . s e t F o r m a t t e r (new S i m p l e F o r m a t t e r ( ) ) ;
l o g g e r . addHandler ( l o g g i n g F i l e ) ;
}
catch ( IOException e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}
}

20
21
22
23
24
25
26
27
28
29

public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )


throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException {
S t r i n g f i l e S e p = System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;

31
32
33

l o g g e r . i n f o ( INFO : H e l l o ) ;
l o g g e r . warning ( WARN : H e l l o ) ;
l o g g e r . s e v e r e ( ERROR : H e l l o ) ;

35
36
37

r e s . setContentType ( t e x t / html ) ;
j a v a . i o . P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( <html><head><t i t l e >S e r v l e t l o g g i n g </ t i t l e ></head><body> ) ;
out . p r i n t l n ( <h2>H e l l o from L o g g e r S e r v l e t </h2> ) ;
out . p r i n t l n ( <br/> ) ;
out . p r i n t l n ( <a h r e f =\ h t t p : / / +
r e q . getServerName ()+ : +
r e q . g e t L o c a l P o r t ()+ f i l e S e p+
l o g g e r +f i l e S e p+ r e s u l t s . l o g \> V i z u a l i z a t i f i s i e r u l l o g </a> ) ;
out . p r i n t l n ( </body></html> ) ;
out . c l o s e ( ) ;

39
40
41
42
43
44
45
46
47
48
49
50

52

public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )


throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException {
doGet ( req , r e s ) ;
}

53
54
55
56

8.6

FileUpload

Deseori clientul trebuie sa furnizeze unui servlet un volum mare de date,


depozitate ntr-un fisier. Un produs care ne ajuta sa ndeplinim acest obiectiv
este commons-fileupload - dezvoltat de apache.
Commons-FileUpload - dezvoltat n cadrul apache - este un produs care
simplifica transferul unui fisier de la un client la programul server (file upload).
Interfata de programare a produsului se refera la partea de server - n cazul de

215

8.6. FILEUPLOAD

fata reprezentat prin servlet.


Instalarea produsului consta din dezarhivarea fisierului descarcat din Internet.
In plus este nevoie de
commons-io
Fisierele
commons-fileupload-*.*.jar
commons-io-*.*.jar
se depun n catalogul lib al servlet-ului.
Transferarea unui fisier, din partea clientului nu ridica nici o problema. In
fisierul html de apelare, se defineste un formular
<form
action=. . .
enctype="multipart/form-data"
method="post">
iar un fisier de ncarcat se fixeaza prin intermediul marcajului
<input type="file" name=. . . size=. . .>
Programul navigator afiseaza o fereastra de cautare, prin care clientul selecteaza fisierul pe care doreste sa-l ncarce.
Daca partea de client este un program, atunci se utilizeaza commonshttpclient, 8.5.1
Programarea ncarcarii revine la
1. Crearea unei fabrici pentru manipularea fisierelor pe disc
FileItemFactory factory = new DiskFileItemFactory();
2. Crearea unei unelte de ncarcare
ServletFileUpload

upload = new ServletFileUpload(factory);

3. Analiza (parsarea) mesajului furnizat de client


List fileItems = upload.parseRequest(req);

216

CAPITOLUL 8. SERVLET

Fiecare element al listei implementeaza interfata FileItem.


Se pot fixa parametrii
dimensiunea zonei de pe disc destinata datelor de ncarcat
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(maxMemorySize);
catalogul temporar de retinere a datelor de ncarcat
factory.setRepositoryPath(tempDirectory);
sau direct
DiskFileItemFactory factory = new DiskFileItemFactory(
maxMemorySize, tempDirectory);
dimensiunea maxima a unui fisier
upload.setSizeMax(maxRequestSize);
4. Prelucrarea elementelor ncarcate
Iterator iter=fileItems.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
// Prelucrarea elementului item care corespunde unei
// date din formularul html care nu este de tip fisier
}
else{
// Prelucrarea elementului item de tip fisier
}
}
5. In cazul unui element care nu este de tip fisier putem obtine numele si
valoarea atributului furnizat de client
String name = item.getFieldName();
String value = item.getString();
6. In cazul unui fisier putem afla numele campului input, numele fisierului,
dimensiunea fisierului

8.6. FILEUPLOAD

217

String fieldName = item.getFieldName();


String fileName = item.getName();
long sizeInBytes = item.getSize();
7. Daca dorim sa salvam fisierul pe calculatorul server atunci prelucrarea
este
File uploadedFile = new File(...);
item.write(uploadedFile);
8. Daca datele fisierului se ncarca n memoria calculatorului atunci prelucrarea este
InputStream in = item.getInputStream();
//preluarea datelor din fluxul in
. . .
in.close();
Alternativ, datele se pot retine ca un sir de octeti prin
byte[] data = item.get();
Exemplul 8.6.1 Sa se obtina n memoria serverului matricea continuta ntr fisierul text, fiecare linie contine o linie a matricei, iar eleun fisier text. In
mentele sunt separate prin spatii.
Metoda getMatrix utilizata va reface matricea din datele fisierului.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

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

218

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

CAPITOLUL 8. SERVLET

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


8.7. DESCARCAREA
UNUI FIS
IER

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

79
80
81
82
83
84
85
86
87
88
89
90
91

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

92
93
94
95
96

97
98

219

Pentru compilare se completeaza variabila de sistem classpath cu referinta


catre fisierul commons-fileupload-*.*.jar.
Formularul clientului este
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

< ! doctype html>


<body bgcolor=#bbccbb >
<h1> I n c &#259; r c a r e a unui f i &#351; i e r </h1>
<form
action= / u pl oa d / u pl oa d
e n c t y p e= m u l t i p a r t / formdata
method= p o s t
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 r e q u i r e d>
<p>
<input type= submit value= Expediaza f i s i e r u l >
</form>
</body>
</html>

8.7

Desc
arcarea unui fisier

Consideram cazul:
Exemplul 8.7.1 Fisierul ales de client dintr-o lista disponibila este descarcat
fiind transmis navigatorului.
1
2

import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;

220

CAPITOLUL 8. SERVLET

10

import
import
import
import
import
import
import
import

12

@WebServlet ( u r l P a t t e r n s = / download )

14

public c l a s s D o w n l o a d S e r v l e t extends H t t p S e r v l e t {
public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ;
S t r i n g f i l e =r e q . g e t P a r a m e t e r ( f i l e ) ;
System . out . p r i n t l n ( f i l e ) ;
Path c a l e=Paths . g e t ( webapps / download / r e s o u r c e s / + f i l e ) ;
try {
System . out . p r i n t l n ( c a l e+ f i l e ) ;
r e s . setContentType ( A p p l i c a t i o n / 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 ) ;
F i l e s . copy ( c a l e , out ) ;
}
catch ( E x c e p t i o n e ) {
r e s . setContentType ( t e x t / p l a i n ) ;
out . p r i n t l n ( C e r e r e a 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 ( ) ;
}

3
4
5
6
7
8
9

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

. http . HttpServlet ;
. http . HttpServletRequest ;
. http . HttpServletResponse ;
. ServletOutputStream ;
. a n n o t a t i o n . WebServlet ;
. Path ;
. Paths ;
. Files ;

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

34
35
36
37
38

javax . s e r v l e t
javax . s e r v l e t
javax . s e r v l e t
javax . s e r v l e t
javax . s e r v l e t
java . nio . f i l e
java . nio . f i l e
java . nio . f i l e

Randul 18 are ca efect pastrarea numelui si a extensiei pentru fisierul selectat


a se descarca.

8.8

Filtru

Un filtru se asemeana unui servlet, dar activitatea ntreprinsa vizeaza uzual


contextul, adica ansamblul servletilor care fac parte din aplicatia Web.
Din nou tehnica de programare poate fi:
Descriptiv. Filtrul se declara n fisierul web.xml prin
<web-app>
. . .
<filter>

8.8. FILTRU

221

<filter-name>nume_filtru</filter-name>
<filter-class>clasa_filtrului</filter-class>
</filter>
<filter-mapping>
<filter-name>nume_filtru</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
. . .
</web-app>
Programat. Se utilizeaza adnotarea WebFilter
. . .
import javax.servlet.annotation.WebFilter;
@WebFilter(filterName="MyFilterDispatcher",urlPatterns={"/*"})
public class MyFilterDispatcher implements Filter {. . .}
Clasa filtrului implementeaza interfata Filter, adica metodele
public void init(FilterConfig filterConfig) throws ServletException
public void destroy()
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain filterChain)
throws IOException, ServletException
Exemplul 8.8.1 Contextul filtrud contine doi servleti HelloServlet si CmmdcServlet, apelabili respectiv din hello.html, cmmdc.html. Sa se programeze un
filtru care
Redirecteaza solicitarea /filtrud/hello catre /cmmdc.html.
Daca se cere ca natura raspunsului sa fie text/xml atunci invalideaza
cererea.
Servletii HelloServlet si CmmdcServlet sunt cei dezvoltati la nceputul acestui capitol. Filtrul (n varianta descriptiva) are codul

222

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

import
import
import
import
import
import
import
import
import
import

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

public c l a s s M y F i l t e r D i s p a t c h e r implements F i l t e r {
private F i l t e r C o n f i g f i l t e r C o n f i g ;
public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws S e r v l e t E x c e p t i o n {
this . f i l t e r C o n f i g = f i l t e r C o n f i g ;
}

15
16
17

public void d e s t r o y ( ) {
this . f i l t e r C o n f i g = null ;
}

19
20
21

public void d o F i l t e r ( S e r v l e t R e q u e s t r e q u e s t , S e r v l e t R e s p o n s e r e s p o n s e ,
F i l t e r C h a i n f i l t e r C h a i n ) throws IOException , S e r v l e t E x c e p t i o n {
HttpServletRequest req = ( HttpServletRequest ) request ;
HttpServletResponse res = ( HttpServletResponse ) response ;
S t r i n g u r i = r e q . getRequestURI ( ) ;
System . out . p r i n t l n ( F i l t e r URI= +u r i ) ;
System . out . p r i n t l n ( u r i ) ;

23
24
25
26
27
28
29

i f ( u r i . equals ( / f i l t r u d ) | | u r i . equals ( / f i l t r u d / ) )
f i l t e r C h a i n . doFilter ( request , response ) ;
else {
i f ( u r i . equals ( / f i l t r u d / h e l l o )){
S t r i n g d i s p a t c h e r U r i= /cmmdc . html ;
R e q u e s t D i s p a t c h e r rd=r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( d i s p a t c h e r U r i ) ;
rd . f o r w a r d ( r e q u e s t , r e s p o n s e ) ;
}
else {
i f ( u r i . e q u a l s ( / f i l t r u d /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 ) ;
}
}

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

49
50

CAPITOLUL 8. SERVLET

Fisierul web.xml este

<?xml version= 1 . 0 e n c o d i n g=ISO88591 ?>


< !DOCTYPE webapp
PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN
h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd >

<webapp>

1
2
3

8.9. EVENIMENT S
I AUDITOR

7
8
9
10
12
13
14
15
16

223

< 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 ntelegerea aplicatiei prezentam si codul fisierului cmmdc.html


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

<html>
<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= / m y s e r v l e t /cmmdc>
<table border= 1 >
<tr>
<td> Primul numar </td>
<td> <input type= t e x t name=m s i z e =10> </td>
</ tr>
<tr>
<td> Al d o i l e a numar </td>
<td> <input type= t e x t name=n s i z e =10> </td>
</ tr>
<tr>
<td> Natura r a s p u n s u l u i </td>
<td> <s e l e c t name= t i p >
<option value= t e x t / html > t e x t / html
<option value= t e x t / p l a i n > t e x t / p l a i n
<option value= t e x t /xml> t e x t /xml
</ s e l e c t> </td>
</ tr>
<tr>
<td> <input type= submit value= C a l c u l e a z a > </td>
<td></td>
</ tr>
</ table>
</form>
</ center>
</body>
</html>

8.9

Eveniment si auditor

Tehnologia Servlet permite urmarirea si interventia de catre serverul Web


n:
ciclul de viata al unui servlet, prin interfata
javax.servlet.ServletContextListener

224

CAPITOLUL 8. SERVLET

evolutia obiectului javax.servlet.http.HttpSession prin interfata


javax.servlet.http.HttpSessionListener
Interfata ServletContextListener declara metodele
void contextInitialized(ServletContextEvent sec)
void contextDestroyed(ServletContextEvent sec)
Interfata HttpSessiontListener declara metodele
void sessionCreated(HttpSessionEvent hse)
void sessionDestroyed(HttpSessionEvent hse)
Clasa care implementeaza una din aceste interfete se declara n fisierul
web.xml printr-un element <listener>>
<listener>
<listener-class> clasa_listener </listener-class>
</listener>
Exemplul 8.9.1 Auditor care sesizeaza ncarcarea si disparitia unui servlet
afisand n fereastra DOS a serverului Web un mesaj.
1
2
3
5
6
7
8
9
10
11
12
13
14
15
16
17

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

Exemplul 8.9.2

8.10. SERVER APACHE-TOMCAT INCORPORAT

1
2
4
5

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

7
8
9
10
11
12
13
14
15
16

225

8.10

Server apache-tomcat ncorporat

Intr-o clasa Java se poate ncorpora un server tomcat n care pot fi instalate
una sau mai multi serveti. Resursele necesare sunt continute n apache-tomcat*-embedded, iar fisierele jar continute trebuie declarate n variabila de sistem
classpath.
Sablonul de programare este:
1
2
3
5
6
7
8
9
10

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

12
13

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

15
16

tomcat . s t a r t ( ) ;
tomcat . g e t S e r v e r ( ) . a w a i t ( ) ;

18
19

}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

20
21
22
23

24
25

Probleme

226

CAPITOLUL 8. SERVLET

Servlet API 3.1 : Upgrade prin tomcat

Intreb
ari recapitulative
1. Precizati sensurile si continutul cuvantului servlet.
2. Unde se instaleaza o aplicatie servlet n serverul Web apache-tomcat?
3. Cum se poate apela aplicatia servlet, dar servlet-ul propriu zis?
4. Extinzand clasa HttpServlet, ce trebuie sa faca programatorul?
5. Care sunt modurile de programare a unui servlet si precizati diferenta
dintre ele.
6. Care sunt sarcinile de indeplinit n metoda doGet?
7. Cum se rezolva solicitatarea clientului ntr-un servlet asincron conform
Servlet-API 3.0 ?
8. Cum se rezolva solicitatarea clientului ntr-un servlet asincron conform
Servlet-API 3.1 ?
9. Ce posibilitate de prelucrare ofera un filtru?
10. Ce posibilitate ofera clasa javax.servlet.http.Cookie?
11. Ce posibilitate ofera clasa javax.servlet.http.HttpSession?
12. Care sunt metodele de programare asincrona a unui servlet?

Capitolul 9
Java Server Page JSP
9.1

Tehnologia JSP

Tipul tehnologiei JSP este denumit procesare de sabloane (template engine). JSP este o tehnologie similara cu PHP, ASP.NET, apache-velocity, etc.
JSP permite includerea de cod Java ntr-un document html. Un asemenea
document se depoziteaza ntr-un server Web, container de servlet, cu extensia
jsp, eventual jspx.
Apelarea documentului JSP se realizeaza prin
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 ntelege calea de la catalogul webapps pana la catalogul ce


contine fisierul jsp.
Vom depozita fisierele JSP ntr-un catalog jsp din arborele
webapps
|--> JSPApp
|
|--> WEB-INF
|
|
|--> classes
|
|
|
web.xml
227

228
|
|

CAPITOLUL 9. JAVA SERVER PAGE JSP

|--> jsp
|
|

doc.jsp

caz n care cale=JSPApp/jsp.


Astfel, schimband numele fisierului Hello.html
1
2
3
4
5

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

n Hello.jsp si plasandu-l n catalogul jsp se obtine acelasi efect, dar prelucrarea paginilor / documentelor este diferita. Fisierul html este prelucrat doar
de programul navigator si poate fi deschis ca fisier, n timp ce fisierul JSP este
prelucrat de serverul Web cu afisarea prin intermediul navigatorului. Prelucrarea efectuata de serverul Web consta din transformarea paginii / documentului JSP ntr-un servlet, care este compilat si lansat n executie. Din aceastra
cauza prima invocare a paginii / documentului JSP dureaza mai mult decat
apelarile ulterioare.
Fisierul JSP poate fi construit pe un document xhtml, avand preambulul
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
sau document html 5. In acest caz preambulul este
<!doctype html>
Apelarea paginii / documentului JSP se face prin jsp/Hello.jsp
Exista doua moduri de a include elemente JSP ntr-un text html:
prin elemente specifice JSP.
Fisierul are extensia jsp si se numeste pagina JSP.
prin elemente xml apartinand spatiului de nume
http://java.sun.com/JSP/Page
Fisierul poate avea extensia jsp sau jspx si se numeste document JSP.
Comentariile JSP se scriu de forma
<%-- Comentariu --%>

229

9.1. TEHNOLOGIA JSP

Consideram urmatorul exemplu introductiv:


Exemplul 9.1.1 Putem afisa valoarea unei variabile Java (de exemplu data
calendaristica) prin
Varianta paginii JSP
1
2
3
4
5
7
8
9
10
12
13
14
15
16
17

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

Daca se utilizeaza operatorul de afisare = atunci dupa expresia de afisat


nu se pune ;.
Variabila predefinita out este de tip javax.servlet.jsp.JspWriter.
Varianta documentului JSP
1
2
3
4
5
6
7
8
9

<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?>


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

Codul Java nglobat ntr-un text html se numeste scriptlet. Sintaxa utilizata este
Varianta paginii JSP
<% cod Java %>

230

CAPITOLUL 9. JAVA SERVER PAGE JSP

Varianta documentului JSP


<jsp:scriptlet> codJava </jsp:scriptlet>
Domeniul de valabilitate. Domeniul de valabilitate defineste intervalul
de timp, de existenta al unui obiect, fiind definit prin valorile:
Valoare
page
request

Domeniu de valabilitate
pagina curenta
n pagina curenta,
n paginile incluse si
n paginile catre care se face o redirectare
session
n sesiunea curenta
application pe durata rularii aplicatiei
In orice pagina
Variabila
out
request
response
session
page
pageContext
application
exception

/ document JSP sunt predefinite 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.getServletConfig().getContext()
java.lang.Throwable

Astfel
String request.getParameter(String numeParametru)
furnizeaza valoarea parametrului numeParametru dintr-un formular html.
Exemplul 9.1.2 Pagina JSP Hello: Clientul transmite numele paginii care i
raspunde cu mesajul de salut Hi + nume + !.
Codul paginii JPS (hello.jsp) este
1
2
3
4
5

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

9.1. TEHNOLOGIA JSP

6
7
8
9
10
11
12
13
14

231

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

apelat din (index.html )


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

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

Compilarea si arhivarea servlet-ului o vom realiza prin intermediul lui


apache-ant. In acest scop se creaza structura:
jsphello
|
|--> src
|
|--> web
|
|
|
|--> jsp
|
|
|
|
hello.jsp
|
|
|--> WEB-INF
|
|
|
|--> classes
|
|
|
|--> lib
|
|
|
|
web.xml
|
|
|
index.html

Fisierul build.xml este simplu


1
2
3
5
6
7
8
9
11
12

<p r o j e c t b a s e d i r= . default= g e n e r a t e . war >


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

232

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

CAPITOLUL 9. JAVA SERVER PAGE JSP

<d e l e t e d i r=web/WEBINF/ c l a s s e s />


<mkdir d i r=web/WEBINF/ c l a s s e s />
<mkdir d i r= ${ d i s t . d i r } />
</ t a r g e t>
<t a r g e t name= c o m p i l e depends= i n i t >
<j a v a c c l a s s p a t h r e f= m y c l a s s p a t h
s r c d i r= s r c
d e s t d i r=web/WEBINF/ 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 >
<j a r d e s t f i l e = ${ d i s t . d i r }/${ d i s t . name } . war b a s e d i r=web />
</ t a r g e t>
</ p r o j e c t>

9.1.1

Declaratii JSP

Printr-o declaratie JSP, putem defini campuri(variabile) si metode Java ce


pot fi apoi folosite, respectiv apelate n documentul respectiv. O declaratie
JSP se defineste printr-un marcaj
<%! . . . %>
sau, n format XML
<jsp:declaration> . . . </jsp:declaration>
Exemplul 9.1.3 Calculul celui mai mare divizor comun a doua numere naturale cu metoda de calcul este definita ntr-o declaratie JSP.
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 ) ;
l o n g 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

9.1. TEHNOLOGIA JSP

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

233

< ! doctype html>


<head>
<meta charset= u t f 8>
</head>
<body bgcolor=#bbccbb >
<center>
<h1> Pagina de a p e l a r e CmmdcServlet </h1>
<form method= g e t
action= j s p /cmmdc . j s p >
<table>
<tr>
<td><l a b e l> Primul numar </ l a b e l></td>
<td>
<input type=number name=m s i z e= 5
r e q u i r e d min= 1 >
</td>
</ tr>
<tr>
<td><l a b e l> Al d o i l e a numar </ l a b e l></td>
<td>
<input type=number name=n s i z e= 5
r e q u i r e d min= 1 >
</td>
</ tr>
<tr>
<td>
<p><input type= submit value= C a l c u l e a z a >
</td>
</ tr>
</ table>
</form>
<center>
</body>
</html>

Exista doua metode jspInit() si jspDestroy() care daca sunt declarate


de programator atunci sunt executate la nceputul si la sfarsitul ciclului de
viata a paginii / documentului JSP.
Exemplul 9.1.4 Metoda jspInit initializeaza un numar cu 0 iar metoda
jspDestroy afiseaza numarul pe calculatorul serverului. Un client introduce
un numar care este adunat la cel retinut de pagina JSP.
Efectul metodei jspDestroy are loc n urma opririi aplicatiei JSP.
Codul paginii JSP este
1
2
3
4
5
6
7
8

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

234

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

CAPITOLUL 9. JAVA SERVER PAGE JSP

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>

9.1.2

Directive JSP

Directivele JSP fixeaza informatii pentru tot documentul jsp. O directiva


jsp se indica prin marcajul
<%@ directiva atribut1 atribut2 . . . %>
sau n format XML
<jsp:directive.directiva atribut1 atribut2 . . . />
unde fiecare atribut are sintaxa nume=valoare.
Directivele pot fi: page, include, taglib.
Directiva page. Mentionam atributele
lista de pachete separate prin ,
text Informatia se poate regasi apeland metoda
getServletInfo()
errorPage=
adresa url a paginii ce trateaza exceptia
isErrorPage= "true | false"
import=
info=

Directiva include permite includerea unor fisiere .html sau .jsp n document
<%@ include file=fisier html, jsp %>

235

9.1. TEHNOLOGIA JSP

Includerea are loc n locul n care apare directiva.


Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSP
initiale (adica cea n care apare directiva).
Directiva taglib indica bibliotecile de marcaje utilizate n documentul
jsp, avand atributele
uri=
uri - Universal Resource Identifier - a bibliotecii de marcaje
prefix= prefixul marcajului

9.1.3

Marcaje JSP predefinite

Un marcaj JSP defineste o actiune care se executa n timpul procesarii


paginii jsp. Sintaxa marcajelor JSP seamana cu cea a marcajelor html sau
xml
<prefix :

marcaj atribute />

Dintre marcajele JSP predefinite adica cu prefixul JSP amintim:


<jsp :

include page=numeFisier jsp sau html />

<jsp :

forward page=numeFisier jsp sau html />

Prelucrarea care urmeaza va fi cea din fisierul mentional. Diferenta dintre


cele doua elemente consta n faptul ca include prevede revenirea n
pagina JSP initiala iar forward nu.
Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSP
initiale.
In cazul marcajelor <jsp: include>, <jsp: forward> se pot transmite parametri prin marcajele incluse
<jsp:param name="nume" value=valoare "/>
sau
<jsp:params>
<jsp:param name="nume" value=valoare "/>
. . . . . .
</jsp:params>

236

CAPITOLUL 9. JAVA SERVER PAGE JSP

<jsp :

useBean id=numeComponentaJava
class=numeClasa
scope=domeniu />

unde domeniu precizeaza domeniul de valabilitate al componentei Java,


adica page, request, session, application.
Creaza un obiect numeComponentaJava de tip numeClasa avand
domeniul de valabilitate data de domeniu.
<jsp :

setProperty name=numeComponentaJava
property=numeProp
value=valoare/>

Acest marcaj este echivalent cu codul Java


numeComponentaJava.setNumeProp(valoare).
<jsp : setProperty name=numeComponentaJava property="*" />
vizeaza toate proprietatile componentei Java, fixarea valorilor facanduse cu datele unui formular. Numele parametrilor din formularele de introducere a datelor trebuie sa coincida cu identificatorii campurilor din
componenta Java corespunzatoare.
<jsp :

getProperty name=numeComponentaJava
property=numeProp/>

Preia si afiseaza valoarea campului numeComponentaJava.numeProp.

9.1.4

Pagini JSP cu componente Java

Clasa componentei Java care se va utiliza ntr-o pagina JSP trebuie inclusa
ntr-un pachet.
Reluam exemplul 9.1.2 cu o componenta Java corespunzatoare numelui din
formularul index.html.
Exemplul 9.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 ;
}
}

9.1. TEHNOLOGIA JSP

237

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


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

<j s p : useBean id= o b j c l a s s= j s p . H e l l o B e a n scope= r e q u e s t />


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

Mai mult, se poate include formularul n pagina JSP, binenteles stergandu-l


din fisierul html:
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>

Exemplul 9.1.6 Pagina JSP pentru calculul celui mai mare divizor comun
cu metoda de calcul definita ntr-o componenta Java.
Utilizand documentului html din Exemplul 9.1.3 se defineste componenta
Java
1
2
3
4
5

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 ;

238

CAPITOLUL 9. JAVA SERVER PAGE JSP

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

7
8
9
10
11
12
13
14
15
16
17
18

24

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

26

long cmmdc( long m, long n ) { . . . }

20
21
22
23

28

Instantiem o componenta Java si i fixam proprietatile (adica i transmitem


parametri problemei) dupa care apelam metoda ce calculeaza rezultatul dorit
n pagina JSP:
1
2
3
4
5
6
7
8
9
10

<j s p : useBean id= o b j c l a s s=cmmdc . CmmdcBean scope= a p p l i c a t i o n />


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

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

9.2. JSP STANDARD TAG LIBRARY JSTL

239

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

9.2

JSP Standard Tag Library JSTL

JSTL este o familie de biblioteci de marcaje ce ofera o serie de facilitati


activitatii de realizare a paginilor Web. JSTL ajuta la separarea activitatii de
programare de proiectarea (design) paginii Web.

240

CAPITOLUL 9. JAVA SERVER PAGE JSP

JSTL este alcatuita din 5 biblioteci:


URI
http://java.sun.com/jsp/jstl/core
http://java.sun.com/jsp/jstl/xml

Descriere
Biblioteca de baza
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 ajutatoare

Instalarea bibliotecilor. Bibliotecile sunt livrate mpreuna cu apachetomcat-* n catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin
fisierele taglibs-standard-spec-*.jar si taglibs-standard-impl-*.jar.
Utilizarea bibliotecilor. In vederea utilizarii, cele doua fisiere trebuie
copiate n catalogul lib al aplicatiei care utilizeaza bibliotecile.
In pagina / documentul JSP, o biblioteca utilizata trebuie declarata printro directiva taglib.

9.2.1

Biblioteca de baz
a

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


Marcaje din biblioteca de baza:
c:set Fixeaza o valoare ntr-o variabila.
Atribute ale marcajului:
Atribut Fel
Descriere
var
obligatoriu Numele variabilei ce va stoca valoarea
expresiei.
value
optional
Expresia care va fi evaluata si atribuita
variabilei
scope
optional
Domeniul de valabilitate al variabilei.
Unul din valorile:
page, request, session, application.
Referirea la o variabila se face prin sintaxa ${numeVariabila }
Referirea la valoarea unui camp dintr-un formular se face prin
${param.numeCamp}
Alaturi de obiectul param, alte obiecte predefinite sunt cookie, header,
initParam, pageContext.

9.2. JSP STANDARD TAG LIBRARY JSTL

241

Se pot defini variabile cu acelasi nume dar avand domenii de valabilitate


diferita. Referirea se face prin ${pageScope.numeVariabila },
${requestScope.numeVariabila }, ${sessionScope.numeVariabila },
${applicationScope.numeVariabila }.
Plasand clauza empty naintea unei variabile, ${empty numeVariabila },
se obtine false sau true dupa cum variabila are sau nu atribuita o
valoare.
c:remove Sterge o variabila.
Atribute ale marcajului:
Atribut Fel
Descriere
var
obligatoriu Numele variabilei ce se sterge.
scope
optional
Domeniul de valabilitate al variabilei.
Unul din valorile:
page, request, session, application.
c:out Afiseaza o valoare.
Atribute ale marcajului:
Atribut
value
default

Fel
Descriere
obligatoriu Valoarea ce se evalueaza si se afiseaza.
optional
Cea ce se afiseaza n cazul n care
expresia nu poate fi evaluata.
escapeXml optional
true / false. Valoarea implicita este true.
Pe false interpreteaza caracterele din value
ca si cod html.
c:if Test, verificarea 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
definita anterior.
In cazul n care conditia are valoarea true se prelucreaza corpul marcajului, n caz contrar, acesta este ignorat.

242

CAPITOLUL 9. JAVA SERVER PAGE JSP

Exemplul 9.2.1 Preluarea datelor unui formular cu campurile de intrare nume, prenume si email se face prin pagina JSP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

<HTML>
<%@ 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 %>
<BODY>
<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 >
<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>
</BODY>
</HTML>

c:choose Marcajul de selectie poate contine oricate marcaje c:when


si cel mult un marcaj c:otherwise. Fiecare marcaj c:when contine
obligatoriu atributul test. Daca ntr-un marcaj c:when conditia are
valoarea true, atunci se prelucreaza corpul acelui marcaj. In cazul n care
toate marcajele c:when au fost evaluate cu false atunci se va prelucra
marcajul c:otherwise (marcaj fara atribute).
c:forEach Ciclu.
Atribute ale marcajului:
Atribut
items
var

Fel
Descriere
optional Colectia care se parcurge.
optional Numele variabilei n care se stocheaza
valoarea elementului curent.
begin
optional Valoarea initiala a variabilei var.
end
optional Valoarea finala a variabilei var.
step
optional Valoarea pasului de iterare. Implicit este 1.
varStatus optional Informatii despre elementul curent.

9.2. JSP STANDARD TAG LIBRARY JSTL

243

Variabila varStatus are campurile:


index valoarea curenta a elementului dupa care se realizeaza ciclarea;
count numarul iteratiei curente;
first are valoarea true daca este primul element al ciclului;
last are valoarea true daca este ultimul element al ciclului;
Exemplul 9.2.2 Lista parametrilor formularului de apelare a exemplului anterior se afiseaza prin:
<h2> Lista parametrilor din formular </h2>
<ul>
<c:forEach items="${param}" var="p">
<li>
<c:out value="${p.key}"/> = <c:out value="${p.value}" />
</li>
</c:forEach>
</ul>

Exemplul 9.2.3 Lista parametrilor unui header se afiseaza prin:


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

Exemplul 9.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 Asigura aceasi functionalitate ca si clasei java.util.String


Tokenizer.
Atribute ale marcajului:

244

CAPITOLUL 9. JAVA SERVER PAGE JSP

Atribut
value

Fel
Descriere
obligatoriu Valoarea ce se evalueaza si se afiseaza.
expresiei.
default
optional
Cea ce se afiseaza n cazul n care
expresia nu poate fi evaluata.
escapeXml optional
true / false. Valoarea implicita este true.
Pe false interpreteaza caracterele din value
ca si cod html.
c:import Permite includerea altor pagini JSP n pagina curenta.
Atribute ale marcajului:
Atribut Fel
Descriere
url
obligatoriu Adresa documentului importat.
context optional
Context-ul paginii / documentului importat.
Simbolul /, urmat de numele unei aplicatii
de pe acelasi server.
var
optional
Numele variabilei n care va fi stocat
documentul importat.
scope
optional
Domeniul de valabilitate al variabilei var.
Unul din valorile:
page, request, session, application.
Cu marcajul c:param se pot fixa parametri pentru pagina importata.
Acest marcaj are doua atribute name si value. Acesti parametri se
transmit cu metoda get.
c:redirect Redirectarea activitatea catre o alta pagina.
Atribute ale marcajului:
Atribut Fel
Descriere
url
obligatoriu Adresa paginii catre care se face redirectarea.
context optional
Context-ul paginii catre care se face redirectarea.
Simbolul /, urmat de numele unei aplicatii
de pe acelasi server.
Prin redirectare, parametrii nu sunt retransmisi automat mai departe.
c:url Retine adrese URL.
Atribute ale marcajului:

245

9.2. JSP STANDARD TAG LIBRARY JSTL

Atribut Fel
Descriere
value
obligatoriu Adresa documentului de retinut.
context optional
Context-ul documentului.
Simbolul /, urmat de numele unei aplicatii
de pe acelasi server.
var
optional
Numele variabilei n care va fi stocata
adresa documentului.
scope
optional
Domeniul de valabilitate al variabilei var.
Unul din valorile:
page, request, session, application.

9.2.2

Biblioteca de lucru cu baze de date

<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>


Marcaje din biblioteca de baza:
sql:setDataSource Fixeaza referinta la baza de date.
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

Fel
obligatoriu
optional
optional
optional
obligatoriu

scope

optional

Descriere
Fraza sql
Referinta la baza de date
Linia de la care se ncepe interogarea
Numarul maxim de rezultate acceptate
Variabila cu rezultatele interogarii
bazei de date
Domeniul de valabilitate al variabilei var.

246

CAPITOLUL 9. JAVA SERVER PAGE JSP

sql:update Actualizarea bazei de date.


Atribute ale marcajului:
Atribut
Fel
Descriere
sql
obligatoriu Fraza sql
dataSource optional
Referinta la baza de date
Exemplul 9.2.5 Sa se afiseze lista din agenda de adrese e-mail creata n
exemplul din Cap. Servlet.
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

<HTML>
<%@ 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 %>
<BODY>
<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>
</BODY>
</HTML>

9.3

Marcaje JSP personale

Programatorul poate crea marcaje JSP proprii care se grupeaza n colectii


numite biblioteci de marcaje. O biblioteca de marcaje este reprezentata de un
identificator, pe care-l vom denumi identificatorul bibliotecii de marcaje.

9.3. MARCAJE JSP PERSONALE

9.3.1

247

Marcaje f
ar
a atribute si f
ar
a corp.

Pentru a crea unui asemenea marcaj JSP propriu este necesara definirea
urmatorelor componente:
1. O clasa de definitie a comportamentului marcajului JSP (tag handler
class).
2. Descriptorul bibliotecii de marcaje JSP, care leaga clasa de definitie a
marcajului cu identificatorul bibliotecii de marcaje. Acest descriptor
este un fisier cu extensia tld. Serverul Web va depista descriptorul
bibliotecii de marcaje n catalogul aplicatiei.
3. Fisierul JSP ce utilizeaza marcajul JSP (clientul).
Exemplificam acesta tehnologie prin
Exemplul 9.3.1 Sa se realizeze un marcaj dateTag, a carui efect sa fie afisarea
datei calendaristice.
1. Clasa de definitie a comportamentului marcajului. Programul consta
din:
(a) Importul pachetelor
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
Aceste pachete se gasesc n fisierul jsp-api.jar.
(b) Un marcaj fara atribute si fara corp trebuie sa extinda clasa TagSupport
si sa suprascrie metoda doStartTag, care defineste activitatea intreprinsa cand este ntalnit marcajul ntr-un document jsp. Metoda
trebuie sa returneze constanta SKIP BODY.
public class NumeClasa extends TagSupport{
public int doStartTag(){
. . .
return SKIP_BODY;
}
}

248

CAPITOLUL 9. JAVA SERVER PAGE JSP

(c) Scrierea n fluxul de iesire se face cu un obiect JspWriter, care se


obtine cu pageContext.getOut(). Metoda print a clasei JspWriter
poate genera o exceptie IOException.
Textul sursa al clasei de definitie a comportamentului marcajului dateTag
este:

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

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

2. Descriptorul bibliotecii de marcaje JSP este dependent de versiunea tomcat folosita. Acest fisier trebuie sa aiba extensia tld (Taglib Language
Definition).

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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< ! 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 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 /webj s p t a g l i b r a r y 2 0 . xsd
version= 2 . 0 >
<t l i b version> 1 . 0 </ t l i b version>
<j s p version> 2 . 0 </ j s p version>
<s h o r t name> m y t a g s l i b r a r y </ s h o r t name>
<u r i>mytags</ 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>

249

9.3. MARCAJE JSP PERSONALE

Elementul uri contine identificatorul bibliotecii de marcaje, mytags.


Pentru fiecare marcaj propriu se completeaza un marcaj tag. Pentru un
marcaj propriu fara atribute elementele acestui marcaj sunt
(a) name Numele simbolic al marcajului.
(b) tag-class Referinta la fisierul class al clasei de definitie a comportamentului marcajului propriu. Referinta se face relativ la catalogul
...\WEB-INF\classes
(c) description Descrierea marcajului propriu.
(d) body-content In cazul nostru are valoarea EMPTY. In cazul unui
marcaj cu corp se da valoarea JSP.
Astfel elementele constitutive se vor gasi n:
webapps
|--> mytag
|
|--> WEB-INF
|
|
|--> classes
|
|
|
|--> jsp
|
|
|
|
|--> DateTag.class
|
|
|
mylibtag.tld
|
|--> jsp
|
|
|
dateTag.jsp
3. Marcajele proprii se utilizeaza cu sintaxa
<prefix : NumeMarcaj />
Referinta la identificatorul bibliotecii de marcaje si prefixul se fixeaza n
directiva taglib.
Un fisier jsp care utilizeaza marcajul realizat este (dateTag.jsp):

1
2
3
4
5
6
7
8

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

250

CAPITOLUL 9. JAVA SERVER PAGE JSP

9
10
11
12
13
14

p r e f i x=mk %>
<p>
Data c u r e n t a e s t e :
<mk : dateTag />
</body>
</html>

apelat din
1
2
3
4
6
7
8
9
10

<html>
<body>
<form method= g e t
action= j s p / dateTag . j s p >
Data c a l e n d a r i s t i c &#259;:
<p><input type= submit value= A f i s e a z a >
</form>
</body>
</html>

9.3.2

Marcaje cu atribute si f
ar
a corp.

Realizam un marcaj ziuaTag cu un atribut ziua care va fi afisat n momentul


prelucrarii marcajului.
1. Pentru fiecare atribut clasa ce defineste actiunea marcajului trebuie sa
contina o metoda
public void setNumeAtribut(String value){...}
care preia valoarea atributului data de parametrul value.
Exemplul 9.3.2
Pentru exemplul enuntat aceasta clasa este

1
2
3
4
6
7
9
10
11

package j s p ;
import j a v a x . s e r v l e t . j s p . J s p W r i t e r ;
import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ;
import j a v a . i o . IOException ;
public c l a s s ZiuaTag extends TagSupport {
String ziua ;
public void s e t Z i u a ( S t r i n g v a l u e ) {
z i u a=v a l u e ;
}

251

9.3. MARCAJE JSP PERSONALE

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

13
14
15
16
17
18
19
20
21
22
23

2. In descriptorul bibliotecii de marcaje pentru fiecare atribut se defineste


un marcaj <attribute>...< /attribute> avand incluse marcajele
Nume marcaj
Semnificatie
name
numele atributului
required
true | false dupa cum atributul e
obligatoriu sau nu
rtexprvalue
true | false dupa cum atributul
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 exemplificat n

1
2
3
4
5
6
7
8
9

<html>
<body>
<form method= g e t
action= j s p / ziuaTag . j s p >
<p>A s t a z i , e s t e
<s e l e c t name= z i u a >
<option value= l u n i > Luni
<option value= m a r t i > Marti
<option value= m i e r c u r i > M i e r c u r i

252

CAPITOLUL 9. JAVA SERVER PAGE JSP

10
11
12
13
14
15
16
17
18

<option value= j o i > J o i


<option value= v i n e r i > V i n e r i
<option value= s i mb a ta > Simbata
<option value= duminica > Duminica
</ s e l e c t>
<p><input type= submit value= A f i s e a z a >
</form>
</body>
</html>

unde ziuaTag.jsp este


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

<html>
<head>
< t i t l e> Tag cu marcaj </ t i t l e>
</head>
<body>
<%@ t a g l i b u r i= mytags
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>

9.3.3

Marcaje cu corp.

In metoda doStartTag valoarea returnata trebuie sa fie EVAL BODY INCLUDE,


n loc de SKIP BODY.
In descriptorul bibliotecii de marcaje apare
<body-content> JSP </body-content>
n loc de EMPTY.
Daca se doreste ca marcajul sa execute actiuni dupa interpretarea corpului,
atunci acele activitati sunt definite n metoda doEndTag. Aceasta metoda
returneaza valoarea EVAL PAGE sau SKIP PAGE dupa cum se doreste sau nu
continuarea procesarii paginii jsp.
Exemplul 9.3.3 Fie marcajul modTag care modifica un text n caractere mari
sau mici dupa valoarea atributului trans. Acest marcaj poate include ale elemente.
Codul clasei ce prelucreaza marcajul este

9.3. MARCAJE JSP PERSONALE

1
2
3
4
6
7
8

package j s p ;
import j a v a x . s e r v l e t . j s p . J s p W r i t e r ;
import j a v a x . s e r v l e t . j s p . t a g e x t . TagSupport ;
import j a v a . i o . IOException ;
public c l a s s ModTag extends TagSupport {
String text ;
boolean toUpperCase ;
public void s e t T e x t ( S t r i n g v a l u e ) {
t e x t=v a l u e ;
}

10
11
12

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

14
15
16

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

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

Descriptorul bibliotecii de marcaje se completeaza cu


<tag>
<name> modTag </name>
<tag-class> jsp.ModTag </tag-class>
<body-content> JSP </body-content>
<description> modifica caracterele </description>
<attribute>
<name>text</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>trans</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

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


1
2
3

<html>
<body>
<form method= g e t

253

254

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

CAPITOLUL 9. JAVA SERVER PAGE JSP

action= j s p / modtextTag . j s p >


I n t r o d u c e o f r a z &#259;
<input type= t e x t name= t e x t s i z e= 40 >
<p>
Se t r a n s f o r m &#259; &#238;n l i t e r e
<s e l e c t name= t r a n s >
<option value= upperCase > mari
<option value= l o w e r C a s e > m i c i
</ s e l e c t>
<p><input type= submit value= A f i s e a z a >
</form>
</body>
</html>

mpreuna cu modtextTag.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

<html>
<body>
<%@ t a g l i b u r i= mytags 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>

9.4

Autentificare si autorizare cu apache-shiro

Apache-shiro este un produs care permite autentificarea si autorizarea unei


aplicatii informatice ca o entitate independenta de aplicatia n cauza. Datele
de autentificare sunt nregistrate ntr-un fisier shiro.ini.
Un utilizator este definit de perechea (nume utilizator, parola), i sunt
atribuite unul sau mai multe roluri iar unui rol i se atribuie unul sau mai
multe actiuni -(permission - n terminologia apache-share).
Apache-shiro este dezvoltat ca un filtru din tehnologia servlet.
In momentul de fata nu este posibila actualizarea dinamica a fisierului
shiro.ini.

9.4. AUTENTIFICARE S
I AUTORIZARE CU APACHE-SHIRO

255

Termeni
Credential informatie pe baza careia se realizeaza autentificarea unui
utilizator / subiect (de exemplu: o parola);
Principal Autentificarea se asigura printr-una sau mai multe credentials
printre care se afla principal, (de exemplu: username);
Realm (taram/domeniu) entitatea care retine datele de identificare a unui
utilizator;
Subject termen utilizat pentru un utilizator (om sau program).
Fisierul de configurare shiro.ini pentru aplicatie Web contine:
1. [main] shiro.loginUrl = /login.jsp
Se indica pagina de autentificare.
2. [users]
Declararea utilizatorilor mpreuna cu parola de autentificare si rolul /
rolurile. Un rol fixeaza activitatile (permissions) de care dispune utilizatorul.
Sintaxa utilizata este
numeUtilizator = parola, rol 1,rol 2,. . .
3. [roles]
Se declara activitatile permise de rol, mai precis pentru care se asigura
autorizarea.
Sintaxa utilizata este
rol = activitatea 1,activitatea 2,. . .
* desemneaza orice activitate.
4. [urls]
Se declara referintele din serverul Web la care se asigura accesul doar n
urma autentificarii, care sunt filtrate de apache-shiro.
Sintaxa utilizata este
/fisier.jsp sau catalog/** = authc
Deconectarea se indica prin
/logout = logout

256

CAPITOLUL 9. JAVA SERVER PAGE JSP

Exemplul 9.4.1
1
2
4
5
6
7
8
9
11
12
13
14
15
17
18
19
20

[ main ]
shiro . loginUrl = / login . jsp
[ users ]
# f o r m a t : username = password , r o l e 1 , r o l e 2 ,
admin = admin , admin
guest = guest , guest
cmmdc=cmmdc , rolCmmdc
h e l l o=h e l l o , r o l H e l l o

. . . , roleN

[ roles ]
# f o r m a t : roleName = p e r m i s s i o n 1 , p e r m i s s i o n 2 ,
admin = a l l
rolCmmdc=cmmdc
r o l H e l l o=h e l l o

. . . , permissionN

[ urls ]
/ l o g i n . j s p = authc
/ logout = logout
/ a c c e s A u t o r i z a t / = authc

Structura unei aplicatii Web cu indicarea resurselor pentru autentificare si


autorizare este
catalogul_aplicatiei
|--> accesAutorizat
|
|
alegeActiune.jsp
|
|
fisiere html/jsp de apelare ale aplicatiilor
|--> WEB-INF
|
|--> lib
|
|
|--> *.jar
|
|
shiro.ini
|
|
web.xml
|
index.html
|
home.jsp
|
login.jsp

Resursele jar necesare sunt:


commons-beanutils-*.jar shiro-web-*.jar
jcl-over-slf4j-*.jar
jstl.jar
standard.jar
slf4j-api-*.jar
slf4j-simple-*.jar
shiro-care-*.jar
Fisierul web.xml este
1
2
3
4
5
6

<?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 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
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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd
version= 2 . 5 >

9.4. AUTENTIFICARE S
I AUTORIZARE CU APACHE-SHIRO

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

257

< l i s t e n e r>
< l i s t e n e r c l a s s>
o r g . apache . s h i r o . web . env . E n v i r o n m e n t L o a d e r L i s t e n e r
</ l i s t e n e r c l a s s>
</ l i s t e n e r>
< f i l t e r>
< f i l t e r name> S h i r o F i l t e r</ f i l t e r name>
< f i l t e r c l a s s>
o r g . apache . s h i r o . web . s e r v l e t . S h i r o F i l t 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> S h i r o F i l t 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>

iar fisierul index.html are codul


1
2
3
4
5
6
7
8

<html>
<head>
<META HTTPEQUIV= R e f r e s h CONTENT= 0 ;URL=home . j s p >
</head>
<body>
<p>A p e l a r e a a p l i c a t i e i . . . </p>
</body>
</html>

Valoarea atributului URL, n cazul de fata home.jsp defineste pagina de


deschidere a aplicatiei.
In acest fisier se utilizeaza marcajele bibliotecii prefix=shiro,
url="http://shiro.apache.org/tags". Activitatile cuprinse sunt:
solicitarea autentificarii;
n cazul autentificarii se indica prin ancore (link) posibilitatile de navigare
(spre aplicatia propriu-zisa sau deconectare (logout))
optional, se vor putea determina rolurile si actiunile permise utilizatorului autentificat, adica autorizarea.

Biblioteca de marcaje url="http://shiro.apache.org/tags"


<shiro:principal/ >
Furnizeaza utilizatorul.
<shiro:guest>
Executa marcajul interior daca utilizatorul (Subject) nu este autentificat.

258

CAPITOLUL 9. JAVA SERVER PAGE JSP

<shiro:user>
Executa marcajul interior daca utilizatorul (Subject) este autentificat.
<shiro:hasRole name=rol>
Executa marcajul interior daca utilizatorul are rolul rol.
<shiro:lacksRole name=rol>
Executa marcajul interior daca utilizatorul nu are rolul rol.
<hasAnyRole name=rol1,rol2,. . . >
Executa marcajul interior daca utilizatorul are unul din rolurile din lista.
<shiro:hasPermission name=actiune>
Executa marcajul interior daca rolului i este atribuit activitatea actiune.
<shiro:hasPermission name=actiune>
Executa marcajul interior daca rolului nu i este atribuit activitatea
actiune.
Exemplul 9.4.2 Aplicatie Web utilizand fisierul shiro.ini cu acces catre
aplicatiile cmmdc1pagina.jsp si hello1pagina.jsp.
Se definesc trei clienti admin, cmmdc si hello. Administratorul va avea
acces la ambele aplicatii dar clientul cmmdc / hello va avea acces doar la
aplicatia cmmdc1pagina / hello1pagina.
Structura aplicatiei si fisierul shiro.ini sunt cele date mai sus.
Fisierul home.jsp este
1
2
4
5
6
8
9
10
12
13
14
15
16
17
18

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>


<%@ t a g l i b p r e f i x= s h i r o u r i= h t t p : / / s h i r o . apache . o r g / t a g s %>
<html>
<body>
<h1>A u t e n t i f i c a r e ( Apache S h i r o ) </h1>
<p>S a l u t
<s h i r o : g u e s t>Guest</ s h i r o : g u e s t>
<s h i r o : u s e r><s h i r o : p r i n c i p a l /></ s h i r o : u s e r> !
<s h i r o : u s e r>
<table>
<tr>
<td>
<a href=<c : u r l
v a l u e= / a c c e s A u t o r i z a t / a l e g e A c t i u n e . j s p />>
Ac&#355; i u n i</a>

9.4. AUTENTIFICARE S
I AUTORIZARE CU APACHE-SHIRO

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

</td>
</ tr>
<tr>
<td>
<a href=<c : u r l v a l u e= / l o g o u t />>Log out</a>
</td>
</ tr>
</ table>
</ s h i r o : u s e r>
<s h i r o : g u e s t>
<a href=<c : u r l v a l u e= / l o g i n . j s p />>Log i n</a>
</ s h i r o : g u e s t>
<p/>
<s h i r o : h a s R o l e name= admin >admin<br/>
<%
s e s s i o n . s e t A t t r i b u t e ( r o l , admin ) ;
%>
</ s h i r o : h a s R o l e>
<s h i r o : h a s R o l e name=rolCmmdc>rolCmmdc<br/>
<%
s e s s i o n . s e t A t t r i b u t e ( r o l , rolCmmdc ) ;
%>
</ s h i r o : h a s R o l e>
<s h i r o : h a s R o l e name= r o l H e l l o > r o l H e l l o<br/>
<%
session . setAttribute ( rol , rolHello );
%>
</ s h i r o : h a s R o l e>
<p/>
<h3>R o l u r i pe c a r e
<p/>
<s h i r o : l a c k s R o l e
<s h i r o : l a c k s R o l e
<s h i r o : l a c k s R o l e

nu l e ave &#355; i</h3>


name= admin >admin<br/></ s h i r o : l a c k s R o l e>
name=rolCmmdc>rolCmmdc<br/></ s h i r o : l a c k s R o l e>
name= r o l H e l l o > r o l H e l l o<br/></ s h i r o : l a c k s R o l e>

<p/>
<h3>A c t i v i t &#259;&#355; i l e dv o a s t r &#259;</h3>
<p>
<s h i r o : h a s P e r m i s s i o n name= a l l > a l l<br/>
<%
s e s s i o n . setAttribute ( act , a l l ) ;
%>
</ s h i r o : h a s P e r m i s s i o n>
<s h i r o : h a s P e r m i s s i o n name=cmmdc>cmmdc<br/>
<%
s e s s i o n . s e t A t t r i b u t e ( a c t , cmmdc ) ;
%>
</ s h i r o : h a s P e r m i s s i o n>
<s h i r o : h a s P e r m i s s i o n name= h e l l o > h e l l o<br/>
<%
s e s s i o n . setAttribute ( act , h e l l o ) ;
%>
</ s h i r o : h a s P e r m i s s i o n>
<p/>
<h3>A c t i v i t &#259;&#355; i de c a r e nu d i s p u n e &#355; i</h3>

259

260

78
79
80
81
82

CAPITOLUL 9. JAVA SERVER PAGE JSP

<p/>
<s h i r o : l a c k s P e r m i s s i o n name=cmmdc>cmmdc<br/></ s h i r o : l a c k s P e r m i s s i o n>
<s h i r o : l a c k s P e r m i s s i o n name= h e l l o > h e l l o<br/></ s h i r o : l a c k s P e r m i s s i o n>
</body>
</html>

Fisierul login.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>
<body>
<h2>Pagina de c o n e c t a r e</h2>
<form method= p o s t >
<table a l i g n= l e f t border= 0 c e l l s p a c i n g= 0 cellpadding= 3 >
<tr>
<td> U t i l i z a t o r :</td>
<td>
<input type= t e x t name= username maxlength= 30 >
</td>
</ tr>
<tr>
<td>P a r o l a :</td>
<td>
<input type= password name= password maxlength= 30 >
</td>
</ tr>
<tr>
<td colspan= 2 a l i g n= r i g h t >
<input type= submit name= submit value= Login >
</td>
</ tr>
</ table>
</form>
</body>
</html>

Fisierul alegeActiune.jsp este


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

<html>
<body bgcolor=#a a e e a a >
<table>
<%
String a c t =(String ) s e s s i o n . g e t A t t r i b u t e ( a c t ) ;
i f ( a c t== a l l ) {
%>
<tr>
<td>
<a href= a l e g e . html >A c t i u n i a d m i n i s t r a t o r</a>
</td>
</ tr>
<%
}
i f ( a c t==cmmdc ) {
%>
<tr>
<td>
<a href=cmmdc . html >C a l c u l cmmdc</a>
</td>
</ tr>
<%

9.4. AUTENTIFICARE S
I AUTORIZARE CU APACHE-SHIRO

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

}
i f ( a c t== h e l l o ) {
%>
<tr>
<td>
<a href= h e l l o . html >A p l i c a t i a H e l l o Name</a>
</td>
</ tr>
<%
}
%>
</ table>
</body
</html>

Aplicatia propriu-zisa (cmmdc1pagina.jsp) se completeaza la sfarsit cu


<p><a href="<c:url value="/home.jsp"/>">Return to the home page.</a></p>
<p><a href="<c:url value="/logout"/>">Log out.</a></p>

Se procedeaza analog si pentru hello1pagina.jsp.

Intreb
ari recapitulative
1. Care este tipul tehnologiei JSP ?
2. Precizati diferenta dintre o pagina JSP si un document JSP.
3. Unde se instaleaza o pagina JSP?
4. Care este rolul unei declaratii JSP ?
5. Care este rolul unei directive JSP ?
6. Cum apeleaza o pagina JSP ?
7. Cum prelucreaza un server Web o pagina / document JSP ?
8. Care sunt trasaturile unei componente Java (bean) ?
9. Care este rolul unui element <jsp:useBean> ?

261

262

CAPITOLUL 9. JAVA SERVER PAGE JSP

Capitolul 10
Desf
asurarea n nor
Dezvoltarea Internetului, nevoia de a reduce costurile legate de realizarea
si ntretinerea infrastructurii care ofera servicii pe Internet, concomitent cu
nevoia de crestere a calitatii serviciilor a condus la servicii n nor (Cloud
Computing).
Avantajele oferite de serviciile serviciile n nor sunt:
Reducerea costurilor
Agilitate (Agility)
Reducerea duratei:
de asteptare n cazul aparitiei unei disfunctionalitati din partea
furnizorului serviciului n nor;
de actualizare si ntretinere din partea realizatorului serviciului n
nor.
Elasticitate (Elasticity)
Posibilitatea de crestere / descrestere a resurselor (n principal hard)
alocate pentru a satisface cerintele clientilor ntr-un interval de timp.
Se face distinctie de scalabilitate, termen care desemneaza nevoia de
cresere / descrestere a resurselor alocate legata de dezvoltarea aplicatiilor
care compun serviciul.
Tipuri de servicii n nor:
Aplicatii ca serviciu (Software as a Service - SaaS )
Skype, Googles Docs, Gmail, Yahoo Messenger, Microsoft Office 365,
etc.
263

264

URAREA IN NOR
CAPITOLUL 10. DESFAS

Infrastructura ca serviciu (Infrastructure as a Service - IaaS )


Amazons Elastic Compute Cloud - (EC2)
Plaforma ca serviciu (Platform as a Service - PaaS )
PaaS poate fi
Ne-portabla : aplicatia va avea o structura predefinita.
Google AppEngine (GAE), Microsoft Azure, OpenShift
Portabila
Heroku
In cele ce urmeaza ne intereseaza doar platformele PaaS care accepta desfasurarea
de aplicatii Java, n mod gratuit, sau ofera un simulator local.

10.1

Servlet si JSP n Google App Engine

Google AppEngine permite:


ncarcarea unei aplicatii Web pe un simulator local al platformei de Cloud
Computing;
ncarcarea unei aplicatii Web pe platforma Google de Cloud Computing.
In prezent, pe platforma GAE se pot ncarca aplicatii realizate n Java,
Python, PHP si Go, alaturi de care care pot aparea fisiere http, css, js. Exista
cate o distributie distincta pentru fiecare din aceste limbaje de programare.

Utilizarea simulatorului local


Incarcarea pe simulatorul local al platformei GAE, n versiunea Java este
construit peste serverul Web jetty.
Instalarea produsului consta din dezarhivarea fisierului appengine-javasdk-*.
Utilizarea. In vederea ncarcarii unui servlet pe simulatorul local se creaza
structura de cataloage si fisiere
war
|-->
|
|
|
|
|
|
|

WEB-INF
|--> classes
|
| *.class
|--> lib
|
| *.jar
|
web.xml
|
appengine-web.xml
index.html

10.1. SERVLET S
I JSP IN GOOGLE APP ENGINE

265

Singurul fisier specific GAE este appengine-web.xml. Codul acestui fiser este
1
2
3
4
6
8

<appengine webapp xmlns= h t t p : // a p p e n g i n e . g o o g l e . com/ ns / 1 . 0 >


< ! R e p l a c e t h i s w i t h your a p p l i c a t i o n i d from
h t t p : // a p p e n g i n e . g o o g l e . com >
<a p p l i c a t i o n></ a p p l i c a t i o n>
<version>1</ version>
</ appengine webapp>

Datele fisierului web.xml corespund servlet-ului, iar prin fisierul index.html se


apeleaza aplicatia Web. Parametrul action al elementului form are forma simplificata action=/numeApel, unde numeApel coincide cu valoarea atributului
urlPattern.
Daca aplicatia se ncarca pe platforma Google de Cloud Computing atunci
trebuie completat elementul <application>.
Lansarea simulatorului si ncarcarea se poate face prin comenzile
set GAE\_HOME=. . .\appengine-java-sdk-*
%GAE\_HOME%\bin\dev_appserver war

lansate ntr-o fereasta DOS, n catalogul care-l contine pe war. Aplicatia se


apeleaza prin http://localhost:8080. Daca n loc de index.html se utilizeaza alt nume, atunci apelarea aplicatiei este
http://localhost:8080/fi
sier.html.
O aplicatie JSP se trateaza asemanator.
Distributia GAE pentru Java contine sablonul unei aplicatii mpreuna cu
un fisier build.xml (appengine-java-sdk-*\demos\new project template)
prin intermediul caruia, cu ajutorul lui ant, se construieste catalogul war descris anterior.
Exemplul 10.1.1 Servlet-ul CmmdcServlet instalat n platforma Google App
Engine de Cloud Computing.
Sablonul se copiaza n zona de lucru sub numele appcmmdc si se completeaza cu fisierele servlet-ului (CmmdcServlet.java, cmmdc.html ) rezultand:
appcmmdc
|--> src
|
|
CmmdcServlet.java
|--> war
|
|--> WEB-INF
|
|
|
appengine-web.xml
|
|
|
web.xml
|
|
cmmdc.html
|
build.xml

266

URAREA IN NOR
CAPITOLUL 10. DESFAS

Se executa cu ant obiectivul implicit din build.xml, urmat de lansarea simulatorului din interiorul catalogului appcmmdc. Deoarece numele fisierului html
difera de index, aplicatia se apeleaza prin
http://localhost:8080/cmmdc.html.
Alternativ, aplicatia se poate construi cu Eclipse folosind o componenta
(plug-in) specifica.
GAE contine n plus un serviciu de autentificare si autorizare UserService,
un sistem de persistenta a datelor Datastore, Task-Queue.

Desf
asurarea n GAE
Acest pas necesita din partea dezvoltatorului cont Google.
Desfasurarea gratuita (cel mult 10 aplicatii) n GAE presupune:
1. Inregistrarea aplicatiei:
(a) Se acceseaza pagina Web https://appengine.google.com/.
(b) Inregistrarea propriu-zisa:
i. Application Identifier
Se fixeaza identificatorul aplicatiei app id, care se trece si n
elementul <application> din appengine-web.xml;
ii. Check Availibility
Verificarea disponibilitatii identificatorului;
iii. Application title
Fixarea titlului aplicatiei;
iv. Create Application
2. Incarcarea n nor (upload)
%GAE_HOME%\bin\appcfg.cmd --oauth2 update locatia_aplicatiei_web

Prin locatia aplicatiei web se ntelege catalogul war construit de GAE.


Aplicatia va fi disponibila prin
http://app_id.appspot.com/ sau
http://app_id.appspot.com/fisier.html

10.2

Heroku

Heroku este o PaaS care ofera suport pentru mai aplicatii dezvoltate n mai
multe limbaje de programare, printre care si Java.

10.2. HEROKU

267

Instalarea resurselor
1. Punctul de pornire este crearea unui cont Heroku la https://devcenter.
heroku.com prin Getting Started. Parametrii contului sunt (adresa de
email, parola).
2. Se va instala Heroku Toolbeit. Cu acest prilej se instaleaza Ruby si Git
n c:\Program Files (x86).1 Ruby se instaleaza n Heroku. Variabila de sistem PATH se actualizeaza cu caile la Heroku si Git (dar nu la
Git\bin\ssh-keygen.exe).
3. Login pentru generarea cheii de identificare.
heroku login
La conectari ulterioare nu se mai genereaza aceasta cheie.

Utilizarea.
Gestionarea aplicatiilor se realizeaza la https://dashboard.heroku.com/
apps.
Dezvoltarea aplicatiilor se bazeaza pe maven iar desfasurarea pe Git.

10.2.1

JSP n Heroku

1. Generarea aplicatiei:
set GroupID=myGroupId
set ArtifactID=myArtifactId
set Version=1.0
mvn archetype:generate -DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-webapp
-DinteractiveMode=false
2. Completarea fisierului pom.xml:
1
2
3
4
5

<p r o j e c t xmlns= h t t p : //maven . apache . o r g /POM/ 4 . 0 . 0


x m l n s : x s i= h t t p : //www. w3 . o r g /2001/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>

Se are n vedere sistemul de operare Windows.

268

URAREA IN NOR
CAPITOLUL 10. DESFAS

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

<g r o u p I d>myGroupId</ g r o u p I d>


< a r t i f a c t I d>m y A r t i f a c t I d</ 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>M y A r t i f a c t I d 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>o r g . e c l i p s e . j e t t y</ g r o u p I d>
< a r t i f a c t I d>j e t t y s e r v l e t</ a r t i f a c t I d>
<version> 9 . 1 . 0 . v20131115</ version>
</ dependency>
<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>m y A r t i f a c t I d</ 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 . 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>mavendependencyp l u g i n</ a r t i f a c t I d>
<version>2 . 3</ version>
<e x e c u t i o n s>
<e x e c u t i o n>
<phase>package</ phase>
<g o a l s><g o a l>copy</ g o a l></ g o a l s>
<c o n f i g u r a t i o n>
< a r t i f a c t I t e m s>
<a r t i f a c t I t e m>
<g r o u p I d>o r g . e c l i p s e . j e t t y</ g r o u p I d>
< a r t i f a c t I d>j e t t y r u n n e r</ a r t i f a c t I d>
<version> 9 . 1 . 0 . v20131115</ version>
<d e s t F i l e N a m e>j e t t y r u n n e r . j a r</ d e s t F i l e N a m e>
</ a r t i f a c t I t e m>
</ a r t i f a c t I t e m s>
</ c o n f i g u r a t i o n>
</ 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>

3. Completarea aplicatiei cu fisierele jsp.


4. Optional aplicatia se poate arhiva si verifica.
mvn clean package
5. Completarea cu fisierele
Procfile

269

10.2. HEROKU

1
2

web: j a v a $JAVA OPTS j a r t a r g e t / dependency / j e t t y r u n n e r . j a r


p o r t $PORT t a r g e t / . war

system.properties
1

j a v a . r u n t i m e . v e r s i o n =1.7

.gitignore
1

target

Structura aplicatiei este


myapp
|--> src
|
|--> main
|
|
|--> resources
|
|
|--> webapp
|
|
|
|--> WEB-INF
|
|
|
|
web.xml
|
|
|
fisiere jsp
|--> target
|
|
*
|
.gitignore
|
Procfile
|
system.properties
|
pom.xml

6. Pregatirea Git
git init
git add .
git commit -m "myapp"
7. Generarea si desfasurarea aplicatiei
heroku create
git push heroku master
Heroku atribuie un nume aplicatiei. Dintr-un navigator aplicatia se va
apela prin acest nume:
http://numeDatDeHeroku.herokuapp.com/
8. Calibrare

270

URAREA IN NOR
CAPITOLUL 10. DESFAS

heroku ps:scale web=1


cu verificarea calibrarii
heroku ps
Aceasta setare fixeaza resursele atribuite aplicatiei la 1 dynos. Un numar
mai mare de resurse presupune un cost.
9. Lansarea aplicatiei n linia de comanda din catalogul aplicatiei
heroku open
10. Optional se poate consulta fisierul de jurnalizare
heroku logs

10.2.2

Servlet n Heroku

Aplicatia servlet se bazeaza pe interfata de programare servlet-api 2.5.


Clasa servletului are metoda main prin care se lanseaza un server Web
ncorporat.
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17

package h e l l o . heroku ;
import j a v a . i o . IOException ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import j a v a x . s e r v l e t . S e r v l e t O u t p u t S t r e a m ;
import o r g . e c l i p s e . j e t t y . s e r v e r . S e r v e r ;
import o r g . e c l i p s e . j e t t y . s e r v l e t . S e r v l e t C o n t e x t H a n d l e r ;
import o r g . e c l i p s e . j e t t y . s e r v l e t . S e r v l e t H o l d e r ;
public c l a s s HelloWorld extends H t t p S e r v l e t {
@Override
protected void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s p )
throws S e r v l e t E x c e p t i o n , IOException {
r e s p . g e t W r i t e r ( ) . p r i n t ( H e l l o from Java ! \ n ) ;
}
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 e r v e r s e r v e r = new S e r v e r ( I n t e g e r . v a l u e O f ( System . g e t e n v ( PORT ) ) ) ;
ServletContextHandler context =
new S e r v l e t C o n t e x t H a n d l e r ( S e r v l e t C o n t e x t H a n d l e r . SESSIONS ) ;
context . setContextPath ( / ) ;
server . setHandler ( context ) ;
c o n t e x t . a d d S e r v l e t (new S e r v l e t H o l d e r (new HelloWorld ( ) ) , / ) ;
server . start ();
server . join ();
}

19
20
21
22
23
24
25
26
27
28
29

10.2. HEROKU

271

Fisierele html, css care asigura interfata grafica a aplicatiei servlet nu fac
parte din ce se ncarca n nor.
Servletul se apeleaza prin
http://numeDatDeHeroku.herokuapp.com/numeApel
Desfasurarea si apelarea consta din
1. Generarea aplicatiei.
2. Completarea fisierului pom.xml:
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

<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>myGroupId</ g r o u p I d>
< a r t i f a c t I d>m y A r t i f a c t I d</ 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>m y A r t i f a c t I d 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>o r g . e c l i p s e . j e t t y</ g r o u p I d>
< a r t i f a c t I d>j e t t y s e r v l e t</ a r t i f a c t I d>
<version> 9 . 1 . 0 . v20131115</ version>
</ 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>
</ 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>m y A r t i f a c t I d</ 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 . 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>3 . 1</ 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>
<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>mavendependencyp l u g i n</ a r t i f a c t I d>
<version>2 . 4</ version>
<e x e c u t i o n s>
<e x e c u t i o n>
<i d>copyd e p e n d e n c i e s</ i d>
<phase>package</ phase>
<g o a l s><g o a l>copyd e p e n d e n c i e s</ g o a l></ g o a l s>
</ e x e c u t i o n>

272

46
47
48
49
50
51
52
53
54
55

URAREA IN NOR
CAPITOLUL 10. DESFAS

</ e x e c u t i o n s>
</ p l u g i n>
<p l u g i n>
<g r o u p I d>o r g . e c l i p s e . j e t t y</ g r o u p I d>
< a r t i f a c t I d>j e t t y mavenp l u g i n</ a r t i f a c t I d>
<version> 9 . 1 . 0 . v20131115</ version>
</ 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>

3. Completarea aplicatiei cu fisierele java si web.xml.


4. Optional aplicatia se poate arhiva si verifica.
Verificarea se face prin
set PORT=5000
java -cp myArtifactId\target\classes;"myArtifactId\target\dependency\*"
clasaServlet

5. Completarea cu fisierele
Procfile
1
2

web: j a v a $JAVA OPTS cp t a r g e t / c l a s s e s : t a r g e t / dependency /


clasaServlet

system.properties
.gitignore
Structura aplicatiei devine
myapp
|--> src
|
|--> main
|
|
|--> java
|
|
|
*.java
|
|
|--> resources
|
|
|--> webapp
|
|
|
|--> WEB-INF
|
|
|
|
|
web.xml
|--> target
|
|
*
|
.gitignore
|
Procfile
|
system.properties
|
pom.xml

6. Pregatirea Git

10.3. OPENSHIFT

273

git init
git add .
git commit -m "myapp"
7. Generarea si desfasurarea aplicatiei
heroku create
git push heroku master
Heroku atribuie un nume aplicatiei. Dintr-un navigator aplicatia se va
apela prin acest nume.
8. Calibrare
heroku ps:scale web=1
cu verificarea calibrarii
heroku ps
Aceasta setare fixeaza resursele atribuite aplicatiei la 1 dynos. Un numar
mai mare de resurse presupune un cost.
9. Daca se transmit date aplicatiei printr-un fisier html atunci lansarea
aplicatiei se face din navigator completand atributul action cu adresa
furnizata de heroku iar n caz contrar din linie de comanda se apeleaza
heroku open
10. Optional se poate consulta fisierul de jurnalizare
heroku logs

10.3

OpenShift

OpenShift este produs de RedHat cu suport pentru aplicatii distribuite n


Java dar si pentru (python, ruby, javascript, php).

274

URAREA IN NOR
CAPITOLUL 10. DESFAS

Comunicatiile unei aplicatii se fac exclusiv potrivit protocoalelor si porturilor din tabelul urmator:
Protocolul
HTTP
HTTPS
SSH-SecureSHell
WebSocket HTTP
WebSocket HTTPS

Portul
80
443
22
8000
8443

O aplicatie apartine unui cartus - cartridge - dar care poate contine si alte
componente ale aplicatiei (de exemplu un SGBD). Unui cartus i se asociaza
un angrenaj - gear - ce trebuie privit ca un container al aplicatiei. Angrenajul
poate fi mic (512 MB), mediu (1 GB) sau mare (2 GB).
Cartusul defineste natura aplicatiei (servlet sau JSP n tomcat 6 sau 7,
aplicatie JEE, etc).
Un utilizator trebuie sa se nregistreze (gratuit) la www.openshift.com,
moment n care se fixeaza codul de identificare - o adresa de e-mail - si o
parola.
Unui dezvoltator i se asociaza un domeniu - namespace - indicat printr-un
cuvant. Apelarea unei aplicatii se face dupa schema
http://numeApp-domeniu.rhcloud.com
Gratuit un dezvoltator poate instala pana la 3 aplicatii ntr-un angrenaj
mic.
O aplicatie se poate dezvolta:
n linie de comanda prin clientul OpenShift rhc;
ntr-o consola Web;
n Eclipse cu o componenta (plug-in) specifica.
In continuare consideram doar dezvoltarea n linie de comanda.

Instalarea clientului rhc


.
1. Se instaleaza Ruby (http://rubyinstaller.org/downloads). Este suficienta o versiune fara procedura propriu-zisa de instalare (7z).

10.3. OPENSHIFT

Verificarea instalarii:
ruby -e puts "Welcome to Ruby"
2. Se instaleaza Git (http://git-scm.com/download/win).
Verificarea instalarii:
git --version
3. Descarcarea clientului OpenShift
gem install rhc
Locatia este RUBY HOME\include.
4. Instalarea clientului OpenShift
rhc setup

Dezvoltarea unei aplicatii


1. rhc app create numeApp cartus
Cartuse pentru aplicatii Java (gratuite)
Denumire cartus Continut
jbossews-1.0
Tomcat 6
jbossews-2.0
Tomcat 7
jbossas-7
JBoss Application Server 7
jenkins-1
Jenkins Server
Pentru jbossews-2.0, n catalogul de lucru se genereaza structura
numeApp
|--> .git (Catalog ascuns - hidden)
|
|
* - resurse Git
|--> .openshift
|
|
* - resurse OpenShift
|--> src
|
|--> main
|
|
|-->
java
|
|
|-->
resources
|
|
|-->
webapp
|
|
|
|--> images
|
|
|
|--> WEB-INF

275

276
|
|
|
|-->
|
|

URAREA IN NOR
CAPITOLUL 10. DESFAS

|
|
|
|
|
|
|
|
|
webapps
README.md
pom.xml

|
web.xml
index.html
snoop.jsp

Dezvoltatorul completeaza catalogul src cu fisierele sursa ale aplicatiei


Web.

Inc
arcarea n nor
git add .
git commit -m "text"
git push

Operatii rhc
rhc --help
rhc --help comanda rhc
rhc cartridge list
Lista cartuselor disponibile.
rhc app delete numeApp
Stergerea aplicatiei.
rhc apps
Lista aplicatiilor.

Intreb
ari recapitulative
1. Precizati tipurile principale de servicii n nor.
2. Enumerati servicii n nor de tip PaaS cu suport pentru Java.

Capitolul 11
Java Web Start
11.1

Java Web Start

O aplicatie Java destinata a fi utilizata pe un calculator poate fi valorificata


si ntr-o retea, pe baza protocolului Java Network Launching Protocol - JNLP.
Tehnologia poarta numele de Java Web Start.
Aplicatia Java trebuie sa satisfaca o serie de restrictii:
Aplicatia trebuie arhivata cu jar. In fisierul MANIFEST.MF trebuie
sa apara atributul
Permissions:

all-permissions

Arhiva jar trebuie certificata. Certificarea se realizeaza cu utilitarele


keytool.exe si jarsigner.exe din distributia jdk;
Eventualele date necesare aplicatiei se introduc prin intermediul unei
interfete grafice (JavaFX, swing, SWT, apache-pivot);
Acces limitat la proprietatile si resursele sistemului client.
Aplicatiei i se ataseaza un fisier xml, dar cu extensia jnlp, care se va apela
dintr-un navigator. Pentru acest fisier folosim terminologia de fisier jnlp.
Fisierul jnlp fixeaza:
referinta URL a aplicatie (prin atributul codebase);
arhivele jar utilizate (prin atributul href);
clasa cu metoda main (prin atributul main-class).
277

278

CAPITOLUL 11. JAVA WEB START

Ansamblul de resurse formeaza o aplicatie Web care poate fi desfasurata


ntr-un server Web (container de servlet) sau poate fi incorporat ntr-un servlet.
Aratam activitatile care trebuie ntreprinse n cazul unui exemplu simplu
dat de clasa VisualCmmdc.java.
1
2
3
4

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
}

9
10

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

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

private void exitForm ( j a v a . awt . e v e n t . WindowEvent e v t ) {


System . e x i t ( 0 ) ;
}

27
28
29

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

31
32
33

private
private
private
private
private
private

35
36
37
38
39
40
41

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 grafica a programului este ilustrata n Fig. 11.1

Instalare ntr-un server Web


Pentru instalarea aplicatiei ntr-un server Web, se parcurg pasii:

279

11.1. JAVA WEB START

Figure 11.1: Interfata grafica a aplicatiei.


1. Se arhiveaza aplicatia
jar cmfv myManifest.mf cmmdc0.jar *.class
unde fisierul myManifest.mf contine doar linia
Permissions:

all-permissions

2. Certificarea se obtine prin


(a)

keytool -genkey -keystore myKeystore -alias myself


-dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO"
-keypass abc123 -storepass 123abc

(b)

keytool -selfcert -alias myself -keystore myKeystore


-keypass abc123 -storepass 123abc

(c)

jarsigner -keystore myKeystore -signedjar cmmdc.jar


-keypass abc123 -storepass 123abc cmmdc0.jar myself
jarsigner -verify cmmdc.jar

Primele doua actiuni au ca rezultat obtinerea certificatului myKeystore


iar ultima actiune reprezinta nglobarea certificarii n arhiva resursa.jar
- n cazul exemplului cmmdc.jar.
3. Se editeaza fisierul launch.jnlp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<j n l p c o d e b a s e= h t t p : // h o s t : 8 0 8 0 /cmmdc>
<i n f o r m a t i o n>
< t i t l e> . . . </ t i t l e>
<vendor> . . . </ vendor>
<d e s c r i p t i o n> . . . </ d e s c r i p t i o n>
</ i n f o r m a t i o n>
<r e s o u r c e s>
<j 2 s e version= 1.2+ />
<j a r h r e f=cmmdc . j a r />
</ r e s o u r c e s>
<s e c u r i t y>
<a l l p e r m i s s i o n s />
</ s e c u r i t y>
<a p p l i c a t i o n d e s c mainc l a s s=VisualCmmdc />
</ j n l p>

280

CAPITOLUL 11. JAVA WEB START

host se nlocuieste cu numele calculatorului care gazduieste serverul Web.


4. Se creaza fisier de apelare a aplicatiei (cmmdc.html )
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 : 8 0 8 0 / cmmdc/ l a u n c h . j n l p >
Launch t h e a p p l i c a t i o n </a>
</ center>
</body>
</html>

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

se copiaza n serverul Web.


Dintr-un navigator, apelarea aplicatiei este http://host:port/cmmdc/ cmmdc. html.
Fisierul jnlp se descarca pe calculatorul clientului si se proceseaza cu
bin\javaws.exe din Java.

Aplicatia Java ca servlet


Pentru includerea aplicatie Java ntr-un servlet, primii trei pasi prezentati
mai sus coincid. Singura diferenta consta n continutul referintelor, dupa host
va apare portul utilizat de serverul Web container de servlet, uzual host:8080.
4. Intr-un catalog de lucru se creaza structura de cataloage si fisiere:
app
|
cmmdc.jar
|
launch.jnlp
WEB-INF
|--> lib
|
|
jnlp-servlet.jar
|
web.xml
cmmdc.html

Fisierul jnlp-servlet.jar se preia din distributia JDK, din catalogul


sample/jnlp/servlet.
Fisierul web.xml este

281

11.1. JAVA WEB START

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?>
< !DOCTYPE webapp
PUBLIC //Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN
h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd >
<webapp>
< ! Standard Ac ti o n S e r v l e t C o n f i g u r a t i o n ( w i t h d e b u g g i n g ) >
<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 arhiveaza ntr-un fisier war.


jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html
6. Utilizand apache-tomcat sau jetty, de exemplu, fisierul war se copiaza n
catalogul webapps al serverului web.
Dintr-un navigator, apelarea aplicatiei se obtine prin
http://host:8080/cmmdc/cmmdc.html.
Daca aplicatia Java utilizeaza imagini grafice acestea trebuie arhivate
mpreuna cu aplicatia, de exemplu ntr-un catalog images.
Incarcarea si afisarea unei imagini programandu-se prin
ClassLoader cl=this.getClass().getClassLoader();
URL file=cl.getResource("images/pic1.jpg");
Image img=Toolkit.getDefaultToolkit().getImage(file);
graphics.drawImage(img,x,y,this);

1. Daca aplicatia Java utilizeaza alte resurse date prin fisiere jar
atunci toate fisierele jar trebuie sa poarte aceasi certificare.
2. Fisierele jar certificate se depun n catalogul app\lib.
3. In fisierul jnlp, n elementul resources, pentru fiecare fisier jar
utilizat se introduce declaratia
<jar href=lib/resource.jar/>

282

CAPITOLUL 11. JAVA WEB START

Daca arhiva jar a aplicatiei Java este executabila atunci, n fisierul jnlp,
elementul application-desc poate lipsi.
Intr-o arhiva jar executabila, fisierul MANIFEST.MF indica clasa cu metoda
main si eventualele resurse externe utilizate (fisiere jar) prin proprietatile
Main-class: numeClasa
Class-path: lib/resursa1.jar lib/resursa2.jar . . .

Pentru a obtine fisierul MANIFEST.MF cu aceste proprietati se editeaza un


fisier text cu continutul de mai sus, denumit de exemplu myManifest.mf,
si se arhiveaza prin
jar cfvm numeArhiva.jar myManifest.mf *.class lib

In mod asemanator se procedeaza si pentru introducerea proprietatii


Permissions: all-permissions.

Intreb
ari recapitulative
1. Ce posibilitate ofera tehnologia Java Web Start ?
2. O aplicatie Java urmeaza sa fie valorificat pe Internet prin Java Web
Start. Daca aplicatia necesita date ale clientului ce restrictie exista si
cum se satisface restrictia ?
3. Ce nseamna abrevierea JNLP?
4. Unde se utilizeaza JNLP?
5. In ce consta utilizarea protocolului JNLP?
6. Care este programul executabil care preceseaza un fisier jnlp?

Capitolul 12
WebSocket
HTML5 introduce protocolul WebSocket pentru comunicatii bidirectionale
ntre un client HTML5 dintr-un navigator si un server Web. Utilizarea protocolului WebSocket conduce la reducerea semnificativa a traficului n retea.
Toate navigatoarele importante suporta protocolul WebSocket.

12.1

Protocolul WebSocket

Protocolul websocket se initiaza dintr-o comunicatie bazata pe protocolul


http prin mecanismul upgrade, introdus de servlet-api 3.0: Intr-un mesaj http
trimis de client se indica solicitarea de trecere de la protocolul http la protocolul WebSocketprin prezenta antetului Upgrade: websocket. Exemplul
unui asemenea mesaj este
GET /HelloWebSocket/hello HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:9090
Origin: null
Sec-WebSocket-Key: tLZ8VGZ8Cw8kt0BvhuV6Vw==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
Cookie: JSESSIONID=2BCFF666164139524DD92D573C3859F7;
JSESSIONID=bf12d2417e8eb1bcd6da6137af9d;
treeForm_tree-hi=treeForm:tree:applications

Mesajul de raspuns afirmativ este


HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ZDE5NmS4T9spIby8/vo/V+rbNAs=

Daca ntre cei doi parteneri se stabileste acordul (handshake) atunci restul
comunicatiilor au loc prin intermediul unui soclu TCP pe portul 80.
Astfel ciclul de viata al procesului de comunicatie este:
283

284

CAPITOLUL 12. WEBSOCKET

1. Un client solicita printr-un mesaj http acordul pentru trecerea la protocolul WebSocket.
2. Serverul raspunde acceptand acordul.
3. Odata stabilita conexiunea, acesta devine bidirectionala (simetrica), clientul si serverul transmit si receptioneaza mesaje.
4. Una din parti nchide conexiunea.

12.2

Interfata de programare HTML5 de client


WebSocket

Interfata de programare este definita de un obiect JavaScript:


Constructor
WebSocket(in String uri )
unde uri este de forma ws://host:port/context/numeApel
Functii
attribute function onopen(evt)
attribute function onmessage(evt)
attribute function onerror(evt)
attribute function onclose(evt)
boolean send(in String data)
close()
Atribute
readyState
Starea conexiunii:
Valoare
0
1
2
3

Semnificatia
Nu s-a stabilit conexiunea
Conexiune pregatita pentru comunicatii
Conexiune n pragul confirmarii (handshake)
Conexiune nchisa si nu mai poate fi redeschisa

12.3. WEBSOCKET IN JAVA

285

bufferedAmount
Numarul octetilor trimisi de functia send. Datele sunt codificate UTF-8.
Un sablon de utilizare poate fi
<script language="javascript" type="text/javascript">
var wsUri = "ws://host:8080/context/numeApel";
var websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { . . . };
websocket.onmessage = function(evt) { . . . };
websocket.onerror = function(evt) { . . . };
websocket.onclose = function(evt) { . . . };
. . .
</script>

Expedierea datelor.
Consideram formularul HTML
<form name="myform">
<input type="text" name="xyz" . . ./>
. . .
<input type="button" onclick="send"/>
</form>

Sablonul functiei send este


function send(){
var xyz=document.myform.xyz.value;
websocket.send(xyz);
}

Receptia unui rezultat furnizat de server. Functia onmessage permite recuperarea rezultatului din evt.data.

12.3

WebSocket n Java

Interfata de programare Java pentru WebSocket declara clase atat pentru


server cat si pentru client.
Servet-API 3.1 contine specificatiile JSR 356 (Java Specification Request)
pentru WebSocket. O implementare de referinta a fost realizata de Oracle n
pachetul tyrus inclusa n glassfish 4.
Pentru server doua moduri de programare sunt definite :
Prin utilizarea adnotarilor (Annotation driven);
Fara utilizarea adnotarilor (Interface driven).

286

CAPITOLUL 12. WEBSOCKET

12.3.1

Programare prin adnot


ari

Sablonul de programare este


@ServerEndpoint(value="/urlPattern")
public class EndpointWebSocketServer {
private static Set<Session> sessions =
Collections.synchronizedSet(new HashSet<Session>());
@OnMessage
public void myTask(String msg, Session session)
throws IOException,EncodeException{
. . .
}
@OnOpen
public void onOpen(Session session){
sessions.add(session);
}
@OnClose
public void onClose(Session session){
sessions.remove(session);
}
}

Metoda cu adnotareae @OnMessage asigura accesul la datele cererii unui client.


Interfata javax.websocket.Session
Metode
void addMessageHandler(MessageHandler handler )
RemoteEndpoint.Basic getBasicRemote()
Prin intermediul unui obiect de tip RemoteEndpoint.Basic se programeaza
expedierea raspunsului catre client.
RemoteEndpoint.Async getAsyncRemote()
void close()
Interfata RemoteEndpoint are subinterfetele
RemoteEndpoint.Async
RemoteEndpoint.Basic.

12.3. WEBSOCKET IN JAVA

287

Interfata javax.websocket.RemoteEndpoint.Basic
Metode
void sendObject(Object data) throws IOException,EncodeException
void sendText(String data) throws IOException
void sendBinary(ByteBuffer data) throws IOException
OutputStream getSendStream() throws IOException
Structura aplicatiei Web cu desfasurare n glassfish este
AppSerser
|--> WEB-INF
|
|--> classes
|
|
|
*.class
|
index.html
Exemplul 12.3.1 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatia server are codul
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
17
19
20
21
22
23
24
25
26
27

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . OnMessage ;
import j a v a x . w e b s o c k e t . s e r v e r . S e r v e r E n d p o i n t ;
import j a v a x . w e b s o c k e t . RemoteEndpoint ;
import j a v a x . w e b s o c k e t . S e s s i o n ;
import j a v a x . w e b s o c k e t . OnOpen ;
import j a v a x . w e b s o c k e t . OnClose ;
import j a v a x . w e b s o c k e t . EncodeException ;
import j a v a . i o . IOException ;
import j a v a . u t i l . S e t ;
import j a v a . u t i l . C o l l e c t i o n s ;
import j a v a . u t i l . HashSet ;
@ServerEndpoint ( v a l u e= /cmmdc )
public c l a s s CmmdcWebSocketServer {
private s t a t i c Set<S e s s i o n > s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t (new HashSet<S e s s i o n > ( ) ) ;
@OnMessage
public void myTask ( S t r i n g msg , S e s s i o n s e s s i o n )
throws IOException , EncodeException {
S t r i n g [ ] elem=msg . s p l i t ( : ) ;
long m=Long . par se Lon g ( elem [ 0 ] ) ;
long n=Long . p ars eL ong ( elem [ 1 ] ) ;
long r=cmmdc(m, n ) ;
for ( S e s s i o n peer : s e s s i o n s ) {
i f ( peer . equals ( s e s s i o n )){

288

CAPITOLUL 12. WEBSOCKET

p e e r . getBasicRemote ( ) . sendText (new Long ( r ) . t o S t r i n g ( ) ) ;

28

29

30
31

33

public long cmmdc( long m, long n ) { . . . }

35

@OnOpen
public void onOpen ( S e s s i o n s e s s i o n ) {
s e s s i o n s . add ( s e s s i o n ) ;
}

36
37
38

@OnClose
public void o n C l o s e ( S e s s i o n s e s s i o n ) {
s e s s i o n s . remove ( s e s s i o n ) ;
}

40
41
42
43
44

In Java 8 codul serverului poate fi


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

package w e b s o c k e t . cmmdc ;
im po rt j a v a x . w e b s o c k e t . OnMessage ;
im po rt j a v a x . w e b s o c k e t . s e r v e r . S e r v e r E n d p o i n t ;
im po rt j a v a x . w e b s o c k e t . S e s s i o n ;
im po rt j a v a x . w e b s o c k e t . OnOpen ;
im po rt j a v a x . w e b s o c k e t . OnClose ;
im po rt j a v a x . w e b s o c k e t . EncodeException ;
im po rt j a v a . i o . IOException ;
im po rt j a v a . u t i l . S e t ;
im po rt j a v a . u t i l . C o l l e c t i o n s ;
im po rt j a v a . u t i l . HashSet ;
im po rt j a v a . u t i l . stream . Stream ;
im po rt j a v a x . w e b s o c k e t . RemoteEndpoint ;
@ServerEndpoint ( v a l u e= /cmmdc )
p u b l i c c l a s s CmmdcWebSocketServer {
i n t e r f a c e CmmdcService {
l o n g cmmdc( l o n g m, l o n g n ) ;
}
s t a t i c CmmdcService cmmdcService=( l o n g m, l o n g n ) >
{
long r , c ;
do {
c=n ;
r=m%n ;
m=n ;
n=r ;
}
while ( r !=0);
return c ;
};
p r i v a t e s t a t i c S e t<S e s s i o n> s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t ( new HashSet<S e s s i o n> ( ) ) ;
@OnMessage
p u b l i c v o i d myTask ( S t r i n g msg , S e s s i o n s e s s i o n )
throws IOException , EncodeException {

12.3. WEBSOCKET IN JAVA

S t r i n g [ ] elem=msg . s p l i t ( : ) ;
l o n g m=Long . pa rse Lo ng ( elem [ 0 ] ) ;
l o n g n=Long . pa rse Lo ng ( elem [ 1 ] ) ;
System . out . p r i n t l n (m+ : +n ) ;
l o n g r=cmmdcService . cmmdc(m, n ) ;
S t r i n g r e z=new Long ( r ) . t o S t r i n g ( ) ;
Stream<S e s s i o n> stream=s e s s i o n s . stream ( ) ;
stream
. f i l t e r ( s>s . e q u a l s ( s e s s i o n ) )
. f o r E a c h ( s>{
RemoteEndpoint . B a s i c e n d p o i n t=s . getBasicRemote ( ) ;
try {
e n d p o i n t . sendText ( r e z ) ;
}
c a t c h ( IOException e ) { } ;
});

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

58

@OnOpen
p u b l i c v o i d onOpen ( S e s s i o n s e s s i o n ) {
s e s s i o n s . add ( s e s s i o n ) ;
}

59
60
61

@OnClose
p u b l i c void onClose ( S e s s i o n s e s s i o n ){
s e s s i o n s . remove ( s e s s i o n ) ;
}

63
64
65
66
67

Clientul HTML5/Javascript este


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

< !DOCTYPE html>


<html>
<head>
<meta httpe q u i v= ContentType content= t e x t / html ; c h a r s e t=UTF8>
< t i t l e>Cmmdc WebSocket</ t i t l e>
<s c r i p t l a n g u a g e= j a v a s c r i p t type= t e x t / j a v a s c r i p t >
v a r wsUri = ws : / / l o c a l h o s t : 8 0 8 0 / CmmdcWebSocket/cmmdc ;
v a r w e b s o c k e t = new WebSocket ( wsUri ) ;
w e b s o c k e t . onopen = f u n c t i o n ( e v t ) { onOpen ( e v t ) } ;
w e b s o c k e t . onmessage = f u n c t i o n ( e v t ) { onMessage ( e v t ) } ;
websocket . o n e r r o r = f u n c t i o n ( evt ) { onError ( evt ) } ;
websocket . o n c l o s e = f u n c t i o n ( evt ) { onClose ( evt ) } ;
function i n i t () {
ou tp ut = document . getElementById ( r e s u l t ) ;
}
f u n c t i o n send ( ) {
v a r sm=document . cmmdc .m. v a l u e ;
v a r sn=document . cmmdc . n . v a l u e ;
v a r msg=sm+ : +sn ;
w e b s o c k e t . send ( msg ) ;
w r i t e T o S c r e e n ( SENT : + msg ) ;
}
f u n c t i o n onOpen ( e v t ) {
w r i t e T o S c r e e n ( CONNECTED ) ;

289

290

CAPITOLUL 12. WEBSOCKET

29

31

f u n c t i o n onMessage ( e v t ) {
w r i t e T o S c r e e n ( RECEIVED : + e v t . data ) ;
}

32
33
35
36
37
38
40
41
42
44
45
46
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

f u n c t i o n onError ( evt ) {
w r i t e T o S c r e e n ( <span s t y l e= c o l o r : r e d ; >ERROR:</span> +
e v t . data ) ;
}
f u n c t i o n onClose ( evt ) {
w r i t e T o S c r e e n ( CLOSED ) ;
}
f u n c t i o n myclose ( ) {
websocket . c l o s e ( ) ;
}
f u n c t i o n w r i t e T o S c r e e n ( message ) {
v a r p r e = document . c r e a t e E l e m e n t ( p ) ;
p r e . s t y l e . wordWrap = breakword ;
p r e . innerHTML = message ;
o ut pu t . appendChild ( p r e ) ;
}
window . a d d E v e n t L i s t e n e r ( l o a d , i n i t , f a l s e ) ;
</ s c r i p t>
</head>
<body>
<h1>CMMDC with WebSocket ! ! </h1>
<div s t y l e= t e x t a l i g n : c e n t e r ; >
<form name=cmmdc>
<table border= 1 >
<tr>
<td> Primul num&#259; r </td>
<td> <input type=number name=m value= 1
r e q u i r e d min= 1 /> </td>
</ tr>
<tr>
<td> Al d o i l e a num&#259; r </td>
<td> <input type=number name=n value= 1
r e q u i r e d min= 1 /> </td>
</ tr>
<tr>
<td>
<input type= b ut to n value= C a l c u l e a z a onclick= send ( ) />
</td>
<td></td>
</ tr>
<tr>
<td>
<input type= b ut to n value= I n c h i d e onclick= m y c l o s e ( ) />
</td>
<td></td>
</ tr>
</ table>
</form>
</ div>

12.3. WEBSOCKET IN JAVA

88
89
90

291

<div id= r e s u l t ></ div>


</body>
</html>

12.3.2

Programare f
ar
a adnot
ari

Clasa javax.websocket.Endpoint
Metode
void onClose(Session session, CloseReason closeReason)
void onError(Session session, Throwable th)
abstract void onOpen(Session session, EndpointConfig config)
Interfata javax.websocket.MessageHandler.Whole<T>
Metode
void onMessage(T message)
In functie de
Mesaj text
String
Reader

tipul mesajului T acesta poate fi


Mesaj binar
ByteBuffer
byte[]
InputStream

Pentru acelasi exemplu, fara modificarea clientului componenta server va


fi alcatuita din doua clase:
MyApplicationConfig
n care se declara clasa care trateaza solicitarea clientului si numele de
apel (urlPattern);
CmmdcWebSocketEndpoint
clasa declarata anterior si care rezolva solicitarea clientului.
Clasa extinde clasa javax.websocket.Endpoint, programatorul implementeaza metodele onOpen, onClose, onError. In metoda onOpen, se
utilizeaza o clasa care implementeaza interfata MessageHandler.Whole
prin care avem acces la parametrii cererii.

292

CAPITOLUL 12. WEBSOCKET

Codurile sunt:

import
import
import
import

public c l a s s M y A p p l i c a t i o n C o n f i g implements S e r v e r A p p l i c a t i o n C o n f i g {

1
2
3

@Override
public Set<S e r v e r E n d p o i n t C o n f i g > g e t E n d p o i n t C o n f i g s (
Set<C l a s s <? extends Endpoint>> s e t ) {
return new HashSet<S e r v e r E n d p o i n t C o n f i g >() {
{
add ( S e r v e r E n d p o i n t C o n f i g . B u i l d e r
. c r e a t e ( CmmdcWebSocketEndpoint . c l a s s , /cmmdc )
. build ( ) ) ;
}
};
}

8
9
10
11
12
13
14
15
16
17
18

@Override
public Set<C l a s s <?>> g e t A n n o t a t e d E n d p o i n t C l a s s e s ( Set<C l a s s <?>> s e t ) {
return C o l l e c t i o n s . emptySet ( ) ;
}

20
21
22
23
24

java . u t i l . Set ;
j a v a x . w e b s o c k e t . Endpoint ;
javax . websocket . s e r v e r . S e r v e r A p p l i c a t i o n C o n f i g ;
javax . websocket . s e r v e r . ServerEndpointConfig ;

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

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . C l os e R e a s o n ;
import j a v a x . w e b s o c k e t . RemoteEndpoint ;
import j a v a x . w e b s o c k e t . S e s s i o n ;
import j a v a x . w e b s o c k e t . Endpoint ;
import j a v a x . w e b s o c k e t . E n d p o i n t C o n f i g ;
import j a v a x . w e b s o c k e t . MessageHandler ;
import j a v a x . w e b s o c k e t . EncodeException ;
import j a v a . i o . IOException ;
public c l a s s CmmdcWebSocketEndpoint extends Endpoint {
public void onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {
f i n a l RemoteEndpoint . B a s i c remote = s e s s i o n . getBasicRemote ( ) ;
s e s s i o n . addMessageHandler (new MessageHandler . Whole<S t r i n g >() {
public void onMessage ( S t r i n g msg ) {
try {
S t r i n g [ ] elem=msg . s p l i t ( : ) ;
long m=Long . par se Lon g ( elem [ 0 ] ) ;
long n=Long . p ars eL ong ( elem [ 1 ] ) ;
System . out . p r i n t l n (m+ : +n ) ;
long r=cmmdc(m, n ) ;
remote . sendText (new Long ( r ) . t o S t r i n g ( ) ) ;
}
catch ( E x c e p t i o n i o e ) { }
}
});
}
public void o n C l o s e ( S e s s i o n s e s s i o n , C l o s e R e a s o n c l o s e R e a s o n ) {
System . out . p r i n t l n ( C l o s i n g : + c l o s e R e a s o n . g e t R e a s o n P h r a s e ( ) ) ;

12.3. WEBSOCKET IN JAVA

32

34

public void o n E r r o r ( S e s s i o n s e s s i o n , Throwable t h r o w a b l e ) {


System . out . p r i n t l n ( E r r o r : + t h r o w a b l e . g e t L o c a l i z e d M e s s a g e ( ) ) ;
}

35
36

public long cmmdc( long m, long n ) { . . . }

38
39

12.3.3

Client Java pentru WebSocket

Programarea unui client Java necesita


clasa javax.websocket.Endpoint
interfata javax.websocket.Session
si n plus
Clasa javax.websocket.ContainerProvider
Metode
public static WebSocketContainer getWebSocketContainer()
Interfata javax.websocket.WebSocketContainer
Metode
Session connectToServer(Endpoint endpointInstance,
ClientEndpointConfig cec, URI path) throws
DeploymentException,IOException
Codul unui client Java pentru una din aplicatiile anterioare este
1
2
3
4
5
6
7
8
9
10
11
13
14
15

import
import
import
import
import
import
import
import
import
import
import

j a v a . i o . IOException ;
j a v a . n e t . URI ;
java . u t i l . Scanner ;
j a v a . n e t . URISyntaxException ;
javax . websocket . ContainerProvider ;
j a v a x . w e b s o c k e t . DeploymentException ;
j a v a x . w e b s o c k e t . WebSocketContainer ;
javax . websocket . S e s s i o n ;
j a v a x . w e b s o c k e t . Endpoint ;
javax . websocket . EndpointConfig ;
j a v a x . w e b s o c k e t . MessageHandler ;

public c l a s s WebSocketClient extends Endpoint {


private s t a t i c boolean s f a r s i t =f a l s e ;
private s t a t i c S t r i n g SERVER =

293

294

CAPITOLUL 12. WEBSOCKET

16

ws : / / l o c a l h o s t : 8 0 8 0 / CmmdcWebSocketAD/cmmdc ;

18

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
S t r i n g sm=new Long (m) . t o S t r i n g ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g sn=new Long ( n ) . t o S t r i n g ( ) ;
S t r i n g data=sm+ : +sn ;
WebSocketContainer c o n t a i n e r =
C o n t a i n e r P r o v i d e r . getWebSocketContainer ( ) ;

19
20
21
22
23
24
25
26
27
28

try {
Session s e s s i o n = container . connectToServer (
WebSocketClient . c l a s s , null , new URI (SERVER ) ) ;
s e s s i o n . getBasicRemote ( ) . sendText ( data ) ;
while ( ! s f a r s i t ) { System . out . p r i n t l n ( ) ; } ;
session . close ();
}
catch ( E x c e p t i o n ex ) {
System . out . p r i n t l n ( LocalEndPoint E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ;
}

30
31
32
33
34
35
36
37
38
39
40

42

public void onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {


s e s s i o n . addMessageHandler (new MessageHandler . Whole<S t r i n g >() {
public void onMessage ( S t r i n g t e x t ) {
System . out . p r i n t l n ( Cmmdc : +t e x t ) ;
s f a r s i t =true ;
}
});
}

43
44
45
46
47
48
49
50

12.3.4

Transmiterea datelor prin adnotarea PathParam

In varianta cu adnotare utilizand ServerEndpoint de forma


@ServerEndpoint(/urlPattern/{param})
un parametru dat este accesibil prin
@OnOpen
public void onOpen(Session session,
@PathParam("param") String param) {
. . .
}
Exemplul 12.3.2

295

12.3. WEBSOCKET IN JAVA

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

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . OnMessage ;
import j a v a x . w e b s o c k e t . s e r v e r . S e r v e r E n d p o i n t ;
import j a v a x . w e b s o c k e t . S e s s i o n ;
import j a v a x . w e b s o c k e t . OnOpen ;
import j a v a x . w e b s o c k e t . OnClose ;
import j a v a x . w e b s o c k e t . OnError ;
import j a v a x . w e b s o c k e t . RemoteEndpoint ;
import j a v a x . w e b s o c k e t . EncodeException ;
import j a v a x . w e b s o c k e t . s e r v e r . PathParam ;
import j a v a . i o . IOException ;
import j a v a . u t i l . S e t ;
import j a v a . u t i l . C o l l e c t i o n s ;
import j a v a . u t i l . HashSet ;
@ServerEndpoint ( v a l u e= /cmmdc/{msg} )
public c l a s s CmmdcWebSocketServer {
private s t a t i c Set<S e s s i o n > s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t (new HashSet<S e s s i o n > ( ) ) ;

23

i n t e r f a c e CmmdcService {
long cmmdc( long m, long n ) ;
}

25

s t a t i c CmmdcService cmmdcService=(long m, long n ) > { . .

27

@OnMessage
public void onMessage ( S t r i n g message , S e s s i o n s e s s i o n ) { }

21
22

28

@OnOpen
public void onOpen ( S e s s i o n s e s s i o n , @PathParam ( msg ) S t r i n g msg )
throws IOException , EncodeException {
s e s s i o n s . add ( s e s s i o n ) ;
S t r i n g [ ] elem=msg . s p l i t ( : ) ;
long m=Long . par se Lon g ( elem [ 0 ] ) ;
long n=Long . p ars eL ong ( elem [ 1 ] ) ;
long r=cmmdcService . cmmdc(m, n ) ;
S t r i n g r e z=new Long ( r ) . t o S t r i n g ( ) ;
s e s s i o n s . stream ( )
. f i l t e r ( s>s . e q u a l s ( s e s s i o n ) )
. f o r E a c h ( s>{
RemoteEndpoint . B a s i c e n d p o i n t=s . getBasicRemote ( ) ;
try {
e n d p o i n t . sendText ( r e z ) ;
}
catch ( IOException e ) { } ;
});
}

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

@OnClose
public void o n C l o s e ( S e s s i o n s e s s i o n ) {
s e s s i o n s . remove ( s e s s i o n ) ;
}

50
51
52
53
54

cu apelarea din
1
2

.};

< !DOCTYPE html>


<html>

296

3
4
5
7
8
10
11
12
14
15
16
17
18
19
20
21
22
23
24
26
27
28
30
31
32
34
35
36
38
39
40
41
43
44
45
47
48
49
50
51
52
54
55
56
57
58
59
60
61

CAPITOLUL 12. WEBSOCKET

<head>
<meta httpe q u i v= ContentType content= t e x t / html ; c h a r s e t=UTF8>
< t i t l e>Cmmdc WebSocket</ t i t l e>
<s c r i p t l a n g u a g e= j a v a s c r i p t type= t e x t / j a v a s c r i p t >
var websocket ;
function i n i t () {
o ut pu t = document . getElementById ( r e s u l t ) ;
}
f u n c t i o n send ( ) {
v a r sm=document . cmmdc .m. v a l u e ;
v a r sn=document . cmmdc . n . v a l u e ;
v a r msg=sm+ : +sn ;
v a r wsUri = ws : / / l o c a l h o s t : 8 0 8 0 / CmmdcWebSocketAD/cmmdc/ +msg ;
w e b s o c k e t = new WebSocket ( wsUri ) ;
w e b s o c k e t . onopen = f u n c t i o n ( e v t ) { onOpen ( e v t ) } ;
w e b s o c k e t . onmessage = f u n c t i o n ( e v t ) { onMessage ( e v t ) } ;
websocket . o n e r r o r = f u n c t i o n ( evt ) { onError ( evt ) } ;
websocket . o n c l o s e = f u n c t i o n ( evt ) { onClose ( evt ) } ;
}
f u n c t i o n myclose ( ) {
websocket . c l o s e ( ) ;
}
f u n c t i o n onOpen ( e v t ) {
w r i t e T o S c r e e n ( CONNECTED ) ;
}
f u n c t i o n onMessage ( e v t ) {
w r i t e T o S c r e e n ( RECEIVED : + e v t . data ) ;
}
f u n c t i o n onError ( evt ) {
w r i t e T o S c r e e n ( <span s t y l e= c o l o r : r e d ; >ERROR:</span> +
e v t . data ) ;
}
f u n c t i o n onClose ( evt ) {
w r i t e T o S c r e e n ( CLOSED ) ;
}
f u n c t i o n w r i t e T o S c r e e n ( message ) {
v a r p r e = document . c r e a t e E l e m e n t ( p ) ;
p r e . s t y l e . wordWrap = breakword ;
p r e . innerHTML = message ;
o ut pu t . appendChild ( p r e ) ;
}
window . a d d E v e n t L i s t e n e r ( l o a d , i n i t , f a l s e ) ;
</ s c r i p t>
</head>
<body>
<h1>CMMDC with WebSocket ! ! </h1>
<div s t y l e= t e x t a l i g n : c e n t e r ; >
<form name=cmmdc>
<table border= 1 >

12.3. WEBSOCKET IN JAVA

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

297

<tr>
<td> Primul num&#259; r </td>
<td> <input type=number name=m value= 1
r e q u i r e d min= 1 /> </td>
</ tr>
<tr>
<td> Al d o i l e a num&#259; r </td>
<td> <input type=number name=n value= 1
r e q u i r e d min= 1 /> </td>
</ tr>
<tr>
<td>
<input type= b ut to n value= C a l c u l e a z a onclick= send ( ) />
</td>
<td></td>
</ tr>
<tr>
<td>
<input type= b ut to n value= I n c h i d e onclick= m y c l o s e ( ) />
</td>
<td></td>
</ tr>
</ table>
</form>
</ div>
<div id= r e s u l t ></ div>
</body>
</html>

12.3.5

Conversie si deconversie prin JSON / XML

Interfata de programare pentru WebSocket ofera posibilitatea conversiei


unei componente Java ntr-un obiect JSON sau document XML1 si transformarea inversa.
Programatorul trebuie sa
Implementeze interfetele Encoder.Text<T> si Decoder.Text<T>;
Declare clasele de conversie si deconversie n adnotarea @ServerEndpoint,
sub forma
@ServerEndpoint(value="/numeApel",
encoders={ClasaConversie.class,. . .},
decoders={ClasaDeconversie.class,. . .})

Sablonul de implementare al interfetei Encoder.Text este


1

Parcurgerea acestei sectiuni necesit


a familiarizarea cu Java Script Object Notation JSON
si JAXB. Pentru JSON se va utiliza pachetul javax.json din JEE.

298

CAPITOLUL 12. WEBSOCKET

import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import javax.websocket.EncodeException;
public class MyEncoder implements Encoder.Text<T> {
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
@Override
public String encode(T obj) throws EncodeException{
// Cod de conversie al campurilor obiectului obj in JSON
return objJsonString;
}
}

Sablonul de implementare al interfetei Decoder.Text este


import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import javax.websocket.DecodeException;
public class MyDecoder implements Decoder.Text<T>{
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
@Override
public T decode(String string) throws DecodeException{
// Instantierea unui obiect de tip T cu datele din string.
}
@Override
public boolean willDecode(String string) {
return true;
}
}

Exemplul 12.3.3
Fie componenta Java
1

import j a v a x . xml . bind . a n n o t a t i o n . XmlRootElement ;

@XmlRootElement ( name= d a t e )
public c l a s s CmmdcBean{
private long m;
private long n ;
public void setM ( long m) {
t h i s .m=m;
}

4
5
6
7
8
9
11
12

public long getM ( ) {


return m;

12.3. WEBSOCKET IN JAVA

13

15

public void setN ( long n ) {


t h i s . n=n ;
}

16
17

public long getN ( ) {


return n ;
}

19
20
21
22

299

Aplicatia server utilizeaza doar decodorul - transformarea din JSON / XML


n obiect de tip CmmdcBean. Transformarea este realizata de serverul Web.
Codul serverului este
1
2
3
4
5
6
7
8
9
10
11
13
14
15
16
17

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . OnMessage ;
import j a v a x . w e b s o c k e t . s e r v e r . S e r v e r E n d p o i n t ;
import j a v a x . w e b s o c k e t . S e s s i o n ;
import j a v a x . w e b s o c k e t . OnOpen ;
import j a v a x . w e b s o c k e t . OnClose ;
import j a v a x . w e b s o c k e t . EncodeException ;
import j a v a . i o . IOException ;
import j a v a . u t i l . S e t ;
import j a v a . u t i l . C o l l e c t i o n s ;
import j a v a . u t i l . HashSet ;
@ServerEndpoint ( v a l u e= /cmmdc ,
d e c o d e r s={CmmdcBeanXMLDecoder . c l a s s , CmmdcBeanJSONDecoder . c l a s s } )
public c l a s s CmmdcWebSocketServer {
private s t a t i c Set<S e s s i o n > s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t (new HashSet<S e s s i o n > ( ) ) ;
@OnMessage
public void myTask ( S e s s i o n s e s s i o n , CmmdcBean o b j )
throws IOException , EncodeException {
long m=o b j . getM ( ) ;
long n=o b j . getN ( ) ;
long r=cmmdc(m, n ) ;
for ( S e s s i o n peer : s e s s i o n s ) {
i f ( peer . equals ( s e s s i o n )){
p e e r . getBasicRemote ( ) . sendText (new Long ( r ) . t o S t r i n g ( ) ) ;
}
}
}

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

@OnOpen
public void onOpen ( S e s s i o n s e s s i o n ) {
s e s s i o n s . add ( s e s s i o n ) ;
}

32
33
34
35

@OnClose
public void o n C l o s e ( S e s s i o n s e s s i o n ) {
s e s s i o n s . remove ( s e s s i o n ) ;
}

37
38
39
40

public long cmmdc( long m, long n ) { . . . }

42
43

300

CAPITOLUL 12. WEBSOCKET

Codul decodorului din JSON este


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

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . Decoder ;
import j a v a x . w e b s o c k e t . E n d p o i n t C o n f i g ;
import j a v a x . w e b s o c k e t . DecodeException ;
import j a v a x . j s o n . Json ;
import j a v a x . j s o n . JsonArray ;
import j a v a x . j s o n . J s o n O b j e c t ;
import j a v a x . j s o n . JsonReader ;
import j a v a . i o . S t r i n g R e a d e r ;
public c l a s s CmmdcBeanJSONDecoder implements Decoder . Text<CmmdcBean>{
@Override
public void i n i t ( E n d p o i n t C o n f i g e c ) { }
@Override
public void d e s t r o y ( ) { }

15
16

@Override
public CmmdcBean de co de ( S t r i n g s t r i n g ) throws DecodeException {
S t r i n g R e a d e r s r=new S t r i n g R e a d e r ( s t r i n g ) ;
JsonReader j s o n R e a d e r = Json . c r e a t e R e a d e r ( s r ) ;
J s o n O b j e c t o b j=j s o n R e a d e r . r e a d O b j e c t ( ) ;
jsonReader . c l o s e ( ) ;
long m=0 ,n=0;
S t r i n g sm=o b j . g e t S t r i n g ( m ) ;
m=Long . par se Lon g ( sm ) ;
S t r i n g sn=o b j . g e t S t r i n g ( n ) ;
n=Long . p ars eL ong ( sn ) ;
CmmdcBean bean=new CmmdcBean ( ) ;
bean . setM (m) ;
bean . setN ( n ) ;
return bean ;
}

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

@Override
public boolean w i l l D e c o d e ( S t r i n g s t r i n g ) {
return true ;
}

35
36
37
38
39

iar codul decodorului din XML este


1
2
3
4
5
6
7
9
10
11

package w e b s o c k e t . cmmdc ;
import j a v a x . w e b s o c k e t . Decoder ;
import j a v a x . w e b s o c k e t . E n d p o i n t C o n f i g ;
import j a v a x . w e b s o c k e t . DecodeException ;
import j a v a x . xml . bind . JAXBContext ;
import j a v a x . xml . bind . U n m a r s h a l l e r ;
import j a v a . i o . S t r i n g R e a d e r ;
public c l a s s CmmdcBeanXMLDecoder implements Decoder . Text<CmmdcBean>{
@Override
public void i n i t ( E n d p o i n t C o n f i g e c ) { }

14

@Override
public void d e s t r o y ( ) { }

16

@Override

13

12.3. WEBSOCKET IN JAVA

public CmmdcBean de co de ( S t r i n g s t r i n g ) throws DecodeException {


S t r i n g R e a d e r s r=new S t r i n g R e a d e r ( s t r i n g ) ;
CmmdcBean bean=n u l l ;
JAXBContext j a x b C o n t e x t ;
try {
j a x b C o n t e x t=JAXBContext . n e w I n s t a n c e (CmmdcBean . c l a s s ) ;
U n m a r s h a l l e r u n m a r s h a l l e r=j a x b C o n t e x t . c r e a t e U n m a r s h a l l e r ( ) ;
bean=(CmmdcBean) u n m a r s h a l l e r . unmarshal ( s r ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}
return bean ;
}

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

@Override
public boolean w i l l D e c o d e ( S t r i n g s t r i n g ) {
return ( s t r i n g != n u l l ) ;
}

32
33
34
35
36

301

Clasa clientului utilizeaza doar conversia datelor n obiect JSON sau XML.
Codorul n JSON este
1
2
3
4
5
7
8
9

import
import
import
import
import

public c l a s s CmmdcBeanJSONEncoder implements Encoder . Text<CmmdcBean> {


@Override
public void i n i t ( E n d p o i n t C o n f i g e c ) { }
@Override
public void d e s t r o y ( ) { }

11
12

@Override
public S t r i n g e nc od e (CmmdcBean o b j ) throws EncodeException {
long m=o b j . getM ( ) ;
long n=o b j . getN ( ) ;
J s o n O b j e c t j s o n O b j e c t=Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( m ,new Long (m) . t o S t r i n g ( ) )
. add ( n ,new Long ( n ) . t o S t r i n g ( ) )
. build ( ) ;
S t r i n g o b j J s o n S t r i n g=j s o n O b j e c t . t o S t r i n g ( ) ;
return o b j J s o n S t r i n g ;
}

14
15
16
17
18
19
20
21
22
23
24
25

j a v a x . w e b s o c k e t . Encoder ;
javax . websocket . EndpointConfig ;
j a v a x . w e b s o c k e t . EncodeException ;
j a v a x . j s o n . Json ;
javax . json . JsonObject ;

iar codorul n XML este


1
2
3
4
5
6

import
import
import
import
import
import

j a v a x . w e b s o c k e t . Encoder ;
javax . websocket . EndpointConfig ;
j a v a x . w e b s o c k e t . EncodeException ;
j a v a x . xml . bind . JAXBContext ;
j a v a x . xml . bind . M a r s h a l l e r ;
java . io . StringWriter ;

302

8
9
10

public c l a s s CmmdcBeanXMLEncoder implements Encoder . Text<CmmdcBean> {


@Override
public void i n i t ( E n d p o i n t C o n f i g e c ) { }
@Override
public void d e s t r o y ( ) { }

12
13

@Override
public S t r i n g e nc od e (CmmdcBean o b j ) throws EncodeException {
JAXBContext j a x b C o n t e x t=n u l l ;
S t r i n g W r i t e r s t=n u l l ;
try {
j a x b C o n t e x t=JAXBContext . n e w I n s t a n c e (CmmdcBean . c l a s s ) ;
M a r s h a l l e r m a r s h a l l e r=j a x b C o n t e x t . c r e a t e M a r s h a l l e r ( ) ;
s t=new S t r i n g W r i t e r ( ) ;
m a r s h a l l e r . m ar sh al ( obj , s t ) ;
System . out . p r i n t l n ( R e s u l t s : +s t . t o S t r i n g ( ) ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}
return s t . t o S t r i n g ( ) ;
}

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

CAPITOLUL 12. WEBSOCKET

Codul clasei client este


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

import
import
import
import
import
import
import
import

j a v a . n e t . URI ;
javax . websocket . ContainerProvider ;
j a v a x . w e b s o c k e t . WebSocketContainer ;
javax . websocket . S e s s i o n ;
java . u t i l . Scanner ;
j a v a x . w e b s o c k e t . Endpoint ;
javax . websocket . EndpointConfig ;
j a v a x . w e b s o c k e t . MessageHandler ;

public c l a s s WebSocketClient extends Endpoint {


private s t a t i c boolean s f a r s i t =f a l s e ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
CmmdcBean o b j=new CmmdcBean ( ) ;
o b j . setM (m) ;
o b j . setN ( n ) ;
i n t t i p =1;
S t r i n g s e r v e r= ;
do{
System . out . p r i n t l n ( Encoder Type ) ;
System . out . p r i n t l n ( 1 : JSON ) ;
System . out . p r i n t l n ( 2 : XML ) ;
t i p=s c a n n e r . n e x t I n t ( ) ;
}
while ( ( t i p !=1) && ( t i p ! = 2 ) ) ;
WebSocketContainer c o n t a i n e r =

12.3. WEBSOCKET IN JAVA

C o n t a i n e r P r o v i d e r . getWebSocketContainer ( ) ;
S t r i n g r e q u e s t=n u l l ;
try {
i f ( t i p ==1){
s e r v e r=ws : / / l o c a l h o s t : 8 0 8 0 / JsonCmmdcWebSocket/cmmdc ;
CmmdcBeanJSONEncoder encoderJSON=new CmmdcBeanJSONEncoder ( ) ;
r e q u e s t=encoderJSON . en co de ( o b j ) ;
}
else {
s e r v e r=ws : / / l o c a l h o s t : 8 0 8 0 / XmlCmmdcWebSocket/cmmdc ;
CmmdcBeanXMLEncoder encoderXML=new CmmdcBeanXMLEncoder ( ) ;
r e q u e s t=encoderXML . en co de ( o b j ) ;
}
System . out . p r i n t l n ( r e q u e s t ) ;
S e s s i o n s e s s i o n=
c o n t a i n e r . c o n n e c t T o S e r v e r ( WebSocketClient . c l a s s , null ,
new URI ( s e r v e r ) ) ;
s e s s i o n . getBasicRemote ( ) . sendText ( r e q u e s t ) ;
while ( ! s f a r s i t ) { ; } ;
}
catch ( E x c e p t i o n ex ) {
System . out . p r i n t l n ( LocalEndPoint E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ;
}

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

58

public void onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {


s e s s i o n . addMessageHandler (new MessageHandler . Whole<S t r i n g >() {
public void onMessage ( S t r i n g t e x t ) {
System . out . p r i n t l n ( Cmmdc : +t e x t ) ;
s f a r s i t =true ;
System . e x i t ( 0 ) ;
}
});
}

59
60
61
62
63
64
65
66
67

303

Verificare prin tyrus-client


Verificarea functionarii unui server WebSocket se poate realiza cu aplicatia
tyrus-client-cli-*.jar prin
java -jar tyrus-client-cli-*.jar ws://host:8080/context/numeApel

Comenzile care se pot utiliza se obtin prin comanda help.


In cazul aplicatiei CmmdcWebSocketAD, daca m = 56 si n = 42 atunci se
va cere
send 56:42
close
quit

304

CAPITOLUL 12. WEBSOCKET

12.3.6

Streaming

Prin socluri se pot transmite fluxuri de date (streaming). Detalii de programare depind de natura datelor ce trebuie vehiculate (text, sunet, grafica).
Expedierea datelor de catre server se realizeaza prin intermediul unui flux
dat de metoda
OutputStream getSendStream()
a clasei javax.websocket.RemoteEndpoint.Basic.
Exemplul 12.3.4 Clientul solicita serverului transmisia unui fisier text, cerere
care va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe care le poate
trimite serverul.
Atat pentru programul server cat si pentru programul client indicam doua
solutii care se corespund.
Clasa server TextStreaming
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
17
18
19
20
21
22
23
25
26
27
28
30
31
32
33
34

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

j a v a x . w e b s o c k e t . OnMessage ;
javax . websocket . s e r v e r . ServerEndpoint ;
javax . websocket . S e s s i o n ;
j a v a x . w e b s o c k e t . OnOpen ;
j a v a x . w e b s o c k e t . OnClose ;
j a v a x . w e b s o c k e t . EncodeException ;
j a v a . i o . IOException ;
j a v a . i o . OutputStream ;
java . u t i l . Set ;
java . u t i l . C o l l e c t i o n s ;
j a v a . u t i l . HashSet ;
j a v a . n i o . f i l e . Paths ;

// V a r i a n t a 1
/
import java . i o . F i l e ;
import java . i o . FileReader ;
import java . i o . BufferedReader ;
i m p o r t j a v a . i o . DataOutputStream ;
/
// V a r i a n t a 2
import j a v a . n i o . f i l e . Path ;
import j a v a . n i o . f i l e . F i l e s ;
@ServerEndpoint ( v a l u e= / t e x t )
public c l a s s TextStreaming {
private s t a t i c Set<S e s s i o n > s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t (new HashSet<S e s s i o n > ( ) ) ;
@OnMessage
public void myTask ( S t r i n g msg , S e s s i o n s e s s i o n )
throws IOException , EncodeException {
S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;
S t r i n g p a t h S e r v e r=new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ;

12.3. WEBSOCKET IN JAVA

i n t x=p a t h S e r v e r . i n d e x O f ( g l a s s f i s h ) ;
S t r i n g path= ;
S t r i n g path0=f s+ TextStreaming +
f s+WEBINF+f s+ t e x t +f s ;
i f ( x==1){
// apachetomcat
path=Paths . g e t ( p a t h S e r v e r ) . t o S t r i n g ()+
f s+ webapps +path0 ;
}
else {
// g l a s s f i s h
x=p a t h S e r v e r . l a s t I n d e x O f ( f s ) ;
S t r i n g p a t h G l a s s f i s h=p a t h S e r v e r . s u b s t r i n g ( 0 , x ) ;
path=Paths . g e t ( p a t h G l a s s f i s h ) . t o S t r i n g ()+
f s+ a p p l i c a t i o n s +path0 ;
}
i n t n o F i l e=I n t e g e r . p a r s e I n t ( msg ) ;
S t r i n g f i l e N a m e= ;
switch ( n o F i l e ) {
case 1 :
f i l e N a m e= c a p i t o l . t x t ;
break ;
case 2 :
f i l e N a m e= j u n i t . t e x ;
break ;
}
System . out . p r i n t l n ( path+f i l e N a m e ) ;
// V a r i a n t a 1
/
F i l e i n p u t F i l e=new F i l e ( p a t h+f i l e N a m e ) ;
F i l e R e a d e r f r=new F i l e R e a d e r ( i n p u t F i l e ) ;
B u f f e r e d R e a d e r b r= new B u f f e r e d R e a d e r ( f r ) ;
fo r ( Session peer : s e s s i o n s ) {
i f ( peer . equals ( s e s s i o n )){
OutputStream o u t=p e e r . getBasicRemote ( ) . getSendStream ( ) ;
DataOutputStream dos=new DataOutputStream ( o u t ) ;
String s ;
w h i l e ( ( s=b r . r e a d L i n e ( ) ) ! = n u l l ) dos . writeUTF ( s ) ;
dos . writeUTF ( e n d O F f i l e ) ;
dos . f l u s h ( ) ;
br . c l o s e ( ) ;
fr . close ();
dos . c l o s e ( ) ;
}
}
/

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

// V a r i a n t a 2
Path c a l e=Paths . g e t ( path+f i l e N a m e ) ;
for ( S e s s i o n peer : s e s s i o n s ) {
i f ( peer . equals ( s e s s i o n )){
OutputStream out=p e e r . getBasicRemote ( ) . getSendStream ( ) ;
F i l e s . copy ( c a l e , out ) ;
out . c l o s e ( ) ;
}
}

82
83
84
85
86
87
88
89
90
91

93

@OnOpen

305

306
public void onOpen ( S e s s i o n s e s s i o n ) {
s e s s i o n s . add ( s e s s i o n ) ;
}

94
95
96

@OnClose
public void o n C l o s e ( S e s s i o n s e s s i o n ) {
s e s s i o n s . remove ( s e s s i o n ) ;
}

98
99
100
101
102

CAPITOLUL 12. WEBSOCKET

Clasa clientului Java WebSocketClient


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

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

j a v a . i o . IOException ;
j a v a . n e t . URI ;
javax . websocket . ContainerProvider ;
j a v a x . w e b s o c k e t . DeploymentException ;
j a v a x . w e b s o c k e t . WebSocketContainer ;
javax . websocket . S e s s i o n ;
java . u t i l . Scanner ;
j a v a x . w e b s o c k e t . Endpoint ;
javax . websocket . EndpointConfig ;
j a v a x . w e b s o c k e t . MessageHandler ;
j a v a . i o . DataInputStream ;
j a v a . i o . InputStream ;
j a v a . i o . ByteArrayInputStream ;

public c l a s s WebSocketClient extends Endpoint {


private s t a t i c boolean s f a r s i t =f a l s e ;
private s t a t i c S t r i n g SERVER=ws : / / l o c a l h o s t : 8 0 8 0 / TextStreaming / t e x t ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( F i s i e r u l de a c c e s a t : ) ;
System . out . p r i n t l n ( 1 : c a p i t o l . t x t ) ;
System . out . p r i n t l n ( 2 : j u n i t . t e x ) ;
i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ;
S t r i n g data=new I n t e g e r ( n o F i l e ) . t o S t r i n g ( ) ;
WebSocketContainer c o n t a i n e r =
C o n t a i n e r P r o v i d e r . getWebSocketContainer ( ) ;
try {
S e s s i o n s e s s i o n=
c o n t a i n e r . c o n n e c t T o S e r v e r ( WebSocketClient . c l a s s , null ,
new URI (SERVER ) ) ;
s e s s i o n . getBasicRemote ( ) . sendText ( data ) ;
while ( ! s f a r s i t ) { ; } ;
}
catch ( E x c e p t i o n ex ) {
System . out . p r i n t l n ( LocalEndPoint E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ;
}
}
// V a r i a n t a 1
/
p u b l i c v o i d onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {
s e s s i o n . addMessageHandler ( new MessageHandler . Whole<b y t e [ ] > ( ) {
p u b l i c v o i d onMessage ( b y t e [ ] msg ) {
t r y ( InputStream i s=new ByteArrayInputStream ( msg ) ;
DataInputStream i n = new DataInputStream ( i s ) ) {
String s ;

12.3. WEBSOCKET IN JAVA

w h i l e ( ! ( s=i n . readUTF ( ) ) . e q u a l s ( e n d O F f i l e ) )
System . o u t . p r i n t l n ( s ) ;

48
49

}
c a t c h ( IOException e ) {
e . printStackTrace ( ) ;
}
s f a r s i t =t r u e ;

50
51
52
53
54

55

});

56

}
/

57
58

// Variana 2
public void onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {
s e s s i o n . addMessageHandler (new MessageHandler . Whole<byte [ ] > ( ) {
public void onMessage ( byte [ ] msg ) {
System . out . p r i n t l n (new S t r i n g ( msg ) ) ;
s f a r s i t =true ;
}
});
}

60
61
62
63
64
65
66
67
68
69

307

Exemplul 12.3.5 Clientul solicita serverului transmisia unui fisier grafic,


cerere care va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe
care le poate trimite serverul.
Clasa server ImageStreaming
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
17
18
19
21
22
23
24
25
26
27

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

j a v a x . w e b s o c k e t . OnMessage ;
javax . websocket . s e r v e r . ServerEndpoint ;
javax . websocket . S e s s i o n ;
j a v a x . w e b s o c k e t . OnOpen ;
j a v a x . w e b s o c k e t . OnClose ;
j a v a x . w e b s o c k e t . EncodeException ;
j a v a . i o . IOException ;
j a v a . i o . OutputStream ;
java . u t i l . Set ;
java . u t i l . C o l l e c t i o n s ;
j a v a . u t i l . HashSet ;
j a v a . n i o . f i l e . Paths ;
j a v a . n i o . f i l e . Path ;
java . nio . f i l e . F i l e s ;

@ServerEndpoint ( v a l u e= / image )
public c l a s s ImageStreaming {
private s t a t i c Set<S e s s i o n > s e s s i o n s =
C o l l e c t i o n s . s y n c h r o n i z e d S e t (new HashSet<S e s s i o n > ( ) ) ;
@OnMessage
public void myTask ( S t r i n g msg , S e s s i o n s e s s i o n )
throws IOException , EncodeException {
S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;
S t r i n g p a t h S e r v e r=new j a v a . i o . F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ;
i n t x=p a t h S e r v e r . i n d e x O f ( g l a s s f i s h ) ;
S t r i n g path= ;

308

CAPITOLUL 12. WEBSOCKET

S t r i n g path0=f s+ ImageStreaming +
f s+WEBINF+f s+ images +f s ;
i f ( x==1){
// apachetomcat
path=Paths . g e t ( p a t h S e r v e r ) . t o S t r i n g ()+
f s+ webapps +path0 ;
}
else {
// g l a s s f i s h
x=p a t h S e r v e r . l a s t I n d e x O f ( f s ) ;
S t r i n g p a t h G l a s s f i s h=p a t h S e r v e r . s u b s t r i n g ( 0 , x ) ;
path=Paths . g e t ( p a t h G l a s s f i s h ) . t o S t r i n g ()+
f s+ a p p l i c a t i o n s +path0 ;
}
i n t n o F i l e=I n t e g e r . p a r s e I n t ( msg ) ;
S t r i n g f i l e N a m e= ;
switch ( n o F i l e ) {
case 1 :
f i l e N a m e= b r a s o v . j p g ;
break ;
case 2 :
f i l e N a m e=xmlp i c . j p g ;
break ;
}
Path c a l e=Paths . g e t ( path+f i l e N a m e ) ;
for ( S e s s i o n peer : s e s s i o n s ) {
i f ( peer . equals ( s e s s i o n )){
OutputStream out=p e e r . getBasicRemote ( ) . getSendStream ( ) ;
F i l e s . copy ( c a l e , out ) ;
out . c l o s e ( ) ;
}
}

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

62

@OnOpen
public void onOpen ( S e s s i o n s e s s i o n ) {
s e s s i o n s . add ( s e s s i o n ) ;
}

63
64
65

@OnClose
public void o n C l o s e ( S e s s i o n s e s s i o n ) {
s e s s i o n s . remove ( s e s s i o n ) ;
}

67
68
69
70
71

Clasa client WebSocketClient.java


1
2
3
4
5
6
7
9
10
11

import
import
import
import
import
import
import

j a v a . i o . IOException ;
j a v a . n e t . URI ;
javax . websocket . ContainerProvider ;
j a v a x . w e b s o c k e t . DeploymentException ;
j a v a x . w e b s o c k e t . WebSocketContainer ;
javax . websocket . S e s s i o n ;
java . u t i l . Scanner ;

import j a v a x . w e b s o c k e t . Endpoint ;
import j a v a x . w e b s o c k e t . E n d p o i n t C o n f i g ;
import j a v a x . w e b s o c k e t . MessageHandler ;

12.3. WEBSOCKET IN JAVA

13
14
15
16
17
19
20
21
22

import
import
import
import
import

j a v a . awt . image . B u f f e r e d I m a g e ;
j a v a x . i m a g e i o . ImageIO ;
j a v a . i o . InputStream ;
j a v a . i o . ByteArrayInputStream ;
j a v a . awt . Image ;

public c l a s s WebSocketClient extends Endpoint {


private s t a t i c boolean s f a r s i t =f a l s e ;
private s t a t i c S t r i n g SERVER =
ws : / / l o c a l h o s t : 8 0 8 0 / ImageStreaming / image ;
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 ( F i s i e r u l de d e s c a r c a t : ) ;
System . out . p r i n t l n ( 1 : Imagine d i n Brasov ) ;
System . out . p r i n t l n ( 2 : p i c xml ) ;
i n t n o F i l e=s c a n n e r . n e x t I n t ( ) ;
S t r i n g data=new I n t e g e r ( n o F i l e ) . t o S t r i n g ( ) ;
WebSocketContainer c o n t a i n e r =
C o n t a i n e r P r o v i d e r . getWebSocketContainer ( ) ;

24
25
26
27
28
29
30
31
32

try {
S e s s i o n s e s s i o n=
c o n t a i n e r . c o n n e c t T o S e r v e r ( WebSocketClient . c l a s s , null ,
new URI (SERVER ) ) ;
s e s s i o n . getBasicRemote ( ) . sendText ( data ) ;
while ( ! s f a r s i t ) { ; } ;
}
catch ( E x c e p t i o n ex ) {
System . out . p r i n t l n ( LocalEndPoint E x c e p t i o n : +ex . g e t M e s s a g e ( ) ) ;
}

34
35
36
37
38
39
40
41
42
43
44

46

public void onOpen ( S e s s i o n s e s s i o n , E n d p o i n t C o n f i g c o n f i g ) {


s e s s i o n . addMessageHandler (new MessageHandler . Whole<byte [ ] > ( ) {
public void onMessage ( byte [ ] msg ) {
try {
InputStream i n=new ByteArrayInputStream ( msg ) ;
B u f f e r e d I m a g e b i=ImageIO . r e a d ( i n ) ;
Image image=(Image ) b i ;
ShowImage s=new ShowImage ( image ) ;
s . show ( ) ;
}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
s f a r s i t =true ;
}
});
}

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

Clasa ShowImage afiseaza imaginea descarcata.

309

310

CAPITOLUL 12. WEBSOCKET

Capitolul 13
Enterprise Java Beans
In prezent se evidentiaza doua abordari privind realizarea aplicatiilor de
complexitate mai mare (aplicatiilor de ntreprindere):
Java Enterprise Edition - JEE este o extensie a interfetei de programare
(API ) Java, pentru care exista mai multe implementari. Principalul
promotor este al modelului este Oracle , dar este sustinut si de RedHat
- JBoss.;
Spring a carei dezvoltare tine de firma VMware. Spring este alcatuit din
mai multe cadre de lucru. Acest model de dezvoltare este sustinut de
Google.
Java Enterprise Edition este un cadru de lucru care nglobeaza pe o serie
implementari ale interfetelor de programare (JDBC, JMS, JNDI, JSF, RMIIIOP, JPA, JTA, JAAS, etc), resurse care pot utiliza componente Enterprise
Java Bean- EJB.
O componenta EJB este o clasa Java - de obicei de tip POJO - care face
parte din aplicatia server, contine metodele care rezolva o problema (business logic) si este continut ntr-un server de aplicatii. Serverul de aplicatii
asigura o serie de functionalitati ca instantierea componentelor EJB, injectarea
dependintelor, conexiunea cu bazele de date, gestiunea tranzactiilor, etc. Serverul
de aplicatii poate fi interpretat si ca un container de componente EJB.
Se spune ca serverul de aplicatie JEE asigura accesul la contextul n care
ruleaza aplicatia, adica la resursele serverului, si la injectarea dependintelor
(Context and Dependency Injection -CDI ).
Servere de aplicatii gratuite:
glassfish - Oracle.
311

312

CAPITOLUL 13. ENTERPRISE JAVA BEANS

geronimo - apache, sprijinit de I.B.M.


JOnAS.
WildFly - RedHat - jboss.
In acelasi timp, aceste servere Web sunt containere EJB, de servlet si JSP.
In cele ce urmeaza vom utiliza glassfish.
Tipuri de componente EJB:
Session - sesiune EJB.
Message Driven - preia mesaje de tipul Java Message Service (JMS).
Vom folosi prescurtarea MDB - Message Driven Bean.
Entity

13.1

Session EJB

Starea unui obiect Java este data de valorile campurilor sale. Din punctul
de vedere al retinerii starii, exista urmatoarele tipuri de componente sesiune
EJB:
stateless - fara retinerea starii;
stateful - cu retinerea starii pe parcursul sesiunii serverului;
singleton - exista o singura instanta a componentei EJB. Durata de viata
a componentei coincide cu intervalul de timp n care componenta EJB
este activa n serverul de aplicatii.
Aplicatiile cu componenta EJB constau din:
componenta EJB - desfasurata n serverul de aplicatii. Aceasta componenta poate fi totodata si un serviciu Web de tip JAX-WS;
aplicatie client care poate fi
client Web - servlet sau client al serviciului Web de tip JAX-WS;
client RMI-IIOP (Internet Inter ORB Protocol).

13.1. SESSION EJB

313

In terminologia JEE componenta EJB, clientul Web si clientul RMI-IIOP


formeaza cate un modul. Componenta EJB si clientul Web formeaza o aplicatie
JEE care se instaleaza n serverul de aplicatii JEE.
Modulele EJB si clientul RMI-IIOP se arhiveaza cu extensia jar iar modulul Web se arhiveaza cu extensia war. Aplicatia JEE se arhiveaza cu extensia
ear -Enterprise ARchive- sau war.
Un client RMI-IIOP apeleaza modulul EJB prin intermediul programului
glassfish\bin\appclient.exe
appclient -client modul-iiop.jar [-targetserver host:port] arg1 . . .

Portul implicit este 3700.

13.1.1

Component
a EJB sesiune stateless

Sablonul pentru crearea unei componente EJB de tip stateless session este
import javax.ejb.Stateless;
@Stateless
public class Componenta{
public tip metoda(. . .){. . .}
. . .
}

Exemplul 13.1.1 Cel mai mare divizor comun a doua numere naturale.
Componentei EJB are codul
1
2
4
5
6
7

package cmmdc . e j b ;
import j a v a x . e j b . S t a t e l e s s ;
@Stateless
public c l a s s CmmdcBean{
public long cmmdc( long m, long n ) { . . . }
}

Aplicatia client va fi un servlet gazduit de acelasi server de aplicatie. Accesul la componenta EJB se poate programa:
prin injectare, utilizand adnotari;
prin JNDI.
In ambele cazuri serverul Web este responsabil de instantierea componentei
EJB.

314

CAPITOLUL 13. ENTERPRISE JAVA BEANS

Injectare cu adnotare
Serverul de aplicatie injecteaza n servlet o instanta a componentei EJB
sau altfel explicat
@EJB
Tip var;

@EJB(name="xyz")
Tip var;

injecteaza (realizeaza o referinta) pentru var catre un obiect de tipul Tip specificat. Actiunea este declansata de adnotarea EJB.
Codul servlet-ului este
1
2
3
4
5
6
7
8
9
10
12
13
14
15

package cmmdc . web ;


import j a v a . i o . IOException ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import cmmdc . e j b . CmmdcBean ;
import j a v a x . e j b . EJB ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
@WebServlet ( u r l P a t t e r n s = /cmmdc )
public c l a s s CmmdcServlet extends H t t p S e r v l e t {
@EJB
CmmdcBean cb ;
public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ;
long m=Long . par se Lo ng ( sm ) , n=Long . par se Lo ng ( sn ) ;
long x=cb . cmmdc(m, n ) ;
P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;

17
18
19
20
21
22

S t r i n g t i t l e =Cmmdc S e r v l e t ;
r e s . setContentType ( t e x t / html ) ;
out . p r i n t l n ( <HTML><HEAD><TITLE> ) ;
out . p r i n t l n ( t i t l e ) ;
out . p r i n t l n ( </TITLE></HEAD><BODY> ) ;
out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ;
out . p r i n t l n ( <P>Cmmdc : +x ) ;
out . p r i n t l n ( </BODY></HTML> ) ;

24
25
26
27
28
29
30
31

out . c l o s e ( ) ;

33
34

36

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

37
38
39
40

Desfasurarea aplicatiei
ejbcmmdc
|--> WEB-INF
|
|--> classes
|
|
|--> cmmdc

315

13.1. SESSION EJB

|
|
|
|
|

|
|
|-->
|
|
|
|
|
|-->
|
|
|
index.html

ejb
|
CmmdcBean.class
web
|
CmmdcServlet.class

Aceasta structura se arhiveaza cu jar, dar cu extensia war.


Acces la componenta EJB prin JNDI
Referinta JNDI are structura
prefix /[nume app][/nume modul ]/nume EJB
unde prefix poate fi
Prefix
Vizibilitatea rezultatului
java:global
Componenta se poate utiliza de oriunde.
Coincide cu numele arhivei ear.
java:app
Componenta se poate utiliza n aplicatie
Coincide cu numele arhivei jar sau war.
java:module Componental se poate utiliza n modul
In cazul exemplului codul servlet-ului va fi
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
18
19
20
21
22
23
24
25
26
27
28

package cmmdc . web ;


import j a v a . i o . IOException ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . S e r v l e t C o n f i g ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import cmmdc . e j b . CmmdcBean ;
import j a v a x . naming . Context ;
import j a v a x . naming . I n i t i a l C o n t e x t ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
@WebServlet ( u r l P a t t e r n s = /cmmdc )
public c l a s s CmmdcServlet extends H t t p S e r v l e t {
CmmdcBean cb ;
public void i n i t ( S e r v l e t C o n f i g c o n f i g ) throws S e r v l e t E x c e p t i o n {
super . i n i t ( c o n f i g ) ;
Context c t x=n u l l ;
try {
c t x=new I n i t i a l C o n t e x t ( ) ;
cb=(CmmdcBean) c t x . l o o k u p ( j a v a : module /CmmdcBean ) ;
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ;
}
}

316

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 { . . . }

30
31

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 { . . . }
}

33
34
35
36

CAPITOLUL 13. ENTERPRISE JAVA BEANS

13.1.2

Component
a cu metode asincrone

In cazul apelarii unei metode a unei componente EJB, clientul este blocat
pana la furnizarea rezultatului de catre serverul de aplicatie. Programand
metode asincrone, programul client va detine controlul imediat dupa apelare
sau altfel explicat apelarea nu mai este blocanta.
Definirea unei metode asincrone
Se ndeplinesc doua conditii:
1. Metoda asincrona este adnotata @Asynchronous (javax.ejb.Asynchronous);
2. Rezultatul metodei va fi de tip java.util.concurrent.Future<V>.
Exemplul 13.1.2
In cazul exemplului tratat anterior, codul componentei EJB sesiune stateless devine
1
2
3
4
5
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package cmmdc . e j b ;
import j a v a x . e j b . S t a t e l e s s ;
import j a v a x . e j b . Asynchronous ;
import j a v a x . e j b . A s y n c R e s u l t ;
import j a v a . u t i l . c o n c u r r e n t . Future ;
@Stateless
public c l a s s CmmdcBean{
@Asynchronous
public Future<Long> cmmdc( long m, long n ) {
long r , c ;
do{
c=n ;
r=m%n ;
m=n ;
n=r ;
} while ( r ! = 0 ) ;
Long r e s u l t=new Long ( c ) ;
return new AsyncResult<Long>( r e s u l t ) ;
}
}

Clasa AsyncResult implementeaza interfata Future.

13.1. SESSION EJB

317

Apelarea unei metode asincrone


Din nou, pentru exemplul anterior apelarea metodei cmmdc se programeaza
prin
Future<Long> result=cb.cmmdc(m,n);
long x=0;
try{
while(! result.isDone()){;};
x=result.get().longValue();
}
catch(Exception e){
e.printStackTrace();
}

13.1.3

Aplicatie JEE cu module EJB, Web si client RMIIIOP

Modificam arhitectura aplicatiei anterioare definind


un modul EJB pentru componta EJB.
modul-ejb
|--> numePachet
|
|
*.class

un modul Web, a carei arhiva va avea extensia war.


modul-Web
|--> WEB-INF
|
|--> classes
|
|
|
*.class
|
index.html

Desfasurarea aplicatiei va fi
|-->
|
|
|

META-INF
|
application.xml
modul-ejb.jar
modul-Web.war

Instalarea aplicatie, adica a ansamblului alcatuit din cele 2 module se face prin
intermediul administratorului.
Fisierul application.xml precizeaza structura aplicatiei

318

CAPITOLUL 13. ENTERPRISE JAVA BEANS

<?xml version="1.0" encoding="UTF-8"?>


<application version="5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd">
<display-name>nume-aplicatie</display-name>
<module>
<ejb>modul-ejb.jar</ejb>
</module>
<module>
<web>
<web-uri>modul-web.war</web-uri>
<context-root>/context</context-root>
</web>
</module>
</application>
Aceasta organizare necesita modificarea componentei EJB din sectiunea
13.1.1 n sensul definirii unei interfete cu adnotarea Remote. Componenta
EJB implementeaza interfata si n plus, daca interfata are numele Xyz atunci
componenta EJB va avea numele XyzBean.
Aceasta constructie este necesara numai n cazul n existentei unui client
RMI-IIPO.
Pentru exemplul discutat codurile sunt:
1
2
4
5
6
7

package cmmdc . e j b ;
import j a v a x . e j b . Remote ;
@Remote
public i n t e r f a c e Cmmdc{
public long cmmdc( long m, long n ) ;
}

si
1
2
4
5
6
7

package cmmdc . e j b ;
import j a v a x . e j b . S t a t e l e s s ;
@Stateless
public c l a s s CmmdcBean implements Cmmdc{
public long cmmdc( long m, long n ) { . . . }
}

Modulul / clientul Web este cel prezentat anterior n sectiunea 13.1.1, cu


diferenta ca referinta la componenta EJB se face prin interfata.
In cazul exemplului tratat, desfasurarea clientului RMI-IIOP va fi

319

13.1. SESSION EJB

cmmdc-iiop
|--> cmmdc
|
|--> client
|
|
|
|
|--> ejb
|
|
|

CmmdcClient.class
Cmmdc.class

Codul clientului prin injectare este


1
2
3
4
6
7
8

package cmmdc . c l i e n t ;
import j a v a x . e j b . EJB ;
import cmmdc . e j b . Cmmdc ;
import j a v a . u t i l . S c a n n e r ;
public c l a s s CmmdcClient {
@EJB
private s t a t i c Cmmdc cb ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
long x=cb . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc : +x ) ;
}

10
11
12
13
14
15
16
17
18
19

Daca se utilizeaza referinta prin JNDI atunci adresarea componentei EJB


va fi:
java:global/cmmdc-ear/cmmdc-ejb/CmmdcBean
Daca dist este catalogul cu arhiva clientului atunci apelarea acestuia este
set GLASSFISH_HOME=. . .\glassfish4
%GLASSFISH_HOME%\glassfish\bin\appclient -client
dist\cmmdc-iiop.jar -targetserver localhost:3700

Apelarea modulului Web se face n mod obisnuit, prin:


http://host:8080/context
unde context a fost definit n fisierul application.xml.

13.1.4

Component
a EJB sesiune singleton

Serverul de aplicatie creaza o singura instantiaza a componentei EJB care


este utilizata de toti clientii. Diferenta consta n utilizarea adnotarii @Singleton
n loc de @Stateless.
Utilizam modelul din sectiunea 13.1.3. Consideram doar varianta bazata
pe adnotari.
Exemplul 13.1.3 Numararea solicitarilor de utilizare a componentei EJB.

320

CAPITOLUL 13. ENTERPRISE JAVA BEANS

Codul componentei EJB singleton


1
2
4
5
6
7

1
2
4
5
6
7
8
9
10

package s i n g l e . e j b ;
import j a v a x . e j b . Remote ;
@Remote
public i n t e r f a c e S i n g l e {
public i n t g e t I n d e x ( ) ;
}
package s i n g l e . e j b ;
import j a v a x . e j b . S i n g l e t o n ;
@Singleton
public c l a s s S i n g l e B e a n implements S i n g l e {
private i n t i n d e x =0;
public i n t g e t I n d e x ( ) {
return ++i n d e x ;
}
}

Servlet-ul aplicatiei client are codul


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

package s i n g l e . web ;
import j a v a . i o . IOException ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import s i n g l e . e j b . S i n g l e ;
import j a v a x . e j b . EJB ;
import j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
@WebServlet ( u r l P a t t e r n s = / s i n g l e )
public c l a s s S i n g l e S e r v l e t extends H t t p S e r v l e t {
@EJB
S i n g l e sb ;
public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
i n t x=sb . g e t I n d e x ( ) ;
P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
r e s . setContentType ( t e x t / html ) ;
S t r i n g t i t l e = S i n g l e S e r v l e t ;
out . p r i n t l n ( <HTML><HEAD><TITLE> ) ;
out . p r i n t l n ( t i t l e ) ;
out . p r i n t l n ( </TITLE></HEAD><BODY> ) ;
out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ;
out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ;
out . p r i n t l n ( </BODY></HTML> ) ;
out . c l o s e ( ) ;
}

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

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

32
33
34
35
36

13.1. SESSION EJB

321

Apelarea servlet-ului se face din fisierul index.html


1
2
3
4
5
6
7
8
9
10
11

<html>
<body bgcolor=#c c b b c c >
<center>
<h1> EJB S i n g l e S e r v l e t </h1>
<form method= g e t
action= s i n g l e >
<p><input type= submit value= A p e l e a z a >
</form>
</ center>
</body>
</html

Contextul aplicatiei definit n META-INF\application.xml este ejbsingle.


Aplicatia client are codul
1
2
3
4
6
7
8

package s i n g l e . c l i e n t ;
import j a v a x . e j b . EJB ;
import s i n g l e . e j b . S i n g l e ;
import j a v a . u t i l . S c a n n e r ;
public c l a s s S i n g l e C l i e n t {
@EJB
private s t a t i c S i n g l e nb ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
S t r i n g ch=Y ;
i n t i n d e x =0;

10
11
12
13

while ( ch . e q u a l s ( Y ) ) {
i n d e x=nb . g e t I n d e x ( ) ;
System . out . p r i n t l n ( Numarul de a p e l a r i : +i n d e x ) ;
System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ;
do{
ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ;
}
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 ) ) ) ;
}

15
16
17
18
19
20
21
22
23

24
25

13.1.5

Component
a EJB sesiune stateful

Diferenta formala fata de modelele Stateless si Singleton consta n utilizarea


adnotarii @Stateful.
Consideram un exemplu ce deriva din cel precedent.
Exemplul 13.1.4 Numararea solicitarilor de utilizare a componentei EJB.
Componenta EJB are interfata

322

1
2
4
5
6
7
8

CAPITOLUL 13. ENTERPRISE JAVA BEANS

package numara . e j b ;
import j a v a x . e j b . Remote ;
@Remote
public i n t e r f a c e Numara{
public i n t g e t I n d e x ( ) ;
public void remove ( ) ;
}

si implementarea
1
2
3
5
6
7
8
9
10

package numara . e j b ;
import j a v a x . e j b . S t a t e f u l ;
import j a v a x . e j b . Remove ;
@Stateful
public c l a s s NumaraBean implements Numara{
private i n t i n d e x =0;
public i n t g e t I n d e x ( ) {
return ++i n d e x ;
}
@Remove
public void remove ( ) {}

12
13
14

Metoda cu adnotarea Remove are ca efect stergerea instantei componentei EJB


din serverul de aplicatii. Din acest motiv, apelarea acestei metode ntr-un
modul Web, are ca efect compromiterea servlet-ului.
Injectarea componentei EJB are loc n momentul activarii servlet-ului. Astfel fiecare client Web va utiliza aceasi componenta EJB.
Modulul IIOP este mult mai util. La fiecare apelare a modulului IIOP
are loc injectarea unei componente EJB. Serverul de aplicatii pastreaza starea
componentei pe durata de utilizare a modulului IIOP.
Codul modulului Web
1
2
3
4
5
6
7
8
9
11
12
13
15
16
17
18
19

package numara . web ;


import j a v a . i o . IOException ;
import j a v a . i o . P r i n t W r i t e r ;
import j a v a x . s e r v l e t . S e r v l e t E x c e p t i o n ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e s p o n s e ;
import numara . e j b . Numara ;
import j a v a x . e j b . EJB ;
public c l a s s NumaraServlet extends H t t p S e r v l e t {
@EJB
Numara nb ;
public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g o p e r=r e q . g e t P a r a m e t e r ( o p e r ) ;
P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
r e s . setContentType ( t e x t / html ) ;

13.1. SESSION EJB

S t r i n g t i t l e =Numara S e r v l e t ;
out . p r i n t l n ( <HTML><HEAD><TITLE> ) ;
out . p r i n t l n ( t i t l e ) ;
out . p r i n t l n ( </TITLE></HEAD><BODY> ) ;
out . p r i n t l n ( <H1>+ t i t l e +</H1> ) ;
switch ( o p e r ) {
case i n d e x :
i n t x=nb . g e t I n d e x ( ) ;
out . p r i n t l n ( <p>V a l o a r e a i n d e x : +x ) ;
break ;
case e x i t :
out . p r i n t l n ( <p>OK: Pe r a s p u n d e r e a dv o a s t r a ) ;
nb . remove ( ) ;
break ;
}
out . p r i n t l n ( </BODY></HTML> ) ;
out . c l o s e ( ) ;

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

39

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

40
41
42
43

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

<html>
<body bgcolor=#c c b b c c >
<center>
<h1> EJB Numar&#259; S e r v l e t </h1>
<form method= g e t
action=numara>
<table>
<tr>
<td>S e l e c t a &#355; i o p e r a &#355; i a</td>
<td>
<s e l e c t name= o p e r >
<option value= i n d e x > Num&#259; r de a p e l &#259; r i
<option value= e x i t > S t e r g e componenta EJB
</ s e l e c t>
</td>
</ tr>
<tr>
<td> <input type= submit value= A p e l e a z a ></td>
<td/>
</ tr>
</ table>
</form>
</ center>
</body>
</html>

Contextul aplicatiei Web este ejbnumara.


Codul modulului IIOP
1
2
3

package numara . c l i e n t ;
import j a v a x . e j b . EJB ;
import numara . e j b . Numara ;

323

324

CAPITOLUL 13. ENTERPRISE JAVA BEANS

import j a v a . u t i l . S c a n n e r ;

public c l a s s NumaraClient {
@EJB
private s t a t i c Numara nb ;

7
8

public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n {


S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
S t r i n g ch=Y , msg= ;
i n t op , i n d e x =0;

10
11
12
13

while ( ch . e q u a l s ( Y ) ) {
System . out . p r i n t l n ( O p e r a t i i : 1 . Numara 2 . S t e r g e componenta EJB ) ;
System . out . p r i n t l n ( O p e r a t i a : ) ;
op=s c a n n e r . n e x t I n t ( ) ;
switch ( op ) {
case 1 :
i n d e x=nb . g e t I n d e x ( ) ;
msg=Numarul de a p e l a r i : +(new I n t e g e r ( i n d e x ) ) . t o S t r i n g ( ) ;
break ;
case 2 :
nb . remove ( ) ;
msg=Sa s t e r s componenta EJB ;
break ;
default :
msg=Cod o p e r a t i e e r o n a t ;
break ;
}
System . out . p r i n t l n ( msg ) ;

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

System . out . p r i n t l n ( C o n t i n u a t i ? (Y/N) ) ;


do{
ch=s c a n n e r . n e x t ( ) . t r i m ( ) . toUpperCase ( ) ;
}
while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ;

34
35
36
37
38

39

40
41

Ruland modulele IIOP ale aplicatiilor corespunzatoare adnotarilor Stateful


si Singleton observati diferenta rezultatelor furnizate.

13.2

Component
a EJB MessageDriven

O componenta EJB MessageDriven (MDB) preia mesaje care sunt trimise


catre un obiect destinatie predefinit de tip Queue sau Topic. Componenta
EJB este adnotata cu
@MessageDriven(mappedName=nume Destinatie)
Prelucrarea mesajelor primite se programeaza n metoda onMessage a interfetei
MessageListener.

EJB MESSAGEDRIVEN
13.2. COMPONENTA

325

Afisarea unor mesaje se obtine prin intermediul unei jurnalizari java.util.


logging.Logger. Textele apar n fisierul server.log aflat n catalogul log
al domeniului.
Obiectele administrator - fabrica de conexiuni, obiectul destinatie - se
creaza naintea desfasurarii componentei EJB.
Crearea obiectelor administrator
Dintr-un navigator, apel
and http://localhost:4848 se acceseaz
a administratorul grafic (web).
Resources | JMS Resources se vor crea obiectele

Din

1. Destination Resources
myQueue
JNDI Name :
myQueue
Physical Destination Name :

javax.jms.Queue

myTopic
JNDI Name :
myTopic
Physical Destination Name :

javax.jms.Topic

2. Connection Factories
myQueueConnectionFactory
JNDI Name :
myQueueConnectionFactory
Resource Type : javax.jms.QueueConnectionFactory
myTopicConnectionFactory
JNDI Name :
myTopicConnectionFactory
Resource Type : javax.jms.TopicConnectionFactory

Exemplul 13.2.1 O aplicatie client trimite un numar de mesaje catre o componenta MDB.
Codul componentei EJB
1
2
3
4
5
6
8
9
10
11
13
14
15
16
17

package mdb ;
import j a v a x . e j b . MessageDriven ;
import j a v a x . jms . Message ;
import j a v a x . jms . TextMessage ;
import j a v a x . jms . M e s s a g e L i s t e n e r ;
import j a v a . u t i l . l o g g i n g . Logger ;
@MessageDriven ( mappedName=myQueue )
public c l a s s MessageBean implements M e s s a g e L i s t e n e r {
private s t a t i c f i n a l Logger l o g g e r =
Logger . g e t L o g g e r ( MessageBean . c l a s s . getName ( ) ) ;
public void onMessage ( Message msg ) {
TextMessage txtMsg = n u l l ;
try {
i f ( msg instanceof TextMessage ) {
txtMsg = ( TextMessage ) msg ;

326

l o g g e r . i n f o ( MESSAGE BEAN: + txtMsg . g e t T e x t ( ) ) ;


System . out . p r i n t l n ( txtMsg . g e t T e x t ( ) ) ;

18
19

}
}
catch ( Throwable th ) {
th . p r i n t S t a c k T r a c e ( ) ;
}

20
21
22
23
24

25
26

CAPITOLUL 13. ENTERPRISE JAVA BEANS

Desfasurarea componentei MDB va fi


simple-mdb
|--> META-INF
|
|
application.xml
|
simple-mdb.jar

Fisierul simple-mdb.jar nu contine decat clasa mdb.MessageBean, reprodusa


mai sus.
Codul clientului cu regasirea obiectilor prin adnotare
1
2
3
4
5
6
8
9
10
11
12

package mdb ;
import j a v a x . jms . QueueConnectionFactory ;
import j a v a x . jms . D e s t i n a t i o n ;
import j a v a x . a n n o t a t i o n . R e s o u r c e ;
import j a v a x . jms . JMSContext ;
import j a v a x . jms . JMSProducer ;
public c l a s s
MessageClient {
@Resource ( l o o k u p= myQueueConnectionFactory )
private s t a t i c QueueConnectionFactory c f ;
@Resource ( l o o k u p=myQueue )
private s t a t i c D e s t i n a t i o n q ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
try {
JMSContext c t x=c f . c r e a t e C o n t e x t ( ) ;
JMSProducer p r o d u c e r=c t x . c r e a t e P r o d u c e r ( ) ;
f o r ( i n t i =0; i <5; i ++){
p r o d u c e r . send ( q , H e l l o +i ) ;
}
p r o d u c e r . send ( q , c t x . c r e a t e M e s s a g e ( ) ) ;
ctx . c l o s e ( ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}
}

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

si prin JNDI
1
2
3
4
5
6

package mdb ;
import j a v a x . jms . QueueConnectionFactory ;
import j a v a x . jms . D e s t i n a t i o n ;
import j a v a x . naming . Context ;
import j a v a x . naming . I n i t i a l C o n t e x t ;
import j a v a x . jms . JMSContext ;

EJB ENTITY
13.3. COMPONENTA

import j a v a x . jms . JMSProducer ;

public c l a s s
MessageClient {
private s t a t i c QueueConnectionFactory c f ;
private s t a t i c D e s t i n a t i o n q ;

10
11

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


Context c t x=n u l l ;
try {
c t x=new I n i t i a l C o n t e x t ( ) ;
c f =( QueueConnectionFactory ) c t x . l o o k u p ( myQueueConnectionFactory ) ;
q=( D e s t i n a t i o n ) c t x . l o o k u p ( myQueue ) ;
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( E r o a r e : +e . g e t M e s s a g e ( ) ) ;
System . e x i t ( 1 ) ;
}

13
14
15
16
17
18
19
20
21
22
23

try {
JMSContext jmsCtx=c f . c r e a t e C o n t e x t ( ) ;
JMSProducer p r o d u c e r=jmsCtx . c r e a t e P r o d u c e r ( ) ;
f o r ( i n t i =0; i <5; i ++){
p r o d u c e r . send ( q , H e l l o +i ) ;
}
p r o d u c e r . send ( q , jmsCtx . c r e a t e M e s s a g e ( ) ) ;
jmsCtx . c l o s e ( ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

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

37
38

327

Clientul se executa prin intermediul lui appclient.

13.3

Component
a EJB Entity

O componenta de tip entity simplifica accesul la o baza de date ntr-o


aplicatie JEE.
Crearea bazei de date
Glassfish contine SGBD JavaDB (derby). Vom lansa serverul glassfish si prin intermediul utilitarului
ij vom crea baza de date AgendaEMail. Crearea se face n modul descris n anexa dedicat
a utiliz
arii unei
SGBD ntr-un program Java.

Definirea elementelor de conexiune dintre glassfish si baza de date


Dintr-un navigator, apel
and http://localhost:4848 se acceseaz
a administratorul grafic (web).
Resources | JDBC se vor crea
1. JDBC Connection Pool
cuv
a de conexiuni la baza de date;

Din

328

CAPITOLUL 13. ENTERPRISE JAVA BEANS

2. JDBC Resources
leg
atura dintre numele JNDI asociat bazei de date cu cuva de conexiuni creat
a anterior.
Creare JDBC Connection Pool
1. Pool Name adresePool un nume simbolic atasat cuvei
2. Resource Type Se selecteaza java.sql.Driver
3. Database Driver Vendor Se selecteaz
a Derby
4. Introspect Se bifeaz
a Enabled
5. Next
6. Driver Classname Se selecteaz
a org.apache.derby.jdbc.ClientDriver
7. Additional Properties Se bifeaz
a URL si se completeaz
a coloana Value cu
jdbc:derby:\. . . calea c
atre locatia bazei de date. . .\AgendaEMail
8. Finish
Creare JDBC Resources
1. JNDI Name jdbc/Adrese, un nume simbolic atasat resursei
2. Pool Name Se selecteaz
a adresePool, numele cuvei de conexiuni
3. OK

Aplicatie cu component
a Entity
O componenta Entity va fi adnotata @Entity si corespunde unui tabel al
bazei de date relationale.
Exemplul 13.3.1 Aplicatie de consultarea a bazei de date AgendaEMail.
Desfasurarea aplicatiei este
agendae-ear
|--> META-INF
|
|
persistence.xml
|
agenda-ejb.jar

unde agenda-ejb.jar are structura


|--> ejb
|
|
AgendaEMail.class
|
|
AgendaEMailBean.class
|--> entity
|
|
Adrese.class
|--> META-INF
|
|
persistence.xml

EJB ENTITY
13.3. COMPONENTA

329

Clasa Adrese.java este componenta Entity si corespunde tabelei adrese.


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

package e n t i t y ;
import j a v a . i o . S e r i a l i z a b l e ;
import j a v a x . p e r s i s t e n c e . E n t i t y ;
import j a v a x . p e r s i s t e n c e . I d ;
import j a v a x . p e r s i s t e n c e . GeneratedValue ;
import j a v a x . p e r s i s t e n c e . GenerationType ;
import j a v a . i o . S e r i a l i z a b l e ;
@Entity
public c l a s s Adrese implements S e r i a l i z a b l e {
@Id
@GeneratedValue ( s t r a t e g y=GenerationType . IDENTITY)
private i n t i d ;
private S t r i n g nume ;
private S t r i n g e m a i l ;
public S t r i n g getNume ( ) {
return nume ;
}
public void setNume ( S t r i n g nume ) {
t h i s . nume = nume ;
}
public S t r i n g g e t E m a i l ( ) {
return e m a i l ;
}
public void s e t E m a i l ( S t r i n g e m a i l ) {
this . email = email ;
}
public i n t g e t I d ( ) {
return i d ;
}
public void s e t I d ( i n t i d ) {
this . id = id ;
}

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

Accesul la baza de date se realizeaza printr-o componenta EJB Session


stateless Codul interfetei AgendaEMail.java este
1
2
3
4
6
7
8
9
10

package e j b ;
import j a v a x . e j b . Remote ;
import e n t i t y . Adrese ;
import j a v a . u t i l . L i s t ;
@Remote
public i n t e r f a c e AgendaEMail {
public L i s t <Adrese> g e t E m a i l ( S t r i n g nume ) ;
public L i s t <Adrese> getNume ( S t r i n g e m a i l ) ;
}

implementat de clasa AgendaEMailBean.java


1
2
3
4
5

package e j b ;
import j a v a x .
import j a v a x .
import j a v a x .
import j a v a x .

ejb . S t a t e l e s s ;
persistence . PersistenceContext ;
p e r s i s t e n c e . EntityManager ;
p e r s i s t e n c e . Query ;

330

6
7
9
10
11
12

import e n t i t y . Adrese ;
import j a v a . u t i l . L i s t ;
@Stateless
public c l a s s AgendaEMailBean implements AgendaEMail {
@ P e r s i s t e n c e C o n t e x t ( unitName= a g e n d a e p e r s i s t e n c e c t x )
EntityManager em ;
public L i s t <Adrese> g e t E m a i l ( S t r i n g nume ) {
S t r i n g nm= \ +nume+ \ ;
S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . nume=+nm ;
System . out . p r i n t l n ( s q l ) ;
Query query=em . c r e a t e Q u e r y ( s q l ) ;
L i s t <Adrese> l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ;
return l i s t ;
}

14
15
16
17
18
19
20
21

public L i s t <Adrese> getNume ( S t r i n g e m a i l ) {


S t r i n g eml= \ +e m a i l+ \ ;
S t r i n g s q l=SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . e m a i l=+eml ;
System . out . p r i n t l n ( s q l ) ;
Query query=em . c r e a t e Q u e r y ( s q l ) ;
L i s t <Adrese> l i s t =( L i s t <Adrese >) query . g e t R e s u l t L i s t ( ) ;
return l i s t ;
}

23
24
25
26
27
28
29
30
31

CAPITOLUL 13. ENTERPRISE JAVA BEANS

Fisierul de configurare persistence.xml este


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

< p e r s i s t e n c e xmlns= h t t p : // j a v a . sun . com/xml/ ns / p e r s i s t e n c e version= 1 . 0 >


<p e r s i s t e n c e u n i t name= a g e n d a e p e r s i s t e n c e c t x >
<j t a datas o u r c e>j d b c / Adrese</ j t a datas o u r c e>
<p r o p e r t i e s>
< !Use t h e j a v a 2 d b f e a t u r e >
<p r o p e r t y name= t o p l i n k . ddlg e n e r a t i o n v a l u e= none />
< ! Generate t h e s q l s p e c i f i c t o Derby d a t a b a s e >
<p r o p e r t y name= t o p l i n k . j d b c . d r i v e r
v a l u e= o r g . apache . derby . j d b c . C l i e n t D r i v e r />
</ p r o p e r t i e s>
</ p e r s i s t e n c e u n i t>
</ p e r s i s t e n c e>

Se observa urmatoarele corelatii


Valoarea atributului name a elementului persistence-unit
(agendae persistence ctx ) este utilizat n clasa AgendaEMailBean n adnotarea @PersistenceContext
Elementul jta-data-surse contine numele JNDI a bazei de date definit
n glassfish.
Aplicatia client
Desfasurarea aplicatiei client este

EJB ENTITY
13.3. COMPONENTA

agendae-client
|--> ejb
|
|
AgendaEMail.class
|--> entity
|
|
Adrese.class
|--> META-INF
|
|
MANIFEST.MF
|
Client.class

Fisierul MANIFEST.MF este completat cu


Main-Class: Client
Class-Path: agendae-ejb.jar

Clasa Client.java are codul


1
2
3
4
5
6
7
9
10
11
12
14
15
16
17
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

import
import
import
import
import
import
import

e j b . AgendaEMail ;
j a v a x . e j b . EJB ;
java . u t i l . List ;
java . u t i l . I t e r a t o r ;
java . u t i l . Scanner ;
j a v a . u t i l . InputMismatchException ;
e n t i t y . Adrese ;

public c l a s s C l i e n t {
@EJB
private s t a t i c AgendaEMail bean ;
private s t a t i c L i s t <Adrese> l i s t =n u l l ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
i n t p r e l , no ;
S t r i n g ch=Y , nume= , e m a i l= ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
I t e r a t o r <Adrese> i t e r=n u l l ;
Adrese i n r e g=n u l l ;
try {
while ( ch . s t a r t s W i t h ( Y ) ) {
do{
System . out . p r i n t l n ( Continue ? (Y/N) ) ;
ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
}
while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ;
i f ( ch . s t a r t s W i t h ( Y ) ) {
System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ;
System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ;
do{
p r e l =0;
try {
p r e l=s c a n n e r . n e x t I n t ( ) ;
}
catch ( InputMismatchException e ) { }
}
while ( ( p r e l <1)&&( p r e l > 2 ) ) ;
switch ( p r e l ) {
case 1 :
System . out . p r i n t l n ( Numele ) ;
nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
l i s t =bean . g e t E m a i l ( nume ) ;
i t e r= l i s t . i t e r a t o r ( ) ;

331

332

CAPITOLUL 13. ENTERPRISE JAVA BEANS

System . out . p r i n t l n ( A d r e s e l e de e m a i l p e n t r u : +nume ) ;


while ( i t e r . hasNext ( ) ) {
i n r e g =( Adrese ) i t e r . n e x t ( ) ;
System . out . p r i n t l n ( i n r e g . g e t E m a i l ( ) ) ;
}
break ;
case 2 :
System . out . p r i n t l n ( Email ) ;
e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ;
l i s t =bean . getNume ( e m a i l ) ;
i t e r= l i s t . i t e r a t o r ( ) ;
System . out . p r i n t l n ( I n r e g i s t r a r i l e p e n t r u a d r e s a : +e m a i l ) ;
while ( i t e r . hasNext ( ) ) {
i n r e g =( Adrese ) i t e r . n e x t ( ) ;
System . out . p r i n t l n ( i n r e g . getNume ( ) ) ;
}
break ;
default : System . out . p r i n t l n ( Comanda e r o n a t a ) ;

45
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 ) {
e . printStackTrace ( ) ;
}

65
66
67
68
69

70
71

Intreb
ari recapitulative
1. Care sunt tipurile de componente EJB studiate?
2. Care sunt posibilitatile de apelare / utilizare al unei componente EJB?
3. Care este tehnologia de comunicatie utilizata pentru apelerea unei componente EJB de un client program?
4. Cum se apeleaza un client - program al unei componente EJB?
5. Care sunt tiputile de componente sesiune EJB din JEE?

Capitolul 14
Aplicatie pe nivele
Ne propunem sa aratam locul unde instrumentele de programare dezvoltate
n cadrul cursului apar n activitatea uzuala de programare pentru o ntreprindere
economica.
Pe langa faptul ca trebuie sa asigure o functionalitate specifica, definirea /
implementarea unui nivel presupune alegerea unei tehnologii informatice sau
a unui produs informatic.
Una din aplicatiile uzuale este ntretinerea unei baze de date. Consideram
cazul unei baze de date gestionata de un sistem de gestiune a bazelor de date
(SGBD) relational. Problema ntretinerii consta n asigurarea urmatoarelor
operatii (denumite generic CRUD):
adaugarea unei nregistrari noi (Create);
consultarea bazei de date, extragerea de date (Read);
modificarea unei nregistrari (Update);
stergerea unei nregistrari (Delete).
In cele ce urmeaza luam n considerare platforma Java.
Punem n evidenta nivele (tiers) (se mai utilizeaza si terminologia staturi
- layers) ca obiective ale unei metode pentru rezolvarea problemei enuntata
anterior.
333

334

CAPITOLUL 14. APLICAT


IE PE NIVELE

14.1

Nivelele unei variante de rezolvare

Nivelul bazei de date


In acest nivel se defineste baza de date si eventual se populeaza cu date de
initializare. In anexa H (Programare distribuita 1), n acest scop s-au utilizat
scripturi sql executate prin intermediul unui utilitar pus la dispozitie de fiecare
SGBD. Un script sql contine comenzi specifice SGBD.

Nivelul de acces la SGBD


Interactiunea dintre Java si SGBD se programeaza:
prin intermediul unui produs de mapare (Object Relational Mapping
-ORM)
care implementeaza interfata Java Persistent API (JPA), parte din
Java Enterprise Edition (JEE) prin javax.persistence. Amintim
implementatile JPA:
Hibernate
OpenJPA
glassfish
apache-empire-db
apache-cayenne
iBATIS
prin acces nemijlocit (varianta utilizata n anexa H (Programare distribuita 1).
prin tehnologia dezvoltata n cadrul de lucru spring.
Utilizand interfata de programare JPA sarcinile sunt:
Fiecarui tabel al bazei de date supusa prelucrarii i se asociaza o clasa Java
(componenta Java, clasa POJO atribuind fiecarei coloane a tabelului un
camp cu metodele set si get. Denumim o asemenea clasa prin clasa entity
asociata tabelului.
Uzual numele clasei coincide cu numele tabelului.
Declararea maparii prin fisierul persistence.xml (sablon minimal)

14.1. NIVELELE UNEI VARIANTE DE REZOLVARE

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

335

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
< p e r s i s t e n c e v e r s i o n= 2 . 1
xmlns= h t t p : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e
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 : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e
h t t p : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e / p e r s i s t e n c e 2 1 . xsd >
<p e r s i s t e n c e u n i t name= n u m e l e u n i t a t i i d e p e r s i s t e n t a
t r a n s a c t i o n t y p e=RESOURCE LOCAL>
<c l a s s >c l a s a e n t i t y a t a b e l u l u i </c l a s s >
<p r o p e r t i e s >
<p r o p e r t y name= j a v a x . p e r s i s t e n c e . j d b c . d r i v e r
v a l u e= d r i v e r u l b a z e i d e d a t e />
<p r o p e r t y name= j a v a x . p e r s i s t e n c e . j d b c . u r l
v a l u e= a d r e s a u r l a b a z e i d e d a t e />
<p r o p e r t y name= j a v a x . p e r s i s t e n c e . j d b c . u s e r
v a l u e= user name />
<p r o p e r t y name= j a v a x . p e r s i s t e n c e . j d b c . password
v a l u e= password />
</ p r o p e r t i e s >
</ p e r s i s t e n c e u n i t >
</ p e r s i s t e n c e >

In glassfish acest fisier este


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

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
< p e r s i s t e n c e v e r s i o n= 2 . 1
xmlns= h t t p : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e
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 : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e
h t t p : / / xmlns . j c p . o r g /xml/ ns / p e r s i s t e n c e / p e r s i s t e n c e 2 1 . xsd >
<p e r s i s t e n c e u n i t name= n u m e l e u n i t a t i i d e p e r s i s t e n t a >
<p r o v i d e r >
org . e c l i p s e . p e r s i s t e n c e . jpa . P e r s i s t e n c e P r o v i d e r
</ p r o v i d e r >
<j t a datas o u r c e >n u m e l e j n d i a l b a z e i d e d a t e </ j t a datas o u r c e >
<p r o p e r t i e s >
<p r o p e r t y name= e c l i p s e . j d b c . d r i v e r
v a l u e= d r i v e r u l b a z e i d e d a t e />
</ p r o p e r t i e s >
</ p e r s i s t e n c e u n i t >
</ p e r s i s t e n c e >

Maparea nseamna stabilirea corespondentei dintre campurile unui obiect de


tip entity cu valorile corespunzatoare coloanelor ale unei nregistrari din tabel.
Folosind chiar accesul nemijlocit la baza de date, definirea clasei / claselor
entity este utila.
In acest nivel programatorul nu are probleme de comunicatii.

336

CAPITOLUL 14. APLICAT


IE PE NIVELE

Nivelul prelucr
arii unui tabel al bazei de date
Modelul prezentat n acest nivel este Data Access Object (DAO). O varianta
de programare a acestui nivel consta din:
O interfata cu operatiile asupra datelor din tabel;
Implementarea interfetei;
O clasa care mijloceste apelarea operatiile interfetei aparand ca un serviciu. Rolul acestei clase este simplificarea aplicatiei client.
Aceasta arhitectura permite utilizarea ei pentru diferite tipuri de client sau
moduri de acces la SGBD. Functie de modul de acces la SGBD utilizat sau de
tipul de client detaliile de programare pot diferi.

Nivelul aplicatiei client


Utilizatorul interactioneaza cu aplicatia de ntretinere a bazei de date prin
intermediul unei aplicatii client:
de sine statatoare (desktop) cu
interfata grafica (Swing, JavaFX)
text (ntr-o fereastra DOS)
aplicatie Web
servlet sau JSP;
aplicatie bazata pe un cadru de lucru de tip Struts, JSF, GWT, etc;
serviciu Web (JAX-WS, JAX-RS);
websocket.
Trebuie facuta distinctie ntre aplicatia client de nivel si clientul aplicatiei
Web care poate fi html, JSP sau chiar o aplicatie desktop.
In toate cazurile aplicatia client de nivel va utiliza serviciul realizat n nivelul
anterior.
In acest nivel apar problemele de comunicatii tratate n cadrul cursului de
Programare distribuita.

14.1. NIVELELE UNEI VARIANTE DE REZOLVARE

337

Nivelul de autentificare si autorizare


Aplicatia client poate fi completata cu o componenta care asigura autentificare si autorizare. In acest scop se poate utiliza apache-shiro.

Exemple
inerea bazei de date Agenda de adrese email.
Exemplul 14.1.1 Intret

Nivelul SGBD : *
Nivelul de acces la SGBD : nemijlocit
Nivelul aplicatiei client : desktop, servlet, rest (jersey), websocket
Nivelul autentificare si autorizare : desktop, servlet, rest (jersey,
inclusiv client jersey)

Nivelul SGBD : Derby (glassfish 4.1)


Nivelul de acces la SGBD : eclipselink (glassfish 4.1)
Nivelul aplicatiei client : servlet + desktop (RMI-IIOP), rest (jersey)
Nivelul autentificare si autorizare : servlet (fara client RMI-IIOP)

Nivelul SGBD : Derby (cu username,passwd), Mysql


Nivelul de acces la SGBD : hibernate
Nivelul aplicatiei client : desktop, servlet, rest (jersey), websocket

Nivelul SGBD : Derby (cu username,passwd), Mysql


Nivelul de acces la SGBD : openjpa
Nivelul aplicatiei client : desktop

Nivelul SGBD : Derby (cu username,passwd), Mysql


Nivelul de acces la SGBD : spring
Nivelul aplicatiei client : desktop, spring-mvc

338

CAPITOLUL 14. APLICAT


IE PE NIVELE

Probleme
1. glassfish cu Mysql
2. glassfish cu client websocket (cu injectii)
3. openjpa cu client servlet, restful, websocket
4. empire sau alt produs ORM

Partea III
ANEXE

339

Anexa A
Unelte de dezvoltare
Incepem aceasta sectiune prin a introduce cateva elemente privind sintaxa
unui document xml.

A.1

XML

EXtensible Markup Language (XML) reprezinta un limbaj pentru definirea


marcajelor de semantica, care mpart un document n parti identificabile n
document. Din 1998, XML este un standard World Wide Web Consortium
(W3C).
Totodata XML este un meta-limbaj pentru definirea sintaxei de utilizat n
alte domenii.
XML descrie structura si semantica si nu formatarea.
Structura unui document XML este
<?xml version="1.0" encoding="tip_codare" [standalone="yes"]?>
corpul documentului alcatuit din elemente
Prima linie - preambulul - reprezinta declaratia de document XML. Tipul
codarii poate fi utf-8, iso-8859-1.
Corpul documentului este alcatuit din elemente. Inceputul unui element
este indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. Elementele pot fi cu corp, alcatuit din alte elemente, avand sintaxa
<marcaj>
corpul elementului
</marcaj>
341

342

ANEXA A. UNELTE DE DEZVOLTARE

sau fara corp, caz n care sintaxa este


<marcaj/>
Un marcaj poate avea atribute date prin sintaxa
numeAtribut="valoareAtribut"
Valoarea unui atribut este cuprinsa ntre ghilimele ().
<marcaj numeAtribut="valoareAtribut" . . .>
corpul elementului
</marcaj>
Exista un singur element radacina. Elementele unui document XML formeaza
un arbore. Fiecarui marcaj de nceput al unui element trebuie sa-i corespunda
un marcaj de sfarsit. Caracterele mari si mici din denumirea unui element sunt
distincte (case sensitive).
Elementele ncuibarite (nested )- incluse ntr-un alt element - nu se pot
amesteca, adica un marcaj de sfarsit corespunde ultimului marcaj de nceput.
Un comentariu se indica prin
<!-Text comentariu
-->
Exemplul A.1.1 Fisier XML - denumirile elementelor si continutul lor permit
ntelegerea simpla a semanticii introduse n document.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

<?xml version= 1 . 0 e n c o d i n g= u t f 8 ?>


<c u r s u r i>
< d i s c i p l i n a f e l = o b l i g a t o r i u >
<nume> A n a l i z a numerica </nume>
<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

20
21
22
23
24
25
26
27

343

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


exista preambul;
fiecare element este nchis sau i corespunde un marcaj de inchidere;
marcajele ncuibarite nu se amesteca.
Un document XML este valid daca
este bine formatat;
n cazul ca exista o referinta catre XML Schema atunci documentul XML
este conform schemei.
Un produs informatic accesibil gratuit, care permite verificarea bine formatarii si a validitatii unui document xml, este XML Copy Editor.
Pentru validare, daca fisierul XML Schema se afla n alt catalog decat cel al
fiserului xml atunci acestuia i se asociaza XML Schema prin XML Associate
XML Schema. . .
Prelucrarea unui document XML n Java se poate face pe baza interfetelor
de programare:
Document Object Model - DOM;
Simple API for XML - SAX;
Stream API for XML - StAX;
Amintim faptul ca reprezentarea obiectelor matematice prin elemente XML
constituie subiectul a doua proiecte MathML si OpenMath. Obiectivul limbajului MathML este reprezentarea unui text matematic ntr-un document HTML,
n timp ce obiectivul proiectului OpenMath este reprezentarea semantica a
datelor matematice pentru realizarea de aplicatii cooperante ntre sisteme de
calcul simbolic - CAS (Computer Algebra System).
Formatul XML se utilizeaza si pentru serializarea unui obiect, adica reprezentarea campurilor mpreuna cu valorile aferente sub forma de text, n cadrul
transmisiilor de date. Interfata de programare este Java Architecture for XML
Binding - JAXB.

344

A.2

ANEXA A. UNELTE DE DEZVOLTARE

apache-ant

Utilitarul apache-ant asigura executarea unui sir de comenzi de operare.


Aceste comenzi se nregistreaza ntr-un fisier de tip xml, cu denumirea build.xml.
Astfel, apache-ant se substituie unui fisier de comenzi bat n Windows sau unui
script shell din Linux/Unix. Avantajul obtinut consta n independenta fata de
platforma de calcul (Windows, Linux).
Instalarea consta n dezarhivarea fisierului descarcat din Internet.
Lansarea n executie necesita fixarea variabilei de mediu JAVA HOME, ce
contine calea la distributia Java. Lansarea se poate face prin urmatorul fisier
de comenzi
set JAVA_HOME=. . .
set ANT_HOME=. . .
%ANT_HOME%\bin\ant.bat %1
Parametrul %1 acestui fisier de comenzi reprezinta obiectivul care se doreste
a fi atins. Daca se modifica denumirea sau locatia fisierului build.xml atunci
fisierul de comenzi se invoca cu optiunea -buildfile.
Un fisier build.xml corespunde unui proiect (project), alcatuit din unul
sau mai multe obiective (target). Atingerea fiecararui obiectiv consta din
ndeplinirea uneia sau mai multor sarcini (task). Apache-ant contine o familie
predefinita de sarcini. Programatorul are datoria fixarii atributelor sarcinilor.
Manualul din documentatia produsului contine descrierea atributelor cat si
exemple. In general, o sarcina reprezinta o operatie executata uzual n linia
de comanda.
Atributele se dau, respectand sintaxa XML
numeAtribut = valoareAtribut
Astfel, un proiect apare sub forma
<project name="numeProiect"
default="obiectiv"
basedir="catalogDeReferinta">
<target name="numeObiectiv">
sarcini
</target>
. . . . . . .
</project>

A.2. APACHE-ANT

345

Daca la apelarea lui Apache-ant lipseste parametrul optional atunci se va


executa obiectivul default.
Intr-un proiect se pot defini variabile prin marcajul
<property name=numeVariabila value=valoareVariabila />
O variabila definita se va utiliza cu sintaxa ${numeVariabila}.
Exemplul A.2.1 Fisierul build pentru executia programelor din 1.2.
1
2
4
5
6
7
8
10
11
12
13
14
15
16
18
19
20
22
23
24
26
27
28
29
30
31

<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= . />
<p r o p e r t y name= h o s t v a l u e= l o c a l h o s t />
<p r o p e r t y name= p o r t v a l u e= 7999 />
<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 >
<a r g l i n e= ${ h o s t } ${ p o r t } />
</ j a v a>
</ t a r g e t>
</ p r o j e c t>

Utilizarea lui apache-ant presupune ca toate resursele utilizate, cuprinse


uzual n fisiere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul
local. Daca calculatorul este conectat la Internet, atunci resursele publice
pot fi descarcate mpreuna cu toate dependintele si utilizate prin apache-ant,
folosind suplimentar apache-ivy 1 .
In vederea utilizarii lui apache-ivy se copiaza fisierul ivy-*.jar din distributia
apache-ivy n ANT HOME\lib.
Fisierul build.xml contine n plus
1

Asem
an
ator cu maven, un alt produs de dezvoltare.

346

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 adauga un fisier ivy.xml, cu dependintele necesare aplicatiei care
urmeaza a fi preluate dintr-unul din depozitele ivy - local, shared, public
<ivy-module version="2.0">
<info organisation="cs.unitbv.ro" module="Biblioteca-Ivy"/>
<dependencies>
<dependency org="commons-fileupload" name="commons-fileupload" rev="1.2"/>
. . .
</dependencies>
</ivy-module>

A.3

apache-maven

Apache-maven 2 este un alt cadru de dezvoltare si gestiune a proiectelor


(Project management framework). Calculatorul pe care se dezvolta proiectul
/ aplicatia trebuie sa fie conectat la internet. Resursele necesare ndeplinitii
diferitelor sarcini (maven artifacts) sunt preluate din internet si depuse ntrun depozit local maven (local repository). In prezent sunt ntretinute depozite
2

Maven acumulator de cunostiinte (Idis).

A.3. APACHE-MAVEN

347

publice de resurse soft necesare dezvoltarii de aplicatii cu maven 3 iar dezvoltatorii de instrumente soft au posibilitatea de a-si promova produsele prin
depunerea ntr-un depozit maven. Dintr-un asemenea depozit public resursele
necesare sunt descarcate n depozitul local.

Gestiunea proiectelor cu apache-maven


Instalarea produsului consta n dezarhivarea fisierului descarcat din internet ntr-un catalog MAVEN HOME.
Utilizarea produsului necesita
Completarea variabilei de sistem PATH cu calea MAVEN HOME\bin.
Declararea variabilei JAVA HOME avand ca valoare calea catre distributia
jdk folosita.
In mod obisnuit depozitul local maven este
C:\Documents and Settings\client\.m2\repository
Locatia depozitului local se poate modifica, introducand elementul
<localRepository>volum:/cale/catalog_depozit</localRepository>
n fisierul MAVEN HOME\conf\settings.xml.
Potrivit principiului separarii preocuparilor (Separation of Conserns), un
proiect maven produce o singura iesire.
Declararea unui proiect se face printr-un fisier pom.xml (Project Object
Model). Este sarcina programatorului sa completeze fisierul pom.xml, creat
la generarea structurii de cataloage ale proiectului, cu specificarea resurselor
suplimentare sau a conditionarilor n efectuarea unor operatii (de exemplu,
prezenta adnotarilor necesita utilizarea versiunii Java 1.5).
Dezvoltarea unei aplicatii / proiect prin maven presupune generarea unei
structuri de cataloage (Standard directory layout for projects). Aceasta structura de cataloage este specifica tipului / sablonului de aplicatie (archetype, n
limbajul maven).
Sabloane uzuale de aplicatii:
Nume sablon
Semnificatia
maven-archetype-quickstart aplicatie simpla
(sablonul implicit)
maven-archetype-webapp
aplicatie Web
3

De exemplu repo1.maven.org/maven2.

348

ANEXA A. UNELTE DE DEZVOLTARE

Sablonul se specifica n parametrul -DarchetypeArtifactId al comenzii


mvn archetype:create.
Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare,
testare, etc) se obtin prin comenzi maven.
Comenzile maven sunt de doua tipuri:

Comenzi pentru gestiunea ciclului de viata al unui proiect (lifecycle commands):

Comanda maven
mvn -version

Semnificatia
afiseaza versiunea maven
(utila pentru verificarea functionarii lui maven)
mvn clean
sterge fisierele maven generate
mvn compile
compilarea sursele Java
mvn test-compile compileaza sursele Java care
realizeaza testele junit
mvn test
executa testul junit
mvn package
creaza o arhiva jar sau war
mvn install
depune arhiva jar sau war n depozitul local

Comenzi de operare inserate (plugin commands):

A.3. APACHE-MAVEN

Comanda maven
mvn -B archetype:generate

349
Semnificatia
genereaza structura de cataloage a
proiectului. Optiunea -B are ca efect
generarea neinteractiva.
mvn -B archetype:generate \
-DgroupId=numelePachetuluiAplicatiei \
-DartifactId=numeleProiectului \
-DarchetypeArtifactId=numeS
ablon\
-Dversion=versiuneaProiectului

mvn archetype:generate

mvn clean:clean
mvn
mvn
mvn
mvn

compiler:compile
surefire:test
jar:jar
install:install-file

genereaza structura de cataloage ai


proiectului.
Sablonul se alege dintr-o lista
sterge fisierele generate n urma
compilarii
compilarea sursele Java
executa testul junit
creaza o arhiva jar
depune o arhiva jar n depozitul local
mvn install:install-file \
-Dfile=numeFisier \
-DgroupId=numePachet \
-DartifactId=numeProiect \
-Dversion=versiunea \
-Dpackaging=tipArhiv
a

mvn exec:java

executa metoda main a unei clase


mvn exec:java -Dexec.mainClass=

mvn dependency:copy-dependencies
Astfel comanda
set GroupID=simple.app.helloworld
set ArtifactID=helloworld
set Version=1.0
mvn -B archetype:generate -DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

genereaza arborescenta

clasaMetodeiMain
-Dexec.args=lista argumente
descarca n catalogul target resursele
declarate n dependencies.

350

hello
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|--> test
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
pom.xml

ANEXA A. UNELTE DE DEZVOLTARE

java
|-->
|
|
|

unitbv
|--> cs
|
|--> calcul
|
|
| App.java

java
|-->
|
|
|

unitbv
|--> cs
|
|--> calcul
|
|
| AppTest.java

Descrierea proiectului este data n fisierul pom.xml generat


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</ 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 verificare bazat pe junit.
Pentru testarea aplicatiei, din catalogul hello se executa comenzile
mvn compile
mvn exec:java -Dexec.mainClass="simple.app.helloworld.App"
mvn test

Executia programului se poate lansa prin intermediul unui profil (profile)


mvn exec:java -PnumeProfil

In prealabil n fisierul pom.xml se introduce secventa


<profiles>
<profile>
<id>numeProfil</id>
<properties>
<target.main.class>clasaCuMetodaMain</target.main.class>
</properties>
</profile>

A.3. APACHE-MAVEN

351

</profiles>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>${target.main.class}</mainClass>
<includePluginDependencies>false</includePluginDependencies>
</configuration>
</plugin>
</plugins>
</build>

Aceasta varianta este avantajoasa n cazul n care proiectul include mai multe
clase cu metoda main.
Sarcina programatorul este acela de a nlocui aceste programe cu cele care
rezolva sarcinile proiectului. Pentru orice prelucrare toate dependintele trebuie
sa se gaseasca n depozitul local maven. Daca o dependinta (resursa jar)
nu se gaseste n depozitul local atunci resursa este cautata ntr-un depozit
global si este descarcata n depozitul global. Este sarcina programatorului sa
declare toate dependintele necesare unei aplicatii. Declararea se face ntr-un
element <dependency>. Daca resursa este inaccesibila atunci maven termina
prelucrarea.
Programatorul are posibilitatea sa specifice depozite globale unde sa se
gaseasca resursele necesare, de exemplu
<repositories>
<repository>
<id>java.net-promoted</id>
<url>https://maven.java.net/content/groups/promoted/</url>
</repository>
</repositories>

Exemplul A.3.1 Dezvoltarea aplicatiei de calcul al celui mai mare divizor


comun a doua numere naturale utilizand maven.
Generam proiectul maven
set GroupID=simple.app.cmmdc
set ArtifactID=cmmdc
set Version=1.0
mvn archetype:generate -DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

Inlocuim clasa App cu clasele

352

ANEXA A. UNELTE DE DEZVOLTARE

1.
1
2
4
5
6
7
8
9
10
11
12

package s i m p l e . app . cmmdc ;


import j a v a . u t i l . S c a n n e r ;
public c l a s s App{
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
MyCmmdc o b j=new MyCmmdc ( ) ;
System . out . p r i n t l n ( cmmdc = +o b j . cmmdcService . cmmdc(m, n ) ) ;
}

14
15

2.
1
2
3
4
5

package s i m p l e . app . cmmdc ;


public c l a s s MyCmmdc{
i n t e r f a c e CmmdcService {
long cmmdc( long m, long n ) ;
}
s t a t i c CmmdcService cmmdcService=(long m, long n ) > { . . . }

7
9

iar programul de testare AppTest.java prin


1
2
3
5
6
7

package s i m p l e . app . cmmdc ;


import o r g . j u n i t . ;
import s t a t i c o r g . j u n i t . A s s e r t . ;
public c l a s s T e s t P r o i e c t {
MyCmmdc o b j ;
long r e z ;
@Before
public void setUp ( ) {
o b j=new MyCmmdc( ) ;
}

9
10
11
12

@Test
public void testCmmdc1 ( ) {
r e z=o b j . cmmdcService . cmmdc ( 5 6 , 4 2 ) ;
a s s e r t E q u a l s (14 l , rez ) ;
}

14
15
16
17
18

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

20
21
22
23

Completarea fisierului pom.xml:


1. Aplicatia necesita Java 8. Aceasta cerinta se declara prin secventa de
cod

A.3. APACHE-MAVEN

353

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2. Intrucat dorim sa folosim cea mai recenta versiune a produsului junit
modificam numarul versiunii.
Fisierul pom.xml devine
1
2
3
4
5
7
8
9
10
12
13
15
16
17
19
20
21
22
23
24
25
26
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 / xsd /maven 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 m p l e . app . cmmdc</ 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>
<version>1.0 SNAPSHOT</ version>
<p a c k a g i n g>j a r</ p a c k a g i n g>
<name>cmmdc</name>
<u r l>h t t p : //maven . apache . o r g</ u r l>
<p r o p e r t i e s>
<p r o j e c t . b u i l d . s o u r c e E n c o d i n g>UTF8</ p r o j e c t . b u i l d . s o u r c e E n c o d i n g>
</ p r o p e r t i e s>
<d e p e n d e n c i e s>
<dependency>
<g r o u p I d>j u n i t</ g r o u p I d>
< a r t i f a c t I d>j u n i t</ a r t i f a c t I d>
<version>4 . 1 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>

354

33
34
35
36
37
38
39
40
41

ANEXA A. UNELTE DE DEZVOLTARE

<c o n f i g u r a t i o n>
< ! or w h a t e v e r version you u s e >
<s o u r c e>1 . 8</ s o u r c e>
<t a r g e t>1 . 8</ 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>

Dupa asamblarea aplicatiei, din catalogul aplicatiei, operarea poate fi


mvn clean compile test
mvn exec:java -Dexec.mainClass="simple.app.cmmdc.App"

maven cu ant
In maven se pot integra sarcini apache-ant pentru orice etapa al evolutiei
unei aplicatii. Utilizarea consta n completarea fisierului pom.xml cu
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>
<!-- etapa de viata : compile, package, install, test -->
</phase>
<configuration>
<tasks>
<!-- Exemplu
<property name="compile_classpath" refid="maven.compile.classpath"/>
<property name="runtime_classpath" refid="maven.runtime.classpath"/>
<property name="test_classpath" refid="maven.test.classpath"/>
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<echo message="compile classpath:
<echo message="runtime classpath:
<echo message="test classpath:
<echo message="plugin classpath:
-->
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

${compile_classpath}"/>
${runtime_classpath}"/>
${test_classpath}"/>
${plugin_classpath}"/>

In elementul <tasks> se definesc sarcinile ant care se doresc executate la


comanda corespunzatoare prelucrarii etapei din evolutia proiectului maven compile, package, install, test, etc.

A.3. APACHE-MAVEN

355

Mai precis, elementele <echo> se nlocuiesc cu sarcinile ant care se doresc


efectuate.
Proprietatile se definesc n elementul
<properties>
<nume.proprietate>valoare</nume.proprietate>
. . .
</properties>

Dezvoltarea unui servlet prin maven


Dezvoltarea unui servlet prin maven 4 se va exemplifica prin aplicatia n
care servletul raspunde clientului cu mesajul Hi nume client, nume client
fiind parametru transmis de catre client la apelarea servlet-ului.
Container de servleti cu care lucreaza maven este jetty.
Dezvoltarea revine la parcurgerea pasilor:
1. Generarea aplicatiei:
set GroupID=hello
set ArtifactID=helloname
set Version=1.0
mvn -B archetype:generate
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-webapp

Se creaza structura de cataloage si fisiere


helloname
|--> src
|
|--> main
|
|
|-->
|
|
|-->
|
|
|
|
|
|
|
|
|
|
pom.xml

resources
webapp
|--> WEB-INF
|
|
web.xml
|
index.jsp

unde fisierul pom.xml este


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

356

ANEXA A. UNELTE DE DEZVOLTARE

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 completeaza structura creata anterior cu
helloname
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|
|
|
|-->
|
|
|-->
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|--> hello
|
|
HelloServlet.java
resources
webapp
|--> WEB-INF
|
|
web.xml
|
index.html

HelloServlet.java este cel utilizat n capitolul Servlet din cursul de


Programare distribuita.
Fisierul web.xml este completat cu elementele specifice servlet-ului
(servlet si servlet-mapping).
1
2
3
5
6
7
8
9
10
11
12
13
14
15

< !DOCTYPE webapp PUBLIC


//Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN
h t t p : // j a v a . sun . com/ dtd /weba p p 2 3 . dtd >
<webapp>
<d i s p l a y name>Archetype C r e a t e d Web A p p l i c a t i o n</ d i s p l a y name>
< s e r v l e t>
<s e r v l e t name> h e l l o</ s e r v l e t name>
<s e r v l e t c l a s s> h e l l o . H e l l o S e r v l e t</ s e r v l e t c l a s s>
</ s e r v l e t>
<s e r v l e t mapping>
<s e r v l e t name> h e l l o</ s e r v l e t name>
<u r l p a t t e r n>/ h e l l o</ u r l p a t t e r n>
</ s e r v l e t mapping>
</webapp>

A.3. APACHE-MAVEN

357

Fisierul index.jsp se nlocuieste cu fisierul index.html utilizat la


servletul mentionat anterior5 .
Fisierul pom.xml se completeaza cu
Referintele la resursele javax.servlet.servlet-api, necesare compilarii.
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

Referintele serverului Web jetty


<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
</plugin>
</plugins>

Codul fisierului pom.xml devine


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

<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>j a v a x . s e r v l e t a p i</ a r t i f a c t I d>
<version> 3 . 0 . 1</ 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 . e c l i p s e . j e t t y</ g r o u p I d>
< a r t i f a c t I d>j e t t y mavenp l u g i n</ a r t i f a c t I d>

Atentie la parametri de apelare a servlet-ului, care eventual trebuie adaptati. Contextul


aplicatiei coincide cu parametrul artifactId

358

ANEXA A. UNELTE DE DEZVOLTARE

32
33
34
35
36

<version> 9 . 1 . 0 . v20131115</ version>


</ p l u g i n>
</ p l u g i n s>
</ b u i l d>
</ p r o j e c t>

Clauza provided din elementul <scope> implica neincluderea resursei n arhiva war.
3. Prelucrarea revine la
(a) mvn clean package
(b) lansarea serverului Web jetty: mvn jetty:run
Serverul se opreste cu Ctrl+C.
(c) testarea servlet-ului: ntr-un navigator se deschide pagina
http://localhost:8080/index.html.

Aplicatie JSP prin maven


Ne propunem sa calculam cel mai mare divizor comun a doua numere naturale ntr-o pagina JSP utilizand o componenta Java pentru calculul propriu-zis
(cf. cursului de Programare distribuita).
Realizarea aplicatiei JSP consta din
1. Generarea cadrului:
set GroupID=jsp
set ArtifactID=cmmdcjsp
set Version=1.0
mvn -B archetype:generate
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-webapp

2. Se completeaza aplicatia cu fisierele CmmdcBean.java, cmmdc.jsp si index.html din cursul Programare distribuita, desfasurarea fiind
cmmdcjsp
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|-->
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|
CmmdcBean.java
resources
webapp
|--> jsp
|
|
cmmdc.jsp
|--> WEB-INF
|
|
web.xml
index.html

A.4. GRADLE PENTRU JAVA

359

3. Fisierul pom.xml se completeaza cu referinta pentru Jetty, la fel cum s-a


procedat la servlet.
4. Prelucrarea consta din
(a) mvn clean package
(b) mvn jetty:run
(c) Din navigator se apeleaza http://localhost:8080/index.html.

A.4

Gradle pentru Java

Gradle este un instrument de dezvoltare oferind:


functionalitati pentru mai multe limbaje de programare (Java, Scala,
Python, C/C++, Android, etc);
posibilitat de integrare n medii integrate de dezvoltare (IDE) Eclipse,
Android Studio, IntelliJ;
functionalitati care combina pe cele oferite de ant, maven si ivy.
Instalarea consta n dezarhivarea fisierului descarcat.

Gradle pentru aplicatii Java desktop


In vederea utilizarea lui Gradle este necesara fixarea variabilei JAVA HOME.
Un proiect dezvoltat prin Gradle cere o structura fixa a aplicatiei.
Generarea structurii
gradle init --type java-library

Structura unei aplicatii simple - (Proiect Gradle) cuprinde n esenta


Catalogul_aplicatiei
|--> src
|
|--> main
|
|
|--> java
|
|
|--> resources
|
|--> test
|
|
|--> java
|
|
|--> resources
|
build.gradle

360

ANEXA A. UNELTE DE DEZVOLTARE

In cataloagele java sunt prezente fisierele Library.java si respectiv LibraryTest.java. Testarea este bazata pe junit. Dezvoltarea se face nlocuind aceste
fisiere cu cele ale aplicatiei.
Intr-un proict, optional pot fi prezente fisierele gradle.properties si
gradle.settings.
Fisierul build.gradle precizeaza prelucrarile solicitate. Compilarea se
obtine cu
1

apply pl ugin :

java

Din catalogul aplicatiei Gradle se va lansa prin


1

gradle clean assemble

In catalogul aplicatiei va rezulta subcatalogul build cu continutul


build
|--> classes
|--> dependency-cache
|--> libs
|
|
catalogul_aplicatiei.jar
|--> tmp
Catalogul libs va lipsi daca sarcina de prelucrare ceruta este compileJava.
Pentru lansarea n executie a programului, fisierul build.gradle trebuie
sa contina
2

apply pl ugin :
apply pl ugin :

mainClassName= c l a s a cu metoda main

java
application

iar lansarea va fi
1

g r a d l e c l e a n a s s e m b l e run

Tabelul A.1 contine sarcini Gradle.


In gradle.settings fixeaza componentele unei aplicatii cu mai multe
proiecte Gradle.
1

include

server , clientfx , clientswing

In acest caz se vor executa sarcinile cerute pentru fiecare din proiectele Gradle
specificate (clean, assemble).

Ant prin Gradle


Un fisier build.xml pentru apache-ant se executa prin Gradle cu fisierul
build.gradle

361

A.4. GRADLE PENTRU JAVA

Sarcina
clean
compileJava
compileTest
assemble
run
test

Actiune
Sterge catalogul build
Compilare
Compilare claselor test
Compilare si arhivare
Executa aplicatia
Executa testele
Table A.1: Sarcini Gradle

ant.importBuild build.xml

prin
gradle obiectiv_Ant_din_build.xml

Detalii de configurare
Introducerea de date se poate face doar prin intermediul unei interfete
grafice.
Comentariile n build.gradle se indica prin
// linie de comentariu
(* text comentariu *)
Preluarea argumentelor din linia de comand
a se indica n build.gradle
prin
1. Varianta 1
2

apply pl ugin :
apply pl ugin :

mainClassName= c l a s a cu metoda main

run {
a r g s System . g e t P r o p e r t y ( e x e c . a r g s ) . s p l i t ( )
}

7
8

java
application

cu
1

g r a d l e . bat c l e a n a s s e m b l e run Dexec . a r g s= a r g 1 a r g 2 . . .

2. Varianta 2

362

ANEXA A. UNELTE DE DEZVOLTARE

apply pl ugin :
apply pl ugin :

mainClassName= c l a s a cu metoda main

run {
i f ( p r o j e c t . hasProperty ( args )){
a r g s p r o j e c t . a r g s . s p l i t ( \\ s )
}
}

7
8
9
10

java
application

cu
1

g r a d l e . bat c l e a n a s s e m b l e run Pargs= a r g 1 a r g 2 . . .

Arhiva jar va fi executabil


a daca n fisierul build.gradle se include
secventa
jar {
manifest {
attributes Main-class: clasa cu metoda main
}
}

Propriet
atile de sistem se declara n fisierul build.gradle
run {
classpath = sourceSets.main.runtimeClasspath
//classpath.each { println it }
/* Can pass all the properties: */
//systemProperties System.getProperties()
/* Or just each by name: */
systemProperty "java.rmi.server.codebase", System.getProperty("java.rmi.server.codebase")
}

si valorile proprietatilor sunt definite n


gradle.bat clean run -DnumeProprietate=valoare . . .

Resursele suplimentare - fisiere jar - depuse n catalogul lib sunt


considerate daca n build.gradle se includ secventele
repositories{
flatDir{
dirs lib
}
}
dependencies{
compile junit:junit:4.12
}

In sectiunea dependencies sintaxa utilizata este


nume pachet : nume arhiva jar : versiune.

A.4. GRADLE PENTRU JAVA

363

Gradle pentru aplicatii Web


Servlet
Gradle ofera suport pentru dezvoltarea unei aplicatii servlet bazat pe servletapi versiunea 2.5 si pentru serverul Web jetty, versiunea 6. Versiunea 2.5 corespunde modelului descriptiv, caracterizat prin prezenta fisierului web.xml.
Astfel dezvoltarea unui servlet bazat pe servlet-api versiunea 3.0 va fi
diferita de cea pentru versiunea 2.5
Servlet 2.5
Structura aplicatiei
Catalogul_aplicatiei
|--> src
|
|--> main
|
|
|--> java
|
|
|--> webapp
|
|
|
|--> WEB-INF
|
|
|
|
|--> lib
(optional)
|
|
|
|
index.html
|
build.gradle
Generarea acestei structuri se face n mod obisnuit
gradle init --type java-library

urmat de crearea manuala a structurii webapp.


Fisierul build.gradle se completeaza cu
apply plugin: java
apply plugin: war
apply plugin: jetty
dependencies{
providedCompile javax.servlet:servlet-api:2.5
}

urmat de comanda
gradle clean assemble jettyRunWar

Se va lansa serverul Web jetty cu servletul activ. Alternativ, arhiva war a


servletului se poate desfasura n orice server Web.

364

ANEXA A. UNELTE DE DEZVOLTARE

Servlet 3.0
Structura aplicatiei
Catalogul_aplicatiei
|--> lib
|
|
servlet-api.jar
|--> src
|
|--> main
|
|
|--> java
|
|
|--> webapp
|
|
|
|--> WEB-INF
|
|
|
|
|--> lib
(optional)
|
|
|
|
index.html
|
build.gradle
Fisierul build.gradle se completeaza cu
apply plugin: java
apply plugin: war
repositories{
flatDir{
dirs lib,src/main/webapp/WEB-INF/lib
}
}
dependencies{
providedCompile javax.servlet:servlet-api:3.0
}

Prelucrarea este
gradle.bat clean assemble

Arhiva war din catalogul build\libs se va desfasura ntr-un server Web compatibil.

Anexa B
Fir de executie prin -expresie
Java introduce firele de executie prin interfetele
java.lang.Runnable
Interfata declara metoda public void run().
Clasa java.lang.Thread implementeaza interfata Runnable.
java.util.concurrent.Callable<V>
Interfata declara metoda public V call().
Sablon pentru definirea unui fir de executie de tip Thread printr-o lambda
expresie
interface MyThread{
Thread service(semnatura datelor de intrare);
}
static MyThread action=(semnatura datelor de intrare)->{
return new Thread(()->{
codul metodei run
});
};
Exemplul B.0.1
interface MyThread{
Thread scrie(String txt);
}
static MyThread f=(String txt)->{

365

366

ANEXA B. FIR DE EXECUT


IE PRIN -EXPRESIE

return new Thread(()->{


System.out.println(txt);
}); // Varianta fara lansare implicita
// Varianta cu lansare implicita
// }).start();
};

Variante de lansare n executie:

public static void main(String args[]){


f.scrie("Primul fir de executie").start();
f.scrie("Al doilea fir de executie").start();
f.scrie("Al treilea fir de executie").start();
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
. . .
static final int NTHREADS=100;
static ExecutorService exec=Executors.newFixedThreadPool(NTHREADS);
. . .
public static void main(String args[]){
exec.execute(f.scrie("Primul fir de executie"));
exec.execute(f.scrie("Al doilea fir de executie"));
exec.execute(f.scrie("Al treilea fir de executie"));
exec.shutdown();
}

Sablon pentru definirea unui fir de executie de tip java.util.concurrent.


Callable<T> printr-o lambda expresie
interface MyCallable{
Callable<T> service(semnatura datelor de intrare);
}
static MyCallable action=(semnatura datelor de intrare)->{
Callable<T> c=()->{
T var;
codul metodei call
return var:
};
return c;
};
Exemplul B.0.2
import java.util.concurrent.Callable;
. . .
interface MyCallable{
Callable<Integer> scrie(int index) throws Exception;

367

}
static MyCallable f=(int index)->{
Callable<Integer> c=()->{
System.out.println("I am "+index);
return index;
};
return c;
};

Variante de lansare n executie:

public static void main(String args[]){


int numarFire=3;
try{
for(int i=0;i<numarFire;i++){
Integer r=f.scrie(i).call();
System.out.println("Returned : "+r);
}
}
catch(Exception e){
System.out.println("Exception : "+e.getMessage());
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.List;
import java.util.ArrayList;
. . .
static final int NTHREADS=100;
static ExecutorService exec=Executors.newFixedThreadPool(NTHREADS);
. . .
public static void main(String args[]){
List<Callable<Integer>> tasks =
new ArrayList<Callable<Integer>>(NTHREADS);
try{
for(int i=0;i<NTHREADS;i++){
tasks.add(f.scrie(i));
}
List<Future<Integer>> results=exec.invokeAll(tasks);
for(int i=0;i<NTHREADS;i++){
Future<Integer> r=results.get(i);
if(r.isDone()) System.out.println("Returned : "+r.get());
}
exec.shutdown();
}
catch(Exception e){
System.out.println("Exception : "+e.getMessage());
}
}

368

ANEXA B. FIR DE EXECUT


IE PRIN -EXPRESIE

Anexa C
Testare cu junit
Verificarea / testarea automata a programelor Java se poate face cu produsul informatic junit. Deseori se formuleaza probleme de test ale caror rezultate sunt cunoscute, cu rolul de a verifica functionarea unui program de rezolvare, pentru depistarea unor greseli.
S-a dezvoltat si o metodologie de lucru Test Driven Development - (TDD)
care presupune pentru orice clasa elaborata realizarea unui program de testare,
chiar a priori.
Un alt produs care are acelasi scop de verificare a rezultatelor este TestNG.
junit permite verificarea automata a rezultatelor furnizate de un program,
pentru o multime de date de test.
Instalarea produsului consta din dezarhivarea fisierului descarcat ntr-un
catalog JUNIT HOME. Pentru compilare si executie, variabila de sistem classpath
trebuie sa contina referinta JUNIT HOME\junit-*.jar.
Utilizarea produsului ntr-un program Java consta din:
1. Declararea resurselor pachetului junit prin
import org.junit.*;
import static org.junit.Assert.*;
2. Declararea clasei cu testele junit - uzual n metoda main.
org.junit.runner.JUnitCore.main("AppClass");
3. Eventuale operatii necesare nainte sau dupa efectuarea testelor se precizeaza respectiv, n cate o metoda care a fost declarata cu adnotarea
@org.junit.Before si respectiv, @org.junit.After.
4. Testele se definesc n metode declarate cu adnotarea @org.junit.Test.
Clasa Assert poseda metodele de verificare ale unui rezultat:
369

370

ANEXA C. TESTARE CU JUNIT

static void assertEquals(Tip asteptat, Tip actual )


unde Tip poate fi double, int, long, Object.
static void assertEquals(double asteptat, double actual, double
delta)
Testul reuseste daca |asteptat-actual | < delta.
static void assertArrayEquals(Tip[ ] asteptat, Tip[ ] actual )
unde Tip poate fi 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)
In cazul exemplului
1
2
4
5
6

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

8
9
10

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

12
13
14
15

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

17
18
19
20

se obtine
JUnit version 4.5
.
Time: 0.03
OK (1 test)

Exemplul C.0.3 Testarea clasei App ( 2.2.1).

371

1
2
3
5
6

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

8
9
10
11

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

13
14
15
16

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

19
20
21
22

Exemplul C.0.4 Testarea clasei MyMServer ( 2.2.1).


Primul test se refera la metoda getServerSocket. Se verifica afirmatiile:
1. Metoda returneaza un obiect 6= null.
2. Obiectul returnat este de tip ServerSocket.
Al doilea test verifica metoda myAction. In acest scop se defineste ntro clasa un fir de executie care n metoda run() apeleaza metoda myAction.
Actiunile metodei de testare sunt:
1. Se obtine un obiect ServerSocket.
2. Se lanseaza firul de executie amintit mai sus.
3. Se simuleaza activitatea unui client.
1
2
3
4
5
6
7
8
9
10

package s e r v e r . impl ;
import s e r v e r . impl . MyMServer ;
import o r g . j u n i t . B e f o r e ;
import o r g . j u n i t . Test ;
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 ;
import j a v a . n e t . S o c k e t ;
import j a v a . i o . DataInputStream ;
import j a v a . i o . DataOutputStream ;

372

12
13
14
15
16
17

public c l a s s TestMyMServer {
private IMyMServer o b j ;
private s t a t i c i n t p o r t =7999;
public s t a t i c f i n a l long M=12;
public s t a t i c f i n a l long N=15;
public s t a t i c f i n a l long RESULT=3;
@Before
public void i n i t i a l i z a r e ( ) {
o b j=new MyMServer ( ) ;
}

19
20
21
22

@Test
public void t e s t ( ) {
i n t p o r t =8999;
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 ( ) ) ;
}

24
25
26
27
28
29
30

@Test
public void t e s t M y A c t i o n ( ) {
long r =0;
S e r v e r S o c k e t s s=o b j . g e t S e r v e r S o c k e t ( p o r t ) ;
EmbeddedThread t h r e a d=new EmbeddedThread ( s s ) ;
thread . s t a r t ( ) ;
try ( S o c k e t cmmdcSocket = new S o c k e t ( l o c a l h o s 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 ( ) ;
}
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 ( ) ) ;
}
a s s e r t E q u a l s ( r , RESULT ) ;
}

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

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

52
53
54

c l a s s EmbeddedThread extends Thread {


ServerSocket ss ;

56
57

EmbeddedThread ( S e r v e r S o c k e t s s ) {
t h i s . s s=s s ;
}

59
60
61

public void run ( ) {


o b j . myAction ( s s ) ;
}

63
64
65

66
67

ANEXA C. TESTARE CU JUNIT

Anexa D
Jurnalizare
Jurnalizarea adica afisarea / retinerea rezultatelor sau evenimentelor ntrun fisier. Deseori prezinta interes evolutia procesului de calcul prin prisma
unor rezultate intermediare. In acest sens se pot utiliza:
pachetul java.util.logging din jdk.
apache-log4j-2.
slf4j (Simple Logging Facade for Java), (www.QOS.ch, Quality of Open
Software).
logback (logback.qos.ch).

Jurnalizare prin java.util.logging


Sablonul de programare cu afisarea mesajelor pe ecranul monitorului este
1

import j a v a . u t i l . l o g g i n g . Logger ;

public c l a s s Exemplu{
s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ;

public s t a t i c void main ( S t r i n g a r g s [ ] ) {


l o g g e r . s e v e r e ( SEVERE : H e l l o ) ;
l o g g e r . warning ( WARNING : H e l l o ) ;
l o g g e r . i n f o ( INFO : H e l l o ) ;
}

6
7
8
9
10
11

Programul afiseaza
Jan 23, 2013 2:34:40 PM Exemplu main
SEVERE: SEVERE : Hello
Jan 23, 2013 2:34:40 PM Exemplu main

373

374

ANEXA D. JURNALIZARE

WARNING: WARNING : Hello


Jan 23, 2013 2:34:40 PM Exemplu main
INFO: INFO : Hello

Daca dorim ca rezultatele sa fie nscrise ntr-un fisier, de exemplu logging.txt


atunci clasa de mai sus se modifica n
1
2
3
4
6
7

import
import
import
import

u t i l . l o g g i n g . Logger ;
u t i l . logging . FileHandler ;
u t i l . l o g g i n g . SimpleFormatter ;
i o . IOException ;

public c l a s s Exemplu{
s t a t i c Logger l o g g e r = Logger . g e t L o g g e r ( Exemplu . c l a s s . getName ( ) ) ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
try {
F i l e H a n d l e r l o g g i n g F i l e = new F i l e H a n d l e r ( l o g g i n g . t x t ) ;
l o g g i n g F i l e . s e t F o r m a t t e r (new S i m p l e F o r m a t t e r ( ) ) ;
l o g g e r . addHandler ( l o g g i n g F i l e ) ;
}
catch ( IOException e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}
l o g g e r . s e v e r e ( SEVERE : H e l l o ) ;
l o g g e r . warning ( WARNING : H e l l o ) ;
l o g g e r . i n f o ( INFO : H e l l o ) ;
}

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

java .
java .
java .
java .

Jurnalizare prin logback


Jurnalizare cu retinerea rezultatelor n fisier
1
2
3
5
6
7
8
9
10
11
12
13
14

package l o g t e s t ;
import o r g . s l f 4 j . Logger ;
import o r g . s l f 4 j . L o g g e r F a c t o r y ;
public c l a s s Exemplu{
s t a t i c Logger l o g g e r=L o g g e r F a c t o r y . g e t L o g g e r ( Exemplu ) ;
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
l o g g e r . t r a c e ( TRACE : H e l l o ) ;
l o g g e r . debug ( DEBUG : H e l l o ) ;
l o g g e r . i n f o ( INFO : H e l l o ) ;
l o g g e r . warn ( WARN : H e l l o ) ;
l o g g e r . e r r o r ( ERROR : H e l l o ) ;
}
}

cu fisierul de configurare
1
2
3
4
5
6

<c o n f i g u r a t i o n>
<appender name=STDOUT c l a s s= ch . q o s . l o g b a c k . c o r e . ConsoleAppender >
<e n c o d e r>
<p a t t e r n>
%d{HH:mm:ss . SSS} [% t h r e a d ] %5 l e v e l %l o g g e r {36} %msg%n
</ p a t t e r n>

375

</ e n c o d e r>
</ appender>

7
8

<appender name=FILE c l a s s= ch . q o s . l o g b a c k . c o r e . F i l e A p p e n d e r >


< f i l e > r e s u l t s . l o g</ f i l e >
<e n c o d e r>
<p a t t e r n>
%d a t e %l e v e l [% t h r e a d ] %l o g g e r {10} [% f i l e : %l i n e ] %msg%n
</ p a t t e r n>
</ e n c o d e r>
</ appender>

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

<r o o t l e v e l= t r a c e >
<appenderr e f r e f=STDOUT />
<appenderr e f r e f=FILE />
</ r o o t>
</ c o n f i g u r a t i o n>

Jurnalizare prin apache-log4j-2


Jurnalizare cu retinerea rezultatelor n fisier
1
2
4
5

import o r g . apache . l o g g i n g . l o g 4 j . LogManager ;


import o r g . apache . l o g g i n g . l o g 4 j . Logger ;
public c l a s s Exemplu{
s t a t i c Logger l o g g e r = LogManager . g e t L o g g e r ( Exemplu . c l a s s ) ;
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
l o g g e r . warn ( WARN : H e l l o ) ;
l o g g e r . debug ( DEBUG : H e l l o ) ;
l o g g e r . i n f o ( INFO : H e l l o ) ;
l o g g e r . f a t a l ( FATAL : H e l l o ) ;
}

7
8
9
10
11
12
13

cu fisierul de configurare
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=UTF8 ?>


<c o n f i g u r a t i o n s t a t u s=OFF>
<p r o p e r t i e s>
<p r o p e r t y name= f i l e n a m e > r e s u l t s . l o g</ p r o p e r t y>
</ p r o p e r t i e s>
<a p p e n d e r s>
<C o n s o l e name= C o n s o l e t a r g e t=SYSTEM OUT>
<P a t t e r n L a y o u t
p a t t e r n=%d{HH:mm:ss . SSS} [% t ] %5 l e v e l %l o g g e r {36} %msg%n />
</ C o n s o l e>
<F i l e name= F i l e f i l e N a m e= ${ f i l e n a m e } >
<P a t t e r n L a y o u t
p a t t e r n=%d{HH:mm:ss . SSS} [% t ] %5 l e v e l %l o g g e r {36} %msg%n />
</ F i l e>
</ a p p e n d e r s>
<l o g g e r s>
<r o o t l e v e l= t r a c e >
<appenderr e f r e f= C o n s o l e />
<appenderr e f r e f= F i l e />

376

20
21
22

</ r o o t>
</ l o g g e r s>
</ c o n f i g u r a t i o n>

ANEXA D. JURNALIZARE

Anexa E
Component
a Java (Java Bean)
O componenta Java este o clasa care poate interactiona cu alte componente
Java, cu un document jsp, etc.
O componenta Java contine cel putin
Un constructor fara nici un argument;
O multime de campuri declarate private;
Pentru fiecare asemenea camp
private Tip xyz;
trebuie definite cel putin una din metodele
public void setXyz(Tip xyz){
this.xyz=xyz;
}
public Tip getXyz(){
return xyz;
}

377

378

JAVA
ANEXA E. COMPONENTA

Anexa F
Serializare f
ar
a XML
Scopul serializarii unor date are ca scop obtinerea unei reprezentari text n
vederea transmiterii prin retea. Orice solutie trebuie sa ofere si posibilitatea
refacerii datelor din forma serializata Serializarea se poate obtine prin

Prin ncorporarea datelor ntr-un document XML. In acest sens amintim


Java Architecture for XML Binding - JAXB.

Metode / tehnologii fara XML:

YAML Aint Markup Language - YAML1


JavaScript Object Notation - JSON

Se considera ca JSON este o restrictie de YAML.

Acronimul YAML are si alt


a semnificatie Yet Another Multicolumn Layout, desemnand
o tehnologie JavaScript-CSS.

379

380

A
XML
ANEXA F. SERIALIZARE FAR

F.1

YAML Aint Markup Language - YAML

Marcaj YAML
Marcaj standard YAML
!!null
!!bool
!!int
!!float
!!binary
!!timestamp
!!omap, !!pairs
!!set
!!str
!!seq
!!map

Tip Java
null
Boolean
Integer, Long, BigInteger
Double
String
java.util.Date, java.sql.Date, java.sql.Timestamp
List of Object[ ]
Set
String
List
Map

In Java vom exemplifica cu produsul snakeyaml.


Exemplul F.1.1
Pornim de la componenta Java
1
2
3

public c l a s s D i s c i p l i n a {
private S t r i n g nume ;
Disciplina (){}
D i s c i p l i n a ( S t r i n g nume ) {
t h i s . nume=nume ;
}
public S t r i n g getNume ( ) {
return nume ;
}
public void setNume ( S t r i n g nume ) {
t h i s . nume=nume ;
}

5
6
7
8
9
10
11
12
13
14

Se instantiaza 3 obiecte care vor fi convertite n reprezentari YAML stringuri ce sunt retinute ntr-un obiect de tip java.util.Map. In final acest
obiect este reprezentat YAML, care este salvat ntr-un fisier.
1
2
3
4
5
7
8

import
import
import
import
import

j a v a . u t i l . Map ;
j a v a . u t i l . HashMap ;
o r g . yaml . snakeyaml . Yaml ;
o r g . yaml . snakeyaml . T y p e D e s c r i p t i o n ;
java . io . PrintWriter ;

public c l a s s G e n e r a r e {
// @SuppressWarnings ( unc hecked )

F.1. YAML AINT MARKUP LANGUAGE - YAML

public s t a t i c void main ( S t r i n g [ ] a r g s ) {


Yaml yaml = new Yaml ( ) ;
Map<S t r i n g , S t r i n g > data = new HashMap<S t r i n g , S t r i n g > ( ) ;

9
10
11

D i s c i p l i n a an=new D i s c i p l i n a ( A n a l i z a numerica ) ;
S t r i n g san=yaml . dump( an ) ;
data . put ( an , san ) ;

13
14
15

D i s c i p l i n a pd=new D i s c i p l i n a ( Programare d i s t r i b u i t a ) ;
S t r i n g spd=yaml . dump( pd ) ;
data . put ( pd , spd ) ;

17
18
19

D i s c i p l i n a sm=new D i s c i p l i n a ( S o f t matematic ) ;
S t r i n g ssm=yaml . dump( sm ) ;
data . put ( sm , ssm ) ;

21
22
23

System . out . p r i n t l n ( S e r i a l i z a r e a d a t e l o r ) ;
System . out . p r i n t l n ( C o n t i n u t u l o b t i n u t : \ n ) ;
try {
P r i n t W r i t e r pw=new P r i n t W r i t e r ( f i l e . yaml ) ;
S t r i n g objYAML=yaml . dump( data ) ;
System . out . p r i n t l n (objYAML ) ;
pw . w r i t e (objYAML ) ;
pw . f l u s h ( ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

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

37
38

381

Fisierul creat anterior este preluat, continutul reconvertit n obiect de tip


Map, iar componentele nmagazinate sunt retransformate n obiecte.
1
2
3
4
5
6
7
8
9
11
12
13
14
16
17
18
19
20
21
23
24
25

import
import
import
import
import
import
import
import
import

java . io . F i l e ;
java . io . FileInputStream ;
j a v a . i o . InputStream ;
j a v a . u t i l . Map ;
o r g . yaml . snakeyaml . Yaml ;
java . io . PrintWriter ;
o r g . yaml . snakeyaml . c o n s t r u c t o r . C o n s t r u c t o r ;
java . u t i l . Collection ;
java . u t i l . I t e r a t o r ;

public c l a s s U t i l i z a r e {
// @SuppressWarnings ( unc hecked )
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
C o n s t r u c t o r c o n s t r u c t o r=new C o n s t r u c t o r ( D i s c i p l i n a . c l a s s ) ;
try {
InputStream i n p u t = new F i l e I n p u t S t r e a m ( f i l e . yaml ) ;
Yaml yaml = new Yaml ( ) ;
O b j e c t data = yaml . l o a d ( i n p u t ) ;
System . out . p r i n t l n ( C o n t i n u t u l i n c a r c a t : \ n ) ;
System . out . p r i n t l n ( data . t o S t r i n g ( ) ) ;
Map<S t r i n g , S t r i n g > map = (Map) data ;
C o l l e c t i o n <S t r i n g > d i s c i p l i n e=map . v a l u e s ( ) ;
I t e r a t o r <S t r i n g > i t e r=d i s c i p l i n e . i t e r a t o r ( ) ;

382

A
XML
ANEXA F. SERIALIZARE FAR

Yaml yaml1 = new Yaml ( c o n s t r u c t o r ) ;


System . out . p r i n t l n ( R e g a s i r e a d a t e l o r : \ n ) ;
while ( i t e r . hasNext ( ) ) {
S t r i n g s o b j=i t e r . n e x t ( ) ;
// Abordare u r a t a ! !
s o b j=s o b j . s u b s t r i n g ( 1 4 , s o b j . l e n g t h ( ) 2 ) ;
D i s c i p l i n a o b j =( D i s c i p l i n a ) yaml1 . l o a d ( s o b j ) ;
System . out . p r i n t l n ( o b j . getNume ( ) ) ;
}

26
27
28
29
30
31
32
33
34

}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

35
36
37
38

39
40

F.2

JavaScript Object Notation - JSON

JSON ofera o modalitate simpla (mai simpla chiar decat XML) pentru
schimbul de date dintre un server si un client.
Pentru reprezentarea datelor n JSON se utilizeaza structurile de date:
colectie de atribute, adica perechi (nume, valoare). O colectie de atribute
este denumit obiect JSON.
sir de valori.
Aceste structuri de date sunt prezente n toate limbajele de programare de uz
general.
O colectie de atribute se reprezinta prin
{numeAtribut:valAtribut,numeAtribut:valAtribut,...}
Un sir de valori se reprezinta prin
[valoare,valoare,...]
valAtribut, valoare poate fi un string, numar, true, false, null, o colectie
sau un sir.

JSON n JavaScript
Utilizarea entitatilor JSON n javascript este exemplificat n aplicatia urmatoare.

F.2. JAVASCRIPT OBJECT NOTATION - JSON

Exemplul F.2.1
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

<HTML>
<HEAD>
<TITLE>Primul exemplu J a v a S c r i p t</TITLE>
<SCRIPT LANGUAGE= J a v a S c r i p t >
< !
var myJSONObj=[{ d i s c i p l i n a : A n a l i z a Numerica } ,
{ d i s c i p l i n a : Programare d i s t r i b u i t a } ,
{ d i s c i p l i n a : S o f t matematic } ] ;
f o r ( var i =0; i<myJSONObj . l e n g t h ; i ++){
document . w r i t e l n ( <br> ) ;
document . w r i t e l n (myJSONObj [ i ] . d i s c i p l i n a ) ;
}
document . w r i t e l n ( <br> ) ;
var myObj=e v a l (myJSONObj ) ;
document . w r i t e l n ( myObj . t o S t r i n g ( ) ) ;
f o r ( var i =0; i <myObj . l e n g t h ; i ++){
document . w r i t e l n ( <br> ) ;
document . w r i t e l n ( myObj [ i ] . d i s c i p l i n a ) ;
}
//>
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

JSON n Java
google-gson
Analogul aplicatiei javascript de mai sus, poate fi
Exemplul F.2.2
1
2
3
4
5
7
8
9

import
import
import
import
import

class D i s c i p l i n a {
private S t r i n g nume ;
Disciplina (){}
D i s c i p l i n a ( S t r i n g nume ) {
t h i s . nume=nume ;
}
public S t r i n g getNume ( ) {
return nume ;
}

11
12
13
14
15
16
17

com . g o o g l e . gson . Gson ;


com . g o o g l e . gson . r e f l e c t . TypeToken ;
j a v a . l a n g . r e f l e c t . Type ;
java . u t i l . Collection ;
java . u t i l . I t e r a t o r ;

383

384

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

A
XML
ANEXA F. SERIALIZARE FAR

public c l a s s TestGSON{
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Gson gson=new Gson ( ) ;
D i s c i p l i n a an=new D i s c i p l i n a ( A n a l i z a numerica ) ;
D i s c i p l i n a pd=new D i s c i p l i n a ( Programare d i s t r i b u i t a ) ;
D i s c i p l i n a sm=new D i s c i p l i n a ( S o f t matematic ) ;
D i s c i p l i n a [ ] d i s c i p l i n e ={an , pd , sm } ;
S t r i n g j s o n=gson . t o J s o n ( d i s c i p l i n e ) ;
System . out . p r i n t l n ( j s o n ) ;
Type c o l l e c t i o n T y p e = new TypeToken<C o l l e c t i o n <D i s c i p l i n a > >(){}. getType ( ) ;
C o l l e c t i o n <D i s c i p l i n a > d = gson . fromJson ( j s o n , c o l l e c t i o n T y p e ) ;
I t e r a t o r <D i s c i p l i n a > i t e r=d . i t e r a t o r ( ) ;
while ( i t e r . hasNext ( ) ) {
D i s c i p l i n a d i s=i t e r . n e x t ( ) ;
System . out . p r i n t l n ( d i s . getNume ( ) ) ;
}
}
}

javax.json
Interfata javax.json.JsonValue introduce obiectele nemodificabile (immutable) JsonArray, JsonObject, JsonString, JsonNumber, JsonValue.TRUE,
JsonValue.FALSE, JsonValue.NULL.
Obiectele se instantiaza prin intermediul unor metode statice ale clasei
javax.json.Json.
Exista structura de interfete
JsonValue JsonStructure JsonArray
JsonObject
JsonString
JsonNumber
acopera tipurile de date Java numerice
BigDecimal, BigInteger, int, long,
double
Clasa javax.json.Json
Metode
static JsonObjectBuilder createObjectBuilder()
static JsonArrayBuilder createArrayBuilder()
static JsonWriter createWriter(java.io.Writer writer )
static JsonReader createReader(java.io.Reader reader )

F.2. JAVASCRIPT OBJECT NOTATION - JSON

385

Interfata javax.json.JsonObjectBuilder
Metode
JsonObjectBuilder add(String name, TipJson value)
TipJson{BigDecimal, BigInteger, int, long, double, boolean,
JsonObjectBuilder, JsonArrayBuilder, JsonValue, String}.
JsonObjectBuilder addNull()
JsonObject build()
Sablon de utilizare
JsonObject jsonObject=Json.createObjectBuilder()
.add("name", value)
. . .
.build();

Interfata javax.json.JsonArrayBuilder
Metode
JsonArrayBuilder add(TipJson value)
TipJson{BigDecimal, BigInteger, int, long, double, boolean,
JsonObjectBuilder, JsonArrayBuilder, JsonValue, String}.
JsonArrayBuilder addNull()
JsonArray build()
Sablon de utilizare
JsonArray jsonArray=Json.createArrayBuilder()
.add(value)
. . .
.build();

Interfata javax.json.WriterBuilder
Metode
void writeArray(JsonArray array)
void writeObject(JsonObject object)
void close()
Sablon de utilizare
PrintWriter printWriter=new PrintWriter(System.out)
JsonWriter jsonWriter=Json.createWriter(printWriter);
jsonWriter.writeArray(jsonArray);
jsonWriter.close();

386

A
XML
ANEXA F. SERIALIZARE FAR

Interfata javax.json.ReaderBuilder
Metode
void readArray()
void readObject()
void close()
Sablon de utilizare
String string=. . .
JsonReader jsonReader = Json.createReader(new StringReader(string));
JsonArray array = jsonReader.readArray();
jsonReader.close();

Exemplul F.2.3 Crearea unui fisier json.


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
33
34
35
36
37

import
import
import
import
import
import
import
import

j a v a x . j s o n . JsonArray ;
javax . json . JsonArrayBuilder ;
javax . json . JsonObject ;
javax . json . JsonObjectBuilder ;
javax . json . JsonWriter ;
j a v a x . j s o n . Json ;
java . io . PrintWriter ;
j a v a . i o . IOException ;

public c l a s s GenerateJSON {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
JsonArray j s o n A r r a y=Json . c r e a t e A r r a y B u i l d e r ( )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , A n a l i z a numerica ) )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , Programare d i s t r i b u i t a ) )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , S o f t matematic ) )
. add ( 1 0 0 )
. add ( j a v a x . j s o n )
. add ( Json . c r e a t e A r r a y B u i l d e r ( )
. add ( 1 )
. add ( 2 )
. add ( 3 ) )
. add ( Json . c r e a t e A r r a y B u i l d e r ( )
. add ( 4 )
. add ( 5 )
. add ( 6 ) )
. build ( ) ;
System . out . p r i n t l n ( System . out : +j s o n A r r a y ) ;
S t r i n g f i l e N a m e= exemplu . j s o n ;
try {
J s o n W r i t e r j s o n W r i t e r=Json . c r e a t e W r i t e r (new P r i n t W r i t e r ( f i l e N a m e ) ) ;
jsonWriter . writeArray ( jsonArray ) ;
jsonWriter . clos e ( ) ;
}

F.2. JAVASCRIPT OBJECT NOTATION - JSON

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 ( ) ) ;
}
J s o n W r i t e r j s o n W r i t e r=Json . c r e a t e W r i t e r (new P r i n t W r i t e r ( System . out ) ) ;
jsonWriter . writeArray ( jsonArray ) ;
jsonWriter . c los e ( ) ;

38
39
40
41
42
43

44
45

Exemplul F.2.4 Consultarea fisierului json creat n exemplul anterior.


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

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

j a v a x . j s o n . JsonArray ;
javax . json . JsonObject ;
j a v a x . j s o n . JsonReader ;
j a v a x . j s o n . Json ;
j a v a x . j s o n . JsonValue ;
javax . json . JsonString ;
j a v a x . j s o n . JsonNumber ;
java . io . FileReader ;
j a v a . i o . IOException ;
java . u t i l . I t e r a t o r ;
j a v a . u t i l . Map ;
java . u t i l . Set ;

public c l a s s ReadJSON{
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 N a m e= exemplu . j s o n ;
S t r i n g path=d : \ \mk\\DISTR2\\GSON\\JEE\\ ex1 \\ ;
JsonArray a r r a y=n u l l ;
try {
JsonReader j s o n R e a d e r =
Json . c r e a t e R e a d e r (new F i l e R e a d e r ( path+f i l e N a m e ) ) ;
array = jsonReader . readArray ( ) ;
jsonReader . c l o s e ( ) ;
}
catch ( IOException e ) {
System . out . p r i n t l n ( Ex : +e . g e t M e s s a g e ( ) ) ;
}
analyse ( array ) ;
}
private s t a t i c void a n a l y s e ( JsonArray v ) {
I t e r a t o r <JsonValue> i t e r a t o r=v . i t e r a t o r ( ) ;
while ( i t e r a t o r . hasNext ( ) ) {
JsonValue v a l u e =( JsonValue ) i t e r a t o r . n e x t ( ) ;
i f ( v a l u e instanceof JsonArray ) {
JsonArray a r r a y =( JsonArray ) v a l u e ;
analyse ( array ) ;
}
i f ( v a l u e instanceof J s o n O b j e c t ) {
J s o n O b j e c t o b j =( J s o n O b j e c t ) v a l u e ;
analyseJsonObject ( obj ) ;
}
i f ( v a l u e instanceof J s o n S t r i n g ) {
J s o n S t r i n g s t r i n g =( J s o n S t r i n g ) v a l u e ;
S t r i n g s=s t r i n g . g e t S t r i n g ( ) ;
System . out . p r i n t l n ( s ) ;

387

388

A
XML
ANEXA F. SERIALIZARE FAR

}
i f ( v a l u e instanceof JsonNumber ) {
JsonNumber number=(JsonNumber ) v a l u e ;
double d=number . d o u b l e V a l u e ( ) ;
System . out . p r i n t l n ( d ) ;
}

47
48
49
50
51
52

53
54

56

private s t a t i c void a n a l y s e J s o n O b j e c t ( J s o n O b j e c t o b j ) {
Map<S t r i n g , JsonValue> o b j e c t =(Map) o b j ;
Set<S t r i n g > k e y s=o b j e c t . k e y S e t ( ) ;
I t e r a t o r <S t r i n g > i t e r=k e y s . i t e r a t o r ( ) ;
while ( i t e r . hasNext ( ) ) {
S t r i n g name=i t e r . n e x t ( ) ;
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( J s o n O b j e c t name : +name ) ;
JsonValue vv=( JsonValue ) o b j e c t . g e t ( name ) ;
i f ( vv instanceof JsonArray ) {
JsonArray a r r a y =( JsonArray ) vv ;
analyse ( array ) ;
}
i f ( vv instanceof J s o n O b j e c t ) {
J s o n O b j e c t o=( J s o n O b j e c t ) vv ;
analyseJsonObject ( o ) ;
}
i f ( vv instanceof J s o n S t r i n g ) {
J s o n S t r i n g s t r i n g =( J s o n S t r i n g ) vv ;
S t r i n g s=s t r i n g . g e t S t r i n g ( ) ;
System . out . p r i n t l n ( s ) ;
}
i f ( vv instanceof JsonNumber ) {
JsonNumber number=(JsonNumber ) vv ;
double d=number . d o u b l e V a l u e ( ) ;
System . out . p r i n t l n ( d ) ;
}
}
}

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

Anexa G
Adnot
ari
O adnotare este o completare, o nota sau o nsemnare care explica sau
ntregeste un text.
O metadata este o adnotare a unei date.
In Java o adnotare (annotation) este o metadata a unui element de cod
(identificator al unei entitati din codul Java).
O adnotare poate sa-si faca efectul:
asupra codului sursa, naintea compilarii;
asupra codului obiect, dupa compilare, dar naintea executarii;
n timpul executiei codului.
Din punctul de vedere al sintaxei intereseaza
definirea unei adnotari;
declararea unei adnotari;
procesarea unei adnotari.

G.1

Definirea unei adnot


ari

Sintaxa utilizata este


import java.lang.annotation.*;
modificator @interface NumeAdnotare{
declarare Element 1
389

390

ANEXA G. ADNOTARI

declarare Element 2
. . .
}
unde declarare Element poate fi:
tip numeElement();
tip numeElement() default valoare;
iar tip poate fi
predefinit (int, short, long, byte, char, float, double, boolean);
String
Class
enum
adnotare
tablou ale carei elemente sunt de un tip precizat anterior
Adnotarea se salveaza ca fisier text, sub numele NumeAdnotare.java.
Dupa numarul elementelor declarate ntr-o adnotare, acesta poate fi
0 - caz n care adnotarea este de tip marker;
1 sau mai multe elemente (single-element / multi-value annotation).

G.2

Declararea unei adnot


ari

O adnotare se poate referi la un pachet, clasa, interfata, metoda, camp.


Inaintea declararii elementului asupra caruia actioneaza, adnotarea se indica prin
@NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )


G.3. PROCESAREA UNEI ADNOTARI

G.3

391

Procesarea unei adnot


ari

Java declara adnotarile


Adnotari regulate
Override
Deprecated
SuppressWarnings

Meta-adnotari
Target
Retention
Documented
Inherited

Adnotarea Override
Adnotarea Override precizeaza faptul ca se suprascrie un element al clasei
parinte.
1
2
3
4
5
6

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

8
9
10
11
12

Daca n locul liniei 9 se pune Date d=new Date(); atunci nu mai apare
mesajul TestOverride.

Adnotarea Deprecated
Adnotarea Deprecated are ca efect afisarea unui mesaj de avertisment n
momentul compilarii.
Exemplificam cu clasele
1
2
3
4
5
6

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

392

ANEXA G. ADNOTARI

Mesajul de avertisment este


Note: TestDeprecated.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

Comentand linia adnotarii are ca efect la o noua compilare disparitia mesajelor


de avertisment.

Adnotarea SuppressWarnings
Adnotarea SuppressWarnings inhiba afisarea mesajelor de avertisment.
Reluam exemplul anterior schimband clasa Test. In urma compilarii nu mai
apar mesajele de avertisment mentionate mai sus.
1
2

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

4
5
6
7
8

Adnotarea Target
Adnotarea Target precizeaza elementul asupra careia actioneaza:
ElementType.TYPE
ElementType.FIELD
ElementType.METHOD
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL VARIABLE
ElementType.ANNOTATION TYPE

Adnotarea Retention
Adnotarea Retention precizeaza momentul actiunii adnotarii:
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME

393

G.3. PROCESAREA UNEI ADNOTARI

Adnotarea Documented
Adnotarea Documented are ca efect mentionarea adnotarii n documentul
obtinut prin javadoc.
Fie clasele
1

import j a v a . l a n g . a n n o t a t i o n . Documented ;

@Documented
public @ i n t e r f a c e MyDocumented{}

si
1
2
3
4

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

6
7
8
9
10

javadoc se lanseaza prin


md docs
javadoc -d docs *Documented.java

Procesarea unei adnotari se refera n primul rand la regasirea n momentul


executiei a valorilor elementelor adnotarii. In functie de valorile regasite se pot
implementa actiuni specifice.
Procesarea unei adnotari se bazeaza pe metodele interfetei AnnotationElement,
implementata de clasele Class, Constructor, Field, Method, Package:
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
Annotation[] getAnnotations()
Annotation[] getDeclaredAnnotations()
boolean isAnnotationPresent(Class<?
notationClass)
Consideram adnotarea

import
import
import
import

@Retention ( R e t e n t i o n P o l i c y .RUNTIME)

1
2
3

java . lang . annotation . Retention ;


j a v a . l a n g . a n n o t a t i o n . Tar ge t ;
java . lang . annotation . RetentionPolicy ;
j a v a . l a n g . a n n o t a t i o n . ElementType ;

extends Annotation> an-

394

7
8
9
10
11

ANEXA G. ADNOTARI

@Target ( ElementType .METHOD)


public @ i n t e r f a c e MyAnnotation {
S t r i n g doAction ( ) default ;
i n t i n d e x ( ) default 0 ;
}

pe care o utilizam n clasa


1

import j a v a . l a n g . r e f l e c t . Method ;

public c l a s s T e s t A n n o t a t i o n {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
T e s t A n n o t a t i o n o b j=new T e s t A n n o t a t i o n ( ) ;
obj . v e r i f ( obj ) ;
}

4
5
6
7

@MyAnnotation ( doAction=XYZ , i n d e x =1)


public void v e r i f ( O b j e c t o ) {
try {
C l a s s c l=o . g e t C l a s s ( ) ;
Method m=c l . getMethod ( v e r i f ,
new C l a s s [ ] { ( new O b j e c t ( ) ) . g e t C l a s s ( ) } ) ;
i f (m. i s A n n o t a t i o n P r e s e n t ( MyAnnotation . c l a s s ) ) {
MyAnnotation a=m. g e t A n n o t a t i o n ( MyAnnotation . c l a s s ) ;
i f ( a != n u l l ) {
S t r i n g numeElement=a . doAction ( ) ;
System . out . p r i n t l n ( numeElement ) ;
i n t i n d e x=a . i n d e x ( ) ;
System . out . p r i n t l n ( i n d e x ) ;
}
}
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( MyEx : +e . g e t M e s s a g e ( ) ) ;
}
}

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

Clasa java.lang.Class furnizeaza o reprezentare (reflectare) a unei clase


n timpul executiei. Metoda
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
furnizeaza o reprezentare (reflectare) a unei metode n timpul executiei unui
program.

Anexa H
Utilizarea SGBD n Java
Scopul acestei anexe este prezentarea bazelor utilizarii unui Sistem de
Gestiune a Bazelor de Date (SGBD - Data Bases Management System - DBMS)
din Java. Exemplificam modul de operare si utilizare pentru crearea si exploatarea unei baze de date corespunzatoare unei agende de adrese e-mail.

H.1

Derby / Javadb

Instalarea produsului consta n dezarhivarea fisierului descarcat.


Utilizarea produsului. Va fi utilizata varianta de retea bazata pe un
server al SGBD care utilizeaza implicit portul 1527.
Se ntreprind urmatoarele operatii:
1. Lansarea serverului Derby / Javadb:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
startNetworkServer.bat -h 0.0.0.0 -noSecurityManager

Prezenta optiunii -h 0.0.0.0 asigura accesul la serverul SGBD de pe


orice calculator.
2. Crearea bazei de date se va face utilizand utilitarul ij din distributia
Derby / Javadb. Acesta se lanseaza prin:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
ij.bat

395

396

ANEXA H. UTILIZAREA SGBD IN JAVA

Exemplul H.1.1
Baza de date AgendaEMail se creaza executand
run CreateAgendaE.sql;
unde fisierul CreateAgendaE.sql este
1
2
3
4
5
6
7

connect j d b c : derby : AgendaEMail ; c r e a t e=t r u e ;


create table a d r e s e (
i d i n t g e n e r a t e d a l w a y s as i d en t i ty ( s t a r t with 1 , i n c r e m e n t by 1 )
primary key ,
nume char ( 2 0 ) not null ,
e m a i l char ( 3 0 ) not n u l l
);

si ncarcarea cu date
run ValuesAgendaE.sql;
cu fisierul ValuesAgendaE.sql
1
2
3

i n s e r t into a d r e s e ( nume , e m a i l ) values ( aaa , aaa@yahoo . com ) ,


( bbb , bbb@gmail . com ) , ( c c c , cc c@un itb v . r o ) ,
( aaa , xyz@unitbv . r o ) ;

H.2

mysql

Instalarea produsului. Pentru instalare s-a descarcat varianta fara instalare automata mysql-*.*.*-win*.zip. Acest fisier se dezarhiveaza ntr-un
catalog MYSQL HOME.
Dezarhivarea este urmata de initializare
Varianta nesecurizata, adica fara utilizarea parolelor:
set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld --initialize-insecure

Varianta securizata:
set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld --initialize

Pentru root se va genera o parole initiala si efemera care trebuie modificata

H.2. MYSQL

397

ALTER USER root@localhost IDENTIFIED BY new_password;

n cadrul unei sesiuni mysql


set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysql -u root -p

Implicit, serverul mysql utilizeaza portul 3306, iar fisierele bazelor de date vor
fi gazduite n catalogul MYSQL HOME\data.
Pentru utilizarea n aplicatii Java trebuie descarcat un conector mysqlconnector-java-*.*.*.tar.gz, continand fisierul mysql-connector-java*.*.*-bin.jar.
Utilizarea produsului.
Se ntreprind urmatoarele operatii:
1. Lansarea serverului mysql :
set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld

2. Exemplul H.2.1
Crearea bazei de date AgendaEMail se va face prin intermediul fisierului
de comenzi
set MYSQL_HOME=d:\mysql-*-win*\bin
set path=%MYSQL_HOME%;%PATH%
mysql -u root < CreateAgendaE.sql
mysql -u root < ValuesAgendaE.sql

unde scriptul CreateAgendaE.sql este


1
2
4
5
6
7
8

create d a t a b a s e AgendaEMail ;
u s e AgendaEMail ;
create table a d r e s e (
i d i n t primary key a u t o i n c r e m e n t not null ,
nume char ( 2 0 ) not null ,
e m a i l char ( 3 0 ) not n u l l
);

iar scriptul de populare cu date (ValuesAgendaE.sql ) este


1
2
3
4
5

u s e AgendaEMail ;
i n s e r t a d r e s e values ( 1 , aaa , aaa@yahoo . com ) ;
i n s e r t a d r e s e values ( 2 , bbb , bbb@gmail . com ) ;
i n s e r t a d r e s e values ( 3 , c c c , ccc @uni tbv . r o ) ;
i n s e r t a d r e s e values ( 1 , aaa , xyz@unitbv . r o ) ;

398

ANEXA H. UTILIZAREA SGBD IN JAVA

3. Serverul mysql se opreste prin


set MYSQL_HOME=d:\mysql-*-win*
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqladmin -u root shutdown

Daca se utilizeaza varianta securizata atunci comenzile mysql de la pct. 2 si


3 trebuie sa contina optiunea -p. Prin aceasta optiune se cere autentificarea
prin introducerea parolei.

H.3

S
ablonul de utilizare a unei baze de date
ntr-un program Java

Interactiunea cu baze de date relationale implica:


1. Stabilirea corespondentei dintre date aflate n obiecte si atribute / tabele
(object to relational database mapping).
2. Apelarea actiunilor CRUD (Create, Read, Update, Delete).
Limbajul SQL (Structured Query Language) este dependent de SGBD utilizat. Dezvoltarea interactiunii dintre un program Java (client) cu o baza de
date dintr-un SGBD s-a nascut din dorinta de a asigura independenta stratului
Java de SGBD. Solutia gasita consta n introducerea unui strat suplimentar,
ntre Java si SGBD care asigura corespondenta ntre obiectele Java cu tabelele
unei baze de date si permite o configurare simpla la schimbarea SGBD. Astfel
se foloseste terminologia de aplicatie multistrat.
Materializarea acestor idei (Object Relational Mapping - ORM) se afla n
interfata de programare (API) Java Persistence API (JPA);
Exista mai multe implementari JPA.
interfata de programare (API) Java Data Object (JDO);
produsul Hibernate.
Hibernate contine si o implementare JPA.
apache-empire
ebean

399

H.3. S
ABLONUL DE UTILIZARE A UNEI BAZE DE DATE

Scopul urmarit este realizarea trecerii de la un SGBD la altul prin modificari


minime n stratul intermediar.
In cele ce urmeaza vom face abstractie de modelele mentionate anterior si
vom trata n modul cel mai simplu realizarea unei aplicatii care interactioneaza
cu o baza de date gestionata de un SGBD.
Pentru a avea acces la o baza de date trebuie stabilita o conexiune la acea
baza de date. In acest sens este necesar cunoasterea:
driver-ului de acces la sistemul de gestiune a bazei de date (SGBD)
Tip SGBD
access
mysql

Driver
sun.jdbc.odbc.JdbcOdbcDriver
com.mysql.jdbc.Driver

derby
javadb
postgresql
hypeqsql
H2
oraclexe

org.apache.derby.jdbc.ClientDriver
org.postgresql.Driver
org.hsqldb.jdbcDriver
org.h2.Driver
oracle.jdbc.driver.OracleDriver

Fisierul driver-ului
mysql-connector-java-*.*.*-bin.jar
(www.mysql.com)
derbyclient.jar
(distributia derby)
postgresql-*.*-*.jdbc4.jar
hsqldb.jar
h2-*.jar
ojdbc14.jar

Daca ntr-un servlet se realizeaza o conexiune la o baza de date atunci


fisierul driver-ului trebuie copiat n catalogul lib al aplicatiei.
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
H2
jdbc:h2:tcp://host/numeBazaDate
oracle
jdbc:oracle:thin:@host:1521:XE
Sablonul de prelucrare este
String URLBazaDate = . . .
String jdbcDriver = . . .
Connection con=null;
try{
Class.forName(jdbcDriver).newInstance();

400

ANEXA H. UTILIZAREA SGBD IN JAVA

con=DriverManager.getConnection(URLBazaDate);
...
}
catch(ClassNotFoundException e){. . .}
catch(SQLException e){. . .}
Anumite SGBD asigura accesul la o baza de date daca sunt fixati parametrii
username si password. In acest caz se programeaza
con=DriverManager.getConnection(URLBazaDate,username,password);
Odata conexiunea cu baza de date stabilita se genereaza un obiect de tip
Statement prin intermediul caruia se executa interogarea SQL.
Statement instructiune=con.createStatement();
String sql=. . . //fraza select;
Rezultatele interogarii bazei de date se obtine prin
try{
ResultSet rs=instructiune.executeQuery(sql);
while(rs.next()){
prelucrarea rezultatului
}
}
catch(SQLException e){...}
Exemplul H.3.1
O interogare simpla a bazei de date AgendaEMail se realizeaza cu programul
1
2
3
4
5
6
8
9
10
11
12
14
15
16

import
import
import
import
import
import

java .
java .
java .
java .
java .
java .

s q l . Connection ;
s q l . DriverManager ;
sql . ResultSet ;
s q l . Statement ;
u t i l . Scanner ;
u t i l . InputMismatchException ;

public c l a s s AgendaE{
private s t a t i c S t r i n g jdbcURLDerby =
j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ;
private s t a t i c S t r i n g j d b c D r i v e r D e r b y =
o r g . apache . derby . j d b c . C l i e n t D r i v e r ;
private s t a t i c S t r i n g jdbcURLMysql =
j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ;
private s t a t i c S t r i n g j d b c D r i v e r M y s q l =

H.3. S
ABLONUL DE UTILIZARE A UNEI BAZE DE DATE

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
59
60
62
63
64
65
66
68
69
70
71
72
73
74
75

com . mysql . j d b c . D r i v e r ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g dbms=null , username=null , password=null , jdbcURL=n u l l ;
switch ( a r g s . l e n g t h ) {
case 0 :
System . out . p r i n t l n ( At l e a s t one argument r e q u i r e d ) ;
System . out . p r i n t l n ( DBMS username password ) ;
System . out . p r i n t l n ( DBMS derby , mysql ) ;
System . e x i t ( 0 ) ;
break ;
case 1 :
dbms=a r g s [ 0 ] ;
break ;
case 2 :
dbms=a r g s [ 0 ] ;
username=a r g s [ 1 ] ;
password= ;
break ;
default :
dbms=a r g s [ 0 ] ;
username=a r g s [ 1 ] ;
password=a r g s [ 2 ] ;
}
C o n n e c t i o n conn = n u l l ;
try {
switch ( dbms ) {
case derby :
C l a s s . forName ( j d b c D r i v e r D e r b y ) . n e w I n s t a n c e ( ) ;
jdbcURL=jdbcURLDerby ;
break ;
case mysql :
C l a s s . forName ( j d b c D r i v e r M y s q l ) . n e w I n s t a n c e ( ) ;
jdbcURL=jdbcURLMysql ;
break ;
default :
System . out . p r i n t l n ( Unknown DBMS . . . ) ;
System . e x i t ( 0 ) ;
}
System . out . p r i n t l n ( jdbcURL=+jdbcURL ) ;
i f ( password==n u l l )
conn = DriverManager . g e t C o n n e c t i o n ( jdbcURL ) ;
else
conn=DriverManager . g e t C o n n e c t i o n ( jdbcURL , username , password ) ;
Statement i n s t r u c t i u n e=conn . c r e a t e S t a t e m e n t ( ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
i n t p r e l , no ;
S t r i n g ch=Y , nume= , e m a i l= , s q l= ;
R e s u l t S e t r s=n u l l ;
while ( ch . s t a r t s W i t h ( Y ) ) {
do{
System . out . p r i n t l n ( Continue ? (Y/N) ) ;
ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
}
while ( ( ! ch . s t a r t s W i t h ( Y ))&&(! ch . s t a r t s W i t h ( N ) ) ) ;
i f ( ch . s t a r t s W i t h ( Y ) ) {
System . out . p r i n t l n ( Natura i n t e r o g a r i i ? ) ;

401

402

ANEXA H. UTILIZAREA SGBD IN JAVA

System . out . p r i n t l n ( ( Dupa nume : 1 , Dupa e m a i l : 2 ) ) ;


do{
p r e l =0;
try {
p r e l=s c a n n e r . n e x t I n t ( ) ;
}
catch ( InputMismatchException e ) { }
}
while ( ( p r e l <1)&&( p r e l > 2 ) ) ;
switch ( p r e l ) {
case 1 :
System . out . p r i n t l n ( Numele ) ;
nume= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ;
s q l= s e l e c t from a d r e s e where nume=+nume ;
r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ;
break ;
case 2 :
System . out . p r i n t l n ( Email ) ;
e m a i l= \ +s c a n n e r . n e x t ( ) . t r i m ()+ \ ;
s q l= s e l e c t from a d r e s e where e m a i l=+e m a i l ;
r s=i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ;
break ;
default : System . out . p r i n t l n ( Comanda e r o n a t a ) ;
}
i f ( r s != n u l l ) {
System . out . p r i n t l n ( R e s u l t s : ) ;
while ( r s . n e x t ( ) ) {
System . out . p r i n t l n ( i d= + r s . g e t I n t ( i d ) ) ;
System . out . p r i n t l n ( nume= + r s . g e t S t r i n g ( nume ) ) ;
System . out . p r i n t l n ( e m a i l= + r s . g e t S t r i n g ( e m a i l ) ) ;
System . out . p r i n t l n ( ) ;
}
}
else {
System . out . p r i n t l n ( No item found ! ) ;
}

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

112

113

}
catch ( E x c e p t i o n e ) {
// h a n d l e t h e e x c e p t i o n
e . printStackTrace ( ) ;
}

114
115
116
117
118

119
120

Fraza select si interogarea se mai putea programa prin


String sql="select * from adrese where nume =?";
PreparedStatement prepStmt=con.prepareStatement(sql);
prepStmt.setString(1,nume);
RezultSet rs=prepStmt.executeQuery();
. . .
prepStmt.close();

H.3. S
ABLONUL DE UTILIZARE A UNEI BAZE DE DATE

403

In acest caz, valoarea variabilei nume este fara apostroafe.


Compilarea si executia programului necesita declararea n variabila classpath
a fisierelor
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.

404

ANEXA H. UTILIZAREA SGBD IN JAVA

Anexa I
Injectarea dependintelor
Injectarea dependintelor (Dependency Injection - DI ) costa n oferirea spre
utilizare a unor obiecte instantiate de mediul de lucru (server Web, server de
aplicatii, container specializat) de catre o clasa.
Injectarea dependintelor este o tehnica uzuala n JEE, dar poate fi programata si utilizata si nafara unui cadru JEE. Produse informatice ce asigura
aceasta facilitate sunt:
Weld realizat de Jboss - RedHat si utilizat de Glassfish.
Guice realizat de Google.

I.1

Weld

Exemplificam pe aplicatia simpla de calcul a celui mai mare divizor comun.


Obiectul ce se va injecta este instanta a clasei
1

package cmmdc ;

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

4
5

Aplicatie de sine st
at
atoare
Structura aplicatiei este
catalogul_applicatiei
|--> cmmdc
|
|
Cmmdc.class
|
|
ApelCmmdc.class

405

406

ANEXA I. INJECTAREA DEPENDINT


ELOR

|-->
|
|

META-INF
|
beans.xml
Client.class

Codurile claselor:
Clasa ApelCmmdc
2

package cmmdc ;
import j a v a x . i n j e c t . I n j e c t ;

public c l a s s ApelCmmdc{

@Inject
Cmmdc o b j ;

6
7

public long compute ( long m, long n ) {


return o b j . cmmdc(m, n ) ;
}

9
10
11
12

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

import
import
import
import

java . u t i l . Scanner ;
o r g . j b o s s . weld . e n vi r o nm e n t . s e . Weld ;
o r g . j b o s s . weld . e n vi r o nm e n t . s e . WeldContainer ;
cmmdc . ApelCmmdc ;

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 c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
long m, n , r ;
System . out . p r i n t l n ( m= ) ;
m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
n=s c a n n e r . nextLong ( ) ;
WeldContainer weld = new Weld ( ) . i n i t i a l i z e ( ) ;
ApelCmmdc o b j = weld . i n s t a n c e ( )
. s e l e c t ( ApelCmmdc . c l a s s )
. get ( ) ;
r=o b j . compute (m, n ) ;
System . out . p r i n t l n ( Cmmdc : +r ) ;
}
}

Fisierul beans.xml este


1

<beans></ beans>

Servlet
Structura aplicatiei Web:

I.1. WELD

contextul_Web
|--> WEB-INF
|
|--> classes
|
|
|
Cmmdc.class
|
|
CmmdcWebServlet.class
|
|--> lib
|
|
|
weld-servlet.jar
|
|
web.xml
|
|
beans.xml
|
index.html

Servletul are codul

10

import
import
import
import
import
import
import
import
import
import

12

@WebServlet ( u r l P a t t e r n s = /cmmdc )

14

public c l a s s CmmdcWeldServlet extends H t t p S e r v l e t {


@Inject
private Cmmdc o b j ;

1
2
3
4
5
6
7
8
9

15
16

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 ) ;
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 Lon g ( sm ) , n=Long . par se Lon g ( sn ) ;
long x=o b j . 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 ( </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 ( ) ;
}

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

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

42
43
44
45
46

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

407

408

ANEXA I. INJECTAREA DEPENDINT


ELOR

iar fisierele de configurare sunt


web.xml
1
2
3
4
5
6
7
9
10
11
12
13
14
15

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp 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
xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e
xmlns:web= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd
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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 3 0 . xsd
i d=WebApp ID version= 3 . 0 >
<d i s p l a y name>CDI Web A p p l i c a t i o n</ d i s p l a y name>
< l i s t e n e r>
< l i s t e n e r c l a s s>
o r g . j b o s s . weld . e n vi r o nm e n t . s e r v l e t . L i s t e n e r
</ l i s t e n e r c l a s s>
</ l i s t e n e r>
</webapp>

beans.xml
1
2
3
4
5
6

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<beans 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
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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e / b e a n s 1 0 . xsd >
</ beans>

Partea IV
TEME DE LABORATOR

409

Anexa J
Teme de aplicatii
J.1

Probleme propuse

1. Sa se realizeze conversia temperaturii exprimata n grade Celsius n grade


Fahrenheit si invers. Formula de transformare este
tF = 1.8tC + 32o F
2. Sa se realizeze conversia a unei sume de bani ntre USD, EURO si RON.
Rata zilnica de schimb preia dinamic sub forma unui fisier xml, apeland
http://www.bnr.ro/nbrfxrates.xml.
3. Sa se realizeze conversia unui numar natural, din cifre arabe n cifre
romane si invers.
Pentru numere x (3999, 3999999], x = a 1000 + b se va folosi scrierea
sub forma (A)B, unde A, B reprezinta conversiile lui a, respectiv b.
Exemplu: Conversia numarului 2289463 este (MMCCLXXXIX)CDLXIII.
Pentru numere x (4000000, 3999999999], x = a1000000+b1000+c se
va folosi scrierea sub forma [A](B)C, unde A, B, C reprezinta conversiile
lui a, b, c.
4. Sa se realizeze conversia unui numar dintr-o baza n alta.
5. Un server aduna la un numar (initializat cu 0) o valoare trimisa de
un client returnand rezultatul. Exista o singura instanta a numarului,
acelasi pentru orice client.
Sa se programeze serviciul descris mai sus.
411

412

ANEXA J. TEME DE APLICAT


II

6. Sa se determine zodia (chinezeasca) corespunzatoare unei date calendaristice. Obs. Inceputul anului nou chinezesc nu coincide cu nceputul
anului nou calendaristic.
(a) Varianta 1
Se va crea baza de date AN CHINEZESC alcatuita din tabelul
INCEPUT
AN
LUNA
ZI
(b) Varianta 2
Datele dintr-un fisier text se introduc ntr-o colectie Java. Rezolvarea cererii unui client se face utilizand facilitatile de programare oferite de interfata java.util.Collection din jdk.

formata din tabelul


7. Se considera baza de date UNITAT
I DE MASUR
A
CONVERSIE
UM SI
UM SIMBOL
DENUMIRE (ROM)
VAL
Exemplu:
1
2
3
4

M
INCH
T
ol
M
FEET (FT) Picior
Uncie (UK)
KG UK ONCE
KG UK POUND Livra (UK)

0.0254
0.3048
0.031103
0.373

Sa se realizeze o aplicatie pentru conversia unitatilor de masura extinzand


continutul bazei de date.
8. Se considera baza de date NORME-DIDACTICE formata din tabelele
CADRU-DIDACTIC
COD-CADRU-DIDACTIC
NUME

MATERIA
COD-MATERIE
DENUMIRE

CURSURI
COD-CURS
COD-CADRU-DIDACTIC
COD-MATERIE

Sa se elaboreze programe de ntretinere si interogare a bazei de date.

J.1. PROBLEME PROPUSE

413

9. Se considera baza de date APROVIZIONARE formata din tabelele


RESURSA
FURNIZOR
CONTRACT
COD-RESURSA COD-FURNIZOR COD-CONTRACT
DENUMIRE
NUME
COD-FURNIZOR
COD-RESURSA
CANTITATE
Sa se elaboreze programe de ntretinere si interogare a bazei de date.
10. Se considera baza de date DESFACERE formata din tabelele
PRODUSE
BENEFICIAR
CONTRACT
COD-PRODUS COD-BENEFICIAR COD-CONTRACT
DENUMIRE
NUME
COD-BENEFICIAR
COD-PRODUS
CANTITATE
Sa se elaboreze programe de ntretinere si interogare a bazei de date.
11. Validarea codului numeric personal.
Codul Numeric Personal (CNP) constituie numarul de ordine atribuit de
Evidenta populatiei unei persoane la nastere, care se nscrie n actele si certificatele de stare civil
a si se preia n celelate acte cu caracter oficial.

Structura unui CMP este


S AA LL ZZ JJ NNN C
| | | | | |
|-> cifra de control
| | | | | |-> numar de ordine atribuit persoanei
| | | | |-> codul judetului
| | | |-> ziua nasterii
| | |-> Luna nasterii
| |-> Anul nasterii
|-> Cifra sexului (M/F)
1/2 nascuti intre 1 ian 1900 s}i 31 dec 1999
3/4 nascuti intre 1 ian 1800 si 31 dec 1899
5/6 nascuti intre 1 ian 2000 si 31 dec 2099
7/8 rezidenti in Romania
9
persoane straine

414

ANEXA J. TEME DE APLICAT


II

Codul judetului (JJ)


Cod
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15

Judet
Alba
Arad
Arges
Bacau
Bihor
Bistrita-Nasaud
Botosani
Brasov
Braila
Buzau
Caras-Severin
Cluj
Constanta
Covasna
Dambovita

Cod
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

Judet
Dolj
Galati
Gorj
Harghita
Hunedoara
Ialomita
Iasi
Ilfov
Maramures
Mehedinti
Mures
Neamt
Olt
Prahova
Satu Mare
Salaj

Cod
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
51
52

Judet
Sibiu
Suceava
Teleorman
Timis
Tulcea
Vaslui
Valcea
Vrancea
Bucuresti
Bucuresti-S1
Bucuresti-S2
Bucuresti-S3
Bucuresti-S4
Bucuresti-S5
Bucuresti-S6
Calarasi
Giurgiu

N N N {001 999} Numerele din acest interval se mpart pe judete,


Birourilor de Evidenta Populatiei, astfel ncat un anumit numa sa nu fie
alocat decat unei persoane nascute n ziua respectiva.
Verificarea cifrei de control: Se foloseste cheia de testare 279146358279.
Primele 12 cifre ale CNP se nmultesc pe rand de la stanga spre dreapta
cu cifra corespunzatoare a cheii de testare. Cele 12 produse se aduna,
iar suma se mparte la 11. Daca restul mpartirii este mai mic decat 10,
atunci acesta va fi cifra de control. Daca restul mpartirii este 10 atunci
cifra de control este 1.
Sa se elaboreze un program pentru verificarea CNP punand n evidenta
toate elementele.
12. Informatiile unui aeroport civil privind decolarile(plecari) si aterizari(sosiri)
pe parcursul unei perioade sunt cuprinse n tabelul activitate al bazei de
date aeroport

415

J.1. PROBLEME PROPUSE

ACTIVITATE
ID
FEL
aterizare/decolare
ZI
TIMP
ora/minut
COMPANIE
OBSERVATIE de la/spre
Sa se realizeze o aplicatie de furnizare a datelor catre clienti (interogarea
bazei de date).
13. Se dau n tipuri de monede Mx1 , Mx2 , . . . , Mxn , xi reprezentand valoarea
monedei, i = 1, 2, . . . , n. Sa se determine variantele de plata a unei sume
S cu un numar minim de monede din cele disponibile.
Se vor trata cazurile:
(a) Numarul monedelor de fiecare tip este nelimitat.
(b) Numarul monedelor disponibile este marginit, respectiv de numerele
k1 , k2 , . . . , kn (k1 x1 + . . . + kn xn S).
14. Globul pamantesc este mpartit n 24 de fuse orare de cate 15o (24 15 =
360) pornind de la meridianul 0 spre stanga si dreapta.
Dandu-se longitudinile a 2 puncte de pe glob sa se calculeze diferenta
de fus orar.
Fixand ora n primul punct sa se indice ora n al doilea punct.
15. Sa se calculeze unghiurile unui triunghi dat prin coordonatele varfurilor.
16. Fixand coeficientii a, b, c, d, e, f ale conicei
ax2 + 2bxy + cy 2 + 2dx + 2ey + f = 0
sa se reduca conica la forma canonica.
17. Sa se calculeze suma multiplilor de 3 sau 5 mai mici decat un numar dat
n.
18. Fie p N fixat si n N, 0 n 2p 1 cu reprezentarea binara
n = ap1 ap2 . . . a1 a0 2 . Sa se determine numarul m care are reprezentarea
binara m = a0 a1 . . . ap2 ap1 2 .
De exemplu, pentru p = 6, n = 17 = 0100012 numarul cautat este m =
1000102 = 34.

416

ANEXA J. TEME DE APLICAT


II

19. Sa se determine numarul de aparitii al fiecarui cuvant dintr-un text dat.


20. Sa se calculeze Bn (Numerele lui Bernoulli) definit prin

Bn =

daca n = 0

Pn1
k=0

n+1
k

Bk

n+1

daca n > 0

Calculele se fac n Q.
21. Problema generalilor bizantini.1 Sunt n generali dintre care unul
este comandant si ceilalti locotenenti. Generalii pot fi loiali sau tradatori.
Numarul generalilor tradatori este m. Comandantul (loial sau tradator)
lanseaza o comanda (atac sau retragere). Toti locotenentii loiali urmeaza
ordinele comandantului si ei trebuie sa ajunga la aceasi concluzie privind
actiunea de urmat.
Algoritmul: Dupa ce un locotenent primeste ordinul comandantului el
retransmite ordinul primit tuturor celorlalti locotenenti. Comanda majoritara este cea care va fi urmata.
Ipoteze: Transmisia mesajelor este sigura. Mesajele nu pot fi interceptate
si modificate. Un tradator nu poate trimite decat un singur mesaj si este
obligat sa urmeze algoritmul.
Se arata ca
Daca n = 3m atunci problema n-are solutie.
Daca n 3m + 1 atunci problema are solutie.
Sa se simuleze problema generalilor bizantini printr-o aplicatie distribuita
utilizand tehnologia soclurilor.
22. Problema 3x + 1. Fie sirul de numere naturale (an )nN definit prin
formula de recurenta

3an + 1 daca an impar
an+1 =
an
daca an par
2
Pentru orice a0 exista n N astfel ncat an = 1.
1

Aplicatia distribuit
a nu este de tip client - server.

417

J.1. PROBLEME PROPUSE

Numim pas trecerea de la un termen impar la urmatorul termen impar


(an si an+p determina un pas daca sunt numere impare si an+1 , . . . , an+p1
sunt numere pare).
Pentru un a0 dat sa se determine numarul de pasi pana la atingerea lui
1.
Exemplu. Pentru a0 = 7 sirul este
7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
iar numarul de pasi este 5.
23. Se definesc tablourile (Tnd ) si (Pnd ) pentru n N , d N prin formulele
de recurenta:
P1d = 1, d N
d
Pn+1
= Tnd , d N, n N
Tnd

d
X

Pnj

d N, n N

j=0

Sa se calculeze Tnd .
Exemplu.

Pnd

n
= 1
2
3

0
1
1
1

1
1
2
3

d
2 3 4
1 1 1
3 4 5
6 10 15

Tnd

n
= 1
2
3

0
1
1
1

1
2
3
4

d
2 3 4
3 4 5
6 10 15
10 20 35

24. Pentru a, b N sa se calculeze u, v Z astfel ncat ua + vb = (a, b).


Indicatie. Se poate utiliza algoritmul lui Euclid pentru calcul celui mai
mare divizor comun a doua numere naturale (Ion D.I., Nita C., 1978,
Elemente de aritmetica cu aplicatii n tehnici de calcul. Ed. Tehnica,
Bucuresti, 103-107).
25. Daca a Zn sa se calculeze, daca exista, a1 .
26. Sa se rezolve ecuatia ax = b n Zn .
Exemplu. In Z8

418

ANEXA J. TEME DE APLICAT


II

(a) 3x = 5

x=7

(b) 4x = 2

(c) 2x = 4

x {2, 6}

Bibliografie
[1] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iasi.

[2] ATHANASIU I., COSTINESCU B., DRAGOI


O.A., POPOVICI F.I.,
1998, Limbajul Java. O perspectiva pragmatica. Ed. Computer Libris
Agora, Cluj-Napoca.
[3] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru
aplicatii Web. Ed. Albastra, Cluj-Napoca.
[4] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicatii. Ed. Albastra, Cluj-Napoca.
[5] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucuresti.
[6] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Iasi.
[7] CARLSON L., 2013, Programming for PaaS. OReilly, Sebastopol CA.
[8] COULOURIS G., DOLLIMORE J., KINDBERG T., Distributed Systems.
Concepts and Design. Addison Wesley, 2005.
I., 2000, Programarea retelelor de calculatoare. Ed. de Vest,
[9] JURCA
Timisoara.
[10] LET
IA S.T., 2002, Programare avansata n Java. Ed. Albastra, ClujNapoca.
[11] SCHEIBER E., 2007, Programare concurenta si paralel distribuita n Java.
Ed. Albastra, Cluj-Napoca.
S., ANDREI S., OLARU C., 2011, Java de la 0 la extert. Ed.
[12] TANASA
Polirom, Iasi.
S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosind
[13] TANASA
Java. Ed. Polirom, Iasi.
419

ERNEST SCHEIBER

PROGRAMARE
IN JAVA
DISTRIBUITA
Volumul II

Brasov

Prefat
a
Cursul Programare distribuita n Java 2 este continuarea cursului Programare distribuita n Java 1. Minimal, pentru ntelegerea cursului este nevoie
de cunoasterea capitolelor Servlet si JSP din partea ntai.
Tematica cursului cuprinde:
Cadre de dezvoltare (framework) a aplicatiilor Web:
Struts2
Java Server Faces
Spring
Google Web Toolkit
Servicii Web cu:
Servicii RPC
JAX-WS (Java API for XML Web Services) prin metro
Servicii REST
JAX-RS (Java API for RESTful Web Services) prin jersey
Modelul OSGi (Open Source Gateway initiative)
Sursele programele din curs sunt disponibile prin git:
https://github.com/e-scheiber/DistributedProgramming2.git

Cuprins
I

APLICAT
II WEB - CADRE DE LUCRU

1 Aplicatii Web
1.1 Modelul MVC . . . . . . . . . . . . . . . . . . .
1.2 Struts 2 . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Aplicatii Struts2 prin modelul descriptiv
1.2.2 Marcaje Struts . . . . . . . . . . . . . .
1.2.3 Aplicatii Struts2 . . . . . . . . . . . . .
1.2.4 Interceptori . . . . . . . . . . . . . . . .
1.2.5 Aplicatii Struts2 prin modelul programat
1.2.6 Struts 2 prin maven . . . . . . . . . . .
1.3 Java Server Faces . . . . . . . . . . . . . . . . .
1.3.1 Structura unei aplicatii JSF . . . . . . .
1.3.2 Marcaje JSF . . . . . . . . . . . . . . . .
1.3.3 Aplicatii JSF cu pagini Facelets . . . . .
1.3.4 Aplicatii JSF cu pagini JSP . . . . . . .
1.3.5 Componente grafice Primefaces . . . . .
1.3.6 JSF dezvoltat prin maven . . . . . . . .

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

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

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

11
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

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

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

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

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

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

13
13
16
16
18
20
32
39
44
47
47
50
52
59
70
76

2 Spring
79
2.1 Aplicatie Spring elementara . . . . . . . . . . . . . . . . . . . . 79
2.2 Dezvoltarea unei aplicatii MVC Spring . . . . . . . . . . . . . . 82
3 Asynchronous JavaScript And Xml AJAX
3.1 AJAX Java . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Google Web Toolkit (GWT) . . . . . . . . . . . . . . . .
3.2.1 Dezvoltarea unei aplicatii GWT prin ant . . . . .
3.2.2 Aplicatie GWT fara apel de procedura la distanta
3.2.3 Aplicatie GWT cu apel de procedura la distanta .
3.2.4 Crearea unui widget client . . . . . . . . . . . . .
5

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

101
101
112
112
114
120
137

CUPRINS

3.2.5
3.2.6
3.2.7

II

Incarcarea unui fisier - GWT Upload . . . . . . . . . . . 141


Dezvoltarea unei aplicatii GWT prin maven . . . . . . . 144
GWT prin Google AppEngine . . . . . . . . . . . . . . . 144

SERVICII WEB

147

4 Servicii JAX-WS
4.1 Descrierea unui serviciu . . . . . . . . . . . . . . . . . . . .
4.1.1 XML Schema . . . . . . . . . . . . . . . . . . . . .
4.1.2 WSDL . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.3 Mesaje SOAP . . . . . . . . . . . . . . . . . . . . .
4.2 Modelul JAX-WS prin Metro . . . . . . . . . . . . . . . .
4.2.1 Serviciu Web ca servlet n apache-tomcat prin ant .
4.2.2 Componenta EJB sesiune stateless ca serviciu Web
4.2.3 Servicii jaxws dezvoltate prin maven . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

149
. 150
. 151
. 154
. 161
. 166
. 166
. 174
. 176

5 Servicii JAX-RS
5.1 Representational State Transfer . .
5.2 Jersey-2 . . . . . . . . . . . . . . .
5.2.1 Generarea resurselor . . . .
5.2.2 Preluarea parametrilor . . .
5.2.3 Date prin componenta Java
5.2.4 Aplicatie cu server asincron
5.2.5 Jersey n glassfish . . . . . .
5.2.6 Dezvoltare prin maven . . .
5.3 Serviciu Restful (jersey) n Heroku
5.4 MVC prin servicii RESTful . . . .
5.5 Serviciu Restful cu GWT . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

III

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

MODELUL OSGi

6 Modelul OSGi
6.1 Cadre de lucru OSGi . . . . . . . . . . . . . . . . . . .
6.2 Programare imperativa - Crearea unui modul OSGi . .
6.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4 Dezvoltare OSGi prin apache-maven . . . . . . . . . .
6.5 Programare declarativa . . . . . . . . . . . . . . . . . .
6.5.1 Programare declarativa prin Declarative Service

179
179
180
180
191
200
205
207
210
212
215
220

227
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

229
230
233
235
238
242
243

CUPRINS

6.6
6.7

6.5.2 Programare declarativa


6.5.3 Programare declarativa
Serviciul OSGi de jurnalizare
Apache-karaf . . . . . . . . .

prin Blueprint . . .
prin apache-iPOJO
. . . . . . . . . . . .
. . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

246
248
250
252

7 OSGi distribuit
255
7.1 Medii OSGi pentru aplicatii distribuite . . . . . . . . . . . . . . 255
7.2 Servlet ca modul OSGi . . . . . . . . . . . . . . . . . . . . . . . 256

IV

JAVA MANAGEMENT EXTENSIONS

8 Java Management Extensions


8.1 Standard MBean . . . . . . . . . . .
8.1.1 Crearea unui Standard MBean
8.1.2 Crearea unui MBeanServer . .
8.1.3 Notificari . . . . . . . . . . .
8.1.4 Agent MBean . . . . . . . . .
8.1.5 Invocarea la distanta . . . . .
Bibliografie

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

261
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

263
. 264
. 264
. 266
. 270
. 273
. 274
289

CUPRINS

Produsele informatice utilizate


Pe durata existentei, produsele informatice evolueaza prin versiunile pe care
producatorii ni le pun la dispozitie. Nu de putine ori o versiune noua nu este
compatibila cu versiunea anterioara, fapt care necesita adaptarea programelor
client.
Lista urmatoare precizeaza versiunile produselor utilizate n lucrare, indicate n majoritatea cazurilor prin resursa de instalare. Lista contine doar
produsele care completeaza pe cele utilizate n Programare distribuita 1.

No.
1
2
3
4
5
6
7
8
9
10
11

Versiunile produselor informatice utilizate n lucrare


Produsul informatic
Resursa/versiunea
apache-karaf
apache-karaf-4.0.4.zip
equinox (OSGi)
org.eclipse.osgi 3.10.1.v20140909-1633.jar
Equinox Bridge Servlet
bridge.war
felix
org.apache.felix.main.distribution-5.4.0.tar.gz
Google Web Toolkit
gwt-2.7.0.zip
jersey
jaxrs-ri-2.22.2.zip
Java Server Faces (JSF)
javax.faces-2.2.12.jar
knopflerfish
knopflerfish osgi sdk 5.2.0.jar
metro
metro-standalone-2.3.1.zip
spring
spring-modul -4.2.6.jar
struts
struts2-2.3.28-all.zip

10

CUPRINS

Partea I
APLICAT
II WEB
CADRE DE LUCRU

11

Capitolul 1
Aplicatii Web
Printre aplicatiile distribuite de tip client server, n care comunicatiile se
bazeaza pe protocolul http, se disting
Aplicatii Web (site): Cererea adresata serverului este lansata de o persoana prin intermediul unui site, utilizand un program navigator: Mozilla
Firefox, Google Chrome, Microsoft InternetExplorer, Opera, Apple Safari, etc.
Servicii Web: Cererea catre server se face de un program. Aplicatia
server si client se programeaza utilizand interfete de programare specifice.
Sunt cunoscute multe cadre de dezvoltare (framework) a aplicatiilor Web
gratuite (http://java-source.net/open-source/web-frameworks).
Cadrele de lucru pentru aplicatii Web asigura:
separarea preocuparilor prin modelul ModelViewController (MVC);
simplificarea gestiunii legaturilor dintre componentele unei aplicatii prin
fisiere de configurare sau metode alternative;
oferirea unor facilitati de programare (de exemplu, completarea prin program a unor casete de selectie, ncarcarea unui fisier, validarea datelor).

1.1

Modelul MVC

Modelul MVC este o schema de proiectare a aplicatiilor client-server. Modelul MVC este alcatuita din trei parti:
13

14

CAPITOLUL 1. APLICAT
II WEB

Componenta Model se refera n principal la datele de intrare si iesire care


determina problema dar contine de obicei si clasele ce rezolva cererile
clientilor asigurand functionalitatea aplicatiei (business classes).
Componenta View asigura interfata grafica a clientului.
Componenta Controller realizeaza comunicarea / legatura ntre clasele
si / sau resursele din View cu clasele din Model.
Bazate pe folosirea tehnologiei servlet-urilor si a JSP, materializarea modelului MVC este bine reprezentata de cadrele de dezvoltare (framework) pentru
aplicatii Web:
Struts
Java Server Faces (JSF)
Google Web Toolkit (GWT)
care sunt prezentate n continuare.
In fiecare caz, gestiunea activitatilor se face de catre cadrul de lucru, deci
are loc inversarea controlului.
In legatura cu MVC sunt modelele Model-View-ViewModel - MVVM si
Model-View-Presenter - MVP.
Diferenta dintre modelul MVP si MVVM consta n faptul ca n modelul
MVP interactiunile sunt executate programat iar n modelul MVVM acestea
sunt realizate automat prin mecanismul de mapare/legare a datelor 1 .
Diferenta fata de MVC este pus n evidenta n Fig. 1.1.
In Java modelul MVVM este exemplificat de produsul Dukescript - knockout.js.

http://joel.inpointform.net/software-development/
mvvm-vs-mvp-vs-mvc-the-differences-explained/.

1.1. MODELUL MVC

Figure 1.1: Comparatia dintre MVC si MVP

15

16

CAPITOLUL 1. APLICAT
II WEB

1.2

Struts 2

Struts2 este un cadru de dezvoltare (framework) a aplicatiilor bazat pe


modelul MVC dezvoltat n cadrul proiectului apache.
Struts2 utilizeaza atat modelul descriptiv de aplicatie, prin intermediul
unui fisier xml, de configurare, struts.xml, cat si modul programat prin
adnotari.
Instalarea produsului. Fisierul struts2-blank-2.*.*.war obtinut din dezarhivarea fisierului descarcat de la www.apache.org ofera un cadru minimal
pentru dezvoltarea unei aplicatii. Acest fisier se copiaza n catalogul TOMCAT
HOME\webapps si n urma (re)pornirii serverului tomcat, fisierul este dezarhivat.
Alternativ, este suficient ca fisierele jar din catalogul
struts2-blank-2.*.*\WEB-INF\lib
sa fie copiate n catalogul lib al aplicatiei Web.

1.2.1

Aplicatii Struts2 prin modelul descriptiv

Modelul descriptiv este caracterizat print-un fisier de configurare struts.xml.


Componentele unei aplicatii Struts2 sunt:
Componenta View este alcatuita din documente html sau pagini JSP,
continand formulare prin care clientul introduce date si prin care se
afiseaza rezultatele.
Apelarea din exteriorul aplicatiei Struts2 se face prin
http://host:port/context/NumeActiune.action
iar din interiorul aplicatiei prin NumeActiune.action.
Componenta Model este alcatuita dintr-o clasa ce extinde clasa
com.opensymphony.xwork2.ActionSupport
care implementeaza interfata Action. Aceasta interfata declara metoda
public String execute() throws Exception

1.2. STRUTS 2

17

Programatorul ori suprascrie aceasta metoda ori indica metoda care


ndeplineste activitatile necesare satisfacerii cererii. Aceasta metoda
se declara prin atributul method a elementului action din componenta
Controller struts.xml.
In ambele cazuri se returneaza un String fixat de clasa ResultNames:
SUCCESS, ERROR, INPUT, LOGIN, NONE.
Parametrilor preluati dintr-un formular li se asociaza n componenta Java
campuri private. Pentru fiecare asemenea camp se definesc metodele set
si / sau get.
Fiecare clasa trebuie sa faca parte dintr-un pachet.
Componenta Controller este reprezentat de fisierul de configurare struts.xml,
plasat n catalogul WEB-INF\classes al aplicatiei Web. Prin datele
acestui fisier se face asocierea dintre numele actiunii, clasa care implementeaza actiunea si fisierele cu rezultatele prelucrarilor.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="pachet" extends="struts-default">
<action name="NumeActiune"
class="pachet.Clasa"
method="numeMetoda">
<result>/jsp/Rezultat1.jsp</result>
<result name="input">/jsp/Rezultat2.jsp</result>
. . .
</action>
. . .
</package>
</struts>

Totodata, utilizarea lui Struts2 necesita fisierul web.xml


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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp i d=WebApp 9 version= 2 . 4
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 >
<d i s p l a y name>n u m e a p l i c a t i e</ d i s p l a y name>
< f i l t e r>
< f i l t e r name>s t r u t s 2</ f i l t e r name>
< f i l t e r c l a s s>
o r g . apache . s t r u t s 2 . d i s p a t c h e r . ng . f i l t e r . S t r u t s P r e p a r e A n d E x e c u t e F i l t e r
</ f i l t e r c l a s s>
</ f i l t e r >

18

17
18
19
20
22
23
24
25

CAPITOLUL 1. APLICAT
II WEB

< f i l t e r mapping>
< f i l t e r name>s t r u t s 2</ 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>
<welcomef i l e l i s t>
<welcome f i l e >i n d e x . html</ welcome f i l e >
</ welcomef i l e l i s t>
</webapp>

Desfasurarea aplicatiei Web este


webapps
|--> catalogul aplicatiei (context)
|--> html
|--> jsp
|--> WEB-INF
|
|--> classes
|
|
|--> pachetul aplicatiei
|
|
|
|
*.class
|
|
|
struts.xml
|
|--> lib
|
|
*.jar
|
|
web.xml
|
index.html

1.2.2

Marcaje Struts

Marcajele Struts sunt definite ntr-o biblioteca care se declara ntr-o pagina
JSP prin
<%@ taglib prefix="s" uri="/struts-tags" %>
Nu este nevoie de specificarea lor n fisierul de configurare web.xml.
Amintim marcajele:
s:form Pentru marcarea formularului.
Atribute ale marcajului:
Atribut Fel
Descriere
action obligatoriu defineste actiunea de executat.

19

1.2. STRUTS 2

s:textfield Declara un camp de introducere date de tip string.


Atribute ale marcajului:
Atribut Fel
Descriere
name
obligatoriu Numele campului.
label
optional
Textul explicativ al informatiei de introdus.
s:password Declara un camp de introducere a parolei.
Atribute ale marcajului:
Atribut Fel
Descriere
name
obligatoriu Numele campului.
label
optional
Textul explicativ al informatiei de introdus.
s:submit Declara un buton de comanda.
Atribute ale marcajului:
Atribut Fel
Descriere
value
optional Textul explicativ al actiunii
s:property Afiseaza valoarea proprietatii (atribut, camp).
Atribute ale marcajului:
Atribut Fel
Descriere
value
obligatoriu Numele proprietatii (al campului)
s:select
Atribute ale marcajului:
Atribut
label
name
list

Fel
optional
optional
obligatoriu

listKey

optional

listValue optional
s:hidden
Atribute ale marcajului:

Descriere
Textul explicativ al controlului grafic
Numele proprietatii
Lista optiunilor sau numele listei
Exemplu: {C2F,F2C}
Valorile cheii. Proprietatea ca avea
valoarea selectata.
Valorile afisate

20

CAPITOLUL 1. APLICAT
II WEB

Atribut Fel
Descriere
name
obligatoriu Numele proprietatii / campului
value
obligatoriu Valoarea transmisa
s:if
Atribute ale marcajului:
Atribut Fel
Descriere
test
obligatoriu Test
s:else
<s:if test="%{incercari > 0}">
Incercari <s:property value="%{incercari+1}"/>
</s:if>
<s:else>
Prima incercare
</s:else>

Marcajele Strut2 folosesc limbajul Object Graph Navigation Language (OGNL)


care
leaga elementele grafice de control de obiecte;
creaza dinamic liste si tabele de proprietati pentru elementele grafice de
control;
ncarca metodele necesare rezolvarii cererii clientului;
Realizeaza conversia datelor din sirul de caractere receptionat n tipurile
Java (String, boolean / Boolean, int / Integer, long / Long, float
/ Float, double / Double, Date, List, Map, array).
La fiecare apelare Struts2 dar naintea executarii solicitarii cerute struts2
creaza un obiect ValueStack care contine Object Stack - stiva obiectelor - si
Context Map cu atributele cererii, ale sesiunii, etc.

1.2.3

Aplicatii Struts2

Exemplificam prin aplicatia simpla de calcul a celui mai mare divizor comun
a doua numere naturale.
Exemplul 1.2.1

1.2. STRUTS 2

21

Aplicatia Struts2 poate contine mai multe actiuni / activitati. Alegerea se


face dintr-o pagina AlegeApp.html, care tine de partea view a aplicatiei Web.
Aceasta pagina html reprezinta punctul de intrare in aplicatie.
Fisierul struts.xml al componentei Controller este
1
2
3
4
5
6
8
9
10
11
13
14
15
17
18

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE s t r u t s PUBLIC
//Apache S o f t w a r e Foundation //DTD S t r u t s C o n f i g u r a t i o n 2 . 0 / /EN
h t t p : // s t r u t s . apache . o r g / d t d s / s t r u t s 2 . 0 . dtd >
< s t r u t s>
<package name=cmmdc e x t e n d s= s t r u t s d e f a u l t >
<a c t i o n name=Cmmdc c l a s s=cmmdc . Cmmdc
method=computeCmmdc>
< r e s u l t>/ j s p /ResultCmmdc . j s p</ r e s u l t>
</ a c t i o n>
<a c t i o n name= >
< r e s u l t>/ html / AlegeApp . html</ r e s u l t>
</ a c t i o n>
</ package>
</ s t r u t s>

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

<html>
<head>
< t i t l e> A l e g e A p p l i c a t i a </ t i t l e>
</head>
<body bgcolor=#a a e e a a >
<h1> A l e g e &#355; i a p l i c a &#355; i a </h1>
<ul>
< l i>
<a href= / my strut s2 app / j s p /Cmmdc . j s p >
C a l c u l u l c e l u i mai mare d i v i z o r comun a dou&#259;
numere n a t u r a l e
</a>
</ l i>
</ ul>
</body
</html>

In cazul de fata este o singura optiune: calculul celui mai mare divizor
comun.
Componenta View a acestei aplicatii este alcatuita din doua fisiere:
Introducerea datelor (Cmmdc.jsp)
1
2
3

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>

22

CAPITOLUL 1. APLICAT
II WEB

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

< t i t l e>C a l c u l u l c e l u i mai mare d i v i z o r comun a dou&#259;


numere n a t u r a l e</ t i t l e>
</head>
<body>
<h3> I n t r o d u c e &#355; i </h3>
<s : form action=Cmmdc . a c t i o n >
<s : t e x t f i e l d l a b e l= Primul numar name=m />
<s : t e x t f i e l d l a b e l= Al d o i l e a numar name=n />
<s : submit value= C a l c u l e a z a />
</ s : form>
</body>
</html>

Afisarea rezultatelor (RezultCmmdc.jsp)


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

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>
< t i t l e >Cmmdc</ t i t l e >
</head>
<body>
<h2>Cmmdc : </h2>
<!
<s : p r o p e r t y v a l u e= message />
>
<s : p r o p e r t y v a l u e=#s e s s i o n . cmmdc/>
</body>
</html>

Componenta Model corespunzatoare actiunii Cmmdc este

package cmmdc ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import j a v a . u t i l . Map ;

public c l a s s Cmmdc extends A c t i o n S u p p o r t {

1
2
3

18

public S t r i n g computeCmmdc ( ) {
long c=cmmdc(m, n ) ;
// v a r i a n t a de t r a n s m i t e r e a r e z u l t a t u l u i p r i n t r un camp
//
// s e t M e s s a g e ( ( new Long ( c ) ) . t o S t r i n g ( ) ) ;
//
// v a r i a n t a de t r a n s m i t e r e a r e z u l t a t u l u i p r i n s e s s i o n
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
a t t r . put ( cmmdc , (new Long ( c ) ) . t o S t r i n g ( ) ) ;
return SUCCESS ;
}

20

public long cmmdc( long m, long n ) { . . . }

22

private long m;
public long getM ( ) {
return m;
}
public void setM ( long m) {
t h i s .m = m;

8
9
10
11
12
13
14
15
16
17

23
24
25
26
27

1.2. STRUTS 2

28

30

private long n ;
public long getN ( ) {
return n ;
}
public void setN ( long n ) {
this . n = n ;
}

31
32
33
34
35
36

/
p r i v a t e S t r i n g message ;
p u b l i c v o i d s e t M e s s a g e ( S t r i n g message ) {
t h i s . message = message ;
}
p u b l i c S t r i n g getMessage () {
r e t u r n message ;
}
/

38
39
40
41
42
43
44
45
46
47

23

Apelarea aplicatiei se face prin index.html


1
2
3
4
5
6
7
8
9

<html>
<head>
<META HTTPEQUIV= R e f r e s h
CONTENT= 0 ;URL=h t t p : / / l o c a l h o s t : 8 0 8 0 / m ystru ts2 app / html / AlegeApp . html >
</head>
<body>
<p>A p e l a r e a a p l i c a t i e i . . . </p>
</body>
</html>

Accesul la un obiect session se poate obtine prin


Map attr=ActionContext.getContext().getSession();
attr.put(key,object);
Aici attr este un identificator definit de programator.
In componenta view referinta la sesiune se poate face prin sintaxa
#sesssion.key sau #attr.key.
Validarea de baz
a. Clasa ActionSupport implementeaza interfata
com.opensymphony.xworks2.Validateable
cu metoda public void validate(), care permite realizarea de verificari
asupra datelor ncarcate.
Metoda void addFieldError(String numeCamp, String mesaj ) afiseaza
mesajul pe iesirea ResultName.INPUT.
In cazul clasei Cmmdc.java completarea pentru verificarea campurilor formularului este

24

CAPITOLUL 1. APLICAT
II WEB

public void validate(){


if(m==0){
addFieldError("m","Camp necompletat");
}
if(n==0){
addFieldError("n","Camp necompletat");
}
}

Verificarea caracterului numeric al datelor convertite de Struts n tipuri numerice este facuta de OGNL.
O facilitate interesanta oferita de Struts este completarea automata a unei
liste de optiuni (select).
Exemplul 1.2.2 Un fisier text contine informatiile {nume judet, capitala judetului,
abrevierea}, separate printr-un spatiu. Se cere construirea unei aplicatii Web
care pentru un judet indicat, afiseaza informatiile corespunzatoare din fisierul
mentionat.
Aplicatia este alcatuita din doua actiuni:
1. Completarea listei de optiuni n cadrul formularului. Aceasta actiune
este lansata la apelarea aplicatei dintr-o pagina html, de exemplu
<a href="http://localhost:8080/mystruts2-app/AlegeJudetul.action">
Referinte despre judete
</a>

Componenta Control :
<action name="AlegeJudetul" class="appjud.ListaJudeteAction">
<result>/jsp/AppJud.jsp</result>
</action>

Pagina JSP de iesie, AppJud.jsp, este pagina pe care o utilizeaza


clientul pentru selectarea judetului. Aceasta pagina reprezinta componenta View - de apelare a actiunii urmatoare.
Componenta Model este data de clasa ListaJudeteAction.java
1
2
3
4
5
6
7
8
9
10
11

package appjud ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import j a v a . u t i l . Map ;
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 j a v a . u t i l . HashMap ;
import j a v a . i o . InputStream ;
import j a v a . i o . InputStreamReader ;
import j a v a . i o . B u f f e r e d R e a d e r ;
import j a v a . i o . IOException ;

25

1.2. STRUTS 2

13
14
15

public c l a s s L i s t a J u d e t e A c t i o n extends A c t i o n S u p p o r t {
private HashMap<S t r i n g , RefJudet> r e f J u d e t e=
new HashMap<S t r i n g , RefJudet > ( ) ;
public L i s t <RefJudet> g e t J u d e t e L i s t ( ) {
L i s t <RefJudet> l i s t =new A r r a y L i s t ( 5 0 ) ;
try (
InputStream f i s =
this . g e t C l a s s ( ) . getResourceAsStream ( j u d e t e . txt ) ;
InputStreamReader i s r =new InputStreamReader ( f 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 ) ; ) {
S t r i n g s= , jud , c a p i t , a b r e v ;
do{
s=br . r e a d L i n e ( ) ;
i f ( s != n u l l ) {
S t r i n g [ ] s t=s . s p l i t ( ) ;
j u d=s t [ 0 ] ;
c a p i t=s t [ 1 ] ;
a b r e v=s t [ 2 ] ;
R e f J u d e t bean=new R e f J u d e t ( ) ;
bean . s e t J u d ( j u d ) ;
bean . s e t C a p i t ( c a p i t ) ;
bean . s e t A b r e v ( a b r e v ) ;
l i s t . add ( bean ) ;
r e f J u d e t e . put ( jud , bean ) ;
}
}
while ( s != n u l l ) ;
}
catch ( IOException e ) {
e . printStackTrace ( ) ;
}
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
a t t r . put ( r e f J u d e t e , r e f J u d e t e ) ;
return l i s t ;
}

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

unde RefJudet.java are codul


1
2
3
4
5

package appjud ;
public c l a s s R e f J u d e t implements j a v a . i o . S e r i a l i z a b l e {
private S t r i n g j u d ;
private S t r i n g c a p i t ;
private S t r i n g a b r e v ;

public R e f J u d e t ( ) { }

public void s e t J u d ( S t r i n g j u d ) {
t h i s . j u d=j u d ;
}
public S t r i n g getJud ( ) {
return j u d ;
}

10
11
12
13
14
16
17
18
19

public void s e t C a p i t ( S t r i n g c a p i t ) {
t h i s . c a p i t=c a p i t ;
}
public S t r i n g g e t C a p i t ( ) {

26

CAPITOLUL 1. APLICAT
II WEB

return c a p i t ;

20
21

23

public void s e t A b r e v ( S t r i n g a b r e v ) {
t h i s . a b r e v=a b r e v ;
}
public S t r i n g getAbrev ( ) {
return a b r e v ;
}

24
25
26
27
28
29

Clasa ListaJudeteAction genereaza:


lista judeteList prin metoda getJudeteList care va fi utilizata
de Struts pentru completarea unei liste de optiuni din formularul aplicatiei. Lista este alcatuita din componente Java de tip
RefJudet.
un obiect de tip HashMap<String,RefJudet> care este retinut
de obiectul sesiune al aplicatiei. Acest obiect contine datele
fisierului text si este utilizat la satisfacerea cererii clientului.
2. Rezolvarea cererii clientului - adica oferirea datelor cerute pe baza selectiei
indicate.
Componenta Controller :
<action name="RefJudet" class="appjud.JudBean">
<result>/jsp/ResultJud.jsp</result>
</action>

Componenta View (AppJud.jsp) este


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

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>
< t i t l e>R e f e r i n t e Judet</ t i t l e>
</head>
<body>
<h1> R e f e r i n t e d e s p r e j u d e t e </h1>
<p/>
<s : form
action= R e f J u d e t . a c t i o n >
<s : s e l e c t name= s e l e c t a t l a b e l= J u d e t e
l i s t = j u d e t e L i s t l i s t K e y=%{j u d } l i s t V a l u e=%{j u d } />
<s : submit />
</ s : form>
</body>
</html>

Campul selectat va contine numele judetului ales. Lista judeteList


este alcatuita din componente RefJudet iar %{jud} se refera ca
campul jud al unei asemenea componente.

27

1.2. STRUTS 2

Componenta View (ResultJud.jsp) de afisare a rezultatelor


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

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>
< t i t l e>R e f e r i t e Judet</ t i t l e>
</head>
<body>
<h2> R e f e r i n t e l e d e s p r e j u d e t u l </h2>
<s : p r o p e r t y value= j u d />
<p/>
Capitala :
<s : p r o p e r t y value= c a p i t />
<p/>
Abrevierea :
<s : p r o p e r t y value= a b r e v />
</body>
</html>

Componenta Model () pentru satisfacerea cererii clientului este data


din
1
2
3
4
5
7
8
9
10
11

package appjud ;
import j a v a . u t i l . Map ;
import j a v a . u t i l . HashMap ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
public c l a s s JudBean extends A c t i o n S u p p o r t {
private S t r i n g j u d=n u l l ;
private S t r i n g c a p i t=n u l l ;
private S t r i n g a b r e v=n u l l ;
private S t r i n g s e l e c t a t ;

13

public JudBean ( ) { }

15

public S t r i n g e x e c u t e ( ) throws E x c e p t i o n {
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
HashMap<S t r i n g , RefJudet> r e f J u d e t e=
( HashMap<S t r i n g , RefJudet >) a t t r . g e t ( r e f J u d e t e ) ;
R e f J u d e t r j=r e f J u d e t e . g e t ( s e l e c t a t ) ;
j u d=r j . getJud ( ) ;
c a p i t=r j . g e t C a p i t ( ) ;
a b r e v=r j . getAbrev ( ) ;
return SUCCESS ;
}

16
17
18
19
20
21
22
23
24
26
27
28
30
31
32
34
35
36

public S t r i n g getJud ( ) {
return j u d ;
}
public S t r i n g g e t C a p i t ( ) {
return c a p i t ;
}
public S t r i n g getAbrev ( ) {
return a b r e v ;
}

28

CAPITOLUL 1. APLICAT
II WEB

public void s e t S e l e c t a t ( S t r i n g s e l e c t a t ) {
t h i s . s e l e c t a t=s e l e c t a t ;
}
public S t r i n g g e t S e l e c t a t ( ) {
return s e l e c t a t ;
}

38
39
40
41
42
43
44

Cele doua parti sunt legate prin


<action name="AlegeJudetul" class="appjud.ListaJudeteAction">
<result>/jsp/AppJud.jsp</result>
</action>
<action name="RefJudet" class="appjud.JudBean">
<result>/jsp/ResultJud.jsp</result>
</action>

Inc
arcarea unui fisier - Upload
Pentru ncarcarea unui fisier, Strut2 ofera o solutie prefabricata, bazata pe
produsul commons-fileupload de la apache.
Actiunea - partea de control - poate fi
<action name="doUpload" class="upload.UploadAction" method="upload">
<result name="success">/jsp/ResultUpload.jsp</result>
<result name="error">/jsp/ErrorUpload.jsp</result>
</action>

Componenta View este alcatuita din


Alegerea fisierului care se ncarca (Upload.jsp)
1
2
3
4
5
6
7
8
9
10
11
12
13

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>< t i t l e>Upload</ t i t l e>
</head>
<body>
<h3> I n c a r c a r e a unui f i s i e r ( up lo ad ) </h3>
<s : form action= doUpload . a c t i o n
method= p o s t e n c t y p e= m u l t i p a r t / formdata >
<s : f i l e name= myFile l a b e l= F i l e />
<s : submit />
</ s : form>
</body>
</html>

commons-fileupload permite ncarea mai multor fisiere, fapt nefolosit n


pagina JSP de mai sus.
Furnizarea unui raspuns.

1.2. STRUTS 2

29

La ncarcarea unui fisier alaturi de fisierul propriu-zis sunt preluate numele si


tipul fisierului. Sablonul de prelucrare este
String dataDir = servletContext.getRealPath("/WEB-INF/");
File savedFile = new File(dataDir, myFileFileName);
myFile.renameTo(savedFile);
unde myFile este numele campului din documentul jsp corespunzator fisierului
care se ncarca. Incarcarea se face ntr-o zona de lucru al serverului Web, fiind
stearsa la finalizarea actiunii. Este sarcina programatorului sa preia fisierul
savedFile n vederea prelucrarii / salvarii persistente. myFileFileName si
myFileContentType sunt completate de Struts cu numele si respectiv, tipul
fisierului ncarcat.
Exemplul 1.2.3 Componenta model care preia ntr-un String continutul unui
fisier text ncarcat.
Modelul este dat de clasa
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
17
19
20
21
23
24
25
27
28
29
31
32
33

package up l oad ;
import o r g . apache . s t r u t s 2 . S e r v l e t A c t i o n C o n t e x t ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import j a v a . u t i l . Map ;
import j a v a . i o . F i l e ;
import j a v a . i o . F i l e I n p u t S t r e a m ;
import j a v a . i o . InputStreamReader ;
import j a v a . i o . B u f f e r e d R e a d e r ;
import j a v a . i o . OutputStreamWriter ;
import j a v a . i o . B u f f e r e d W r i t e r ;
import j a v a . i o . F i l e O u t p u t S t r e a m ;
public c l a s s UploadAction extends A c t i o n S u p p o r t {
private F i l e myFile ;
private S t r i n g myFileFileName ;
private S t r i n g myFileContentType ;
public F i l e g e t M y F i l e ( ) {
return myFile ;
}
public void s e t M y F i l e ( F i l e myFile ) {
t h i s . myFile = myFile ;
}
public S t r i n g getMyFileFileName ( ) {
return myFileFileName ;
}
public void s e t M y F i l e F i l e N a m e ( S t r i n g myFileFileName ) {
t h i s . myFileFileName = myFileFileName ;
}

30

public S t r i n g getMyFileContentType ( ) {
return myFileContentType ;
}

35
36
37

public void setMyFileContentType ( S t r i n g myFileContentType ) {


t h i s . myFileContentType = myFileContentType ;
}

39
40
41

public S t r i n g u pl oa d ( ) throws E x c e p t i o n {
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
ServletContext servletContext =
ServletActionContext . getServletContext ( ) ;
i f ( myFile != n u l l ) {
S t r i n g d a t a D i r = s e r v l e t C o n t e x t . g e t R e a l P a t h ( /WEBINF/ ) ;
System . out . p r i n t l n ( d a t a D i r = +d a t a D i r ) ;
System . out . p r i n t l n ( FileName = +myFileFileName ) ;
F i l e s a v e d F i l e = new F i l e ( dataDir , myFileFileName ) ;
myFile . renameTo ( s a v e d F i l e ) ;

43
44
45
46
47
48
49
50
51
52

S t r i n g B u f f e r sb=new S t r i n g B u f f e r ( ) ;
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 ( s a v e d F i l e ) ;
InputStreamReader i s r =new InputStreamReader ( f 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 ) ;

54
55
56
57

F i l e f=new F i l e ( webapps / m ystrut s2 app / u pl oa d / +myFileFileName ) ;


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 ( f ) ;
OutputStreamWriter osw=new OutputStreamWriter ( f o s ) ;
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 ( osw ) ;
String line ;
do{
l i n e=br . r e a d L i n e ( ) ;
i f ( l i n e != n u l l ) {
sb . append ( l i n e+ \n ) ;
bw . w r i t e ( l i n e , 0 , l i n e . l e n g t h ( ) ) ;
bw . newLine ( ) ;
}
}
while ( l i n e != n u l l ) ;
a t t r . put ( f i l e s , sb . t o S t r i n g ( ) ) ;
bw . c l o s e ( ) ;
osw . c l o s e ( ) ;
fos . close ();
br . c l o s e ( ) ;
isr . close ();
return SUCCESS ;

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

}
else {
a t t r . put ( e r r o r , Upload E r r o r ) ;
return ERROR;
}

80
81
82
83
84

85
86

CAPITOLUL 1. APLICAT
II WEB

1.2. STRUTS 2

31

Desc
arcarea unui fisier - Download
Si pentru aceasta problema Struts2 are o solutie predefinita: este declarat
un tip de raspuns stream, caz n care raspunsul este implicit un flux InputStream.
In acest caz, numai pentru rezultat este nevoie de un fisier jsp.
Exemplul 1.2.4 Aplicatie Web n care clientul alege dintr-o lista un fisier
care este descarcat.
In compunenta de control se introduce
<action name="doDownload" class="download.DownloadAction">
<result type="stream">
<param name="inputName">fileInputStream</param>
<param name="contentDisposition">attachment;filename=${fileName}</param>
<param name="bufferSize">2048</param>
<param name="contentType">application/octet-stream</param>
</result>
</action>

Lansarea aplicatiei se face din (Download.jsp)


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

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>< t i t l e>Download</ t i t l e>
</head>
<body>
<h3> D e s c a r c a r e a unui f i s i e r ( download ) </h3>
<s : form
action= doDownload . a c t i o n >
<s : s e l e c t name= f i l e l a b e l= A l e g e
l i s t = { c a p i t o l . t x t , xmlp i c . jpg , TomJones . mp3 , c l o c k . a v i } />
<s : submit value= D e s c a r c a />
</ s : form>
</body>
</html>

Struts injecteaza n codul actiunii numele fisierului de descarcat - n cazul


exemplului, numele este continut de campul file.
Clasa modelului (actiunii) este
1
2
3
4
5
6
7
8
10
11
12
13
14

package download ;
im po rt j a v a x . s e r v l e t . S e r v l e t C o n t e x t ;
im po rt com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
im po rt o r g . apache . s t r u t s 2 . S e r v l e t A c t i o n C o n t e x t ;
im po rt j a v a . i o . InputStream ;
im po rt j a v a . i o . F i l e ;
im po rt j a v a . i o . F i l e I n p u t S t r e a m ;
im po rt j a v a . n i o . f i l e . Paths ;
p u b l i c c l a s s DownloadAction e x t e n d s A c t i o n S u p p o r t {
private String f i l e ;
public void s e t F i l e ( String f i l e ) {
this . f i l e=f i l e ;
}

32

CAPITOLUL 1. APLICAT
II WEB

18

public String getFile (){


return f i l e ;
}

20

p r i v a t e InputStream f i l e I n p u t S t r e a m ;

22

p u b l i c InputStream g e t F i l e I n p u t S t r e a m ( ) {
return fileInputStream ;
}
p u b l i c S t r i n g e x e c u t e ( ) throws E x c e p t i o n {
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 ) ;
ServletContext servletContext =
ServletActionContext . getServletContext ( ) ;
S t r i n g path=s e r v l e t C o n t e x t . g e t R e a l P a t h ( / )+
f s+ r e s o u r c e s +f s ;
f i l e I n p u t S t r e a m = new F i l e I n p u t S t r e a m ( new F i l e ( path+ f i l e ) ) ;
r e t u r n SUCCESS ;
}

16
17

23
24
25
26
27
28
29
30
31
32
33
34

1.2.4

Interceptori

Interceptorii sunt componente Struts2 care executa sarcini naintea sau


dupa procesarea unei cereri. Interceptorii fixeaza fluxul de prelucrare al unei
aplicatii Struts2 si asigura realizarea de sarcini transversale (cross-cutting
tasks).
Pachetul struts-default declara o familie de interceptori defaultStack
necesara pentru ndeplinirea sarcinilor uzuale.
Exemplul 1.2.5 Interceptorii predefiniti timer si logger ntr-o aplicatie Struts2.
Rezultatele sunt vizibile n fereastra serverului Web. Aplicatia consta din:
Componenta control
1
2
3
4
5
6
7
8
9
10
11
12
13
14

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE s t r u t s PUBLIC
//Apache S o f t w a r e Foundation //DTD S t r u t s C o n f i g u r a t i o n 2 . 0 / /EN
h t t p : // s t r u t s . apache . o r g / d t d s / s t r u t s 2 . 0 . dtd >
< s t r u t s>
<package name= p r i m u l e x t e n d s= s t r u t s d e f a u l t >
<a c t i o n name= MyAction c l a s s= exemplu . MyAction >
<i n t e r c e p t o r r e f name= t i m e r />
<i n t e r c e p t o r r e f name= l o g g e r />
<i n t e r c e p t o r r e f name= d e f a u l t S t a c k />
< r e s u l t>s u c c e s s . j s p</ r e s u l t>
</ a c t i o n>
</ package>
</ s t r u t s>

Componenta model

1.2. STRUTS 2

1
2
4
5
6
7
8

33

package exemplu ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
public c l a s s MyAction extends A c t i o n S u p p o r t {
public S t r i n g e x e c u t e ( ) {
return s u c c e s s ;
}
}

Componenta view contine fisierele


index.jsp
1
2
3
4
5
6
7
8
9
10

<%@ page contentType= t e x t / html ; c h a r s e t=UTF8%>


<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>Exemplu</head>
<body>
<s : form action= MyAction >
<s : submit />
</ s : form>
</body>
</html>

success.jsp
1
2
3
4
5

<html>
<body>
Success
</body>
</html>

Se pot defini interceptori proprii. Consideram exemplul


Exemplul 1.2.6 Aplicatie Struts2 pentru ghicirea unui numar ntreg cuprins
ntre 1 si 10 din 3 ncercari.
Pornind de la aplicatia Struts simpla vom modifica programul prin introducerea un interceptor.
Componenta control
1
2
3
4
6
7
8
9
10
11
12
13
14

? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE s t r u t s PUBLIC
//Apache S o f t w a r e Foundation //DTD S t r u t s C o n f i g u r a t i o n 2 . 0 / /EN
h t t p : // s t r u t s . apache . o r g / d t d s / s t r u t s 2 . 0 . dtd >
< s t r u t s>
<package name= d e f a u l t e x t e n d s= s t r u t s d e f a u l t >
<a c t i o n name= g u e s s c l a s s= exemplu . GuessNumber>
< r e s u l t name= i n p u t >/ j s p / i n d e x . j s p</ r e s u l t>
< r e s u l t>/ j s p / s u c c e s s . j s p</ r e s u l t>
< r e s u l t name= e r r o r >/ j s p / e r r o r . j s p</ r e s u l t>
</ a c t i o n>
</ package>
</ s t r u t s>

34

CAPITOLUL 1. APLICAT
II WEB

Componenta model
1

package exemplu ;

import
import
import
import

public c l a s s GuessNumber extends A c t i o n S u p p o r t implements S e s s i o n A w a r e {

4
5

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

j a v a . u t i l . Map ;
j a v a . u t i l . Random ;
o r g . apache . s t r u t s 2 . i n t e r c e p t o r . S e s s i o n A w a r e ;
com . opensymphony . xwork2 . A c t i o n S u p p o r t ;

private
private
private
private

int
int
Map
int

numar ;
i n c e r c a r i =1;
session ;
m a x I n c e r c a r i =4;

public i n t getNumar ( ) {
return numar ;
}
public void setNumar ( i n t numar ) {
t h i s . numar = numar ;
}
public i n t g e t I n c e r c a r i ( ) {
return i n c e r c a r i ;
}
public void s e t I n c e r c a r i ( i n t i n c e r c a r i ) {
this . i n c e r c a r i = i n c e r c a r i ;
}
public void s e t M a x I n c e r c a r i ( i n t m a x I n c e r c a r i ) {
this . maxIncercari = maxIncercari ;
}
public i n t g e t M a x I n c e r c a r i ( ) {
return m a x I n c e r c a r i ;
}
@Override
public void s e t S e s s i o n (Map s e s s i o n ) {
this . s e s s i o n = s e s s i o n ;
}
public void v a l i d a t e ( ) {
i f ( getNumar ()==0)
a d d F i e l d E r r o r ( numar , I n t r o d u c e t i numerul ) ;
i f ( ( numar>10) | | ( numar <1))
a d d F i e l d E r r o r ( numar , T r e b u i e s a f i e c u p r i n s i n t r e 1 s i 10 ) ;
}
@Override
public S t r i n g e x e c u t e ( ) {
int deGhicit ;
I n t e g e r o b j I n c e r c a r i =( I n t e g e r ) s e s s i o n . g e t ( i n c e r c a r i ) ;
i f ( o b j I n c e r c a r i==n u l l ) {
Random random=new Random ( ) ;
d e G h i c i t=random . n e x t I n t ( 1 0 ) + 1 ;
s e s s i o n . put ( g u e s s ,new I n t e g e r ( d e G h i c i t ) ) ;
}
else {
d e G h i c i t =(( I n t e g e r ) s e s s i o n . g e t ( g u e s s ) ) . i n t V a l u e ( ) ;

1.2. STRUTS 2

i n c e r c a r i=o b j I n c e r c a r i . i n t V a l u e ( ) ;
}
i n c e r c a r i ++;
s e s s i o n . put ( i n c e r c a r i ,new I n t e g e r ( i n c e r c a r i ) ) ;
i f ( numar==d e G h i c i t ) {
s e s s i o n . remove ( g u e s s ) ;
s e s s i o n . remove ( i n c e r c a r i ) ;
return SUCCESS ;
}
else {
i f ( i n c e r c a r i==m a x I n c e r c a r i ) {
s e s s i o n . remove ( g u e s s ) ;
s e s s i o n . remove ( i n c e r c a r i ) ;
return ERROR;
}
else {
return INPUT ;
}
}

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79

Componenta view contine fisierele


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

<%@ page contentType= t e x t / html ; c h a r s e t=UTF8%>


<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<body>
<h1> G h i c i &#355; i num&#259; r u l &#238;n 3
&#238; n c e r c &#259; r i</h1>
<p/>
<s : i f t e s t=#s e s s i o n . i n c e r c a r i != n u l l >
&#206; n c e r c a r e a <s : p r o p e r t y value=#s e s s i o n . i n c e r c a r i />
</ s : i f>
<s : e l s e>
&#206; n c e r c a r e a 1
</ s : e l s e>
<p>
<s : form action= g u e s s >
<s : t e x t f i e l d name=numar l a b e l= A l e g e r e a mea />
<br/>
<s : submit value= V e r i f i c a numarul />
</ s : form>
</body>
</html>

success.jsp
1
2
3
4
5
6
7
8
9

<%@ page contentType= t e x t / html ; c h a r s e t=UTF8%>


<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<body>
<h1> G h i c i &#355; i num&#259; r u l &#238;n
<s : p r o p e r t y value=%{m a x I n c e r c a r i 1} />&#238; n c e r c &#259; r i
</h1>
<p/>
Num&#259; r u l a f o s t g h i c i t &#238;n

35

36

CAPITOLUL 1. APLICAT
II WEB

10
11
12
13
14
15
16

<s : p r o p e r t y value=%{ i n c e r c a r i 1} /> &#238; n c e r c &#259; r i !


<br/>
<a href= h t t p : / / l o c a l h o s t : 8 0 8 0 / g u e s s >
&#206; nc &#259; o dat &#259;
</a>
</body>
</html>

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

<%@ page contentType= t e x t / html ; c h a r s e t=UTF8%>


<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<body>
<h1> G h i c i &#355; i num&#259; r u l &#238;n
<s : p r o p e r t y value=%{m a x I n c e r c a r i 1} />&#238; n c e r c &#259; r i
</h1>
<p/>
A t i dep&#259;&#351; i t num&#259; r u l de &#238; n c e r c &#259; r i !
</p>
Num&#259; r u l nu a f o s t g h i c i t !
<br/>
<a href= h t t p : / / l o c a l h o s t : 8 0 8 0 / g u e s s >
&#206; nc &#259; o dat &#259;
</a>
</body>
</html>

Clasa unui interceptor implementeaza interfata


com.opensymphony.xwork2.interceptor.Interceptor.
Interfata declara metodele
public void init()
public void destroy()
public String intercept(ActionInvocation actionInvocation) throws
Exception
Introducem un interceptor pentru generarea numarului ales aleator.

package exemplu ;
import j a v a . u t i l . Map ;
import j a v a . u t i l . Random ;
import com . opensymphony . xwork2 . A c t i o n ;
import com . opensymphony . xwork2 . A c t i o n I n v o c a t i o n ;
import com . opensymphony . xwork2 . i n t e r c e p t o r . I n t e r c e p t o r ;

public c l a s s RandomNumberInterceptor implements I n t e r c e p t o r {

2
3
4
5
6

11

@Override

1.2. STRUTS 2

public void d e s t r o y ( ) {
// TODO Autog e n e r a t e d method s t u b
}

12
13
14

@Override
public void i n i t ( ) {
// TODO Autog e n e r a t e d method s t u b
}

16
17
18
19

@Override
public S t r i n g i n t e r c e p t ( A c t i o n I n v o c a t i o n a c t i o n I n v o c a t i o n )
throws E x c e p t i o n {
// Se p r e i a s e s i u n e a
Map s e s s i o n=a c t i o n I n v o c a t i o n . g e t I n v o c a t i o n C o n t e x t ( ) . g e t S e s s i o n ( ) ;
// F i x e a z a numarul a l e a t o r l a i n c e p u t u l a p l i c a t i e i
i f ( ! s e s s i o n . c o n t a i n s K e y ( g u e s s ) | | ! ( s e s s i o n . g e t ( g u e s s ) != n u l l ) ) {
Random random = new Random ( ) ;
i n t d e G h i c i t = random . n e x t I n t ( 1 0 ) + 1 ;
s e s s i o n . put ( g u e s s , d e G h i c i t ) ;
}
// I n v o c a r e a c e l o r l a l t e s a r c i n i
return a c t i o n I n v o c a t i o n . i n v o k e ( ) ;
}

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

37

Metoda invoke a clasei ActionInvocation apeleaza urmatorul pas din procesarea interceptorilor iar n final se returneaza un cod de retur.
Modificarile suferite de cele trei componente sunt
Componenta control
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE s t r u t s PUBLIC
//Apache S o f t w a r e Foundation //DTD S t r u t s C o n f i g u r a t i o n 2 . 0 / /EN
h t t p : // s t r u t s . apache . o r g / d t d s / s t r u t s 2 . 0 . dtd >
< s t r u t s>
<package name= d e f a u l t e x t e n d s= s t r u t s d e f a u l t >
< i n t e r c e p t o r s>
<i n t e r c e p t o r name= r a n d o m I n t e r c e p t o r
c l a s s= exemplu . RandomNumberInterceptor />
<i n t e r c e p t o r s t a c k name= myStack >
<i n t e r c e p t o r r e f name= d e f a u l t S t a c k />
<i n t e r c e p t o r r e f name= r a n d o m I n t e r c e p t o r />
</ i n t e r c e p t o r s t a c k>
</ i n t e r c e p t o r s>
<a c t i o n name= g u e s s c l a s s= exemplu . GuessNumber>
<i n t e r c e p t o r r e f name= myStack />
< r e s u l t name= i n p u t >/ j s p / i n d e x . j s p</ r e s u l t>
< r e s u l t>/ j s p / s u c c e s s . j s p</ r e s u l t>
< r e s u l t name= e r r o r >/ j s p / e r r o r . j s p</ r e s u l t>
</ a c t i o n>
</ package>
</ s t r u t s>

Componenta model
1
2

package exemplu ;
import j a v a . u t i l . Map ;

38

3
4
6
7
8
9
10
11
13
14
15
16
17
18
20
21
22
23
24
25
27
28
29
30
31
32
34
35
36
37
39
40
41
42
43
44
45
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

CAPITOLUL 1. APLICAT
II WEB

import o r g . apache . s t r u t s 2 . i n t e r c e p t o r . S e s s i o n A w a r e ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
public c l a s s GuessNumber extends A c t i o n S u p p o r t
implements S e s s i o n A w a r e {
private i n t numar ;
private i n t i n c e r c a r i =1;
private Map s e s s i o n ;
private i n t m a x I n c e r c a r i =4;
public i n t getNumar ( ) {
return numar ;
}
public void setNumar ( i n t numar ) {
t h i s . numar = numar ;
}
public i n t g e t I n c e r c a r i ( ) {
return i n c e r c a r i ;
}
public void s e t I n c e r c a r i ( i n t i n c e r c a r i ) {
this . i n c e r c a r i = i n c e r c a r i ;
}
public void s e t M a x I n c e r c a r i ( i n t m a x I n c e r c a r i ) {
this . maxIncercari = maxIncercari ;
}
public i n t g e t M a x I n c e r c a r i ( ) {
return m a x I n c e r c a r i ;
}
@Override
public void s e t S e s s i o n (Map s e s s i o n ) {
this . s e s s i o n = s e s s i o n ;
}
public void v a l i d a t e ( ) {
i f ( getNumar ()==0) {
a d d F i e l d E r r o r ( numar , I n t r o d u c e t i numerul ) ;
}
i f ( ( numar>10) | | ( numar <1))
a d d F i e l d E r r o r ( numar , T r e b u i e s a f i e c u p r i n s i n t r e 1 s i 10 ) ;
}
@Override
public S t r i n g e x e c u t e ( ) {
i n t d e G h i c i t =(( I n t e g e r ) s e s s i o n . g e t ( g u e s s ) ) . i n t V a l u e ( ) ;
I n t e g e r o b j I n c e r c a r i =( I n t e g e r ) s e s s i o n . g e t ( i n c e r c a r i ) ;
i f ( o b j I n c e r c a r i != n u l l ) {
i n c e r c a r i=o b j I n c e r c a r i . i n t V a l u e ( ) ;
}
System . out . p r i n t l n ( i n c e r c a r i+ +numar+ +d e G h i c i t ) ;
i n c e r c a r i ++;
s e s s i o n . put ( i n c e r c a r i ,new I n t e g e r ( i n c e r c a r i ) ) ;
i f ( numar==d e G h i c i t ) {
s e s s i o n . remove ( g u e s s ) ;
s e s s i o n . remove ( i n c e r c a r i ) ;
return SUCCESS ;
}

39

1.2. STRUTS 2

else {
i f ( i n c e r c a r i==m a x I n c e r c a r i ) {
s e s s i o n . remove ( g u e s s ) ;
s e s s i o n . remove ( i n c e r c a r i ) ;
return ERROR;
}
else {
return INPUT ;
}
}

62
63
64
65
66
67
68
69
70
71

72
73

Componenta view nu sufera modificari.

1.2.5

Aplicatii Struts2 prin modelul programat

Modelul programat se obtine prin utilizarea adnotarilor. O actiune este


denumita printr-un identificator, de exemplu xyz. Clasa corespunzatoare va fi
actions.XyzAction. Aceasta clasa contine metoda
public String execute(),
care este invocata de Struts2 pentru ndeplinirea cererii clientului.
String-ul returnat fixeaza componenta view n adnotarea org.apache.
struts2.convention.annotation.Result. Campurile adnotarii sunt name,
location, type, params. In cazul mai multor adnotari Result acestea se includ n adnotarea org.apache.struts2.convention.annotation.Results.
Aceste resurse se gasesc n arhiva struts2-convention-plugin-*.jar.
Reluam aplicatia din sectiunea 1.2.3.
Cmmdc.jsp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>
<t i t l e >
C a l c u l u l c e l u i mai mare d i v i z o r comun a dou&#259; numere n a t u r a l e
</ t i t l e >
</head>
<body>
<h3> I n t r o d u c e &#355; i </h3>
<s : form a c t i o n=cmmdc>
<s : t e x t f i e l d l a b e l= Primul numar name=m/>
<s : t e x t f i e l d l a b e l= Al d o i l e a numar name=n />
<s : submit v a l u e= C a l c u l e a z a />
</s : form>
</body>
</html>

cu actiunea corespunzatoare

40

CAPITOLUL 1. APLICAT
II WEB

package a c t i o n s ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import j a v a . u t i l . Map ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t ;

@Result ( name= s u c c e s s , l o c a t i o n= / j s p /ResultCmmdc . j s p )

public c l a s s CmmdcAction{
public S t r i n g e x e c u t e ( ) {
long c=cmmdc(m, n ) ;
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
a t t r . put ( cmmdc , (new Long ( c ) ) . t o S t r i n g ( ) ) ;
return s u c c e s s ;
}

1
2
3

9
10
11
12
13
14
16

public long cmmdc( long m, long n ) { . . . }

18

private long m;
public long getM ( ) {
return m;
}
public void setM ( long m) {
t h i s .m = m;
}

19
20
21
22
23
24

private long n ;
public long getN ( ) {
return n ;
}
public void setN ( long n ) {
this . n = n ;
}
private S t r i n g message ;
public void s e t M e s s a g e ( S t r i n g message ) {
t h i s . message = message ;
}
public S t r i n g g e t M e s s a g e ( ) {
return message ;
}

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

Exista o alta varianta de programare bazata pe extinderea clasei


com.opensymphony.xwork2.ActionSupport si bazat pe adnotarea
org.apache.struts2.convention.annotation.Action.
1
2
3
4
6
7
8

package a c t i o n s ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . A c t i o n ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t ;
@Result ( name= s u c c e s s , l o c a t i o n= / j s p /ResultCmmdc . j s p )
@Action ( cmmdc )
public c l a s s Cmmdc extends A c t i o n S u p p o r t {
public S t r i n g e x e c u t e ( ) throws E x c e p t i o n {
. . .

10
11
12

1.2. STRUTS 2

41

Daca o actiune Struts2 produce mai multe variante de rezultat acestea se


programeaza
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
@Results({
@Result(. . .),
@Result(. . .),
. . .
})

In cazul exemplului 1.2.2 se lanseaza actiunea


http://localhost:8080/mystruts2-anapp/listajud

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

package a c t i o n s ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import j a v a . u t i l . ;
import j a v a . i o . ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t ;
@Result ( name= s u c c e s s , l o c a t i o n= / j s p /AppJud . j s p )
public c l a s s L i s t a j u d A c t i o n {
private HashMap<S t r i n g , RefJudet> r e f J u d e t e=
new HashMap<S t r i n g , RefJudet > ( ) ;
public S t r i n g e x e c u t e ( ) {
return s u c c e s s ;
}
public L i s t <RefJudet> g e t J u d e t e L i s t ( ) throws IOException {
L i s t <RefJudet> l i s t =new A r r a y L i s t <RefJudet > ( ) ;
InputStream f i s =t h i s . g e t C l a s s ( ) . g e t R e s o u r c e A s S t r e a m ( j u d e t e . t x t ) ;
InputStreamReader i s r =new InputStreamReader ( f 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 ) ;
S t r i n g s= , jud , c a p i t , a b r e v ;
do{
s=br . r e a d L i n e ( ) ;
i f ( s != n u l l ) {
S t r i n g [ ] s t=s . s p l i t ( ) ;
j u d=s t [ 0 ] ;
c a p i t=s t [ 1 ] ;
a b r e v=s t [ 2 ] ;
R e f J u d e t bean=new R e f J u d e t ( ) ;
bean . s e t J u d ( j u d ) ;
bean . s e t C a p i t ( c a p i t ) ;
bean . s e t A b r e v ( a b r e v ) ;
l i s t . add ( bean ) ;
r e f J u d e t e . put ( jud , bean ) ;
}
}
while ( s != n u l l ) ;
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
a t t r . put ( r e f J u d e t e , r e f J u d e t e ) ;

42

return l i s t ;

41

42
43

CAPITOLUL 1. APLICAT
II WEB

AppJud.jsp are codul


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

<%@ t a g l i b p r e f i x= s u r i= / s t r u t s t a g s %>
<html>
<head>
< t i t l e>R e f e r i n t e Judet</ t i t l e>
</head>
<body>
<h1> R e f e r i n t e d e s p r e j u d e t e </h1>
<p/>
<s : form action= judbean >
<s : s e l e c t name= s e l e c t a t l a b e l= J u d e t e
l i s t = j u d e t e L i s t l i s t K e y=%{j u d } l i s t V a l u e=%{j u d } />
<s : submit />
</ s : form>
</body>
</html>

careie i corespunde actiunea data de clasa

package a c t i o n s ;
import j a v a . u t i l . ;
import com . opensymphony . xwork2 . A c t i o n C o n t e x t ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t ;

@Result ( name= s u c c e s s , l o c a t i o n= / j s p / R e s u l t J u d . j s p )

public c l a s s JudbeanAction {
private S t r i n g j u d=n u l l ;
private S t r i n g c a p i t=n u l l ;
private S t r i n g a b r e v=n u l l ;
private S t r i n g s e l e c t a t ;

1
2
3

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

public S t r i n g e x e c u t e ( ) throws E x c e p t i o n {
Map a t t r=A c t i o n C o n t e x t . g e t C o n t e x t ( ) . g e t S e s s i o n ( ) ;
HashMap<S t r i n g , RefJudet> r e f J u d e t e =
( HashMap<S t r i n g , RefJudet >) a t t r . g e t ( r e f J u d e t e ) ;
R e f J u d e t r j=r e f J u d e t e . g e t ( s e l e c t a t ) ;
j u d=r j . getJud ( ) ;
c a p i t=r j . g e t C a p i t ( ) ;
a b r e v=r j . getAbrev ( ) ;
return s u c c e s s ;
}
public S t r i n g getJud ( ) {
return j u d ;
}
public S t r i n g g e t C a p i t ( ) {
return c a p i t ;
}
public S t r i n g getAbrev ( ) {
return a b r e v ;
}

1.2. STRUTS 2

public void s e t S e l e c t a t ( S t r i n g s e l e c t a t ) {
t h i s . s e l e c t a t=s e l e c t a t ;
}

37
38
39

public S t r i n g g e t S e l e c t a t ( ) {
return s e l e c t a t ;
}

41
42
43
44

43

Adnotarile
org.apache.struts2.convention.annotation.InterceptorRef
org.apache.struts2.convention.annotation.InterceptorRefs
declara interceptorii necesari unei actiuni.
In cazul exemplului tratat n sectiunea dedicata interceptorilor, clasa interceptorului actions.RandomNumber Interceptor ramane nemodificata iar interceptorul se declara n fisierul struts.xml
1
2
3
4
5
6
7
8
9
10
11
12

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE s t r u t s PUBLIC
//Apache S o f t w a r e Foundation //DTD S t r u t s C o n f i g u r a t i o n 2 . 0 / /EN
h t t p : // s t r u t s . apache . o r g / d t d s / s t r u t s 2 . 0 . dtd >
< s t r u t s>
<package name= a n i n t e x t e n d s= s t r u t s d e f a u l t >
< i n t e r c e p t o r s>
<i n t e r c e p t o r name= r a n d o m I n t e r c e p t o r
c l a s s= a c t i o n s . RandomNumberInterceptor />
</ i n t e r c e p t o r s>
</ package>
</ s t r u t s>

Clasa actiunii actions.GuessNumber devine


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

package a c t i o n s ;
import j a v a . u t i l . Map ;
import j a v a . u t i l . Random ;
import o r g . apache . s t r u t s 2 . i n t e r c e p t o r . S e s s i o n A w a r e ;
import com . opensymphony . xwork2 . A c t i o n S u p p o r t ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . R e s u l t s ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . A c t i o n ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . I n t e r c e p t o r R e f ;
import o r g . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . I n t e r c e p t o r R e f s ;
@Results ( {
@Result ( name= e r r o r , l o c a t i o n= / j s p / e r r o r . j s p ) ,
@Result ( name= s u c c e s s , l o c a t i o n= / j s p / s u c c e s s . j s p ) ,
@Result ( name= i n p u t , l o c a t i o n= / j s p / i n d e x . j s p ) ,
})
@org . apache . s t r u t s 2 . c o n v e n t i o n . a n n o t a t i o n . ParentPackage ( v a l u e = a n i n t )
@Action ( v a l u e= g u e s s ,
i n t e r c e p t o r R e f s ={@ I n t e r c e p t o r R e f ( r a n d o m I n t e r c e p t o r ) ,

44

CAPITOLUL 1. APLICAT
II WEB

21

@InterceptorRef ( defaultStack )})

23

public c l a s s GuessNumber extends A c t i o n S u p p o r t implements S e s s i o n A w a r e {


. . .
}

24
25

1.2.6

Struts 2 prin maven

Aplicatiile dezvoltate corespund celor dezvoltate anterior, calculul celui


mai mare divizor comun (Cmmdc.java) si regasirea datelor unui judet (JudBean.java, ListaJudeteAction.java, RefJudet.java).

Modelul descriptiv
Dezvoltarea aplicatiei consta din:
1. Generarea aplicatiei
set GroupID=action
set ArtifactID=mystruts2
set Version=1.0
set ArchetypeVersion=2.3.24.1
mvn archetype:generate -B
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeGroupId=org.apache.struts
-DarchetypeArtifactId=struts2-archetype-blank
-DarchetypeVersion=%ArchetypeVersion%

unde *.*.* se nlocuieste cu versiunea Struts2 folosita.


2. Se adapteaza structura de cataloage si fisiere la
mystruts2
|--> src
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

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

java
|--> action
|
|--> cmmdc
|
|
|
Cmmdc.java
|
|--> appjud
|
|
|
JudBean.java
|
|
|
ListaJudeteAction
|
|
|
RefJudet.java
resources
|
judete.txt
|
struts.xml
webapp
|--> html
|
|
AlegeApp.html

45

1.2. STRUTS 2

|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pom.xml

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

jsp
|
Cmmdc.jsp
|
AppJud.jsp
|
ResultCmmdc.jsp
|
ResultJud.jsp
WEB-INF
|
web.xml
index.html

In clasa ListaJudeteAction.java fisierul judete.txt se ncarca prin


InputStream fis=this.getClass().getResourceAsStream("../judete.txt");

3. Prelucrarea consta din


(a) mvn clean package
(b) Fisierul war care rezulta se desfasoara n serverul Web.

Modelul programat
Indicam doar diferentele fata de varianta anterioara:
1. In fisierul pom.xml se adauga:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>${struts2.version}</version>
</dependency>

2. Se adapteaza structura de cataloage si fisiere la


mystruts2annotation
|--> src
|
|--> main
|
|
|--> java
|
|
|
|--> action
|
|
|
|
|--> cmmdc
|
|
|
|
|
|
Cmmdc.java
|
|
|
|
|--> appjud
|
|
|
|
|
|
JudBean.java
|
|
|
|
|
|
ListaJudeteAction
|
|
|
|
|
|
RefJudet.java
|
|
|--> resources
|
|
|
|
judete.txt
|
|
|--> webapp
|
|
|
|--> html
|
|
|
|
|
AlegeApp.html
|
|
|
|--> jsp
|
|
|
|
|
Cmmdc.jsp

46

CAPITOLUL 1. APLICAT
II WEB

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
pom.xml

|
|
|
|-->
|
|

|
AppJud.jsp
|
ResultCmmdc.jsp
|
ResultJud.jsp
WEB-INF
|
web.xml
index.html

3. In paralel se adapteaza pachetele claselor Java si referintele din fisierele


html.
Probleme
Struts n nor (GAE, Heroku, OpenShift)

1.3. JAVA SERVER FACES

1.3

47

Java Server Faces

Java Server Faces (JSF) este un cadru de dezvoltare (framework) a aplicatiilor


Web, asemanator cu Struts.
Amintim urmatoarele doua implementari JSF:
JSF - RI (Reference Implementation), dezvoltat de firma Oracle-Sun
Microsystems; JSF este inclusa n extensia Java Enterprise Edition JEE.
Distributia JSF de sine statatoare consta dintr-un fisier javax.faces-*.jar,
care trebuie copiat n catalogul WEB-INF\lib al aplicatiei.
MyFaces, dezvoltat n cadrul fundatiei apache.

1.3.1

Structura unei aplicatii JSF

Partea de view din JSF poate fi dezvoltata utilizand:


Facelets - caz n care vorbim de pagini Facelets, reprezentate de
fisiere cu extensia xhtml. Resursele necesare tehnologiei Facelets
trebuie descarcate suplimentar.
Resursele necesare sunt:
javax.faces.*.jar
javax.servlet.jsp.jstl.jar
javax.servlet.jsp.jstl-api.jar
JSP
Resursele necesare sunt:
javax.faces.*.jar
taglib-standard-impl-*.jar, taglib-standard-spec-*.jar
aflate n TOMCAT HOME\webapps\
examples\WEB- INF\lib. Acestea din urma definesc Java Standard Tag Library (JSTL).
Biblioteci de componente grafice:
Primefaces, dezvoltat de C
agatay C
ivici, utilizarea careia s-a
raspandit n ultima vreme.
Resursele necesare sunt:
javax.faces.*.jar

48

CAPITOLUL 1. APLICAT
II WEB

taglibs-standard-impl-*.jar, taglibs-standard-spec-*.jar
primefaces-*.jar
Richfaces
In toate cazuri se utilizeaza biblioteca de marcaje specifice JSF.
Facelets se impune datorita incompatibilitatilor dintre JSF si JSP n
ciclul de activitati pe care le desfasoara pentru rezolvarea unei apelari.
Partea de model este alcatuita din componente Java (bean) care se
ncarca cu datele furnizate din paginile JSP/Facelets, asigura functionalitatea specifica aplicatiei si constituie sursa de date pentru paginile de
afisare a rezultatelor. Clasele Java trebuie sa implementeze interfata
java.io.Serializable.
JSF instantiaza componentele Java si injecteaza datele n aceste componente.
Controller -ul este dat de fisierul de configurare faces-config.xml n
care se fixeaza
legatura dintre paginile de furnizare a datelor si cele care afiseaza
rezultatul prelucrarii, prin elementele <navigation-rule>. Astfel
elementul <from-view-id> contine referinta la pagina Facelets
/ JSP furnizoare de date;
elementul <navigation-case> declara o posibilitate de iesire.
Corpul acestui element contine:
<from-outcome> element n care se declara stringul care
directioneaza iesirea.
<to-view-id> contine referinta la pagina Facelets / JSP
de afisare a rezultatelor obtinute n urma actiunii corespunzatoare stringului din <from-outcome>.
Toate referinta se raportateaza la contextul aplicatiei.
Elementul <navigation-rule> poate fi evitat prin precizarea n
instructiunea return, din codul actiunii, a fisierului care trateaza
prelucrarea care urmeaza, de exemplu
return "/cmmdcOutput.jsp";

componentele Java utilizate, prin elemente <managed-bean> avand


componenta:

1.3. JAVA SERVER FACES

49

elementul <managed-bean-name> declara numele simbolic al


unei componente Java (bean).
elementul <managed-bean-class> specifica clasa componentei. Referinta se raporteaza la catalogul WEB-INF\classes.
elementul <managed-bean-scope> specifica durata de existenta
a componentei Java: page, request, session, application.
Intr-un element <managed-bean> se pot fixa valorile unor campuri
ale componentei Java prin intermediul marcajelor
<managed-property>
<property-name> . . . </property-name>
<value> . . . </value>
</managed-property>
Elementul <managed-bean> poate fi evitat prin utilizarea adnotarilor
aplicate componentei Java.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="nume_componenta")
@SessionScoped | @ApplicationScoped
@ManagedProperty(name="nume_camp",value="valoare_camp")
Daca n adnotarea @ManagedBean lipseste atributul name si daca
identificatorul componentei Java (clasei) este Xyz (adica fisierul clasei este Xyz.java) atunci n fisierele view referinta la campurile si
metodele clasei se face prin sintaxa #{xyz.camp},
respectiv #{xyz.metoda}.
Fisierul web.xml este independent de aplicatie si n principiu are codul
1
2
3
4
5
6
8
9
10
11
12
13

<?xml version= 1 . 0 e n c o d i n g= UTF8 ?>


<webapp version= 2 . 5
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
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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd >
. . .
< s e r v l e t>
<s e r v l e t name>F a c e s 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 a v a x . f a c e s . webapp . F a c e s S e r v l e t</ s e r v l e t c l a s s>
<l o a d ons t a r t u p>1</ l o a d ons t a r t u p>
</ s e r v l e t>

50

15
16
17
18
19
20

CAPITOLUL 1. APLICAT
II WEB

<s e r v l e t mapping>
<s e r v l e t name>F a c e s 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> . f a c e s sau . j s f</ u r l p a t t e r n>
</ s e r v l e t mapping>
. . .
</webapp>

Desfasurarea unei aplicatii JSF este


|--> webapps
|
|--> app_jsf_context
|
|
|--> WEB-INF
|
|
|
|--> lib
|
|
|
|
| javax.faces.*.jar
|
|
|
|
| alte_arhive_jar
|
|
|
|--> classes
|
|
|
|
|--> pachetul_aplicatiei
|
|
|
|
|
*.class (componentele Java)
|
|
|
|
web.xml
|
|
|
|
faces-config.xml
|
|
|
index.html
|
|
|
pagini_JSP sau pagini_Facelets

Prin index.html se lanseaza aplicatia JSF.


Un ciclu de executie JSF consta din
1. Afisarea componentei view;
2. Preluarea datelor necesare satisfacerii cererii;
3. Validarea datelor;
4. Actualizarea componentei model cu datele preluate;
5. Invocarea metodelor componentei model care rezolva cererea clientului;
6. Afisarea raspunsului.

1.3.2

Marcaje JSF

Marcajele JSF sunt definite n doua biblioteci. Ele se declara n paginile


JSP prin
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
Nu este nevoie de specificarea lor n fisierul de configurare web.xml.
Amintim marcajele:

51

1.3. JAVA SERVER FACES

f:view Vizualizeaza componentele grafice.


h:form Pentru marcarea formularului.
h:outputText Afiseaza un text.
Atribute ale marcajului:
Atribut Fel
Descriere
value
obligatoriu Textul ce se afiseaza. Poate fi si referinta
la campul unei componente Java.
h:inputText Declara un camp de introducere date de tip string.
Atribute ale marcajului:
Atribut
value
required
id
validator

Fel
obligatoriu
optional
optional
optional

Descriere
Campul componentei Java alimentat.
true / false, pentru validare.
Numele simbolic al campului.
Referinta la metoda de validare.

h:panelGrid Componentele incluse sunt aranjate ntr-un tablou.


Atribute ale marcajului:
Atribut Fel
Descriere
columns obligatoriu Numarul coloanelor.
h:selectOneMenu Declara un control grafic de tip select.
Atribute ale marcajului:
Atribut
value
required
id
validator

Fel
obligatoriu
optional
optional
optional

Descriere
Campul componentei Java alimentat.
true / false, pentru validare.
Numele simbolic al campului.
Referinta la metoda de validare.

Optiunile se definesc n elementul <f:selectItem> ale carui atribute


sunt
Atribut
Fel
Descriere
itemLabel obligatoriu Textul explicativ afisat.
itemValue obligatoriu Valoarea atasata optiunii.
Exemplu:

52

CAPITOLUL 1. APLICAT
II WEB

<h:selectOneMenu required="true" value="#{conv.tip}">


<f:selectItem itemLabel="Celsius -> Fahrenheit" itemValue="C2F" />
<f:selectItem itemLabel="Fahrenheit -> Celsius" itemValue="F2C" />
</h:selectOneMenu>

h:commandButton Declara un buton de comanda.


Atribute ale marcajului:
Atribut Fel
Descriere
action obligatoriu Numele simbolic al actiunii,
declarat ntr-un marcaj <from-outcome>
din faces-config.xml.
value
obligatoriu Textul butonului.
h:messages Afiseaza mesajele de eroare rezultate n urma validarilor.
h:message Afiseaza mesajele de eroare rezultate n urma validarilor.
Atribute ale marcajului:
Atribut Fel
Descriere
for
obligatoriu Numele simbolic al campului supus verificarii.

1.3.3

Aplicatii JSF cu pagini Facelets

In acest caz fisierul web.xml se completeaza este


<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>

Componenta view a unei aplicatii este alcatuita din pagini Facelets.


Pentru nceput, plecam de la codul cu marcaje JSF (cmmdcInput.xhtml ) corespunzatoare unui formular de date pentru calculul celui mai mare divizor
comun a doua numere naturale
1
2
3
4
5
6
7
8
9
10
11

<html>
<h : form>
<h : p a n e l G r i d columns= 2 >
<h : outputText value= Primul num&#259; r />
<h : i n p u t T e x t value=#{cb . sm} />
<h : outputText value= Al d o i l e a num&#259; r />
<h : i n p u t T e x t value=#{cb . sn } />
<h : commandButton action=#{cb . compute } value= C a l c u l e a z &#259; />
</h : p a n e l G r i d>
</h : form>
</html>

1.3. JAVA SERVER FACES

53

Referinta la resursele unei componente Java se indica cuprinse prin #{ } sau


${ }. In acest cod, cb desemneaza o componenta Java pentru calculul celui mai
mare divizor comun a doua numere naturale. sm,sn sunt campuri iar compute
este o metoda - codul complet al clasei este dat mai jos.
O pagina Facelets poate corespunde unui sablon, o resursa Facelets reutilizabila. In sablon se definesc zone a caror continut se poate initializa si care
ulterior se pot modifica. O regiune se defineste prin
<ui:insert name="numeZona">continut</ui:insert>
Zona poate fi initializata cu continutul unui alt fisier Facelets sau html, prin
<ui:include src="fisier.[x]html"/>
Intr-o pagina Facelets dezvoltata pe sablon, referinta la acesta se obtine
prin
<ui:composition template="sablon.xhtml">
. . .
</ui:composition>
Continutul aflat nafara elementului <ui:composition> este ignorat. Acest
efect este anulat daca n schimb se utilizeaza
<ui:decorate template="sablon.xhtml">
. . .
</ui:decorate>
Modificarea unei zone se programeaza prin
<ui:define name="numeZona">
noul continut
</ui:define>
Introducerea / definirea unui continut nou Facelets se obtine cu
<ui:component>
. . .
</ui:component>
Continutul aflat nafara acestui element este ignorat. Acest efect este anulat
daca n schimb se utilizeaza

54

CAPITOLUL 1. APLICAT
II WEB

<ui:fragment>
. . .
</ui:fragment>
Prin elementul
<ui:param name="nume_parametru" value="#{componentaJava.camp}"/>
se pot transmite parametrii catre un document xhtml. Utilizarea acestei variante ofera o generalitate marita documentului xhtml
Fie sablonul template.xhtml
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

<? xml v e r s i o n = 1 . 0 e n c o d i n g =UTF8 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : u i= h t t p : / / j a v a . sun . com/ j s f / f a c e l e t s
xmlns : f= h t t p : / / j a v a . sun . com/ j s f / c o r e
xmlns : h= h t t p : / / j a v a . sun . com/ j s f / html >
<u i : i n s e r t name= t i t l e >
Title
</ u i : i n s e r t>
<br/>
<table width=100%>
<tr>
<td width=20%>
<u i : i n s e r t name= sidemenu >
S i d e Menu
</ u i : i n s e r t>
</td>
<td width=80%>
<u i : i n s e r t name= body >
Body
</ u i : i n s e r t>
</td>
</ tr>
</ table>
<br/>
<u i : i n s e r t name= s u b s o l >
<u i : i n c l u d e src= f o o t e r T e m p l a t e . html />
</ u i : i n s e r t>
</html>

unde footerTemplate.html are codul


1
2
3
4
5

<html>
<body>
<i>F a c e l e t s t e c h n o l o g y</ i>
</body>
</html>

Intre titlu si subsol s-a introdus un tabel cu doua coloane pentru un meniu
(sidemenu) si pentru zona body.

1.3. JAVA SERVER FACES

55

Exemplul 1.3.1 Calculul celui mai mare divizor comun a doua numere naturale.
Pe acest sablon se dezvolta paginile Facelets de introducere a datelor (cmmdcInput.xhtml ) si de afisare a rezultatelor (cmmdcOutput.xhtml ):
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

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

<? xml v e r s i o n = 1 . 0 e n c o d i n g =UTF8 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : u i= h t t p : / / j a v a . sun . com/ j s f / f a c e l e t s
xmlns : h= h t t p : / / j a v a . sun . com/ j s f / html >
<u i : c o m p o s i t i o n t e m p l a t e= t e m p l a t e . xhtml >
<u i : d e f i n e name= t i t l e >
<h1>Cel mai mare d i v i z o r comun</h1>
</ u i : d e f i n e>
<u i : d e f i n e name= body >
<h : form>
<h : p a n e l G r i d columns= 2 >
<h : outputText value= Primul num&#259; r />
<h : i n p u t T e x t value=#{cb . sm} />
<h : outputText value= Al d o i l e a num&#259; r />
<h : i n p u t T e x t value=#{cb . sn } />
<h : commandButton action=#{cb . compute } value= C a l c u l e a z &#259; />
</h : p a n e l G r i d>
</h : form>
</ u i : d e f i n e>
</ u i : c o m p o s i t i o n>
</html>
<? xml v e r s i o n = 1 . 0 e n c o d i n g =UTF8 ?>
< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : u i= h t t p : / / j a v a . sun . com/ j s f / f a c e l e t s
xmlns : h= h t t p : / / j a v a . sun . com/ j s f / html >
<u i : c o m p o s i t i o n t e m p l a t e= t e m p l a t e . xhtml >
<u i : d e f i n e name= t i t l e >
<h1> CMMDC R e z u l t a t </h1>
</ u i : d e f i n e>
<u i : d e f i n e name= body >
<h : outputText value=Cmmdc= />
<h : outputText value=#{cb . s r e s u l t } />
</ u i : d e f i n e>
</ u i : c o m p o s i t i o n>
</html>

Componenta model este data de clasa


1

package cmmdc ;

public c l a s s CmmdcBean implements j a v a . i o . S e r i a l i z a b l e {


private S t r i n g sm ;
private S t r i n g sn ;
private S t r i n g s r e s u l t ;

4
5
6

56
public CmmdcBean ( ) { }

public S t r i n g getSm ( ) {
return sm ;
}

10
11
12

public void setSm ( S t r i n g sm ) {


t h i s . sm=sm ;
}

14
15
16

public S t r i n g getSn ( ) {
return sn ;
}

18
19
20

public void s e t S n ( S t r i n g sn ) {
t h i s . sn=sn ;
}

22
23
24

public S t r i n g g e t S r e s u l t ( ) {
return s r e s u l t ;
}
public S t r i n g compute ( ) {
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
long c=cmmdc(m, n ) ;
s r e s u l t =(new Long ( c ) ) . t o S t r i n g ( ) ;
return OK ;
}

26
27
28
29
30
31
32
33
34
35

private long cmmdc( long m, long n ) { . . . }

37
38

CAPITOLUL 1. APLICAT
II WEB

Componenta controller este data de fisierul faces-config.xml


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


<f a c e s c o n f i g xmlns= h t t p : / / xmlns . j c p . o r g /xml/ ns / j a v a e e
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 : / / xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : / / xmlns . j c p . o r g /xml/ ns / j a v a e e /webf a c e s c o n f i g 2 2 . xsd
v e r s i o n= 2 . 2 >
<n a v i g a t i o n r u l e>
<d e s c r i p t i o n />
<fromviewid>/cmmdcInput . xhtml</ fromviewid>
<n a v i g a t i o n c a s e>
<d e s c r i p t i o n />
<fromoutcome>OK</ fromoutcome>
<toviewid>/cmmdcOutput . xhtml</ toviewid>
</ n a v i g a t i o n c a s e>
</ n a v i g a t i o n r u l e>
<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cb</managedbeanname>
<managedbeanc l a s s>cmmdc . CmmdcBean</managedbeanc l a s s>
<managedbeanscope> s e s s i o n</managedbeanscope>
</managedbean>
</ f a c e s c o n f i g>

1.3. JAVA SERVER FACES

57

Aplicatia se lanseaza prin (index.html )


1
2
3
4
5
6
7
8
9
10

<html>
<body>
<center>
<h1> A p l i c a &#355; i e JSF </h1>
<a href= / m y j s f F a c e l e t s /cmmdcInput . f a c e s >
A p l i c a &#355; i e JSF
</a>
</ center>
</body>
</html>

Extensia faces semnaleaza serverului Web ca se executa o aplicatie JSF.


Extindem aplicatia pentru a exemplifica utilizarea unui element <ui:component>.
In acest sens se definesc clasele MenuItem
1
2
3

public c l a s s MenuItem implements j a v a . i o . S e r i a l i z a b l e {


private S t r i n g u r l ;
private S t r i n g l a b e l ;
public void s e t U r l ( S t r i n g u r l ) {
t h i s . u r l=u r l ;
}
public S t r i n g g e t U r l ( ) {
return u r l ;
}

5
6
7
8
9
10

public void s e t L a b e l ( S t r i n g l a b e l ) {
t h i s . l a b e l=l a b e l ;
}
public S t r i n g g e t L a b e l ( ) {
return l a b e l ;
}

12
13
14
15
16
17

public MenuItem ( ) { }
public MenuItem ( S t r i n g u r l , S t r i n g l a b e l ) {
t h i s . u r l=u r l ;
t h i s . l a b e l=l a b e l ;
}

19
20
21
22
23
24

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

import j a v a . u t i l . C o l l e c t i o n ;
import j a v a . u t i l . A r r a y L i s t ;
public c l a s s MenuBean implements j a v a . i o . S e r i a l i z a b l e {
private C o l l e c t i o n <MenuItem> menus ;
public C o l l e c t i o n <MenuItem> getMenus ( ) {
return menus ;
}
public void setMenus ( C o l l e c t i o n <MenuItem> menus ) {
t h i s . menus=menus ;
}
public MenuBean ( ) {
menus=new A r r a y L i s t <MenuItem > ( ) ;
menus . add (new MenuItem ( cmmdcInput . f a c e s , CMMDC automat ) ) ;

58

menus . add (new MenuItem ( cmmdcInput1 . f a c e s , CMMDC manual ) ) ;


menus . add (new MenuItem ( a p p j u d I n p u t . f a c e s , App j u d e t e ) ) ;

16
17

18
19

CAPITOLUL 1. APLICAT
II WEB

O instanta a clasei MenuBean este creat de JSF prin


<managed-bean>
<managed-bean-name>menuBean</managed-bean-name>
<managed-bean-class>MenuBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Acum suntem n masura sa definim componenta view: sideMenu.xhtml pentru


elementul sidemenu definit n sablon.
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 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : //www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : //www. w3 . o r g /1999/ xhtml
x m l n s : u i= h t t p : // j a v a . sun . com/ j s f / f a c e l e t s
x m l n s : f= h t t p : // j a v a . sun . com/ j s f / c o r e
x m l n s : h= h t t p : // j a v a . sun . com/ j s f / html
x m l n s : c= h t t p : // j a v a . sun . com/ j s t l / c o r e >
<u i : c o m p o n e n t>
< !
<c : f o r E a c h v a r=menu i t e m s=#{menuBean . menus} >
>
<c : f o r E a c h v a r=menu i t e m s=#{menus} >
<a h r e f=#{menu . u r l } >#{menu . l a b e l }</ a><br />
</ c : f o r E a c h>
</ u i : c o m p o n e n t>
</ html>

Linia comentata corespunde versiunii fara elementul <ui:param> a fisierului


cmmdcOutput.xhtml, care se modifica n
1
2
3
4
5
6
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 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : //www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : //www. w3 . o r g /1999/ xhtml
x m l n s : u i= h t t p : // j a v a . sun . com/ j s f / f a c e l e t s
x m l n s : h= h t t p : // j a v a . sun . com/ j s f / html >
<u i : c o m p o s i t i o n t e m p l a t e= t e m p l a t e . xhtml >
< u i : d e f i n e name= t i t l e >
<h1> CMMDC R e z u l t a t </ h1>
</ u i : d e f i n e>
< u i : d e f i n e name= sidemenu >
< u i : i n c l u d e s r c= sideMenu . xhtml >
<u i : p a r a m name=menus v a l u e=#{menuBean . menus} />
</ u i : i n c l u d e>
</ u i : d e f i n e>
< u i : d e f i n e name= body >
<h : o u t p u t T e x t v a l u e=Cmmdc= />
<h : o u t p u t T e x t v a l u e=#{cb . s r e s u l t } />
</ u i : d e f i n e>
</ u i : c o m p o s i t i o n>
</ html>

1.3. JAVA SERVER FACES

59

Valoarea menus a atributului name din elementul <ui:param este introdus n randul 14 din fisierul cmmdcOutput.xhtml Fiecare element al colectiei
menuBean.menus genereaza o linie n sideMenu.
Valoarea menu a atributului var din elementul <c:forEach din liniile 11
si 13 din fisierul sideMenu.xhtml contine nregistrarea curenta din colectia care
se parcurge.

1.3.4

Aplicatii JSF cu pagini JSP

Extensia faces a unei ancore este semnalul prin care serverul Web apeleaza JSF si coincide cu declaratia din elementul <url-pattern> din fisierul
web.xml.
Reluam aplicatia dezvoltata mai sus cu pagini JSP pentru partea de view
Exemplul 1.3.2 Calculul celui mai mare divizor comun a doua numere naturale cu verificarea datelor.
Completam codul clasei cmmdc.CmmdcBean cu codul de verificare a datelor
care se injecteaza sm, sn
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

package cmmdc ;
im po rt j a v a x . f a c e s
im po rt j a v a x . f a c e s
im po rt j a v a x . f a c e s
im po rt j a v a x . f a c e s

. a p p l i c a t i o n . FacesMessage ;
. component . UIComponent ;
. context . FacesContext ;
. validator . ValidatorException ;

p u b l i c c l a s s CmmdcBean implements j a v a . i o . S e r i a l i z a b l e {
. . .
p u b l i c v o i d v a l i d a t e S t r i n g ( F a c e s C o n t e x t c o n t e x t , UIComponent component ,
O b j e c t v a l u e ) throws V a l i d a t o r E x c e p t i o n {
i f ( ( c o n t e x t==n u l l ) | | ( component==n u l l ) ) {
throw new N u l l P o i n t e r E x c e p t i o n ( ) ;
}
i f ( value . t o S t r i n g ( ) . trim ( ) . equals ( ) ) {
throw new V a l i d a t o r E x c e p t i o n ( new FacesMessage (
Nu a t i c o m p l e t a t campul ) ) ;
}
else{
S t r i n g s=v a l u e . t o S t r i n g ( ) ;
try {
Long . pa rse Lo ng ( s ) ;
}
c a t c h ( NumberFormatException e ) {
throw new V a l i d a t o r E x c e p t i o n ( new FacesMessage ( Nu e s t e numar ) ) ;
}
}
}
}

Partea de view este data de fisierele JSP


apps.jsp

60

CAPITOLUL 1. APLICAT
II WEB

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

<html>
<body>
<center>
<h1> A p l i c a &#355; i i JSF </h1>
<table border=2>
<tr>
<td>
<a href= / myjsfJSP /cmmdc . j s p >
Cmmdc cu p r e l u a r e automat &#259; a d a t e l o r
</a>
</td>
</ tr>
</ table>
</ center>
</body>
</html>

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

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<h1> C a l c u l u l Cmmdc </h1>
<f : view>
<p>
<h : form >
<h : p a n e l G r i d columns= 3 >
<h : outputText value= Primul numar e s t e />
<h : i n p u t T e x t id=m value=#{cb . sm} r e q u i r e d= t r u e
v a l i d a t o r=#{cb . v a l i d a t e S t r i n g } />
<h : message f o r=m />
<h : outputText value= Al d o i l e a numar e s t e />
<h : i n p u t T e x t id=n value=#{cb . sn } r e q u i r e d= t r u e
v a l i d a t o r=#{cb . v a l i d a t e S t r i n g } />
<h : message f o r=n />
<h : commandButton id= submit value=#{cb . compute }
action=#{cb . compute } />
</h : p a n e l G r i d>
</h : form>
</ f : view> .
</body>
</html>

cmmdcOutput.jsp
1
2
3
4
5
6
7
8
9

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<f : view>
<h : outputText value=Cmmdc = #{cb . s r e s u l t } />
</ f : view>
</body>
</html>

1.3. JAVA SERVER FACES

61

Partea controller (config-faces.xml) are codul


1

? xml v e r s i o n= 1 . 0 e n c o d i n g= UTF8 ?>

<f a c e s c o n f i g xmlns= h t t p : // xmlns . j c p . o r g /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
x s i : s c h e m a L o c a t i o n= h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e /webf a c e s c o n f i g 2 2 . xsd
version= 2 . 2 >

4
5
6
7
9
10
11
12
13
14
15
16
17
19
20
21
22
23
24
25

<n a v i g a t i o n r u l e>
<d e s c r i p t i o n />
<fromviewi d>/cmmdcInput . j s p</ fromviewi d>
<n a v i g a t i o n c a s e>
<d e s c r i p t i o n />
<fromoutcome>OK</ fromoutcome>
<toviewi d>/cmmdcOutput . j s p</ toviewi d>
</ n a v i g a t i o n c a s e>
</ n a v i g a t i o n r u l e>
<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cb</managedbeanname>
<managedbeanc l a s s>cmmdc . CmmdcBean</managedbeanc l a s s>
<managedbeans c o p e> s e s s i o n</managedbeans c o p e>
</managedbean>
</ f a c e s c o n f i g>

In exemplul dat, cadrul de lucru JSF injecteaza valorile celor doua numere
n componenta Java cb. Se pot prelua manual datele direct din formular
prin intermediul variabilei de tip ExternalContext, prin care avem acces la
variabile de tip HttpServletRequest, HttpSession.
ExternalContext context =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request=(HttpServletRequest)context.getRequest();
HttpSession session=(HttpSession)context.getSession(true);
n care caz, n fisierul cmmdcInput.jsp trebuie denumita formularul de preluare
prin
<h:form id="myform" >
Fisierul CmmdcBean.java devine
1
2
3
4
6
7

package cmmdc1 ;
import j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t R e q u e s t ;
import j a v a x . f a c e s . c o n t e x t . F a c e s C o n t e x t ;
import j a v a x . f a c e s . c o n t e x t . E x t e r n a l C o n t e x t ;
public c l a s s CmmdcBean implements j a v a . i o . S e r i a l i z a b l e {
private S t r i n g s r e s u l t ;

62

CAPITOLUL 1. APLICAT
II WEB

public CmmdcBean ( ) { }

9
11

private long cmmdc( long m, long n ) { . . . }

13

public S t r i n g g e t S r e s u l t ( ) {
return s r e s u l t ;
}

14
15

public S t r i n g compute ( ) {
ExternalContext context =
FacesContext . g e t C u r r e n t I n s t a n c e ( ) . getExternalContext ( ) ;
H t t p S e r v l e t R e q u e s t r e q u e s t =( H t t p S e r v l e t R e q u e s t ) c o n t e x t . g e t R e q u e s t ( ) ;
S t r i n g sm = r e q u e s t . g e t P a r a m e t e r ( myform : sm ) ;
S t r i n g sn = r e q u e s t . g e t P a r a m e t e r ( myform : sn ) ;
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
long c=cmmdc(m, n ) ;
s r e s u l t =(new Long ( c ) ) . t o S t r i n g ( ) ;
return OK ;
}

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

Componenta model a aplicatiei de calcul a celui mai mare divizor comun


a doua numere, CmmdcBean contine cod specific problemei dar si cod care
vizeaza JSF. Arhitectura pe care o vom prezenta separa cele doua aspecte:
Partea specifica, adica calculul celui mai mare divizor comun se face
ntr-o clasa POJO (Plain Old Java Object) fara nici o legatura JSF,
CmmdcBean
1
2
3
4
5

package cmmdc . model ;


public c l a s s CmmdcBean implements j a v a . i o . S e r i a l i z a b l e {
private long m=1;
private long n=1;
private long r e s u l t ;

public CmmdcBean ( ) { }

public long getM ( ) {


return m;
}
public void setM ( long m) {
t h i s .m=m;
}

10
11
12
13
14
16
17
18
19
20
21

public long getN ( ) {


return n ;
}
public void setN ( long n ) {
t h i s . n=n ;
}

25

public long g e t R e s u l t ( ) {
return r e s u l t ;
}

27

public void compute ( ) {

23
24

1.3. JAVA SERVER FACES

r e s u l t=cmmdc(m, n ) ;

28

29

private long cmmdc( long m, long n ) { . . . }

31
32

63

Aplicatia JSF interactioneaza cu clasa POJO doar prin intermediul unei


clase controller, CmmdcController
1
2
3
4
5
6
8
9
10
11
12
14
15
16
17
18
19
21
22
23
24
25
26
28
29
30
31
32
33
35
36
37
38
39
40
41
42
44
45
46
47
48
49

ackage
import
import
import
import
import

cmmdc . c o n t r o l l e r ;
j a v a x . f a c e s . component . UIInput ;
j a v a x . f a c e s . component . UIOutput ;
j a v a x . f a c e s . a p p l i c a t i o n . FacesMessage ;
javax . f a c e s . context . FacesContext ;
cmmdc . model . CmmdcBean ;

public c l a s s CmmdcController implements j a v a . i o . S e r i a l i z a b l e {


private CmmdcBean cmmdcBean ;
private UIInput primulNumar ;
private UIInput alDoileaNumar ;
// p r i v a t e UIOutput r e z u l t a t ;
public CmmdcBean getCmmdcBean ( ) {
return cmmdcBean ;
}
public void setCmmdcBean (CmmdcBean cmmdcBean ) {
t h i s . cmmdcBean=cmmdcBean ;
}
public UIInput getPrimulNumar ( ) {
return primulNumar ;
}
public void setPrimulNumar ( UIInput primulNumar ) {
t h i s . primulNumar=primulNumar ;
}
public UIInput getAlDoileaNumar ( ) {
return alDoileaNumar ;
}
public void setAlDoileaNumar ( UIInput alDoileaNumar ) {
t h i s . alDoileaNumar=alDoileaNumar ;
}
/
p u b l i c UIOutput g e t R e z u l t a t ( ) {
return r e z u l t a t ;
}
p u b l i c v o i d s e t R e z u l t a t ( UIOutput r e z u l t a t ) {
t h i s . r e z u l t a t=r e z u l t a t ;
}
/
public S t r i n g cmmdc ( ) {
FacesContext facesContext = FacesContext . g e t C u r r e n t I n s t a n c e ( ) ;
try {
cmmdcBean . compute ( ) ;
// r e z u l t a t . s e t R e n d e r e d ( t r u e ) ;
f a c e s C o n t e x t . addMessage ( null , new FacesMessage (

64

CAPITOLUL 1. APLICAT
II WEB

FacesMessage . SEVERITY INFO , OK , n u l l ) ) ;


}
catch ( E x c e p t i o n e )
{
// r e z u l t a t . s e t R e n d e r e d ( f a l s e ) ;
f a c e s C o n t e x t . addMessage ( null , new FacesMessage (
FacesMessage . SEVERITY ERROR, e . g e t M e s s a g e ( ) , n u l l ) ) ;
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
}
return OK ;

50
51
52
53
54
55
56
57
58

59
60

Varianta comentata corespunde situatiei n care afisarea rezultatului se


face n pagina JSF de preluare a datelor.
Componentele view si controller depind de locul unde are loc afisarea rezultatului:
Afisarea se face n alt fisier JSP decat cel n care se preiau datele.
Componenta view este formata din fisierele cmmdcInput.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<h1> C a l c u l u l Cmmdc </h1>
<f : view>
<p>
<h : form >
<h : p a n e l G r i d columns= 3 >
<h : outputText value= Primul numar e s t e />
<h : i n p u t T e x t id=m r e q u i r e d= t r u e
value=#{cmmdcController . cmmdcBean .m}
b i n d i n g=#{cmmdcController . primulNumar } />
<h : message f o r=m />
<h : outputText value= Al d o i l e a numar e s t e />
<h : i n p u t T e x t id=n r e q u i r e d= t r u e
value=#{cmmdcController . cmmdcBean . n}
b i n d i n g=#{cmmdcController . alDoileaNumar } />
<h : message f o r=n />
<h : commandButton id= submit value= C a l c u l e a z a
action=#{cmmdcController . cmmdc} />
</h : p a n e l G r i d>
</h : form>
</ f : view> .
</body>
</html>

si cmmdcOutput.jsp
1
2
3
4
5

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<f : view>

1.3. JAVA SERVER FACES

6
7
8
9
10

65

<h : outputText value=


Cmmdc = #{cmmdcController . cmmdcBean . r e s u l t } />
</ f : view>
</body>
</html>

Componenta controller - faces-config.xml


1

<?xml version= 1 . 0 e n c o d i n g= UTF8 ?>

<f a c e s c o n f i g xmlns= h t t p : // xmlns . j c p . o r g /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
x s i : s c h e m a L o c a t i o n= h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e /webf a c e s c o n f i g 2 2 . xsd
version= 2 . 2 >

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

<n a v i g a t i o n r u l e>
<d e s c r i p t i o n />
<fromviewi d>/cmmdcInput . j s p</ fromviewi d>
<n a v i g a t i o n c a s e>
<d e s c r i p t i o n />
<fromoutcome>OK</ fromoutcome>
<toviewi d>/cmmdcOutput . j s p</ toviewi d>
</ n a v i g a t i o n c a s e>
</ n a v i g a t i o n r u l e>
<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cmmdcController</managedbeanname>
<managedbeanc l a s s>
cmmdc . c o n t r o l l e r . CmmdcController
</managedbeanc l a s s>
<managedbeans c o p e>r e q u e s t</managedbeans c o p e>
<managedp r o p e r t y>
<p r o p e r t y name>cmmdcBean</ p r o p e r t y name>
<v a l u e>#{cmmdcBean}</ v a l u e>
</managedp r o p e r t y>
</managedbean>
<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cmmdcBean</managedbeanname>
<managedbeanc l a s s>cmmdc . model . CmmdcBean</managedbeanc l a s s>
<managedbeans c o p e>none</managedbeans c o p e>
</managedbean>
</ f a c e s c o n f i g>

Afisarea se face n acelasi fisier JSP n care se preiau datele.


Componenta view este formata din fisierul cmmdc.jsp
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/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<h1> C a l c u l u l Cmmdc </h1>
<f : view>

66

CAPITOLUL 1. APLICAT
II WEB

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

<p>
<h : form >
<h : p a n e l G r i d columns= 3 >
<h : outputText value= Primul numar e s t e />
<h : i n p u t T e x t id=m r e q u i r e d= t r u e
value=#{cmmdcController . cmmdcBean .m}
b i n d i n g=#{cmmdcController . primulNumar } />
<h : message f o r=m />
<h : outputText value= Al d o i l e a numar e s t e />
<h : i n p u t T e x t id=n r e q u i r e d= t r u e
value=#{cmmdcController . cmmdcBean . n}
b i n d i n g=#{cmmdcController . alDoileaNumar } />
<h : message f o r=n />
<h : commandButton id= submit value= C a l c u l e a z a
action=#{cmmdcController . cmmdc} />
</h : p a n e l G r i d>
</h : form>
<h : outputFormat b i n d i n g=#{cmmdcController . r e z u l t a t }
r e n d e r e d= f a l s e >
<h : outputText
value=Cmmdc = #{cmmdcController . cmmdcBean . r e s u l t } />
</h : outputFormat>
</ f : view> .
</body>
</html>

Componenta controller - faces-config.xml


1

<?xml version= 1 . 0 e n c o d i n g= UTF8 ?>

<f a c e s c o n f i g xmlns= h t t p : // xmlns . j c p . o r g /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
x s i : s c h e m a L o c a t i o n= h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : // xmlns . j c p . o r g /xml/ ns / j a v a e e /webf a c e s c o n f i g 2 2 . xsd
version= 2 . 2 >

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

<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cmmdcController</managedbeanname>
<managedbeanc l a s s>
cmmdc . c o n t r o l l e r . CmmdcController
</managedbeanc l a s s>
<managedbeans c o p e>r e q u e s t</managedbeans c o p e>
<managedp r o p e r t y>
<p r o p e r t y name>cmmdcBean</ p r o p e r t y name>
<v a l u e>#{cmmdcBean}</ v a l u e>
</managedp r o p e r t y>
</managedbean>
<managedbean>
<d e s c r i p t i o n />
<managedbeanname>cmmdcBean</managedbeanname>
<managedbeanc l a s s>cmmdc . model . CmmdcBean</managedbeanc l a s s>
<managedbeans c o p e>none</managedbeans c o p e>
</managedbean>
</ f a c e s c o n f i g>

Exemplul 1.3.3 Un fisier text contine informatiile {nume judet, capitala jude-

1.3. JAVA SERVER FACES

67

tului, abrevierea}, separate printr-un spatiu. Se cere construirea unei aplicatii


Web care pentru un judet indicat, afiseaza informatiile corespunzatoare din
fisierul mentionat.
Initializarea aplicatiei consta dintr-o componenta Java CountyBean care
retine informatiile din fisier ntr-o variabila de tip HashMap<String,RefJudet>,
unde RefJudet.java este
1
2
3
4
5

package appjud ;
public c l a s s R e f J u d e t implements j a v a . i o . S e r i a l i z a b l e {
private S t r i n g j u d ;
private S t r i n g c a p i t ;
private S t r i n g a b r e v ;

public R e f J u d e t ( ) { }

public void s e t J u d ( S t r i n g j u d ) {
t h i s . j u d=j u d ;
}

10
11

public S t r i n g getJud ( ) {
return j u d ;
}

13
14
15

public void s e t C a p i t ( S t r i n g c a p i t ) {
t h i s . c a p i t=c a p i t ;
}

17
18
19

public S t r i n g g e t C a p i t ( ) {
return c a p i t ;
}

21
22
23

public void s e t A b r e v ( S t r i n g a b r e v ) {
t h i s . a b r e v=a b r e v ;
}

25
26
27

public S t r i n g getAbrev ( ) {
return a b r e v ;
}

29
30
31
32

Aceasta variabila de tip HashMap este retinuta de sesiunea aplicatiei. Codul


componentei Java CountyBean este
1
2
3
4
5
6
7
8
9
10
11

package appjud ;
import j a v a x . f a c e s . model . S e l e c t I t e m ;
import j a v a . u t i l . A r r a y L i s t ;
import j a v a . u t i l . HashMap ;
import j a v a . u t i l . C o l l e c t i o n ;
import j a v a . i o . InputStream ;
import j a v a . i o . InputStreamReader ;
import j a v a . i o . B u f f e r e d R e a d e r ;
import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n ;
import j a v a x . f a c e s . c o n t e x t . E x t e r n a l C o n t e x t ;
import j a v a x . f a c e s . c o n t e x t . F a c e s C o n t e x t ;

68

13
14

CAPITOLUL 1. APLICAT
II WEB

public c l a s s CountyBean implements j a v a . i o . S e r i a l i z a b l e {


private A r r a y L i s t <S e l e c t I t e m > j u d e t e=n u l l ;

16

private HashMap<S t r i n g , RefJudet> r e f J u d e t e=new HashMap<S t r i n g , RefJudet > ( ) ;

18

public CountyBean ( ) {
j u d e t e=new A r r a y L i s t <S e l e c t I t e m > ( 5 0 ) ;
try {
InputStream f i s =t h i s . g e t C l a s s ( ) . g e t R e s o u r c e A s S t r e a m ( j u d e t e . t x t ) ;
InputStreamReader i s r =new InputStreamReader ( f 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 ) ;
S t r i n g s= , jud , c a p i t , a b r e v ;
do{
s=br . r e a d L i n e ( ) ;
i f ( s != n u l l ) {
S t r i n g [ ] s t=s . s p l i t ( ) ;
j u d=s t [ 0 ] ;
c a p i t=s t [ 1 ] ;
a b r e v=s t [ 2 ] ;
j u d e t e . add (new S e l e c t I t e m ( jud , j u d ) ) ;

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

R e f J u d e t r j=new R e f J u d e t ( ) ;
r j . setJud ( jud ) ;
r j . setCapit ( capit ) ;
r j . setAbrev ( abrev ) ;
r e f J u d e t e . put ( jud , r j ) ;

34
35
36
37
38

}
}
while ( s != n u l l ) ;
E x t e r n a l C o n t e x t c o n t e x t=
FacesContext . g e t C u r r e n t I n s t a n c e ( ) . getExternalContext ( ) ;
H t t p S e s s i o n s e s s i o n =( H t t p S e s s i o n ) c o n t e x t . g e t S e s s i o n ( true ) ;
session . setAttribute ( refJudete , refJudete ) ;
br . c l o s e ( ) ;
isr . close ();
f i s . close ();

39
40
41
42
43
44
45
46
47
48

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

49
50
51
52
53

55

public C o l l e c t i o n <S e l e c t I t e m > g e t J u d e t e ( ) {


return j u d e t e ;
}

56
57
58

Clasa SelectItem din API-ul JSF ofera o modalitate eficienta de completare


a unei componente grafice ComboBox dintr-un document jsp.
Componenta Java care satisface cererea clientului este JudBean.java

package appjud ;
import j a v a . u t i l . HashMap ;
import j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n ;
import j a v a x . f a c e s . c o n t e x t . E x t e r n a l C o n t e x t ;
import j a v a x . f a c e s . c o n t e x t . F a c e s C o n t e x t ;

public c l a s s JudBean implements j a v a . i o . S e r i a l i z a b l e {

1
2
3
4

1.3. JAVA SERVER FACES

10

private S t r i n g j u d=n u l l ;
private S t r i n g c a p i t=n u l l ;
private S t r i n g a b r e v=n u l l ;

12

public JudBean ( ) { }

14

public S t r i n g e x e c u t e ( ) {
ExternalContext context =
FacesContext . g e t C u r r e n t I n s t a n c e ( ) . getExternalContext ( ) ;
H t t p S e s s i o n s e s s i o n =( H t t p S e s s i o n ) c o n t e x t . g e t S e s s i o n ( true ) ;
HashMap<S t r i n g , RefJudet> r e f J u d e t e =
( HashMap<S t r i n g , RefJudet >) s e s s i o n . g e t A t t r i b u t e ( r e f J u d e t e ) ;
R e f J u d e t r j=r e f J u d e t e . g e t ( j u d ) ;
c a p i t=r j . g e t C a p i t ( ) ;
a b r e v=r j . getAbrev ( ) ;
return OK ;
}

8
9

15
16
17
18
19
20
21
22
23
24

public void s e t J u d ( S t r i n g j u d ) {
t h i s . j u d=j u d ;
}

26
27
28

public S t r i n g getJud ( ) {
return j u d ;
}

30
31
32

public S t r i n g g e t C a p i t ( ) {
return c a p i t ;
}

34
35
36

public S t r i n g getAbrev ( ) {
return a b r e v ;
}

38
39
40
41

Fisierele JSP atasate aplicatiei sunt


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

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<head>
< t i t l e> appjud </ t i t l e>
</head>
<body>
<f : view>
<h : outputText value= I n f o r m a t i i d e s p r e j u d e t e />
<br>
<h : form>
<h : outputText value= R e f e r i n t e d e s p r e j u d e t u l : />
<h : selectOneMenu value=#{judBean . j u d } r e q u i r e d= t r u e >
<f : s e l e c t I t e m s value=#{countyBean . j u d e t e } />
</h : selectOneMenu>
<p>
<h : commandButton id= submit value= A f i s e a z a
action=#{judBean . e x e c u t e } />
</h : form>

69

70

CAPITOLUL 1. APLICAT
II WEB

21
22
23

</ f : view>
</body>
</html>

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

<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / html p r e f i x=h %>


<%@ t a g l i b u r i= h t t p : / / j a v a . sun . com/ j s f / c o r e p r e f i x= f %>
<html>
<body>
<f : view>
<h : outputText value= R e f e r i n t e l e d e s p r e j u d e t u l />
<h : outputText value=#{judBean . j u d } />
<p>
<h : outputText value= C a p i t a l a : />
<h : outputText value=#{judBean . c a p i t } />
<p>
<h : outputText value= A b r e v i e r e a : />
<h : outputText value=#{judBean . a b r e v } />
</ f : view>
</body>
</html>

Fisierul config-faces.xml se completeaza cu


<navigation-rule>
<description/>
<from-view-id>/appjudInput.jsp</from-view-id>
<navigation-case>
<description/>
<from-outcome>OK</from-outcome>
<to-view-id>/appjudOutput.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<description/>
<managed-bean-name>countyBean</managed-bean-name>
<managed-bean-class>appjud.CountyBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<description/>
<managed-bean-name>judBean</managed-bean-name>
<managed-bean-class>appjud.JudBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

1.3.5

Componente grafice Primefaces

Biblioteca de componente grafice este declarata, alaturi de marcajele JSF,


prin

71

1.3. JAVA SERVER FACES

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
Un fisier cu componente grafice primefaces va avea extensia xhtml si va avea
structura
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
. . .
</h:head>
<h:body>
. . .
</h:body>
</html>

Componente grafice primefaces:


p:panel Container de componente grafice.
Atribute ale marcajului:
Atribut
id
header
footer

Fel
optional
optional
optional

Descriere
Numele simbolic al elementului.
Textul din antet.
Text subsol.

p:panelGrid Tablou.
Atribute ale marcajului:
Atribut
id
columns
cellpadding

Fel
optional
optional
optional

Descriere
Numele simbolic al elementului.
Numarul coloanelor.
Distanta dintre coloane n pixeli.

p:separator Defineste o linie de separatie.


p:commandButton Buton de comanda.
Atribute ale marcajului:

72

CAPITOLUL 1. APLICAT
II WEB

Atribut
value
actionListener
update

Fel
optional
obligatoriu
optional

Descriere
textul butonului.
Numele actiunii.
Lista componentelor care vor
fi modificate.

p:keyboard Tastatura virtuala de editare.


Atribute ale marcajului:
Atribut Fel
Descriere
id
optional
Numele simbolic al elementului.
value
obligatoriu Campul componentei Java alimentat.
p:ajax Activitate desfasurata de primefaces.
Atribute ale marcajului:
Atribut
Fel
Descriere
event="change" optional Natura actiunii primefaces.
listener
optional Numele actiunii care urmareste
activitatea.
update
optional Lista componentelor care vor
fi modificate.
p:selectOneMenu Camp de alegere a unui optiuni. Multimea optiunilor
este data n elementul <f:selectItems value="sursa"/>
Atribute ale marcajului:
Atribut
id
value
update

Fel
optional
optional
optional

Descriere
Numele simbolic al elementului.
Campul componentei Java alimentat.
Lista componentelor care vor
fi modificate.

Exemplul 1.3.4
Componenta view pentru aplicatia de calcul a celui mai mare divizor comun.
1
2
3
4
5

<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : h= h t t p : / / j a v a . sun . com/ j s f / html

1.3. JAVA SERVER FACES

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

73

xmlns : f= h t t p : / / j a v a . sun . com/ j s f / c o r e


xmlns : p= h t t p : / / p r i m e f a c e s . o r g / u i >
<h : head>
</h : head>
<h : body>
<h1>C a l c u l cmmdc</h1>
<h : form>
<p : p a n e l id= mypanel h e a d e r=CMMDC>
<p : s e p a r a t o r></p : s e p a r a t o r>
<p : p a n e l G r i d columns= 2 cellpadding= 5 >
<h : outputText id= out1 value= Primul numar : ></h : outputText>
<p : keyboard id= key1 value=#{cb . sm} >
<p : a j a x event= change l i s t e n e r=#{cb . v a l i d a t e S m }
update= out0 key1 />
</p : keyboard>
<h : outputText id= out2 value= Al d o i l e a numar : ></h : outputText>
<p : keyboard id= key2 value=#{cb . sn } >
<p : a j a x event= change l i s t e n e r=#{cb . v a l i d a t e S n }
update= out0 key2 />
</p : keyboard>
<p : commandButton value= C a l c u l e a z a ! a c t i o n L i s t e n e r=#{cb . compute }
update= out0 ></p : commandButton>
<h : outputText id= out0 value=#{cb . s r e s u l t } ></h : outputText>
</p : p a n e l G r i d>
</p : p a n e l>
</h : form>
</h : body>
</html>

Exemplul 1.3.5
Componenta view pentru exemplul cu afisarea datelor unui judet.
1
2
3
4
5
6
7
8
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 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : h= h t t p : / / j a v a . sun . com/ j s f / html
xmlns : f= h t t p : / / j a v a . sun . com/ j s f / c o r e
xmlns : p= h t t p : / / p r i m e f a c e s . o r g / u i >
<h : head>
</h : head>
<h : body>
<h1>R e f e r i n &#355; e d e s p r e j u d e t e</h1>
<h : form>
<p : p a n e l h e a d e r= J u d e t e >
<p : p a n e l G r i d columns= 2 cellpadding= 5 >
<h : outputText id= out1 value= J u d e t u l : ></h : outputText>
<p : selectOneMenu value=#{judBean . j u d } id= x2 update= out2 >
<f : s e l e c t I t e m s value=#{countyBean . j u d e t e } />
</p : selectOneMenu>
<p : commandButton value= Cauta ! a c t i o n L i s t e n e r=#{judBean . e x e c u t e }
update= out3 out4 out5 >
</p : commandButton>
<h : outputText id= out6 value= ></h : outputText>
<h : outputText id= out7 value= J u d e t u l ></h : outputText>
<h : outputText id= out3 value=#{judBean . j u d } ></h : outputText>

74

25
26
27
28
29
30
31
32
33

CAPITOLUL 1. APLICAT
II WEB

<h : outputText
<h : outputText
<h : outputText
<h : outputText
</p : p a n e l G r i d>
</p : p a n e l>
</h : form>
</h : body>
</html>

id= out8
id= out4
id= out9
id= out5

value= C a p i t a l a ></h : outputText>


value=#{judBean . c a p i t } ></h : outputText>
value= A b r e v i e r e a ></h : outputText>
value=#{judBean . a b r e v } ></h : outputText>

Inc
arcarea unui fisier - Upload
Exemplul 1.3.6 Aplicatie de ncarcare a unui fisier text (cu extensia txt) de
dimensiune cel mult 1024 de octeti. Fisierul ncarcat va fi afisat.
Solutia bazata pe resursele JSF propriu-zise, utilizand adnotari are codul
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
17
19
20
21
22
23
25
26
27
28
29
30
31
32
33
34
35
36
37

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

j a v a x . f a c e s . a p p l i c a t i o n . FacesMessage ;
j a v a x . f a c e s . bean . ManagedBean ;
j a v a x . f a c e s . bean . ViewScoped ;
j a v a x . f a c e s . bean . RequestScoped ;
j a v a x . f a c e s . component . UIComponent ;
javax . f a c e s . context . FacesContext ;
javax . f a c e s . v a l i d a t o r . ValidatorException ;
j a v a x . s e r v l e t . h t t p . Part ;
j a v a . i o . IOException ;
java . u t i l . ArrayList ;
java . u t i l . List ;
java . u t i l . Scanner ;

import
import
import
import

java .
java .
java .
java .

io
io
io
io

. File ;
. FileOutputStream ;
. OutputStreamWriter ;
. BufferedWriter ;

@ManagedBean ( name= uploadPage )


@RequestScoped
public c l a s s UploadPage {
private Part u p l o a d F i l e ;
private S t r i n g f i l e C o n t e n t ;
public void v a l i d a t e F i l e ( F a c e s C o n t e x t ctx , UIComponent comp , O b j e c t v a l u e ) {
L i s t <FacesMessage> msgs = new A r r a y L i s t <FacesMessage > ( ) ;
Part f i l e = ( Part ) v a l u e ;
i f ( f i l e . g e t S i z e ( ) > 1024) {
msgs . add (new FacesMessage ( f i l e t o o b i g ) ) ;
}
i f ( ! t e x t / p l a i n . e q u a l s ( f i l e . getContentType ( ) ) ) {
msgs . add (new FacesMessage ( not a t e x t f i l e ) ) ;
}
i f ( ! msgs . isEmpty ( ) ) {
throw new V a l i d a t o r E x c e p t i o n ( msgs ) ;
}
}

1.3. JAVA SERVER FACES

public S t r i n g u p l o a d F i l e ( ) throws E x c e p t i o n {
try {
S c a n n e r s c a n n e r=new S c a n n e r ( u p l o a d F i l e . g e t I n p u t S t r e a m ( ) ) ;
S t r i n g B u f f e r sb=new S t r i n g B u f f e r ( ) ;
while ( s c a n n e r . h a s N e x t L i n e ( ) )
sb . append ( s c a n n e r . n e x t L i n e ()+ \n ) ;
f i l e C o n t e n t=sb . t o S t r i n g ( ) ;
}
catch ( IOException e ) {
FacesMessage msg =
new FacesMessage ( FacesMessage . SEVERITY ERROR,
e r r o r uploading f i l e ,
null ) ;
F a c e s C o n t e x t . g e t C u r r e n t I n s t a n c e ( ) . addMessage ( null , msg ) ;
}
S t r i n g myFileName=g e t F i l e n a m e ( u p l o a d F i l e ) ;
F i l e f=new F i l e ( webapps / myjsfUpload / up lo ad / +myFileName ) ;
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 ( f ) ;
OutputStreamWriter osw=new OutputStreamWriter ( f o s ) ;
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 ( osw ) ;
bw . w r i t e ( f i l e C o n t e n t , 0 , f i l e C o n t e n t . l e n g t h ( ) ) ;
bw . c l o s e ( ) ;
osw . c l o s e ( ) ;
fos . close ();
return uploadOutput ;
}

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

public Part g e t U p l o a d F i l e ( ) {
return u p l o a d F i l e ;
}

66
67
68

public void s e t U p l o a d F i l e ( Part u p l o a d F i l e ) {


this . uploadFile = uploadFile ;
}

70
71
72

public S t r i n g g e t F i l e C o n t e n t ( ) {
return f i l e C o n t e n t ;
}

74
75
76

// h t t p : / /www. r a m k i t e c h . com/2013/06/ f i l e upload i s easyinj s f 2 2 . html


private s t a t i c S t r i n g g e t F i l e n a m e ( Part p a r t ) {
f o r ( S t r i n g cd : p a r t . g e t H e a d e r ( c o n t e n t d i s p o s i t i o n ) . s p l i t ( ; ) ) {
i f ( cd . t r i m ( ) . s t a r t s W i t h ( f i l e n a m e ) ) {
String filename =
cd . s u b s t r i n g ( cd . i n d e x O f ( = ) + 1 ) . t r i m ( ) . r e p l a c e ( \ , ) ;
return f i l e n a m e . s u b s t r i n g ( f i l e n a m e . l a s t I n d e x O f ( / ) + 1 ) .
s u b s t r i n g ( f i l e n a m e . l a s t I n d e x O f ( \\ ) + 1 ) ; // MSIE f i x .
}
}
return n u l l ;
}

78
79
80
81
82
83
84
85
86
87
88
89
90

Componente view este alcatuita din fisierele


upload.xhtml
1
2

<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN

75

76

CAPITOLUL 1. APLICAT
II WEB

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

h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >


<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : f= h t t p : / / xmlns . j c p . o r g / j s f / c o r e
xmlns : h= h t t p : / / xmlns . j c p . o r g / j s f / html >
<body>
<f : view>
<h : form id= form e n c t y p e= m u l t i p a r t / formdata >
<h : m e s s a g e s />
<h : p a n e l G r i d columns= 2 >
<h : outputText value= F i l e : />
<h : i n p u t F i l e id= f i l e value=#{uploadPage . u p l o a d F i l e }
v a l i d a t o r=#{uploadPage . v a l i d a t e F i l e } />
</h : p a n e l G r i d>
<h : commandButton value= Upload F i l e
action=#{uploadPage . u p l o a d F i l e } />
</h : form>
</ f : view>
</body>
</html>

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

<? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE html PUBLIC //W3C//DTD XHTML 1 . 0 T r a n s i t i o n a l //EN
h t t p : / /www. w3 . o r g /TR/ xhtml1 /DTD/ xhtml1t r a n s i t i o n a l . dtd >
<html xmlns= h t t p : / /www. w3 . o r g /1999/ xhtml
xmlns : f= h t t p : / / xmlns . j c p . o r g / j s f / c o r e
xmlns : h= h t t p : / / xmlns . j c p . o r g / j s f / html >
<body>
<f : view>
<h : p a n e l G r i d id= c o n t e n t columns= 1 >
<h : outputText value= Content : />
<h : i n p u t T e x t a r e a readonly= t r u e value=#{uploadPage . f i l e C o n t e n t }
rows= 10 c o l s= 100 />
</h : p a n e l G r i d>
</ f : view>
</body>
</html>

1.3.6

JSF dezvoltat prin maven

Aplicatiile dezvoltate corespund celor dezvoltate anterior, calculul celui


mai mare divizor comun (Cmmdc.java) si regasirea datelor unui judet (JudBean.java, ListaJudeteAction.java, RefJudet.java).
Dezvoltarea aplicatiei consta din:
1. Generarea aplicatiei
set
set
set
mvn

GroupID=myjsfFacelets
ArtifactID=myjsf
Version=1.0
-B archetype:generate
-DgroupId=%GroupID%

1.3. JAVA SERVER FACES

-DartifactId=%ArtifactID%
-Dversion=%Version%
-DarchetypeArtifactId=maven-archetype-webapp

2. Se adapteaza structura de cataloage si fisiere la


myjsfFacelets
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|-->
|
|
|
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|--> myjsf
|
|--> cmmdc
|
|
|
CmmdBean.java
|
|--> cmmdc1
|
|
|
CmmdBean.java
|
|--> appjud
|
|
|
JudBean.java
|
|
|
CountyBean.java
|
|
|
RefJudet.java
resources
|
judete.txt
webapp
|--> WEB-INF
|
|
web.xml
|
|
faces-config.xml
|
footerTemplate.html
|
appjudInput.xhtml
|
appjudOutput.xhtml
|
apps.xhtml
|
cmmdcInput.xhtml
|
cmmdcInput1.xhtml
|
cmmdcOutput.xhtml
|
cmmdcOutput1.xhtml
|
sideMenu.xhtml
|
template.xhtml
|
index.html

In clasa CountyBean.java fisierul judete.txt se ncarca prin


InputStream fis=this.getClass().getResourceAsStream("../judete.txt");

3. Fisierul pom.xml se completeaza cu


<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>*.*.*</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>

77

78

CAPITOLUL 1. APLICAT
II WEB

<artifactId>javax.servlet.jsp.jstl</artifactId>
<version>1.2.1</version>
</dependency>

unde *.*.* se nlocuieste cu versiunea JSF folosita.


4. Prelucrarea consta din
(a) mvn clean package
(b) Fisierul war care rezulta se desfasoara n serverul Web.
Observatia 1.3.1
Daca se nlocuiesc resursele jar de JSF de la Oracle cu cele din apache myfaces
atunci programele functioneaza corect fara nici o modificare.
Observatia 1.3.2
Utilizand resursele JSF de la apache myfaces aplicatia JSF este compatibila
cu google appengine.

Capitolul 2
Spring
In prezent exista doua directii majore de realizare a aplicatiilor de tip
enterprise- ntretinerea si utilizarea unei baze de date prin clienti desktop
si/sau Web:
Interfata de programare Java Enterprise Edition (JEE) avand implementari realizate de Oracle si Red Hat - JBoss;
Cadrul de lucru Spring, directie sprijina si de Google.
Cadrul de lucru Spring permite realizarea de asemenea aplicatii care pot fi
executate ntr-un container de servlet si JSP (apache-tomcat, jetty) si nu doar
ntr-un container de aplicatie.
String permite realizarea de legaturi transversale (crosscutting concerns)
ntre componentele unei aplictii prin programare orientata pe aspecte (POA)
(Aspect Oriented Programming - AOP ).
Spring este compus din mai multe module care se pot descarca prin apachemaven.
Spring ofera posibilitatea dezvoltarii unei aplicatii dupa mai multe sabloane
de programare.

2.1

Aplicatie Spring elementar


a

Spring plaseaza o aplicatie ntr-un container virtual prin care intervine


asupra ei prin
Inversarea controlului;
Injectarea dependintelor.
79

80

CAPITOLUL 2. SPRING

Vom dezvolta o aplicatie Spring simpla care ruleaza pe un calculator si n


care punem n evidenta mecanismul injectarea dependintelor prin
generarea unei componente Java (POJO bean) instantiata de containerul
Spring n urma datelor dintr-un fisier de configurare sau prin mecanismul
adnotarii si nu de catre programator;
furnizarea (injectarea) valorii unui parametru componentei amintita anterior.
Exemplul 2.1.1 Aplicatie care afiseaza un mesaj.
Componenta Java (POJO) are codul
1
2
3
4
5
6

package h e l l o ;
public c l a s s HelloWorld {
private S t r i n g message ;
public void s e t M e s s a g e ( S t r i n g message ) {
t h i s . message = message ;
}
public S t r i n g s a y H e l l o ( ) {
return H e l l o ! + message ;
}

8
9
10
11

Injectarea valorii parametrului message se face de catre containerul Spring.


String ofera mai multe moduri pentru instantierea si utilizarea componentei
Java. Fiecare mod de procesare necesita resurse Spring specifice.
1. Varianta cu fisier de configurare si utilizand interfata ApplicationContext
Clasa cu metoda main a aplicatiei apeleaza resursele cadrului de lucru
Spring pentru crearea containerului si regasirea componentei Java identificata prin numele ei helloWorld.
1
2
3
4
6
7
8
9
10
11
12
13
14

package h e l l o ;
import o r g . s p r i n g f r a m e w o r k . c o n t e x t . A p p l i c a t i o n C o n t e x t ;
import o r g . s p r i n g f r a m e w o r k . c o n t e x t . s u p p o r t . C l a s s P a t h X m l A p p l i c a t i o n
Context ;
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 ) {
ApplicationContext context =
new C l a s s P a t h X m l A p p l i c a t i o n C o n t e x t ( HelloWorld . xml ) ;
HelloWorld h e l l o W o r l d=
( HelloWorld ) c o n t e x t . getBean ( HelloWorldBean ) ;
System . out . p r i n t l n ( h e l l o W o r l d . s a y H e l l o ( ) ) ;
}
}

Fisierul de configurare (HelloWorld.xml ) este


2.1. APLICAT
IE SPRING ELEMENTARA

1
2
3
4
5
6
8
9
10
11

81

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
<beans xmlns= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / schema / beans
xmlns : x s i= h t t p : / /www. w3 . o r g /2001/XMLSchemai n s t a n c e
xmlns : aop= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / schema / aop
x s i : s c h e m a L o c a t i o n= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / schema / beans
h t t p : / /www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 3 . 0 . xsd >
<bean i d= HelloWorldBean c l a s s= h e l l o . HelloWorld >
<p r o p e r t y name= message v a l u e=Cum va p l a c e S p r i n g ? />
</bean>
</beans>

Desfasurarea aplicatiei este


hello
|
HelloWorld.class
|
Main.class
HelloWorld.xml

iar variabila de sistem classpath contine referintele catre


spring-core-*.jar
spring-context-*.jar
spring-expression-*.jar
spring-beans-*.jar
commons-logging-*.jar
2. Varianta cu fisier de configurare si utilizand interfata XmlBeanFactory
Utilizand acelasi fisier de configurare HelloWorld.xml si aceleasi resurse
jar, clasa cu metoda main are codul
1
2
3
5
6
7
8
9
10
11
12
13

package h e l l o ;
import o r g . s p r i n g f r a m e w o r k . beans . f a c t o r y . xml . XmlBeanFactory ;
import o r g . s p r i n g f r a m e w o r k . c o r e . i o . C l a s s P a t h R e s o u r c e ;
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 ) {
XmlBeanFactory b e a n F a c t o r y =
new XmlBeanFactory (new C l a s s P a t h R e s o u r c e ( HelloWorld . xml ) ) ;
HelloWorld myBean =
( HelloWorld ) b e a n F a c t o r y . getBean ( HelloWorldBean ) ;
System . out . p r i n t l n ( myBean . s a y H e l l o ( ) ) ;
}
}

3. Varianta cu adnotare
Responsabil de instantierea componentei Java si de injectarea n campul
message este clasa

82

CAPITOLUL 2. SPRING

1
2
3
5
6
7
8
9
10
11
12

package h e l l o ;
import o r g . s p r i n g f r a m e w o r k . c o n t e x t . a n n o t a t i o n . Bean ;
import o r g . s p r i n g f r a m e w o r k . c o n t e x t . a n n o t a t i o n . C o n f i g u r a t i o n ;
@Configuration
public c l a s s H e l l o W o r l d C o n f i g {
public @Bean HelloWorld h e l l o W o r l d ( ) {
HelloWorld bean=new HelloWorld ( ) ;
bean . s e t M e s s a g e ( Cum va p l a c e S p r i n g ? ) ;
return bean ;
}
}

Clasa Main este


1
2
3
5
6
7
8
9
10
11
12

package h e l l o ;
import o r g . s p r i n g f r a m e w o r k . c o n t e x t . a n n o t a t i o n . A n n o t a t i o n C o n f i g
ApplicationContext ;
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 ) {
AnnotationConfigApplicationContext context =
new A n n o t a t i o n C o n f i g A p p l i c a t i o n C o n t e x t ( H e l l o W o r l d C o n f i g . c l a s s ) ;
HelloWorld myBean = ( HelloWorld ) c o n t e x t . getBean ( h e l l o W o r l d ) ;
System . out . p r i n t l n ( myBean . s a y H e l l o ( ) ) ;
}
}

Resursele necesare sunt


spring-aop-*.jar
spring-beans-*.jar
spring-core-*.jar
spring-context-*.jar
spring-expression-*.jar
commons-logging-*.jar

2.2

Dezvoltarea unei aplicatii MVC Spring

Introducem construirea unei aplicatii Web cu Spring MCV prin exemple


utilizand un sablon.
Exemplul 2.2.1 Aplicatie care afiseaza un mesaj si data calendaristica.
Fixam doi parametrii:
Numele aplicatiei coincide cu contexul aplicatiei (numele arhiver war=catalogul
aplicatiei n serverul Web):
helloworld

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

83

Parametrul de legatura cu metoda/metodele clasei control:


hw
Aplicatia se va lansa prin index.jsp:
1

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>

<c : r e d i r e c t u r l= /hw . htm />

Extensia htm - modificabila - este recunoscuta de serverul Web prin continutul


fisierului web.xml ca lansare a unei aplicatii Spring. In continuare controlul
este preluat de Spring prin servlet-ul org.springframework.web.servlet.DispatcherServlet.
Fisierul web.xml corespunzator servlet-ului are codul
1
2
3
4
5
6
8
9
10
11
12
13
14
16
17
18
19
21
22
23
25

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp version= 2 . 4
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 >
< s e r v l e t>
<s e r v l e t name>h e l l o w o r l d</ s e r v l e t name>
<s e r v l e t c l a s s>
o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . D i s p a t c h e r S e r v l e t
</ s e r v l e t c l a s s>
<l o a d ons t a r t u p>1</ l o a d ons t a r t u p>
</ 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 w o r l d</ s e r v l e t name>
<u r l p a t t e r n> . htm</ u r l p a t t e r n>
</ s e r v l e t mapping>
<welcomef i l e l i s t>
<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>

Parametrul din servlet-name trebuie sa coincida cu numele aplicatiei.


Numele aplicatiei contribuie la fixarea denumirii unui fisier de configurare
prin
numele aplicatiei -servlet.xml
In cazul de fata helloworld-servlet.xml:
1
2
3
4
5

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<beans xmlns= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
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 m l n s : p= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /p
x m l n s : c o n t e x t= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t

84

x s i : s c h e m a L o c a t i o n= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans


h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t / s p r i n g c o n t e x t 3 . 0 . xsd >

6
7
8
9

<bean name= / h e l l o w o r l d . htm


c l a s s= h e l l o w o r l d . web . H e l l o W o r l d C o n t r o l l e r />

11
12

<bean i d= v i e w R e s o l v e r c l a s s=
o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . I n t e r n a l R e s o u r c e V i e w R e s o l v e r >

14
15
17
18
19
20

CAPITOLUL 2. SPRING

<p r o p e r t y name= p r e f i x v a l u e= /WEBINF/ j s p / />


<p r o p e r t y name= s u f f i x v a l u e= . j s p />
</ bean>
</ beans>

Prin acest fisier de configurare Spring recunoaste clasa controller care participa
la generarea view -ului.
In liniile 11-12 se precizeaza clasa controller.
In liniile 14-15 se precizeaza clasa responsabila cu legatura cu fisierele view.
In liniile 17-18 se precizeaza locatia (prefix ) si extensia (suffix ) fisierelor
view.
Astfel serverul Web si Spring determin
a clasa controller din
fisierul de configurare iar metoda care satisface cererea din clasa
controller prin parametrul de leg
atur
a.
Clasa controller, HelloWorldController, are codul
1
2
3
4
5
7
8

package h e l l o w o r l d . web ;
import j a v a . i o . IOException ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;
@Controller
public c l a s s H e l l o W o r l d C o n t r o l l e r {
@RequestMapping ( /hw . htm )
public ModelAndView h a n d l e R e q u e s t ( ) {
ModelAndView modelAndView = new ModelAndView ( h e l l o ) ;
modelAndView . addObject ( message , H e l l o World MVC! ) ;
modelAndView . addObject ( d a t e , (new j a v a . u t i l . Date ( ) ) . t o S t r i n g ( ) ) ;
return modelAndView ;
}

10
11
12
13
14
15
16
17

unde
/hm.htm: Parametrul de legatura cu metoda clasei controller ;
hello: Denumirea fisierului view ;
message, date: campuri din view ce urmeaza a fi completate.

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

85

Clasa org.springframework.web.servlet.ModelAndView fixeaza view -ul


care trebuie redat, mpreuna cu datele aferente.
Constructori:
public ModelAndView(String viewName)
public ModelAndView(String viewName, String modelName, Object
modelObject)
Metode:
public ModelAndView addObject(String attributeName, Object attributeValue)
Componenta view a aplicatiei Web este o pagina JSP (hello.jsp) avand
codul
1

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>

<html>
<body>
<h1><c : out value= $ { message } /></h1>
<p> Date <c : out value= $ { d a t e } /> </p>
<a href=<c : u r l v a l u e= h e l l o w o r l d . htm/>>R e l u a r e</a>
</body>
</html>

4
5
6
7
8
9

Desfasurarea aplicatiei n serverul Web este


helloworld
|--> WEB-INF
|
|--> classes
|
|
|--> helloworld
|
|
|
|--> web
|
|
|
|
|
HelloWorldController.class
|
|--> jsp
|
|
|
hello.jsp
|
|--> lib
|
|
|
spring-web-*.jar
|
|
|
spring-web.servlet-*.jar
|
|
|
spring-expression-*.jar
|
|
|
spring-core-*.jar
|
|
|
spring-context-*.jar
|
|
|
spring-beans-*.jar
|
|
|
spring-aop-*.jar
|
|
|
taglib-standard-spec-*.jar
|
|
|
taglib-standard-impl-*.jar
|
|
|
commons-logging-*.jar
|
|
helloworld-servlet.xml
|
|
web.xml
|
index.jsp

86

CAPITOLUL 2. SPRING

Aplicatie Spring cu formular de introducere date


Exemplul 2.2.2 Extindem aplicatia anterioara prin afisarea mesajului Hi+nume,
unde parametrul nume se preia dintr-un formular.
Parametrii aplicatiei sunt:
Numele aplicatiei: helloname;
Parametrul de legatura cu metoda/metodele clasei control: newname.
Partea unei aplicatii Spring gestionata de un Controller o vom numi cadru.
Aplicatia dintr-un singur cadru: datele dintr-un formular sunt preluate
de clasa controller si trimise componentei view - data de aceasi pagina JSP,
hello.jsp 1 .
Activitatile de executat vor fi programate n spatele unei fatade alcatuita
din doua cataloage model (sau domain) si service:
In catalogul model se scriu componentele Java care acopera datele cu
care se opereaza;
In catalogul service se scriu clasele care realizeaza prelucrarile propriuzise (opereaza asupra unor obiecte de tipul claselor din catalogul model ).
Pentru exemplu, catalogul model contine clasa helloname.model.Nume.java
1

package h e l l o n a m e . model ;

public c l a s s Nume{
private S t r i n g nume= ;

public void setNume ( S t r i n g nume ) {


t h i s . nume=nume ;
}

6
7
8

public S t r i n g getNume ( ) {
return nume ;
}

10
11
12
13

iar catalogul service contine clasa helloname.service.NumeManager.java


1
2
4
5

package h e l l o n a m e . s e r v i c e ;
import h e l l o n a m e . model . Nume ;
public c l a s s NumeManager{
private Nume name=n u l l ;
1

Cu adaptarea corespunzatoare a adresei continute n ancora <a> .

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

public void setName (Nume name ) {


t h i s . name=name ;
}

7
8
9

public S t r i n g s a y H e l l o ( ) {
return Hi +name . getNume ( ) ;
}

11
12
13
14

Desfasurarea aplicatiei n serverul Web va fi


helloname
|--> WEB-INF
|
|--> classes
|
|
|--> helloname
|
|
|
|--> model
|
|
|
|
|
Nume.class
|
|
|
|--> service
|
|
|
|
|
NumeManager.class
|
|
|
|--> web
|
|
|
|
|
HelloNameController.class
|
|--> jsp
|
|
|
hello.jsp
|
|
|
nameForm.jsp
|
|--> lib
|
|
|
spring-web-*.jar
|
|
|
spring-web.servlet-*.jar
|
|
|
spring-expression-*.jar
|
|
|
spring-core-*.jar
|
|
|
spring-context-*.jar
|
|
|
spring-beans-*.jar
|
|
|
spring-aop-*.jar
|
|
|
taglib-standard-spec-*.jar
|
|
|
taglib-standard-impl-*.jar
|
|
|
commons-logging-*.jar
|
|
helloname-servlet.xml
|
|
web.xml
|
index.jsp

Codul clasei HelloNameController este


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

package h e l l o n a m e . web ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import h e l l o n a m e . model . Nume ;
import h e l l o n a m e . s e r v i c e . NumeManager ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . S e s s i o n A t t r i b u t e s ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . M o d e l A t t r i b u t e ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMethod ;
import o r g . s p r i n g f r a m e w o r k . u i . ModelMap ;
@Controller
public c l a s s H e l l o N a m e C o n t r o l l e r {
//VARIANTA 1 p e n t r u prima p a g i n a :
// prima p a g i n a ( i n c a z a p e l GET)
/

87

88

CAPITOLUL 2. SPRING

@RequestMapping ( v a l u e = /newname . htm , method = RequestMethod .GET)


p u b l i c ModelAndView metodaPrimaPagina ( ) {
Nume nume=new Nume ( ) ;
nume . setNume ( H e l l o World MVC! ) ;

18
19
20
21

ModelAndView modelAndView = new ModelAndView (nameForm ) ;


modelAndView . a d d O b j e c t (command , nume ) ;
// daca i n JSP nu s e s p e c i f i c a numele v a r i a b i l e i command ,
// i m p l i c i t e command
r e t u r n modelAndView ;

23
24
25
26
27

}
/

28
29

//VARIANTA 2 p e n t r u prima p a g i n a :
// prima p a g i n a ( i n c a z a p e l GET)
@RequestMapping ( v a l u e = /newname . htm , method = RequestMethod .GET)
public S t r i n g metodaPrimaPagina ( ModelMap modelMap ) {
Nume nume=new Nume ( ) ;
nume . setNume ( H e l l o World MVC! ) ;

31
32
33
34
35
36

modelMap . a d d A t t r i b u t e ( command , nume ) ;


// daca i n JSP nu s e s p e c i f i c a numele v a r i a b i l e i command ,
// i m p l i c i t e command
return nameForm ;

38
39
40
41
42

44

// a 2a p a g i n a ( i n c a z a p e l POST)
@RequestMapping ( v a l u e = /newname . htm , method = RequestMethod . POST)
public ModelAndView metodaADouaPagina ( @ModelAttribute ( command )
Nume nume ) {
NumeManager nm=new NumeManager ( ) ;
nm . setName ( nume ) ;

45
46
47
48
49

S t r i n g myMessage = nm . s a y H e l l o ( ) ;
S t r i n g myDate=(new j a v a . u t i l . Date ( ) ) . t o S t r i n g ( ) ;

51
52

ModelAndView modelAndView = new ModelAndView ( h e l l o ) ;


modelAndView . addObject ( message , myMessage ) ;
modelAndView . addObject ( d a t e , myDate ) ;
return modelAndView ;

54
55
56
57

58
59

Liniile 20-21, respectiv 35-36, completeaza campul nume din formularul


view nameForm.jsp instantiind totodata un obiect model.
Dupa completarea formularului de utilizator si returnarea prin POST se
instantiaza un obiect service care completeaza raspunsul.
Campul value=/newname.htm din adnotarea RequestMapping se poate
declara global prin RequestMapping(/newname.htm) pus naintea liniei 13.
Fisierul de configurare al aplicatiei Spring, helloname-servlet.xml este
1

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>

<beans xmlns= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans


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

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

5
6
7
8
9
10
11
12
14
15
16
18
19
21
22
23
24
25
26
27
28

89

x m l n s : c o n t e x t= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
xmlns:mvc= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc
x s i : s c h e m a L o c a t i o n= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc/ s p r i n g mvc 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t / s p r i n g c o n t e x t 3 . 0 . xsd >
< ! Scaneaza c l a s s p a t h p e n t r u c l a s e a d n o t a t e cu @Components
p t a f i i n r e g i s t r a t e ca beanu r i >
<c o n t e x t : c o m p o n e n t s c a n basepackage= h e l l o n a m e />
< ! A c t i v e a z a a d n o t a r i d i n c o n t r o l e r e , a d n o t a r i v a l i d a r e e t c >
<m v c : a n n o t a t i o n d r i v e n />
<bean i d= v i e w R e s o l v e r c l a s s=
o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . I n t e r n a l R e s o u r c e V i e w R e s o l v e r >
<p r o p e r t y name= v i e w C l a s s
v a l u e= o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . J s t l V i e w />
<p r o p e r t y name= p r e f i x v a l u e= /WEBINF/ j s p / />
<p r o p e r t y name= s u f f i x v a l u e= . j s p />
</ bean>
</ beans>

Aplicatia lansata din index.jsp


1

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>

<c : r e d i r e c t u r l= /newname . htm />

ncarca pagina de introducere date (nameForm.jsp)


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

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>


<%@ t a g l i b p r e f i x= form u r i= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / t a g s / form %>
<html>
<body>
<h1>A p l i c a t i e S p r i n g cu f o r m u l a r p e n t r u d a t e</h1>
<form : form method= p o s t >
<p/> I n t r o d u c e t i numele :
<form : input path=nume />
<input type= submit value= Submit >
</form : form>
</body>
</html>

Atributul path a elementului <form:input> precizeaza campul componentei


Java care va fi completat cu data introdusa.
Pagina de afisare a rezultatelor (hello.jsp) este analoaga cu cea de la aplicatia
helloworld.
Consideram acum cazul aplicatiei cu doua cadre, fiecare cadru avand propriul controller. Arhitectura pune n evidenta mecanismul de transmitere a
datelor ntre doua cadre.

90

CAPITOLUL 2. SPRING

Clasa model (Nume.java), clasa service (NumeManager ) cat si fisierele view


(nameForm.jsp, hello.jsp) raman nemodificate.
Fisierul de configurare este
1

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>

<beans xmlns= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans


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 m l n s : c o n t e x t= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
xmlns:mvc= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc
x s i : s c h e m a L o c a t i o n= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /mvc/ s p r i n g mvc 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t / s p r i n g c o n t e x t 3 . 0 . xsd >

4
5
6
7
8
9
10
11
12

15
16
17
19
20
22
23
24
25
26
27
28
30
31

< ! Scaneaza c l a s s p a t h p e n t r u c l a s e a d n o t a t e cu @Components p t r .


a f i i n r e g i s t r a t e ca beanu r i >
<c o n t e x t : c o m p o n e n t s c a n basepackage= h e l l o n a m e />
< ! A c t i v e a z a a d n o t a r i d i n c o n t r o l e r e , a d n o t a r i v a l i d a r e e t c >
<m v c : a n n o t a t i o n d r i v e n />
<bean i d= v i e w R e s o l v e r c l a s s=
o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . I n t e r n a l R e s o u r c e V i e w R e s o l v e r >
<p r o p e r t y name= v i e w C l a s s
v a l u e= o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . J s t l V i e w />
<p r o p e r t y name= p r e f i x v a l u e= /WEBINF/ j s p / />
<p r o p e r t y name= s u f f i x v a l u e= . j s p />
</ bean>
<bean i d=numeManager c l a s s= h e l l o n a m e . s e r v i c e . NumeManager />
</ beans>

Clasele controler sunt:


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

package h e l l o n a m e . web ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . R e d i r e c t V i e w ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import o r g . s p r i n g f r a m e w o r k . beans . f a c t o r y . a n n o t a t i o n . Autowired ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . M o d e l A t t r i b u t e ;
import o r g . s p r i n g f r a m e w o r k . u i . ModelMap ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMethod ;
import h e l l o n a m e . model . Nume ;
import h e l l o n a m e . s e r v i c e . NumeManager ;
@Controller
@RequestMapping ( /newname1 . htm )
public c l a s s F i r s t N a m e C o n t r o l l e r {
@Autowired
private NumeManager nm ;
@RequestMapping ( method = RequestMethod .GET)
public ModelAndView m e t o d a C e r e r e I n i t i a l a ( ) {

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

Nume nume=new Nume ( ) ;


nume . setNume ( H e l l o World MVC! ) ;
ModelAndView modelAndView=new ModelAndView ( nameForm ) ;
modelAndView . addObject ( command , nume ) ;
return modelAndView ;

21
22
23
24
25
26

28

@RequestMapping ( method = RequestMethod . POST)


public ModelAndView metodaDupaSubmit ( @ModelAttribute ( command )
Nume nume ) {
System . out . p r i n t l n ( nume . getNume ( ) ) ;
nm . setName ( nume ) ;
return new ModelAndView (new R e d i r e c t V i e w ( newname2 . htm ) ) ;
}

29
30
31
32
33
34
35

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

package h e l l o n a m e . web ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import o r g . s p r i n g f r a m e w o r k . beans . f a c t o r y . a n n o t a t i o n . Autowired ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMethod ;
import h e l l o n a m e . s e r v i c e . NumeManager ;
@Controller
@RequestMapping ( /newname2 . htm )
public c l a s s S e co n d Na m e Co n t ro l l er {
@Autowired
private NumeManager nm ;
@RequestMapping ( method = RequestMethod .GET)
public ModelAndView metoda ( ) {
S t r i n g myMessage = nm . s a y H e l l o ( ) ;
S t r i n g myDate=(new j a v a . u t i l . Date ( ) ) . t o S t r i n g ( ) ;
ModelAndView modelAndView = new ModelAndView ( h e l l o ) ;
modelAndView . addObject ( message , myMessage ) ;
modelAndView . addObject ( d a t e , myDate ) ;
return modelAndView ;
}

15
16
17
18
19
20
21
22
23
24

91

Datele care se transmit ntre componentele controller ale celor


dou
a straturi sunt fixate n c
ampuri ale componentei Java (NumeManager.java).
Exemplul 2.2.3 Aplicatie Spring de calcul a celui mai mare divizor comun a
doua numere.
Aplicatia va fi cu un singur cadru si n plus se vor valida datele introduse.
Parametrii aplicatiei sunt:
Numele aplicatiei: cmmdc;

92

CAPITOLUL 2. SPRING

Parametrul de legatura cu metoda/metodele clasei control: cmmdcdata.


Modelul aplicatiei este dat de clasa cmmdc.model.DouaNumere
1

package cmmdc . model ;

public c l a s s DouaNumere{
private S t r i n g sm= ;
private S t r i n g sn= ;

4
5

public void setSm ( S t r i n g sm ) {


t h i s . sm=sm ;
}
public S t r i n g getSm ( ) {
return sm ;
}

7
8
9
10
11
12

public void s e t S n ( S t r i n g sn ) {
t h i s . sn=sn ;
}
public S t r i n g getSn ( ) {
return sn ;
}

14
15
16
17
18
19
20

Clasa service cmmdc.service.CmmdcManager consta din


1
2
4
5

package cmmdc . s e r v i c e ;
import cmmdc . model . DouaNumere ;
public c l a s s CmmdcManager{
private DouaNumere data=n u l l ;
public void s e t D a t a ( DouaNumere data ) {
t h i s . data=data ;
}

7
8
9

public S t r i n g cmmdcService ( ) {
long m=Long . par se Lon g ( data . getSm ( ) ) ;
long n=Long . p ars eL ong ( data . getSn ( ) ) ;
return (new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ;
}

11
12
13
14
15

private long cmmdc( long m, long n ) { . . . }

17
18

Controller -ul este dat declasa controller, cmmdc.web.CmmdcController:


1
2
3
4
5
6
7
8
9
10
11

package cmmdc . web ;


import cmmdc . model . DouaNumere ;
import cmmdc . s e r v i c e . CmmdcManager ;
import cmmdc . s e r v i c e . DouaNumereValidator ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import o r g . s p r i n g f r a m e w o r k . u i . ModelMap ;
import o r g . s p r i n g f r a m e w o r k . u i . Model ;
import o r g . s p r i n g f r a m e w o r k . v a l i d a t i o n . B i n d i n g R e s u l t ;
import o r g . s p r i n g f r a m e w o r k . beans . f a c t o r y . a n n o t a t i o n . Autowired ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMethod ;

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

12
13
14
16
17
18
19
20
21
22
23
24
25
26
27

import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;


import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . M o d e l A t t r i b u t e ;
import o r g . s p r i n g f r a m e w o r k . v a l i d a t i o n . E r r o r s ;
@Controller
@RequestMapping ( /cmmdcdata . htm )
public c l a s s CmmdcController {
// prima p a g i n a ( a p e l GET)
@RequestMapping ( method = RequestMethod .GET)
protected S t r i n g m e t o d a I n i t i a l a ( ModelMap modelMap ) {
DouaNumere data=new DouaNumere ( ) ;
data . setSm ( 1 ) ;
data . s e t S n ( 1 ) ;
modelMap . a d d A t t r i b u t e ( command , data ) ;
return dataForm ;
}
// dupa s u b m i t ( a p e l POST)
@RequestMapping ( method = RequestMethod . POST)
protected ModelAndView metodaDupaSubmit ( Model model ,
@ModelAttribute ( command ) DouaNumere data , B i n d i n g R e s u l t r e s u l t ) {
DouaNumereValidator v a l i d a t o r=new DouaNumereValidator ( ) ;
v a l i d a t o r . v a l i d a t e ( data , r e s u l t ) ;
i f ( r e s u l t . hasErrors ()){
ModelAndView mv = new ModelAndView ( dataForm ) ;
return mv ;
}
CmmdcManager cm=new CmmdcManager ( ) ;
cm . s e t D a t a ( data ) ;
S t r i n g myMessage=cm . cmmdcService ( ) ;
ModelAndView modelAndView = new ModelAndView ( cmmdc ) ;
modelAndView . addObject ( message , myMessage ) ;
modelAndView . addObject ( sm , data . getSm ( ) ) ;
modelAndView . addObject ( sn , data . getSn ( ) ) ;
return modelAndView ;
}

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

Formularul de introducere a datelor (dataForm.jsp) este


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

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>


<%@ t a g l i b p r e f i x= form
u r i= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / t a g s / form %>
<html>
<body>
<h1>Cmmdc A p l i c a t i e S p r i n g </h1>
<form : form method= p o s t >
<t a b l e b o r d e r= 1 >
<t r >
<td> Primul numar </td>
<td> <form : i n p u t path=sm/> </td>
<td> <form : e r r o r s path=sm/> </td>
</td>
</t r >
<t r >
<td> Al d o i l e a numar </td>
<td> <form : i n p u t path= sn /> </td>

93

94

20
21
22
23
24
25
26
27
28
29
30

CAPITOLUL 2. SPRING

<td> <form : e r r o r s path= sn /> </td>


</t r >
<t r >
<td/>
<td><i n p u t t y p e= submit v a l u e= C a l c u l e a z a ></td>
<td/>
</t r >
</ t a b l e >
</form : form>
</body>
</html>

si pagina JSP de afisare a rezultatului (cmmdc.jsp) este


1

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>

<html>
<body>
<h1> C a l c u l u l c e l u i mai mare d i v i z o r comun </h1>
<p>
Cmmdc(<c : out value= $ {sm} /> ,<c : out value= $ { sn } />)=
<c : out value= $ { message } />
</p>
</body>
</html>

4
5
6
7
8
9
10
11

Fisierul de configurare cmmdc-servlet.xml


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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<beans xmlns= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
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 m l n s : p= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema /p
x m l n s : c o n t e x t= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
x s i : s c h e m a L o c a t i o n= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 3 . 0 . xsd
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / c o n t e x t / s p r i n g c o n t e x t 3 . 0 . xsd >
<bean name= /cmmdcdata . htm c l a s s=cmmdc . web . CmmdcController >
<p r o p e r t y name= commandClass v a l u e=cmmdc . model . DouaNumere />
<p r o p e r t y name= formView v a l u e= dataForm />
<p r o p e r t y name= v a l i d a t o r >
<bean c l a s s=cmmdc . s e r v i c e . DouaNumereValidator />
</ p r o p e r t y>
</ bean>
<bean i d= v i e w R e s o l v e r c l a s s=
s p r i n g .web . s e r v l e t . view . I n t e r n a l R e s o u r c e V i e w R e s o l v e r >
<p r o p e r t y name= v i e w C l a s s
v a l u e= o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . J s t l V i e w />
<p r o p e r t y name= p r e f i x v a l u e= /WEBINF/ j s p / />
<p r o p e r t y name= s u f f i x v a l u e= . j s p />
</ bean>
</ beans>

Validarea datelor este declarata prin proprietatea validator, precizand si


clasa care realizeaza validarea. Mai mult, formularul de introducere date are
elementul <form:errors> pentru afisarea mesajelor de eroare.

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

95

Clasa care realizeaza validarea (cmmdc.service.DouaNumereValidator ) are


codul

package cmmdc . s e r v i c e ;
import o r g . s p r i n g f r a m e w o r k . v a l i d a t i o n . V a l i d a t o r ;
import o r g . s p r i n g f r a m e w o r k . v a l i d a t i o n . E r r o r s ;
import cmmdc . model . DouaNumere ;

public c l a s s DouaNumereValidator implements V a l i d a t o r {

1
2
3

public boolean s u p p o r t s ( C l a s s c l a z z ) {
return DouaNumere . c l a s s . e q u a l s ( c l a z z ) ;
}

8
9
10

public void v a l i d a t e ( O b j e c t obj , E r r o r s e r r o r s ) {


DouaNumere data = ( DouaNumere ) o b j ;
S t r i n g sm=data . getSm ( ) ;
i f ( ( sm == n u l l ) | | ( sm . e q u a l s ( ) ) ) {
e r r o r s . r e j e c t V a l u e ( sm , null , Camp n e c o m p l e t a t ) ;
}
else {
try {
long m=Long . par se Lo ng ( sm ) ;
}
catch ( NumberFormatException e ) {
e r r o r s . r e j e c t V a l u e ( sm , null , Nu e s t e numar ) ;
}
}
S t r i n g sn=data . getSn ( ) ;
i f ( ( sn == n u l l ) | | ( sn . e q u a l s ( ) ) ) {
e r r o r s . r e j e c t V a l u e ( sn , null , Camp n e c o m p l e t a t ) ;
}
else {
try {
long n=Long . p ars eL ong ( sn ) ;
}
catch ( NumberFormatException e ) {
e r r o r s . r e j e c t V a l u e ( sn , null , Nu e s t e numar ) ;
}
}
}

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

Cele doua metode, supports, validate sunt declarate de interfata Validator.


Exemplul 2.2.4 Un fisier text contine informatiile {nume judet, capitala judetului,
abrevierea}, separate printr-un spatiu. Se cere construirea unei aplicatii Web
care pentru un judet indicat, afiseaza informatiile corespunzatoare din fisierul
mentionat.
Elementul de noutate care va fi introdus de aceasta aplicatie este caseta
ComboBox din formularul de introducere date si care va fi alimentat cu optiuni
de clasa controller.
Parametrii aplicatiei:

96

CAPITOLUL 2. SPRING

Numele aplicatiei: judete;


Parametrul de legatura cu metoda/metodele clasei control: judete.
Arhitectura aplicatiei este ntr-un singur cadru.
Modelul aplicatiei este (judete.model.Judet)
1

package j u d e t e . model ;

public c l a s s Judet {
private S t r i n g nume= ;
private S t r i n g c a p i t a l a= ;
private S t r i n g a b r e v i e r e= ;

4
5
6

public void setNume ( S t r i n g nume ) {


t h i s . nume=nume ;
}
public S t r i n g getNume ( ) {
return nume ;
}

8
9
10
11
12
13

public void s e t A b r e v i e r e ( S t r i n g a b r e v i e r e ) {
t h i s . a b r e v i e r e=a b r e v i e r e ;
}
public S t r i n g g e t A b r e v i e r e ( ) {
return a b r e v i e r e ;
}

15
16
17
18
19
20

public void s e t C a p i t a l a ( S t r i n g c a p i t a l a ) {
t h i s . c a p i t a l a=c a p i t a l a ;
}
public S t r i n g g e t C a p i t a l a ( ) {
return c a p i t a l a ;
}

22
23
24
25
26
27
28

Serviciile oferite de model sunt (judete.service.JudeteManager )


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

package j u d e t e . s e r v i c e ;
import j u d e t e . model . Judet ;
import j a v a . u t i l . L i s t ;
import j a v a . u t i l . HashMap ;
import j a v a . u t i l . L i n k e d L i s t ;
import j a v a . i o . InputStream ;
import j a v a . i o . F i l e I n p u t S t r e a m ;
import j a v a . i o . InputStreamReader ;
import j a v a . i o . B u f f e r e d R e a d e r ;
public c l a s s JudeteManager {
private HashMap<S t r i n g , Judet> r e f J u d e t e=n u l l ;
private L i s t <S t r i n g > l s t J u d=n u l l ;
JudeteManager ( ) {
r e f J u d e t e=new HashMap<S t r i n g , Judet > ( ) ;
l s t J u d=new L i n k e d L i s t <S t r i n g > ( ) ;
try {
InputStream i s=
new F i l e I n p u t S t r e a m ( / apachetomcat 6 . 0 . 2 6 / webapps / j u d e t e / j u d e t e . t x t ) ;

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

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 ) ;
S t r i n g s= ;
do{
s=br . r e a d L i n e ( ) ;
S t r i n g [ ] t s=s . s p l i t ( ) ;
Judet j u d=new Judet ( ) ;
j u d . setNume ( t s [ 0 ] ) ;
jud . s e t C a p i t a l a ( t s [ 1 ] ) ;
jud . s e t A b r e v i e r e ( t s [ 2 ] ) ;
r e f J u d e t e . put ( t s [ 0 ] , j u d ) ;
l s t J u d . add ( t s [ 0 ] ) ;
}
while ( s != n u l l ) ;
br . c l o s e ( ) ;
isr . close ();
is . close ();

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

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

38
39
40
41
42

44

public HashMap<S t r i n g , Judet> g e t R e f J u d e t e ( ) {


return r e f J u d e t e ;
}

45
46

public L i s t <S t r i n g > g e t L s t J u d ( ) {


return l s t J u d ;
}

48
49
50
51

97

Metoda citeste datele dintr-un fisier si creaza o variabila de tip List si una
de tip HashMap. Lista va fi utilizata n formularul adresat clientului iar variabila de tip HashMap se utilizeaza pentru regasirea datelor n vederea furnizarii
rezultatelor.
Clasa controller - judete.web.JudeteController are codul
1
2
3
4
5
6
7
8
9
10
11
12
14
15
16
17
18
20

package j u d e t e . web ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . ModelAndView ;
import o r g . s p r i n g f r a m e w o r k . web . s e r v l e t . view . R e d i r e c t V i e w ;
import o r g . s p r i n g f r a m e w o r k . s t e r e o t y p e . C o n t r o l l e r ;
import o r g . s p r i n g f r a m e w o r k . beans . f a c t o r y . a n n o t a t i o n . Autowired ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . M o d e l A t t r i b u t e ;
import o r g . s p r i n g f r a m e w o r k . u i . ModelMap ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMapping ;
import o r g . s p r i n g f r a m e w o r k . web . bind . a n n o t a t i o n . RequestMethod ;
import j a v a . u t i l . HashMap ;
import j u d e t e . model . Judet ;
import j u d e t e . s e r v i c e . JudeteManager ;
@Controller
@RequestMapping ( / j u d e t e . htm )
public c l a s s J u d e t e C o n t r o l l e r {
@Autowired
private JudeteManager jm ;
@RequestMapping ( method = RequestMethod .GET)

98

public ModelAndView m e t o d a C e r e r e I n i t i a l a ( ) {
Judet j u d=new Judet ( ) ;
ModelAndView modelAndView=new ModelAndView ( judeteForm ) ;
modelAndView . addObject ( command , j u d ) ;
modelAndView . addObject ( l s t J u d , jm . g e t L s t J u d ( ) ) ;
return modelAndView ;
}

21
22
23
24
25
26
27

// a 2a p a g i n a ( i n c a z a p e l POST)
@RequestMapping ( method = RequestMethod . POST)
public ModelAndView metodaDupaSubmit ( @ModelAttribute ( command ) Judet j u d ) {
System . out . p r i n t l n ( j u d . getNume ( ) ) ;
S t r i n g nume=j u d . getNume ( ) ;
HashMap<S t r i n g , Judet> r e f J u d e t e=jm . g e t R e f J u d e t e ( ) ;
j u d=r e f J u d e t e . g e t ( nume ) ;
ModelAndView modelAndView = new ModelAndView ( j u d e t e ) ;
modelAndView . addObject ( nume , nume ) ;
modelAndView . addObject ( c a p i t a l a , j u d . g e t C a p i t a l a ( ) ) ;
modelAndView . addObject ( a b r e v i e r e a , j u d . g e t A b r e v i e r e ( ) ) ;
return modelAndView ;
}

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

CAPITOLUL 2. SPRING

Adnotarea Autowired injecteaza n clasa Controller o instanta a clasei


service.
In linia 25 se introduce n pagina view judeteForm.jsp lista de optiuni a
elementului select (ComboBox).
Paginile view sunt
judeteForm.jsp
1
2
3
5
6
7
9
10
12
13
14
16
17
18
19

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>


<%@ t a g l i b p r e f i x= form
u r i= h t t p : / /www. s p r i n g f r a m e w o r k . o r g / t a g s / form %>
<html>
<body>
<h1>I n f o r m a t i i d e s p r e j u d e t e A p l i c a t i e S p r i n g </h1>
<form : form method= p o s t >
S e l e c t a t i j u d e t u l din l i s t a
<form : s e l e c t path=nume>
<form : o p t i o n s i t e m s= $ { l s t J u d } />
</form : s e l e c t>
<p/><input type= submit value= Cauta >
</form : form>
</body>
</html>

judete.jsp
1

<%@ t a g l i b p r e f i x= c u r i= h t t p : / / j a v a . sun . com/ j s p / j s t l / c o r e %>

2.2. DEZVOLTAREA UNEI APLICAT


II MVC SPRING

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

<html>
<body>
<h1> R e z u l t a t u l c a u t a r i i </h1>
<table border= 1 >
<tr>
<td> Numele j u d e t u l u i </td>
<td> <c : out value= $ {nume} /></td>
</ tr>
<tr>
<td> C a p i t a l a j u d e t u l u i </td>
<td> <c : out value= $ { c a p i t a l a } /></td>
</ tr>
<tr>
<td> A b r e v i e r e a j u d e t u l u i </td>
<td> <c : out value= $ { a b r e v i e r e a } /></td>
</ tr>
</ table>
</body>
</html>

Codul fisierului de configurare judete-servlet.xml este


1

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>

<beans xmlns= h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans


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 : //www. s p r i n g f r a m e w o r k . o r g / schema / beans
h t t p : //www. s p r i n g f r a m e w o r k . o r g / schema / beans / s p r i n g beans 2 . 5 . xsd >

4
5
6
8
10
11
12
13
14
16
17
18
19
20
21
22
23

<bean i d= judManager c l a s s= j u d e t e . s e r v i c e . JudeteManager />


<bean name= / j u d e t e . htm c l a s s= j u d e t e . web . J u d e t e C o n t r o l l e r >
<p r o p e r t y name=jm r e f= judManager />
<p r o p e r t y name= commandClass v a l u e= j u d e t e . model . Judet />
<p r o p e r t y name= formView v a l u e= judeteForm />
</ bean>
<bean i d= v i e w R e s o l v e r
c l a s s=
s p r i n g .web . s e r v l e t . view . I n t e r n a l R e s o u r c e V i e w R e s o l v e r >
<p r o p e r t y name= v i e w C l a s s
v a l u e= s p r i n g .web . s e r v l e t . view . J s t l V i e w />
<p r o p e r t y name= p r e f i x v a l u e= /WEBINF/ j s p / />
<p r o p e r t y name= s u f f i x v a l u e= . j s p />
</ bean>
</ beans>

99

100

CAPITOLUL 2. SPRING

Capitolul 3
Asynchronous JavaScript And
Xml AJAX
AJAX - Asynchronous JavaScript And Xml - permite, pe partea de client,
un schimb de date cu un program server Web, prin functii JavaScript. La baza
se afla o interfata de programare (API - Application Programming Interface)
XMLHttpRequest (XHR), initiata de Microsoft, ce poate fi utilizata de un
limbaj de scripting (JavaScript, JScript, VBScript, etc) pentru
transfer de date catre un server Web utilizand protocolul HTTP;
manipularea datelor XML sau JSON (JavaScript Object Notation).
Caracterul asincron consta n faptul ca raspunsul furnizat de un program server
reface doar o parte din pagina html si nu ntrega pagina, asa cum, de exemplu,
este cazul utilizarii obisnuite a unui servlet.

3.1

AJAX Java

Exista doua implementari a interfetei XMLHttpRequest:


ActiveXObject n navigatorul MS InternetExplorer;
XMLHttpRequest n celelate navigatoare.
Metodele interfetei XMLHttpRequest.
open(method,URL)
open(method,URL,async)
101

102

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

open(method,URL,async,userName)
open(method,URL,async,userName,password )
method poate fi get sau post.
async fixeaza natura comunicatiei - true pentru comunicatie asincrona.
send(content)
abord()
getAllResponseHeaders()
getResponseHeader(headerName)
setRequestHeader(label,value)
Propriet
atile interfetei XMLHttpRequest.
onreadystatechange
Contine numele functiei script care prelucreaza raspunsul.
readyState
Indicatorul obiectului XMLHttpRequest: 0 - neinitializat; 1 - deschis; 2 trimis; 3 - receptionat; 4 - ncarcat.
responseText / responseXML
Contine raspunsul sub forma text / xml.
status / statusText
404 - Not Found; 200 - OK.
Punctul de pornire al unei aplicatii AJAX - Java este o pagina Web html. La generarea unui eveniment legat de un element grafic al paginii Web
se apeleaza o serie de functii JavaScript a caror executie realizeaza comunicatia
cu un program server - servlet sau jsp. Uzual, programul server formuleaza un
raspuns sub forma unui fisier xml, care este prelucrat de o functie JavaScript
oferind date clientului.
Simplificand, punem n evidenta 3 functii JavaScript
1. Generarea unui obiect XMLHTTPRequest

3.1. AJAX JAVA

1
2
3
4
5
6
7
8
9

103

function initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
}
else
i f ( window . ActiveXObject ){
r e t u r n new ActiveXObject ( M i c r o s o f t .XMLHTTP ) ;
}
}

2. Functia apelata de eveniment si care lanseaza comunicatia AJAX


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

f u n c t i o n XXX( ) {
var i d F i e l d=document . getElementById ( numeCimp ) ;
var u r l=
http : / / h o s t : p o r t / c o n t e x t / numeServlet ?numeCimp=+
escape ( idField . value ) ;
var r e q = i n i t R e q u e s t ( ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4 ) {
i f ( r e q . s t a t u s == 200) {
f u n c t i a P r e l u c r a r e R a s p u n s ( r e q . responseXML ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . open ( GET , u r l , t r u e ) ;
r e q . send ( n u l l ) ;
}
Campul responseXML se utilizeaza pentru nmagazinarea unui raspuns
n format XML, iar responseText se utilizeaza pentru preluarea unui
raspuns JSON.

3. Functia de prelucrare a raspunsului.


Exemplul 3.1.1 Aplicatie Web de alegere a unei oferte. Pagina Web a aplicatiei
afiseaza o lista de oferte de cursuri optionale. Un student - client - selecteaza
cursul dorit iar selectia este transmisa unui servlet care centralizeaza alegerile.

104

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Lista cursurilor optionale este ncarcata n momentul apelarii paginii Web


utilizand AJAX. Pentru AJAX, pe partea de server este un alt servlet care
trimite lista cursurilor optionale sub forma unui fisier XML.
Gazduita de apache-tomcat desfasurarea aplicatiei este
webapps
|--- ajax
|--- WEB-INF
|
|--> classes
|
|
|--- AJAXAlegereServlet.class
|
|
|--- AJAXCompletareServlet.class
|
|--> lib
|
|
|--- javax.json.jar
|
|--- web.xml
|--- index.html
Codul Java al programului AJAXCompletareServlet este
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import
import
import
import
import
import
import
import
import

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

public c l a s s AJAXCompletareServlet 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 ( ) ;
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 ) ;
r e s . s e t H e a d e r ( CacheC o n t r o l , noc a c h e ) ;
i f ( t i p . e q u a l s ( xml ) ) {
r e s . setContentType ( t e x t /xml ) ;
out . p r i n t ( <?xml v e r s i o n =\1.0\ ?> ) ;
out . p r i n t ( <o p t i o n a l e > ) ;
out . p r i n t ( < d i s c i p l i n a > ) ;
out . p r i n t ( <denumire> C a l c u l P a r a l e l </denumire> ) ;
out . p r i n t ( </ d i s c i p l i n a > ) ;
out . p r i n t ( < d i s c i p l i n a > ) ;
out . p r i n t ( <denumire> T e h n o l o g i i d i s t r i b u i t e </denumire> ) ;
out . p r i n t ( </ d i s c i p l i n a > ) ;
out . p r i n t ( < d i s c i p l i n a > ) ;
out . p r i n t ( <denumire> R e z o l v a r e a numerica a e . d . o . </denumire> ) ;
out . p r i n t ( </ d i s c i p l i n a > ) ;
out . p r i n t ( </ o p t i o n a l e > ) ;
}
else {

105

3.1. AJAX JAVA

r e s . setContentType ( a p p l i c a t i o n / j s o n ) ;
// j e e
JsonArray j s o n A r r a y=Json . c r e a t e A r r a y B u i l d e r ( )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , A n a l i z a numerica ) )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , Programare d i s t r i b u i t a ) )
. add ( Json . c r e a t e O b j e c t B u i l d e r ( )
. add ( nume , S o f t matematic ) )
. build ( ) ;
J s o n W r i t e r j s o n W r i t e r=Json . c r e a t e W r i t e r ( out ) ;
jsonWriter . writeArray ( jsonArray ) ;
jsonWriter . c los e ( ) ;

33
34
35
36
37
38
39
40
41
42
43
44
45

}
out . c l o s e ( ) ;

46
47
48

50

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

51
52
53
54

Raspunsul nu se stocheaza la receptie


response.setHeader("Cache-Control","no-cache");
In varianata XML, natura raspunsului este text/xml
response.setContentType("text/xml");
iar n varianta JSON acesta este text/plain.
In cazul exemplului, n varianta XML raspunsul la apelarea servlet-ului
este fisierul xml
1
2
3
4
5
6
7
8
9
10
11
12

<?xml version=\ 1 . 0 \ ?>


<o p t i o n a l e>
< d i s c i p l i n a>
<denumire> C a l c u l p a r a l e l </ denumire>
</ d i s c i p l i n a>
< d i s c i p l i n a>
<denumire> T e h n o l o g i i d i s t r i b u i t e </ denumire>
</ d i s c i p l i n a>
< d i s c i p l i n a>
<denumire> R e z o l v a r e a numerica a e . d . o . </ denumire>
</ d i s c i p l i n a>
</ o p t i o n a l e>

iar, n varianta JSON, raspunsul este stringul


[{"nume":"Analiza numerica"},{"nume":"Programare distribuita"},{"nume":"Soft matematic"}]

Servlet-ul aplicatiei (AJAXalegereServlet) este banal: confirma clientului


alegerea facuta

106

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

import
import
import
import
import
import

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

public c l a s s AJAXAlegereServlet extends H t t p S e r v l e t {


public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g m a t e r i a=r e q . g e t P a r a m e t e r ( a l e g e r e ) ;
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 ) ;
out . p r i n t l n ( <html><body> ) ;
out . p r i n t l n ( <h1> D i s c i p l i n a o p t i o n a l a s e l e c t a t a </h1> ) ;
out . p r i n t l n ( <p>+m a t e r i a ) ;
out . p r i n t l n ( </body></html> ) ;
out . c l o s e ( ) ;
}
public void doPost ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )
throws S e r v l e t E x c e p t i o n , IOException {
doGet ( req , r e s ) ;
}

21
22
23
24
25

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Pagina Web de apelare a aplicatiei (indexXMLAlegere.html ) este


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

<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 initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
}
e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}
f u n c t i o n doCompletion ( ) {
var t i p F i e l d=document . g e t E l e m e n t B y I d ( t i p ) ;
var u r l = h t t p : / / l o c a l h o s t : 8 0 8 0 / a j a x / c o m p l e t a r e ? t i p=+
e s c a p e ( t i p F i e l d . value ) ;
var r e q = i n i t R e q u e s t ( ) ;
i f ( r e q != n u l l ) {
r e q . open ( GET , u r l , t r u e ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
p a r s e M e s s a g e s ( r e q . responseXML ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . send ( n u l l ) ;

3.1. AJAX JAVA

32
33

35

f u n c t i o n p a r s e M e s s a g e s ( responseXML ) {
var o p t i o n a l e = responseXML . getElementsByTagName ( o p t i o n a l e ) [ 0 ] ;
var s e l e c t=document . g e t E l e m e n t B y I d ( a l e g e r e ) ;
f o r ( l o o p = 0 ; l o o p < o p t i o n a l e . c h i l d N o d e s . l e n g t h ; l o o p ++){
var d i s c i p l i n a = o p t i o n a l e . c h i l d N o d e s [ l o o p ] ;
var denumire = d i s c i p l i n a . getElementsByTagName ( denumire ) [ 0 ] ;
var den=denumire . c h i l d N o d e s [ 0 ] . nodeValue ;
s e l e c t . o p t i o n s [ l o o p ]=new Option ( den , den , f a l s e , f a l s e ) ;
}
}
>
</ s c r i p t>

36
37
38
39
40
41
42
43
44
45
46
48
49
50
51
52

< t i t l e>
AutoCompletion u s i n g Asynchronous J a v a S c r i p t and XML (AJAX)
</ t i t l e>
</head>
<body onload= doCompletion ( ) >

54

<h1>AutoCompletion u s i n g Asynchronous J a v a S c r i p t and XML (AJAX)</h1>

56

<form name= a u t o f i l l f o r m
action= / a j a x / a l e g e r e a method= g e t >

57

60
62
63
65
66
67
68
69
70
71

<b>D i s c i p l i n a o p t i o n a l : </b>
<s e l e c t name= a l e g e r e id= a l e g e r e >
</ s e l e c t>
<p>
<input type= Submit value= Transmite >
<input type= r e s e t value=Abandon >
<input type= h id de n id= t i p value=xml >
</form>
</body>
</html>

respectiv (indexJSONAlegere.html )
1
2
4
5
6
7
8
9
10
11
12
13
15
16

<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 initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
}
e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}
f u n c t i o n doCompletion ( ) {
var t i p F i e l d=document . g e t E l e m e n t B y I d ( t i p ) ;

107

108

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

var u r l = h t t p : / / l o c a l h o s t : 8 0 8 0 / a j a x / c o m p l e t a r e ? t i p=+
e s c a p e ( t i p F i e l d . value ) ;
var r e q = i n i t R e q u e s t ( ) ;
i f ( r e q != n u l l ) {
r e q . open ( GET , u r l , t r u e ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
parseMessages ( req . responseText ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . send ( n u l l ) ;
}

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

35

f u n c t i o n parseMessages ( responseText ){
var s=e v a l ( r e s p o n s e T e x t ) ;
var s e l e c t=document . g e t E l e m e n t B y I d ( a l e g e r e ) ;
f o r ( var i =0; i<s . l e n g t h ; i ++){
s e l e c t . o p t i o n s [ i ]=new Option ( s [ i ] . nume , s [ i ] . nume , f a l s e , f a l s e ) ;
}
}
>
</ s c r i p t>

36
37
38
39
40
41
42
43
45
46
47
48
49

< t i t l e>
AutoCompletion u s i n g Asynchronous J a v a S c r i p t and JSON (AJAX)
</ t i t l e>
</head>
<body onload= doCompletion ( ) >

51

<h1>AutoCompletion u s i n g Asynchronous J a v a S c r i p t and XML (AJAX)</h1>

53

<form name= a u t o f i l l f o r m
action= / a j a x / a l e g e r e a method= g e t >

54

57
59
60
62
63
64
65
66
67
68

<b>D i s c i p l i n a o p t i o n a l : </b>
<s e l e c t name= a l e g e r e id= a l e g e r e >
</ s e l e c t>
<p>
<input type= Submit value= Transmite >
<input type= r e s e t value=Abandon >
<input type= h id de n id= t i p value= j s o n >
</form>
</body>
</html>

Exemplul 3.1.2 Calcul celui mai mare divizor comun a doua numere naturale
cu client AJAX.
Programul servlet este

3.1. AJAX JAVA

import
import
import
import
import
import

public c l a s s AJAXCmmdcServlet extends H t t p S e r v l e t {

1
2
3
4
5

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

10

public long cmmdc( long m, long n ) { . . . }

12

public void doGet ( H t t p S e r v l e t R e q u e s t req , H t t p S e r v l e t R e s p o n s e r e s )


throws S e r v l e t E x c e p t i o n , IOException {
S t r i n g sm=r e q . g e t P a r a m e t e r ( m ) , sn=r e q . g e t P a r a m e t e r ( n ) ;
long m=Long . par se Lon g ( sm ) , n=Long . par se Lon g ( sn ) ;
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 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 ( ) ;
r e s . s e t H e a d e r ( CacheC o n t r o l , noc a c h e ) ;
i f ( t i p . e q u a l s ( xml ) ) {
r e s . setContentType ( t e x t /xml ) ;
out . p r i n t ( <?xml v e r s i o n =\1.0\ ?> ) ;
out . p r i n t ( <r e z u l t a t > ) ;
out . p r i n t ( (new Long ( x ) ) . t o S t r i n g ( ) ) ;
out . p r i n t ( </ r e z u l t a t > ) ;
}
else {
r e s . setContentType ( a p p l i c a t i o n / j s o n ) ;
out . p r i n t l n ( (new Long ( x ) ) . t o S t r i n g ( ) ) ;
}
out . c l o s e ( ) ;
}

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

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

34
35
36
37
38

109

Se observa diferenta fata de solutia non-AJAX doar n raspunsul formulat


care este un document xml si nu html.
Clientul n format XML
1
2
4
5

<html>
<head>
<s c r i p t type= t e x t / j a v a s c r i p t >
< !

13

function initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
} e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}

15

f u n c t i o n compute ( ) {

7
8
9
10
11
12

110

var
var
var
var

mField=document . g e t E l e m e n t B y I d ( m ) ;
n F i e l d=document . g e t E l e m e n t B y I d ( n ) ;
t i p F i e l d=document . g e t E l e m e n t B y I d ( t i p ) ;
u r l = h t t p : / / l o c a l h o s t : 8 0 8 0 / a j a x /cmmdc?m= +
e s c a p e ( mField . value)+&n=+e s c a p e ( n F i e l d . value ) +
&t i p= + e s c a p e ( t i p F i e l d . value ) ;
var r e q = i n i t R e q u e s t ( ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
p a r s e M e s s a g e s ( r e q . responseXML ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . open ( g e t , u r l , t r u e ) ;
r e q . send ( n u l l ) ;

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

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

}
f u n c t i o n p a r s e M e s s a g e s ( responseXML ) {
var r = responseXML . getElementsByTagName ( r e z u l t a t ) [ 0 ] ;
var cmmdc=r . c h i l d N o d e s [ 0 ] . nodeValue ;
document . g e t E l e m e n t B y I d ( r e z u l t a t ) . innerHTML=Cmmdc = +cmmdc ;
}
>
</ s c r i p t>
< t i t l e> Cmmdc AJAX</ t i t l e>
</head>
<body>
<h1>Cmmdc with AJAX</h1>
<p>
Primul numar :
<input type= t e x t id=m value= 1 s i z e= 15 >
<p>
Al d o i l e a numar :
<input type= t e x t id=n value= 1 s i z e= 15 >
<input type= h id de n id= t i p value=xml >
<p>
<input type= b ut to n value= C a l c u l e a z a onClick= compute ( ) >
<p>
Cel mai mare d i v i z o r comun a c e l o r doua numere e s t e
<p>
<div id= r e z u l t a t />
</body>
</html>

In varianta JSON functia javascript de prelucrare a raspunsului este


function parseMessages(responseText) {
var cmmdc=responseText;
document.getElementById("rezultat").innerHTML="Cmmdc = "+cmmdc;
}

Functiile javascript pot fi salvate ntr-un fisier iar referinta la ele se da prin
<script language="javascript" src="fisier_functii.js"
</script>

111

3.1. AJAX JAVA

S-au creat mai multe cadre de lucru (framework) pentru dezvoltarea aplicatiilor
Web bazate pe AJAX:
Dojo
GWT
MooTools
Prototype
Yahoo User Interface Library
Buidows
Isomorphic Smart Client
Nexaweb

Ext
jQuery
OpenRico
Scriptaculous
Backbase
Icefaces
JackBe

Dintre acestea se remarca prin eleganta solutiei Google Web Tooltit - (GWT).

112

3.2

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Google Web Toolkit (GWT)

GWT permite dezvoltarea aplicatiilor Web cu schimburi de date bazate pe


protocolul Asynchronous JavaScript And Xml - AJAX utilizand Java. La baza
protocolului AJAX se afla o interfata de programare (API) XMLHttpRequest
(XHR) ce poate fi utilizara de un limbaj de scripting (JavaScript, JScript,
VBScript, etc) pentru
transfer de date catre un server Web utilizand protocolul HTTP;
manipularea datelor XML sau JSON (JavaScript Object Notation).
Caracterul asincron consta n faptul ca raspunsul furnizat de un program server
reface doar o parte din pagina html si nu ntrega pagina, asa cum, de exemplu,
este cazul utilizarii obisnuite a unui servlet.
Utilizand GWT, programatorul dezvolta aplicatia n Java si html iar GWT
o transforma n JavaScript. Astfel se evita programarea n JavaScript. Intr-o
aplicatie GWT se dezvolta atat partea de client cat si partea de server. Partea
de server este bazata pe tehnologia servlet.
GWT este distribuit gratuit de firma Google.
Instalarea produsului consta din dezarhivarea fisierului descarcat din
Internet.
O aplicatie GWT se dezvolta
n linie de comanda, cu ant, utilizand fisierul build.xml generat n
cadrul fiecarei aplicatii;
n Eclipse, prin folosirea unei extensii adecvate (plug-in);
n linie de comanda, cu maven.

3.2.1

Dezvoltarea unei aplicatii GWT prin ant

Din punct de vedere al structurii aplicatiei GWT, acesta poate fi


simpla, fara apel de procedura la distanta. In acest caz, rezolvarea cererii
este programata n clase aflate n catalogul client.
cu apel de procedura la distanta.
O aplicatie GWT se initiaza prin generarea unei structuri de cataloage si
fisiere. Daca se doreste realizarea unei aplicatii cu punctul de intrare data de
clasa context.MyApp si care sa se afle ntr-un catalog catapp, atunci generarea
se obtine prin comanda

3.2. GOOGLE WEB TOOLKIT (GWT)

113

webAppCreator -out catapp context.MyApp


lansata ntr-o fereasta DOS. Contextul poate reprezenta un sir de cataloage.
Rezultatul este reprezentat n Fig. 3.1 si corespunde unei aplicatii de ntampinare.
catapp
|-->
|
|
|
|
|
|
|
|
|
|
|-->
|-->
|
|
|
|
|
|
|
|
|
|

src
|--> context
|
|--> client
|
|
|
MyApp.java
|
|
|
GreetingService.java
|
|
|
GreetingServiceAsync.java
|
|--> server
|
|
|
GreetingServiceImpl.java
|
|--> shared
|
|
|
FieldVerifier.java
|
|
MyApp.gwt.xml
test
war
|--> WEB-INF
|
|
web.xml
|
MyApp.css
|
MyApp.html
|
favicon.ico
.classpath
.project
MyApp.launch
README.txt
build.xml

Figure 3.1: Initializarea unei aplicatii GWT.


Acesta structura reprezinta un proiect GWT. Spunem ca aplicatia este generata de perechea (catapp,context.MyApp). Proiect generat este punctul de
plecare pentru construirea oricarei alte aplicatii, a carei dezvoltare consta n
modificarea, rescrierea fisierelor create si completarea cu altele noi. O asemenea aplicatie GWT se mai numeste si modul (module) GWT.
Fisierul MyApp.gwt.xml este un fisier de configurare unde trebuie declarate
modulele externe utilizate.
Versiunea initiala este
1
2
3
4
5
6
7
8
9
10
11

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !
When u p d a t i n g your version o f GWT, you s h o u l d a l s o u p d a t e
t h i s DTD r e f e r e n c e ,
so t h a t your app can t a k e a d v a n t a g e o f
t h e l a t e s t GWT module c a p a b i l i t i e s .
>
< !DOCTYPE module PUBLIC //Google I n c . / /DTD Google Web T o o l k i t 2 . 5 . 1 / /EN
h t t p : // g o o g l e webt o o l k i t . g o o g l e c o d e . com/ svn / t a g s / 2 . 5 . 1 / d i s t r o s o u r c e /
c o r e / s r c /gwtmodule . dtd >
<module renamet o= myapp >
< ! I n h e r i t t h e c o r e Web T o o l k i t s t u f f .
>

114

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

12

< i n h e r i t s name= com . g o o g l e . gwt . u s e r . User />

14

20

< ! I n h e r i t t h e default GWT s t y l e s h e e t . You can change


>
< ! t h e theme o f your GWT a p p l i c a t i o n by uncommenting
>
< ! any one o f t h e f o l l o w i n g l i n e s .
>
< i n h e r i t s name= com . g o o g l e . gwt . u s e r . theme . c l e a n . Clean />
< ! < i n h e r i t s name= com . g o o g l e . gwt . u s e r . theme . s t a n d a r d . Standard /> >
< ! < i n h e r i t s name= com . g o o g l e . gwt . u s e r . theme . chrome . Chrome /> >
< ! < i n h e r i t s name= com . g o o g l e . gwt . u s e r . theme . dark . Dark />
>

22

< ! Other module i n h e r i t s

>

24

< ! S p e c i f y t h e app e n t r y p o i n t c l a s s .
<e n t r y p o i n t c l a s s= u n i t b v . c s . td . c l i e n t . MyApp />

>

< ! S p e c i f y t h e p a t h s f o r t r a n s l a t a b l e code
<s o u r c e path= c l i e n t />
<s o u r c e path= s h a r e d />

>

15
16
17
18
19

25
27
28
29
31

</ module>

O aplicatie GWT poate fi executata n


modul de dezvoltare. Rularea n acest mod se lanseaza prin
ant devmode
Verificarea aplicatiei se face prin intermediul navigatorului implicit.
modul Web (de productie) - caz n care se genereaza arhiva war a aplicatiei.
Se va executa
ant war
Cu notatiile utilizate mai sus, va rezulta fisierul MyApp.war. Dupa
desfasurarea aplicatiei ntr-un server Web, container de servlet, se va
apela http://host:port/MyApp/MyApp.html.

3.2.2

Aplicatie GWT f
ar
a apel de procedur
a la distant
a

Dupa generarea proiectului, aplicatia GWT se dezvolta parcurgand pasii (se


presupune din nou ca numele aplicatiei este MyApp aflat n catalogul catapp):
1. Proiectarea interfetei grafice vizeaza elementele care se definesc n fisierul
MyApp.html, punctul de intrare n aplicatie. Varianta initiala a fisierului
este

115

3.2. GOOGLE WEB TOOLKIT (GWT)

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

< !DOCTYPE HTML PUBLIC //W3C//DTD HTML 4 . 0 1 T r a n s i t i o n a l //EN>


< ! The HTML 4 . 0 1 T r a n s i t i o n a l DOCTYPE d e c l a r a t i o n>
< ! a b o v e s e t a t t h e t o p o f t h e f i l e w i l l s e t
>
< ! t h e browser s r e n d e r i n g e n g i n e i n t o
>
< ! Q u i r k s Mode . R e p l a c i n g t h i s d e c l a r a t i o n
>
< ! w i t h a S t a n d a r d s Mode doctype i s s u p p o r t e d , >
< ! b u t may l e a d t o some d i f f e r e n c e s i n l a y o u t .
>
<html>
<head>
<meta httpe q u i v= c o n t e n t t y p e
content= t e x t / html ; c h a r s e t=UTF8>
< !
>
< ! C o n s i d e r i n l i n i n g CSS t o r e d u c e t h e number
o f r e q u e s t e d f i l e s >
< !
>
<l i n k type= t e x t / c s s r e l= s t y l e s h e e t href=MyApp . c s s >
< !
>
< ! Any t i t l e i s f i n e
>
< !
>
< t i t l e>Web A p p l i c a t i o n S t a r t e r P r o j e c t</ t i t l e>
< !
>
< ! This s c r i p t l o a d s your c o m p i l e d module .
>
< ! I f you add any GWT meta t a g s , t h e y must
>
< ! be added b e f o r e t h i s l i n e .
>
< !
>
<s c r i p t type= t e x t / j a v a s c r i p t l a n g u a g e= j a v a s c r i p t
src=myapp/myapp . n o c a c h e . j s ></ s c r i p t>
</head>
< !
< ! The body can have a r b i t r a r y html , or
< ! you can l e a v e t h e body empty i f you want
< ! t o c r e a t e a c o m p l e t e l y dynamic UI .
< !
<body>

>
>
>
>
>

< ! OPTIONAL: i n c l u d e t h i s i f you want h i s t o r y s u p p o r t >


<iframe src= j a v a s c r i p t : id= g w t h i s t o r y F r a m e tabIndex=1
s t y l e= p o s i t i o n : a b s o l u t e ; width : 0 ; h e i g h t : 0 ; b o r d e r : 0 >
</ iframe>

55

< ! RECOMMENDED i f your web app w i l l n o t


f u n c t i o n w i t h o u t J a v a S c r i p t e n a b l e d >
<noscript>
<div s t y l e= width : 22em ; p o s i t i o n : a b s o l u t e ; l e f t : 50%;
margin l e f t : 11em ; c o l o r : r e d ; backgroundc o l o r : w h i t e ;
b o r d e r : 1px s o l i d r e d ; padding : 4px ; f o n t f a m i l y : sans s e r i f >
Your web b r o w s e r must have J a v a S c r i p t e n a b l e d
in order f o r t h i s a p p l i c a t i o n to d i s p l a y c o r r e c t l y .
</ div>
</ noscript>

57

<h1>Web A p p l i c a t i o n S t a r t e r P r o j e c t</h1>

46
47
48
49
50
51
52
53
54

116

59
60
61
62
63
64
65
66
67
68
69
70

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

<table a l i g n= c e n t e r >
<tr>
<td colspan= 2 s t y l e= f o n t w e i g h t : b o l d ; >
P l e a s e e n t e r your name :</td>
</ tr>
<tr>
<td id= n a m e F i e l d C o n t a i n e r ></td>
<td id= s e n d B u t t o n C o n t a i n e r ></td>
</ tr>
</ table>
</body>
</html>

Liniile 5668 sunt cele care trebuie adaptate aplicatiei dezvoltate.


Un widget 1 (element sau control) grafic va fi redat de navigator ntr-o
fanta (slot) definita, uzual, printr-un container div
<div id="slot"></div>
2. Construirea interfetei grafice consta n definirea obiectelor Java care
umplu fantele declarate mai sus. Acest lucru se programeaza n clasa
MyApp.java, care implementeaza interfata EntryPoint, interfata ce declara
doar metoda
public void onModuleLoad().
Implementarea acestei metode reprezinta tocmai constructia interfetei
grafice. Interfata de programare GWT (API) contine o famile de clase
widget. O instanta a unui widget se asociaza fantei prin
RootPanel.get("slot").add(widget);
Dintre clasele widget amintim:
Label
Constructori:
Label()
Label(String text)
Metode:
public void setText(String text)
1

widget=gadget virtual, gadget=dispozitiv amuzant, fara nsemnatate practica.

117

3.2. GOOGLE WEB TOOLKIT (GWT)

TextBox
Constructori:
TextBox()
Metode:
public String getText()
Button
Constructori:
Button(String text)
Metode:
public HandlerRegistration addClickHandler(ClickHandler
clickHandler )
Containere de widget
VerticalPanel
VerticalSplitPanel
HorizontalPanel HorizontalSplitPanel
FlowPanel
DockPanel
Un widget se include ntr-un container cu metoda
void add(Widget widget)
3. Generarea evenimentelor. Activitatile / actiunile care constituie obiectivul aplicatiei GWT se lanseaza printr-un clic pe un buton. Fiecarui buton i se atribuie un obiect care implementeaza interfata ClickHandler.
Activitatile amintite mai sus sunt definite n codul metodei public void
onClick(ClickEvent event).
4. Programarea activitatilor corespunzatoare evenimentelor atasate butoanelor,
adica implementarea metodelor onClick.
5. Fixarea elementelor de stil ale elementelor grafice n fisierul MyApp.css.
Atasarea la un widget a unui element de stil se obtine cu metoda public
void addStyleName(String style).
Urmarim acesti pasi n
Exemplul 3.2.1 Calculul celui mai mare divizor comun a doua numere naturale.
Se genereaza proiectului GWT unitbv.cs.td.Cmmdc

118

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Proiectarea interfetei grafice. Consideram interfeta grafica continuta


ntr-un container de tip VerticalPanel cmmdcPanel
CMMDC Label title
m=
Label mLabel
TextBox mTextBox pentru introducerea primului numar
n=
nLabel
TextBox nTextBox pentru introducerea celui de al doilea numar
Compute Button button
Label cmmdcLabel pentru afisarea rezultatului
Containerul va fi redat n slotul <div id="cmmdcPage" ></div>.
Construirea interfetei grafice. Codul care implementeaza interfata grafica
imaginata mai sus este
public void onModuleLoad() {
final Label title=new Label("CMMDC");
final Label mLabel=new Label("m=");
final Label nLabel=new Label("n=");
final Label cmmdcLabel=new Label();
final TextBox mTextBox=new TextBox();
final TextBox nTextBox=new TextBox();
final Button button = new Button("Compute");
VerticalPanel cmmdcPanel = new VerticalPanel();
cmmdcPanel.add(title);
cmmdcPanel.add(mLabel);
cmmdcPanel.add(mTextBox);
cmmdcPanel.add(nLabel);
cmmdcPanel.add(nTextBox);
cmmdcPanel.add(button);
cmmdcPanel.add(cmmdcLabel);
RootPanel.get("cmmdcPage").add(cmmdcPanel);
}
}

Generarea evenimentelor. Butonului i se asociaza o instanta a clasei


MyClickHandler, care contine actiunile executate dupa clic pe buton.
MyClickHandler clickHandler=new MyClickHandler(mTextBox,nTextBox,cmmdcLabel);
button.addClickHandler(clickHandler);

Programarea activitatilor corespunzatoare evenimentelor. Acest pas corespunde realizarii clasei MyClickHandler. Pentru fiecare din cele doua
numere se verifica
1. daca sunt furnizare;
2. daca sirul de caractere introdus este numar.

3.2. GOOGLE WEB TOOLKIT (GWT)

119

In cazul n care o conditie de mai sus nu este ndeplinita atunci se afiseaza


un mesaj de atentionare, iar n caz contrar se calculeaza cel mai mare
divizor comun.
Codul clasei MyClickHandler este
1
2
3

c l a s s MyClickHandler implements C l i c k H a n d l e r {
TextBox mTextBox=null , nTextBox=n u l l ;
L a b e l cmmdcLabel=n u l l ;
MyClickHandler ( TextBox mTextBox , TextBox nTextBox , L a b e l cmmdcLabel ) {
t h i s . mTextBox=mTextBox ;
t h i s . nTextBox=nTextBox ;
t h i s . cmmdcLabel=cmmdcLabel ;
}

5
6
7
8
9
11

private long cmmdc( long m, long n ) { . . . }

13

public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g sm=mTextBox . g e t T e x t ( ) ;
S t r i n g sn=nTextBox . g e t T e x t ( ) ;
long m=0 ,n=0;
i f ( sm . e q u a l s ( ) ) {
Window . a l e r t ( \ m\ nu e s t e dat ) ;
//GWT. l o g ( \ m\ nu e s t e d a t , n u l l ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
i f ( sn . e q u a l s ( ) ) {
Window . a l e r t ( \ n \ nu e s t e dat ) ;
//GWT. l o g ( \ n \ nu e s t e d a t , n u l l ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
m=Long . par se Lon g ( sm ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ m\ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
n=Long . p ars eL ong ( sn ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ n \ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
long c =0;
i f ( (m!=0)&&(n ! = 0 ) ) c=cmmdc(m, n ) ;
cmmdcLabel . s e t T e x t ( Cmmdc=+(new Long ( c ) ) . t o S t r i n g ( ) ) ;
}

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

Fixarea elementelor de stil. Fisierul Cmmdc.css contine

120

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

.pc-template-btn {
display: block;
font-size: 16pt;
}
.label-title{
font-family: Georgia, "Times New Roman", Times, serif;
font-weight: bold;
font-size: 18pt
}

Codul complet al clasei Cmmdc.java 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
31
32
33
34
35
36
37
38

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . e v e n t . dom . c l i e n t . C l i c k E v e n t ;
import com . g o o g l e . gwt . e v e n t . dom . c l i e n t . C l i c k H a n d l e r ;
import com . g o o g l e . gwt . c o r e . c l i e n t . E n t r y P o i n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . Button ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . RootPanel ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . V e r t i c a l P a n e l ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . TextBox ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . L a b e l ;
import com . g o o g l e . gwt . u s e r . c l i e n t . Window ;
public c l a s s Cmmdc implements E n t r y P o i n t {
public void onModuleLoad ( ) {
f i n a l L a b e l t i t l e =new L a b e l ( CMMDC ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
f i n a l L a b e l mLabel=new L a b e l ( m= ) ;
f i n a l L a b e l nLabel=new L a b e l ( n= ) ;
f i n a l L a b e l cmmdcLabel=new L a b e l ( ) ;
f i n a l TextBox mTextBox=new TextBox ( ) ;
f i n a l TextBox nTextBox=new TextBox ( ) ;
f i n a l Button b ut to n = new Button ( Compute ) ;
bu tt on . addStyleName ( pct e m p l a t e btn ) ;
V e r t i c a l P a n e l cmmdcPanel = new V e r t i c a l P a n e l ( ) ;
cmmdcPanel . setWidth ( 100% ) ;
cmmdcPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
cmmdcPanel . add ( t i t l e ) ;
cmmdcPanel . add ( mLabel ) ;
cmmdcPanel . add ( mTextBox ) ;
cmmdcPanel . add ( nLabel ) ;
cmmdcPanel . add ( nTextBox ) ;
MyClickHandler c l i c k H a n d l e r=new MyClickHandler ( mTextBox , nTextBox ,
cmmdcLabel ) ;
bu tt on . a d d C l i c k H a n d l e r ( c l i c k H a n d l e r ) ;
cmmdcPanel . add ( b ut to n ) ;
cmmdcPanel . add ( cmmdcLabel ) ;
RootPanel . g e t ( cmmdcPage ) . add ( cmmdcPanel ) ;
}
}

3.2.3

Aplicatie GWT cu apel de procedur


a la distant
a

GWT asigura posibilitatea legaturii dintre o aplicatie dezvoltata n acest


mediu si un servlet. GWT ofera doua variante de dezvoltare:

3.2. GOOGLE WEB TOOLKIT (GWT)

121

Client al unei aplicatii server exterioare aplicatiei GWT, caz n care vorbim de client http;
Serverul si clientul GWT trebuie sa ruleze n acelasi server Web (Same
Origin Policy).
Client si aplicatia server apartin aceleiasi aplicatii GWT, caz n care
vorbim de apel de procedura la distanta GWT.
Schimburile de date au loc potrivit tehnologiei AJAX. In terminologia
Google se vorbeste de servicii implementate printr-un server apelat de o
componenta client GWT. Serverul are o constructie specifica GWT.
Clientul este responsabil de trimiterea cererilor si de receptia raspunsurilor,
iar partea de server de rezolvarea cererilor. Astfel se justifica terminologia de apel de procedura la distanta GWT. Atat clientul cat si serverul
utilizeaza resurse GWT.

Client HTTP
La programarea unui client HTTP sarcina programatorului consta n
1. Lansarea cererii catre server, n cazul de fata un servlet;
2. Receptionarea si prelucrarea raspunsului.
Clasele implicate n comunicatia cu servlet-ul apartin pachetului com.google.
gwt.http.client.
Receptionarea si prelucrarea raspunsului se programeaza implementand
interfata RequestCallback, cu metodele
public void onError(Request request,Throwable exception)
public void onResponseReceived(Request request,Response response)
Un sablon simplu este
class MyRequestCallback implements RequestCallback{
private static final int STATUS_CODE_OK=200;
public void onError(Request request,Throwable exception){
// tratarea erorii
}

122

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

public void onResponseReceived(Request request,Response response){


int sc=response.getStatusCode();
if(sc==STATUS_CODE_OK){
// prelucrarea raspunsului
}
else{
// tratarea mesajului receptionat de la server
}
}
}
Sablonul de lansare a unei cereri GET catre servlet este
public void doGet(String url){
RequestBuilder rb=new RequestBuilder(RequestBuilder.GET,url);
try{
Request response=rb.sendRequest(null, RequestCallback);
}
catch(RequestException e){
// tratarea exceptiei
}
}
Sablonul de lansare a unei cereri POST catre servlet este
public void doPost(String url,String postData){
RequestBuilder rb=new RequestBuilder(RequestBuilder.POST,url);
rb.setHeader("Content-Type","application/x-www-form-urlencoded");
try{
Request response=rb.sendRequest(postData, RequestCallback);
}
catch(RequestException e){
// tratarea exceptiei
}
}
Pregatirea datelor n vederea expedierii se poate programa prin
StringBuffer sb=new StringBuffer();
String encodedParam=URL.encodeComponent(paramName)+"="+
URL.encodeComponent(paramValue);

3.2. GOOGLE WEB TOOLKIT (GWT)

123

sb.append(encodedParam);
sb.append("&");
. . .
String postData=sb.toString();
O aplicatie client http se poate verifica doar n modul Web.
Exemplul 3.2.2 Client http dezvoltat pentru servlet-ul CmmdcServlet. Interfata
grafica este identica cu cea din aplicatia anterioara, de calcul a celui mai mare
divizor comun a doua numere naturale (Cmmdc.java).
Metodele onModuleLoad ale claselor HttpClient si Cmmdc coincid. Reamintim ca servlet-ul CmmdcServlet preia 3 parametrii: cele doua numere (m, n)
ale caror cel mai mare divizor comun se calculeaza si un parametru tip care
precizeaza natura raspunsului (text/html sau text/plain).
Apelarea servlet-ului este facuta n metoda onClick() a clasei ce implementeaza interfata ClickHandler, n cazul de fata MyClickHandler.
Codul clientului este
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . c o r e . c l i e n t . E n t r y P o i n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . ;
import com . g o o g l e . gwt . h t t p . c l i e n t . ;
import com . g o o g l e . gwt . u s e r . c l i e n t . Window ;
import com . g o o g l e . gwt . e v e n t . dom . c l i e n t . ;
public c l a s s H t t p C l i e n t implements E n t r y P o i n t {
public void onModuleLoad ( ) {
L a b e l t i t l e =new L a b e l ( CMMDC ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
L a b e l mLabel=new L a b e l ( m= ) ;
L a b e l nLabel=new L a b e l ( n= ) ;
L a b e l cmmdcLabel=new L a b e l ( ) ;
TextBox mTextBox=new TextBox ( ) ;
TextBox nTextBox=new TextBox ( ) ;
Button b ut to n = new Button ( Compute ) ;
bu tt on . addStyleName ( pct e m p l a t e btn ) ;
V e r t i c a l P a n e l cmmdcPanel = new V e r t i c a l P a n e l ( ) ;
cmmdcPanel . setWidth ( 100% ) ;
cmmdcPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
cmmdcPanel . add ( t i t l e ) ;
cmmdcPanel . add ( mLabel ) ;
cmmdcPanel . add ( mTextBox ) ;
cmmdcPanel . add ( nLabel ) ;
cmmdcPanel . add ( nTextBox ) ;
MyClickHandler c l i c k H a n d l e r=
new MyClickHandler ( mTextBox , nTextBox , cmmdcLabel ) ;
bu tt on . a d d C l i c k H a n d l e r ( c l i c k H a n d l e r ) ;
cmmdcPanel . add ( b ut to n ) ;
cmmdcPanel . add ( cmmdcLabel ) ;
RootPanel . g e t ( cmmdcPage ) . add ( cmmdcPanel ) ;
}

124

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

34

36

c l a s s MyClickHandler implements C l i c k H a n d l e r {
TextBox mTextBox=null , nTextBox=n u l l ;
L a b e l cmmdcLabel=n u l l ;

37
38
40
41
42
43
44
46
47
48
49
50
51
52
53
54
55
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

MyClickHandler ( TextBox mTextBox , TextBox nTextBox , L a b e l cmmdcLabel ) {


t h i s . mTextBox=mTextBox ;
t h i s . nTextBox=nTextBox ;
t h i s . cmmdcLabel=cmmdcLabel ;
}
public void doGet ( S t r i n g u r l ) {
R e q u e s t B u i l d e r rb=new R e q u e s t B u i l d e r ( R e q u e s t B u i l d e r .GET, u r l ) ;
MyRequestCallback r c=new MyRequestCallback ( cmmdcLabel ) ;
try {
Request r e s p o n s e=rb . s e n d R e q u e s t ( null , r c ) ;
}
catch ( R e q u e s t E x c e p t i o n e ) {
cmmdcLabel . s e t T e x t ( R e q u e s t E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
}
}
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g u r l= /appcmmdc/cmmdc ;
S t r i n g sm=mTextBox . g e t T e x t ( ) ;
S t r i n g sn=nTextBox . g e t T e x t ( ) ;
long m=0 ,n=0;
i f ( sm . e q u a l s ( ) ) {
Window . a l e r t ( \ m\ nu e s t e dat ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
i f ( sn . e q u a l s ( ) ) {
Window . a l e r t ( \ n \ nu e s t e dat ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
m=Long . par se Lon g ( sm ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ m\ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
n=Long . p ars eL ong ( sn ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ n \ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
i f ( (m!=0)&&(n ! = 0 ) ) {
S t r i n g u r l E x t i n s=u r l+ ?m=+sm+&n=+sn+&t i p=t e x t / p l a i n ;
doGet ( u r l E x t i n s ) ;
}
}

3.2. GOOGLE WEB TOOLKIT (GWT)

93

95

c l a s s MyRequestCallback implements R e q u e s t C a l l b a c k {
Label label ;
private s t a t i c f i n a l i n t STATUS CODE OK=200;

96
97

MyRequestCallback ( L a b e l l a b e l ) {
t h i s . l a b e l=l a b e l ;
}

99
100
101

public void o n E r r o r ( Request r e q u e s t , Throwable e ) {


l a b e l . s e t T e x t ( C o n n e c t i o n e r r o r : +e . g e t M e s s a g e ( ) ) ;
}

103
104
105

public void o n R e s p o n s e R e c e i v e d ( Request r e q u e s t , Response r e s p o n s e ) {


i n t s c=r e s p o n s e . g e t S t a t u s C o d e ( ) ;
i f ( s c==STATUS CODE OK) {
label . setText ( response . getText ( ) ) ;
}
else {
l a b e l . s e t T e x t ( STATUS CODE : +s c ) ;
}
}

107
108
109
110
111
112
113
114
115
116

125

Apel de procedur
a la distant
a GWT
Constructia clientului si a serverului este supusa unor restrictii: metodele
serviciului sunt definite ntr-o interfata care este implementata de server n
clase POJO.
Legatura dintre client si server se face prin intermediul fisierului web.xml
prin adaugarea elementelor
<servlet>
<servlet-name>nume-servlet</servlet-name>
<servlet-class>. . .server.ServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>nume-servlet</servlet-name>
<url-pattern>/myapp/urlPattern</url-pattern>
</servlet-mapping>

Datele din elementul xml <url-pattern> cuprind


Denumirea unui catalog myapp. Catalogul apare numai n arhiva war iar
numele coincide cu numele aplicatiei (clasei client) scris cu litere mici.
Parametrul urlPattern va fi utilizat n clasa client la apelarea metodelor
oferite de server.

126

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Dezvoltarea clientului
Partea de client este alcatuita din:
1. Interfata serviciului.
Metodele care pot fi invocate de client se declara ntr-o interfata
package ...client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface InterfataService extends RemoteService{
public tip metoda1(tip var,. . .);
public tip metoda2(tip var,. . .);
. . .
}
2. Interfata asincrona.
Interfata asincrona are rolul de a semnala clientului receptionarea raspunsului
dat de server. Numele acestei interfete se formeaza din numele interfetei
serviciului plus sufixul Async. Cele doua interfete contin aceleasi metode
dar au semnaturi diferite.
package ...client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface InterfataServiceAsync{
public void metoda1(tip var,. . .,AsyncCallback<tip> callback);
public void metoda2(tip var,. . .,AsyncCallback<tip> callback);
. . .
}
tip corespunde clasei obiectului returnat de metoda.
Daca o metoda returneaza o valoare de tip predefinit atunci tip va fi
clasa acoperitoare.
Daca metoda rentoarce void atunci tip=Void.
3. Interfata asincrona este implementata de client si contine prelucrarile
referitoare la receptia raspunsului furnizat de server. Interfata AsyncCallback
contine doua metode

3.2. GOOGLE WEB TOOLKIT (GWT)

127

public void onSuccess(Object result)


public void onFailure(Throwable caught)
Programatorul defineste actiunile care se fac n cazul n care apelul
metodei la distanta s-a terminat cu succes, respectiv cu insucces.
Structura clasei este
package ...client;
import
import
import
import

com.google.gwt.user.client.rpc.AsyncCallback;
com.google.gwt.core.client.GWT;
com.google.gwt.user.client.Window;
com.google.gwt.user.client.ui.*;

public class ClientCallback implements AsyncCallback {


public void onFailure(Throwable caught) {
GWT.log("Error ", caught);
caught.printStackTrace();
Window.alert(caught.toString());
}
public void onSuccess(Object result) {
// cod client
. . .
}
}
4. Clientul propriu-zis este o aplicatie GWT
package ...client;
import
import
import
import

com.google.gwt.core.client.EntryPoint;
com.google.gwt.core.client.GWT;
com.google.gwt.user.client.ui.*;
com.google.gwt.user.client.rpc.ServiceDefTarget;

public class Client implements EntryPoint {


public void apelMetoda1(. . .){

128

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

InterfataServiceAsync myService=
(InterfataServiceAsync)GWT.create(InterfataService.class);
ServiceDefTarget target=(ServiceDefTarget)myService;
String relativeURL=GWT.getModuleBaseURL()+"urlPattern";
target.setServiceEntryPoint(relativeURL);
myService.metoda1(variabile actuale pentre metoda1,
new ClientCallback());
}
public void onModuleLoad(){
. . .
final Button button=new Button(. . .);
. . .
button.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
. . .
apelMetoda1(lista variabile);
}
}
});
. . .
RootPanel.get("slot").add(button);
}
}
unde
urlPattern este cel precizat n fisierul web.xml, fara numele catalogului.
slot corespunde containerului div n care se include butonul.
Dezvoltarea serverului
Programul server implementeaza metodele interfetei declarata n pachetul
client.
package ...server;
import client.*;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

129

3.2. GOOGLE WEB TOOLKIT (GWT)

public class ServiceImpl extends RemoteServiceServlet


implements InterfataService{
public tip metoda1(tip var,. . .){. . .}
public tip metoda2(tip var,. . .){. . .}
. . .
}
Exemplul 3.2.3 Transformam programul GWT de calcul a celui mai mare divizor comun a doua numere naturale ntr-o aplicatie cu apel la distanta GWT.
Interfata aplicatiei este
1
2
4
5
6

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . r p c . R e m o t e S e r v i c e ;
public i n t e r f a c e CmmdcService extends R e m o t e S e r v i c e {
public long cmmdc( long m, long n ) ;
}

iar interfata asincrona


1
2
4
5
6

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . r p c . A s y n c C a l l b a c k ;
public i n t e r f a c e CmmdcServiceAsync {
public void cmmdc( long m, long n , AsyncCallback<Long> c a l l b a c k ) ;
}

Implementarea interfetei asincrone este


1

package u n i t b v . c s . td . c l i e n t ;

import
import
import
import
import
import

4
5
6
7
8
10
11
12
13
14
15
16
17
18
19
20
21
22
23

com .
com .
com .
com .
com .
com .

google
google
google
google
google
google

. gwt .
. gwt .
. gwt .
. gwt .
. gwt .
. gwt .

user
core
user
user
user
user

.
.
.
.
.
.

client
client
client
client
client
client

. rpc . AsyncCallback ;
.GWT;
. Window ;
. u i . RootPanel ;
. ui . VerticalPanel ;
. u i .HTML;

public c l a s s CmmdcCallback implements A s y n c C a l l b a c k {


public void o n F a i l u r e ( Throwable ca ug ht ) {
GWT. l o g ( E r r o r , ca ug ht ) ;
c aug ht . p r i n t S t a c k T r a c e ( ) ;
Window . a l e r t ( c au gh t . t o S t r i n g ( ) ) ;
}
public void o n S u c c e s s ( O b j e c t r e s u l t ) {
// V a r i a n t a 1
HTML html =
new HTML( <h1 s t y l e = b o r d e r : 1 px g r a y s o l i d ; c o l o r : r e d ; > +
Cmmdc = + r e s u l t . t o S t r i n g ( ) +</h1> ) ;
V e r t i c a l P a n e l vp = new V e r t i c a l P a n e l ( ) ;
vp . add ( html ) ;
RootPanel . g e t ( ) . add ( vp ) ;

130

// V a r i a n t a 2
// l o n g r e z =((Long ) r e s u l t ) . l o n g V a l u e ( ) ;
// Window . a l e r t (Cmmdc=+r e z ) ;
}

25
26
27
28
29

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

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

import
import
import
import
import
import
import
import
import
import
import

com .
com .
com .
com .
com .
com .
com .
com .
com .
com .
com .

google
google
google
google
google
google
google
google
google
google
google

. gwt . c o r e . c l i e n t . E n t r y P o i n t ;
. gwt . u s e r . c l i e n t . u i . Button ;
. gwt . u s e r . c l i e n t . u i . RootPanel ;
. gwt . u s e r . c l i e n t . u i . V e r t i c a l P a n e l ;
. gwt . u s e r . c l i e n t . u i . TextBox ;
. gwt . u s e r . c l i e n t . u i . L a b e l ;
. gwt . u s e r . c l i e n t . Window ;
. gwt . c o r e . c l i e n t .GWT;
. gwt . u s e r . c l i e n t . r p c . S e r v i c e D e f T a r g e t ;
. gwt . e v e n t . dom . c l i e n t . C l i c k E v e n t ;
. gwt . e v e n t . dom . c l i e n t . C l i c k H a n d l e r ;

public c l a s s CmmdcClient implements E n t r y P o i n t {


public void g e t R e s u l t ( long m, long n ) {
CmmdcServiceAsync cmmdcService=
( CmmdcServiceAsync )GWT. c r e a t e ( CmmdcService . c l a s s ) ;
S e r v i c e D e f T a r g e t s d t =( S e r v i c e D e f T a r g e t ) cmmdcService ;
S t r i n g e n d p o i n t=GWT. getModuleBaseURL ()+ cmmdcrpc ;
sdt . setServiceEntryPoint ( endpoint ) ;
cmmdcService . cmmdc(m, n , new CmmdcCallback ( ) ) ;
}
public void onModuleLoad ( ) {
L a b e l t i t l e =new L a b e l ( CMMDC ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
L a b e l mLabel=new L a b e l ( m= ) ;
L a b e l nLabel=new L a b e l ( n= ) ;
f i n a l L a b e l cmmdcLabel=new L a b e l ( ) ;
f i n a l TextBox mTextBox=new TextBox ( ) ;
f i n a l TextBox nTextBox=new TextBox ( ) ;
Button b ut to n = new Button ( Compute ) ;
bu tt on . addStyleName ( pct e m p l a t e btn ) ;
V e r t i c a l P a n e l cmmdcPanel = new V e r t i c a l P a n e l ( ) ;
cmmdcPanel . setWidth ( 100% ) ;
cmmdcPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
cmmdcPanel . add ( t i t l e ) ;
cmmdcPanel . add ( mLabel ) ;
cmmdcPanel . add ( mTextBox ) ;
cmmdcPanel . add ( nLabel ) ;
cmmdcPanel . add ( nTextBox ) ;
bu tt on . a d d C l i c k H a n d l e r (new C l i c k H a n d l e r ( ) {
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g sm=mTextBox . g e t T e x t ( ) ;
S t r i n g sn=nTextBox . g e t T e x t ( ) ;
long m=0 ,n=0;
i f ( sm . e q u a l s ( ) ) {
Window . a l e r t ( \ m\ nu e s t e dat ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}

3.2. GOOGLE WEB TOOLKIT (GWT)

i f ( sn . e q u a l s ( ) ) {
Window . a l e r t ( \ n \ nu e s t e dat ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
m=Long . par se Lon g ( sm ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ m\ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
n=Long . p ars eL ong ( sn ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ n \ nu e s t e numar ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
long c =0;
i f ( (m!=0)&&(n ! = 0 ) )
g e t R e s u l t (m, n ) ;

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

}
});
cmmdcPanel . add ( b ut to n ) ;
cmmdcPanel . add ( cmmdcLabel ) ;
RootPanel . g e t ( cmmdcPage ) . add ( cmmdcPanel ) ;

75
76
77
78
79

80
81

Serverul, adica implementarea serviciului este


1
2
3
5
6
7
8

package u n i t b v . c s . td . s e r v e r ;
import com . g o o g l e . gwt . u s e r . s e r v e r . r p c . R e m o t e S e r v i c e S e r v l e t ;
import u n i t b v . c s . td . c l i e n t . CmmdcService ;
public c l a s s CmmdcServiceImpl extends R e m o t e S e r v i c e S e r v l e t
implements CmmdcService {
public long cmmdc( long m, long n ) { . . . }
}

web.xml se completeaza cu
<servlet>
<servlet-name>cmmdcrpc</servlet-name>
<servlet-class>unitbv.cs.td.server.CmmdcServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cmmdcrpc</servlet-name>
<url-pattern>/cmmdcclient/cmmdcrpc</url-pattern>
</servlet-mapping>

Test GWT
Generand modulul GWT cu optiunea suplimentara -junit

131

132

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

webAppCreator -out catapp -junit cale catre\junit*.jar context.MyApp


n catalogul catapp se creaza suplimentar structura
catapp
. . .
|--> test
|
|-->
|
|
|
|
|
|
. . .

context
|--> client
|
|
MyAppTest.java
|
MyAppJUnit.gwt.xml

Obiectivele ant: test.dev si test.prod asigura efectuarea testelor prin intermediul lui junit.
In cazul unei aplicatii cu apel de procedura la distanta GWT sarcina
programatorului consta din (cu adaptarea corespunzatoare a denumirii clasei
MyApp):
Editarea clasei MyAppTest pe baza sablonului prezent;
Modificarea / adaptarea corespunzatoare a fisierului de configurare MyAppJUnit.gwt.xml.
Pentru aplicatia anterioara codul clasei unitbv.cs.td.client.CmmdcClientJUnit
este
1

package u n i t b v . c s . td . c l i e n t ;

import
import
import
import
import

public c l a s s CmmdcClientTest extends GWTTestCase {

4
5
6

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

u n i t b v . c s . td . s h a r e d .
com . g o o g l e . gwt . c o r e .
com . g o o g l e . gwt . j u n i t
com . g o o g l e . gwt . u s e r .
com . g o o g l e . gwt . u s e r .

FieldVerifier ;
c l i e n t .GWT;
. c l i e n t . GWTTestCase ;
c l i e n t . rpc . AsyncCallback ;
c l i e n t . rpc . ServiceDefTarget ;

public S t r i n g getModuleName ( ) {
return u n i t b v . c s . td . CmmdcClientJUnit ;
}
public void testCmmdcService ( ) {
// Crearea unui o b i e c t de a p e l a r e .
CmmdcServiceAsync cmmdcService = GWT. c r e a t e ( CmmdcService . c l a s s ) ;
S e r v i c e D e f T a r g e t t a r g e t = ( S e r v i c e D e f T a r g e t ) cmmdcService ;
t a r g e t . s e t S e r v i c e E n t r y P o i n t (GWT. getModuleBaseURL ( ) +
cmmdcclient /cmmdcrpc ) ;
delayTestFinish (10000);
// Apel s e r v e r .
cmmdcService . cmmdc ( 5 6 , 4 8 , new AsyncCallback<Long >() {
public void o n F a i l u r e ( Throwable ca ug ht ) {
f a i l ( Request f a i l u r e : + ca ug ht . g e t M e s s a g e ( ) ) ;
}

133

3.2. GOOGLE WEB TOOLKIT (GWT)

public void o n S u c c e s s ( Long r e s u l t ) {


a s s e r t T r u e ( r e s u l t . l o n g V a l u e ()==8);
finishTest ();
}
});

29
30
31
32
33

34
35

Fisierul de configurare CmmdcClientJUnit.gwt.xml are codul


1
2
3
4
6
7
8
10

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<module>
< ! I n h e r i t our a p p l i c a t i o n s main module .
< i n h e r i t s name= u n i t b v . c s . td . CmmdcClient />

>

< ! S p e c i f y t h e p a t h t o any remote s e r v i c e s .


>
< s e r v l e t path= / cmmdcclient /cmmdcrpc
c l a s s= u n i t b v . c s . td . s e r v e r . CmmdcServiceImpl />
</ module>

Exemplul 3.2.4 Aplicatie de consultare a unei baze de date. Se considera o


baza de date AgendaEMail alcatuita dintr-un singur tabel adrese (nume varchar(20), email varchar(30)). Se cere realizarea unei aplicatii de consultare a
agendei de adrese e-mail.
Codul interfetei
1
2
3
5
6
7
8

package u n i t b v . c s . td . c l i e n t ;
import j a v a . u t i l . L i s t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . r p c . R e m o t e S e r v i c e ;
public i n t e r f a c e A d r e s e S e r v i c e extends R e m o t e S e r v i c e {
public L i s t <S t r i n g > getEMail ( S t r i n g nume ) ;
public S t r i n g getNume ( S t r i n g e m a i l ) ;
}

Codul interfetei asincrone


1
2
3
5
6
7
8

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . r p c . A s y n c C a l l b a c k ;
import j a v a . u t i l . L i s t ;
public i n t e r f a c e A d r e s e S e r v i c e A s y n c {
public void getEMail ( S t r i n g nume , AsyncCallback<L i s t <S t r i n g >> c a l l b a c k ) ;
public void getNume ( S t r i n g e m a i l , AsyncCallback<S t r i n g > c a l l b a c k ) ;
}

Implementarea interfetei asincrone este (AdreseCallback.java)


1

package u n i t b v . c s . td . c l i e n t ;

import
import
import
import

4
5
6

com .
com .
com .
com .

google
google
google
google

. gwt .
. gwt .
. gwt .
. gwt .

user
core
user
user

.
.
.
.

client
client
client
client

. rpc . AsyncCallback ;
.GWT;
. Window ;
. ui . ;

134

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

import j a v a . u t i l . ;

public c l a s s A d r e s e C a l l b a c k implements A s y n c C a l l b a c k {
public void o n F a i l u r e ( Throwable ca ug ht ) {
GWT. l o g ( E r r o r , ca ug ht ) ;
c aug ht . p r i n t S t a c k T r a c e ( ) ;
Window . a l e r t ( c au gh t . t o S t r i n g ( ) ) ;
}

10
11
12
13
14

public void o n S u c c e s s ( O b j e c t r e s u l t ) {
f i n a l L a b e l l a b e l R e z=new L a b e l ( ) ;
Grid g r i d=new Grid ( 1 , 2 ) ;
i f ( r e s u l t instanceof S t r i n g ) {
S t r i n g nume=( S t r i n g ) r e s u l t ;
f i n a l L a b e l labelNume=new L a b e l ( ( S t r i n g ) r e s u l t ) ;
l a b e l R e z . s e t T e x t ( Numele c a u t a t : ) ;
g r i d . setWidget ( 0 , 0 , labelRez ) ;
g r i d . s e t W i d g e t ( 0 , 1 , labelNume ) ;
RootPanel . g e t ( r e z ) . add ( g r i d ) ;
}
i f ( r e s u l t instanceof L i s t ) {
f i n a l L i s t B o x l i s t A d r e s e=new L i s t B o x ( ) ;
L i s t <S t r i n g > l i s t =( L i s t <S t r i n g >) r e s u l t ;
f o r ( i n t i =0; i < l i s t . s i z e ( ) ; i ++){
l i s t A d r e s e . addItem ( ( S t r i n g ) l i s t . g e t ( i ) ) ;
}
labelRez . setText ( Adresele cautate : ) ;
g r i d . setWidget ( 0 , 0 , labelRez ) ;
g r i d . setWidget ( 0 , 1 , l i s t A d r e s e ) ;
RootPanel . g e t ( r e z ) . add ( g r i d ) ;
}
}

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

Codul programului client este


1

package u n i t b v . c s . td . c l i e n t ;

import
import
import
import
import
import
import

4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
21
22
23

com . g o o g l e . gwt . c o r e . c l i e n t . E n t r y P o i n t ;
com . g o o g l e . gwt . c o r e . c l i e n t .GWT;
com . g o o g l e . gwt . u s e r . c l i e n t . u i . ;
com . g o o g l e . gwt . u s e r . c l i e n t . r p c . S e r v i c e D e f T a r g e t ;
com . g o o g l e . gwt . e v e n t . dom . c l i e n t . C l i c k E v e n t ;
com . g o o g l e . gwt . e v e n t . dom . c l i e n t . C l i c k H a n d l e r ;
java . u t i l . ;

public c l a s s AgendaEMail implements E n t r y P o i n t {


public void findByNume ( S t r i n g nume ) {
A d r e s e S e r v i c e A s y n c a d r e s e S e r v i c e=
( A d r e s e S e r v i c e A s y n c )GWT. c r e a t e ( A d r e s e S e r v i c e . c l a s s ) ;
S e r v i c e D e f T a r g e t t a r g e t =( S e r v i c e D e f T a r g e t ) a d r e s e S e r v i c e ;
S t r i n g r e l a t i v e U R L=GWT. getModuleBaseURL ()+ a d r e s e ;
t a r g e t . setServiceEntryPoint ( relativeURL ) ;
a d r e s e S e r v i c e . getEMail ( nume , new A d r e s e C a l l b a c k ( ) ) ;
}
public void findByEMail ( S t r i n g e m a i l ) {
A d r e s e S e r v i c e A s y n c a d r e s e S e r v i c e=
( A d r e s e S e r v i c e A s y n c )GWT. c r e a t e ( A d r e s e S e r v i c e . c l a s s ) ;

3.2. GOOGLE WEB TOOLKIT (GWT)

S e r v i c e D e f T a r g e t t a r g e t =( S e r v i c e D e f T a r g e t ) a d r e s e S e r v i c e ;
S t r i n g r e l a t i v e U R L=GWT. getModuleBaseURL ()+ a d r e s e ;
t a r g e t . setServiceEntryPoint ( relativeURL ) ;
a d r e s e S e r v i c e . getNume ( e m a i l , new A d r e s e C a l l b a c k ( ) ) ;

24
25
26
27
28

30

public void onModuleLoad ( ) {


f i n a l Button b ut to n=new Button ( Cauta ) ;
f i n a l L a b e l l a b e l C r i t e r i u=new L a b e l ( C r i t e r i u l de c a u t a r e ) ;
f i n a l L a b e l l a b e l E n t i t a t e=new L a b e l ( E n t i t a t e a c a u t a t a ) ;
f i n a l L i s t B o x l i s t B o x C r i t e r i u=new L i s t B o x ( ) ;
f i n a l TextBox t e x t B o x E n t i t a t e=new TextBox ( ) ;

31
32
33
34
35

V e r t i c a l P a n e l a d r e s e P a n e l=new V e r t i c a l P a n e l ( ) ;
L a b e l t i t l e =new L a b e l ( Agenda de a d r e s e EMAIL ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
Grid g r i d=new Grid ( 2 , 2 ) ;
g r i d . setWidget ( 0 , 0 , l a b e l C r i t e r i u ) ;
l i s t B o x C r i t e r i u . addItem ( nume ) ;
l i s t B o x C r i t e r i u . addItem ( e m a i l ) ;
listBoxCriteriu . setVisibleItemCount ( 1 ) ;
g r i d . setWidget ( 0 , 1 , l i s t B o x C r i t e r i u ) ;
g r i d . setWidget ( 1 , 0 , l a b e l E n t i t a t e ) ;
g r i d . setWidget ( 1 , 1 , textBoxEntitate ) ;
bu tt on . a d d C l i c k H a n d l e r (new C l i c k H a n d l e r ( ) {
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g s=t e x t B o x E n t i t a t e . g e t T e x t ( ) ;
i f ( ! . equals ( s ) ) {
i f ( l i s t B o x C r i t e r i u . g e t S e l e c t e d I n d e x ()==0)
findByNume ( s ) ;
else
findByEMail ( s ) ;
}
}
});
a d r e s e P a n e l . add ( t i t l e ) ;
a d r e s e P a n e l . add ( g r i d ) ;
a d r e s e P a n e l . add ( bu tt on ) ;
RootPanel . g e t ( a d r e s e P a n e l ) . add ( a d r e s e P a n e l ) ;

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

Partea specifica aplicatiei din pagina Web (AgendaTelefonica.html ) este


<h1>AgendaEMail</h1>
<p>
<div id="adresePanel"> </div>
</p>
<p>
<div id="rez"> </div>
</p>

cu fixarea containerelor n care GWT include widget-urile grafice.


Implementarea interfetei, adica serverul, are codul
1
2
3
4

package u n i t b v . c s . td . s e r v e r ;
import u n i t b v . c s . td . c l i e n t . ;
import j a v a . u t i l . ;
import j a v a . s q l . ;

135

136

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

import com . g o o g l e . gwt . u s e r . s e r v e r . r p c . R e m o t e S e r v i c e S e r v l e t ;

public c l a s s A d r e s e S e r v i c e I m p l extends R e m o t e S e r v i c e S e r v l e t
implements A d r e s e S e r v i c e {
public s t a t i c f i n a l S t r i n g DRIVER=
o r g . apache . derby . j d b c . C l i e n t D r i v e r ;
public s t a t i c f i n a l S t r i n g PROTOCOL=
j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ;

8
9
10
11
12

public L i s t <S t r i n g > getEMail ( S t r i n g nume ) {


L i s t <S t r i n g > a d r e s e ;
try {
C l a s s . forName (DRIVER ) . n e w I n s t a n c e ( ) ;
C o n n e c t i o n con = DriverManager . g e t C o n n e c t i o n (PROTOCOL) ;
Statement s = con . c r e a t e S t a t e m e n t ( ) ;
ResultSet rs =
s . e x e c u t e Q u e r y ( SELECT e m a i l FROM a d r e s e where nume=\ +nume+ \ ) ;
a d r e s e=new A r r a y L i s t <S t r i n g > ( ) ;
while ( r s . n e x t ( ) ) {
a d r e s e . add ( r s . g e t S t r i n g ( e m a i l ) ) ;
}
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
a d r e s e=n u l l ;
}
finally {
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 i g n o r e ) {}
}
return a d r e s e ;
}

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

public S t r i n g getNume ( S t r i n g e m a i l ) {
S t r i n g nume= ;
try {
C o n n e c t i o n con = DriverManager . g e t C o n n e c t i o n (PROTOCOL) ;
Statement s = con . c r e a t e S t a t e m e n t ( ) ;
ResultSet rs =
s . e x e c u t e Q u e r y ( SELECT nume FROM a d r e s e where e m a i l =\ +e m a i l+ \ ) ;
i f ( r s . next ( ) )
nume=r s . g e t S t r i n g ( nume ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
nume=n u l l ;
}
finally {
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 i g n o r e ) {}
}
return nume ;
}

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

3.2. GOOGLE WEB TOOLKIT (GWT)

137

web.xml se completeaza cu
<servlet>
<servlet-name>adrese</servlet-name>
<servlet-class>unitbv.cs.td.server.AdreseServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>adrese</servlet-name>
<url-pattern>/agendaemail/adrese</url-pattern>
</servlet-mapping>

In plus, driverul bazei de date trebuie copiat n catalogul war\WEB-INF\lib.

3.2.4

Crearea unui widget client

In paralel cu oferta de clase widget puse la dispozitie de GWT exista posibilitatea de a crea widget-e propri sau client.
O varianta de creare este prezentata n continuare.
O arhitectura posibila a unei asemenea aplicatii este data n Fig. 3.2.
Desfasurarea bibliotecii de widget-e este delimitata prin linii orizontale.
Widget-ele apartin pachetului mywidgets. . . client. MyWidget.css contine clasele
css utilizate de widget-uri. Acest fapt este specificat n fisierul de configurare
Widgets.gwt.xml, avand codul
1
2
3
4
5
6
7
9
10

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


< !DOCTYPE module PUBLIC //Google I n c . / /DTD Google Web T o o l k i t 1 . 6 . 4 / /EN
h t t p : // g o o g l e webt o o l k i t . g o o g l e c o d e . com/ svn / t a g s / 1 . 6 . 4 /
d i s t r o s o u r c e / c o r e / s r c /gwtmodule . dtd >
<module renamet o= mywidgets >
< ! I n h e r i t t h e c o r e Web T o o l k i t s t u f f .
>
< i n h e r i t s name= com . g o o g l e . gwt . u s e r . User />
< s t y l e s h e e t s r c= MyWidget . c s s />
</ module>

Utilizarea bibliotecii mywidgets se declara n fisierul de configurare al aplicatiei


MyApp.gwt.xml prin
<inherits name=mywidgets...Widgets/>
Caracterul . . . corespunde lantului din definitia pachetului, mai putin client.
Clasa unui widget client extinde clasa
com.google.gwt.user.client.ui.Composite. Clasa Composite trebuie privita
ca o clasa acoperitoare unui obiect de tip Widget. Elementele care formeaza
interfata grafica a widget-ului client se includ ntr-un container reprezentabil
grafic (de exemplu VerticalPanel). Acest container este ncarcat de aplicatia
GWT care utilizeaza un widget client. In codul widget-ului client acest lucru

138

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

catapp
|--> src
---------------------------------------|
|--> mywidgets
|
|
|. . .
|
|
|
|--> client
|
|
|
|
|
WidgetClass1.java
|
|
|
|
|
. . .
|
|
|
|--> public
|
|
|
|
|
MyWidget.css
|
|
|
|
Widgets.gwt.xml
---------------------------------------|
|--> context
|
|
|--> client
|
|
|
|
MyApp.java
|
|
|. . .
|
|--> war
|
|
|. . .
|
.classpath
|
.project
|
MyApp.launch
|
README.txt
|
build.xml
Figure 3.2: Aplicatie GWT cu biblioteca de widget-e.

3.2. GOOGLE WEB TOOLKIT (GWT)

139

este exprimat prin protected void initWidget(Widget container ). Aceasta


metoda poate fi apelata o singura data.
Sablonul codului unui widget client este
package *.client;
import com.google.gwt.user.client.ui.Composite;
. . .
public class ClasaWidget extends Composite {
public ClasaWidget() {
. . .
initWidget(container);
}
. . .
}
Exemplul 3.2.5 Se creaza o biblioteca alcatuita din doua clase widget:
HelloNameWidget - genereaza un cadru cu un camp pentru nume si un
buton. Dupa clic pe buton apare mesajul Hello nume.
CmmdcWidget aplicatia anterioara transformata n widget.
Cele doua widget-e au codurile, respectiv
1
2
3
5
6
7
8
9
10
11
12
14
15
16
17
18
19
20
21
22
23
24
25
26

package mywidgets . c l i e n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . ;
import com . g o o g l e . gwt . e v e n t . dom . c l i e n t . ;
public c l a s s HelloNameWidget extends Composite {
public HelloNameWidget ( ) {
L a b e l t i t l e =new L a b e l ( H e l l o Name Widget ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
Button b ut to n = new Button ( Apasama ) ;
L a b e l nameLabel=new L a b e l ( I n t r o d u c e t i numele ) ;
f i n a l L a b e l s L a b e l=new L a b e l ( ) ;
f i n a l TextBox nameTextBox=new TextBox ( ) ;
bu tt on . addStyleName ( b ut to n ) ;
V e r t i c a l P a n e l vPanel = new V e r t i c a l P a n e l ( ) ;
vPanel . addStyleName ( v p a n e l ) ;
vPanel . add ( t i t l e ) ;
vPanel . setWidth ( 100% ) ;
vPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
vPanel . add ( nameLabel ) ;
vPanel . add ( nameTextBox ) ;
vPanel . add ( b ut to n ) ;
vPanel . add ( s L a b e l ) ;
bu tt on . a d d C l i c k H a n d l e r (new C l i c k H a n d l e r ( ) {
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g name=nameTextBox . g e t T e x t ( ) ;

140

s L a b e l . s e t T e x t ( H e l l o +name+ ! ) ;
}
});
i n i t W i d g e t ( vPanel ) ;

27
28
29
30

31
32

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

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

package mywidgets . c l i e n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . ;
import com . g o o g l e . gwt . u s e r . c l i e n t . Window ;
import com . g o o g l e . gwt . e v e n t . dom . c l i e n t . ;
public c l a s s CmmdcWidget extends Composite {
public CmmdcWidget ( ) {
L a b e l t i t l e =new L a b e l ( Cmmdc Widget ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
L a b e l mLabel=new L a b e l ( m= ) ;
L a b e l nLabel=new L a b e l ( n= ) ;
L a b e l cmmdcLabel=new L a b e l ( ) ;
TextBox mTextBox=new TextBox ( ) ;
TextBox nTextBox=new TextBox ( ) ;
Button b ut to n = new Button ( C a l c u l e a z a ) ;
bu tt on . addStyleName ( b ut to n ) ;
V e r t i c a l P a n e l cmmdcPanel = new V e r t i c a l P a n e l ( ) ;
cmmdcPanel . setWidth ( 100% ) ;
cmmdcPanel . addStyleName ( v p a n e l ) ;
cmmdcPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
cmmdcPanel . add ( t i t l e ) ;
cmmdcPanel . add ( mLabel ) ;
cmmdcPanel . add ( mTextBox ) ;
cmmdcPanel . add ( nLabel ) ;
cmmdcPanel . add ( nTextBox ) ;
CmmdcWidgetClickHandler c l i c k H a n d l e r=
new CmmdcWidgetClickHandler ( mTextBox , nTextBox , cmmdcLabel ) ;
bu tt on . a d d C l i c k H a n d l e r ( c l i c k H a n d l e r ) ;
cmmdcPanel . add ( b ut to n ) ;
cmmdcPanel . add ( cmmdcLabel ) ;

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

i n i t W i d g e t ( cmmdcPanel ) ;

33

34
35

37

c l a s s CmmdcWidgetClickHandler implements C l i c k H a n d l e r { . . . }

Codul aplicatiei GWT care foloseste widget-ele client definite anterior este

package u n i t b v . c s . td . c l i e n t ;
import com . g o o g l e . gwt . c o r e . c l i e n t . E n t r y P o i n t ;
import com . g o o g l e . gwt . u s e r . c l i e n t . u i . ;
import mywidgets . c l i e n t . ;

public c l a s s MyApp implements E n t r y P o i n t {

1
2
3

8
9
10

public void onModuleLoad ( ) {


H o r i z o n t a l P a n e l hPanel=new H o r i z o n t a l P a n e l ( ) ;
hPanel . s e t S p a c i n g ( 5 0 ) ;

3.2. GOOGLE WEB TOOLKIT (GWT)

CmmdcWidget cw=new CmmdcWidget ( ) ;


HelloNameWidget hnw=new HelloNameWidget ( ) ;
hPanel . add ( hnw ) ;
hPanel . add ( cw ) ;
RootPanel . g e t ( g i n t e r f a c e ) . add ( hPanel ) ;

11
12
13
14
15

16
17

141

3.2.5

Inc
arcarea unui fisier - GWT Upload

GWT ofera o solutie prefabricata problemei ncarcarii unui fisier al clientului pe calculatorul server.
Aplicatia GWT corespunde clientului care alege fisierul de ncarcat si transmite datele unui server receptor, reprezentat, n cazul exemplului dezvoltat, de
un servlet. Clasele widget ajutatoare sunt FormPanel si FileUpload. Intr-un
container FormPanel pot fi incluse widgete de tip TextBox, PasswordTextBox,
RadioButton, CheckBox, TextArea, FileUpload, Hidden.
Dintre metodele care intervin la ncarcarea unui fisier amintim:
public void setAction(String url )
public void setMethod(FormPanel.METHOD POST)
In alt context se poate folosi FormPanel.METHOD GET.
public void setEncoding(FormPanel.ENCODING MULTIPART)
In alt context se poate folosi FormPanel.ENCODING URLENCODED.
public void submit()
HandlerRegistration addSubmitHandler(FormPanel.SubmitHandler
handler )
Interfata SubmitHandler
HandlerRegistration addSubmitCompleteHandler(FormPanel.
SubmitCompleteHandler handler )
Fiecare din interfetele SubmitHandler si SubmitCompleteHandler declara metoda
void onSubmit(FormPanel.SubmitEvent event) n care se programeaza activitatile naintea expedierii formularului si respectiv, dupa receptia raspunsului
furnizat de servlet.
Widgetul UploadFile afiseaza o fereastra de dialog prin care se selecteaza
fisierul ce umeaza a fi ncarcat.
Codul clasei client este

142

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

package u n i t b v . c s . td . c l i e n t ;

import
import
import
import
import

4
5
6
7
9
10
11
12
13
14

com .
com .
com .
com .
com .

google
google
google
google
google

. gwt . c o r e . c l i e n t . ;
. gwt . u s e r . c l i e n t . Window ;
. gwt . u s e r . c l i e n t . u i . ;
. gwt . e v e n t . dom . c l i e n t . C l i c k E v e n t ;
. gwt . e v e n t . dom . c l i e n t . C l i c k H a n d l e r ;

public c l a s s Upload implements E n t r y P o i n t {


public void onModuleLoad ( ) {
f i n a l FormPanel form = new FormPanel ( ) ;
form . s e t A c t i o n ( h t t p : / / l o c a l h o s t : 8 0 8 0 / u pl oa d / u pl oa d ) ;
form . s e t E n c o d i n g ( FormPanel .ENCODING MULTIPART ) ;
form . setMethod ( FormPanel .METHOD POST) ;
L a b e l t i t l e =new L a b e l ( F i l e u pl oa d ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;

16
17

20

V e r t i c a l P a n e l p a n e l = new V e r t i c a l P a n e l ( ) ;
form . s e t W i d g e t ( p a n e l ) ;

22

p a n e l . add ( t i t l e ) ;

24

// Crearea unui w i d g e t F i l e U p l o a d
F i l e U p l o a d up lo ad = new F i l e U p l o a d ( ) ;
up l oad . setName ( uploadFormElement ) ;
p a n e l . add ( u pl oa d ) ;

19

25
26
27

// Adaugarea unui b u t o n s u b m i t
p a n e l . add (new Button ( Submit , new C l i c k H a n d l e r ( ) {
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
form . submit ( ) ;
}
}));

29
30
31
32
33
34

// A c t i v i t a t i p r e m e r g a t o a r e e x p e d i e r i i f o r m u l a r u l u i .
form . addSubmitHandler (new FormPanel . SubmitHandler ( ) {
public void onSubmit ( FormPanel . SubmitEvent e v e n t ) {
}
});

36
37
38
39
40

// A c t i v i t a t i l a r e c e p t i o n a r e a r a s p u n s u l u i
form . addSubmitCompleteHandler (new FormPanel . SubmitCompleteHandler ( ) {
public void onSubmitComplete ( FormPanel . SubmitCompleteEvent e v e n t ) {
S t r i n g r e s u l t s=e v e n t . g e t R e s u l t s ( ) ;
Window . a l e r t ( r e s u l t s ) ;
}
});
RootPanel . g e t ( ) . add ( form ) ;

42
43
44
45
46
47
48
49

50
51

Servlet-ul utilizeaza pachetele apache commons-fileupload, commons-io si


se va instala n catalogul upload a serverului Web apache-tomcat. Fisierele
ncarcate de client se vor salva n catalogul . . . \webapps\upload\upload. Codul
servet-ului este
1

package up l oad ;

3.2. GOOGLE WEB TOOLKIT (GWT)

17

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

19

@WebServlet ( u r l P a t t e r n s = / u pl oad )

21

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 {

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

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

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

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 {
S t r i n g f s=System . g e t P r o p e r t y ( f i l e . s e p a r a t o r ) ;
S t r i n g pathTomcat = new F i l e ( . ) . g e t C a n o n i c a l P a t h ( ) ;
S t r i n g c o n t e x t P a t h=r e q . g e t C o n t e x t P a t h ( ) ;
r e s . setContentType ( t e x t / p l a i n ) ;
S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
try {
S e r v l e t F i l e U p l o a d up lo ad = new S e r v l e t F i l e U p l o a d ( ) ;
F i l e I t e m I t e r a t o r i t e r = up lo ad . g e t I t e m I t e r a t o r ( r e q ) ;
while ( i t e r . hasNext ( ) ) {
F i l e I t e m S t r e a m item = i t e r . n e x t ( ) ;
S t r i n g name = item . getFieldName ( ) ;
out . p r i n t l n ( name ) ;
i f ( ! item . i s F o r m F i e l d ( ) ) {
S t r i n g f i l e N a m e = item . getName ( ) ;
out . p r i n t l n ( f i l e N a m e ) ;
InputStream i n=item . openStream ( ) ;
F i l e f i l e =new F i l e ( pathTomcat+f s+ webapps +
c o n t e x t P a t h+f s+ up lo ad +f s+f i l e N a m e ) ;
byte [ ] b=new byte [ 1 0 2 4 ] ;
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 ( f i l e ) ;
i n t s =0;
do{
s=i n . r e a d ( b , 0 , 1 0 2 4 ) ;
i f ( s !=1)
fos . write (b ,0 , s ) ;
}
while ( s != 1);
fos . close ();
in . close ( ) ;
out . p r i n t l n ( The f i l e +f i l e N a m e+ has been u p l o a d e d ! ) ;
out . c l o s e ( ) ;
}
}
}
catch ( E x c e p t i o n e ) {

143

144

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

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

61

62

63
64

Pentru utilizarea aplicatiei client n modul Web, dupa compilare, continutul


catalogului war se copiaza n catalogul . . . \webapps din apache-tomcat. Dintrun navigator, clientul se apeleaza prin
http://host:8080/GwtUpload/GwtUpload.html.

3.2.6

Dezvoltarea unei aplicatii GWT prin maven

Aplicatia se genereaza cu
set groupId=. . .
set artifactid=. . .
set module=. . .
set version=. . .
set gwt-version=. . .
mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo
-DarchetypeArtifactId=gwt-maven-plugin
-DarchetypeVersion=%gwt-version%
-DgroupId=%groupId%
-DartifactId=%artifactId%
-Dmodule=%module%
-Dversion=%version%
-DinteractiveMode=false
Procesarea maven este mvn clean package.

3.2.7

GWT prin Google AppEngine

Integrarea unei aplicatii client GWT n platforma Google AppEngine (GAE)


de Cloud Computing, necesita executarea urmatoarelor operatii:
1. Se compileaza aplicatia GWT n vederea utilizarii n modul Web;
2. Catalogul war se completeaza cu fisierul appengine-web.xml plasandu-l
n catalogul WEB-INF;
3. Catalogul war se redenumeste www.
Din catalogul care contine catalogul www se lanseaza simulatorul GAE.

3.2. GOOGLE WEB TOOLKIT (GWT)

145

Exemplul 3.2.6 Integrarea aplicatiei GWT de calcul a celui mai mare divizor
comun n platforma Google de Cloud Computing.
In urma operatiilor de mai sus rezulta structura
gwtcmmdc
|--> www
|
|-->
|
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

cmmdc
| . . .
WEB-INF
|--> classes
|
| . . .
|--> lib
|
| . . .
|
appengine-web.xml
|
web.xml
Cmmdc.html
Cmmdc.css

Dupa lansarea simulatorului GAE, aplicatia se apeleaza prin


http://localhost:8080/Cmmdc.html.

146

CAPITOLUL 3. ASYNCHRONOUS JAVASCRIPT AND XML AJAX

Partea II
SERVICII WEB

147

Capitolul 4
Servicii JAX-WS
Un serviciu Web este o aplicatie client-server cu serverul gazduit de un
server Web, apelabil prin aplicatia client si realizat potrivit unei interfete de
programare specifice. Protocolul de comunicatie este http.
Sunt cunoscute urmatoarele tipuri de servicii Web:
Servicii bazate pe modelul Remote Precedure Call (RPC) - Apel de Procedura de la Distanta.
Protocolul de reprezentare a cererii si a raspunsului (de serializare /
deserializare) variaza. Din acest punct de vedere sunt cunoscute:
Servicii xml-rpc (www.xmlrpc.org). Cererea si raspunsul sunt transmise prin cod xml cuprins n corpul mesajului http.
Servicii json-rpc (www.json-rpc.org) bazat pe reprezentarea JSON.
Servicii hessian. Se utilizeaza un protocol pentru serializare / deserealizare bazat pe reprezentarea binara a datelor. Protocolul a fost
dezvoltat de firma Caucho Technologies (2007).
Servicii bazate pe interfata de programare Java API for XML Web
Services - JAX-WS. Interfata de programare JAX-WS este varianta
cea mai recenta pentru serviciile cunoscute sub numele de servicii
soap-rpc.
Pentru fiecare caz semnalat mai sus sunt realizate implementari n mai
multe limbaje / platforme de programare.
Servicii REST.
149

150

CAPITOLUL 4. SERVICII JAX-WS

REpresentational State Transfer (REST) este un model de arhitectura


de aplicatie distribuita1 .
REST specifica modul cum o resursa - entitate care contine informatie
specifica - este definita si cum poate fi adresata.
Identificarea unei resurse se face printr-un URI (Universal Resource Identifier ).
Interfata standard de programare a unui serviciu REST este Java API
for XML Restful Services - JAX-WS.
Transferul resursei catre un client si prelucrarea resursei se face prin
operatii indicate de antetele mesajului http GET, POST, PUT, DELETE, etc.

4.1

Descrierea unui serviciu

Spre deosebire de aplicatiile bazate pe apelul de procedura la distanta


(RMI, CORBA,) unde prezentarea ofertei se face printr-o interfata Java, ntrun serviciu JAX-WS, JAX-RS descrierea sau specificarea acestuia se realizeaza
prin sublimbaje xml:
Web Service Description Language - WSDL pentru servicii JAX-WS.
Descrierea datelor din mesajele vehiculate se face prin XML Schema, de
asemenea un sublimbaj xml.
Web Application Description Language - WADL pentru servicii JAX-RS.
Mesajele dintre client si server folosesc protocolul de reprezentare Simple
Object Access Protocol - SOAP care este independent de platforma de calcul si
de limbajul de programare. SOAP este tot un sublimbaj xml, standard World
Wide Web Consortium - W3C. In instrumentele actuale de dezvoltare, SOAP
este transparent programatorului, dar Java ofera suport de programare prin
pachetul javax.xml.soap.
Produsul soapUI ofera posibilitatea vizualizarii mesajelor SOAP ale serviciilor Web pornind de la descrierea acestora prin WSDL, respectiv WADL.
Consideram familiarizarea cu XML-Schema si WSDL importanta.
1

REST a fost introdus de Roy Fielding, n teza sa de doctorat din 2000. Roy Fielding
este autorul principal al specificatiilor protocolului http.

4.1. DESCRIEREA UNUI SERVICIU

4.1.1

151

XML Schema

O schema este un model pentru descrierea structurii informatiei. In contextul xml, o schema descrie un model pentru o familie de documente xml.
Primul obiectiv al unei scheme este de a permite validarea automata a
structurii unui document xml.
Familiarizarea cu elementele de continut si sintaza XML Schema se va
ncepe cu un exemplu:
Documentul struct.xml
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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<m k : s t r u c t u r a xmlns:mk= h t t p : //www. d i s t r 2 . edu
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 : //www. d i s t r 2 . edu s t r u c t schema . xsd >
<m k : d i s c i p l i n a f e l = o b l i g a t o r i u >
<mk:nume> A n a l i z a numerica </mk:nume>
<mk:fonddetimp>
<m k : c u r s>2</ m k : c u r s>
<mk:seminar>1</ mk:seminar>
<m k : l a b o r a t o r>1</ m k : l a b o r a t o r>
</ mk:fonddetimp>
</ m k : d i s c i p l i n a>
<m k : d i s c i p l i n a f e l = o b l i g a t o r i u >
<mk:nume> Programare d i s t r i b u i t a </mk:nume>
<mk:fonddetimp>
<m k : c u r s>2</ m k : c u r s>
<mk:seminar>0</ mk:seminar>
<m k : l a b o r a t o r>2</ m k : l a b o r a t o r>
</ mk:fonddetimp>
</ m k : d i s c i p l i n a>
<m k : d i s c i p l i n a f e l = o b l i g a t o r i u >
<mk:nume> S o f t matematic </mk:nume>
<mk:fonddetimp>
<m k : c u r s>2</ m k : c u r s>
<mk:seminar>0</ mk:seminar>
<m k : l a b o r a t o r>1</ m k : l a b o r a t o r>
</ mk:fonddetimp>
</ m k : d i s c i p l i n a>
</ m k : s t r u c t u r a>

de exemplu, are schema struct-schema.xsd


1
2
3
4
6
7
8
9
10
11
12

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<x s d : s c h e m a x m l n s : x s d= h t t p : //www. w3 . o r g /2001/XMLSchema
xmlns:mk= h t t p : //www. d i s t r 2 . edu
t a r g e t N a m e s p a c e= h t t p : //www. d i s t r 2 . edu >
<x s d : e l e m e n t name= s t r u c t u r a >
<xsd:complexType>
<x s d : c h o i c e minOccurs= 0 maxOccurs= unbounded >
<x s d : e l e m e n t r e f= m k : d i s c i p l i n a />
</ x s d : c h o i c e>
</ xsd:complexType>
</ x s d : e l e m e n t>

152

CAPITOLUL 4. SERVICII JAX-WS

22

<x s d : e l e m e n t name= d i s c i p l i n a >


<xsd:complexType mixed= t r u e >
<x s d : s e q u e n c e>
<x s d : e l e m e n t r e f=mk:nume />
<x s d : e l e m e n t r e f= mk:fonddetimp />
</ x s d : s e q u e n c e>
< x s d : a t t r i b u t e name= f e l t y p e= x s d : s t r i n g u s e= r e q u i r e d />
</ xsd:complexType>
</ x s d : e l e m e n t>

24

<x s d : e l e m e n t name=nume t y p e= x s d : s t r i n g />

26

34

<x s d : e l e m e n t name= fonddetimp >


<xsd:complexType mixed= t r u e >
<x s d : s e q u e n c e>
<x s d : e l e m e n t r e f= m k : c u r s />
<x s d : e l e m e n t r e f= mk:seminar />
<x s d : e l e m e n t r e f= m k : l a b o r a t o r />
</ x s d : s e q u e n c e>
</ xsd:complexType>
</ x s d : e l e m e n t>

36

<x s d : e l e m e n t name= c u r s t y p e= x s d : s t r i n g />

38

<x s d : e l e m e n t name= s e m i n a r t y p e= x s d : s t r i n g />

40

<x s d : e l e m e n t name= l a b o r a t o r t y p e= x s d : s t r i n g />


</ x s d : s c h e m a>

14
15
16
17
18
19
20
21

27
28
29
30
31
32
33

41

Alte marcaje utilizabile sunt:

<xsd:simpleType name=". . ." >


<xsd:restriction base="xsd:string" >
<xsd:maxLength value="n" />
<xsd:pattern value="[0-9]" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="aaa" >
<xsd:sequence>
<xsd:element name="bbb" type="ccc"
minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

Tipuri simple: string, byte, integer, decimal, boolean, time, date, etc.
Grupuri. Se pot defini grupuri de elemente si de atribute
<xsd:group name="tipElementDisciplina" >
<xsd:sequence>
<xsd:element name="nume" type="tipNume" />
<xsd:element name="fond-de-timp" type="tipFondTimp" />
</xsd:sequence>
</xsd:group>
<xsd:attributeGroup name="atribDisciplina" >
<xsd:attribute name="fel" type="xsd:string" use="required" />
<xsd:attribute name="finalizare" type="xsd:string" />

4.1. DESCRIEREA UNUI SERVICIU

153

</xsd:attributeGroup>
<xsd:complexType name="tipdisciplina" >
<xsd:sequence>
<xsd:group ref="tipElementDisciplina" />
<xsd:attributeGroup ref="attribDisciplina" />
<xsd:sequence>
</xsd:complexType>

Comentariile
destinate a fi citite de oameni se introduc n marcajul xsd:documentation;
destinate a fi procesate se introduc n marcajul xsd:appinfo
Ambele marcaje trebuie inglobate n xsd:annotation.
<xsd:annotation>
<xsd:documentation xml:lang="en">
text
</xsd:documentation>
<xsd:appinfo source=". . ." >
<bind xmlns=". . ." >
<class name=". . ." />
</bind>
</xsd:appinfo>
</xsd:annotation>

Schemele se pot compune prin


<xsd:include schemaLocation="fisier.xsd" />
Pentru a evita conflictul ntre numele atribuite diverselor elemente se introduc:
Spatiul de nume - namespace - definit ca un sir de caractere sub forma
unui URI (Universal Resource Identifier);
Numele calificat - QName qualified name - alcatuit dintr-un nume local
asociat cu namespace.
Procesarea documentelor xml face apel la numele calificat al unei entitati.
Un spatiu de nume se defineste prin
<xsd:schema targetNamespace="numeleSpatiuluiDeNume"
xmlns:prefix="numeleSpatiuluiDeNume"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Prin folosirea prefixului se specifica spatiul de nume al fiecarei entitati
utilizate.

154

4.1.2

CAPITOLUL 4. SERVICII JAX-WS

WSDL

WSDL (Web Service Description Language) este un limbaj xml pentru


descrierea serviciilor Web.
Presupunem existenta urmatoarelor entitati
|| Server Web la adresa http://localhost:8080
||
Serviciu Web /CmmdcWS
||
Operatie
||
Nume: cmmdc
||
Operatie
||
Nume: . . .

Serviciul se va apela prin http://localhost:8080/CmmdcWS. Aceasta referinta


se numeste punct final - endpoint.
Pentru a evita conflictul ntre numele atribuite diverselor elemente se utilizeaza denumiri calificate. iar structura de mai sus devine
|| Server Web la adresa http://localhost:8080
||
Serviciu Web /CmmdcWS
||
Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Operatie
||
Nume local: . . .

Pentru acest exemplu, operatia este definita de o metoda avand doi parametrii
si returneaza un rezultat:
|| Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Parametrii:
||
m: string
||
n: string
||
Returneaza:
||
string

Tipurile (string, int, long, etc) utilizate sunt precizate n spatiul de nume
http://www.w3.org/2001/XMLSchema.
Definirea operatiei devine
|| Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Parametrii:
||
m: string din http://www.w3.org/2001/XMLSchema
||
n: string din http://www.w3.org/2001/XMLSchema
||
Returneaza:
||
string din http://www.w3.org/2001/XMLSchema

In terminologia serviciilor Web RPC se utilizeaza


mesaj de intrare - input message - pentru datele de apelare a unei metode;

4.1. DESCRIEREA UNUI SERVICIU

155

parte - part - pentru un parametru al mesajului de intrare;


mesaj de iesire - output message - pentru datele returnate de operatie.
Asfel vom avea
|| Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Input message:
||
Part 1:
||
Name: m
||
Type: string din http://www.w3.org/2001/XMLSchema
||
Part 2:
||
Name: n
||
Type: string din http://www.w3.org/2001/XMLSchema
||
Output message:
||
Part:
||
Name: return
||
Type: string din http://www.w3.org/2001/XMLSchema

Codul unui mesaj de intrare poate fi


<pre:cmmdc xmlns:pre="http://cs.unitbv.ro/ws">
<m>56</m>
<n>48</n>
</pre:cmmdc>

iar mesajul de iesire poate fi


<pre:cmmdc xmlns:pre="http://cs.unitbv.ro/ws">
<return>8</return>
</pre:cmmdc>

XMLSchema permite definirea de tipuri complexe:


<xsd:schema targetNamespace="http://cs.unitbv.ro/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cmmdcRequest">
<xsd:complexType>
<xsd:element name="m" type="xsd:string"/>
<xsd:element name="n" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Definirea operatiei va consta din


1. schema
<xsd:schema targetNamespace="http://cs.unitbv.ro/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cmmdcRequest">
<xsd:complexType>
<xsd:element name="m" type="xsd:string"/>
<xsd:element name="n" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>

156

CAPITOLUL 4. SERVICII JAX-WS

2. operatia propriu-zisa
|| Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Input message:
||
Part 1:
||
Name: cerereCmmdc
||
Type: cmmdcRequest din http://cs.unitbv.ro/ws
||
Output message:
||
Part 1:
||
Name: return
||
Type: string din http://www.w3.org/2001/XMLSchema

iar mesajul de intrare va fi


<pre:cmmdcRequest xmlns:pre="http://cs.unitbv.ro/ws">
<m>56</m>
<n>48</n>
</pre:cmmdcRequest>

Extindem incluzand si raspunsul oferit de operatie


1. schema
<xsd:schema targetNamespace="http://cs.unitbv.ro/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cmmdcRequest">
<xsd:complexType>
<xsd:element name="m" type="xsd:string"/>
<xsd:element name="n" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="responseCmmdc" type="xsd:string"/>
</xsd:schema>

2. operatia propriu-zisa
|| Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Input message:
||
Part 1:
||
Name: cerereCmmdc
||
Type: cmmdcRequest din http://cs.unitbv.ro/ws
||
Output message:
||
Part 1:
||
Name: raspunsCmmdc
||
Type: responseCmmdc din http://cs.unitbv.ro/ws

Raspunsul va fi
<pre:cmmdcResponse xmlns:pre="http://cs.unitbv.ro/ws">
8
</pre:cmmdcResponse>

4.1. DESCRIEREA UNUI SERVICIU

157

Acest mod de definire a unui serviciu Web poarta numele de stilul document 2 . Acest stil este impus de WS-I (Web Services Interoperability organization).
Determinarea operatiei apelate se face exclusiv pe baza tipului din mesajul
de intrare. Nu pot exista doua operatii cu datele de intrare definite prin acelasi
nume calificat.
Asambland, se obtine
|| Server Web la adresa http://localhost:8080
||
Schema
||
. . .
||
Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Input message:
||
Part 1:
||
Name: cerereCmmdc
||
Type: cmmdcRequest din http://cs.unitbv.ro/ws
||
Output message:
||
Part 1:
||
Name: raspunsCmmdc
||
Type: responseCmmdc din http://cs.unitbv.ro/ws

PortType. Operatiile sunt grupate n colectii numite PortType. Un PortType este denumita printr-un nume calificat (nume local si namespace).
|| Server Web la adresa http://localhost:8080
||
Schema
||
. . .
||
||
PortType
||
Nume local: functiiWS
||
Namespace: http://cs.unitbv.ro/ws
||
||
Operatie
||
Nume local: cmmdc
||
Namespace: http://cs.unitbv.ro/ws
||
Input message:
||
Part 1:
||
Name: cerereCmmdc
||
Type: cmmdcRequest din http://cs.unitbv.ro/ws
||
Output message:
||
Part 1:
||
Name: raspunsCmmdc
||
Type: responseCmmdc din http://cs.unitbv.ro/ws
||
||
Operatie
||
. . .
||
||
PortType
||
. . .
2

Un alt mod de definire, nerecomandat n prezent, este stilul RPC.

158

CAPITOLUL 4. SERVICII JAX-WS

Binding. Prin binding se specifica protocolul utilizat pentru prelucrarea si


transmiterea mesajelor. Cel mai utilizat protocol pentru prelucrarea mesajelor
- aproape complet transparent programatorului - este Simple Object Access
Protocol SOAP, iar pentru transportul mesajelor este Hyper Text Transport
Protocol HTTP.
||
||
||
||

Name
Port type
Format
Transport

:
:
:
:

binding1
functiiWS
SOAP
HTTP

Port. Serviciul se poate instala / desfasura pe mai multe calculatoare.


Fiecare asemenea calculator devine un port. Implementarea propriu-zisa a
operatiilor poate fi diferita - chiar n limbaje de programare diferite.
Astfel, obtinem urmatoarea descriere a serviciului
|| Serviciu Web
||
Schema
||
. . .
||
||
PortType
||
Nume local: functiiWS
||
Namespace: http://cs.unitbv.ro/ws
||
||
Operatie
||
. . .
||
||
PortType
||
. . .
||
||
Binding
||
Name
: binding1
||
Port type : functiiWS
||
Format
: SOAP
||
Transport : HTTP
||
. . .
||
||
Port
||
Name
: port1
||
Binding : binding1
||
Endpoint:
||
. . .

Toate notiunile introduse pentru descrierea serviciului Web vor face parte
dintr-un acelasi spatiu de nume targetNamespace
|| Serviciu Web
|| Target namespace: http://cs.unitbv.ro/ws
||
Schema
||
. . .
||
||
PortType

4.1. DESCRIEREA UNUI SERVICIU

||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||
||

159

Nume local: functiiWS


Namespace: http://cs.unitbv.ro/ws
Operatie
. . .
PortType
. . .
Binding
Name
Port type
Format
Transpoat
. . .
Port
Name
:
Binding :
Endpoint:
. . .

:
:
:
:

binding1
functiiWS
SOAP
HTTP

port1
binding1

Aceasta descriere a unui serviciu Web corespunde standardului WSDL.


Structura unui document wsdl cuprinde
<definitions>
<types>
Definirea tipurilor de date utilizate
</types>
<message>
Definirea mesajelor utilizate. Un mesaj corespunde
parametrilor sau rezultatelor functiilor ce compun
serviciul.
</message>
<portType>
Declara functiile serviciului.
Un port defineste un punct de conexiune cu serviciul Web.
</portType>
<binding>
Declara protocoalele utilizate de serviciul web.
</binding>
</definitions>
Pentru un serviciu Web, documentul wsdl generat depinde de produsul informatic care sustine serviciul Web. Functie de acest produs, sunt introduse n
documentul wsdl si alte elemente.

160

CAPITOLUL 4. SERVICII JAX-WS

Exemplul 4.1.1 Fisierul wsdl pentru serviciul Web de calcul a celui mai
mare divizor comun a doua numere naturale generat de Metro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

<?xml version= 1 . 0 e n c o d i n g= UTF8 ?>


< ! P u b l i s h e d by JAXWS RI a t h t t p : // j a x ws . dev . j a v a . n e t .
RI s v e r s i o n i s Metro / 2 . 3
( t a g s / 2 . 3 7 5 2 8 ; 20130429 T 1 9 : 3 4 : 1 0 +0000)
JAXWSRI / 2 . 2 . 8 JAXWS/ 2 . 2 svnr e v i s i o n#unknown . >
<! Generated by JAXWS RI a t h t t p : // jax ws . dev . j a v a . n e t .
RI s version i s Metro / 2 . 3 ( t a g s /2.3 7528; 20130429 T 1 9 : 3 4 : 1 0 +0000)
JAXWSRI / 2 . 2 . 8 JAXWS/ 2 . 2 svnr e v i s i o n#unknown . >
< d e f i n i t i o n s xmlns:wsu=
h t t p : // d o c s . o a s i s open . o r g / wss /2004/01/ o a s i s 200401wss
w s s e c u r i t y u t i l i t y 1 . 0 . xsd
xmlns:wsp= h t t p : //www. w3 . o r g / ns /wsp o l i c y
x m l n s : w s p 1 2= h t t p : // schemas . xmlsoap . o r g /ws /2004/09/ p o l i c y
xmlns:wsam= h t t p : //www. w3 . o r g /2007/05/ a d d r e s s i n g / metadata
x m l n s : s o a p= h t t p : // schemas . xmlsoap . o r g / wsdl / soap /
x m l n s : t n s= h t t p : // s e r v e r . cmmdc/
x m l n s : x s d= h t t p : //www. w3 . o r g /2001/XMLSchema
xmlns= h t t p : // schemas . xmlsoap . o r g / wsdl /
t a r g e t N a m e s p a c e= h t t p : // s e r v e r . cmmdc/
name=CmmdcWSService>
<t y p e s>
<x s d : s c h e m a>
<x s d : i m p o r t namespace= h t t p : // s e r v e r . cmmdc/
s c h e m a L o c a t i o n= h t t p : // j o n a t h a n : 8 0 8 0 / jaxwscmmdc/cmmdcws? xsd=1 />
</ x s d : s c h e m a>
</ t y p e s>
<message name=cmmdc>
<p a r t name= p a r a m e t e r s e l e m e n t= tns:cmmdc />
</ message>
<message name= cmmdcResponse >
<p a r t name= p a r a m e t e r s e l e m e n t= tns:cmmdcResponse />
</ message>
<portType name=CmmdcWS>
<o p e r a t i o n name=cmmdc>
<i n p u t
wsam:Action= h t t p : // s e r v e r . cmmdc/CmmdcWS/ cmmdcRequest
message= tns:cmmdc />
<ou tp ut
wsam:Action= h t t p : // s e r v e r . cmmdc/CmmdcWS/ cmmdcResponse
message= tns:cmmdcResponse />
</ o p e r a t i o n>
</ portType>
<b i n d i n g name=CmmdcWSPortBinding t y p e=tns:CmmdcWS>
<s o a p : b i n d i n g
t r a n s p o r t= h t t p : // schemas . xmlsoap . o r g / soap / h t t p
s t y l e= document />
<o p e r a t i o n name=cmmdc>
<s o a p : o p e r a t i o n s o a p A c t i o n= />
<i n p u t>
<s o a p : b o d y u s e= l i t e r a l />
</ i n p u t>
<ou tp ut>
<s o a p : b o d y u s e= l i t e r a l />
</ ou tp ut>
</ o p e r a t i o n>

4.1. DESCRIEREA UNUI SERVICIU

56
57
58
59
60
61
62
63
64

161

</ b i n d i n g>
< s e r v i c e name=CmmdcWSService>
<p o r t name=CmmdcWSPort
b i n d i n g= tns:CmmdcWSPortBinding >
<s o a p : a d d r e s s
l o c a t i o n= h t t p : // j o n a t h a n : 8 0 8 0 / jaxwscmmdc/cmmdcws />
</ p o r t>
</ s e r v i c e>
</ d e f i n i t i o n s>

4.1.3

Mesaje SOAP

Un mesaj SOAP este un document XML constand din


o nvelitoare (envelope) care poate contine
un numar arbitrar de antete (header );
un corp (body);
un numar variabil de obiecte atasate (attachments) MIME (Multipurpose
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>
Facilitatile Java de manipulare a mesajelor SOAP sunt continute n pachetul javax.xml.soap, din distributia jdk.
Crearea unui mesaj SOAP
MessageFactory mf=MessageFactory.newInstance();
SOAPMessage soapMsg=mf.createMessage();
Mesajul creat are definita structura de baza a mesajului SOAP: invelitoarea, un antet si corp. Aceste elemente pot fi accesate prin

162

CAPITOLUL 4. SERVICII JAX-WS

SOAPPart part=soapMsg.getSOAPPart();
SOAPEnvelope envelope=part.getEnvelope();
SOAPHeader header=envelope.getHeader();
SOAPBody body=envelope.getBody();
Completarea corpului unui mesaj SOAP
Oricarui element n este asociat un obiect javax.xml.soap.Name. Din
acest obiect se pot afla
String getLocalName()
String getPrefix()
String getURI()
String getQualifiedName()
Numele calificat are structura
<prefix:NumeleLocal xmlns:prefix="uri">

Elementul cu numele local e1 se genereaza prin


Name n1=envelope.createName("e1");
In body un element se poate include, pe baza numelui creat prin
SOAPElement e1=body.addBodyElement(n1);
In general, un element se include n elementul parinte, care poate fi chiar si
body, prin metoda clasei SOAPElement
SOAPElement addChildElement(Name name)
Completam elementul e1 cu un text: primul, prin
e1.addTextNode("primul");
Exemplul 4.1.2 Mesajul SOAP

4.1. DESCRIEREA UNUI SERVICIU

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>

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

import
import
import
import
import
import
import
import

j a v a x . xml . soap . M es sa geF ac tor y ;


j a v a x . xml . soap . SOAPMessage ;
j a v a x . xml . soap . SOAPPart ;
j a v a x . xml . soap . SOAPEnvelope ;
j a v a x . xml . soap . SOAPBody ;
j a v a x . xml . soap . SOAPElement ;
j a v a x . xml . soap . Name ;
java . i o . FileOutputStream ;

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 age Fa 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 fisier text cu


FileOutputStream f=new FileOutputStream(. . .);

163

164

CAPITOLUL 4. SERVICII JAX-WS

soapMsg.writeTo(f);
Continutul fisierului este
SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/><SOAP-ENV:Body><e1>primul<e11>al treilea</e11></e1>
<e2>al doilea</e2></SOAP-ENV:Body></SOAP-ENV:Envelope>

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

11

import
import
import
import
import
import
import
import
import
import
import

13

public c l a s s MsgSOAPReceiver {

1
2
3
4
5
6
7
8
9
10

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

j a v a x . xml . soap . M es sa geF ac tor y ;


j a v a x . xml . soap . SOAPBody ;
j a v a x . xml . soap . SOAPBodyElement ;
j a v a x . xml . soap . SOAPMessage ;
j a v a x . xml . soap . SOAPEnvelope ;
j a v a x . xml . soap . SOAPPart ;
j a v a x . xml . soap . SOAPElement ;
j a v a x . xml . soap . Name ;
java . u t i l . I t e r a t o r ;
java . io . FileInputStream ;
o r g . w3c . dom . Node ;

public s t a t i c void a n a l y z e ( SOAPElement r o o t E l e m e n t ) {


I t e r a t o r i t e r a t o r=r o o t E l e m e n t . g e t C h i l d E l e m e n t s ( ) ;
while ( i t e r a t o r . hasNext ( ) ) {
SOAPElement e l e m e n t = ( SOAPElement ) i t e r a t o r . n e x t ( ) ;
short nodeType=e l e m e n t . getNodeType ( ) ;
System . out . p r i n t l n ( nodeType ) ;
Name name=e l e m e n t . getElementName ( ) ;
System . out . p r i n t l n ( name : +name . getLocalName ( ) ) ;
System . out . p r i n t l n ( v a l u e : + e l e m e n t . g e t V a l u e ( ) ) ;
i f ( nodeType==Node . ENTITY NODE) a n a l y z e ( e l e m e n t ) ;
}
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
try {

4.1. DESCRIEREA UNUI SERVICIU

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 ( MySOAPMessage . xml ) ;


Me ss age Fa 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 ( null , f i s ) ;
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 ( ) ;
a n a l y z e ( body ) ;

30
31
32
33
34
35
36

}
catch ( E x c e p t i o n ex ) {
ex . p r i n t S t a c k T r a c e ( ) ;
}

37
38
39
40

41
42

165

Observatia 4.1.1
Produsul Oracle-Open Message Queue ofera posibilitatea transformarii unui
mesaj SOAP n mesaj JMS si invers.
Transformarea unui mesaj SOAP n mesaj JMS
SOAPMessage soapMsg=. . .
Message msg=
MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);
Transformarea unui mesaj JMS n mesaj SOAP
MessageFactory mf=. . .
Message msg=. . .
SOAPMessage soapMsg =
MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);

166

CAPITOLUL 4. SERVICII JAX-WS

4.2

Modelul JAX-WS prin Metro

JSR (Java Specification Request) 109 defineste o interfata de programare


(API) pentru realizarea serviciilor Web bazate pe RPC : Java API for XML
Web Services (JAX-WS). Un asemenea serviciu Web se poate implementa prin:
servlet:
Serviciul este implementat ca o clasa Java care ruleaza ntr-un container
Web, fiind integrat ntr-un servlet. Integrarea este complet transparenta
programatorului.
sesiune EJB (Enterprise Java Bean) fara stare (stateless session):
Serviciul ruleaza ntr-un container EJB.

4.2.1

Serviciu Web ca servlet n apache-tomcat prin ant

Cadrul de lucru pe care l vom utiliza este Metro, dezvoltat de Oracle. Un


scop al cadrului de lucru Metro este asigurarea interoperabilitatii ntre server
si client atunci cand acestea sunt realizate pe platformele soft Java si .NET,
dar faciliteaza si dezvoltarea n mediul omogen Java. Metro implementeaza
modelul JAX-WS.
Alternativ, s-ar fi putut folosi implementarea de referinta jaxws-ri, dezvoltat tot de Oracle sau apache-CXF.
Metro ofera suport pentru dezvoltarea serviciului Web pe serverele:
apache-tomcat; 3
glassfish.
Instalarea n apache-tomcat se face
prin ant cu fisierul metro-on-tomcat.xml aflat n distributia lui Metro.
fisierele jar aflate n catalogul metro\lib se copiaza n apache-tomcat*\lib sau n catalogul WEB-INF\lib al serviciului.
Dezvoltarea aplicatiei server
Clasa serverului este o clasa POJO cu adnotari specifice. Vom dezvolta
serviciul Web pentru calculul celui mai mare divizor comun a doua numere
naturale.
3

Functioneaz
a si n serverul Web jetty.

4.2. MODELUL JAX-WS PRIN METRO

167

Definirea serviciului, a operatiilor pe care le ofera serviciul si a parametrilor


de intrare pentru fiecare operatie se face utilizand adnotarile @WebService,
respectiv @WebMethod si @WebParam.
Structura clasei server va fi
1
2
3
4
6
7

package cmmdc . s e r v e r ;
import j a v a x . j w s . WebMethod ;
import j a v a x . j w s . WebParam ;
import j a v a x . j w s . WebService ;
@WebService ( )
public c l a s s CmmdcWS {
@WebMethod
public long cmmdc(@WebParam( name = m ) long m,
@WebParam( name = n ) long n ) { }

9
10
11
12

Programatorul va completa codul metodei cmmdc.


Vom considera structura
myapp
|--> src
|
|--> mypackage
|
|
|--> server
|
|
|
| *.java
|--> war
|
|--> WEB-INF
|
|
|--> classes
|
|
|--> lib
|
|
|
web.xml
|
|
|
sun-jaxws.xml

Compilarea se face prin intermediul utilitarului apt - Annotation Proccessing


Tool din jdk prin intermediul unei sarcini date de clasa com.sun.tools.ws.ant.Apt
din Metro. Codul corespunzator din build.xml este
<taskdef name="apt" classname="com.sun.tools.ws.ant.Apt">
<classpath refid="myclasspath"/>
</taskdef>
<target name="build-server" depends="init">
<apt
fork="true"
debug="true"
destdir="war/WEB-INF/classes"
sourcedestdir="war/WEB-INF/classes"
sourcepath="src">
<classpath>
<path refid="myclasspath"/>
</classpath>
<source dir="src">
<include name="**/server/*.java"/>
</source>
</apt>
</target>

168

CAPITOLUL 4. SERVICII JAX-WS

Pe baza claselor din source=src\mypackage\server se vor genera n sourcedestdir


o serie de clase iar rezultatul compilarii se depun n catalogul indicat de
destdir.
In cazul exemplului considerat aceste clase sunt cmmdc.server.jaxws. Cmmdc.java si cmmdc.server.jaxws.CmmdcResponse.java.
Sunt necesare doua fisiere de configurare
sun-jaxws.xml
1

? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>

<e n d p o i n t s xmlns= h t t p : // j a v a . sun . com/xml/ ns / jax ws/ r i / r u n t i m e


version= 2 . 0 >
<e n d p o i n t
name= jaxwscmmdc
i m p l e m e n t a t i o n= cmmdc . s e r v e r .CmmdcWS
u r l p a t t e r n= /cmmdcws />
</ e n d p o i n t s>

4
5
6
7
8
9

web.xml
1

? xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>

<webapp version= 2 . 4 xmlns= h t t p : // j a v a . sun . com/xml/ ns / j 2 e e >


< l i s t e n e r>
< l i s t e n e r c l a s s>
com . sun . xml . ws . t r a n s p o r t . h t t p . s e r v l e t . W S S e r v l e t C o n t e x t L i s t e n e r
</ l i s t e n e r c l a s s>
</ l i s t e n e r>
< s e r v l e t>
<s e r v l e t name>cmmdcws</ s e r v l e t name>
<s e r v l e t c l a s s>
com . sun . xml . ws . t r a n s p o r t . h t t p . s e r v l e t . WSServlet
</ s e r v l e t c l a s s>
<l o a d ons t a r t u p>1</ l o a d ons t a r t u p>
</ s e r v l e t>
<s e r v l e t mapping>
<s e r v l e t name>cmmdcws</ s e r v l e t name>
<u r l p a t t e r n>/cmmdcws</ u r l p a t t e r n>
</ s e r v l e t mapping>
<s e s s i o n c o n f i g>
<s e s s i o n t i m e o u t>60</ s e s s i o n t i m e o u t>
</ s e s s i o n c o n f i g>
</webapp>

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

Se retin urmatoarele corelatii ale denumirilor:


url-pattern fixat n web.xml este redeclarat n fisierele sun-jaxws.xml.
Numele serviciului declarat n sun-jaxws.xml trebuie sa fie numele arhivei
war.
Pentru exemplul nostru, wsdl -ul serviciului va fi disponibil la

4.2. MODELUL JAX-WS PRIN METRO

169

http://host:8080/jaxws-cmmdc/cmmdcws?wsdl

Dezvoltarea aplicatiei client. Realizarea aplicatiei client presupune ca


serviciul sa fie activ pe serverul Web.
Dezvoltarea partii (aplicatiei) client ncepe cu generarea unor clase care
mijlocesc apelarea serviciului. Generarea se face utilizand utilitarul wsimport
din jdk pe baza accesarii fisierului wsdl asociat serviciului.
Codul obiectivului din build.xml este
<target name="generate-client" depends="init">
<exec executable="${env.JAVA_HOME}/bin/wsimport">
<arg value="-d"/>
<arg value="${build.dir}"/>
<arg value="-keep"/>
<arg value="-p"/>
<arg value="${app.name}.client"/>
<arg value="${wsdl.uri}"/>
</exec>
</target>

Optiunea -d specifica locatia unde se depun fisierele generate, optiunea -p


indica pachetul din care fac parte clasele generate.
Dintre aceste clase, n codul clientului propriu-zis se foloseste clasa CmmdcWSService. Numele clasei s-a obtinut adaugand sufixul Service la numele
clasei server. Aceasta clasa contine metoda getCmmdcWSPort() ce returnreaza un reprezentant al serviciului pe calculatorul clientului.
Astfel referinta la serviciu se obtine prin
CmmdcWSService service=new CmmdcWSService();
CmmdcWS port=service.getCmmdcWSPort();
Prin variabila port putem apela orice operatie a serviciului.
Codul clientului sincron este
1
2
4
5
6
7
8
9
10
11
12
13
14

package cmmdc . c l i e n 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 ) {
try {
CmmdcWS p o r t=new CmmdcWSService ( ) . getCmmdcWSPort ( ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
long r e s u l t=p o r t . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc=+r e s u l t ) ;

170

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

15
16
17
18

19
20

CAPITOLUL 4. SERVICII JAX-WS

Alternativ, serviciul si clientul se pot dezvolta n mediul de dezvoltare


Netbeans. In acest caz, realizarea fisierelor de configurare nu mai este n sarcina
programatorului. De asemenea, definirea operatiilor oferite de serviciul Web
se pot introduce prin intermediul unei interfete grafice, Netbeans generand
antetul metodelor corespunzatoare.
Client Web al serviciului Web
Clientul Web este reprezentat de pagina JSP (index.jsp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

<html>
<body>
<form method= p o s t >
<table>
<tr>
<td>Primul numar e s t e </td>
<td><input type= t e x t name=m s i z e=5 value= 1 > </td>
</ tr>
<tr>
<td>Al d o i l e a numar e s t e </td>
<td><input type= t e x t name=n s i z e=5 value= 1 > </td>
</ tr>
<tr>
<td><input type= submit value= C a l c u l e a z a ></td>
<td/>
</ tr>
</ table>
</form>
<%
try {
cmmdc . c l i e n t . CmmdcWSService s e r v i c e=
new cmmdc . c l i e n t . CmmdcWSService ( ) ;
cmmdc . c l i e n t .CmmdcWS p o r t=s e r v i c e . getCmmdcWSPort ( ) ;
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 ) ;
l o n g m=((sm==n u l l ) | | ( . e q u a l s ( sm ) ) ) ? 1 : Long . p ar se Lon g ( sm ) ;
l o n g n=(( sn==n u l l ) | | ( . e q u a l s ( sn ) ) ) ? 1 : Long . par se Lon g ( sn ) ;
l o n g r e z=p o r t . cmmdc(m, n ) ;
String r e s u l t =(new Long ( r e z ) ) . t o S t r i n g ( ) ;
out . p r i n t l n ( R e s u l t = +r e s u l t ) ;
}
catch ( Exception e ) {
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 ( ) ) ;
}
%>
<hr/>
</body>
</html>

4.2. MODELUL JAX-WS PRIN METRO

171

Structura aplicatiei Web care se desfasoara n serverul Web este


client-web
|-->WEB-INF
|
|--> classes
|
|
|
*.class
|
|--> lib
|
|
web.xml
|
index.jsp

Fisierele class sunt cele generate de wsimport la dezvoltarea aplicatiei.


Fisierul web.xml este
1
2
3
4
5
6
7
8
9
10
11
12
13
14

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp version= 2 . 4 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 >
<s e s s i o n c o n f i g>
<s e s s i o n t i m e o u t>
30
</ s e s s i o n t i m e o u t>
</ s e s s i o n c o n f i g>
<welcomef i l e l i s t>
<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>

Valoarea jspclient din sun-web.xml reprezinta numele de apel al aplicatiei client


si coincide cu numele arhivei war.
Clienti asincroni
JAX-WS si prin urmare si Metro ofera posibilitatea dezvoltarii de clienti
asincroni. Caracterul asincron se refera la faptul ca programul client nu se
blocheaza n asteptarea raspunsului oferit de serviciul Web.
De aceasta data utilitarul wsimport se foloseste indirect, mai precis prin
intermediul clasei com.sun.tools.ws.ant.WsImport din Metro.
Generarea metodelor utilizate de client n acest scop se obtine incluzand
proprietatea
binding=etc/custom-client.xml
n sarcina wsimport, iar continutul fisierului custom-client.xml este
1
2
3
4
5
6
7
8
9
10

<?xml version= 1 . 0 e n c o d i n g=UTF8 standalone= y e s ?>


<b i n d i n g s
x m l n s : x s d= h t t p : //www. w3 . o r g /2001/XMLSchema
x m l n s : w s d l= h t t p : // schemas . xmlsoap . o r g / wsdl /
w s d l L o c a t i o n= h t t p : // l o c a l h o s t : 8 0 8 0 / jaxwscmmdc/cmmdcws? wsdl
xmlns= h t t p : // j a v a . sun . com/xml/ ns / jaxws >
<b i n d i n g s node= w s d l : d e f i n i t i o n s >
<enableAsyncMapping>t r u e</ enableAsyncMapping>
</ b i n d i n g s>
</ b i n d i n g s>

172

CAPITOLUL 4. SERVICII JAX-WS

Codul corespunzator din build.xml este


<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
<classpath refid="myclasspath"/>
</taskdef>
<target name="generate-client" depends="init">
<wsimport
debug="true"
verbose="${verbose}"
keep="true"
destdir="${build.dir}"
package="${app.name}.client"
binding="etc/custom-client.xml"
xendorsed="true"
wsdl="${wsdl.uri}">
<arg line="-extension"/>
</wsimport>
</target>

Pe calculatorul clientului, n clasa reprezentand serviciul (CmmdcWS pentru exemplul tratat), pentru fiecare metoda a serviciului se genereaza una
din metodele
public Response<MetodaResponse> metodaAsync( lista parametrilor
formali )
public Future<?> metodaAsync( lista parametrilor formali,
AsyncHandler<MetodaResponse> asyncHandler )
Pentru exemplul tratat metoda=cmmdc.
Cele doua metode ofera posibilitatea construirii a cate unui program client
specific, denumite, respectiv modelul polling si modelul callback.
Au intervenit interfetele
public interface Response<T> extends
java.util.concurrent.Future<T>
Un obiect de acest tip contine raspunsul serviciului. Raspunsul se obtine
cu metoda T get(), mostenita de la Future.
Metoda boolean isDone() returneaza true daca s-a primit raspuns.
public interface AsyncHandler<T>
Interfata declara metoda void handleResponse(Response<T> res) responsabila de prelucrarea raspunsului.
Exemplul 4.2.1 Client construit pe modelul polling.

4.2. MODELUL JAX-WS PRIN METRO

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

package cmmdc . c l i e n t ;
import j a v a x . xml . ws . Response ;
import j a v a . u t i l . S c a n n e r ;
public c l a s s CmmdcAsyncClient {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
long d e l t a =500;
try {
CmmdcWS p o r t=new CmmdcWSService ( ) . getCmmdcWSPort ( ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
Response<CmmdcResponse> r e s p o n s e=p o r t . cmmdcAsync (m, n ) ;
while ( ! r e s p o n s e . i s D o n e ( ) ) {
System . out . p r i n t l n ( Wait +d e l t a+ ms ) ;
Thread . s l e e p ( d e l t a ) ;
}
CmmdcResponse out pu t=r e s p o n s e . g e t ( ) ;
long r e s u l t=o ut pu t . g e t R e t u r n ( ) ;
System . out . p r i n t l n ( Cmmdc=+r e s u l t ) ;

16
17
18
19
20
21
22
23

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

24
25
26
27

28
29

Exemplul 4.2.2 Client construit pe modelul callback.


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

package cmmdc . c l i e n t ;
import j a v a . u t i l . c o n c u r r e n t . E x e c u t i o n E x c e p t i o n ;
import j a v a . u t i l . c o n c u r r e n t . Future ;
import j a v a x . xml . ws . Response ;
import j a v a x . xml . ws . AsyncHandler ;
import j a v a . u t i l . S c a n n e r ;
public c l a s s CmmdcAsyncClient {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
long d e l t a =500;
try {
CmmdcWS p o r t=new CmmdcWSService ( ) . getCmmdcWSPort ( ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
CmmdcAsyncHandler a s y n c H a n d l e r=new CmmdcAsyncHandler ( ) ;
Future <?> r e s p o n s e=p o r t . cmmdcAsync (m, n , a s y n c H a n d l e r ) ;
while ( ! r e s p o n s e . i s D o n e ( ) ) {
System . out . p r i n t l n ( Wait +d e l t a+ ms ) ;
Thread . s l e e p ( d e l t a ) ;
}

173

174

CAPITOLUL 4. SERVICII JAX-WS

CmmdcResponse out pu t=a s y n c H a n d l e r . g e t R e s p o n s e ( ) ;


long r e s u l t=o ut pu t . g e t R e t u r n ( ) ;
System . out . p r i n t l n ( Cmmdc=+r e s u l t ) ;

25
26
27

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

28
29
30
31

32
33

35

c l a s s CmmdcAsyncHandler implements AsyncHandler<CmmdcResponse>{


private CmmdcResponse out p ut ;

36

public void h a n d l e R e s p o n s e ( Response<CmmdcResponse> r e s p o n s e ) {


try {
ou tp ut=r e s p o n s e . g e t ( ) ;
}
catch ( E x e c u t i o n E x c e p t i o n e ) {
System . out . p r i n t l n ( E x e c u t i o n E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
e . printStackTrace ( ) ;
}
catch ( I n t e r r u p t e d E x c e p t i o n e ) {
System . out . p r i n t l n ( I n t e r r u p t e d E x c e p t i o n : +e . g e t M e s s a g e ( ) ) ;
e . printStackTrace ( ) ;
}
}

38
39
40
41
42
43
44
45
46
47
48
49
50

CmmdcResponse g e t R e s p o n s e ( ) {
return ou tp ut ;
}

52
53
54
55

4.2.2

Component
a EJB sesiune stateless ca serviciu Web

Sablonul pentru crearea unei componente EJB de tip stateless session ca


serviciu Web de tip JAX-WS este
import
import
import
import

javax.ejb.Stateless;
javax.jws.WebService;
javax.jws.WebMethod;
javax.jws.WebParam;

@WebService
@Stateless
public class Componenta{
@WebMethod
public tip metoda(@WebParam(name="numeVarFormala")tip numeVarFormala,. . .){. . .}
. . .
}

Exemplul 4.2.3 Cel mai mare divizor comun a doua numere naturale
Componentei EJB are codul

4.2. MODELUL JAX-WS PRIN METRO

1
2
3
4
5
7
8
9

package cmmdcws ;
import j a v a x . j w s . WebService ;
import j a v a x . j w s . WebMethod ;
import j a v a x . j w s . WebParam ;
import j a v a x . e j b . S t a t e l e s s ;
@WebService
@Stateless
public c l a s s CmmdcEJB {
@WebMethod
public long cmmdc(@WebParam( name = m ) long m,
@WebParam( name = n ) long n ) { . . . }

11
12
13
14

175

Clasa compilata obisnuit se arhiveaza cu extensia jar si se desfasoara n


serverul de aplicatie (glassfish). Diferenta fata de varianta de serviciu ca servlet
consta n structura arhivei care se desfasoara n serverul Web.
cmmdc-ejb
|--> cmmdcws
|
|
CmmdcEJB.class

Clientul este unul obisnuit pentru serviciul Web de tip JAX-WS. In cazul
de fata codul clientului este
1
2
3
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package c l i e n t ;
import cmmdcws . ;
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 ) {
try {
CmmdcEJB p o r t=new CmmdcEJBService ( ) . getCmmdcEJBPort ( ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
long r e s u l t=p o r t . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc=+r e s u l t ) ;
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t f ( AnException : +e . g e t M e s s a g e ( ) ) ;
}
}
}

Reamintim ca dezvoltarea clientului se face cu serviciul Web activ, fiind necesara generarea unor clase - reprezentante ale serviciului - pe calculatorul clientului. La generarea claselor de catre wsimport, referinta URL a serviciului
Web trebuie sa corespunda serverului Web care contine serviciul n timpul
utilizarii.

176

CAPITOLUL 4. SERVICII JAX-WS

4.2.3

Servicii jaxws dezvoltate prin maven

Dezvoltarea aplicatiei server


Serviciul jaxws se va desfasura n serverul Web glassfish.
Vom dezvolta serviciul pentru calculul celui mai mare divizor comun cu
contextul jaxws-cmmdc
numele de apel cmmdcws
Acesti parametrii sunt specificati n fisierul sun-jaxws.xml.
Dezvoltarea aplicatiei consta din:
1. Generarea aplicatiei
set GroupID=cmmdc.server
set ArtifactID=jaxws-cmmdc
set Version=1.0
mvn archetype:generate -B
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-DarchetypeArtifactId=maven-archetype-webapp
-Dversion=%Version%

2. Se adapteaza structura de cataloage si fisiere la


jaxws-cmmdc
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|
|
|
|
|
|
|-->
|
|
|-->
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|--> cmmdc
|
|--> server
|
|
|
CmmdcWS.java
resources
webapp
|--> WEB-INF
|
|
web.xml
|
|
sun-jaxws.xml

3. Fisierul pom.xml se completeaza cu


<dependencies>
. . .
<dependency>
<groupId>org.glassfish.metro</groupId>
<artifactId>webservices-rt</artifactId>
<version>2.3.1</version>
</dependency>
. . .
</dependencies>
<repositories>

4.2. MODELUL JAX-WS PRIN METRO

<repository>
<id>maven2-repository.java.net</id>
<name>Java.net Repository for Maven 2</name>
<url>http://download.java.net/maven/2/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>maven2-repository.java.net</id>
<name>Java.net Repository for Maven 2</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>

4. Prelucrarea consta din


(a) mvn clean package
(b) Fisierul war care rezulta se desfasoara n glassfish.
Dezvoltarea aplicatiei client
Dezvoltarea aplicatiei consta din:
1. Generarea aplicatiei
set GroupID=cmmdc.client
set ArtifactID=jaxws-cmmdc-client
set Version=1.0
mvn archetype:generate -B
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-DarchetypeArtifactId=maven-archetype-quickstart
-Dversion=%Version%
end{verbatim}
\normalsize
\item
Se adapteaz\u{a} structura de cataloage \c{s}i fi\c{s}iere la
\scriptsize
\begin{verbatim}
jaxws-cmmdc-client
|--> src
|
|--> main
|
|
|--> java
|
|
|
|--> cmmdc
|
|
|
|
|--> client
|
|
|
|
|
|
CmmdcClient.java
|
pom.xml

In clasa CmmdcClient.java se introduce


import cmmdc.server.*;

177

178

CAPITOLUL 4. SERVICII JAX-WS

2. Fisierul pom.xml se completeaza cu


<dependencies>
. . .
<dependency>
<groupId>org.glassfish.metro</groupId>
<artifactId>webservices-rt</artifactId>
<version>2.3</version>
</dependency>
. . .
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<!-- Needed with JAXP 1.5 -->
<vmArgs>
<vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
</vmArgs>
</configuration>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlUrls>
<wsdlUrl>
http://localhost:8080/jaxws-cmmdc/cmmdcws?wsdl
</wsdlUrl>
</wsdlUrls>
<packageName>cmmdc.client</packageName>
</configuration>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
</plugins>

3. Prelucrarea consta din


(a) mvn clean compile
(b) mvn exec:java -Dexec.mainClass="cmmdc.client.CmmdcClient"

Capitolul 5
Servicii JAX-RS
5.1

Representational State Transfer

REpresentational State Transfer (REST) este un model de arhitectura de


aplicatie distribuita REST specifica modul cum o resursa - entitate care contine
informatie specifica - este definita si cum poate fi adresata.
Identificarea unei resurse se face printr-un URI (Universal Resource Identifier ).
Transferul resursei catre un client sau prelucrarea resursei se face utilizand o interfata care contine o multime de operatii http: GET, POST, PUT,
DELETE.
Resursele sunt fara stare iar modelul de aplicatie este cel de client-server.
Pentru sistemelele care satisfac aceste restrictii se utilizeaza terminologia
RESTful.
Principalul exemplu de sistem RESTful este World Wide Web (WWW) cu
protocolul Hyper Text Transfer Protocol (HTTP).
Serviciile Web bazate pe REST se bazeaza pe accesul la resurse - definite prin identificatori si nu pe apelarea unor metode, ca n modelul Remote
Procedure Call (RPC).
Standardul JAX-RS Java API for RESTful Web Services a ajuns la versiunea 2. (Versiunea 1 este definita de JSR 311, iar versiunea 2 este definita de
JSR 339)
In prezent, n Java, exista mai multe implementari pentru servicii REST.
Entitatile utilizate sunt:
Clasa resursa - Resource class. Resursa Web este reprezinta de o clasa
Java cu adnotari JAX-RS. Clasa resursa radacina - Root resource class.
179

180

CAPITOLUL 5. SERVICII JAX-RS

Clasa cu adnotarea @Path. Resursele adiacente se definesc relativ la


aceasta clasa (resursa).
Metoda de identificare a cererii - Request method designator. Adnotarea @GET / @POST /@PUT / @DELETE este folosita pentru identificarea
cererii HTTP n vederea desemnarii metodei de generare / prelucrare a
resursei.
Metoda de generare / prelucrare a resusei - Resource method.
Localizator a resurselor adiacente - Sub-resource locator. Metoda pentru localizarea a resurselor adiacente, adica a resurselor care se specifica
relativ la resursa radacina.
Metoda de generare / prelucrare a unei resurse adiacente - Sub-resource
method.
Provider o implementare a interfetei JAX-RS.
O implementare de referinta (Reference Implementation - RI) este oferita
de pachetul jersey-*.*.* realizat de Oracle.

5.2
5.2.1

Jersey-2
Generarea resurselor

Instalarea. Se va descarca o arhiva care contine resursele necesare sub


forma de fisiere jar.
Serverul Web care se va utiliza va fi apache-tomcat. In vederea desfasurarii,
serviciul se arhiveaza cu extensia war. Numele arhivei va desemna numele
serviciului. Structura care se arhiveaza va fi
catalogul_serviciului_RESTful
|--> WEB-INF
|
|--> classes
|
|
|--> resources
|
|
|
|
*.class
|
|--> lib
|
|
|
*.jar
|
|
web.xml
|
index.html sau index.jsp

5.2. JERSEY-2

181

Printre fisierele *.class se gasesc resursele serviciului. index.html sau index.jsp


ofera posibilitatea apelarii serviciului si de obicei reprezinta un client Web.
Alternativ un serviciu JAX-RS se poate apela dintr-un program client.
Fisierul web.xml este
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp version= 2 . 5 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
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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd >
< s e r v l e t>
<s e r v l e t name>J e r s e y Web A p p l i c a t i o n</ s e r v l e t name>
<s e r v l e t c l a s s>
org . g l a s s f i s h . j e r s e y . s e r v l e t . ServletContainer
</ s e r v l e t c l a s s>
<i n i t param>
<paramname>
j e r s e y . c o n f i g . s e r v e r . provider . packages
</paramname>
<paramv a l u e>r e s o u r c e s</paramv a l u e>
</ i n i t param>
<l o a d ons t a r t u p>1</ l o a d ons t a r t u p>
</ s e r v l e t>
<s e r v l e t mapping>
<s e r v l e t name>J e r s e y Web A p p l i c a t i o n</ s e r v l e t name>
<u r l p a t t e r n>/ r e s o u r c e s /</ u r l p a t t e r n>
</ s e r v l e t mapping>
</webapp>

Resursele jar necesare sunt sunt cuprinse n distributia jersey.


Exemplul 5.2.1 Serviciul RESTful Hello World care consta n furnizarea textului Hello World.
Codul sursa al resursei este:
1

package r e s o u r c e s ;

import j a v a x . ws . r s . Produces ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;

4
5
7
8

@Path ( h e l l o w o r l d )
public c l a s s H e l l o W o r l d R e s o u r c e {

10

public H e l l o W o r l d R e s o u r c e ( ) {}

12

@GET
@Produces ( t e x t / p l a i n )
public S t r i n g g e t T e x t ( ) {
return ( H e l l o World ) ;
}

13
14
15
16
18
19
20
21

@Path ( html )
@GET
@Produces ( t e x t / html )
public S t r i n g getAsHtml ( ) {

182

CAPITOLUL 5. SERVICII JAX-RS

return <html><head></head><body b g c o l o r=\#bbeebb\>< c e n t e r >


<p>H e l l o World</p></c e n t e r ></body></html> ;

22
23
24

26

@Path ( xml )
@GET
@Produces ( a p p l i c a t i o n /xml )
public S t r i n g getAsXml ( ) {
return <r e s p o n s e >H e l l o World</r e s p o n s e > ;
}

27
28
29
30
31
32

Adnotarea @Path("helloworld") face ca localizarea resursei sa fie


http://host:port/NumeServiciuRESTful /resources/helloworld
Metoda getText() este o metoda de generare a resursei si are adnotarile
@GET - raspunde la o cerere GET;
@Produces(String mime-type) - rezultatul produs are tipul MIME (Multipurpose Internet Mail Exchange) text/plain.
Suplimentar sunt definite doua resurse adiacente. In urma adnotarii @Path("html"),
localizarea resursei este
http://host:port/NumeServiciuRESTful /resources/helloworld/html
La o solicitare GET, resursa (clasa) furnizeaza clientului o pagina html.
Analog se trateaza resursa adiacenta cu adnotarea @Path ("xml").
Desfasurand serviciul ntr-un server Web (cu numele de apel HelloWorld )
si apeland http:// localhost:8080/HelloWorld/resources/ application.wadl se
obtine descrierea WADL a serviciului:
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=UTF8 standalone= y e s ?>


<a p p l i c a t i o n xmlns= h t t p : // wadl . dev . j a v a . n e t /2009/02 >
<doc x m l n s : j e r s e y= h t t p : // j e r s e y . j a v a . n e t /
j e r s e y : g e n e r a t e d B y= J e r s e y : 2 . 9 20140522 05 : 1 2 : 1 0 />
<doc x m l n s : j e r s e y= h t t p : // j e r s e y . j a v a . n e t /
j e r s e y : h i n t= This i s s i m p l i f i e d WADL with u s e r
and c o r e r e s o u r c e s o n l y . To g e t f u l l WADL with
e x t e n d e d r e s o u r c e s u s e t h e query p a r a m e t e r d e t a i l . L i n k :
h t t p : // l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / a p p l i c a t i o n . wadl ? d e t a i l=t r u e />
<grammars />
<r e s o u r c e s b a s e= h t t p : // l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / >
<r e s o u r c e path= h e l l o w o r l d >
<method i d= g e t T e x t name=GET>
<r e s p o n s e>
<r e p r e s e n t a t i o n mediaType= t e x t / p l a i n />
</ r e s p o n s e>
</ method>
<r e s o u r c e path= html >
<method i d= getAsHtml name=GET>

5.2. JERSEY-2

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

183

<r e s p o n s e>
<r e p r e s e n t a t i o n mediaType= t e x t / html />
</ r e s p o n s e>
</ method>
</ r e s o u r c e>
<r e s o u r c e path=xml>
<method i d= getAsXml name=GET>
<r e s p o n s e>
<r e p r e s e n t a t i o n mediaType= a p p l i c a t i o n /xml />
</ r e s p o n s e>
</ method>
</ r e s o u r c e>
</ r e s o u r c e>
</ r e s o u r c e s>
</ a p p l i c a t i o n>

Apelarea serviciului prin internediul unui navigator se poate face prin intermediul fisierului index.html - client Web
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>
<body>
<table border= 2 >
<tr>
<td>
<a href= / HelloWorld / r e s o u r c e s / h e l l o w o r l d >
R e z u l t a t t e x t / p l a i n </a>
</td>
</ tr>
<tr>
<td>
<a href= / HelloWorld / r e s o u r c e s / h e l l o w o r l d / html >
R e z u l t a t t e x t / html </a>
</td>
</ tr>
<tr>
<td>
<a href= / HelloWorld / r e s o u r c e s / h e l l o w o r l d /xml>
R e z u l t a t a p p l i c a t i o n /xml</a>
</td>
</ tr>
</ table>
</body>
</html>

In acest caz, apelarea este http://host:port/HelloWorld.

Aplicatii client n Java


Elaborarea unui program client pentru un serviciu RESTful realizat prin
jersey se poate baza pe
1. Clasa java.net.HttpURLConnection sau java.net.ssl.HttpsURLConnection
din distributia jdk.
Conexiunea cu resursa furnizata de serviciul RESTful se obtine prin

184

CAPITOLUL 5. SERVICII JAX-RS

URL url=new URL(String url_resursa);


HttpURLConnection conn=(HttpURLConnection) url.openConnection();

Prin metodele clasei HttpURLConnection se determina


Codul rentors de serviciul RESTful - public int getResponseCode().
Succesul apelului este dat de codul 200.
Mesajul explicativ al codului - public String getResponseMessage().
Fluxul care furnizeaza resursa - public InputStream getInputStream()
throws IOException.
In final trebuie deconectata conexiunea prin void disconnect().
Un client al serviciului RESTfull anterior este clasa
1
2
3
4
5
7
8
9
10
11
12
13
14
15
16
17
18
19
21
22
23
24
25
26
27
28
29
30
31
33
34
35
36
37
38
39

import
import
import
import
import

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

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 [ ] ) {
System . out . p r i n t l n ( R e z u l t a t / \ t e x t / p l a i n \ ) ;
S t r i n g u r l S t r=
h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d ;
try {
S t r i n g r e z u l t a t=httpGetText ( u r l S t r ) ;
System . out . p r i n t l n ( r e z u l t a t ) ;
}
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 message : +e . g e t M e s s a g e ( ) ) ;
}
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( R e z u l t a t / \ t e x t / html \ ) ;
urlStr =
h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d / html ;
try {
S t r i n g r e z u l t a t=httpGetText ( u r l S t r ) ;
System . out . p r i n t l n ( r e z u l t a t ) ;
}
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 message : +e . g e t M e s s a g e ( ) ) ;
}
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( R e z u l t a t / \ a p p l i c a t i o n /xml \ ) ;
urlStr =
h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d /xml ;
try {
S t r i n g r e z u l t a t=httpGetText ( u r l S t r ) ;
System . out . p r i n t l n ( r e z u l t a t ) ;
}

185

5.2. JERSEY-2

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 message : +e . g e t M e s s a g e ( ) ) ;
}

40
41
42
43

45

public s t a t i c S t r i n g httpGetText ( S t r i n g u r l S t r )
throws IOException {
URL u r l=new URL( u r l S t r ) ;
HttpURLConnection conn=(HttpURLConnection ) u r l . op enConn ection ( ) ;

46
47
48

i f ( conn . getResponseCode ( ) != 2 0 0 ) {
throw new IOException ( conn . g e t R e s p o n s e M e s s a g e ( ) ) ;
}

50
51
52

// B u f f e r t h e r e s u l t i n t o a s t r i n g
B u f f e r e d R e a d e r rd = 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 ( ) ) ) ;
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 ( ) ;
String line ;
while ( ( l i n e = rd . r e a d L i n e ( ) ) != n u l l ) {
sb . append ( l i n e+ \n ) ;
}
rd . c l o s e ( ) ;

54
55
56
57
58
59
60
61
62

conn . d i s c o n n e c t ( ) ;
return sb . t o S t r i n g ( ) ;

64
65

66
67

2. Resursele interfetei de programare (API) Jersey Client, continute n pachetul com.sun.jersey.api.client. Aceasta varianta asigura o prelucrere mai simpla si unitara a rezultatelor furnizate de un serviciu RESTful.
Sablonul de prelucrare consta din:
(a) Crearea unei instante a clasei javax.ws.rs.client.Client
Client client = ClientBuilder.newClient();

(b) Fixarea adresei serviciului RESTful n interfata javax.ws.rs.client.


WebTarget.
WebTarget webTarget=client.target(String url_resursa);

(c) Utilizarea metodelor clasei WebTarget:


WebTarget path(String path)
Adresa obtinuta prin juxtapunere cu \path.
Invocation.Builder request()
Invocation.Builder request(String... acceptedResponseTypes)

186

CAPITOLUL 5. SERVICII JAX-RS

Invocation.Builder request(MediaType... acceptedResponseTypes)


Construieste obiectul care executa apelarea resursei.
URI getUri()
Furnizeaza adresa resursei.
WebTarget queryParam(String name, Object... values)
Adauga parametrii cererii.
(d) Apelarea resurselor prin metodele interfetei javax.ws.rs.client.
Invocation.Builder:

<T> T get(Class<T> responseType)


<T> T post(Class<T> responseType)
<T> T post(Entity<?> entity, Class<T> responseType)
AsyncInvoker async()

javax.ws.rs.client.SyncInvoker este suprainterfata pentru


Invocation.Builder.
(e) Alternativ, interfata javax.ws.rs.client.AsyncInvoker ofera metoda
Future<Response> get()
<T> Future<T> get(InvocationCallback<T> callback )
Interfata javax.ws.rs.client.InvocationCallback<RESPONSE> declara
metodele
void completed(RESPONSE response)
Destinat prelucrarii raspunsului.
void failed(Throwable throwable)
Este apelat n cazul unei erori.
Cu aceasta tehnologie, codul sursa al clasei client n varianta sincrona
este
1
2
3
4
5
7
8
9
10
11
12

package hw ;
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .

rs
rs
rs
rs

.
.
.
.

client
client
client
client

. Client ;
. ClientBuilder ;
. WebTarget ;
. Invocation ;

public c l a s s J e r s e y 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 [ ] ) {
C l i e n t c l i e n t = C l i e n t B u i l d e r . newClient ( ) ;
S t r i n g rootURL =
h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d ;
S t r i n g r e s p o n s e= ;

187

5.2. JERSEY-2

WebTarget webTarget=n u l l ;
I n v o c a t i o n . B u i l d e r i n v o c a t i o n B u i l d e r=n u l l ;

13
14

webTarget=c l i e n t . t a r g e t ( rootURL ) ;
i n v o c a t i o n B u i l d e r=webTarget . r e q u e s t ( ) ;
r e s p o n s e=i n v o c a t i o n B u i l d e r . g e t ( S t r i n g . c l a s s ) ;
System . out . p r i n t l n ( PLAIN TEXT ) ;
System . out . p r i n t l n ( r e s p o n s e+ \n ) ;

16
17
18
19
20

i n v o c a t i o n B u i l d e r=webTarget
. path ( html )
. request ( ) ;
r e s p o n s e=i n v o c a t i o n B u i l d e r . g e t ( S t r i n g . c l a s s ) ;
System . out . p r i n t l n ( HTML ) ;
System . out . p r i n t l n ( r e s p o n s e+ \n ) ;

22
23
24
25
26
27

i n v o c a t i o n B u i l d e r=webTarget
. path ( xml )
. request ( ) ;
r e s p o n s e=i n v o c a t i o n B u i l d e r . g e t ( S t r i n g . c l a s s ) ;
System . out . p r i n t l n ( XML ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;

29
30
31
32
33
34

35
36

Varianta asincrona de client este


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

package hw ;
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a . u t i l
import j a v a . u t i l

rs . c l i en t . Client ;
rs . client . ClientBuilder ;
rs . c l i e n t . InvocationCallback ;
. c o n c u r r e n t . CountDownLatch ;
. c o n c u r r e n t . TimeUnit ;

public c l a s s J e r s e y A s y n c 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 [ ] ) {
System . out . p r i n t l n ( Asyncronous E x e c u t i o n \n ) ;
S t r i n g rootURL =
h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d ;
S t r i n g [ ] u r l s ={rootURL , rootURL+ / html , rootURL+ /xml } ;
CountDownLatch c d l=new CountDownLatch ( u r l s . l e n g t h ) ;
C l i e n t c l i e n t=C l i e n t B u i l d e r . n e w C l i e n t ( ) ;
for ( S t r i n g u r l : u r l s ){
client . target ( url )
. request ()
. async ( )
. g e t (new I n v o c a t i o n C a l l b a c k <S t r i n g >(){
@Override
public void c o m p l e t e d ( S t r i n g msg ) {
System . out . p r i n t l n ( R e c e i v e d : + \n+msg ) ;
c d l . countDown ( ) ;
}
@Override
public void f a i l e d ( Throwable t h r o w a b l e ) {
System . out . p r i n t l n ( t h r o w a b l e . g e t M e s s a g e ( ) ) ;
c d l . countDown ( ) ;
}
});
}

188

CAPITOLUL 5. SERVICII JAX-RS

try {
cdl . await ( ) ;
client . close ();
}
catch ( f i n a l I n t e r r u p t e d E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

33
34
35
36
37
38
39

40
41

Daca catalogul resurselor (resources n cazul exemplului anterior) se doreste


ascuns, atunci se poate nlocui cu o referinta virtuala, de exemplu webresources.
In acest caz codul de apelare va fi
http://localhost:8080/HelloWorld/webresources/helloworld.
Aceast efect se obtine introducand clasa
1
2
3
4
6
7

package r e s o u r c e s ;
import j a v a . u t i l . S e t ;
import j a v a x . ws . r s . A p p l i c a t i o n P a t h ;
import j a v a x . ws . r s . c o r e . A p p l i c a t i o n ;
@ApplicationPath ( webresources )
public c l a s s MyApplication extends A p p l i c a t i o n {
@Override
public Set<C l a s s <?>> g e t C l a s s e s ( ) {
Set<C l a s s <?>> r e s o u r c e s = new j a v a . u t i l . HashSet < >();
r e s o u r c e s . add ( H e l l o W o r l d R e s o u r c e . c l a s s ) ;
return r e s o u r c e s ;
}

9
10
11
12
13
14
15

care leaga referinta virtuala webresources de clasa care genereaza resursa radacina,
HelloWorldResource . Clasa javax.ws.rs.core.Application contine metodele
public Set<Class<?>> getClasses()
public Set<Class<?>> getSingletons()
Prezenta arhivei jersey-container-servlet-*.jar permite eliminarea fisierului
web.xml.
Fiecare tip de resursa a fost generat ca o subresursa cu o cale specifica.
Aceasta abordare a facut posibila realizarea unui client Web si a unui client
bazat pe clasa java.net.URL. Un client jersey poate prelua o resursa pe baza
tipului MIME (Multipurpose Internet Mail Extensions). Modificam codul clasei HelloWorldResource n
1

package r e s o u r c e s ;

import j a v a x . ws . r s . Produces ;
import j a v a x . ws . r s . Path ;

189

5.2. JERSEY-2

5
6
8
9

import j a v a x . ws . r s .GET;
import j a v a x . ws . r s . c o r e . MediaType ;
@Path ( h e l l o w o r l d )
public c l a s s H e l l o W o r l d R e s o u r c e {

11

public H e l l o W o r l d R e s o u r c e ( ) {}

13

@GET
@Produces ( MediaType . TEXT PLAIN)
public S t r i n g g e t T e x t ( ) {
return ( H e l l o World ) ;
}

14
15
16
17

@GET
@Produces ( MediaType .TEXT HTML)
public S t r i n g getAsHtml ( ) {
return <html><head></head><body b g c o l o r=\#bbeebb\>< c e n t e r >
<p>H e l l o World</p></c e n t e r ></body></html> ;
}

19
20
21
22
23
24

@GET
@Produces ( MediaType .TEXT XML)
public S t r i n g getAsXml ( ) {
return <r e s p o n s e >H e l l o World</r e s p o n s e > ;
}

26
27
28
29
30

@GET
@Produces ( MediaType . APPLICATION XML)
public S t r i n g getAsAppXml ( ) {
return <r e s p o n s e >H e l l o World</r e s p o n s e > ;
}

32
33
34
35
36

@GET
@Produces ( MediaType . APPLICATION JSON)
public S t r i n g g e t A s J s o n ( ) {
return [ \ H e l l o World \ ] ;
}

38
39
40
41
42
43

iar codul clasei client JerseyClient n


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

package hw ;
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .

rs
rs
rs
rs
rs

.
.
.
.
.

c l i en t . Client ;
client . ClientBuilder ;
c l i e n t . WebTarget ;
c l i e n t . Invocation ;
c o r e . MediaType ;

public c l a s s J e r s e y 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 serviceURL= h t t p : / / l o c a l h o s t : 8 0 8 0 / HelloWorld / r e s o u r c e s / h e l l o w o r l d ;
C l i e n t c l i e n t = C l i e n t B u i l d e r . newClient ( ) ;
WebTarget webTarget=c l i e n t . t a r g e t ( serviceURL ) ;
String response ;
System . out . p r i n t l n ( MediaType . TEXT PLAIN TYPE ) ;
r e s p o n s e=webTarget . r e q u e s t ( MediaType . TEXT PLAIN TYPE)
. get ( String . class ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;

190

System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( MediaType .TEXT HTML TYPE ) ;
r e s p o n s e=webTarget . r e q u e s t ( MediaType .TEXT HTML TYPE)
. get ( String . class ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( MediaType . TEXT XML TYPE ) ;
r e s p o n s e=webTarget . r e q u e s t ( MediaType . TEXT XML TYPE)
. get ( String . class ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( MediaType . APPLICATION XML TYPE ) ;
r e s p o n s e=webTarget . r e q u e s t ( MediaType . APPLICATION XML TYPE)
. get ( String . class ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( MediaType . APPLICATION JSON TYPE ) ;
r e s p o n s e=webTarget . r e q u e s t ( MediaType . APPLICATION JSON TYPE)
. get ( String . class ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
System . out . p r i n t l n ( ) ;

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

39
40

CAPITOLUL 5. SERVICII JAX-RS

In exemplul anterior, codul html a fost generat de o metoda. Daca se ofera


un fisier html existent, atunci acesta se furnizeaza prin
import javax.servlet.ServletContext;
. . .
@Context ServletContext sc;
//@Path("html")
@ProduceMime("text/html")
@GET
public InputStream doGet() {
return sc.getResourceAsStream("/Index.html");
}

Caracterul / din argumentul metodei getResourceAsStream precizeaza radacina


aplicatiei, mai precis catalogul aplicatiei din webapps.
Printr-o adnotare @Context se pot defini variabile de tip UriInfo, Request,
HttpHeaders, ServletContext, etc.
Exemplu de furnizare a unei imagini jpg, png, aflat n catalogul resources
este data de metoda
1
2
3
4
5
6
7
9
10

package r e s o u r c e s ;
import j a v a . n e t .URL;
import j a v a x . ws . r s . Produces ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;
import j a v a x . a c t i v a t i o n . DataSource ;
import j a v a x . a c t i v a t i o n . F i l e D a t a S o u r c e ;
@Path ( i m a g i n e )
public c l a s s ImageResource {

5.2. JERSEY-2

12

public ImageResource ( ) {}

14

@GET
@Produces ( image / j p g )
public DataSource getImageRep ( ) {
URL jpgURL = t h i s . g e t C l a s s ( ) . g e t R e s o u r c e ( f o r e s t . j p g ) ;
return new F i l e D a t a S o u r c e ( jpgURL . g e t F i l e ( ) ) ;
}

15
16
17
18
19
20

191

Pe partea de client, imaginea se obtine cu metoda


import java.awt.Image;
import java.awt.Toolkit;
. . .
public static Image httpGetImage(String urlStr) throws IOException {
URL url=new URL(urlStr);
return Toolkit.getDefaultToolkit().getImage(url);
}

unde urlStr localizeaza resursa.

5.2.2

Preluarea parametrilor

Exista mai multe metode de programare a preluarii argumentelor provenind


din formulare html sau din programe client si generarea resursei raspuns:
Prin context;
Prin adnotarea @QueryParam @FormParam.
Parametrii necesari pentru generarea unei resurse pot fi transmisi sub forma
unei liste plasat n urma adresei URL a serviciului RESTful. Argumentele sunt
separate prin virgula iar separatorul dintre URL si lista argumentelor este /.
In serviciul RESTful va apare adnotarea @PathParam.
Preluarea parametrilor prin context
Preluarea unui parametru implica utilizarea mai multor clase ale interfetei
JAX-RS.
Interfata javax.ws.rs.core.UriInfo
Metode
MultivaluedMap<java.lang.String,java.lang.String>
getQueryParameters()
Returneaza lista parametrilor corespunzatori cererii.

192

CAPITOLUL 5. SERVICII JAX-RS

Interfata javax.ws.rs.core.MultivaluedMap<K,V>
extends java.util.Map<K,java.util.List<V>>
Metode
V getFirst(K key)
Returneaza valoarea corespunzatoare cheii key.
Clasa javax.ws.rs.core.Response
Metode
public static Response.ResponseBuilder ok(Object entity, String
mimetype)
Creaza un obiect care contine reprezentarea raspunsului.
Clasa javax.ws.rs.core.Response.ResponseBuilder
Metode
public abstract Response build()
Creaza obiectul Response n urma executarii metodei ok.
Pentru acelasi exemplu codul serviciului este:
1
2
3
4
5
6
7
8
10
11

package r e s o u r c e s ;
import j a v a x . ws . r s . c o r e . MultivaluedMap ;
import j a v a x . ws . r s . c o r e . Response ;
import j a v a x . ws . r s . c o r e . Context ;
import j a v a x . ws . r s . c o r e . U r i I n f o ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;
import j a v a . n e t . URLDecoder ;
@Path ( h e l l o )
public c l a s s H e l l o R e s o u r c e {

13

public H e l l o R e s o u r c e ( ) {}

15

@Context U r i I n f o u r i I n f o ;
@GET
public Response doGet ( ) {
MultivaluedMap<S t r i n g , S t r i n g > params=u r i I n f o . g e t Q u e r y P a r a m e t e r s ( ) ;
S t r i n g nume=params . g e t F i r s t ( nume ) ;
S t r i n g t i p=n u l l ;
try {
t i p=URLDecoder . d ec od e ( params . g e t F i r s t ( t i p ) , UTF8 ) ;
}
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 ( Param : +nume+ +t i p ) ;
Response r=n u l l ;

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

5.2. JERSEY-2

switch ( t i p ) {
case t e x t / p l a i n :
r=Response . ok ( g e t P l a i n R e p ( nume ) , t e x t / p l a i n ) . b u i l d ( ) ;
break ;
case t e x t / html :
r=Response . ok ( getHtmlRep ( nume ) , t e x t / html ) . b u i l d ( ) ;
break ;
}
return r ;

29
30
31
32
33
34
35
36
37
38

40

public S t r i n g g e t P l a i n R e p ( S t r i n g nume ) {
return H e l l o +nume+ ! ;
}

41
42

public S t r i n g getHtmlRep ( S t r i n g nume ) {


return <html><head></head><body b g c o l o r=\#a a e e a a\>< c e n t e r >
<h1>H e l l o +nume+ ! </h1></c e n t e r ></body></html> ;
}

44
45
46
47
48

193

Preluarea argumentelor prin adnotarea @QueryParam | @FormParam


Utilizarea adnotarilor @QueryParam, @FormParam permite preluarea parametrilor unui formular transmisi prin metoda GET, respectiv POST. In acest
caz serverul Web injecteaza parametrii metodelor n care este prezenta adnotarea.
Exemplul 5.2.2 Serviciu RESTful care furnizeaza mesajul Hello nume,
unde nume este un parametru al clientului. Un al doilea parametru tip
fixeaza natura raspunsului text/plain sau text/html.
Codul serviciului cu metoda GET este:
1
2
3
4
5
6
8
9

package r e s o u r c e s ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;
import j a v a x . ws . r s . QueryParam ;
import j a v a x . ws . r s . c o r e . Response ;
import j a v a . n e t . URLDecoder ;
@Path ( h e l l o )
public c l a s s H e l l o R e s o u r c e {

11

public H e l l o R e s o u r c e ( ) {}

13

@GET
public Response p r o c e s s Q u e r y (
@QueryParam ( nume ) S t r i n g nume ,
@QueryParam ( t i p ) S t r i n g t i p ) {
S t r i n g t i p 0=n u l l ;
try {
t i p 0=URLDecoder . de co de ( t i p , UTF8 ) ;

14
15
16
17
18
19

194

CAPITOLUL 5. SERVICII JAX-RS

}
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 ( ) ) ;
}
Response r=n u l l ;
switch ( t i p 0 ) {
case t e x t / p l a i n :
r=Response . ok ( g e t P l a i n R e p ( nume ) , t e x t / p l a i n ) . b u i l d ( ) ;
break ;
case t e x t / html :
r=Response . ok ( getHtmlRep ( nume ) , t e x t / html ) . b u i l d ( ) ;
break ;
}
return r ;

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

36

public S t r i n g g e t P l a i n R e p ( S t r i n g nume ) {
return H e l l o +nume+ ! ;
}

37
38

public S t r i n g getHtmlRep ( S t r i n g nume ) {


return <html><head></head><body b g c o l o r=\#a a e e a a\>< c e n t e r >
<h1>H e l l o +nume+ ! </h1></c e n t e r ></body></html> ;
}

40
41
42
43
44

Apelarea serviciului RESTful dintr-un navigator se obtine cu


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

<html>
<body>
<center>
<h1> S e r v i c i u H e l l o de t i p RESTful </h1>
<form method= g e t
action= / H e l l o / r e s o u r c e s / h e l l o >
<p> I n t r o d u c e t i numele </p>
<input type= t e x t name=nume s i z e= 10 />
<p> S e l e c t a t i t i p u l r a s p u n s u l u i </p>
<s e l e c t name= t i p >
<option value= t e x t / p l a i n > Text / P l a i n </ option>
<option value= t e x t / html > Text /Html </ option>
</ s e l e c t>
<p>
<input type= submit value= A p e l e a z a />
</form>
</ center>
</body>
</html>

Utilizand metoda POST n programul serviciului, adnotarea @QueryParam


se nlocuieste cu adnotarea @FormParam.
In cazul unui serviciu RESTful care raspunde la o cerere GET, n programul
client bazat pe clasa HttpURLConnect, datele de intrare trebuie codate UTF-8
si asamblate n adresa URL:
1
2
3

import j a v a . n e t .URL;
import j a v a . n e t . HttpURLConnection ;
import j a v a . n e t . URLEncoder ;

195

5.2. JERSEY-2

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

import
import
import
import

i o . IOException ;
i o . InputStreamReader ;
i o . BufferedReader ;
u t i l . Scanner ;

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 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 {
S t r i n g param= ? ;
System . out . p r i n t l n ( Numele ) ;
S t r i n g nume=URLEncoder . en code ( s c a n n e r . n e x t ( ) , UTF8 ) ;
param=param+nume=+nume+& ;
param=param+ t i p=+URLEncoder . e nc od e ( t e x t / p l a i n , UTF8 ) ;
S t r i n g u r l S t r= h t t p : / / l o c a l h o s t : 8 0 8 0 / H e l l o / r e s o u r c e s / h e l l o +param ;
System . out . p r i n t l n ( u r l S t r ) ;
S t r i n g r e z u l t a t=httpGetText ( u r l S t r ) ;
System . out . p r i n t l n ( r e z u l t a t ) ;
}
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 message : +e . g e t M e s s a g e ( ) ) ;
}
System . out . p r i n t l n ( ) ;
}
public s t a t i c S t r i n g httpGetText ( S t r i n g u r l S t r ) throws IOException { . . . }

29
30

java .
java .
java .
java .

In varianta JerseyClient codul clasei client este


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

package h e l l o ;
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a . u t i l

rs . c l i en t . Client ;
rs . client . ClientBuilder ;
r s . c l i e n t . WebTarget ;
. Scanner ;

public c l a s s J e r s e y 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 [ ] ) {
C l i e n t c l i e n t = C l i e n t B u i l d e r . newClient ( ) ;
WebTarget webTarget=
c l i e n t . t a r g e t ( http :// l o c a l h o s t :8080/ Hello / r e s o u r c e s / h e l l o ) ;
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 t i p u l r a s p u n s u l u i : ) ;
System . out . p r i n t l n ( ( p l a i n / html ) ) ;
S t r i n g t i p=s c a n n e r . n e x t ( ) ;
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 ( ) ;
S t r i n g r e s p o n s e=webTarget . queryParam ( nume , nume ) .
queryParam ( t i p , t e x t / +t i p ) . r e q u e s t ( ) . g e t ( S t r i n g . c l a s s ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
}
}

Pentru metoda POST, n varianta httpcomponent clientul este


1
2
3
4

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 . methods . HttpPost ;
o r g . apache . h t t p . impl . c l i e n t . C l o s e a b l e H t t p C l i e n t ;

196

5
6
7
8
9
10
12
13
15
16

import
import
import
import
import
import

o r g . apache . h t t p . impl . c l i e n t . H t t p C l i e n t s ;
java . u t i l . List ;
java . u t i l . ArrayList ;
java . u t i l . Scanner ;
o r g . apache . h t t p . NameValuePair ;
o r g . apache . h t t p . message . BasicNameValuePair ;

import o r g . apache . h t t p . c l i e n t . e n t i t y . UrlEncodedFormEntity ;


import j a v a . i o . ;
public c l a s s C l i e n t {
private 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 / H e l l o / r e s o u r c e s / h e l l o ;
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 ( Numele ) ;
S t r i n g nume=s c a n n e r . n e x t L i n e ( ) . t r i m ( ) ;

18
19
20
21

CloseableHttpClient httpclient = HttpClients . createDefault ( ) ;


L i s t <NameValuePair> qparams = new A r r a y L i s t <NameValuePair > ( ) ;
qparams . add (new BasicNameValuePair ( nume , nume ) ) ;
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 ( (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 ( ) ) ;
}

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

44
45

CAPITOLUL 5. SERVICII JAX-RS

si n varianta JerseyClient clasei client este


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

package h e l l o ;
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a x . ws .
import j a v a . u t i l

rs . c l i en t . Client ;
rs . c l i e n t . Entity ;
rs . client . ClientBuilder ;
r s . c l i e n t . WebTarget ;
r s . c o r e . Form ;
r s . c o r e . Response ;
. Scanner ;

public c l a s s J e r s e y 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 [ ] ) {
C l i e n t c l i e n t = C l i e n t B u i l d e r . newClient ( ) ;
WebTarget webTarget=
c l i e n t . t a r g e t ( http :// l o c a l h o s t :8080/ Hello / r e s o u r c e s / h e l l o ) ;
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 ) ;

197

5.2. JERSEY-2

System . out . p r i n t l n ( I n t r o d u c e t i t i p u l r a s p u n s u l u i : ) ;
System . out . p r i n t l n ( ( p l a i n | html ) ) ;
S t r i n g t i p=s c a n n e r . n e x t ( ) ;
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 ( ) ;
Form f=new Form ( ) . param ( nume , nume ) . param ( t i p , t e x t / +t i p ) ;
Response r e s p o n s e=webTarget . r e q u e s t ( ) . p o s t ( E n t i t y . form ( f ) ) ;
String r = response . readEntity ( String . class ) ;
System . out . p r i n t l n ( r ) ;

16
17
18
19
20
21
22
23
24

25
26

Adnotarea @PathParam
In cazul utilizarii metodei http GET o solutie mai simpla pentru fixarea
unui numar mic de parametri este introducerea lor n adnotarea @Path sub
forma
@Path("refCale/{param1},{param2},. . .")
Metoda care preia parametri utilizeaza adnotarea @PathParam:
public T getResursa(@PathParam("param1") String p1,
@PathParam("param2") String p2,. . .){. . .}
Stringul care fixeaza URL-ul de apelare va fi de forma
.../resources/refCale/valParam1,valParam2
Exemplul 5.2.3 Serviciu RESTful pentru calculul celui mai mare divizor comun a doua numere naturale.
Codul serviciului este
1
2
3
4
5
6
8
9

package r e s o u r c e s ;
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s

. Path ;
. PathParam ;
. Produces ;
.GET;
. c o r e . MediaType ;

@Path ( cmmdc/{num1 } , { num2} )


public c l a s s CmmdcResource {

11

public CmmdcResource ( ) { }

13

@GET
@Produces ( MediaType . APPLICATION XML)
public S t r i n g getCmmdcAsXML( @PathParam ( num1 ) S t r i n g sm ,
@PathParam ( num2 ) S t r i n g sn ) {
System . out . p r i n t l n ( sm+ +sn ) ;

14
15
16
17

198

long m=Long . par se Lon g ( sm ) ;


long n=Long . p ars eL ong ( sn ) ;
long c=cmmdc(m, n ) ;
S t r i n g r e s u l t =(new Long ( c ) ) . t o S t r i n g ( ) ;
return <?xml v e r s i o n =\1.0\ e n c o d i n g =\UTF8\?>< r e z u l t a t >+
r e s u l t+</ r e z u l t a t > ;

18
19
20
21
22
23

24

private long cmmdc( long m, long n ) { . . . }

26
27

CAPITOLUL 5. SERVICII JAX-RS

iar al clientului
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

com . sun . j e r s e y . a p i . c l i e n t . C l i e n t ;
com . sun . j e r s e y . a p i . c l i e n t . WebResource ;
j a v a x . ws . r s . c o r e . MediaType ;
java . u t i l . Scanner ;

public c l a s s J e r s e y C l i e n t {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( Primul numar : ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g sm=(new Long (m) ) . t o S t r i n g ( ) ;
S t r i n g sn =(new Long ( n ) ) . t o S t r i n g ( ) ;
Client c l i e n t = Client . create ( ) ;
WebResource webResource = c l i e n t . r e s o u r c e (
h t t p : / / l o c a l h o s t : 8 0 8 0 / cmmdcapp/ r e s o u r c e s /cmmdc/ +sm+ , +sn ) ;
S t r i n g r e s p o n s e=
webResource . a c c e p t ( MediaType . APPLICATION XML ) . g e t ( S t r i n g . c l a s s ) ;
System . out . p r i n t l n ( ) ;
System . out . p r i n t l n ( MediaType . APPLICATION XML ) ;
System . out . p r i n t l n ( r e s p o n s e ) ;
}
}

In acest caz un client Web se obtine cu AJAX


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

< ! doctype html>


<head>
<s c r i p t type= t e x t / j a v a s c r i p t >
< !
function initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
} e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}
f u n c t i o n compute ( ) {
var mField=document . g e t E l e m e n t B y I d ( m ) ;
var n F i e l d=document . g e t E l e m e n t B y I d ( n ) ;
var u r l = h t t p : / / l o c a l h o s t : 8 0 8 0 / cmmdcapp/ r e s o u r c e s /cmmdc/ +
e s c a p e ( mField . value)+ , +e s c a p e ( n F i e l d . value ) ;
var r e q = i n i t R e q u e s t ( ) ;

5.2. JERSEY-2

req . onreadystatechange = function () {


i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
p a r s e M e s s a g e s ( r e q . responseXML ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . open ( g e t , u r l , t r u e ) ;
r e q . send ( n u l l ) ;

20
21
22
23
24
25
26
27
28
29
30
31
33
34
35
36
37
38
39
41
42
43
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

}
f u n c t i o n p a r s e M e s s a g e s ( responseXML ) {
var r = responseXML . getElementsByTagName ( r e z u l t a t ) [ 0 ] ;
var cmmdc=r . c h i l d N o d e s [ 0 ] . nodeValue ;
document . g e t E l e m e n t B y I d ( r e z u l t a t ) . innerHTML=Cmmdc = +cmmdc ;
}
>
</ s c r i p t>
< t i t l e> Cmmdc AJAX</ t i t l e>
</head>
<body bgcolor=#bbccbb >
<h1>Cmmdc with AJAX</h1>
<form>
<table>
<tr>
<td><l a b e l> Primul numar </ l a b e l></td>
<td>
<input type=number id=m s i z e= 5
r e q u i r e d min= 1 >
</td>
</ tr>
<tr>
<td><l a b e l> Al d o i l e a numar </ l a b e l></td>
<td>
<input type=number id=n s i z e= 5
r e q u i r e d min= 1 >
</td>
</ tr>
<tr>
<td>
<p><input type= b ut to n value= C a l c u l e a z a onClick= compute ( ) >
</td>
</ tr>
</ table>
</form>
<p>
Cel mai mare d i v i z o r comun a l c e l o r doua numere e s t e
<p>
<div id= r e z u l t a t />
</body>
</html>

199

200

CAPITOLUL 5. SERVICII JAX-RS

5.2.3

Date prin component


a Java

Datele catre serviciul RESTful cat si rezultatele pot fi trimise respectiv


receptionate printr-o componenta Java (bean). Datele care urmeaza a fi schimbate ntre client si server se includ n componente Java. La receptie programatorul are acces la o componenta Java.
Componenta Java va fi reprezentata sub forma unui document xml sau
json ce va fi inclusa n corpul unui mesaj http.
Exista mai multe tehnologii care permit acest lucru MOXy POJO based
JSON binding, jackson, jettison.
Daca componenta Java se reprezinta ca document xml atunci resursele din
jersey sunt suficiente dar n cazul unui document json sunt necesare resurse
suplimentare.
Exemplificarea se va face utilizand MOXy POJO based JSON binding iar
resursele suplimentare necesare sunt:
jersey-entity-filtering-*.jar
jersey-media-moxy-*.jar
org.eclipse.persistence.antlr *.jar
org.eclipse.persistence.asm *.jar
org.eclipse.persistence.core *.jar
org.eclipse.persistence.moxy *.jar
In clientul Jersey componenta Java este acoperita de un obiect
javax.ws.rs.client.Entity, iar tipul datelor este
MediaType.APPLICATION JSON,
MediaType.APPLICATION XML.
Clasa javax.ws.rs.client.Entity<T>
Metode
public static <T> Entity<T> entity(T entity, MediaType media Type)
Exemplul 5.2.4
Clasa componentei Java (POJO) - CmmdcBean.java.
2

package r e s o u r c e s ;
// i m p o r t j a v a x . xml . b i n d . a n n o t a t i o n . XmlRootElement ;

// @XmlRootElement ( name=d a t e )

201

5.2. JERSEY-2

5
6
7
8

public c l a s s CmmdcBean{
private S t r i n g sm ;
private S t r i n g sn ;
private S t r i n g r e s u l t ;
public void setSm ( S t r i n g sm ) {
t h i s . sm=sm ;
}
public S t r i n g getSm ( ) {
return sm ;
}

10
11
12
13
14
15

public void s e t S n ( S t r i n g sn ) {
t h i s . sn=sn ;
}
public S t r i n g getSn ( ) {
return sn ;
}

17
18
19
20
21
22

public void s e t R e s u l t ( S t r i n g 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 g e t R e s u l t ( ) {
return r e s u l t ;
}

24
25
26
27
28
29
30

Liniile comentate trebuie decomentate daca comunicatia se baseaza pe


mesaje xml.
Clasa serviciului RESTful - CmmdcResource.java.
1
2
3
4
5
6
8
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package r e s o u r c e s ;
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s
import j a v a x . ws . r s

. Consumes ;
. POST ;
. Path ;
. Produces ;
. c o r e . MediaType ;

@Path ( cmmdc )
public c l a s s CmmdcResource {
public CmmdcResource ( ) { }
@POST
@Produces ( MediaType . APPLICATION JSON)
@Consumes ( MediaType . APPLICATION JSON)
public CmmdcBean myJob (CmmdcBean o b j ) {
S t r i n g sm=o b j . getSm ( ) ;
S t r i n g sn=o b j . getSn ( ) ;
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
long c=cmmdc(m, n ) ;
S t r i n g cmmdc=(new Long ( c ) ) . t o S t r i n g ( ) ;
CmmdcBean cb=new CmmdcBean ( ) ;
cb . s e t R e s u l t (cmmdc ) ;
return cb ;
}

202

CAPITOLUL 5. SERVICII JAX-RS

public long cmmdc( long m, long n ) { . . . }

27
28

In cazul comunicatiei prin mesaje xml se va folosi MediaType.APPLICATION XML.


Client de tip Jersey
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
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

package cmmdc ;
import j a v a x . ws . r s . c l i e n t . C l i e n t ;
import j a v a x . ws . r s . c l i e n t . C l i e n t B u i l d e r ;
import j a v a x . ws . r s . c l i e n t . WebTarget ;
import j a v a x . ws . r s . c l i e n t . E n t i t y ;
import j a v a x . ws . r s . c o r e . MediaType ;
import j a v a . u t i l . S c a n n e r ;
import j a v a . i o . P r i n t W r i t e r ;
import r e s o u r c e s . CmmdcBean ;
public c l a s s J e r s e y C l i e n t {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( Primul numar : ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
long n=s c a n n e r . nextLong ( ) ;
S t r i n g sm=(new Long (m) ) . t o S t r i n g ( ) ;
S t r i n g sn =(new Long ( n ) ) . t o S t r i n g ( ) ;
CmmdcBean bean=new CmmdcBean ( ) ;
bean . setSm ( sm ) ;
bean . s e t S n ( sn ) ;
i n t t i p =1;
do{
System . out . p r i n t l n ( Encoder Type ) ;
System . out . p r i n t l n ( 1 : JSON ) ;
System . out . p r i n t l n ( 2 : XML ) ;
t i p=s c a n n e r . n e x t I n t ( ) ;
}
while ( ( t i p !=1) && ( t i p ! = 2 ) ) ;
C l i e n t c l i e n t = C l i e n t B u i l d e r . newClient ( ) ;
S t r i n g sURI= ;
i f ( t i p ==1){
sURI= h t t p : / / l o c a l h o s t : 8 0 8 0 / JsonCmmdc/ r e s o u r c e s /cmmdc ;
}
else {
sURI= h t t p : / / l o c a l h o s t : 8 0 8 0 /XmlCmmdc/ r e s o u r c e s /cmmdc ;
}
WebTarget t a r g e t=c l i e n t . t a r g e t ( sURI ) ;
CmmdcBean o b j ;
i f ( t i p ==1){
obj = target
. request ()
. p o s t ( E n t i t y . e n t i t y ( bean , MediaType . APPLICATION JSON ) ,
CmmdcBean . c l a s s ) ;
}
else {
obj = target
. request ()

203

5.2. JERSEY-2

. p o s t ( E n t i t y . e n t i t y ( bean , MediaType . APPLICATION XML) ,


CmmdcBean . c l a s s ) ;

52
53

}
System . out . p r i n t l n ( o b j . g e t R e s u l t ( ) ) ;

54
55

56
57

Client Web (index.html )


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

<html>
<head>
<s c r i p t type= t e x t / j a v a s c r i p t >
< !
function initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
} e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}
f u n c t i o n compute ( ) {
var mField=document . g e t E l e m e n t B y I d ( m ) ;
var n F i e l d=document . g e t E l e m e n t B y I d ( n ) ;
var u r l = /JsonCmmdc/ r e s o u r c e s /cmmdc
var msg=JSON . s t r i n g i f y ( {
sm : mField . value ,
sn : n F i e l d . value
});
var r e q = i n i t R e q u e s t ( ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
parseMessages ( req . responseText ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . open ( p o s t , u r l , t r u e ) ;
r e q . s e t R e q u e s t H e a d e r ( ContentType , a p p l i c a t i o n / j s o n ) ;
r e q . send ( msg ) ;

23
24
25
26
27
28
29
30
31
32
33
34
35
37
38
39
40
41
42
43
44
45
46
47
48
49

}
f u n c t i o n parseMessages ( responseText ) {
var r e s=r e s p o n s e T e x t ;
var s=JSON . p a r s e ( r e s ) ;
document . g e t E l e m e n t B y I d ( r e z u l t a t ) . innerHTML=
Cmmdc = +s . r e s u l t ;
}
>
</ s c r i p t>
< t i t l e> Cmmdc AJAX</ t i t l e>
</head>
<body>
<h1>Cmmdc with AJAX</h1>
<p>

204

CAPITOLUL 5. SERVICII JAX-RS

50
51
52
53
54
55
56
57
58
59
60
61
62

Primul numar :
<input type= t e x t id=m value= 1 s i z e= 15 >
<p>
Al d o i l e a numar :
<input type= t e x t id=n value= 1 s i z e= 15 >
<p>
<input type= b ut to n value= C a l c u l e a z a onClick= compute ( ) >
<p>
Cel mai mare d i v i z o r comun a c e l o r doua numere e s t e
<p>
<div id= r e z u l t a t />
</body>
</html>

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

<html>
<head>
<s c r i p t type= t e x t / j a v a s c r i p t >
< !
function initRequest () {
i f ( window . XMLHttpRequest ) {
r e t u r n new XMLHttpRequest ( ) ;
} e l s e i f ( window . A c t i v e X O b j e c t ) {
r e t u r n new A c t i v e X O b j e c t ( M i c r o s o f t .XMLHTTP ) ;
}
}
f u n c t i o n compute ( ) {
var mField=document . g e t E l e m e n t B y I d ( m ) . value ;
var n F i e l d=document . g e t E l e m e n t B y I d ( n ) . value ;
var u r l = /XmlCmmdc/ r e s o u r c e s /cmmdc
var msg=
<?xml v e r s i o n =\ 1 . 0 \ e n c o d i n g=\UTF8\ s t a n d a l o n e =\ y e s \ ?>+
<date><sm>+mField+</sm><sn>+n F i e l d+</sn></date> ;
var r e q = i n i t R e q u e s t ( ) ;
req . onreadystatechange = function () {
i f ( r e q . r e a d y S t a t e == 4) {
i f ( r e q . s t a t u s == 200) {
parseMessages ( req . responseText ) ;
} else {
a l e r t ( r e q . s t a t u s+ : +r e q . s t a t u s T e x t ) ;
}
}
};
r e q . open ( p o s t , u r l , t r u e ) ;
r e q . s e t R e q u e s t H e a d e r ( ContentType , a p p l i c a t i o n /xml ) ;
r e q . send ( msg ) ;

22
23
24
25
26
27
28
29
30
31
32
33
34
36
37
38
39
40
41
42

}
f u n c t i o n parseMessages ( responseText ) {
var r e s=r e s p o n s e T e x t ;
document . g e t E l e m e n t B y I d ( r e z u l t a t ) . innerHTML=Cmmdc = +r e s ;
}
>
</ s c r i p t>
< t i t l e> Cmmdc AJAX</ t i t l e>

5.2. JERSEY-2

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

205

</head>
<body>
<h1>RESTful Cmmdc with AJAX cu mesaj XML</h1>
<p>
Primul numar :
<input type= t e x t id=m value= 1 s i z e= 15 >
<p>
Al d o i l e a numar :
<input type= t e x t id=n value= 1 s i z e= 15 >
<p>
<input type= b ut to n value= C a l c u l e a z a onClick= compute ( ) >
<p>
Cel mai mare d i v i z o r comun a c e l o r doua numere e s t e
<p>
<div id= r e z u l t a t />
</body>
</html>

5.2.4

Aplicatie cu server asincron

Programarea satisfacerii cererii n mod asincron se realizeaza prin lansarea


unui fir de executie responsabil de rezolvarea cererii. In acest scop
Elementul <servlet> din web.xml se completeaza cu
<async-supported>true</async-supported>
Metoda cu executia asincrona contine variabila formala
@Suspended AsyncResponse response
cu referintele
import javax.ws.rs.container.Suspended;
import javax.ws.rs.container.AsyncResponse;
Sablonul de programare al firului de executie este
new Thread(()->{
// Cod pentru formarea raspunsului response
response.resume(response);
}).start();

Optional se poate fixa o limita n timp pentru rezolvarea cererii

206

CAPITOLUL 5. SERVICII JAX-RS

import java.util.concurrent.TimeUnit;
. . .
int timeOut=. . .;
response.setTimeout(timeOut, TimeUnit.SECONDS);
response.setTimeoutHandler((asyncResp) -> {
asyncResp.resume(Response.status(Response.Status.REQUEST_TIMEOUT).build());
});

Argumentul metodei setTimeoutHandler este un obiect care implementeaza


interfata javax.ws.rs.container.TimeoutHandler. Aceasta interfata
declara metoda
void handleTimeout(AsyncResponse asyncResponse)
Exemplul 5.2.5
1
2
3
4
5
6
7
8
10
11
13
14
15
16
17
18

package r e s o u r c e s ;
import j a v a x . ws . r s . QueryParam ;
import j a v a x . ws . r s . c o r e . Response ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;
import j a v a x . ws . r s . c o n t a i n e r . Suspended ;
import j a v a x . ws . r s . c o n t a i n e r . AsyncResponse ;
import j a v a . u t i l . c o n c u r r e n t . TimeUnit ;
@Path ( query )
public c l a s s CmmdcResource {
@GET
public void processForm ( @Suspended AsyncResponse r e s p o n s e ,
@QueryParam ( m ) S t r i n g sm ,
@QueryParam ( n ) S t r i n g sn ) {
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
new Thread (()>{
long c=cmmdc(m, n ) ;
S t r i n g s c=Cmmdc : +new Long ( c ) . t o S t r i n g ( ) ;
r e s p o n s e . resume ( s c ) ;
}). start ();

20
21
22
23
24

r e s p o n s e . s e t T i m e o u t ( 5 , TimeUnit .SECONDS ) ;
// c l i e n t w i l l r e c i e v e a HTTP 408 ( t i m e o u t e r r o r ) a f t e r 5 s e c o n d s
r e s p o n s e . s e t T i m e o u t H a n d l e r ( ( asyncResp ) > {
asyncResp . resume ( Response
. s t a t u s ( Response . S t a t u s .REQUEST TIMEOUT ) . b u i l d ( ) ) ;
});

26
27
28
29
30
31
32

34

private long cmmdc( long m, long n ) {


long c , r ;
do{
c=n ;
r=m%n ;
m=n ;

35
36
37
38
39

5.2. JERSEY-2

n=r ;
}
while ( r ! = 0 ) ;
/
try {
Thread . s l e e p ( 1 0 0 0 0 ) ;
}
catch ( I n t e r r u p t e d E x c e p t i o n e ){}
/
return c ;

40
41
42
43
44
45
46
47
48
49

50
51

207

In mediu JEE (de exemplu glassfish) codul de mai sus se simplifica n


sensul ca generarea firului de executie n care se creaza raspunsul nu mai este
n sarcina programatorului.

5.2.5

Jersey n glassfish

Pachetul jersey este continut n glassfish. In consecinta arhiva war destinata desfasurarii unei aplicatii nu trebuie sa contina resursele care tin de
jersey.
Aplicatiile dezvoltate anterior functioneaza fara nici o modificare n glassfish.
Semnalam arhitectura unei aplicatii care utilizeaza o componenta EJB de
tip session stateless, care este injectata n clasa serviciului RESTful. Injectarea
se poate programa utilizand:
adnotarile javax.annotation.ManagedBean si javax.inject.Inject.
In acest caz, este nevoie de prezenta unui fisier beans.xml, avand codul
1
2
3
4
5
6

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
<beans xmlns= h t t p : / / j a v a . sun . com/xml/ ns / j a v a e e
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 / j a v a e e
h t t p : / / j a v a . sun . com/xml/ ns / j a v a e e / b e a n s 1 0 . xsd >
</beans>

adnotarea javax.ejb.EJB.
Exemplul 5.2.6 Calculul celui mai mare divizor comun a doua numere naturale.
Structura aplicatiei este

208

CAPITOLUL 5. SERVICII JAX-RS

Cmmdc
|--> WEB-INF
|
|--> classes
|
|
|--> cmmdc
|
|
|
|
App.class
|
|
|--> resources
|
|
|
|
CmmdcQueryResources.class
|
|
beans.xml
|
|
web.xml
|
index.html

Codul clasei CmmdcQueryResources este


1
2
3
4
5
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
34
35
36
37
38
39
40
42
43
44
46
47

package r e s o u r c e s ;
import j a v a x . ws . r s . QueryParam ;
import j a v a x . s e r v l e t . S e r v l e t C o n t e x t ;
import j a v a x . ws . r s . c o r e . Response ;
import j a v a x . ws . r s . Produces ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;
import j a v a . n e t . URLDecoder ;
import j a v a x . a n n o t a t i o n . ManagedBean ;
import j a v a x . i n j e c t . I n j e c t ;
import cmmdc . App ;
@Path ( cmmdcquery )
@ManagedBean
public c l a s s CmmdcQueryResource {
@Inject
App o b j ;
@GET
public Response p r o c e s s Q u e r y (
@QueryParam ( m ) S t r i n g sm ,
@QueryParam ( n ) S t r i n g sn ,
@QueryParam ( t i p ) S t r i n g t i p ) {
S t r i n g t i p 0=URLDecoder . de co de ( t i p ) ;
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
System . out . p r i n t l n (m+ : +n+ : +t i p 0 ) ;
long c=o b j . cmmdc(m, n ) ;
S t r i n g message =(new Long ( c ) ) . t o S t r i n g ( ) ;
Response r=n u l l ;
switch ( t i p 0 ) {
case t e x t / p l a i n :
r=Response . ok ( g e t P l a i n R e p ( message ) , t e x t / p l a i n ) . b u i l d ( ) ;
break ;
case t e x t / html :
r=Response . ok ( getHtmlRep ( message ) , t e x t / html ) . b u i l d ( ) ;
break ;
}
return r ;
}
public S t r i n g g e t P l a i n R e p ( S t r i n g msg ) {
return msg ;
}
public S t r i n g getHtmlRep ( S t r i n g msg ) {
return <html><head></head><body b g c o l o r=\#a a e e a a\>< c e n t e r >

5.2. JERSEY-2

<h1>Cmmdc : + msg+</h1></c e n t e r ></body></html> ;

48

49
50

209

Este recomandat ca serviciul RESTful sa implementeze functiile CRUD


(Create, Read, Update, Delete) asociindu-le, respectiv cu metodele PUT,
GET, POST, DELETE.
Exemplul 5.2.7 Server asincron
1
2
3
4
5
6
7
8
10
11
12

package r e s o u r c e s ;
import j a v a x . ws . r s .GET;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s . QueryParam ;
import j a v a x . ws . r s . c o n t a i n e r . Suspended ;
import j a v a x . ws . r s . c o n t a i n e r . AsyncResponse ;
import j a v a x . e j b . S t a t e l e s s ;
import j a v a x . e j b . Asynchronous ;
@Stateless
@Path ( /cmmdc )
public c l a s s AsynchronousCmmdcResource {
@GET
@Asynchronous
public void asyncRestMethod ( @Suspended f i n a l AsyncResponse asyncResponse ,
@QueryParam ( m ) S t r i n g sm ,
@QueryParam ( n ) S t r i n g sn ) {
long m=Long . par se Lon g ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
System . out . p r i n t l n (m+ : +n ) ;
long r=cmmdc(m, n ) ;
S t r i n g r e s u l t = new Long ( r ) . t o S t r i n g ( ) ;
a s y n c R e s p o n s e . resume ( r e s u l t ) ;
}

14
15
16
17
18
19
20
21
22
23
24
25

private long cmmdc( long m, long n ) {


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

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

Elementul <web-app> din fisierul web.xml trebuie sa fie


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

210

CAPITOLUL 5. SERVICII JAX-RS

Aplicatii de verificare a unui server REST


Advanced REST Client disponibil in Chrome Web Store
restclient-ui-*-jar-with-dependencies.jar
java -jar restclient-ui-*-jar-with-dependencies.jar

5.2.6

Dezvoltare prin maven

Dezvoltarea aplicatiei server


Dezvoltarea aplicatiei Web consta din:
1. Generarea aplicatiei
set GroupId=resources
set ArtifactId=hw
set jersey-version=2.22.1
set Version=1.0
mvn -B archetype:generate
-DgroupId=%GroupId%
-DartifactId=%ArtifactId%
-Dversion=%Version%
-DarchetypeArtifactId=jersey-quickstart-webapp
-DarchetypeGroupId=org.glassfish.jersey.archetypes
-DinteractiveMode=false
-DarchetypeVersion=%jersey-version%

2. Se adapteaza structura de cataloage si fisiere la


hello
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|-->
|
|
|-->
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|--> HelloWorldResource.java
resources
webapp
|--> WEB-INF
|
|
web.xml
|
index.html

3. Prelucrarea consta din


(a) mvn clean package
(b) Fisierul war care rezulta se desfasoara n serverul Web.

211

5.2. JERSEY-2

Dezvoltarea aplicatiei client


Dezvoltarea aplicatiei consta din:
1. Generarea aplicatiei
set GroupId=hw
set ArtifactId=client
set jersey-version=2.22.1
set Version=1.0
set ArchetypeArtifactId=maven-archetype-quickstart
mvn -B archetype:generate
-DarchetypeArtifactId=%ArchetypeArtifactId%
-DgroupId=%GroupId%
-DartifactId=%ArtifactId%
-Dversion=%Version%
-DinteractiveMode=false

2. Se adapteaza structura de cataloage si fisiere la


hello-client
|--> src
|
|--> main
|
|
|-->
|
|
|
|
|
|
|
|
|
|
pom.xml

java
|--> hw
|
|
|
|

JerseyClient.java
Client.java

3. Fisierul pom.xml se completeaza cu


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
. . .
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>

212

CAPITOLUL 5. SERVICII JAX-RS

</dependency>
. . .
</dependencies>
<properties>
<jersey.version>2.22.1</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

4. Prelucrarea consta din


(a) mvn clean compile
(b) mvn exec:java -Dexec.mainClass="hw.JerseyClient"
respectiv
mvn exec:java -Dexec.mainClass="hw.Client"

5.3

Serviciu Restful (jersey) n Heroku

Vom folosi exemplul


Exemplul 5.3.1 Serviciul RESTful Hello World care consta n furnizarea textului Hello World n trei formate text/plain, html si xml.
Dezvoltam aplicatia cu apache-maven:
1
2
3
4
5
6
7
8
9
10
11

s e t g r o u p I d=r e s o u r c e s
s e t a r t i f a c t I d=hw
s e t package= u n i t b v . c s . td
s e t j e r s e y v e r s i o n =2.13
mvn a r c h e t y p e : g e n e r a t e D a r c h e t y p e A r t i f a c t I d=j e r s e y herokuwebapp
DarchetypeGroupId=o r g . g l a s s f i s h . j e r s e y . a r c h e t y p e s
D i n t e r a c t i v e M o d e=f a l s e
DgroupId=%g r o u p I d%
D a r t i f a c t I d=%a r t i f a c t I d%
Dpackage=%package%
D a r c h e t y p e V e r s i o n=%j e r s e y v e r s i o n%

Esential este proprietatea archetypeArtifactId=jersey-heroku-webapp .


Se aduce structura de cataloage si fisiere la forma
hw
|-->
|
|
|
|
|
|
|
|
|

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

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

java
|--> unitbv
|
|--> cs
|
|
|-->
|
|
|
|
|
|
|
|
|
webapp

td
|--> heroku
|
|
Main.java
|
HelloWorldResources.java

5.3. SERVICIU RESTFUL (JERSEY) IN HEROKU

|
|
|
|
|

213

|
|
|--> WEB-INF
|
|
|
|
web.xml
Procfile
system.properties
pom.xml

Rolul programatorului este sa realizeze clasa HelloWorldResources. Clasa


Main ca si celelalte fisiere sunt generate automat. Clasa Main ncorporeaza
un server Web de tip jetty prin care va obtine resursa generata de HelloWorldResources. Cataloage si fisiere suplimentare se vor sterge.
Codul clasei HelloWorldResources este
1

package u n i t b v . c s . td ;

import j a v a x . ws . r s . Produces ;
import j a v a x . ws . r s . Path ;
import j a v a x . ws . r s .GET;

4
5
7
8

@Path ( h e l l o w o r l d )
public c l a s s H e l l o W o r l d R e s o u r c e {

10

public H e l l o W o r l d R e s o u r c e ( ) {}

12

@GET
@Produces ( t e x t / p l a i n )
public S t r i n g g e t T e x t ( ) {
return ( H e l l o World ) ;
}

13
14
15
16

@Path ( html )
@GET
@Produces ( t e x t / html )
public S t r i n g getAsHtml ( ) {
return <html><head></head><body b g c o l o r=\#bbeebb\>
<c e n t e r ><p>H e l l o World</p></c e n t e r ></body></html> ;
}

18
19
20
21
22
23
24

@Path ( xml )
@GET
@Produces ( a p p l i c a t i o n /xml )
public S t r i n g getAsXml ( ) {
return <r e s p o n s e >H e l l o World</r e s p o n s e > ;
}

26
27
28
29
30
31
32

Dupa comanda mvn clean package aplicatia se poate verifica


Local, lansand un server Web jetty: mvn jetty:run.
Se poate utiliza clientul Web
1
2
3
4
5
6

<html>
<body>
<table border= 2 >
<tr>
<td>
<a href= h t t p : / / l o c a l h o s t : 8 0 8 0 / h e l l o w o r l d >

214

CAPITOLUL 5. SERVICII JAX-RS

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

R e z u l t a t t e x t / p l a i n </a>
</td>
</ tr>
<tr>
<td>
<a href= h t t p : / / l o c a l h o s t : 8 0 8 0 / h e l l o w o r l d / html >
R e z u l t a t t e x t / html </a>
</td>
</ tr>
<tr>
<td>
<a href= h t t p : / / l o c a l h o s t : 8 0 8 0 / h e l l o w o r l d /xml>
R e z u l t a t a p p l i c a t i o n /xml</a>
</td>
</ tr>
</ table>
</body>
</html>

Desfasurand aplicatia n alt server, de exemplu apache-tomcat. Intr-un


client Web singura deosebire va fi adresa din ancore, care vor fi de forma
http://localhost:8080/hw/helloworld

Desfasurarea n Heroku este obisnuita:


1. Pregatirea Git
git init
git add .
git commit -m "myapp"
2. Generarea si desfasurarea aplicatiei
heroku create
git push heroku master
Din nou se poate utilize acelasi client Web, dar adresa din ancore va fi de
forma
http://numele furnizat de Heroku.herokuapp.com/helloworld

215

5.4. MVC PRIN SERVICII RESTFUL

5.4

MVC prin servicii RESTful

JCP 371 se refera la programarea unei aplicatii pe modelul MVC ndeplinit


de un serviciu RESTful. Implementarea de referinta este denumita ozark
(https://ozark.java.net).
Acest cadrul de lucru urmeaza sa fie inclus n JEE 8.
Functie de un fisier de configurare exista variantele de aplicatie:
Varianta cu web.xml
Varianta cu glassfish-web.xml
Exemplificarea va fi facuta prin aplicatia de calcul a celui mai mare divizor
comun a doua numere naturale.

Variant
a cu web.xml
Structura aplicatiei
|--> WEB-INF
|
|--> classes
|
|
|
Controller.class
|
|
|
Model.class
|
|
|
HandlebarsViewEngine.class
|
|--> lib
|
|
|
*.lib
|
|
beans.xml
|
|
web.xml
|
index.html
|
output.hbs

-> CmmdcController.class
-> CmmdcBean.class

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

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
<! This web . xml f i l e i s not r e q u i r e d when u s i n g S e r v l e t 3 . 0 c o n t a i n e r ,
see implementation d e t a i l s
h t t p : // j e r s e y . j a v a . n e t / nonav / d o c u m e n t a t i o n / l a t e s t / j a x r s . html >
<webapp v e r s i o n= 2 . 5 xmlns= h t t p : / / j a v a . sun . com/xml/ ns / j a v a e e
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 / j a v a e e
h t t p : / / j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd >
<s e r v l e t >
<s e r v l e t name>J e r s e y Web A p p l i c a t i o n </ s e r v l e t name>
<s e r v l e t c l a s s >
org . g l a s s f i s h . j e r s e y . s e r v l e t . ServletContainer
</ s e r v l e t c l a s s >
<i n i t param>
<paramname>j e r s e y . c o n f i g . s e r v e r . p r o v i d e r . p ackage s </paramname>
<paramv a l u e >r e s o u r c e s </paramv a l u e >
</ i n i t param>
<l o a d ons t a r t u p >1</l o a d ons t a r t u p >

216

19
20
21
22
23
24

CAPITOLUL 5. SERVICII JAX-RS

</ s e r v l e t >
<s e r v l e t mapping>
<s e r v l e t name>J e r s e y Web A p p l i c a t i o n </ s e r v l e t name>
<u r l p a t t e r n >/ r e s o u r c e s /</u r l p a t t e r n >
</ s e r v l e t mapping>
</webapp>

Fisierul beans.xml
1

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>

<beans xmlns= h t t p : / / xmlns . j c p . o r g /xml/ ns / j a v a e e


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 : / / xmlns . j c p . o r g /xml/ ns / j a v a e e
h t t p : / / xmlns . j c p . o r g /xml/ ns / j a v a e e / b e a n s 1 1 . xsd
beand i s c o v e r y mode= a l l >
</beans>

4
5
6
7
8

Ambele variante au n comun:


output.hbs este pagina de afisare a rezultatului/rezultatelor.
HandlebarsViewEngine.java

Variant
a cu glassfish-web.xml
Structura aplicatiei
|--> WEB-INF
|
|--> classes
|
|
|
App.class
|
|
|
Controller.class
|
|
|
Model.class
|
|
|
HandlebarsViewEngine.class
|
|--> lib
|
|
|
*.lib
|
|
beans.xml
|
|
glassfish-web.xml
|
index.html
|
output.hbs

-> CmmdcController.class
-> CmmdcBean.class

Fisierul glassfish-web.xml
1
2
3
4
5
6
7
8
9
10
11

<?xml v e r s i o n= 1 . 0 e n c o d i n g=UTF8?>
<!DOCTYPE g l a s s f i s h webapp PUBLIC
// G l a s s F i s h . o r g //DTD G l a s s F i s h A p p l i c a t i o n S e r v e r 3 . 1 S e r v l e t 3 . 0 / /EN
h t t p : / / g l a s s f i s h . o r g / d t d s / g l a s s f i s h weba p p 3 0 1. dtd >
< g l a s s f i s h webapp e r r o r u r l= >
<c o n t e x t r o o t >/mvc</c o n t e x t r o o t >
<l o c a l e c h a r s e t i n f o defaultl o c a l e=UTF8>
<l o c a l e c h a r s e t map l o c a l e= c h a r s e t= />
<parametere n c o d i n g defaultc h a r s e t=UTF8/>
</ l o c a l e c h a r s e t i n f o >
</ g l a s s f i s h webapp>

5.4. MVC PRIN SERVICII RESTFUL

217

Clasa App fixeaza un context virtual pentru Controller


1

package r e s o u r c e s ;

import
import
import
import

4
5
6
8
9

rs . ApplicationPath ;
rs . core . Application ;
. Collections ;
. Set ;

@ A p p l i c a t i o n P a t h ( app )
public c l a s s App extends A p p l i c a t i o n {
@Override
public Set<C l a s s <?>> g e t C l a s s e s ( ) {
return C o l l e c t i o n s . s i n g l e t o n ( C o n t r o l l e r . c l a s s ) ;
}

11
12
13
14
15

j a v a x . ws .
j a v a x . ws .
java . u t i l
java . u t i l

Clasa HandlebarsViewEngine are rol in transmisia datelor de la controler


catre view.
1

package r e s o u r c e s ;

import
import
import
import
import
import
import

com . g i t h u b . j k n a c k . h a n d l e b a r s . H a n d l e b a r s ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . H e l p e r ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . O p ti on s ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . Template ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . h e l p e r . B l o c k H e l p e r ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . h e l p e r . EachHelper ;
com . g i t h u b . j k n a c k . h a n d l e b a r s . h e l p e r . EmbeddedHelper ;

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

javax . annotation . PostConstruct ;


javax . annotation . P r i o r i t y ;
javax . i n j e c t . I n j e c t ;
j a v a x . mvc . Models ;
j a v a x . mvc . e n g i n e . P r i o r i t i e s ;
j a v a x . mvc . e n g i n e . ViewEngine ;
j a v a x . mvc . e n g i n e . ViewEngineContext ;
j a v a x . mvc . e n g i n e . ViewEngineException ;
javax . s e r v l e t . ServletContext ;
javax . s e r v l e t . http . HttpServletRequest ;
javax . s e r v l e t . http . HttpServletResponse ;
javax . v a l i d a t i o n . ConstraintViolation ;
java . io . ;
java . u t i l . ;
j a v a . u t i l . stream . C o l l e c t o r s ;

4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
27
28
30
31
33
34
35
36
38
39

@ P r i o r i t y ( P r i o r i t i e s .DEFAULT)
public c l a s s HandlebarsViewEngine implements ViewEngine {
@Inject
private S e r v l e t C o n t e x t s e r v l e t C o n t e x t ;
@Override
public boolean s u p p o r t s ( S t r i n g view ) {
return view . endsWith ( . hbs ) ;
}
@Override
public void p r o c e s s V i e w ( ViewEngineContext c o n t e x t )

218

CAPITOLUL 5. SERVICII JAX-RS

throws ViewEngineException {

40

Models models = c o n t e x t . g e t M o d e l s ( ) ;
S t r i n g viewName = c o n t e x t . getView ( ) ;
i f ( ! viewName . s t a r t s W i t h ( / ) )
viewName = / + viewName ;

42
43
44
45

try ( P r i n t W r i t e r w r i t e r = c o n t e x t . g e t R e s p o n s e ( ) . g e t W r i t e r ( ) ;
InputStream r e s o u r c e A s S t r e a m =
s e r v l e t C o n t e x t . g e t R e s o u r c e A s S t r e a m ( viewName ) ;
InputStreamReader i n =
new InputStreamReader ( r e s o u r c e A s S t r e a m , UTF8 ) ;
B u f f e r e d R e a d e r b u f f e r e d R e a d e r = new B u f f e r e d R e a d e r ( i n ) ; ) {

47
48
49
50
51
52

S t r i n g viewContent =
bufferedReader . l i n e s ( ) . c o l l e c t ( Collectors . j o i n i n g ( ) ) ;

54
55

H a n d l e b a r s h a n d l e b a r s = new H a n d l e b a r s ( ) ;
Template t e m p l a t e = h a n d l e b a r s . c o m p i l e I n l i n e ( viewContent ) ;
t e m p l a t e . a p p l y ( models , w r i t e r ) ;
} catch ( IOException e ) {
throw new ViewEngineException ( e ) ;
}

57
58
59
60
61
62

63
64

Exemplul 5.4.1
Controller - CmmdcController
1

package r e s o u r c e s ;

import
import
import
import
import
import
import
import
import
import
import

4
5
6
7
8
9
10
11
12
13
15
16
17
19
20
22
23
24
25
27

javax . i n j e c t . I n j e c t ;
j a v a x . mvc . C o n t r o l l e r ;
j a v a x . mvc . Models ;
j a v a x . mvc . View ;
j a v a x . mvc . Viewable ;
javax . v a l i d a t i o n . Valid ;
j a v a x . ws . r s . ;
j a v a x . ws . r s . c o r e . Response ;
j a v a . n e t . URI ;
java . u t i l . ;
j a v a x . ws . r s . QueryParam ;

@Path ( / )
@Controller
public c l a s s CmmdcController {
@Inject
private Models models ;
@GET
@Path ( /cmmdc )
public S t r i n g computeCmmdc ( @QueryParam ( m ) S t r i n g sm ,
@QueryParam ( n ) S t r i n g sn ) {
CmmdcBean cb=new CmmdcBean ( ) ;

5.4. MVC PRIN SERVICII RESTFUL

cb . setSm ( sm ) ;
cb . s e t S n ( sn ) ;
long r e s u l t =cmmdc( Long . p ars eL ong ( sm ) , Long . pa rse Lo ng ( sn ) ) ;
cb . s e t R e s u l t (new Long ( r e s u l t ) . t o S t r i n g ( ) ) ;
System . out . p r i n t l n ( sm+ : +sn+ : +r e s u l t ) ;
models . put ( cmmdc , cb ) ;

28
29
30
31
32
33

return cmmdc . hbs ;

35

36

public long cmmdc( long m, long n ) { . . . }

38
39

Model - CmmdcBean
1

package r e s o u r c e s ;

public c l a s s CmmdcBean{
private S t r i n g sm ;
private S t r i n g sn ;
private S t r i n g r e s u l t ;

public CmmdcBean ( ) { }

4
5

public void setSm ( S t r i n g sm ) {


t h i s . sm=sm ;
}

10
11
12

public S t r i n g getSm ( ) {
return sm ;
}

14
15
16

public void s e t S n ( S t r i n g sn ) {
t h i s . sn=sn ;
}

18
19
20

public S t r i n g getSn ( ) {
return sn ;
}

22
23
24

public void s e t R e s u l t ( S t r i n g r e s u l t ) {
t h i s . r e s u l t=r e s u l t ;
}

26
27
28

public S t r i n g g e t R e s u l t ( ) {
return r e s u l t ;
}

30
31
32
33

View
Fisierul index.html de lansare a aplicatiei
1
2
3
4
5

<! d o c t y p e html>
<head>
<meta c h a r s e t= u t f 8>
</head>
<body b g c o l o r=#bbccbb >

219

220

CAPITOLUL 5. SERVICII JAX-RS

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

<c e n t e r >
<h1> Pagina de a p e l a r e CmmdcServlet </h1>
<form method= g e t
a c t i o n= / Ozark / app /cmmdc>
<t a b l e >
<t r >
<td><label> Primul numar </label ></td>
<td>
<i n p u t t y p e=number name=m s i z e= 5
r e q u i r e d min= 1 >
</td>
</t r >
<t r >
<td><label> Al d o i l e a numar </label ></td>
<td>
<i n p u t t y p e=number name=n s i z e= 5
r e q u i r e d min= 1 >
</td>
</t r >
<t r >
<td>
<p><i n p u t t y p e= submit v a l u e= C a l c u l e a z a >
</td>
</t r >
</ t a b l e >
</form>
<c e n t e r >
</body>
</html>

Fisierul cmmdc.hbs de afisare a rezultatului


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

5.5

<!DOCTYPE html>
<html>
<head l a n g= en >
<meta c h a r s e t=UTF8>
< t i t l e >Cmmdc View</ t i t l e >
</head>
<body>
<h1> MVC REST
<p>
Cmmdc(<span >{{cmmdc . sm}}</span >,<span >{{cmmdc . sn }}</span >)=
<span >{{cmmdc . r e s u l t }}</span>
</p>
</body>
</html>

Serviciu Restful cu GWT

Dintr-un client GWT se poate apela un server care poate fi n interiorul sau
exteriorul aplicatiei GWT (3.2.3). Cazul serverului exterior nu ridica nici o
problema (3.2.3). Pentru cazul serverului interior aplicatiei GWT se utilizeaza:
modelul de programare prezentat n (3.2.3) ;

5.5. SERVICIU RESTFUL CU GWT

221

Interfata serviciului lipseste dar exista interfata asincrona. Rolul interfetei


asincrone consta n:
1. Sa precizeze componenta Java cu datele cererii;
2. Sa indice metoda de apel invers (callback ) responsabila de prelucrarea raspunsului furnizat de serviciul Restful (de server).
schimbul de date dintre client si server prin intermediul componentelor
Java, codificate n obiecte JSON (de exemplu utilizand tehnologia MOXy
POJO based JSON binding) (5.2.3);
produsul RestyGWT.
Problemele de detaliu sunt prezentate n cazul exemplului:
Exemplul 5.5.1 Calculul celui mai mare divizor comun a doua numere naturale.
Presupunem ca numele modulul GWT este RestClient.
Structura initiala a aplicatiei este
|src
|-->
|
|
|
|
|
|
|
|
|war
|-->
|
|
|
|
|

. . .
|--> client
|
|
RestClient.java
|
|
AsyncClientInterface.java
|--> server
|
|
CmmdcResource.java
|--> shared
|
|
CmmdcBean.java
|
RestClient.wgt.xml
WEB-INF
|--> lib
|
|
*.jar
|
web.xml
RestClient.html
RestClient.css

Raportandu-ne la aplicatia din sectiunea (5.2.3) codurile claselor CmmdcBean.java, CmmdcResources.java sunt nemodificate (mai putin numele pachetului), la fel coincid fisierele html si css (mai putin numele fisierelor).
Codurile celorlalte claselor sunt

222

CAPITOLUL 5. SERVICII JAX-RS

Clasa AsyncClientInterface - interfata asincrona


1
2
3

package u n i t b v . c s . td . c l i e n t ;
import j a v a x . ws . r s . POST ;
import j a v a x . ws . r s . Path ;

import o r g . f u s e s o u r c e . r e s t y g w t . c l i e n t . MethodCallback ;
import o r g . f u s e s o u r c e . r e s t y g w t . c l i e n t . R e s t S e r v i c e ;

import u n i t b v . c s . td . s h a r e d . CmmdcBean ;

10
11

@Path ( xyz /cmmdc )


public i n t e r f a c e A s y n c C l i e n t I n t e r f a c e extends R e s t S e r v i c e {
@POST
public void g e t R e s u l t (CmmdcBean bean ,
MethodCallback<CmmdcBean> c a l l b a c k ) ;

13
14
15
16

Clasa RestClient - clientul GWT


1

package u n i t b v . c s . td . c l i e n t ;

import o r g . f u s e s o u r c e . r e s t y g w t . c l i e n t . D e f a u l t s ;
import o r g . f u s e s o u r c e . r e s t y g w t . c l i e n t . Method ;
import o r g . f u s e s o u r c e . r e s t y g w t . c l i e n t . MethodCallback ;

4
5

16

import
import
import
import
import
import
import
import
import
import

18

import u n i t b v . c s . td . s h a r e d . CmmdcBean ;

20

public c l a s s R e s t C l i e n t implements E n t r y P o i n t {
public void onModuleLoad ( ) {
f i n a l L a b e l t i t l e =new L a b e l ( CMMDC ) ;
t i t l e . addStyleName ( l a b e l t i t l e ) ;
f i n a l L a b e l mLabel=new L a b e l ( m= ) ;
f i n a l L a b e l nLabel=new L a b e l ( n= ) ;
f i n a l L a b e l cmmdcLabel=new L a b e l ( ) ;
f i n a l TextBox mTextBox=new TextBox ( ) ;
f i n a l TextBox nTextBox=new TextBox ( ) ;
f i n a l Button b ut to n = new Button ( Compute ) ;
bu tt on . addStyleName ( pct e m p l a t e btn ) ;

7
8
9
10
11
12
13
14
15

21
22
23
24
25
26
27
28
29
30
32
33
34
35
36
37
38

com .
com .
com .
com .
com .
com .
com .
com .
com .
com .

google
google
google
google
google
google
google
google
google
google

. gwt . e v e n t . dom . c l i e n t . C l i c k E v e n t ;
. gwt . e v e n t . dom . c l i e n t . C l i c k H a n d l e r ;
. gwt . c o r e . c l i e n t . E n t r y P o i n t ;
. gwt . u s e r . c l i e n t . u i . Button ;
. gwt . u s e r . c l i e n t . u i . RootPanel ;
. gwt . u s e r . c l i e n t . u i . V e r t i c a l P a n e l ;
. gwt . u s e r . c l i e n t . u i . TextBox ;
. gwt . u s e r . c l i e n t . u i . L a b e l ;
. gwt . u s e r . c l i e n t . Window ;
. gwt . c o r e . c l i e n t .GWT;

V e r t i c a l P a n e l cmmdcPanel = new V e r t i c a l P a n e l ( ) ;
cmmdcPanel . setWidth ( 100% ) ;
cmmdcPanel . s e t H o r i z o n t a l A l i g n m e n t ( V e r t i c a l P a n e l . ALIGN CENTER ) ;
cmmdcPanel . add ( t i t l e ) ;
cmmdcPanel . add ( mLabel ) ;
cmmdcPanel . add ( mTextBox ) ;
cmmdcPanel . add ( nLabel ) ;

5.5. SERVICIU RESTFUL CU GWT

cmmdcPanel . add ( nTextBox ) ;


MyClickHandler c l i c k H a n d l e r =
new MyClickHandler ( mTextBox , nTextBox , cmmdcLabel ) ;
bu tt on . a d d C l i c k H a n d l e r ( c l i c k H a n d l e r ) ;
cmmdcPanel . add ( b ut to n ) ;
cmmdcPanel . add ( cmmdcLabel ) ;
RootPanel . g e t ( s l o t ) . add ( cmmdcPanel ) ;

39
40
41
42
43
44
45

46
47

49

c l a s s MyClickHandler implements C l i c k H a n d l e r {
TextBox mTextBox=null , nTextBox=n u l l ;
L a b e l cmmdcLabel=n u l l ;

50
51
53
54
55
56
57
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

MyClickHandler ( TextBox mTextBox , TextBox nTextBox , L a b e l cmmdcLabel ) {


t h i s . mTextBox=mTextBox ;
t h i s . nTextBox=nTextBox ;
t h i s . cmmdcLabel=cmmdcLabel ;
}
public void o n C l i c k ( C l i c k E v e n t e v e n t ) {
S t r i n g sm=mTextBox . g e t T e x t ( ) ;
S t r i n g sn=nTextBox . g e t T e x t ( ) ;
long m=0 ,n=0;
i f ( sm . e q u a l s ( ) ) {
Window . a l e r t ( \ m\ i s m i s s i n g ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
i f ( sn . e q u a l s ( ) ) {
Window . a l e r t ( \ n \ i s m i s s i n g ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
m=Long . par se Lon g ( sm ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ m\ i s not a number ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
try {
n=Long . p ars eL ong ( sn ) ;
}
catch ( NumberFormatException e ) {
Window . a l e r t ( \ n \ i s not a number ) ;
cmmdcLabel . s e t T e x t ( ? ) ;
return ;
}
i f ( (m!=0)&&(n ! = 0 ) ) {
CmmdcBean bean=new CmmdcBean ( ) ;
bean . setSm ( sm ) ;
bean . s e t S n ( sn ) ;
D e f a u l t s . s e t S e r v i c e R o o t (GWT. getHostPageBaseURL ( ) ) ;
AsyncClientInterface client =
GWT. c r e a t e ( A s y n c C l i e n t I n t e r f a c e . c l a s s ) ;
c l i e n t . g e t R e s u l t ( bean , new MethodCallback<CmmdcBean>(){
public void o n S u c c e s s ( Method method , CmmdcBean r e s p o n s e ) {

223

224

CAPITOLUL 5. SERVICII JAX-RS

cmmdcLabel . s e t T e x t ( Cmmdc = +r e s p o n s e . g e t R e s u l t ( ) ) ;

98

99

public void o n F a i l u r e ( Method method , Throwable ex ) {


GWT. l o g ( E r r o r , ex ) ;
ex . p r i n t S t a c k T r a c e ( ) ;
Window . a l e r t ( ex . t o S t r i n g ( ) ) ;
}
});

101
102
103
104
105
106

}
else {
long c=Math . max( Math . abs (m) , Math . abs ( n ) ) ;
cmmdcLabel . s e t T e x t ( Cmmdc = +c ) ;
}

107
108
109
110
111

112
113

Codul specific continand implementarea apelului invers este cuprins ntre


liniile 90-112.
Fisierul *.wgt.xml se completeaza cu declaratia pentru RestyGWT
<inherits name="org.fusesource.restygwt.RestyGWT"/>
Fisierul web.xml are codul
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
27
28
29
30

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<webapp 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 a v a e e
h t t p : // j a v a . sun . com/xml/ ns / j a v a e e /weba p p 2 5 . xsd
version= 2 . 5
xmlns= h t t p : // j a v a . sun . com/xml/ ns / j a v a e e >
< s e r v l e t>
<s e r v l e t name>MyApplication</ s e r v l e t name>
<s e r v l e t c l a s s>
org . g l a s s f i s h . j e r s e y . s e r v l e t . ServletContainer
</ s e r v l e t c l a s s>
<i n i t param>
<paramname>
j e r s e y . c o n f i g . s e r v e r . provider . packages
</paramname>
<paramv a l u e>
u n i t b v . c s . td . s e r v e r
</paramv a l u e>
</ i n i t param>
</ s e r v l e t>
<s e r v l e t mapping>
<s e r v l e t name>MyApplication</ s e r v l e t name>
<u r l p a t t e r n>/ xyz /</ u r l p a t t e r n>
</ s e r v l e t mapping>
<welcomef i l e l i s t>
<welcome f i l e >R e s t C l i e n t . html</ welcome f i l e >
</ welcomef i l e l i s t>
</webapp>

5.5. SERVICIU RESTFUL CU GWT

225

Subliniem numele de apel - xyz - este declarat n interfata asincrona, unde


apare si localizatorul serviciului. Merita observat ca numele de apel nu apare
n codul serviciului.

226

CAPITOLUL 5. SERVICII JAX-RS

Partea III
MODELUL OSGi

227

Capitolul 6
Modelul OSGi
OSGi - Open Sourse Gateway initiative, 1999, (semnificatia numelui fiind
astazi depasita) a dezvoltat un model de cadru de lucru (platforma) privind:
gestiunea ciclului de viata a unei aplicatii (application life cycle management);
registru de servicii;
mediu de executie;
module.
Pe aceasta baza au fost dezvoltate interfete de programare (API), servicii,
extensii OSGi (OSGi layers).
Cadrul de lucru contine un model specific de aplicatie sub forma de componenta sau modul OSGi (bundle for deployment). O asemenea componenta
poate pune la dispozitia altor componente functionalitati, comportandu-se ca
un serviciu (ofertant de servicii) sau poate executa o actiune punctuala. O
componenta OSGi se prezinta sub forma unei arhive jar.
In esenta, scopul unui cadru de lucru OSGi este oferirea unui mediu pentru
crearea si integrarea uniforma de unitati (module, componente) de soft.
Un modul este dat de
O interfata de programare (API), pentru rezolvarea unei problemei (optional);
O familie de clase realizate n vederea solutionarii unei probleme;
Multimea resurselor necesare claselor.
229

230

CAPITOLUL 6. MODELUL OSGI

Un modul n tehnologia OSGi se va nregistra ca un serviciu, ntr-un registru


de servicii specific cadrului de lucru.
Crearea unei asemenea serviciu presupune definirea unei interfate si a clasei
(claselor) care o implementeaza, definind doua componente OSGi.
O componenta OSGi se poate instala, lansa n executie, opri, actualiza si
dezinstala.
Cadrul de lucru contine un registru de servicii care permite unei componente OSGi sa sesizeze existenta, aparitia sau disparitia unor servicii.
Interfata de programare OSGi (API) este alcatuit din
Nucleul OSGi (Core Specification)
Extensii OSGi (Compendium Specification):
LogService, ConfigurationAdmin, HttpService
Enterprise OSGi :
RemoteServices, JDBCService, JPAService
Programarea unei aplicatii (serviciu) OSGi se poate face n mod
imperativ prin existenta unei clase ce implementeaza interfata org.osgi.
framework.BundleActivator.
declarativ prin utilizarea unor resurse OSGi suplimentare.

6.1

Cadre de lucru OSGi

Exista mai multe implementari a modelului OSGi:


apache-felix
equinox
Knopflerfish
apache-karaf
Fiecare cadru de lucru ofera un mediu OSGi.

231

6.1. CADRE DE LUCRU OSGI

OSGi prin apache-felix


Instalarea consta n dezarhivarea arhivei descarcate din Internet.
Utilizare. Din catalogul unde s-a instalat apache-felix, mediul se lanseaza
prin
java -jar bin\felix.jar
In catalogul n care s-a instalat apache-felix se va crea un subcatalog felixcache care este folosit de cadrul de lucru.
Comenzile OSGi sunt
Comanda
lb
exit <int>
install file:modulOSGi .jar

Functionalitatea
Afiseaza lista modulelor OSGi instalate.
Paraseste si nchide cadrul de lucru.
Instaleaza modulul OSGi
La instalare unui modul i se atribuie n
vederea identificarii un numar natural id.
start id
Lanseaza modulul OSGi id.
start file: modulOSGi .jar
Instaleaza si lanseaza modulul OSGi
stop id
Opreste modulul OSGi id.
uninstall id
Dezinstaleaza modulul OSGi id.
Interfata de lucru, Apache Felix Gogo, implementeaza RFC (Request for
Comments) 147 publicat de Internet Engineering Task Force (IETF).
Lansarea se poate realiza si dintr-un program Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import j a v a . u t i l . A r r a y L i s t ;
import j a v a . u t i l . HashMap ;
import j a v a . u t i l . L i s t ;
import j a v a . u t i l . Map ;
import j a v a . u t i l . S e r v i c e L o a d e r ;
import o r g . o s g i . framework . Bundle ;
import o r g . o s g i . framework . BundleContext ;
import o r g . o s g i . framework . B u n d l e E x c e p t i o n ;
import o r g . o s g i . framework . l a u n c h . Framework ;
import o r g . o s g i . framework . l a u n c h . FrameworkFactory ;
public c l a s s Launcher {
public s t a t i c void main ( S t r i n g a r g s [ ] ) throws B u n d l e E x c e p t i o n {
FrameworkFactory frameworkFactory =
S e r v i c e L o a d e r . l o a d ( FrameworkFactory . c l a s s ) . i t e r a t o r ( ) . n e x t ( ) ;
Map<S t r i n g , S t r i n g > c o n f i g = new HashMap< >();
Framework framework = frameworkFactory . newFramework ( c o n f i g ) ;
framework . s t a r t ( ) ;
BundleContext c o n t e x t = framework . g e t B u n d l e C o n t e x t ( ) ;
L i s t <Bundle> b u n d l e s = new A r r a y L i s t < >();
b u n d l e s . add ( c o n t e x t . i n s t a l l B u n d l e (
f i l e : l i b / o r g . apache . f e l i x . gogo . command 0 . 1 4 . 0 . j a r ) ) ;
b u n d l e s . add ( c o n t e x t . i n s t a l l B u n d l e (
f i l e : l i b / o r g . apache . f e l i x . gogo . runtime 0 . 1 2 . 1 . j a r ) ) ;

232

b u n d l e s . add ( c o n t e x t . i n s t a l l B u n d l e (
f i l e : l i b / o r g . apache . f e l i x . gogo . s h e l l 0 . 1 0 . 0 . j a r ) ) ;
f o r ( Bundle bu nd le : b u n d l e s ) {
bu nd l e . s t a r t ( ) ;
}

24
25
26
27
28

29
30

CAPITOLUL 6. MODELUL OSGI

OSGi prin Equinox


Instalare. Dintr-o distributie Eclipse, se copiaza n catalogul propriu
fisierul org.eclipse.osgi *.jar, schimband numele n equinox.jar. Alternativ,
fisierul mentionat mai sus se poate descarca de la http://download.eclipse.org/eclipse/
equinox.
Utilizare. Equinox a adoptat interfata Apache Felix Gogo. In vederea
lansarii se va crea structura
equinox
|--> configuration
|
|
config.ini
|
org.eclipse.equinox.console_*.jar
|
org.apache.felix.gogo.runtime_*.jar
|
org.apache.felix.gogo.shell_*.jar
|
org.apache.felix.gogo.command_*.jar
|
equinox.jar

unde config.ini are codul


1
2
3
4

o s g i . b u n d l e s= f i l e \ : o r g . e c l i p s e . e q u i n o x . c o n s o l e . j a r @ s t a r t ,
f i l e : \ o r g . apache . f e l i x . gogo . r u n t i m e . j a r @ s t a r t ,
f i l e : \ o r g . apache . f e l i x . gogo . s h e l l . j a r @ s t a r t ,
f i l e : \ o r g . apache . f e l i x . gogo . command . j a r @ s t a r t

Lansarea se obtine prin


java -jar equinox.jar -console
aparand prompt-ul osgi>.
Comenzile sunt cele utilizate n apache-felix.
In plus se pot utiliza si comenzile
Comanda Functionalitatea
ss
short status Afiseaza lista modulelor
OSGi instalate.
exit
Paraseste si nchide cadrul de lucru.
Cadrul de lucru foloseste subcatalogul configuration.

- CREAREA UNUI MODUL OSGI


6.2. PROGRAMARE IMPERATIVA

233

OSGi prin knopflerfish


Instalarea consta n dezarhivarea arhivei descarcate din Internet, reprezentat de un fisier jar executabil.
Utilizare. Din catalogul . . . \knopflerfish osgi *.*.*\osgi se lanseaza java
-jar framework.jar. Toate comenzile de operare sunt lansate dintr-o interfata
grafica.

6.2

Programare imperativ
a - Crearea unui modul
OSGi

Un modul sau componenta OSGi (bundle) se poate afla n starile UNINSTALLED,


INSTALLED, RESOLVED, STARTING, STOPPING, ACTIVE, constante definite de
interfata org.osgi.framework.Bundle. Doar cadrul de lucru OSGi poate
instantia o componenta OSGi.
O componenta OSGi este compusa din

1. O clasa ce implementeaza interfata BundleActivator.


Interfata BundleActivator declara metodele

public void start(BundleContext ctx )


Activitati executate la lansarea modulului OSGi.
public void stop(BundleContext ctx )
Activitati executate la oprirea modulului OSGi.

Daca se defineste un modul interfata atunci aceasta clasa lipseste.

2. Un fisier text manifest.mf de proprietati (nume: valoare) ale modulului


OSGi, cu extensia mf. Acest fisier trebuie sa se termine cu o linie vida.

234

CAPITOLUL 6. MODELUL OSGI

Proprietati OSGi
Numele proprietatii
Bundle-Name
Bundle-Version
Bundle-Activator

Semnificatia
Numele modului OSGi
Versiunea modulului OSGi
Clasa modulului care implementeaza interfata
BundleActivator
Bundle-SymbolicName
Numele simbolic atribuit modulului OSGi
Bundle-Description
Descrierea modulului OSGi
Manifest-Version
Versiunea tipului de manifest
Bundle-ManifestVersion Versiunea manifestului atasat modulului OSGi
Bundle-Vendor
Producatorul modulului OSGi
Bundle-Classpath
Calea catre resursele suplimentare utilizate
Import-Package
Lista pachetelor utilizate de modulul OSGi
Export-Package
Lista pachetelor ce pot fi utilizate de alte
module OSGi
Structura arhivei jar a unei componente OSGi este
structura de cataloage corespunzatoare pachetului aplicatiei
| . . .
*.class
META-INF
| manifest.mf
Programarea se bazeaza pe interfata BundleContext, care este implementat de fiecare cadru de lucru OSGi n parte.
Metode
ServiceRegistration registerService(String clazz, Object service,
java.util.Dictionary properties)
Inregistreaza n cadrul de lucru serviciul definit de obiectul service, de tip
clazz si cu proprietaile adiacente date de al treilea parametru. Rezultatul
este folosit de cadrul de lucru OSGi.
ServiceReference[] getServiceReferences(String clazz, String filter ) throws InvalidSyntaxException
Returneaza referintele de tip clazz.
Object getService(ServiceReference reference)
Returneaza obiectul corespunzator referintei.

235

6.3. EXEMPLE

6.3

Exemple

Exemplul 6.3.1 Calculul celui mai mare divizor comun a doua numere naturale - ca serviciu OSGi.
Aplicatia se compune din 3 module OSGi:
interfata;
1. Clasa interfetei cmmdc.ICmmdc.java
1

package cmmdc ;

public i n t e r f a c e ICmmdc{
public long cmmdc( long m, long n ) ;
}

4
5

2. Fisierul manifest.mf
1
2
3
4
5

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName : icmmdc
BundleName : I n t e r f a t a Cmmdc
BundleV e r s i o n : 1 . 0 . 0
ExportPackage : cmmdc ; v e r s i o n= 1 . 0 . 0

serviciu care implementeaza interfata;


1. Clasa cmmdc.service.Activator implementeaza interfata
BundleActivator. In metoda start, se nregistreaza o instanta a
clasei ce implementeaza interfata ca serviciu a cadrului OSGi.
1
2
3
4
6
7
8
9
10
11

package cmmdc . s e r v i c e ;
import cmmdc . ICmmdc ;
import o r g . o s g i . framework . B u n d l e A c t i v a t o r ;
import o r g . o s g i . framework . BundleContext ;
public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {
public void s t a r t ( BundleContext c o n t e x t ) {
c o n t e x t . r e g i s t e r S e r v i c e (ICmmdc . c l a s s . getName ( ) ,
new CmmdcService ( ) , n u l l ) ;
System . out . p r i n t l n ( R e g i s t e r i n g Cmmdc s e r v i c e . ) ;
}
public void s t o p ( BundleContext c o n t e x t ) {}

13
14

2. Clasa cmmdc.service.CmmdcService implementeaza interfata ICmmdc

236

CAPITOLUL 6. MODELUL OSGI

package cmmdc . s e r v i c e ;

public c l a s s CmmdcService implements cmmdc . ICmmdc{


public long cmmdc( long m, long n ) { . . . }
}

4
5

3. Fisierul manifest.mf
1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName : cmmdcservice
BundleName : Cmmdc S e r v i c e
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : cmmdc . s e r v i c e . A c t i v a t o r
ImportPackage : o r g . o s g i . framework , cmmdc

client care utilizeaza interfata.


Prezentam doua variante de modul OSGi client.
1. Referinta obiectului serviciu se obtine prin intermediul obiectului
context:BundleContext.
(a) Clasa care implementeaza interfata BundleActivator este cmmdc.client.Activator.java. In metoda start, prin context se
obtine o referinta la serviciul care implementeaza interfata ICmmdc, apoi se foloseste functionalitatea obtinuta - apeland metoda
cmmdc.
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package cmmdc . c l i e n t ;
import cmmdc . ICmmdc ;
import j a v a . u t i l . S c a n n e r ;
import o r g . o s g i . framework . B u n d l e A c t i v a t o r ;
import o r g . o s g i . framework . BundleContext ;
import o r g . o s g i . framework . S e r v i c e R e f e r e n c e ;
public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {
public void s t a r t ( BundleContext c o n t e x t ) {
try {
S e r v i c e R e f e r e n c e [ ] r e f s=
c o n t e x t . g e t S e r v i c e R e f e r e n c e s (ICmmdc . c l a s s . getName ( ) ,
null ) ;
i f ( r e f s != n u l l ) {
ICmmdc o b j =(ICmmdc) c o n t e x t . g e t S e r v i c e ( r e f s [ 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 ( C l i e n t Cmmdc 1 ) ;
System . out . p r i n t l n ( Primul numar : ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( a l d o i l e a numar : ) ;
long n=s c a n n e r . nextLong ( ) ;
long c=o b j . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc = +c ) ;
}
}

237

6.3. EXEMPLE

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

26
27
28

29

public void s t o p ( BundleContext c o n t e x t ) {}

31
32

(b) Fisierul manifest.mf


1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName : clientcmmdc1
BundleName : Cmmdc C l i e n t
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : cmmdc . c l i e n t . A c t i v a t o r
ImportPackage : o r g . o s g i . framework , cmmdc

2. Referinta obiectului serviciu se obtine prin intermediul unui obiect


de tip ServiceTracker, clasa introdusa pentru simplificarea lucrului cu componente OSGi.
Constructor
public ServiceTracker(BundleContext context, String clazz,
ServiceTrackerCustomizer customizer )
Metode
public void open()
public Object getService()
(a) Clasa care implementeaza interfata BundleActivator este cmmdc.client.Activator.java. In metoda start, se creaza o instanta
de tip ServiceTracker corespunzatoare serviciului generat de
interfata ICmmdc, care este pornita prin metoda open si n final se obtine o referinta a serviciului, adica o instanta a clasei
care implementeaza interfata ICmmdc.
1
2
3
4
5
6
8
9
10
11
12
13
14
15

package cmmdc . c l i e n t ;
import cmmdc . ICmmdc ;
import j a v a . u t i l . S c a n n e r ;
import o r g . o s g i . framework . B u n d l e A c t i v a t o r ;
import o r g . o s g i . framework . BundleContext ;
import o r g . o s g i . u t i l . t r a c k e r . S e r v i c e T r a c k e r ;
public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {
public void s t a r t ( BundleContext c o n t e x t ) {
S e r v i c e T r a c k e r s e r v i c e T r a c k e r=new S e r v i c e T r a c k e r ( c o n t e x t ,
ICmmdc . c l a s s . getName ( ) , n u l l ) ;
s e r v i c e T r a c k e r . open ( ) ;
ICmmdc o b j =(ICmmdc) s e r v i c e T r a c k e r . g e t S e r v i c e ( ) ;
System . out . p r i n t l n ( C l i e n t Cmmdc 2 ) ;
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 ) ;

238

CAPITOLUL 6. MODELUL OSGI

System . out . p r i n t l n ( Primul numar : ) ;


long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( a l d o i l e a numar : ) ;
long n=s c a n n e r . nextLong ( ) ;
long c=o b j . cmmdc(m, n ) ;
System . out . p r i n t l n ( Cmmdc = +c ) ;

16
17
18
19
20
21

22

public void s t o p ( BundleContext c o n t e x t ) {}

24
25

(b) Fisierul manifest.mf


1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName : clientcmmdc2
BundleName : Cmmdc C l i e n t
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : cmmdc . c l i e n t . A c t i v a t o r
ImportPackage : o r g . o s g i . framework , o r g . o s g i . u t i l . t r a c k e r , cmmdc

Sa presupunem ca s-au generat cele module OSGi sub forma


interfata
cmmdc.jar
serviciul (implementarea interfetei) cmmdcservice.jar
client
client1cmmdc.jar
Executia n mediul apache-felix consta din
start file:d:/. . ./icmmdc.jar
start file:d:/. . ./cmmdcservice.jar
start file:d:/. . ./clientcmmdc1.jar

6.4

Dezvoltare OSGi prin apache-maven

Codurile claselor Java raman nemodificate, iar fisierele manifest.mf vor fi


generate de maven, dar continutul lor va trebui specificat n fisierele pom.xml.
Exemplificam cu aplicatia de calcul a celui mai mare divizor comn, dezvoltata n capitolul OSGi.
Intr-un catalog, de exemplu - cmmdc, se genereaza trei module maven
mvn archetype:generate -B
-DgroupId=%GroupID%
-DartifactId=%ArtifactID%
-DarchetypeArtifactId=maven-archetype-quickstart
-Dversion=%Version%

respectiv cu datele
set GroupID=cmmdc
set ArtifactID=interface
set Version=1.0.0

6.4. DEZVOLTARE OSGI PRIN APACHE-MAVEN

239

set GroupID=cmmdc.service
set ArtifactID=impl
set Version=1.0.0
set GroupID=cmmdc.client
set ArtifactID=client
set Version=1.0.0

In cataloagele generate clasa App.java se nlocuieste cu clasele aplicatiei,


dupa cum urmeaza
Catalog Clase
interface ICmmdc.java
impl
CmmdcService.java
Activator.java
client
Activator.java
iar fisiere pom.xml cu cele reproduse mai jos.
Fisierul pom.xml din catalogul interface
1
2
3
4
5
7
8
9
10
12
13
15
16
17
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<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 / xsd /maven 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>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 . 0</ version>
<p a c k a g i n g>b un dl e</ p a c k a g i n g>
<name> i n t e r f a c e</name>
<u r l>h t t p : //maven . apache . o r g</ u r l>
<p r o p e r t i e s>
<p r o j e c t . b u i l d . s o u r c e E n c o d i n g>UTF8</ p r o j e c t . b u i l d . s o u r c e E n c o d i n g>
</ p r o p e r t i e s>
<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>o r g . o s g i</ g r o u p I d>
< a r t i f a c t I d>o r g . o s g i . c o r e</ a r t i f a c t I d>
<version> 4 . 3 . 0</ 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 . f e l i x</ g r o u p I d>
< a r t i f a c t I d>mavenbundlep l u g i n</ a r t i f a c t I d>
<version> 3 . 0 . 1</ version>

240

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

CAPITOLUL 6. MODELUL OSGI

<e x t e n s i o n s>t r u e</ e x t e n s i o n s>


<c o n f i g u r a t i o n>
< i n s t r u c t i o n s>
<BundleSymbolicName>
${ p r o j e c t . a r t i f a c t I d }
</ BundleSymbolicName>
<ExportPackage>
cmmdc
</ ExportPackage>
</ i n s t r u c t i o n s>
</ 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>

Fisierul pom.xml din catalogul impl


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

<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 / xsd /maven 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>cmmdc</ g r o u p I d>
< a r t i f a c t I d>cmmdcservice</ a r t i f a c t I d>
<version> 1 . 0 . 0</ version>
<p a c k a g i n g>b un dl e</ p a c k a g i n g>
<name>impl</name>
<u r l>h t t p : //maven . apache . o r g</ u r l>
<p r o p e r t i e s>
<p r o j e c t . b u i l d . s o u r c e E n c o d i n g>UTF8</ p r o j e c t . b u i l d . s o u r c e E n c o d i n g>
<path> . . . / cmmdc</ path>
</ p r o p e r t i e s>
<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>o r g . o s g i</ g r o u p I d>
< a r t i f a c t I d>o r g . o s g i . c o r e</ a r t i f a c t I d>
<version> 4 . 3 . 0</ version>
</ dependency>
<dependency>
<g r o u p I d>icmmdc 1 . 0 . 0</ g r o u p I d>
< a r t i f a c t I d>cmmdc . icmmdc</ a r t i f a c t I d>
<version> 1 . 0 . 0</ version>
<s c o p e>system</ s c o p e>
<systemPath>${ path }/ i n t e r f a c e / t a r g e t /icmmdc 1 . 0 . 0 . j a r</ systemPath>
</ 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>

6.4. DEZVOLTARE OSGI PRIN APACHE-MAVEN

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

<p l u g i n>
<g r o u p I d>o r g . apache . f e l i x</ g r o u p I d>
< a r t i f a c t I d>mavenbundlep l u g i n</ a r t i f a c t I d>
<version> 3 . 0 . 1</ version>
<e x t e n s i o n s>t r u e</ e x t e n s i o n s>
<c o n f i g u r a t i o n>
< i n s t r u c t i o n s>
<BundleSymbolicName>
${ p r o j e c t . a r t i f a c t I d }
</ BundleSymbolicName>
<ImportPackage>
o r g . o s g i . framework , cmmdc ,
</ ImportPackage>
<BundleA c t i v a t o r>cmmdc . s e r v i c e . A c t i v a t o r</ BundleA c t i v a t o r>
<ExportPackage />
</ i n s t r u c t i o n s>
</ 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>

Fisierul pom.xml din catalogul client


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

<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 / xsd /maven 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>cmmdc</ g r o u p I d>
< a r t i f a c t I d>clientcmmdc</ a r t i f a c t I d>
<version> 1 . 0 . 0</ version>
<p a c k a g i n g>b un dl e</ p a c k a g i n g>
<name> c l i e n t</name>
<u r l>h t t p : //maven . apache . o r g</ u r l>
<p r o p e r t i e s>
<p r o j e c t . b u i l d . s o u r c e E n c o d i n g>UTF8</ p r o j e c t . b u i l d . s o u r c e E n c o d i n g>
<path> . . . / cmmdc</ path>
</ p r o p e r t i e s>
<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>o r g . o s g i</ g r o u p I d>
< a r t i f a c t I d>o r g . o s g i . c o r e</ a r t i f a c t I d>
<version> 4 . 3 . 0</ version>
</ dependency>
<dependency>
<g r o u p I d>icmmdc 1 . 0 . 0</ g r o u p I d>
< a r t i f a c t I d>cmmdc . icmmdc</ a r t i f a c t I d>
<version> 1 . 0 . 0</ version>

241

242

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

CAPITOLUL 6. MODELUL OSGI

<s c o p e>system</ s c o p e>


<systemPath>${ path }/ i n t e r f a c e / t a r g e t /icmmdc 1 . 0 . 0 . j a r</ systemPath>
</ 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 . f e l i x</ g r o u p I d>
< a r t i f a c t I d>mavenbundlep l u g i n</ a r t i f a c t I d>
<version> 3 . 0 . 1</ version>
<e x t e n s i o n s>t r u e</ e x t e n s i o n s>
<c o n f i g u r a t i o n>
< i n s t r u c t i o n s>
<BundleSymbolicName>
${ p r o j e c t . a r t i f a c t I d }
</ BundleSymbolicName>
<ImportPackage>
o r g . o s g i . framework , cmmdc ,
</ ImportPackage>
<BundleA c t i v a t o r>cmmdc . c l i e n t . A c t i v a t o r</ BundleA c t i v a t o r>
<ExportPackage />
</ i n s t r u c t i o n s>
</ 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>

In catalogul aplicatiei se introduce fisierul pom.xml


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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<p r o j e c t>
<m o d e l V e r s i o n> 4 . 0 . 0</ m o d e l V e r s i o n>
< a r t i f a c t I d>cmmdc</ a r t i f a c t I d>
<g r o u p I d>cmmdc</ g r o u p I d>
<version> 1 . 0 . 0</ version>
<name>Si m pl e cmmdc</name>
<p a c k a g i n g>pom</ p a c k a g i n g>
<modules>
<module> i n t e r f a c e</ module>
<module>impl</ module>
<module> c l i e n t</ module>
</ modules>
</ p r o j e c t>

si se lanseaza comanda maven mvn clean package, n urma careia se creaza


componentele OSGi ale aplicatiei.

6.5

Programare declarativ
a

Modelul declarativ de realizare a unui modul OSGi nu mai necesita realizarea unei clase care sa implementeze interfata BundleActivator. Prezenta
fisierului manifest.mf ramane obligatorie. Exista mai multe variante dezvoltate de programare declarativa:

243

6.5. PROGRAMARE DECLARATIVA

Declarative Service
Blueprint
iPOJO

6.5.1

Programare declarativ
a prin Declarative Service

Modelul de programare este functional pe platformele apache-felix si equinox,


dar resursele suplimentare necesare a fi instalate sunt diferite.
Cadrul OSGi
felix
equinox

Componenta OSGi (*.jar)


org.osgi.compendium-4.*.*.jar
org.apache.felix.scr-*.jar
org.eclipse.osgi.services 3.*.*.v*.jar
org.eclipse.equinox.util *.jar
org.eclipse.equinox.ds *.jar

Cu exceptia interfetelor, programatorul trebuie sa editeze un fisier de configurare OSGI-INF\component.xml, care se include n arhiva jar a componentei OSGi. Acest fisierul de configurare este mentionat n fisierul manifest.mf
prin linia
Service-Component:

OSGI-INF/component.xml

Astfel arhiva modulului OSGi are structura


structura de cataloage corespunzatoare pachetului aplicatiei
| . . .
*.class
META-INF
|
manifest.mf
OSGI-INF
|
component.xml
Un serviciu programat prin modelul declarativ se poate apela de catre un
client programat prin modelul imperativ, dar se poate programa si un modul
OSGi client prin model declarativ.
Exemplul 6.5.1 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatia este alcatuita din cele trei componente:

244

CAPITOLUL 6. MODELUL OSGI

interfata
1.
1

package cmmdc ;

public i n t e r f a c e ICmmdc{
public long cmmdc( long m, long n ) ;
}

4
5

2. manifest.mf
1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName: icmmdc
BundleName: I n t e r f a t a Cmmdc
BundleVendor: u n i t b v
BundleV e r s i o n : 1 . 0 . 0
ExportP a c k a g e : cmmdc ; v e r s i o n= 1 . 0 . 0

clasa serviciului OSGi, care implementeaza interfata


1.
1

package cmmdc . s e r v i c e ;

public c l a s s CmmdcService implements cmmdc . ICmmdc{


public long cmmdc( long m, long n ) { . . . }
}

4
5

2. manifest.mf
1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName: cmmdcservice
BundleName: Cmmdc S e r v i c e
BundleV e r s i o n : 1 . 0 . 0
ImportP a c k a g e : cmmdc
S e r v i c e Component: OSGIINF/ component . xml

3. component.xml
1
2
3
4
5
6
7
8

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<s c r : c o m p o n e n t x m l n s : s c r= h t t p : //www. o s g i . o r g / xmlns / s c r / v1 . 1 . 0
name=DS S e r v i c e Sample >
<i m p l e m e n t a t i o n c l a s s=cmmdc . s e r v i c e . CmmdcService />
< s e r v i c e>
<p r o v i d e i n t e r f a c e=cmmdc . ICmmdc />
</ s e r v i c e>
</ s c r : c o m p o n e n t>

Client declarativ
Pentru compilarea aplicatiei client este nevoie de osgi R4 compendium-*.jar.
1.
1
2
3

package cmmdc . c l i e n t ;
import j a v a . u t i l . S c a n n e r ;
import cmmdc . ICmmdc ;


6.5. PROGRAMARE DECLARATIVA

5
6

public c l a s s CmmdcClient {
private ICmmdc s e r v i c e ;
public void b i n d M y S e r v i c e (ICmmdc a ) {
System . out . p r i n t l n ( S e r v i c e was s e t ) ;
service = a ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( m= ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( n= ) ;
long n=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Cmmdc = +s e r v i c e . cmmdc(m, n ) ) ;
}

8
9
10
11
12
13
14
15
16
17

public void unbindMyService (ICmmdc a ) {


i f ( s e r v i c e==a )
s e r v i c e = null ;
System . out . p r i n t l n ( S e r v i c e was u n s e t ) ;
}

19
20
21
22
23
24

2. manifest.mf
1
2
3
4
5
6
7
8

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName: c l i e n t d s
S e r v i c e Component: OSGIINF/ component . xml
P r i v a t e P a c k a g e : cmmdc . c l i e n t
BundleName: D e c l a r a t i v e S e r v i c e Cmmdc C l i e n t
BundleD e s c r i p t i o n : DS Cmmdc C l i e n t
BundleV e r s i o n : 1 . 0 . 0
ImportP a c k a g e : cmmdc

3. component.xml
1
2
3
4
5
6
7
8
9

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<s c r : c o m p o n e n t x m l n s : s c r= h t t p : //www. o s g i . o r g / xmlns / s c r / v1 . 1 . 0
name=DS C l i e n t >
<i m p l e m e n t a t i o n c l a s s=cmmdc . c l i e n t . CmmdcClient />
< r e f e r e n c e i n t e r f a c e=cmmdc . ICmmdc
name=ICmmdc c a r d i n a l i t y= 1 . . 1 p o l i c y= s t a t i c
bind= b i n d M y S e r v i c e
unbind= unbindMyService />
</ s c r : c o m p o n e n t>

Sunt declarate metodele care


consuma serviciul (bind=...);
disponibilizeaza serviciul injectat (unbind=...).

245

246

CAPITOLUL 6. MODELUL OSGI

6.5.2

Programare declarativ
a prin Blueprint

Modelul de programare este functional pe platformele apache-felix si equinox.


Implementarea de referinta este data n proiectul apache-aries.
Cadrul OSGi
felix & equinox

Componenta OSGi (*.jar)


org.apache.felix.configadmin-*.jar
pax-logging-api-*.jar
pax-logging-service-*.jar
org.apache.aries.blueprint-*.jar
org.apache.aries.proxy-*.jar
Toate partile unei aplicatii (interfete, implementarile lor, clientii) trebuie
sa faca parte din aceasi componenta OSGi. Un client este reprezentat de doua
clase:
Inregistratorul (listener );
Mediul OSGi asigura serviciul, adica un obiect care implementeaza interfata aplicatiei. Trebuie programate doua metode, una n care se utilizeaza serviciul (uzual se apeleaza un clientul propriu-zis) si a doua n
care se disponibilizeaza serviciul. Cele doua metode sunt precizate n
fisierul de configurare OSGI-INF\blueprint\config.xml.
Clientul propriu-zis.
Serviciile nregistrate pot fi apelate si de un client programat imperativ.
In afara fisierului manifest.mf mai este necesar fisierul de configurare
OSGI-INF\blueprint\config.xml.
Astfel arhiva modulului OSGi are structura
structura de cataloage corespunzatoare pachetului aplicatiei
| . . .
*.class
META-INF
|
manifest.mf
OSGI-INF
|--> blueprint
|
|
config.xml
Exemplul 6.5.2 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatia va contine:


6.5. PROGRAMARE DECLARATIVA

247

Clasele cmmdc.ICmmdc si cmmdc.service.CmmdcService amintite anterior.


Clasa listener cmmdc.client.RegistrationListener
1
2
3
4
6
7
8
9

package cmmdc . c l i e n t ;
import j a v a . u t i l . Map ;
import j a v a . u t i l . S c a n n e r ;
import cmmdc . ICmmdc ;
public c l a s s R e g i s t r a t i o n L i s t e n e r {
public void r e g i s t e r (ICmmdc obj , Map p r o p e r t i e s ) {
VisualCmmdcClient myApp=new VisualCmmdcClient ( o b j ) ;
}
public void u n r e g i s t e r (ICmmdc obj , Map p r o p e r t i e s ) {
System . out . p r i n t l n ( Cmmmdc s e r v i c e u n r e g i s t e r e d ) ;
}

11
12
13
14

Clasa VisualCmmdcClient este un client cu interfataa grafica. (Se va utiliza setDefaultCloseOperation(javax.swing.WindowConstants.HIDE


ON CLOSE).)
manifest.mf
1
2
3
4
5
6
7
8
9

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName: b l u e p r i n t
BundleName: B l u e p r i n t Cmmdc C l i e n t
BundleD e s c r i p t i o n : B l u e p r i n t Cmmdc App
BundleV e r s i o n : 1 . 0 . 0
ImportP a c k a g e : o r g . o s g i . framework , j a v a x . swing ,
o r g . o s g i . s e r v i c e . b l u e p r i n t ; v e r s i o n= [ 1 . 0 . 0 , 2 . 0 . 0 )
ExportP a c k a g e : cmmdc , b l u e p r i n t ;
u s e s := o r g . o s g i . framework ; v e r s i o n= 1 . 0 . 0 . SNAPSHOT

OSGI-INF\blueprint\config.xml
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<b l u e p r i n t xmlns= h t t p : //www. o s g i . o r g / xmlns / b l u e p r i n t / v1 . 0 . 0 >
<bean i d=cmmdc
c l a s s=cmmdc . s e r v i c e . CmmdcService s c o p e= p r o t o t y p e />
< s e r v i c e i d= s e r v i c e C l i e n t r e f=cmmdc>
< i n t e r f a c e s>
<v a l u e>cmmdc . ICmmdc</ v a l u e>
</ i n t e r f a c e s>
< r e g i s t r a t i o n l i s t e n e r
r e g i s t r a t i o n method= r e g i s t e r
u n r e g i s t r a t i o n method= u n r e g i s t e r >
<bean c l a s s=cmmdc . c l i e n t . R e g i s t r a t i o n L i s t e n e r />
</ r e g i s t r a t i o n l i s t e n e r>
</ s e r v i c e>
</ b l u e p r i n t>

248

CAPITOLUL 6. MODELUL OSGI

6.5.3

Programare declarativ
a prin apache-iPOJO

Acest model este functional pe platforma OSGi apache felix. In etapa de


dezvoltare continutul fisierului manifest.mf este extins cu date dintr-un alt
fisier metadata.xml - aspectul declarativ al modelului de programare. Datele
acestui fisier definesc componenta OSGi care se nregistreaza pe platforma
OSGi data de apache-felix.
Completarea fisierului manifest.mf se face automat, cu instrumente specifice apache-ant sau apache-maven.
Exemplul 6.5.3 Calculul celui mai mare divizor comun a doua numere naturale.
Aplicatia este alcatuita din cele trei componente:
interfata
1

package cmmdc ;

public i n t e r f a c e ICmmdc{
public long cmmdc( long m, long n ) ;
}

4
5

clasa serviciului OSGi, care implementeaza interfata


1

package cmmdc . s e r v i c e ;

public c l a s s CmmdcService implements cmmdc . ICmmdc{


public long cmmdc( long m, long n ) { . . . }
}

4
5

metadata.xml
1
2
3
4
5
6
8
9
10
12
13

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<i p o j o
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= o r g . apache . f e l i x . i p o j o
h t t p : // f e l i x . apache . o r g / i p o j o / schemas /CURRENT/ c o r e . xsd
xmlns= o r g . apache . f e l i x . i p o j o >
<component c l a s s n a m e=cmmdc . s e r v i c e . CmmdcService name= CmmdcProvider >
<p r o v i d e s />
</ component>
<i n s t a n c e component= CmmdcProvider name= CmmdcService />
</ i p o j o>

client OSGi

249

6.5. PROGRAMARE DECLARATIVA

package cmmdc . c l i e n t ;
import cmmdc . ICmmdc ;

public c l a s s CmmdcClient implements Runnable {

/
I n t a r z i e r e i n t r e doua a p e l a r i automate
/
private s t a t i c f i n a l i n t DELAY = 1 0 0 0 0 ;

7
8
9

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

/
Reprezentant a l s e r v i c i u l u i
/
private ICmmdc m cmmdc ;

i n j e c t a t de iPOJO

/
Indicator pentru d e p i s ta r e a s t a r s i t u l u i
/
private boolean m end ;
/
Argumente p e n t r u m e t o d e l e i n v o c a t e
i n j e c t a t e de c o n t a i n e r u l OSGi
/
private S t r i n g sm ;
private S t r i n g sn ;
/
Metoda run ( j a v a . l a n g . Runnable )
/
public void run ( ) {
while ( ! m end ) {
try {
invokeCmmdcServices ( ) ;
Thread . s l e e p (DELAY) ;
} catch ( I n t e r r u p t e d E x c e p t i o n i e ) {
/ s e v e r i f i c a c o n d i t i a de s f a r s i t /
}
}
}
/
Invocarea s e r v i c i u l u i
/
public void invokeCmmdcServices ( ) {
i n t i =0;
long m=Long . par se Lo ng ( sm ) ;
long n=Long . p ars eL ong ( sn ) ;
System . out . p r i n t l n (m cmmdc . cmmdc(m, n ) ) ;
m end=true ;
}
/
Start
/
public void s t a r t i n g ( ) {
Thread t h r e a d = new Thread ( t h i s ) ;

250

CAPITOLUL 6. MODELUL OSGI

m end = f a l s e ;
thread . s t a r t ( ) ;

59
60
61

63

/
Stop
/
public void s t o p p i n g ( ) {
m end = true ;
}

64
65
66
67
68
69

metadata.xml
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
18
19
20
21
22

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<i p o j o
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= o r g . apache . f e l i x . i p o j o
h t t p : // f e l i x . apache . o r g / i p o j o / schemas /CURRENT/ c o r e . xsd
xmlns= o r g . apache . f e l i x . i p o j o >
<component c l a s s n a m e=cmmdc . c l i e n t . CmmdcClient >
<r e q u i r e s f i e l d =m cmmdc />
<c a l l b a c k t r a n s i t i o n= v a l i d a t e method= s t a r t i n g />
<c a l l b a c k t r a n s i t i o n= i n v a l i d a t e method= s t o p p i n g />
<p r o p e r t i e s>
<p r o p e r t y f i e l d =sm name=sm />
<p r o p e r t y f i e l d = sn name= sn />
</ p r o p e r t i e s>
</ component>
<i n s t a n c e component=cmmdc . c l i e n t . CmmdcClient >
<p r o p e r t y name=sm v a l u e= 56 />
<p r o p e r t y name= sn v a l u e= 42 />
</ i n s t a n c e>
</ i p o j o>

Executia consta din instalarea si lansarea componentelor


start file:. . ./org.apache.felix.ipojo-*.jar
start file:. . ./org.apache.felix.shell-*.jar
start file:. . ./org.apache.felix.ipojo.arch-*.jar
start file:. . ./icmmdc.jar
start file:. . ./cmmdcservice.jar
start file:. . ./clientcmmdc.jar

6.6

Serviciul OSGi de jurnalizare

Interfata de programare (API) OSGi contine pentru jurnalizare o serie de


interfete a caror implementare ofera servicii de jurnalizare.
In cazul mediului apache-felix serviciile de jurnalizare trebuie instalate,
resursa fiind
org.apache.felix.log-*.jar

6.6. SERVICIUL OSGI DE JURNALIZARE

251

Interfata org.osgi.service.log.LogService
Clasa care implementeaza aceasta interfata asigura jurnalizarea. Mesajele
sunt retinute de mediul OSGi.
Sunt declarate nivelele LogService.LOG ERROR, LogService.LOG WARNING,
LogService.LOG INFO, LogService.LOG DEBUG.
Metode
void log(int level, String message)
Interfata org.osgi.service.log.LogReaderService
Are ca scop preluarea mesajelor de jurnalizare. Uzual aceste mesaje sunt
prelucrate de un ascultator, un obiect care implementeaza interfata LogListener
Metode
void addLogListener(LogListener listener )
Interfata org.osgi.service.log.LogListener
Metode
void logged(LogEntry entry)
Instalarea tuturor serviciilor se obtine cu o componenta OSGi avand activatorul

import
import
import
import
import
import
import

public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {

1
2
3
4
5
6

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

org .
org .
org .
org .
org .
org .
org .

osgi
osgi
osgi
osgi
osgi
osgi
osgi

. framework . B u n d l e A c t i v a t o r ;
. framework . BundleContext ;
. framework . S e r v i c e R e f e r e n c e ;
. s e r v i c e . log . LogService ;
. s e r v i c e . log . LogReaderService ;
. s e r v i c e . log . LogListener ;
. s e r v i c e . l o g . LogEntry ;

public void s t a r t ( BundleContext c o n t e x t ) throws E x c e p t i o n {


ServiceReference ref =
c o n t e x t . g e t S e r v i c e R e f e r e n c e ( L o g S e r v i c e . c l a s s . getName ( ) ) ;
L o g S e r v i c e l o g S e r v i c e=n u l l ;
i f ( r e f != n u l l ) {
logService = ( LogService ) context . getService ( r e f ) ;
}
r e f = c o n t e x t . g e t S e r v i c e R e f e r e n c e ( L o g R e a d e r S e r v i c e . c l a s s . getName ( ) ) ;
i f ( r e f != n u l l ) {
LogReaderService reader = ( LogReaderService ) context . g e t S e r v i c e ( r e f ) ;
r e a d e r . a d d L o g L i s t e n e r (new LogWriter ( ) ) ;
}
l o g S e r v i c e . l o g ( L o g S e r v i c e . LOG INFO , P o r n i r e a s e r v i c i u l u i de j u r n a l i z a r e ) ;
}

252

CAPITOLUL 6. MODELUL OSGI

26

public void s t o p ( BundleContext c o n t e x t ) throws E x c e p t i o n {}

28

c l a s s LogWriter implements L o g L i s t e n e r {
public void l o g g e d ( LogEntry e n t r y ) {
System . out . p r i n t l n ( e n t r y . g e t M e s s a g e ( ) ) ;
}
}

29
30
31
32
33

mpreuna cu fisierul manifest


1
2
3
4
5
6

BundleM a n i f e s t V e r s i o n : 2
BundleSymbolicName : L o g S e r v i c e
BundleName : L o g S e r v i c e
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : A c t i v a t o r
ImportPackage : o r g . o s g i . framework , o r g . o s g i . s e r v i c e . l o g

6.7

Apache-karaf

Apache-karaf este un mediu OSGi, care integreaza o serie de functionalitati


OSGi (blueprint, http, etc.). Folosim denumirea simplificata Karaf, pentru
mediul de lucru.
Instalarea produsului consta n dezarhivarea fisierului descarcat.
Lansarea mediului este
set JAVA_HOME=. . .
set KARAF_HOME=. . .
del %KARAF_HOME%\lock
del %KARAF_HOME%\instances\*
rmdir %KARAF_HOME%\instances
%KARAF_HOME%\bin\karaf.bat clean

In catalogul %KARAF HOME% se genereaza catalogul instances iar n fereastra DOS va apare prompt-ul karaf@root>.
Oprirea se obtine apasand tastele CTRL+D.
Karaf poseda o consola DOS dar si o consola Web. Consola Web trebuie
instalata
feature:install webconsole
Consola Web se apeleaza dintr-un navigator prin
http://localhost:8181/system/console
Pentru a schimba portul se creaza n prealabil fisierul etc\org.ops4j.pax.web.cfg
cu continutul
org.osgi.service.http.port=8080
Instalarea componentelor OSGi se poate face

6.7. APACHE-KARAF

253

copiindu-le n catalogul
%KARAF HOME%\deploy
n mod obisnuit, prin comanda install file:. . .
In acest caz fisierul MANIFEST.mf trebuie sa contina atributele
Bundle-ManifestVersion: 2
Bundle-SymbolicName: numeComponentaOSGi

Comenzi OSGi uzuale: start n, stop n, install file:..., uninstall


n, list, help.
Karaf permite executarea componentelor OSGi programate imperativ si
descriptiv prin blueprint dar pentru care trebuie instalate doar
org.apache.aries.blueprint-*.jar,
componenta OSGi a aplicatiei propriu-zise.

254

CAPITOLUL 6. MODELUL OSGI

Capitolul 7
OSGi distribuit
Integrarea unei aplicatii Web ntr-o platforma OSGi necesita o abordare
specifica. Integrata ntr-o platforma OSGi, aplicatia Web nu mai este desfasurata
nemijlocit n serverul Web, dar apelurile se vor adresa n continuare serverului
Web. In consecinta, este nevoie de o punte ntre platforma OSGi si serverul
Web, care eventual sa asigure functionalitati suplimentare.

7.1

Medii OSGi pentru aplicatii distribuite

Apache-Karaf
Mediul OSGi apache-karaf utilizeaza serverul Web incorporat Jetty. Se va
instala suportul pentru protocolul http
feature:install http
Apelarea aplicatiei servlet va fi http://host:port/fisier.html

Glassfish
Mediul OSGi are la baza platforma apache-felix. Glassfish ofera posibilitati
OSGi pentru serviciile
HttpService
TransactionService
JDBC Data Source Service
255

256

CAPITOLUL 7. OSGI DISTRIBUIT

JMS Resource Service


Comenzile OSGi se apeleaza prin
asadmin osgi comanda OSGi
Astfel pentru lansarea unui servlet se va executa comanda:
asadmin osgi start file:. . ./arhiva.jar
Apelarea aplicatiei servlet va fi http://host:port/osgi/fisier.html

Equinox Bridge Servlet


Equinox Bridge Servlet 1 este distribuit printr-o arhiva war, destinata a fi
desfasurata ntr-un server Web precum apache-tomcat sau jetty. In felul acesta
Equinox Bridge Servlet integreaza platforma OSGi equinox ntr-un server Web
container de servlet. Equinox Bridge Servlet lanseaza platforma equinox. Consola OSGi se obtine apasand tasta Enter n fereastra DOS atasata serverului
Web.
Functionarea corecta a servlet-ului Equinox Bridge Servlet se verifica prin
apelul http://localhost:8080/bridge/sp test. Binenteles, n acest caz
s-a presupus ca serverul Web n care s-a desfasurat Equinox Bridge Servlet
este calculatorul local.
Platforma equinox instalata n serverul Web se poate instala, dezinstala, reinstala, porni si opri prin apelurile http://host:port/bridge/numeApel, unde
numeApel are valorile, respectiv sp deploy, sp undeploy, sp redeploy,
sp start, sp stop.

7.2

Servlet ca modul OSGi

Prezentam integrarea unei aplicatii servlet ntr-o componenta OSGi bazata


pe interfata HttpService. Cu foarte putine diferente componenta OSGi se va
putea utiliza pe platforme OSGi diferite apache-karaf, glassfish, bridge. Clasa
servlet-ului ramane nemodificata.

Integrarea servlet-ului prin HttpService


Interfata org.osgi.service.http.HttpService declara:
Metode
1

www.eclipse.org/equinox/server/http_in_container.php

7.2. SERVLET CA MODUL OSGI

257

void registerResources(String alias, String name, HttpContext


context) throws NamespaceException
void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context)ServletException, NamespaceException
void unregister(String alias)
Structura componentei OSGi corespunzatoare unui servlet este Structura
componentei OSGi este
|-->
|
|
|
|

META-INF
|
MANIFEST.MF
ClasaServlet.class
Activator.class
fisier.html

Ramane la latitudinea programatorului sa includa sau nu pagina html.


Compilarea necesita accesul la unul din pachetele care implementeaza interfata
HttpService:
org.eclipse.osgi.services 3.*.*.v*.jar.
org.apache.felix.http.bundle-*.jar
Prezentam doua moduri de programare n cate un exemplu.
Exemplul 7.2.1 Integrarea servlet-ului HelloServlet.
Aplicatia servlet este alcatuita din clasa HelloServlet.java si o pagina html
de apelare helloname.html.
Clasa Activator are codul

import
import
import
import

public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {

1
2
3

osgi
osgi
osgi
osgi

. framework . B u n d l e A c t i v a t o r ;
. framework . BundleContext ;
. framework . S e r v i c e R e f e r e n c e ;
. s e r v i c e . http . HttpService ;

public void s t a r t ( BundleContext c o n t e x t ) throws E x c e p t i o n {


S e r v i c e R e f e r e n c e sRef =
c o n t e x t . g e t S e r v i c e R e f e r e n c e ( H t t p S e r v i c e . c l a s s . getName ( ) ) ;
i f ( s R e f != n u l l ) {
HttpService s e r v i c e = ( HttpService ) context . g e t S e r v i c e ( sRef ) ;
s e r v i c e . r e g i s t e r S e r v l e t ( / h e l l o , new H e l l o S e r v l e t ( ) , null , n u l l ) ;
s e r v i c e . r e g i s t e r R e s o u r c e s ( / h e l l o n a m e . html , / i n d e x . html , n u l l ) ;
}
}

8
9
10
11
12
13
14
15
16

public void s t o p ( BundleContext c o n t e x t ) throws E x c e p t i o n {}

18
19

org .
org .
org .
org .

258

CAPITOLUL 7. OSGI DISTRIBUIT

Fisierul manifest.mf al componentei OSGi este


1
2
3
4
5
6
7
8
9
10

M a n i f e s t V e r s i o n : 1 . 0
BundleM a n i f e s t V e r s i o n : 2
BundleName: H e l l o S e r v l e t
BundleSymbolicName: H e l l o S e r v l e t
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : A c t i v a t o r
ImportP a c k a g e : j a v a x . s e r v l e t ,
j a v a x . s e r v l e t . http ,
o r g . o s g i . framework ; v e r s i o n= 1 . 3 . 0 ,
o r g . o s g i . s e r v i c e . h t t p ; v e r s i o n= 1 . 2 . 0

Apelarea servlet-ului din pagina html este dependenta de platforma OSGi


utilizata:
Cadrul OSGi
karaf

Apel (aplicatie, servlet)


http://host:8080/helloname.html
/hello
glassfish
http://host:8080/osgi/helloname.html
/osgi/hello
Equinox Bridge Servlet http://host:port/bridge/helloname.html
/bridge/hello
bridge este numele de apel definit de Equinox Bridge Servlet n fisierul web.xml.
A doua varianta de programare se bazeaza pe utilizarea clasei ServiceTracker
pentru nregistrarea servlet-ului.
Exemplul 7.2.2 Integrarea servlet-ului CmmdcServlet.
Aplicatia servlet este alcatuita din clasa CmmdcServlet.java si o pagina html
de apelare cmmdc.html.
Clasa Activator are codul
1
2
3
4
5
7
8

import
import
import
import
import

org .
org .
org .
org .
org .

osgi
osgi
osgi
osgi
osgi

. framework . B u n d l e A c t i v a t o r ;
. framework . BundleContext ;
. framework . S e r v i c e R e f e r e n c e ;
. s e r v i c e . http . HttpService ;
. u t i l . tracker . ServiceTracker ;

public c l a s s A c t i v a t o r implements B u n d l e A c t i v a t o r {
private S e r v i c e T r a c k e r h t t p S e r v i c e T r a c k e r ;

13

public void s t a r t ( BundleContext c o n t e x t ) throws E x c e p t i o n {


h t t p S e r v i c e T r a c k e r = new H t t p S e r v i c e T r a c k e r ( c o n t e x t ) ;
h t t p S e r v i c e T r a c k e r . open ( ) ;
}

15

public void s t o p ( BundleContext c o n t e x t ) throws E x c e p t i o n {

10
11
12

7.2. SERVLET CA MODUL OSGI

httpServiceTracker . close ( ) ;
h t t p S e r v i c e T r a c k e r = null ;

16
17
18

20

private c l a s s H t t p S e r v i c e T r a c k e r extends S e r v i c e T r a c k e r {

22

public H t t p S e r v i c e T r a c k e r ( BundleContext c o n t e x t ) {
super ( c o n t e x t , H t t p S e r v i c e . c l a s s . getName ( ) , n u l l ) ;
}

23
24

public O b j e c t a d d i n g S e r v i c e ( S e r v i c e R e f e r e n c e r e f e r e n c e ) {
HttpService httpService = ( HttpService ) context . getService ( ref ere nce ) ;
try {
h t t p S e r v i c e . r e g i s t e r R e s o u r c e s ( /cmmdc . html , /cmmdc . html , n u l l ) ;
h t t p S e r v i c e . r e g i s t e r S e r v l e t ( /cmmdc ,new CmmdcServlet ( ) , null , n u l l ) ;
}
catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}
return h t t p S e r v i c e ;
}

26
27
28
29
30
31
32
33
34
35
36

public void r e m o v e d S e r v i c e ( S e r v i c e R e f e r e n c e r e f e r e n c e , O b j e c t s e r v i c e ) {
HttpService httpService = ( HttpService ) s e r v i c e ;
h t t p S e r v i c e . u n r e g i s t e r ( /cmmdc . html ) ;
h t t p S e r v i c e . u n r e g i s t e r ( /cmmdc ) ;
super . r e m o v e d S e r v i c e ( r e f e r e n c e , s e r v i c e ) ;
}

38
39
40
41
42
43

44
45

259

Serverul Web va recunoaste apelul catre fisierul cmmdc.html si catre servlet


prin numele de apel cmmdc.html si respectiv cmmdc - liniile de cod 29-30.
Fisierul manifest.mf al componentei OSGi este
1
2
3
4
5
6
7
8
9
10
11

M a n i f e s t V e r s i o n : 1 . 0
BundleM a n i f e s t V e r s i o n : 2
BundleName: CmmdcServlet
BundleSymbolicName: CmmdcServlet
BundleV e r s i o n : 1 . 0 . 0
BundleA c t i v a t o r : A c t i v a t o r
BundleL o c a l i z a t i o n : p l u g i n
ImportP a c k a g e : j a v a x . s e r v l e t , j a v a x . s e r v l e t . http ,
o r g . o s g i . framework ; v e r s i o n= 1 . 3 . 0 ,
o r g . o s g i . s e r v i c e . h t t p ; v e r s i o n= 1 . 2 . 0 ,
o r g . o s g i . u t i l . t r a c k e r ; v e r s i o n= 1 . 3 . 1

Variant
a descriptiv
a n Bridge
Clasa care implementeaza interfata BundleActivator este nlocuita cu un
fisier de configurare plugin.xml. Structura componentei OSGi este
|--> META-INF
|
|
MANIFEST.MF
|
ClasaServlet.class

260

|
|

CAPITOLUL 7. OSGI DISTRIBUIT

fisier.html
plugin.xml

Pentru exemplul anterior fisierul manifest.mf este


1
2
3
4
5
6
7
8

M a n i f e s t V e r s i o n : 1 . 0
BundleM a n i f e s t V e r s i o n : 2
BundleName: CmmdcServlet P l u g I n
BundleSymbolicName: CmmdcServlet P l u g I n ; s i n g l e t o n :=t r u e
BundleV e r s i o n : 1 . 0 . 0
BundleL o c a l i z a t i o n : p l u g i n
ImportP a c k a g e : j a v a x . s e r v l e t , j a v a x . s e r v l e t . h t t p
Require B u n d l e : o r g . e c l i p s e . e q u i n o x . h t t p . r e g i s t r y

iar continutul fisierului plugin.xml este


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

<?xml version= 1 . 0 e n c o d i n g=UTF8 ?>


<? e c l i p s e version= 3 . 0 ?>
<p l u g i n>
<e x t e n s i o n p o i n t i d= s e r v l e t s
name= H t t p S e r v i c e s e r v l e t s
schema= schema / s e r v l e t s . e x s d />
<e x t e n s i o n p o i n t i d= r e s o u r c e s
name= H t t p S e r v i c e r e s o u r c e s
schema= schema / r e s o u r c e s . e x s d />
<e x t e n s i o n p o i n t i d= h t t p c o n t e x t s
name= H t t p S e r v i c e h t t p c o n t e x t s
schema= schema / h t t p c o n t e x t s . e x s d />
<e x t e n s i o n
i d= m y S e r v l e t
p o i n t= o r g . e c l i p s e . e q u i n o x . h t t p . r e g i s t r y . s e r v l e t s >
<s e r v l e t
a l i a s= / p l u g i n /cmmdc
c l a s s= CmmdcServlet >
</ s e r v l e t>
</ e x t e n s i o n>
<e x t e n s i o n
i d= myResource
p o i n t= o r g . e c l i p s e . e q u i n o x . h t t p . r e g i s t r y . r e s o u r c e s >
<r e s o u r c e
a l i a s= / p l u g i n /cmmdc . html
basename= /cmmdc . html
/>
</ e x t e n s i o n>
</ p l u g i n>

Se va proceda la fel ca n varianta anterioara cu observatia ca adresele de


apelare, definite de atributul alias, vor fi
http://host:port/bridge/plugin/cmmdc.html
http://host:port/bridge/plugin/cmmdc

Partea IV
JAVA MANAGEMENT
EXTENSIONS

261

Capitolul 8
Java Management Extensions
Java Management Extensions (JMX) face posibila ca un obiect Java sa
permita gestionarea metodelor si a anumitor campuri de catre alte obiecte.
Obiectele Java care si expun astfel resursele se numesc MBean - uri si formeaza
temelia cadrului de lucru JMX.
Exista mai multe tipuri de MBean-uri:
Standard MBean;
Dynamic MBean;
Open MBean;
Model MBean;
MXBean;
Un obiect care gestioneaza resursele unui MBean se numeste agent sau server
MBean. Agentul dispune de mijloace care interactioneaza cu un MBean,
permitandu-i:
accesul la valorile unui camp si la modificarea lor;
invocarea metodelor.
In general, un agent poate fi definit ca
autorul unei actiuni;
factor care provoaca actiuni;
reprezentant al unei institutii nsarcinat cu ndeplinirea unor actiuni.
263

264

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Terminologia server MBean se justifica prin faptul ca poate fi invocat de un


program client. In aceasta ipostaza, serverul MBean are rolul unui container
de MBean-uri si de gestionare si executie a apelurilor clientilor.
Structura unei aplicatii JMX contine doua nivele:
componentele MBean;
agentul (serverul MBean).

8.1
8.1.1

Standard MBean
Crearea unui Standard MBean

O componenta MBean este alcatuita dintr-o interfata si o clasa care implementeaza interfata satisfacand urmatoarele restrictii:
1. interfata are numele clasei care o implementeaza avand n plus sufixul
MBean;
2. Interfata si clasa care o implementeaza apartin aceluiasi pachet;
3. constructorii si metodele expuse trebuie sa fie publice.
In continuare campurile si metodele destinate expunerii se vor denumi
atribute, respectiv operatii. Fiecarui atribut xxx i se ataseaza cel putin una
din metodele
public void setXxx(tip xxx){
this.xxx=xxx;
}
si / sau
public tip getXxx(){
return xxx;
}
Un atribut se precizeaza doar prin aceste metode, fara definirea / declararea
campului corespunzator. Campul se defineste n clasa ce implementeaza interfata
MBean-ului.
Astfel, un MBean este caracterizat de

8.1. STANDARD MBEAN

265

atribute
care pot fi consultate (citite), modificate (scrise) sau cu ambele optiuni.
operatii
notificari
cu evidenta modificarilor suferite de atribute.
Exemplul 8.1.1
Construim un MBean cu
atributele
label
ce poate fi numai citit;
cursEuro
care poate fi consultat si modificat;
operatiile
public String sayHello()
afiseaza un mesaj;
public long cmmdc(long m, long n);
de calcul a celui mai mare divizor comun a doua numere naturale.
Interfata IntroMBean este
1

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

4
5
6

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

8
9
10
11
12
13
14

fiind implementat de clasa Intro

266

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

package b a s i c ;

public c l a s s I n t r o implements IntroMBean {


// A t r i b u t e
private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ;
private double c u r s E u r o = 4 . 5 0 ;

5
6
7

public S t r i n g g e t L a b e l ( ) {
return l a b e l ;
}

9
10
11

public double getCursEuro ( ) {


return c u r s E u r o ;
}

13
14
15

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

17
18
19

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

21
22
23
24
25
26

public long cmmdc( long m, long n ) { . . . }

28
29

In acest caz nu s-a implementat posibilitatea notificarilor atributului cursEuro.

8.1.2

Crearea unui MBeanServer

Un agent sau MBean server implementeaza interfata MBeanServer. Un


asemenea obiect se obtine printr-una din metodele statice
static MBeanServer ManagementFactory.getPlatformMBeanServer()
Utilitarul jconsole permite conectarea la serverul MBean.
static MBeanServer MBeanServerFactory.createMBeanServer()
In agent se nregistreaza componente MBean. Un obiect MBean este caracterizat de un nume, un obiect de tip ObjectName. Inregistrarea si / sau
crearea unei componente MBean necesita definirea n prealabil a acestui nume.
Structura unei nume este
domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . .
unde

8.1. STANDARD MBEAN

267

domeniu
este un nume simbolic (String). Daca domeniul este stringul vid atunci
se considera valoarea implicita DefaultDomain.
atribute uzuale:
type=numele MBean-ului
index=numar de identificare a MBean-ului
Cel putin un atribut este obligatoriu.
Clasa ObjectName
Constructori
ObjectName(String nume)
Parametrul nume are structura descrisa mai sus.
ObjectName(String domeniu, Hashtable<String,String> tabel )
ObjectName(String domeniu, String numeAtribut, String
valAtribut)
Metode
static ObjectName getInstance(String nume)
Inregistrarea si utilizarea MBean-ului face apel la metodele interfetei MBeanServer.
ObjectInstance
Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblului alcatuit de un obiect ObjectName asociat unui MBean si numele clasei
corespunzatoare.
Interfata MBeanServer
Metode
ObjectInstance registerMBean(Object obj , ObjectName nume)
Inregistreaza pe platforma, instanta obj a unui MBean avand numele
nume.

268

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

void unregister(ObjectName nume)


ObjectInstance createMBean(String numeClasa , ObjectName nume)
Creaza si nregistreaza un MBean de clasa numeClasa si de nume nume.
ObjectInstance createMBean(String numeClasa , ObjectName nume,
Object[] param, String[] sign)
In plus, sirul param contine parametri constructorului, de tip, respectiv
sign.
String getDefaultDomain()
Object invoke(ObjectName mbeanName, String operationName, Object[]
param, String[] paramTip)
Se invoca operatia operationName a MBean-ului mbeanName. Parametri
necesari operatiei mpreuna cu tipurile corespunzatoare sunt dati n variabilele param si respectiv paramTip.
Object getAttribute(ObjectName mbeanName,String atribut)
Returneaza valoarea atributului atribut a mbean-ului mbeanName.
void setAttribute(ObjectName mbeanName,Attribute atribut)
Fixeaza valoarea atributului atribut a MBean-ului mbeanName. Retinem
doar constructorul clasei Attribute prin
Attribute(String nume, Object valoare)
MBeanInfo getMBeanInfo(ObjectName mbeanName)
Returneaza un obiect de tip MBeanInfo util inspectarii resurselor unui
MBean.
Exista mai multe sabloane de programare a nregistrarii unei componente
MBean.
Exemplul 8.1.2 Se creaza doua componente MBean de tip Intro care vor fi
inspectate prin intermediul utilitarului jconsole1 - distributia jdk .
Utilitarul jconsole permite apelarea operatiilor, modificarea atributelor si
semnaleaza notificarile.
1

In acest caz, este nevoie ca variabilele de tip clasa acoperitoare Double, Long sa fie
nlocuite prin tipuri predefinite.

8.1. STANDARD MBEAN

1
2
3
4
6
7
8
9
10
11
12

package b a s i c ;
import j a v a . l a n g . management . ManagementFactory ;
import j a v a x . management . ObjectName ;
import j a v a x . management . MBeanServer ;
public c l a s s Main{
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g domeniu= ;
i f ( a r g s . l e n g t h >0) domeniu=a r g s [ 0 ] ;
try {
// S e r v e r u l p l a t f o r m e i
MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ;
// V a r i a n t a 1
// C o n s t r u i r e a ObjectName c o r e s p u n z a t o r MBeanu l u i
ObjectName mbeanObjectName =
new ObjectName ( domeniu+ : t y p e=I n t r o , i n d e x=1 ) ;

14
15
16
17

// Crearea MBeanu l u i
I n t r o mbean = new I n t r o ( ) ;

19
20

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

22
23

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

25
26
27

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

29
30
31

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

32
33
34
35

36
37

269

Executarea aplicatiei revine la


1. Intr-o fereastra DOS se lanseaza agentul Main prin
java -Dcom.sun.manager.jmxremote basic.Main
2. Intr-o alta fereastra DOS se lanseaza
jconsole
pornind utilitarul jconsole.
3. In fereastra de dialog jconsole:Connect to Agent se da clic pe Connect.
4. In panoul Tree gasim domeniul dat. Prin clic pe domeniu apar MBeanurile de indice 1 si 2.
5. Prin clic pe unul din aceste MBean-uri, n panoul central avem acces la
atributele si la operatiile lor.

270

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Rezultatul unei operatii apare ntr-o fereastra de informare (Fig. 8.1).

Figure 8.1: Rezultatele furnizate de jcluster.

8.1.3

Notific
ari

Pentru implementarea retinerii de catre un agent MBean a notificarilor,


clasa ce implementeaza interfata MBean-ului trebuie sa extinda clasa NotificationBroadcasterSupport.
Modificarile unui atribut se retin ntr-un obiect de tip Notification si este
transmis prin metoda
sendNotification(Notification notification)

8.1. STANDARD MBEAN

271

a clasei NotificationBroadcasterSupport.
Suplimentar se defineste metoda
public MBeanNotificationInfo[] getNotificationInfo()
n care se precizeaza
tipul notificarii - (constanta definita de clasa AttributeChangeNotification);
clasa n care s-a generat notificarea
String name = AttributeChangeNotification.class.getName();
o descriere a modificarii.
Astfel, introducerea notificarilor presupune familiarizarea cu clasele
NotificationBroadcasterSupport
Constructori
NotificationBroadcasterSupport()
Metode
void sendNotification(Notification notificare)
Notification
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()

272

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

AttributeChangeNotification extends Notification


Constructori
AttributeChangeNotification(Object source, long sequenceNumber , long timeStamp, String msg, String attributeName, String
attributeType, Object oldValue, Object newValuE )
C
ampuri
static String ATTRIBUTE CHANGE
Semnaleaza schimbarea atributului
Exemplul 8.1.3 Extinderea MBean-ului Intro cu notificarea modificarilor atributelor
n jconsole.
Implementarea notificarilor n clasa Intro presupune modificarea metodei
setCursEuro. Totodata se adauga metoda getNotificationInfo, ce furnizeaza
informatii referitoare la modificarea aparuta. Codul clasei care implementeaza
interfata devine
1
2
3
4
5
7
8
9

package ag en tn ;
import j a v a x . management . N o t i f i c a t i o n ;
import j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ;
import j a v a x . management . N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t ;
import j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ;
public c l a s s I nt r oN extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t
implements IntroNMBean {
private long sequenceNumber =1;

13

// A t r i b u t e
private f i n a l S t r i n g l a b e l = Fac . Matematica s i I n f o r m a t i c a ;
private double c u r s E u r o = 4 . 5 0 ;

15

public S t r i n g g e t L a b e l ( ) { . . . }

17

public double getCursEuro ( ) { . . . }

19

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

11
12

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

8.1. STANDARD MBEAN

sendNotification (n ) ;

32
33

35

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

36
37
38
39
40
41
42
43
44

// O p e r a t i i
public S t r i n g s a y H e l l o ( ) { . . . }

46
47

public long cmmdc( long m, long n ) { . . . }

49
50

273

In jconsole pentru notificare, n prealabil este nevoie de subscriere.

8.1.4

Agent MBean

In exemplelele anterioare resursele unui MBean au fost utilizate prin jconsole. Valorificarea resurselor unui MBean Intro, dintr-un MBeanServer (agent)
se programeaza prin
Exemplul 8.1.4
1
2
3
4
5
6
7
9
10
11
12
13
15
16
17
18
19
20
22
23
24

package a g e n t ;
import j a v a . i o . IOException ;
import j a v a x . management . ObjectName ;
import j a v a x . management . MBeanServer ;
import j a v a x . management . MBeanServerFactory ;
import j a v a x . management . A t t r i b u t e ;
import j a v a . u t i l . S c a n n e r ;
public c l a s s Agent {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
try {
// Crearea A g e n t u l u i MBeanServer
MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;
// Crearea unui MBean
S t r i n g domain = mbs . g e t D e f a u l t D o m a i n ( ) ;
S t r i n g className= a g e n t . I n t r o ;
S t r i n g sObjectName=domain+ : t y p e=+className ;
ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
mbs . createMBean ( className , mbeanObjectName ) ;
// U t i l i z a r e a 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 ;

274

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

25

mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ;

27

o p e r a t i a=cmmdc ;
System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
System . out . p r i n t l n ( Primul numar : ) ;
long m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
long n=s c a n n e r . nextLong ( ) ;
O b j e c t [ ] param={m, n } ;
S t r i n g [ ] s i g n ={ l o n g , l o n g } ;
Long r =(Long ) mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ;
System . out . p r i n t l n ( cmmdc=+r . t o S t r i n g ( ) ) ;

28
29
30
31
32
33
34
35
36
37

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

39
40
41

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

43
44
45
46
47
48

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

49
50
51
52

53
54

8.1.5

Invocarea la distant
a

Din punct de vedere al programarii distribuite, cazul interesant este cel


n care clasa ce implementeaza MBean-ul si clientul (agentul MBean) care o
utilizeaza se afla pe calculatoare diferite.
In acest caz:
Este nevoie de o clasa server (agent) al carui rol este
Instantierea unui MBeanServer
Instantiarea unui server de conexiune, obiect de tip MBeanServerConnection.
Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneaza
comunicatia dintre un client si serverul MBeanServer. Serverul de
conexiune si serverul MBeanServer apartin aceleiasi clase.
In cazul utilizarii tehnologiei RMI rmiregistry si serverul MBeanServer
trebuie sa ruleze pe acelasi calculator.
Utilizand tehnologia RMI-IIOP, orbd si serverul MBeanServer pot
rula pe calculatoare distincte.

8.1. STANDARD MBEAN

275

Lansarea n executie a serverului de conexiune.


Clientul dispune de interfata MBean-ului.
Interfata MBeanServerConnection este implementata de clasa MBeanServer
Sablonul de programare pentru instantierea obiectului de tip MBeanServerConnection
si lansarea sa n executie poate fi:
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 catre


client.
Lansarea n executie a serverului este precedata de pornirea registrului
rmiregistry, respectiv orbd.
Exemplul 8.1.5
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package s e r v e r ;
import j a v a x . management . MBeanServer ;
import j a v a x . management . MBeanServerFactory ;
import j a v a x . management . remote . JMXServiceURL ;
import j a v a x . management . remote . JMXConnectorServer ;
import j a v a x . management . remote . JMXConnectorServerFactory ;
public c l a s s MBServer {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1099 ;
// S t r i n g p o r t =1050;
i f ( a r g s . l e n g t h ==0){
System . out . p r i n t l n ( The name o f t h e s e r v e r i s r e q u i r e d ) ;
System . e x i t ( 0 ) ;
}
i f ( a r g s . l e n g t h >=2)
h o s t=a r g s [ 1 ] ;
i f ( a r g s . l e n g t h >=3)
p o r t=a r g s [ 2 ] ;
try {
// Crearea MBeanServer
MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;

276

// Crearea unui s e r v e r c o n e c t o r
S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +
h o s t+ : +p o r t+ / +a r g s [ 0 ] ;
// S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+
//
h o s t +:+ p o r t +/+ a r g s [ 0 ] ;
JMXServiceURL u r l=new JMXServiceURL ( s u r l ) ;
JMXConnectorServer c s=
JMXConnectorServerFactory . newJMXConnectorServer ( u r l , null , mbs ) ;

25
26
27
28
29
30
31
32

// 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 . st art ( ) ;
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 ( ) ;

34
35
36
37
38

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

39
40
41
42
43

44
45

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Primul argument care trebuie furnizat programului anterior (args[0] ) este numele serverului.
Clientul, la randul lui, este nevoit sa creeze un conector catre server (agent),
prin intermediul caruia obtine un obiect ce implementeaza interfata MBeanServerConnection.
Prin acest obiect, clientul va putea crea MBean-uri - n agent - si le va putea
utiliza resursele.
Sablonul de programare pentru crearea obiectului MBeanServerConnection
poate fi
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 statica
mbeanClass proxy =
(mbeanClass)MBeanServerInvocationHandler.newProxyInstance(
mbeanServerConnection,mbeanObjectName,mbeanClass.class,true);
In final, MBean-ul se sterge din serverul de conexiune, prin
cs.unregisterMBean(mbeanObjectName).

8.1. STANDARD MBEAN

277

Exemplul 8.1.6 Client ce utilizeaza un MBean Intro, definit n Exemplul


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

package c l i e n t ;
import j a v a . u t i l . S c a n n e r ;
import j a v a x . management . MBeanServerConnection ;
import j a v a x . management . ObjectName ;
import j a v a x . management . A t t r i b u t e ;
import j a v a x . management . M B e a n S e r v e r I n v o c a t i o n H a n d l e r ;
import j a v a x . management . remote . JMXServiceURL ;
import j a v a x . management . remote . JMXConnector ;
import j a v a x . management . remote . JMXConnectorFactory ;
public c l a s s C l i e n t {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1099 ;
i f ( a r g s . l e n g t h <=1){
System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ;
System . e x i t ( 0 ) ;
}
S t r i n g serverName=a r g s [ 0 ] ;
S t r i n g domain=a r g s [ 1 ] ;
i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ;
i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 4 ] ;
S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
try {
// Crearea unui c o n e c t o r s i a o b i e c t u l u i de t i p M B e a n S e r v e r c s e c t i o n
S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +
h o s t+ : +p o r t+ / +a r g s [ 0 ] ;
// S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+
//
h o s t +:+ p o r t +/+ a r g s [ 0 ] ;
JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;
// Domeniile a g e n t u l u i s u n t
System . out . p r i n t l n ( Domains : ) ;
S t r i n g domains [ ] = c s . getDomains ( ) ;
f o r ( i n t i = 0 ; i < domains . l e n g t h ; i ++) {
System . out . p r i n t l n ( \ tDomain [ + i + ] = + domains [ i ] ) ;
}
// i a r domeniul i m p l i c i t
System . out . p r i n t l n ( DefaultDomain : +c s . g e t D e f a u l t D o m a i n ( ) ) ;
System . out . p r i n t l n ( Domain : +domain ) ;
// Crearea unui MBean I n t r o
S t r i n g className= b a s i c . I n t r o ;
S t r i n g sObjectName=domain+ : t y p e=+className ;
ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;
double c u r s E u r o ;
long m, n ;
// U t i l i z a r e a 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

278

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

56
57
58
59
60
61
62

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

64
65
66

// o p e r a t i a cmmdc
System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ;
System . out . p r i n t l n ( Primul numar : ) ;
m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
n=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Cmmdc=+proxy . cmmdc(m, n ) ) ;

68
69
70
71
72
73
74

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

76
77
78
79
80
81

// V a r i a n t a 2 de i n v o c a r e p r i n c o n e x i u n e
System . out . p r i n t l n ( V a r i a n t a de i n v o c a r e p r i n c o n e x i u n e ) ;
// A p e l a r e a o p e r a t i i l o r
S t r i n g o p e r a t i a= s a y H e l l o ;
c s . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ;
o p e r a t i a=cmmdc ;
System . out . p r i n t l n ( Cmmdc a l n u m e r e l o r : ) ;
System . out . p r i n t l n ( Primul numar : ) ;
m=s c a n n e r . nextLong ( ) ;
System . out . p r i n t l n ( Al d o i l e a numar : ) ;
n=s c a n n e r . nextLong ( ) ;
O b j e c t [ ] param={m, n } ;
S t r i n g [ ] s i g n ={ l o n g , l o n g } ;
Long r =(Long ) c s . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ;
System . out . p r i n t l n ( Cmmdc=+r . t o S t r i n g ( ) ) ;

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

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

99
100
101

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

103
104
105
106
107
108
109

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

110
111
112
113
114

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

8.1. STANDARD MBEAN

115

279

Inspectarea si valorificarea resurselor unei componente MBean se


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

private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) {


System . out . p r i n t l n ( CLASA : \ t + i n f o . getClassName ( ) ) ;
System . out . p r i n t l n ( DESCR: \ t + i n f o . g e t D e s c r i p t i o n ( ) ) ;
System . out . p r i n t l n ( ATTRIBUTE ) ;
MBeanAttributeInfo [ ] a t t r I n f o = i n f o . g e t A t t r i b u t e s ( ) ;
i f ( a t t r I n f o . length > 0) {
f o r ( i n t i = 0 ; i < a t t r I n f o . l e n g t h ; i ++) {
System . out . p r i n t l n ( \tNUME: \ t + a t t r I n f o [ i ] . getName ( ) ) ;
System . out . p r i n t l n ( \tDESC : \ t + a t t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ;
System . out . p r i n t l n ( \ tTIP : \ t + a t t r I n f o [ i ] . getType ( ) +
READ: + a t t r I n f o [ i ] . i s R e a d a b l e ( ) +
WRITE: + a t t r I n f o [ i ] . i s W r i t a b l e ( ) ) ;
}
}
else
System . out . p r i n t l n ( \ t F a r a a t r i b u t e ! ) ;
System . out . p r i n t l n ( CONSTRUCTORI ) ;
MBeanConstructorInfo [ ] c o n s t r I n f o = i n f o . g e t C o n s t r u c t o r s ( ) ;
f o r ( i n t i =0; i <c o n s t r I n f o . l e n g t h ; i ++) {
System . out . p r i n t l n ( \tNUME: \ t + c o n s t r I n f o [ i ] . getName ( ) ) ;
System . out . p r i n t l n ( \tDESCR : \ t + c o n s t r I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ;
System . out . p r i n t l n ( \tPARAM: \ t +
c o n s t r I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ;
}
System . out . p r i n t l n ( OPERATII ) ;
MBeanOperationInfo [ ] o p I n f o = i n f o . g e t O p e r a t i o n s ( ) ;
i f ( opInfo . length > 0) {
f o r ( i n t i = 0 ; i < o p I n f o . l e n g t h ; i ++) {
System . out . p r i n t l n ( \tNUME: \ t + o p I n f o [ i ] . getName ( ) ) ;
System . out . p r i n t l n ( \tDESCR : \ t + o p I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ;
System . out . p r i n t l n ( \tPARAM: \ t +
o p I n f o [ i ] . g e t S i g n a t u r e ( ) . l e n g t h + p a r a m e t r i ) ;
}
}
else
System . out . p r i n t l n ( \ t F a r a o p e r a t i i ) ;
System . out . p r i n t l n ( NOTIFICARI ) ;
MBeanNotificationInfo [ ] n o t i f I n f o = info . g e t N o t i f i c a t i o n s ( ) ;
i f ( n o t i f I n f o . length > 0) {
f o r ( i n t i = 0 ; i < n o t i f I n f o . l e n g t h ; i ++) {
System . out . p r i n t l n ( \tNUME: + n o t i f I n f o [ i ] . getName ( ) ) ;
System . out . p r i n t l n ( \tDESCR : + n o t i f I n f o [ i ] . g e t D e s c r i p t i o n ( ) ) ;
String notifTypes [ ] = n o t i f I n f o [ i ] . getNotifTypes ( ) ;
f o r ( i n t j = 0 ; j < n o t i f T y p e s . l e n g t h ; j ++) {
System . out . p r i n t l n ( \ tTIP : + n o t i f T y p e s [ j ] ) ;
}
}
}
else
System . out . p r i n t l n ( \ t F a r a n o t i f i c a r i ) ;
}

Aceasta metoda poate fi inserata n oricare din programele agent sau client.

280

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Notificarea la distant
a
Notificarea la distanta presupune utilizarea unui MBean posedand aceasta
facilitate. Pe partea de client trebuie implementat interfata NotificationListener
care declara metoda
public void handleNotification(Notification notification, Object
handback )
Atasarea si disponibilizarea clasei ce implementeaza interfata Notification
Listener se obtin prin metodele interfetei MBeanServerConnection:
void addNotificationListener(ObjectName name, NotificationListener
listener , NotificationFilter filter , Object handback )throws InstanceNotFoundException, IOException
void removeNotificationListener(ObjectName name, ObjectName listener )throws InstanceNotFoundException, ListenerNotFoundException,
IOException
Exemplul 8.1.7 Folosind exemplul 8.1.6 - dar cu MBean-ul creat pentru 8.1.3
se creaza un client cu notificare, care sesiseaza modificarea valoarii 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 . ge t 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 ( Curs c u r e n t
: +
myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ;
}
}

Codul clasei client este


1
2
3
4
5

package c l i e n t ;
import j a v a x . management . ObjectName ;
import j a v a x . management . MBeanInfo ;
import j a v a x . management . M B e a n A t t r i b u t e I n f o ;
import j a v a x . management . MBeanConstructorInfo ;

8.1. STANDARD MBEAN

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

import
import
import
import
import
import

public c l a s s C l i e n t N o t i f {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1099 ;
i f ( a r g s . l e n g t h <=1){
System . out . p r i n t l n ( The s e r v e r and domain names a r e r e q u i r e d ) ;
System . e x i t ( 0 ) ;
}
S t r i n g serverName=a r g s [ 0 ] ;
S t r i n g domain=a r g s [ 1 ] ;
i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ;
i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 3 ] ;
C l i e n t N o t i f o b j=new C l i e n t N o t i f ( ) ;
try {
// Crearea unui c o n e c t o r s i a o b i e c t u l u i
// de t i p MBeanServerConnection
S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +
h o s t+ : +p o r t+ / +a r g s [ 0 ] ;
JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;
// Crearea o b i e c t u l u i OBjectName a t a s a t 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 ) ;

35
36
37
38

MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


getMBeanResources ( i n f o ) ;

40
41

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

43
44
45
46
47

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

49
50
51
52
53
54
55
56
57
58

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

59
60
61
62
63
64

j a v a x . management . MBeanOperationInfo ;
j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ;
j a v a x . management . MBeanServerConnection ;
j a v a x . management . remote . JMXServiceURL ;
j a v a x . management . remote . JMXConnector ;
j a v a x . management . remote . JMXConnectorFactory ;

281

282

private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }

66
68

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Clasa Client care creaza MBean-ul trebuie lansata naintea clasei ClientNotif.
Aceste doua clase pot rula pe calculatoare distincte.
Exemplul 8.1.8 O aplicatie servlet ntretine un cont. Actiunile ce pot fi
ntreprinse sunt: depunerea unei sume, extragerea unei sume n limita soldului si consultarea contului. Contul este implementat ca un MBean standard.
Se cere urmarirea la distanta a modificarilor suferite de cont.
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
2
3
4
6
7
8
9
11
12
13
15
16
17
18
19
20
21
22
23
24
25
26
27
28
30
31
32

import
import
import
import

j a v a x . management . N o t i f i c a t i o n ;
j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ;
j a v a x . management . N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t ;
j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ;

public c l a s s Cont extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t


implements ContMBean{
private long sequenceNumber =1;
private double c o n t ;
public synchronized double getCont ( ) {
return c o n t ;
}
public synchronized void s e t C o n t ( double c o n t ) {
double oldCont=t h i s . c o n t ;
t h i s . c o n t=c o n t ;
N o t i f i c a t i o n n=new A t t r i b u t e C h a n g e N o t i f i c a t i o n (
this ,
sequenceNumber++,
System . c u r r e n t T i m e M i l l i s ( ) ,
Schimbarea Cont ,
cont ,
double ,
oldCont ,
cont ) ;
sendNotification (n ) ;
}
public M B e a n N o t i f i c a t i o n I n f o [ ] g e t N o t i f i c a t i o n I n f o ( ) {
S t r i n g [ ] t y p e s = new S t r i n g [ ] {
A t t r i b u t e C h a n g e N o t i f i c a t i o n .ATTRIBUTE CHANGE

8.1. STANDARD MBEAN

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

33
34
35
36
37
38

39
40

283

Codul servlet-ului este


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

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

j a v a . i o . IOException ;
javax . s e r v l e t . ServletException ;
javax . s e r v l e t . http . HttpServlet ;
javax . s e r v l e t . http . HttpServletRequest ;
javax . s e r v l e t . http . HttpServletResponse ;
javax . s e r v l e t . ServletOutputStream ;
javax . s e r v l e t . ServletConfig ;
j a v a x . s e r v l e t . a n n o t a t i o n . WebServlet ;
j a v a x . s e r v l e t . a n n o t a t i o n . WebInitParam ;
j a v a x . management . ObjectName ;
j a v a x . management . A t t r i b u t e ;
j a v a x . management . MBeanServerConnection ;
j a v a x . management . remote . JMXServiceURL ;
j a v a x . management . remote . JMXConnector ;
j a v a x . management . remote . JMXConnectorFactory ;

@WebServlet ( u r l P a t t e r n s = / a p p d e p o z i t ,
initParams = {
@WebInitParam ( name = j m x S e r v e r H o s t , v a l u e = l o c a l h o s t )
}
)
public c l a s s D e p o z i t S e r v l e t extends H t t p S e r v l e t {
MBeanServerConnection c s=n u l l ;
ObjectName mbeanObjectName=n u l l ;
String host ;
S t r i n g p o r t= 1099 ;
S t r i n g s e r v e r= s e r v e r ;
public void i n i t ( S e r v l e t C o n f i g c o n f i g ) {
try {
super . i n i t ( c o n f i g ) ;
h o s t=c o n f i g . g e t I n i t P a r a m e t e r ( j m x S e r v e r H o s t ) ;
S t r i n g s u r l= s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / +h o s t+ : +p o r t+ / +s e r v e r ;
// S t r i n g s u r l = s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://+ h o s t +:+ p o r t +/+ s e r v e r ;
JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
c s = jmxc . getMBeanServerConnection ( ) ;
S t r i n g domain = c s . g e t D e f a u l t D o m a i n ( ) ;
S t r i n g className= Cont ;
S t r i n g sObjectName=domain+ : t y p e=+className ;
mbeanObjectName = new ObjectName ( sObjectName ) ;
c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;
}
catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
System . e x i t ( 0 ) ;
}
}

284

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

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=JMXE r r o r : +e . g e t M e s s a g e ( ) ;
}
double v a l u e=o b j V a l u e . d o u b l e V a l u e ( ) ;
double x ;
A t t r i b u t e c u r s=n u l l ;
switch ( o p e r ) {
case dep :
x=v a l u e+suma ;
c u r s=new A t t r i b u t e ( Cont , x ) ;
try {
c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
message=Sa depus suma ;
}
catch ( E x c e p t i o n e ) {
message=JMXE r r o r : +e . g e t M e s s a g e ( ) ;
}
break ;
case e x t :
i f ( v a l u e>=suma ) {
x=v a l u e suma ;
c u r s=new A t t r i b u t e ( Cont , x ) ;
try {
c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
message=Sa e x t r a s suma ;
}
catch ( E x c e p t i o n e ) {
message=JMXE r r o r : +e . g e t M e s s a g e ( ) ;
}
}
else {
message= C e r e r e a nu p o a t e f i i n d e p l i n i t a ;
}
break ;
case con :
message=Suma d i n c o n t e s t e +v a l u e+ u n i t . ;
break ;
}
r e s . setContentType ( t e x t / html ) ;
out . p r i n t l n ( <html> ) ;
out . p r i n t l n ( <head><t i t l e >Depozit </ t i t l e ></head> ) ;
out . p r i n t l n ( <body> ) ;
out . p r i n t l n ( <h1>O p e r a t i u n i Cont</h1> ) ;
out . p r i n t l n ( <p> ) ;

8.1. STANDARD MBEAN

out .
out .
out .
out .

108
109
110
111

p r i n t l n ( message ) ;
p r i n t l n ( </p> ) ;
p r i n t l n ( </body></html> ) ;
close ();

112

114

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

115
116
117
118

Pagina de apelare a servlet-ului fiind (index.html )


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

<html>
<head>
< t i t l e> S e r v l e t u l H e l l o </ t i t l e>
</head>
<body bgcolor=#a a e e a a >
<center>
<h1> Pagina de &#238; n t r e &#355; i n e r e a d e p o z i t u l u i </h1>
<form method= p o s t
action= h t t p : / / l o c a l h o s t : 8 0 8 0 / appcont / a p p d e p o z i t >
<p>I n t r o d u c e &#355; i :
<p>Opera&#355; i a : <s e l e c t name= o p e r >
<option value= dep >Depunere
<option value= e x t >E x t r a g e r e
<option value= con >C o n s u l t a r e
</ s e l e c t>
<p>
<input type= t e x t name=suma value= 0 >
<p>
<input type= submit value= Executa >
</form>
</ center>
</body>
</html>

Clientlul care urmareste de la distanta contul are codul


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

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

j a v a x . management . ObjectName ;
j a v a x . management . MBeanInfo ;
j a v a x . management . M B e a n A t t r i b u t e I n f o ;
j a v a x . management . MBeanConstructorInfo ;
j a v a x . management . MBeanOperationInfo ;
j a v a x . management . M B e a n N o t i f i c a t i o n I n f o ;
j a v a x . management . MBeanServerConnection ;
j a v a x . management . N o t i f i c a t i o n ;
j a v a x . management . N o t i f i c a t i o n L i s t e n e r ;
j a v a x . management . A t t r i b u t e C h a n g e N o t i f i c a t i o n ;
j a v a x . management . remote . JMXServiceURL ;
j a v a x . management . remote . JMXConnector ;
j a v a x . management . remote . JMXConnectorFactory ;

public c l a s s C l i e n t N o t i f {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g h o s t= l o c a l h o s t ;
S t r i n g p o r t= 1099 ;
i f ( a r g s . l e n g t h ==0){

285

286

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

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

20
21

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

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

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

35
36
37
38
39
40

MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


getMBeanResources ( i n f o ) ;

42
43

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

45
46
47
48
49

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

51
52
53
54
55
56
57
58
59
60

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

61
62
63
64
65

66

private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }

68
69

71

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 . ge t O l d V a l u e ( ) . t o S t r i n g ( ) ) ;

72
73
74
75
76
77
78

8.1. STANDARD MBEAN

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

79
80

81
82

287

Serverul MBean este cel prezentat n Exemplul 8.1.5.


Serverul MBean este plasat n servlet (n catalogul WEB-INF/classes al
aplicatiei) iar clientul care urmareste de la distanta se poate afla oriunde.
Dupa instalarea servlet-ului se lanseaza pe masina acestuia server-ul MBean.
Deoarece notificarea presupune existenta MBean-ului, iar acesta se instanteaza
prin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depunand
0 unitati. Dupa aceasta operatie se lanseaza n executie programul ClientNotif.

Intreb
ari recapitulative
1. Ce posibilitate ofera Java Management Extensions (JMX) ?
2. Care este structute unui MBean standard ?
3. Precizati continutul unui server MBean cu agenti la distanta.
4. Precizati termenul de notificare n legatura cu MBean.

288

CAPITOLUL 8. JAVA MANAGEMENT EXTENSIONS

Bibliografie

[1] ATHANASIU I., COSTINESCU B., DRAGOI


O.A., POPOVICI F.I.,
1998, Limbajul Java. O perspectiva pragmatica. Ed. Computer Libris
Agora, Cluj-Napoca.
[2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru
aplicatii Web. Ed. Albastra, Cluj-Napoca.
[3] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicatii. Ed. Albastra, Cluj-Napoca.
[4] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucuresti.
[5] BURAGA S. (ed), 2007, Programarea n Web 2.0., Ed. Polirom, Iasi.
I., 2000, Programarea retelelor de calculatoare. Ed. de Vest,
[6] JURCA
Timisoara.
[7] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming.
OReilly.
[8] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iasi.
[9] SCHEIBER E., 2007, Programare concurenta si paralel distribuita n Java.
Ed. Albastra, Cluj-Napoca.
S., ANDREI S., OLARU C., 2011, Java de la 0 la extert. Ed.
[10] TANASA
Polirom, Iasi.
S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosind
[11] TANASA
Java. Ed. Polirom, Bucuresti.
[12] * * * , Java 2 SDK 1.*.*/docs/, Sun Microsystems.
[13] * * * , JavaWS Tutorial 1.*, Sun Microsystems.
289

290
[14] * * * , J2EE Tutorial 1.5, Sun Microsystems.
[15] * * * , Java 2 Tutorial, Sun Microsystems.

BIBLIOGRAFIE

S-ar putea să vă placă și