Sunteți pe pagina 1din 273

Universitatea Transilvania din Braşov

Facultatea de Matematică–Informatică
Catedra de Informatică Teoretică

ERNEST SCHEIBER

PROGRAMARE DISTRIBUITĂ ÎN


JAVA

Braşov
2
Introducere

Reţelele locale, internetul, răspândirea pe o arie geografică a resurselor şi a


locaţiilor ı̂n care se petrec acţiuni ce ţin de o activitate bine definită sau sunt
urmărite, gestionate din alte locuri au drept consecinţă existenţa aplicaţiilor dis-
tribuite. Termenul distribuit se referă tocmai la faptul că componente ale aplicaţiei
se află pe calculatoare diferite dar ı̂ntre care au loc schimburi de date. Dacă
părţile unei aplicaţii sau resursele utilizate se găsesc pe calculatoare distincte atunci
aplicaţia se numeşte distribuită.
Între părţile sau resursele unei aplicaţii distribuite au loc schimburi de date,
ceea ce se face utilizând diferite mecanisme la realizarea cărora concură sistemul de
calcul, sistemul de operare şi limbajul de programare.
Astfel se vorbeşte de programare distribuită ca mijloc de realizare a aplicaţiilor
distribuite. Pe lângă algoritm, structuri de date, limbaj de programare, la realizarea
unei aplicaţii distribuite intervin comunicaţiile: schimbul de date dintre două com-
ponente aflate pe calculatoare diferite.
Punem ı̂n evidenţă două modele de aplicaţii distribuite:

• client-server: Programul server execută cererile clienţilor. Amintim următoarele


tehnologii Java pentru realizarea aplicaţiilor client-server:

– RMI (Remote Method Invocation)


– CORBA (Common Object Request Brocker Arhitecture)
– JMS (Java Message Service)
– Servlet şi JSP (Java Server Pages)
– Portlet
– Java Web Start
– Java Management Extentions (JMX)

• dispecer-lucrător: Programul dispecer distribuie sarcinile de executat lucrătorilor


şi le coordonează activitatea. Pentru programarea unei aplicaţii bazată pe
modelul dispecer-lucrător se poate utiliza

– un soft ce implementează una din interfeţele:

3
4

∗ PVM (Parallel Virtual Machine)


∗ MPI (Message Passing Interface)
∗ BSP (Bulk Synchronous Parallel)
– produse bazate pe modelul Linda:
∗ TSpaces
∗ JavaSpaces conţinut ı̂n jini.
– Alte abordări:
∗ Java Parallel Distribute Framework (JPPF);
∗ Terracotta;
∗ ProActive;
∗ GridGain.
Lista opţiunilor este departe de a fi completă.
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit
programarea aplicaţiilor client - server:
• socluri Java;
• apelarea metodelor de la distanţă (Remote Method Invocation - RMI );
• CORBA - Common Object Request Brocker Arhitecture;
• mesageria Java;
• servlet;
• Java Server Pages - JSP;
• Portlet şi Portal;
• Java Management Extentions - JMX.
Metodele şi instrumentele de programare vor fi exemplificate pe problema foarte
simplă de calcul a celui mai mare divizor comun a două numere naturale. Codul
metodei de calcul este
1 public long cmmdc( long m, long n ) {
2 long r , c ;
3 do{
4 c=n ;
5 r=m%n ;
6 m=n ;
7 n=r ;
8 }
9 while ( r ! = 0 ) ;
10 return c ;
11 }

Pentru aplicaţiile care utilizează o bază de date, sistemul de gestiune a bazei de


date (SGBD) va fi una dintre sistemele Derby sau mysql.
Cuprins

1 Applet - Miniaplicaţie Java 9


1.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Desfăşurarea unui applet . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Programare cu socluri Java 17


2.1 Aplicaţii client – server . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2 Noţiuni despre reţele . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3.1 Clasa Socket . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.2 Clasa ServerSocket . . . . . . . . . . . . . . . . . . . . . . . 19
2.4 Aplicaţie client – server cu socluri . . . . . . . . . . . . . . . . . . . 20
2.5 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.5.1 Clasa DatagramPacket. . . . . . . . . . . . . . . . . . . . . . 24
2.5.2 Clasa DatagramSocket . . . . . . . . . . . . . . . . . . . . . . 25
2.5.3 Clasa InetAddress . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.4 Aplicaţii client – server cu datagrame. . . . . . . . . . . . . . 29
2.5.5 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . . . . 32
2.6 Canale de comunicaţie . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.6.1 Clasa Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.6.2 Clasa ByteBuffer . . . . . . . . . . . . . . . . . . . . . . . . 37
2.6.3 Clasa InetSocketAddress . . . . . . . . . . . . . . . . . . . . 38
2.6.4 Clasa ServerSocketChannel . . . . . . . . . . . . . . . . . . 38
2.6.5 Clasa SocketChannel . . . . . . . . . . . . . . . . . . . . . . 39
2.6.6 Clasa DatagramChannel . . . . . . . . . . . . . . . . . . . . . 41
2.7 Conexiuni HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

3 Regăsirea obiectelor prin servicii de nume 47


3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . . . . 47

4 Invocarea procedurilor la distanţă 53


4.1 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . . . . 53

5
6 CUPRINS

4.1.1 Crearea unei aplicaţii RMI . . . . . . . . . . . . . . . . . . . 56


4.1.2 Tipare de programare . . . . . . . . . . . . . . . . . . . . . . 61
4.1.3 Obiect activabil la distanţă . . . . . . . . . . . . . . . . . . . 66
4.2 CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.2.1 Conexiunea RMI - CORBA . . . . . . . . . . . . . . . . . . . 72
4.2.2 Aplicaţie Java prin CORBA . . . . . . . . . . . . . . . . . . . 77

5 Mesaje ı̂n Java 85


5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . . . . 85
5.2 Sun Java System Message Queue . . . . . . . . . . . . . . . . . . . . 86
5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.4 Elemente de programare - JMS . . . . . . . . . . . . . . . . . . . . . 88
5.4.1 Trimiterea unui mesaj . . . . . . . . . . . . . . . . . . . . . . 88
5.4.2 Recepţia sincronă a unui mesaj . . . . . . . . . . . . . . . . . 93
5.4.3 Recepţia asincronă a unui mesaj . . . . . . . . . . . . . . . . 95
5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . . 96
5.4.5 Subscrierea şi recepţia mesajelor . . . . . . . . . . . . . . . . 97
5.5 Mesaje SOAP prin Java Message Service . . . . . . . . . . . . . . . . 99
5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.5.3 Ataşamente SOAP . . . . . . . . . . . . . . . . . . . . . . . . 107
5.6 Advanced Message Queue Protocol - Qpid . . . . . . . . . . . . . . . 113

6 Servlet 123
6.1 Marcajul <form> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . . . . 125
6.3 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . . . . 126
6.3.1 Instalarea unui servlet . . . . . . . . . . . . . . . . . . . . . . 126
6.3.2 Compilarea şi apelarea unui servlet . . . . . . . . . . . . . . . 128
6.3.3 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . . . . 129
6.4 Facilităţi de programare cu servlet . . . . . . . . . . . . . . . . . . . 135
6.4.1 Program client al unui servlet . . . . . . . . . . . . . . . . . . 135
6.4.2 Servlete ı̂nlănţuite . . . . . . . . . . . . . . . . . . . . . . . . 138
6.4.3 Sesiune de lucru . . . . . . . . . . . . . . . . . . . . . . . . . 139
6.4.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
6.4.5 Autorizarea accesului prin parola . . . . . . . . . . . . . . . . 143
6.4.6 Servlet cu conexiune la o bază de date . . . . . . . . . . . . . 145
6.4.7 Imagini furnizate de servlet . . . . . . . . . . . . . . . . . . . 147
6.4.8 Servlet cu RMI . . . . . . . . . . . . . . . . . . . . . . . . . . 149
6.4.9 Servlet cu JMS . . . . . . . . . . . . . . . . . . . . . . . . . . 150
6.5 FileUpload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
CUPRINS 7

7 Java Server Page – JSP 159


7.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
7.1.1 Declaraţii JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 164
7.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
7.1.3 Marcaje JSP predefinite . . . . . . . . . . . . . . . . . . . . . 166
7.1.4 Componentă Java (Java Bean) . . . . . . . . . . . . . . . . . 167
7.1.5 Pagini JSP cu componente Java . . . . . . . . . . . . . . . . 168
7.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . . . . 171
7.2.1 Biblioteca de bază . . . . . . . . . . . . . . . . . . . . . . . . 172
7.2.2 Biblioteca de lucru cu baze de date . . . . . . . . . . . . . . . 176
7.3 Marcaje JSP personale . . . . . . . . . . . . . . . . . . . . . . . . . . 178
7.3.1 Marcaje fără atribute şi fără corp. . . . . . . . . . . . . . . . 178
7.3.2 Marcaje cu atribute şi fără corp. . . . . . . . . . . . . . . . . 181
7.3.3 Marcaje cu corp. . . . . . . . . . . . . . . . . . . . . . . . . . 183

8 Portlet 187
8.1 Apache-pluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
8.2 Portlet container JSR 286 . . . . . . . . . . . . . . . . . . . . . . . . 189
8.3 Dezvoltarea unui portlet . . . . . . . . . . . . . . . . . . . . . . . . . 190
8.4 Elemente de programare . . . . . . . . . . . . . . . . . . . . . . . . . 193
8.5 Produse Portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
8.5.1 uPortal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
8.5.2 Jetspeed-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

9 Java Web Start 209


9.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

10 Java Management Extensions 215


10.1 Standard MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
10.1.1 Crearea unui Standard MBean . . . . . . . . . . . . . . . . . 216
10.1.2 Crearea unui MBeanServer . . . . . . . . . . . . . . . . . . . 218
10.1.3 Notificări . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
10.1.4 Agent MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
10.1.5 Invocarea la distanţă . . . . . . . . . . . . . . . . . . . . . . . 225

11 Teme de laborator 239


11.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

A XML 249

B Apache-ant 253
8 CUPRINS

C Utilizarea SGBD ı̂n Java 257


C.1 Derby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
C.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
C.3 PostgrSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
C.4 Şablonul de utilizare ı̂ntr-un program Java . . . . . . . . . . . . . . . 260
C.5 Java Persistence API - JPA . . . . . . . . . . . . . . . . . . . . . . . 264
C.5.1 apache-openjpa . . . . . . . . . . . . . . . . . . . . . . . . . . 264

Bibliografie 273
Capitolul 1

Applet - Miniaplicaţie Java

O categorie deosebită de programe Java ı̂l reprezintă miniaplicaţiile (applet-uri),


care se execută prin intermediul unui program de navigare ı̂n WWW (World Wide
Web) – browser (Mozilla Firefox, Crome, Microsoft InternetExplorer, Opera, Safari.
La apariţia limbajului de programare Java, acest tip de aplicaţie a reprezentat unul
din factorii de impact prin noutatea şi simplitatea soluţiei oferite.
Applet-ul este o resursă program, depusă ı̂ntr-o zona publică, accesibilă prin
Internet (server Web.) Un program de navigare preia codul applet-ului şi ı̂l execută.
Apelarea unui applet se face dintr-un fişier html.
Datorită acestui mod de folosire, applet-urile au o structură specială şi sunt
supuse la reguli stricte de securitate, printre care acela de a nu putea scrie informaţii
pe calculatorul pe care se execută - calculatorul clientului.
Metoda actuală de apelare a unui applet se face prin intermediul protocolu-
lui jnlp (Java Network Launching Protocol). Fişierul html de apelare applet-ului
utilizează o resursă javascript – http://java.com/js/deployJava.js prin care se
evită problemele de compatibilitate cu programul navigator. Această resursă real-
izează descărcarea applet-ului cât şi lansarea ı̂n execuţie. Java trebuie să fie instalat
pe calculatorul client, adică pe care rulează applet-ul.

1.1 Clasa Applet


Clasa Applet extinde clasa java.awt.Panel.
Structura unui applet este

import java.applet.*;
import java.awt.*;

public classNumeClasă extends Applet{


public void init(){

9
10 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

Acţiuni efectuate la instanţierea clasei applet-ului.


}
public void start(){
Acţiuni efectuate la lansarea applet-ului ı̂n execuţie sau la
reı̂ntoarcerea ı̂n pagina applet-ului.
}
public void paint(Graphics g){
Acţiuni efectuate ori de câte ori este necesară redesenarea
ferestrei applet-ului.
}
public void stop(){
Acţiuni efectuate la oprirea applet-ului, ca urmare a
ı̂nchiderii ferestrei corespunzătoare applet-ului.
}
public void destroy(){
Acţiuni efectuate la distrugerea applet-ului, ce au loc când
navigatorul părăseşte documentul html din care s-a apelat
applet-ul.
}
}

Executarea applet-ului este controlat de programul navigator şi revine la apelarea


metodelor init, start, stop. Acest fenomen se numeşte inversarea controlului.

1.2 Desfăşurarea unui applet


Prin desfăşurarea (deployment) unei aplicaţii se ı̂nţelege descrierea structurilor
de cataloage şi fişiere dar şi a operaţiilor care trebuie ı̂ntreprinse ı̂n vederea asigurării
funcţionării unei aplicaţii distribuite.
Desfăşurarea unui applet presupune:

1. Arhivarea fişierelor class ale applet-ului.

2. Editarea unui fişier de configurare având extensia jnlp. Structura acestui


fişier este

<?xml version="1.0" encoding="UTF-8"?>


<jnlp spec="1.0+" codebase="" href="">
<information>
<title>. . .</title>
<vendor>. . .</vendor>
</information>
<resources>
1.2. DESFĂŞURAREA UNUI APPLET 11

<!-- Application Resources -->


<j2se version="1.6+"
href="http://java.sun.com/products/autodl/j2se"
max-heap-size="128m" />

<jar href="numele_arhivei_jar" main="true" />


</resources>
<applet-desc
name="numele_simbolic_al_applet-ului"
main-class="clasa_principala_a_applet-ului"
width="latimea_ferestrei_applet-ului"
height="inaltimea_ferestrei_applet-ului">
</applet-desc>
</jnlp>

3. Editarea fişierului html de apelare a applet-ului. Şablonul specific apelării


applet-ului este

<BODY>
. . .
<script src="http://java.com/js/deployJava.js"></script>
<script>
var attributes={ code:’numele_arhivei_jar’,width:...,height:...};
var parameters={jnlp_href:’numele_fisierului_de_configurare_jnlp’};
deployJava.runApplet(attributes, parameters, ’1.6’);
</script>
. . .
</BODY>

4. Cele trei fişiere se depun ı̂ntr-un catalog al unui server Web, asigurând visibil-
itatea aplicaţiei in internet.
Verificarea aplicaţiei se poate face, dintr-un program navigator, prin simpla
apelare a fişierului html, aflat ı̂n catalogul de lucru. În acest caz, calculatorul
trebuie să fie conectat la internet.

1. HelloWorld. Codul applet-ului este:


1 import j a v a . awt . ∗ ;
2 import j a v a . a p p l e t . ∗ ;

4 public c l a s s I n c e p u t extends Applet {


5 public void i n i t ( ) { }

7 public void p a i n t ( G r a p h i c s g ) {
8 g . d r a w S t r i n g ( ” H e l l o World ! ! ” , 5 0 , 60 ) ;
12 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

9 }
10 }

2. Fişierul de configurare inceput.jnlp


1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 <j n l p s p e c=” 1.0+ ” c o d e b a s e=” ” h r e f=” ”>
3 <i n f o r m a t i o n>
4 < t i t l e>I n c e p u t</ t i t l e>
5 <vendor>T r a n s i l v a n i a U n i v e r s i t y o f Brasov</ vendor>
6 </ i n f o r m a t i o n>
7 <r e s o u r c e s>
8 < !−− A p p l i c a t i o n R e s o u r c e s −−>
9 <j 2 s e version=” 1.6+ ”
10 h r e f=” h t t p : // j a v a . sun . com/ p r o d u c t s / a u t o d l / j 2 s e ”
11 max−heap−s i z e=” 128m” />

13 <j a r h r e f=” i n c e p u t . j a r ” main=” t r u e ” />


14 </ r e s o u r c e s>
15 <a p p l e t −d e s c
16 name=” I n c e p u t Applet ”
17 main−c l a s s=” I n c e p u t ”
18 width=” 300 ”
19 h e i g h t=” 300 ”>
20 </ a p p l e t −d e s c>
21 </ j n l p>

3. Fişierul html de apelare (inceput.html )


1 <HTML>
2 <HEAD>
3 <TITLE> H e l l o </TITLE>
4 </HEAD>
5 <BODY>
6 <s c r i p t src=” h t t p : / / j a v a . com/ j s / d e p l o y J a v a . j s ”></ s c r i p t>
7 <s c r i p t>
8 v a r a t t r i b u t e s = { code : ’ i n c e p u t ’ , width : 3 0 0 , h e i g h t : 3 0 0 } ;
9 var parameters = { j n l p h r e f : ’ inceput . jnlp ’ } ;
10 d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , ’ 1 . 6 ’ ) ;
11 </ s c r i p t>
12 </BODY>
13 </HTML>

Exemplul 1.2.1 Calculul celui mai mare divizor comun a două naturale.

Într-un applet, introducerea datelor din exterior se poate face doar prin inter-
mediul unei interfeţe grafice. Codul sursă este:
1 import j a v a . awt . ∗ ;
2 import j a v a . a p p l e t . ∗ ;
3 import j a v a . awt . e v e n t . ∗ ;

5 public c l a s s Cmmdc extends Applet implements A c t i o n L i s t e n e r {


6 T e x t F i e l d tm , tn , r e z ;
1.2. DESFĂŞURAREA UNUI APPLET 13

8 public void i n i t ( ) {
9 setBackground ( Color . yellow ) ;
10 GridLayout g l=new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ;
11 setLayout ( g l ) ;
12 L a b e l lm=new L a b e l ( ” Primul numar : ” ) ;
13 add ( lm ) ;
14 tm=new T e x t F i e l d ( ” 1 ” , 5 ) ;
15 add ( tm ) ;
16 L a b e l l n=new L a b e l ( ” Al d o i l e a numar : ” ) ;
17 add ( l n ) ;
18 tn=new T e x t F i e l d ( ” 1 ” , 5 ) ;
19 add ( tn ) ;
20 Button compute=new Button ( ” C a l c u l e a z a ” ) ;
21 compute . a d d A c t i o n L i s t e n e r ( t h i s ) ;
22 add ( compute ) ;
23 r e z=new T e x t F i e l d ( ” 1 ” , 5 ) ;
24 rez . setEditable ( false ) ;
25 add ( r e z ) ;
26 }

28 public void p a i n t ( G r a p h i c s g ) {
29 S t r i n g sm=tm . g e t T e x t ( ) ;
30 long m=Long . parseLong ( sm ) ;
31 S t r i n g sn=tn . g e t T e x t ( ) ;
32 long n=Long . parseLong ( sn ) ;
33 long c=cmmdc(m, n ) ;
34 r e z . s e t T e x t ( (new Long ( c ) ) . t o S t r i n g ( ) ) ;
35 }

37 public void a c t i o n P e r f o r m e d ( ActionEvent ae ) {


38 repaint ( ) ;
39 }

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


42 }

O alternativă la modul de apelare al applet-ului descris anterior este dat de


utilizarea elementului html <applet>.

Atributele obligatorii ale unui element applet sunt

• code
Valoarea atributului este numele clasei applet-ului.

• width
Valoarea atributului este lăţimea ferestrei atribuită de navigator applet-ului la
afişarea documentului html.

• height
Valoarea atributului este ı̂nălţimea ferestrei atribuită de navigator applet-ului
la afişarea documentului html.

Atribute opţionale sunt


14 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

• codebase
Valoarea atributului este adresa URL ( Universal Resource Locator) sau calea
la fişierul cu clasa applet-ului. În lipsa acestui parametru, căutarea clasei are
loc ı̂n catalogul din care a fost ı̂ncărcată sursa html.

• vspace
Valoarea atributului este lungimea, exprimată ı̂n pixeli, care se lasă liberă
deasupra şi dedesuptul ferestrei miniaplicaţiei.

• hspace
Valoarea parametrului este lungimea, exprimată ı̂n pixeli, care se lasă liberă
la stânga şi la dreapta ferestrei applet-ului.

În marcajul <applet> prin intermediul elementului <param> pot fi incluşi parametri
ce pot fi preluaţi de applet. Un parametru se defineşte prin atributele:

• name
Valoarea atributului este numele variabilei recunoscut ı̂n applet.

• value
Valoarea atributului este valoarea recepţionat de applet şi este de tip String.
Preluarea se realizează cu metoda

public String getParameter(String name)

Documentul html de apelare al applet-ului Inceput este:


1 <HTML>
2 <HEAD>
3 <TITLE> H e l l o </TITLE>
4 </HEAD>
5 <BODY>
6 <CENTER>
7 <APPLET
8 code = ” Inceput . c l a s s ”
9 width = ” 500 ”
10 height = ” 300 ” >
11 </APPLET>
12 </CENTER>
13 </BODY>
14 </HTML>

Dacă fişierul class al applet-ului nu se află ı̂n acelaşi catalog cu documentul html
atunci localizarea clasei se face cu valoarea atributului codebase =
"file://host/calea către catalogul clasei applet-ului"
Pentru testare, ı̂n locul navigatorului se poate folosi programul appletviewer.exe
din distribuţia jdk.
Elementul applet activează maşina virtuală Java utilizată de programul navi-
gator. Această maşină virtuală s-ar putea să nu fie compatibilă cu maşina virtuală
1.2. DESFĂŞURAREA UNUI APPLET 15

Java de la Sun. Dacă pe calculatorul clientului este instalată distribuţia jdk atunci
documentul html se poate converti astfel ı̂ncât execuţia applet-ului să fie execu-
tată de maşina virtuală Java a distribuţiei jdk. Convertirea se face cu utilitarul
HtmlConverter, din distribuţia jdk.
16 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA
Capitolul 2

Programare cu socluri Java

Limbajul de programare Java oferă facilităţi de elaborare ale unor programe care
utilizează şi interacţionează cu resurse din Internet şi din World Wide Web.
În plus limbajul Java permite utilizarea URL-ului (Universal Resource Locator
– adresa resurselor ı̂n Internet), a soclurilor (socket) şi a datagramelor.

2.1 Aplicaţii client – server


O aplicaţie client – server se compune din:

• componenta server - alcătuită din programe / clase ce asigură una sau mai
multe funcţiuni (servicii), care pot fi apelate de către clienţi.

• componenta client - alcătuită din programe / clase care permit accesul la server
şi apelarea serviciilor acestuia.

Serverul şi clientul (clienţii) rulează, de obicei, pe calculatoare distincte. Un


server trebuie să satisfacă cererile mai multor clienţi.
Durata de viaţă a unei aplicaţii client – server este dată de durata funcţionării
serverului. Această durată poate fi alcătuită din intervale disjuncte de timp, ı̂ntre
acele intervale, din diverse motive, serverul este inactiv.
Intervalul de timp determinat de conectarea unui client la server şi până la
deconectare poartă numele de sesiune. În această perioadă, clientul poate invoca
mai multe servicii ale serverului. Un client poate iniţia mai multe sesiuni.
Un client trebuie să-şi regăsească datele ı̂n cadrul unei sesiuni, ı̂ntre sesiuni, pe
toată durata de viaţă a aplicaţiei. Astfel se pune problema reţinerii datelor pentru
fiecare client ı̂n parte.

17
18 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Autentificare şi autorizare


Uzual, pentru a folosi serviciul unui server, un client trebuie să se ı̂nregistreze,
moment ı̂n care i se stabilesc drepturile de care dispune la utilizarea serviciilor oferite
de server.
La apelarea serverului, clientul este autentificat - adică i se recunoaşte identitatea
- şi apoi i se asigură accesul la servicii ı̂n limita drepturilor pe care le are.

2.2 Noţiuni despre reţele


Calculatoarele ce rulează ı̂n Internet comunică ı̂ntre ele folosind protocolul TCP
(Transport Control Protocol) sau UDP (User Datagram Protocol).
Într-un program Java se utilizează clasele pachetului java.net prin intermediul
cărora se accesează nivelele deservite de protocoalele TCP sau UDP. În felul acesta
se pot realiza comunicaţii independente de platforma de calcul. Pentru a alege care
clasă Java să fie utilizată trebuie cunoscută diferenţa dintre TCP şi UDP.

TCP Când două aplicaţii comunică ı̂ntre ele se stabileşte o conexiune prin in-
termediul căreia se schimbă date. Folosind protocolul TCP, comunicaţia garantează
că datele trimise dintr-un capăt ajung ı̂n celălalt capăt cu păstrarea ordinii ı̂n care
au fost trimise. Acest tip de comunicaţie seamănă cu o convorbire telefonică. TCP
furnizează un canal sigur de comunicaţie ı̂ntre aplicaţii.

UDP Utilizarea protocolului UDP presupune trimiterea unor pachete de date –


numite datagrame – de la o aplicaţie la alta fără să se asigure faptul că datagrame-
leajung la destinaţie şi nici ordinea lor de sosire. Acest tip de comunicaţie seamănă
cu trimiterea scrisorilor prin poştă.

2.3 Soclu TCP


Conexiunile bazate pe URL reprezintă un mecanism de nivel ı̂nalt pentru acce-
sarea resurselor din Internet.
Aplicaţii de tip client – server se pot realiza utilizând comunicaţii de nivel scăzut.
Pentru a comunica utilizând TCP programul client şi programul server stabilesc o
conexiune sigură. Fiecare program se leagă la conexiune printr-un soclu (socket).
Un soclu este capătul unei căi de comunicaţie bidirecţional ı̂ntre două programe
ce rulează ı̂n reţea. Un soclu este legat de un port – prin care nivelul TCP poate
identifica aplicaţia căreia ı̂i sunt transmise datele. Din punct de vedere fizic, un port
este o adresă de memorie cuprinsă ı̂ntre 0 şi 65535.
Pentru a comunica atât clientul cât şi serverul citesc date de la şi scriu date la
soclul legat la conexiunea dintre ele.
2.3. SOCLU TCP 19

În pachetul java.net clasele Socket şi ServerSocket implementează un soclu


din partea clientului şi respectiv din partea serverului.
Clientul cunoaşte numele calculatorului pe care rulează serverul cât şi portul la
care acesta este conectat. Pentru stabilirea conexiunii, clientul ı̂ncearcă un rendez-
vous cu serverul de pe maşina serverului şi la portul serverului. Dacă totul de-
curge bine, serverul acceptă conexiunea. După acceptare, serverul crează pentru
client un nou soclu legat la un alt port ı̂n aşa fel ı̂ncât ascultarea cererilor la soclul
iniţial să poată continua ı̂n timp ce sunt satisfăcute cererile clientului conectat. Din
partea clientului, după acceptarea conexiunii soclul este creat şi este utilizat pentru
comunicaţia cu serverul.

2.3.1 Clasa Socket


Resursele clasei Socket sunt destinate clientului.
Constructori
• public Socket(String host, int port) throws UnknownHostException, IOException
Crează un soclu conectat la calculatorul cu portul specificat.
• public Socket(InetAddress host, int port) throws IOException
Crează un soclu conectat la calculatorul cu portul specificat.
Metode
• public InputStream getInputStream() throws IOException
Returnează un flux de intrare ataşt soclului, pentru citirea (preluarea) informaţiilor
de la soclu.
• public OutputStream getOutputStream() throws IOException
Returnează un flux de ieşire ataşt soclului, pentru scrierea (transmiterea)
informaţiilor la soclu.
• public synchronized void close() throws IOException
ı̂nchide soclul de referinţă.

2.3.2 Clasa ServerSocket


Resursele clasei ServerSocket sunt destinate serverului.
Constructori
• public ServerSocket(int port) throws IOException
Crează un soclu la portul specificat. Dacă port=0, atunci va fi utilizat orice
port disponibil. Capacitatea şirului (tamponului) de aşteptare pentru cererile
de conectare se fizează la valoarea implicită 50. Cererile ı̂n exces vor fi refuzate.
20 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• public ServerSocket(int port, int lung) throws IOException


În plus fixează lungimea şirului (tamponului) de aşteptare.

• public ServerSocket(int port, int lung, InetAddress adr )


throws IOException
Se specifică ı̂n plus calculatorul de la care se aşteaptă cereri. Dacă adr =null,
atunci se acceptă cereri de la orice calculator.

Metode

• public Socket accept() throws IOException


Metoda blochează procesul (firul de execuţie) apelant până la sosirea unei
cereri de conectare şi crează un soclu client prin care se va desfăşura comuni-
carea cu solicitantul acceptat.

• public synchronized void close() throws IOException


ı̂nchide soclul de referinţă.

2.4 Aplicaţie client – server cu socluri


Serverul trebuie să satisfacă simultan solicitările mai multor clienţi. Fiecare
client apelează programul server la acelaşi port şi ı̂n consecinţă cererile de conectare
sunt recepţionate de acelaşi ServerSocket. Serverul recepţionează apelurile secvenţial.
La un apel, se crează de partea severului un soclu prin care se va face schimbul de
date cu clientul. Cererile clienţilor pot fi satisface concurent/paralel, utilizând fire
de execuţie ce implementează serviciul oferit sau secvenţial - ı̂n cazul unor servicii
de durată scurtă.

Exemplul 2.4.1 Sistem client - server pentru calculul celui mai mare divizor comun
a două numere naturale. Portul obiectului de tip ServerSocket este 7999.

Programul client CmmdcClient se conectează la server, transmite serverului


cele două numere naturale şi recepţionează rezultatul pe care apoi ı̂l afişează.
În esenţă orice program client trebuie să execute:

1. Deschide/crează un soclu.

2. Deschide/crează fluxuri de date pentru comunicaţia cu serverul.

3. Transmite şi recepţionează date potrivit specificului aplicaţiei (protocolului


serverului). Acest pas variază de la un program client la altul.

4. Închiderea fluxurilor de date.


2.4. APLICAŢIE CLIENT – SERVER CU SOCLURI 21

5. Închiderea soclului.

1 import j a v a . i o . ∗ ;
2 import j a v a . n e t . ∗ ;
3 import j a v a . u t i l . Sca nner ;

5 public c l a s s CmmdcClient {
6 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException {
7 S t r i n g h o s t=” l o c a l h o s t ” ;
8 i n t p o r t =7999;
9 i f ( a r g s . l e n g t h >0)
10 h o s t=a r g s [ 0 ] ;
11 i f ( a r g s . l e n g t h >1)
12 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
13 S o c k e t cmmdcSocket = n u l l ;
14 DataInputStream i n=n u l l ;
15 DataOutputStream out=n u l l ;

17 try {
18 cmmdcSocket = new S o c k e t ( hos t , p o r t ) ;
19 out=new DataOutputStream ( cmmdcSocket . getOutputStream ( ) ) ;
20 i n=new DataInputStream ( cmmdcSocket . g e t I n p u t S t r e a m ( ) ) ;
21 }
22 catch ( E x c e p t i o n e ) {
23 System . e r r . p r i n t l n ( ” 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 ( ) ) ;
24 System . e x i t ( 1 ) ;
25 }

27 Sc anner s c a n n e r=new Sc anner ( System . i n ) ;


28 long m, n , r ;
29 System . out . p r i n t l n ( ”m=” ) ;
30 m=s c a n n e r . nextLong ( ) ;
31 System . out . p r i n t l n ( ”n=” ) ;
32 n=s c a n n e r . nextLong ( ) ;

34 try {
35 out . w r i t e L o n g (m) ;
36 out . w r i t e L o n g ( n ) ;
37 r=i n . readLong ( ) ;
38 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;
39 }
40 catch ( IOException e ) {
41 System . e r r . p r i n t l n ( ” Comunication e r r o r ”+e . g e t M e s s a g e ( ) ) ;
42 }

44 out . c l o s e ( ) ;
45 in . close ( ) ;
46 cmmdcSocket . c l o s e ( ) ;
47 }
48 }

Se presupune că programul server rulează pe calculatorul local şi utilizează portul
7999. Dacă aceşti parametri se modifică - de exemplu serverul rulează ı̂n reţea pe
calculatorul atlantis la portul 8200 - atunci la apelare transmitem aceşti parametri
prin java CmmdcClient atlantis 8200
Partea server este alcătuită din mai multe clase:
22 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• Clasa MyMServer, independentă de un serviciu anume, preia apelurile clienţilor


şi lansează satisfacerea cererii.
1 import j a v a . n e t . ∗ ;
2 import j a v a . i o . ∗ ;

4 public c l a s s MyMServer {
5 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException {
6 i n t p o r t =7999;
7 boolean l i s t e n i n g=true ;
8 ServerSocket s e r v e r S o c k e t = null ;
9 try {
10 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 ) ;
11 }
12 catch ( IOException e ) {
13 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 ) ;
14 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
15 System . e x i t ( 1 ) ;
16 }

18 while ( l i s t e n i n g )
19 // v a r i a n t a 1
20 new AppThread ( s e r v e r S o c k e t . a c c e p t ( ) ) . s t a r t ( ) ;
21 // v a r i a n t a 2
22 /∗
23 {
24 S o c k e t s o c k e t=s e r v e r S o c k e t . a c c e p t ( ) ;
25 try {
26 DataOutputStream o u t=
27 new DataOutputStream ( s o c k e t . g e t O u t p u t S t r e a m ( ) ) ;
28 DataInputStream i n=
29 new DataInputStream ( s o c k e t . g e t I n p u t S t r e a m ( ) ) ;
30 l o n g m=0,n=0, r ;
31 App app=new App ( ) ;
32 m=i n . readLong ( ) ;
33 n=i n . readLong ( ) ;
34 r=app . cmmdc(m, n ) ;
35 out . writeLong ( r ) ;
36 out . c l o s e ( ) ;
37 in . c l o s e ( ) ;
38 socket . close ();
39 }
40 c a t c h ( IOException e ) {
41 System . e r r . p r i n t l n (” S e r v e r c o m u n i c a t i o n e r r o r : ”+
42 e . getMessage ( ) ) ;
43 }
44 }
45 ∗/
46 serverSocket . close ( ) ;
47 }
48 }

În ciclul while, la recepţia unei solicitări de conexiune se crează şi se lansează
un fir de execuţie a cărei metodă run conţine acţiunile ce răspund solicitării.
O soluţie mai eficientă este utilizarea unui bazin de fire de execuţie:

static final int NTHREADS=100;


2.4. APLICAŢIE CLIENT – SERVER CU SOCLURI 23

static ExecutorService exec=Executors.newFixedThreadPool(NTHREADS);


. . .
while(listening){
AppThread obj=new AppThread(serverSocket.accept());
exec.execute(obj);
}
. . .

• Clasa AppTread - fir de execuţie responsabil de preluarea datelor şi de trans-


mitere a rezultatului.
1 import j a v a . n e t . ∗ ;
2 import j a v a . i o . ∗ ;

4 public c l a s s AppThread extends Thread {


5 S o c k e t s o c k e t=n u l l ;

7 public AppThread ( S o c k e t s o c k e t ) {
8 t h i s . s o c k e t=s o c k e t ;
9 }

11 public void run ( ) {


12 try {
13 DataOutputStream out=new DataOutputStream ( s o c k e t . getOutputStream ( ) ) ;
14 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 ( ) ) ;
15 long m=0 ,n=0 , r ;
16 App app=new App ( ) ;
17 m=i n . readLong ( ) ;
18 n=i n . readLong ( ) ;
19 r=app . cmmdc(m, n ) ;
20 out . w r i t e L o n g ( r ) ;
21 out . c l o s e ( ) ;
22 in . close ( ) ;
23 socket . close ( ) ;
24 }
25 catch ( IOException e ) {
26 System . e r r . p r i n t l n ( ” S e r v e r c o m u n i c a t i o n e r r o r : ”+e . g e t M e s s a g e ( ) ) ;
27 }
28 }
29 }

• Clasa App corespunzătoare calcului celui mai mare divizor comul a două nu-
mere naturale.
1 public c l a s s App{
2 public long cmmdc( long m, long n ) { . . . }
3 }

Rularea programelor. Se porneşte la ı̂nceput programul server MyMServer


iar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculator al
reţelei. Dacă programul client se execută pe alt calculator decât cel pe care rulează
programul server, atunci la apelarea clientului trebuie precizat numele calculatorului
server şi eventual portul utilizat.
24 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.5 Datagrame
Pentru utilizarea datagramelor pachetul java.net pune la dispoziţie clasele
• DatagramSocket

• DatagramPacket

• MulticastSocket
O aplicaţie trimite şi recepţionează pachete DatagramPacket prin intermediul
unui DatagramSocket. Un pachet DatagramPacket poate fi trimis la mai mulţi
destinatari prin intermediul unui MulticastSocket.
Reamintim că o datagramă este un mesaj trimis prin reţea a cărei sosire nu este
garantat iar momentul de sosire este neprecizat.

2.5.1 Clasa DatagramPacket.


Trimiterea unui pachet UDP necesită crearea unui obiect
DatagramPachet care conţine corpul mesajului şi adresa destinaţiei. Apoi acest
obiect DatagramPacket poate fi pus ı̂n reţea ı̂n vederea trimiterii sale. Pri- mirea
unui pachet UDP necesită crearea unui obiect DatagramPacket şi apoi acceptarea
unui pachet UDP din reţea. După primire, se poate extrage din obiectul DatagramPacket
adresa sursă şi conţinutul mesajului.
Constructori
Există doi constructori pentru datagrame UDP. Primul constructor este folosit
pentru primirea de pachete şi necesită doar furnizarea unei memorii tampon, iar
celălalt este folosit pentru trimiterea de pachete necesită şi specificarea adresei.
• DatagramPacket(byte[ ] buffer ,int lung)
Acest contructor este folosit pentru primirea pachetelor. Un pachet se memo-
rează ı̂n tamponul buffer având lung octeţi. Dacă lungimea pachetului depăşeşte
această lungime, atunci pachetul este trunchiat iar octeţii ı̂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 conţinut ı̂n tamponul buffer având lung octeţi. Pa-
chetul va fi trimis către adresa şi portul specificat. Trebuie să existe un server
UDP care ascultă la portul specificat pentru trimiterea pachetelor. Un server
UDP şi un server TCP care ascultă acelaşi port pot coexista.
Metode
• InetAddress getAddress()
returnează adresa IP a pachetului.
2.5. DATAGRAME 25

• int getPort()
returnează portul.

• byte[] getData()
returnează conţinutul pachetului.

• int getLength()
returnează lungimea pachetului.

• void setAddress(InetAddress adresa)


fixează adresa IP a pachetului.

• void setPort(int port)


fixează portul.

• void setData(byte[] buffer )


fixează conţinutul pachetului.

• void setLength(int lung)


fixează lungimea pachetului.

2.5.2 Clasa DatagramSocket


Această clasă se foloseşte atât pentru trimiterea, cât şi pentru primirea obiectelor
DatagramPacket. Un obiect DatagramSocket ascultă la un port cuprins ı̂ntre 1
şi 65535 (porturile cuprinse ı̂ntre 1 şi 1023 sunt rezervate pentru aplicaţiile sis-
tem). Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect
DatagramSocket pentru trimiterea pachetelor către diferite destinaţii şi primirea
pachetelor de la diferite surse.
Constructori

• DatagramSocket() throws SocketException


Crează un obiect DatagramSocket cu un număr de port aleator;

• DatagramSocket(int port) throws SocketException


Crează un obiect DatagramSocket cu numărul de port specificat;

• DatagramSocket(int port, InetAddress adresă) throws SocketException


Crează un obiect DatagramSocket cu numărul de port specificat la adresa
specificată;
26 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Metode
Clasa DatagramSocket conţine metode pentru trimiterea şi primirea de obiecte
DatagramPacket, ı̂nchiderea soclului, determinarea informaţiilor adresei locale şi
setarea timpului de primire.

• void send(DatagramPacket pachet) throws IOException


Trimite pachetul prin reţea. Dacă se trimit pachete la o destinaţie necunoscută
sau care nu ascultă, ı̂n cele din urmă se generează o excepţie IOException.
• void receive(DatagramPacket pachet) throws IOException
Metoda primeşte un singur pachet UDP ı̂n obiectul pachet specificat. Apoi,
pachetul poate fi inspectat pentru determinarea adresei IP sursă, portul sursă
şi lungimea mesajului. Execuţia metodei este blocată până când se primeşte
cu succes un pachet sau se scurge timpul de aşteptare.
• InetAddress getLocalAddress()
Returnează adresa locală către care este legat acest DatagramSocket;
• int getLocalPort()
Returnează numărul de port unde ascultă DatagramSocket.
• void close()
Închide DatagramSocket.
• void setSoTimeout(int timpDeAşteptere) throws SocketException
Metoda fixează timpul de aşteptare (ı̂n milisecunde) a soclului. Metoda receive()
se va bloca pentru timpul de aşteptare specificat pentru primirea unui pachet
UDP, după care va arunca o excepţie Interrupted Exception. Dacă valoarea
parametrului este 0, atunci soclul este blocat.
• int getSoTimeout() throws SocketException
Returnează timpul de aşteptare.
• void setSendBufferSize(int lungime) throws SocketException
Fixează lungimea tamponului de trimitere a soclului la valoarea specificată.
Mesaj UDP de lungime mai mare de această valoare nu pot fi trimis.
• int getSendBufferSize() throws SocketException
Returnează lungimea tamponului de trimitere a soclului.
• void setReceiveBufferSize(int lungime) throws SocketException
Fixează lungimea tamponului de primire a soclului la valoarea specificată.
Mesaj UDP de lungime mai mare de această valoare nu pot fi primit.
2.5. DATAGRAME 27

• int getReceiveBufferSize() throws SocketException


Returnează lungimea tamponului de primire a soclului.

• void connect(InetAddress adresa, int port) throws SocketException


Conectează soclul la adresa şi portul specificat. Această metodă nu este cerută
pentru operaţiile uzuale UDP.

• void disconnect()
Deconectează soclul conectat.

• InetAddress getInetAddress()
Returnează obiectul InetAddress către care este conectat soclul sau null dacă
acesta nu este conectat.

• int getPort()
Returnează portul la care este conectat soclul sau -1 dacă acesta nu este conec-
tat.

2.5.3 Clasa InetAddress


Datele pot fi trimise prin reţea indicând adresa IP corespunzătoare maşinii
destinaţie. Clasa InetAddress furnizează acces la adresele IP.
Nu există constructori pentru această clasă. Instanţele trebuie create folosind
metodele statice:

• InetAddress getLocalHost() throws UnknownHostException


Returnează un obiect InetAddress corespunzător maşinii locale.

• InetAddress getByName(String host) throws UnknownHostException


Returnează un obiect InetAddress corespunzător maşinii 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
Returnează un şir de obiecte InetAddress corespunzător fiecărei adrese IP a
maşinii host.

Metodele clasei InetAddress

• byte [ ] getAddress()
Returnează şirul de octeţi corespunzător obiectului InetAddress de referinţă.
28 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• String getHostName()
Returnează numele maşinii gazdă.

• String getHostAddress()
Returnează adresa IP a maşinii gazdă.

• boolean isMulticastAddress()
Returnează true dacă obiectul InetAddress reprezintă o adresă IP multicast
(primul octet cuprins ı̂ntre 224 şi 239).

Exemplul următor afişează numele şi adresa calculatorului gazdă cât şi acela al
calculatoarelor ale căror nume este transmis programului ca parametru.

Exemplul 2.5.1

1 import j a v a . n e t . ∗ ;

3 public c l a s s AdreseIP {
4 public s t a t i c void main ( S t r i n g a r g [ ] ) {
5 I n e t A d d r e s s a d r e s a=n u l l ;
6 try {
7 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 ( ) ;
8 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 : ” ) ;
9 System . out . p r i n t l n ( ” numele : ”+a d r e s a . getHostName ( ) ) ;
10 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 ( ) ) ;
11 }
12 catch ( UnknownHostException e ) {
13 System . out . p r i n t l n ( ” UnknownHostException : ”+e . g e t M e s s a g e ( ) ) ;
14 }
15 i f ( a r g . l e n g t h >0){
16 f o r ( i n t i =0; i <a r g . l e n g t h ; i ++){
17 try {
18 a d r e s a=I n e t A d d r e s s . getByName ( a r g [ i ] ) ;
19 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 : ” ) ;
20 System . out . p r i n t l n ( ” a d r e s a IP \” getByName \” : ”+a d r e s a ) ;
21 byte [ ] b=a d r e s a . g e t A d d r e s s ( ) ;
22 f o r ( i n t j =0; j <b . l e n g t h ; j ++)
23 i f ( b [ j ] <0)
24 System . out . p r i n t (256+b [ j ]+ ” . ” ) ;
25 else
26 System . out . p r i n t ( b [ j ]+ ” . ” ) ;
27 System . out . p r i n t l n ( ) ;
28 }
29 catch ( UnknownHostException e ) {
30 System . out . p r i n t l n ( ” UnknownHostException : ”+
31 e . getMessage ( ) ) ;
32 }
33 }
34 }
35 }
36 }
2.5. DATAGRAME 29

2.5.4 Aplicaţii client – server cu datagrame.


Un pachet de tip DatagramPacket este alcătuit dintr-un şir de octeţi. Este da-
toria programatorului să transforme datele (mesajul) ı̂n şiruri de octeţi la expediere
şi la recepţie.
Transformarea unui obiect serializabil ı̂ntr-un şir de octeţi şi invers se poate
realiza cu schema
Object Object
? 6
ObjectOutputStream ObjectInputStream
? 6
ByteArrayOutputStream ByteArrayInputStream
? 6
output - DatagramPacket input - DatagramPacket
? 6

Fie socket un obiect de tip DatagramSocket prin intermediul căruia se execută


expedierea / recepţionarea pachetelor de tip DatagramPacket.
În principiu expedierea şi transformarea obiectului obj ı̂ntr-un şir de octeţi se
poate realiza cu secvenţa de cod

ByteArrayOutputStream baos=new ByteArrayOutputStream(256);


ObjectOutputStream out=new ObjectOutputStream(baos);
out.writeObject(p);
byte[] bout=baos.toByteArray();

DatagramPacket packet=new DatagramPacket(bout,bout.length,


address,port);
socket.send(packet);

unde address şi port sunt adresa şi portul utilizat de expeditorul mesajului. Dacă
packet este un obiect DatagramPacket recepţionat atunci metodele getAddress()
şi getPort() furnizează adresa şi portul expeditorului
Recepţionarea şi transformarea inversă 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();
30 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Dacă mesajul este un obiect String atunci el se transformă ı̂ntr-un şir de octeţi
cu metoda byte[] String.getByte() şi invers, el se obţine prin new String(bin)
sau new String(packet.getData()).

Exemplul 2.5.2 Programăm serviciul calculului celui mai mare divizor comun a
două numere.

În vederea transportului definim clasa

1 import j a v a . i o . ∗ ;

3 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 {
4 long x , y ;
5 P r o t o c o l ( long x , long y ) {
6 t h i s . x=x ;
7 t h i s . y=y ;
8 }
9 }

Clientul va trimite un obiect Protocol, care va conţine datele problemei şi va


recepţiona un obiect de acelaşi tip cu rezultatul (cel mai mare divizor comun) ı̂n
primul câmp al obiectului.
Programul client este

1 import j a v a . n e t . ∗ ;
2 import j a v a . i o . ∗ ;
3 import j a v a . u t i l . Sca nne r ;

5 public c l a s s ClientCmmdc {
6 public s t a t i c void main ( S t r i n g [ ] args ){

8 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 ” ;
9 i n t p o r t S e r v e r =7999;
10 i f ( a r g s . l e n g t h >0)
11 h o s t S e r v e r=a r g s [ 0 ] ;
12 i f ( a r g s . l e n g t h >1)
13 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 ] ) ;
14 try {
15 // Crearea unui s o c l u Datagramsocket
16 DatagramSocket s o c k e t=new DatagramSocket ( ) ;

18 // Formarea m e s a j u l u i
19 P r o t o c o l p=new P r o t o c o l ( 0 , 0 ) ;
20 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
21 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 : ” ) ;
22 p . x=s c a n n e r . nextLong ( ) ;
23 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 : ” ) ;
24 p . y=s c a n n e r . nextLong ( ) ;

26 // Transformarea m e s a j u l u i i n t r −un s i r de o c t e t i

28 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;


29 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;
30 out . w r i t e O b j e c t ( p ) ;
2.5. DATAGRAME 31

31 byte [ ] bout=baos . toByteArray ( ) ;

33 // E x p e d i e r e a m e s a j u l u i

35 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 ) ;
36 DatagramPacket p a c k e t=new
37 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 ) ;
38 s o c k e t . send ( p a c k e t ) ;

40 // A s t e p t a r e a r a s p u n s u l u i

42 byte [ ] b i n=new byte [ 2 5 6 ] ;


43 p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ;
44 socket . r e c e i v e ( packet ) ;

46 // P r e l u c r a r e a r a s p u n s u l u i

48 ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ;


49 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 ) ;
50 p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ;
51 System . out . p r i n t l n ( ”Cmmdc = ”+p . x ) ;

53 socket . close ( ) ;
54 }
55 catch ( E x c e p t i o n e ) {
56 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
57 }
58 }
59 }

Programul server este

1 import j a v a . n e t . ∗ ;
2 import j a v a . i o . ∗ ;

4 public c l a s s ServerCmmdc{
5 public s t a t i c void main ( S t r i n g [ ] args ){

7 DatagramSocket s o c k e t=n u l l ;
8 i n t s e r v e r P o r t =7999;
9 try {
10 // Crearea unui s o c l u DatagramSocket

12 s o c k e t=new DatagramSocket ( s e r v e r P o r t ) ;

14 }
15 catch ( E x c e p t i o n e ) {
16 System . out . p r i n t l n ( ” DatagramSocket−e r r o r −”+e . g e t M e s s a g e ( ) ) ;
17 System . e x i t ( 0 ) ;
18 }

20 // A c t i v i t a t e a s e r v e r u l u i

22 boolean l i s t e n i n g=true ;
23 DatagramPacket p a c k e t=n u l l ;
24 App app=new App ( ) ;
25 P r o t o c o l p=n u l l ;

27 while ( l i s t e n i n g ) {
32 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

28 try {

30 // R e c e p t i o n a r e a unui mesaj

32 byte [ ] b i n=new byte [ 2 5 6 ] ;


33 p a c k e t=new DatagramPacket ( bin , b i n . l e n g t h ) ;
34 socket . r e c e i v e ( packet ) ;

36 // P r e l u c r a r e a d a t e l o r

38 ByteArrayInputStream b a i s=new ByteArrayInputStream ( b i n ) ;


39 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 ) ;
40 p=( P r o t o c o l ) i n . r e a d O b j e c t ( ) ;

42 // R e z o l v a r e a c e r e r i i clientului

44 p . x=app . cmmdc( p . x , p . y ) ;
45 p . y =0;

47 // Transformarea m e s a j u l u i de r a s p u n s i n t r −un s i r de o c t e t i

49 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;


50 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;
51 out . w r i t e O b j e c t ( p ) ;
52 byte [ ] bout=baos . toByteArray ( ) ;

54 // E x p e d i e r e a m e s a j u l u i n e c e s i t a c u n o a s t e r e a e x p e d i t o r u l u i

56 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 ( ) ;
57 i n t p o r t=p a c k e t . g e t P o r t ( ) ;
58 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 ) ;
59 s o c k e t . send ( p a c k e t ) ;
60 }
61 catch ( E x c e p t i o n e ) {
62 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
63 }
64 }
65 socket . close ( ) ;
66 }
67 }

Clasa App este cea utilizată la exemplul cu socluri TCP.

2.5.5 Clasa MulticastSocket


Multicast vs. Broadcast
Prin intermediul unui soclu de tip MulticastSocket se pot recepţiona datagrame
expediate de un server către toţi clienţii cu un asemenea soclu.

Constructori

• MulticastSocket(int port) throws SocketException

Metode

• void joinGroup(InetAddress adresă) throws SocketException


2.5. DATAGRAME 33

Soclul se ”conectează” la grupul definit de adresa IP (de tip D, adică cuprins


ı̂ntre 224.0.0.0 şi 239.255.255.255).

• void leaveGroup(InetAddress adresă) throws SocketException


Soclul se ”deconectează” la grupul definit de adresa IP.

• void close()

Pregătirea clientului ı̂n vederea recepţionării datagramelor printr-un soclu de tip


MulticastSocket constă din

MulticastSocket socket= new MulticastSocket(port);


InetAddress adresa=InetAddress.getByName("230.0.0.1");
socket.joinGroup(adresa);

În final, clientul se deconectează şi ı̂nchide soclul.

socket.leaveGroup(adresa);
socket.close();

Pachetele trimise de programul server trebuie să se adreseze grupului, identificat


prin adresa IP de tip D.
Astfel prin multicast serverul trimite pachete la o adresă de grup şi la un port
fixat. Pachetele emise de server sunt recepţionate de orice client ce crează un soclu de
tip MulticastSocket pentru portul la care emite serverul şi care se alătură grupului.
Prin broadcast serverul emite datagrame către orice calculator al reţelei locale
la un anumit port. Faptul că emiterea datagramelor este de tip broadcast se indică
prin

DatagramSocket.setBroadcast(true)

Orice client care ı̂şi crează un soclu la portul la care emite serverul recepţionează
datagramele trimise de server. Adresa utilizată de server la crearea datagramelor
trebuie să identifice reţeaua.
Observaţie. În cazul unui calculator ”izolat” este nevoie de instalarea driverului
Microsoft Loopback Adapter, care simulează existenţa unei plăci de reţea active.

Exemplul 2.5.3 Multicast şi Broadcast: programele server emit din cinci ı̂n
cinci secunde ora exactă. Un client va recepţiona câte cinci datagrame.

Codurile sunt date ı̂n Fig. 2.1 şi Fig. 2.2, respectiv pentru partea de server şi
cea de client.
34 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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

public class MulticastServer{ public class BroadcastServer{


public static void main(String[] args){ public static void main(String[] args){
long FIVE_SECONDS = 5000; long FIVE_SECONDS = 5000;
boolean sfarsit=false; boolean sfarsit=false;
DatagramSocket socket = null; DatagramSocket socket = null;
int serverPort=7000; int serverPort=7000;
int clientPort=7001; int clientPort=7001;
byte[] buf = new byte[256]; byte[] buf = new byte[256];
Date data=null; Date data = null;
DatagramPacket packet = null; DatagramPacket packet = null;
try{ try{
socket=new DatagramSocket(serverPort); socket=new DatagramSocket(serverPort);
} }
catch(SocketException e){ catch(SocketException e){
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
while (! sfarsit){ while (! sfarsit) {
try{ try{
data=new Date(); data=new Date();
String df=DateFormat. String df=DateFormat.
getTimeInstance().format(data); getTimeInstance().format(data);
buf = df.getBytes(); buf = df.getBytes();
// send it
InetAddress group = InetAddress group =
InetAddress.getByName("230.0.0.1"); InetAddress.getByName("192.168.0.255");
packet=new DatagramPacket(buf, packet=new DatagramPacket(buf,
buf.length,group,clientPort); 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) { catch (Exception e) {
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
} }
socket.close(); socket.close();
} }
} }

Table 2.1: Clasele server.


2.5. DATAGRAME 35

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

public class MulticastClient { public class BroadcastClient {

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

Table 2.2: Clasele client.


36 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.6 Canale de comunicaţie


Odată cu versiunea j2sdk1.4 apar clase noi pentru operaţii de intrare - ieşire ı̂n
pachetele java.nio şi java.nio.channels. Pachetul java.nio.channels conţine
clase pentru comunicaţia ı̂n reţea, şi anume canalele de comunicaţie.
Informaţia transportată printr-un canal de comunicaţie trebuie ı̂nglobată ı̂n
obiecte container de tip Buffer.

2.6.1 Clasa Buffer


Ierarhia claselor Buffer

abstract Buffer
ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer

Un obiect de tip typeBuffer este un tampon (container) care conţine date de


tipul specificat de denumirea clasei.
Un obiect de tip Buffer este caracterizat de

• capacitate (capacity) numărul elementelor care pot fi ı̂nmagazitate ı̂n tampon;

• limită (limit) marginea superioră a indicelui;

• indice (position) valoarea curentă a indicelui, ce corespunde unui cursor ce


indică ı̂nceputul zonei unde se introduc sau de unde se extrag date din tampon.

Metode generale

• clear() permite unui obiect de tip Buffer să fie reı̂ncărcat. Fixează limita =
capacitate şi indice = 0.

• flip() pregăteşte obiectul de tip Buffer pentru consultare (citire). Fixează


limita =numărul elementelor din tampon şi indice = 0.

• rewind() pregăteşte obiectul de tip Buffer pentru re-citire.


2.6. CANALE DE COMUNICAŢIE 37

2.6.2 Clasa ByteBuffer


Instanţierea unui obiect se obţine prin fabrica

static ByteBuffer allocate(capacitate)

Introducerea şi extragerea datelor din tampon se poate face ı̂ mod

• relativ - implică modificarea indicelui tamponului;

• absolut - fară modificarea indicelui.

Metode
Introducerea datelor ı̂n mod relativ:

• ByteBuffer put(byte b)

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


Dacă indicele nu este egal cu limita atunci returnează true, semnalând existenţa
ı̂n tampon a unor octeţi.

• static ByteBuffer wrap(byte[] array)

• public static ByteBuffer wrap(byte[] array,int offset,int length)


Converteşte şirul de octeţi ı̂ntr-un obiect Bytebuffer.
38 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• public final byte[] array()


Transformarea inversă, obiectul ByteBuffer este convertit ı̂ntr-un şir de octeţi.

Un obiect de tip ByteBuffer se poate percepe ca un obiect de tip LongBuffer,


DoubleBuffer, etc prin

ByteBuffer bb=ByteBuffer.allocate(10);
LongBuffer lb=bb.asLongBuffer();
DoubleBuffer db=bb.asDoubleBuffer();

2.6.3 Clasa InetSocketAddress


Clasa InetSocketAddress ı̂ncapsulează adresa unui calculator din Internet ı̂mpreună
cu un port ı̂n vederea legării la un ServerSocket, extinzând clasa SocketAddress.
Constructori:

• InetSocketAddress(InetAddress addr ,int port)

• InetSocketAddress(String numeCalculator ,int port)

2.6.4 Clasa ServerSocketChannel


Crearea unui obiect de tip ServerSocketChannel se realizează prin

static ServerSocketChannel open() throws IOException

Unui asemenea obiect i se asociază un ServerSocket prin metoda

ServerSocket socket() throws IOException.

Obiectul de tip ServerSocket trebuie leagat la un port de comunicaţie prin metoda

void bind(InetSocketAddress endpoint) throws IOException.

Şablonul de utilizare este

try{
ServerSocketChannel ssc=ServerSocketChannel.open();
ServerSocket ss=ssc.socket();
InetSocketAddress isa=new InetSocketAddress(addr,port);
ss.bind(isa);
}
catch(Exception e){. . .}

La apelul unui client, serverul trebuie să genereze un obiect de tip Socket
Channel prin care se vor derula comunicaţiile cu clientul. Acest canal de comunicaţie
se obţine cu metoda accept().
2.6. CANALE DE COMUNICAŢIE 39

2.6.5 Clasa SocketChannel


Crearea unui obiect de tip SocketChannel se realizează prin
static SocketChannel open() throws IOException
Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului cu
metoda connect(InetSocketAddress addr ).
Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datele se
transmit prin metoda
int write(ByteBuffer sursă)
şi se recepţionează prin metoda
int read(ByteBuffer destinaţie)
Valoarea returnată de cele două metode reprezintă numărul octeţilor trimişi /
recepţionaţi.
Doar octeţii unui obiect de tip ByteBuffer cuprinşi ı̂ntre indice şi limită sunt
transmişi prin canal. Astfel, după ı̂ncărcarea unui obiectului ByteBuffer cu metode
relative trebuie apelată metoda flip().
Canalul se ı̂nchide cu metoda close().

Exemplul 2.6.1 Calculul celui mai mare divizor comun a două numere naturale.

Aplicaţie client-server bazat pe canale de comunicaţie prin socluri are programul


server
1 import java . io . ∗ ;
2 import java . net . ∗ ;
3 import java . nio . ∗ ;
4 import java . nio . channels . ∗ ;
5 import java . u t i l . ∗ ;

7 public c l a s s SocketChannelCmmdcServer {

9 private s t a t i c void s e r v i c i u ( S e r v e r S o c k e t C h a n n e l s s c ) {
10 S o ck e t Ch a n ne l s c = n u l l ;
11 try {
12 s c=s s c . a c c e p t ( ) ;
13 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 ) ;
14 // 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 ( ) ;
15 s c . r e a d ( bb ) ;
16 // V a r i a n t a 1
17 long m=bb . getLong ( 0 ) ;
18 long n=bb . getLong ( 8 ) ;
19 // V a r i a n t a 2
20 // l o n g m=l b . g e t ( 0 ) ;
21 // l o n g n=l b . g e t ( 1 ) ;
22 App app=new App ( ) ;
23 long r=app . cmmdc(m, n ) ;
24 bb . c l e a r ( ) ;
40 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

25 // V a r i a n t a 1
26 bb . putLong ( 0 , r ) ;
27 // V a r i a n t a 2
28 // l b . p u t ( r ) ;
29 s c . w r i t e ( bb ) ;
30 sc . clos e ( ) ;
31 }
32 catch ( E x c e p t i o n e ) {
33 System . out . p r i n t l n ( ” S e r v e r e r r o r : ”+e . g e t M e s s a g e ( ) ) ;
34 }
35 }

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


38 i n t p o r t =7999;
39 S e r v e r S o c k e t C h a n n e l s s c=n u l l ;
40 try {
41 s s c = S e r v e r S o c k e t C h a n n e l . open ( ) ;
42 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 ) ;
43 S e r v e r S o c k e t s s=s s c . s o c k e t ( ) ;
44 s s . bind ( i s a ) ;
45 }
46 catch ( IOException e ) {
47 System . out . p r i n t l n ( ” S e r v e r S o c k e t C h a n n e l E r r o r : ”+e . g e t M e s s a g e ( ) ) ;
48 System . e x i t ( 0 ) ;
49 }
50 System . out . p r i n t l n ( ” S e r v e r r e a d y . . . ” ) ;
51 while ( true ) {
52 serviciu ( ssc );
53 }
54 }
55 }

şi clientul
1 import java . io . ∗ ;
2 import java . net . ∗ ;
3 import java . nio . ∗ ;
4 import java . nio . channels . ∗ ;
5 import j a v a . u t i l . Sca nne r ;

7 public c l a s s SocketChannelCmmdcClient {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
9 S t r i n g h o s t=” l o c a l h o s t ” ;
10 i n t p o r t =7999;
11 i f ( a r g s . l e n g t h >0)
12 h o s t=a r g s [ 0 ] ;
13 i f ( a r g s . l e n g t h >1)
14 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
15 S oc k e t Ch a n ne l s c=n u l l ;
16 try {
17 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 ) ;
18 s c=S oc k e tC h a nn e l . open ( ) ;
19 sc . connect ( i s a ) ;
20 }
21 catch ( UnknownHostException e ) {
22 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 ( ) ) ;
23 System . e x i t ( 1 ) ;
24 }
25 catch ( IOException e ) {
26 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 : ”+
2.6. CANALE DE COMUNICAŢIE 41

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


28 System . e x i t ( 1 ) ;
29 }
30 Sc anner s c a n n e r=new Sc anner ( System . i n ) ;
31 long m, n , r ;
32 System . out . p r i n t l n ( ”m=” ) ;
33 m=s c a n n e r . nextLong ( ) ;
34 System . out . p r i n t l n ( ”n=” ) ;
35 n=s c a n n e r . nextLong ( ) ;

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 ) ;
38 // V a r i a n t a 1
39 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ;
40 // V a r i a n t a 2
41 // 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 ( ) ;
42 // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ;
43 try {
44 s c . w r i t e ( bb ) ;
45 bb . c l e a r ( ) ;
46 s c . r e a d ( bb ) ;
47 // V a r i a n t a 1
48 r=bb . getLong ( 0 ) ;
49 // V a r i a n t a 2
50 // r=l b . g e t ( 0 ) ;
51 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;
52 sc . c los e ( ) ;
53 }
54 catch ( E x c e p t i o n e ) {
55 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 ( ) ) ;
56 }
57 }
58 }

Varianta comentată corespunde cazului ı̂n care se utilizeară clasa acoperitoare LongBuffer.

2.6.6 Clasa DatagramChannel


Şablonul de programare pentru instanţierea unui obiect de tip DatagramChannel
este

DatagramChannel dc=null;
InetSocketAddress isa=new InetSocketAddress(port);
try{
dc=DatagramChannel.open();
DatagramSocket datagramSocket=dc.socket();
datagramSocket.bind(isa);
}
catch(Exception e){. . .}

unde port este portul folosit de DatagramChannel. Dacă port=0 atunci se alege
aleator un port disponibil.
Transmiterea unui obiect ByteBuffer se face cu metoda
42 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

public int send(ByteBuffer src, SocketAddress target) throws


IOException

Metoda returnează numărul de octeţi expediaţi. Recepţia unui ByteBuffer se obţine


cu metoda

public SocketAddress receive(ByteBuffer dst) throws IOException

Obiectul returnat reprezintă adresa expeditorului.

Exemplul 2.6.2 Calculul celui mai mare divizor comun a două numere naturale.

1 import java . io . ∗ ;
2 import java . net . ∗ ;
3 import java . nio . ∗ ;
4 import java . nio . channels . ∗ ;
5 import java . u t i l . ∗ ;

7 public c l a s s DatagramChannelCmmdcServer {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
9 i n t p o r t =7999;
10 DatagramChannel dc=n u l l ;
11 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 ) ;
12 try {
13 dc=DatagramChannel . open ( ) ;
14 }
15 catch ( IOException e ) {
16 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
17 }
18 DatagramSocket datagramSocket=dc . s o c k e t ( ) ;
19 try {
20 datagramSocket . bind ( i s a ) ;
21 }
22 catch ( S o c k e t E x c e p t i o n e ) {
23 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
24 }
25 System . out . p r i n t l n ( ” S e r v e r r e a d y . . . ” ) ;
26 boolean l i s t e n i n g=true ;

28 while ( l i s t e n i n g ) {
29 try {
30 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 ) ;
31 // 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 ( ) ;
32 S o c k e t A d d r e s s c l i e n t=dc . r e c e i v e ( bb ) ;
33 // V a r i a n t a 1
34 long m=bb . getLong ( 0 ) ;
35 long n=bb . getLong ( 8 ) ;
36 // V a r i a n t a 2
37 // l o n g m=l b . g e t ( 0 ) ;
38 // l o n g n=l b . g e t ( 1 ) ;
39 App app=new App ( ) ;
40 long r=app . cmmdc(m, n ) ;
41 bb . c l e a r ( ) ;
42 // V a r i a n t a 1
43 bb . putLong ( 0 , r ) ;
44 // V a r i a n t a 2
2.6. CANALE DE COMUNICAŢIE 43

45 // l b . p u t ( 0 , r ) ;
46 dc . send ( bb , c l i e n t ) ;
47 }
48 catch ( E x c e p t i o n e ) {
49 System . out . p r i n t l n ( ” E r o a r e s e r v e r : ”+e . g e t M e s s a g e ( ) ) ;
50 System . e x i t ( 1 ) ;
51 }
52 }
53 }
54 }

1 import java . io . ∗ ;
2 import java . net . ∗ ;
3 import java . nio . ∗ ;
4 import java . nio . channels . ∗ ;
5 import j a v a . u t i l . Sca nner ;

7 public c l a s s DatagramChannelCmmdcClient {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException {
9 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 ” ;
10 i n t p o r t =7999;
11 i f ( a r g s . l e n g t h >0)
12 s e r v e r H o s t=a r g s [ 0 ] ;
13 i f ( a r g s . l e n g t h >1)
14 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
15 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 ;
16 try {
17 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 ) ;
18 }
19 catch ( UnknownHostException e ) {
20 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 ( ) ) ;
21 System . e x i t ( 1 ) ;
22 }
23 i s a=new I n e t S o c k e t A d d r e s s ( 0 ) ;
24 DatagramChannel dc=n u l l ;
25 try {
26 dc=DatagramChannel . open ( ) ;
27 DatagramSocket s o c k e t = dc . s o c k e t ( ) ;
28 s o c k e t . bind ( i s a ) ;
29 }
30 catch ( IOException e ) {
31 System . e r r . p r i n t l n ( ” Couldn ’ t open t h e DatagramChannel ”+ e . g e t M e s s a g e ( ) ) ;
32 System . e x i t ( 1 ) ;
33 }
34 long m, n , r ;
35 Sc anner s c a n n e r=new Sc anner ( System . i n ) ;
36 System . out . p r i n t l n ( ”m=” ) ;
37 m=s c a n n e r . nextLong ( ) ;
38 System . out . p r i n t l n ( ”n=” ) ;
39 n=s c a n n e r . nextLong ( ) ;
40 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 ) ;
41 // V a r i a n t a 1
42 bb . putLong ( 0 ,m) . putLong ( 8 , n ) ;
43 // V a r i a n t a 2
44 // 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 ( ) ;
45 // l b . p u t ( 0 ,m) . p u t ( 1 , n ) ;
46 try {
47 dc . send ( bb , s e r v e r ) ;
48 bb . c l e a r ( ) ;
44 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

49 dc . r e c e i v e ( bb ) ;
50 // V a r i a n t a 1
51 r=bb . getLong ( 0 ) ;
52 // V a r i a n t a 2
53 // r=l b . g e t ( 0 ) ;
54 System . out . p r i n t l n ( ”Cmmdc = ”+r ) ;
55 }
56 catch ( E x c e p t i o n e ) {
57 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 ( ) ) ;
58 }
59 finally {
60 i f ( dc != n u l l ) dc . d i s c o n n e c t ( ) ;
61 }
62 }
63 }

2.7 Conexiuni HTTP


Clasa URL permite realizarea unei conexiuni cu un server Web1 potrivit proto-
colului HTTP (Hyper Text Transport Protocol) şi accesarea fişierelor - uzual html
- din zona publică.
Constructori

• URL(String spec) throws MalformedURLException


Crează un obiect URL legat de resursa specificată de spec, care trebuie să fie o
referinţă URL validă.

Metode

• InputStream openStream() throws IOException


Returnează fluxul de intrare pentru citirea resursei.

Exemplul 2.7.1 Pe baza referinţei către un fişier html dintr-un catalog vizibil al
unui server Web, să se afişeze conţinutul fişierului.

În codul reprodus mai jos, fişierul Hello.html se află pe un server apache-tomcat,
ı̂n catalogul webapps\myservlet.
1 import j a v a . n e t . ∗ ;
2 import j a v a . i o . ∗ ;

4 public c l a s s ReadHTTP{
5 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
6 try {
7 S t r i n g adr=” 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 / H e l l o . html ” ;
8 URL u r l=new URL( adr ) ;
9 InputStream i n=u r l . openStream ( ) ;

1
apache-tomcat, apache, Micrsoft IIS (Internet Information Services), etc.
2.7. CONEXIUNI HTTP 45

10 InputStreamReader i s r =new InputStreamReader ( i n ) ;


11 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 ) ;
12 String s ;
13 do{
14 s=br . r e a d L i n e ( ) ;
15 i f ( s != n u l l )
16 System . out . p r i n t l n ( s ) ;
17 }
18 while ( s != n u l l ) ;
19 br . c l o s e ( ) ;
20 isr . close ();
21 in . close ( ) ;
22 }
23 catch ( E x c e p t i o n e ) {
24 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
25 }
26 }
27 }
46 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA
Capitolul 3

Regăsirea obiectelor prin


servicii de nume

Oricărui obiect ı̂i sunt asociate un nume şi o referinţă. Regăsirea / căutarea
obiectului se face pornind de la numele obiectului, prin referinţă se ajunge la obiect.
Exemple date prin şablonul (Nume ⇒ Referinţă ⇒ Obiect)

1. Accesul la o carte ı̂ntr-o bibliotecă:


Titlul cărţii ⇒ Referintă cărţii din bibliotecă ⇒ Carte

2. Contactul telefonic cu o persoana:


Nume persoană ⇒ Număr telefon ⇒ Persoană

Un serviciu de nume conţine asocieri dintre nume de obiecte şi obiecte şi poate
oferi facilităţi de regăsire a obiectelor.

3.1 Java Naming and Directory Interface


Java Naming and Directory Interface - JNDI este o interfaţă de programare (Ap-
plication Programming Interface - API ) care descrie funcţionalitatea unui serviciu
de nume.
Cuvântul servici este utilizat ı̂n sens comun, entitate care pune la dispoziţie
facilităţi de folosire.
Alături de interfaţa JNDI, arhitectura JNDI mai conţine interfaţa Service Provider
Interface - SPI. Implementarea interfeţei SPI de un furnizor de servicii JNDI are ca
efect independenţa programului Java de furnizorul de servicii JNDI.
JNDI este implementat de serviciile de nume:

• Filesystem are ca obiect asocierea dintre numele de fişier sau catalog cu obiec-
tul corespunzător.

47
48 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME

• DNS - Domain Name System are ca obiect asocierea dintre adresa Internet cu
adresa IP.

• RMI registry utilizat ı̂n aplicaţii RMI, din Java. Are ca obiect asocierea ı̂ntre
un nume de serviciu de invocare ale obiectelor la distanţă cu un delegat al
serviciului (stub).

• COS - Common Object Service Naming utilizat ı̂n aplicaţii CORBA. Are ca
obiect asocierea ı̂ntre numele unui serviciu de invocare ale obiectelor la distanţă
cu referinţa la serviciu.

• LDAP - Lightweight Directory Access Protocol

Interfaţa Context
Printr-un context se va ı̂nţelege o mulţime de asocieri nume - obiect. Core-
spunzător unui context, JNDI defineşte interfaţa Context, cu metodele

• void bind(String nume,Object object)

• void rebind(String nume,Object object)

• void unbind(String nume)

• Object lookup(String nume)

• NamingEnumeration list(String nume)


Returnează lista cu nume obiectelor ı̂mpreuna cu tipul lor.

• NamingEnumeration listBindings(String nume)


Returnează lista cu nume obiectelor ı̂mpreuna cu tipul şi locaţia acestora.

Specificaţiile JNDI prevăd definirea unui context iniţial, implementat prin clasa
InitialContext, clasă ce implementează interfaţa Context.
Constructori.

• public InitialContext() throws NamingException

• protected void init(Hashtable<?,?> environment)throws


NamingException

Pentru crearea contextului iniţial trebuie specificaţa clasa care crează contextul
iniţial prin parametrul java.naming.factory.initial sau constanta
Contect.INITIAL CONTEXT FACTORY.
Acest parametru se poate da ı̂n mai multe moduri:
3.1. JAVA NAMING AND DIRECTORY INTERFACE 49

• Includerea ı̂n obiectul Hashtable care apare ı̂n constructorul clasei InitalContext.

Hashtable env=new Hashtable()


env.put("java.naming.factory.initial",...);
Context ctx=InitialContext(env);

sau

Hashtable env=new Hashtable()


env.put(Context.INITIAL_CONTEXT_FACTORY,...);
Context ctx=new InitialContext(env);

• Ca parametru de sistem furnizat la lansarea programului Java, prin

java -Djava.naming.factory.initial=... ClasaJava

Parametrul se poate da ı̂n interiorul programului prin

System.setProperty("java.naming.factory.initial",...);

sau

System.setProperty(Context.INITIAL_CONTEXT_FACTORY,...);

• Atribut ı̂n fişierul de proprietăţi jndi.properties.


În aceste ultime două cazuri, contextul initial se crează prin

Context ctx=new InitialContext();

Funcţie de serviciul de nume, clasa care crează contextul iniţial este dat ı̂n tabelul

Serviciul de nume Clasa


Filesystem com.sun.jndi.fscontect.RefFSContextFactory
COS com.sun.jndi.cosnaming.CNCtxFactory
RMI com.sun.jndi.rmi.registry.RegistryContextFactory
DNS com.sun.jndi.dns.DnsContextFactory
LDAP com.sun.jndi.ldap.LdapCtxFactory

Exemplul 3.1.1 Utilizând serviciul JNDI Filesystem se crează un context prin in-
termediul căreia se afişează conţinutul unui catalog indicat de client.
50 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME

1 import j a v a x . naming . ∗ ;
2 import java . io . F i l e ;
3 import java . u t i l . Hashtable ;
4 import j a v a . u t i l . Sca nne r ;

6 c l a s s Lookup {
7 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
8 Context c t x=n u l l ;
9 /∗
10 // V a r i a n t a 1
11 H a s h t a b l e env = new H a s h t a b l e ( 1 1 ) ;
12 env . p u t ( C o n t e x t . INITIAL CONTEXT FACTORY,
13 ”com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ” ) ;
14 try {
15 c t x = new I n i t i a l C o n t e x t ( env ) ;
16 }
17 c a t c h ( NamingException e ) {
18 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 ( ) ) ;
19 }
20 ∗/
21 /∗
22 // V a r i a n t a 2
23 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 ” ,
24 ”com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ” ) ;
25 try {
26 c t x = new I n i t i a l C o n t e x t ( ) ;
27 }
28 c a t c h ( NamingException e ) {
29 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 ( ) ) ;
30 }
31 ∗/

33 // V a r i a n t a 3
34 try {
35 c t x = new I n i t i a l C o n t e x t ( ) ;
36 }
37 catch ( NamingException e ) {
38 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 ( ) ) ;
39 }

42 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;


43 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 : ” ) ;
44 S t r i n g myName=s c a n n e r . n e x t ( ) ;
45 try {
46 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 ” ) ;
47 System . out . p r i n t l n ( c t x . l o o k u p (myName ) ) ;

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


50 NamingEnumeration l s t =c t x . l i s t (myName ) ;
51 while ( l s t . hasMore ( ) ) {
52 NameClassPair nc = ( NameClassPair ) l s t . n e x t ( ) ;
53 System . out . p r i n t l n ( nc ) ;
54 }

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


57 NamingEnumeration l s t 1 = c t x . l i s t B i n d i n g s (myName ) ;
58 while ( l s t 1 . hasMore ( ) ) {
59 B i n d i n g bd = ( B i n d i n g ) l s t 1 . n e x t ( ) ;
3.1. JAVA NAMING AND DIRECTORY INTERFACE 51

60 System . out . p r i n t l n ( bd ) ;
61 // System . o u t . p r i n t l n ( bd . getName ( ) + ” : ” + bd . g e t O b j e c t ( ) ) ;
62 }
63 ctx . c l o s e ( ) ;
64 }
65 catch ( NamingException e ) {
66 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 }

Serviciul de nume Filesystem este dat de fişierele fscontext.jar, providerutil.jar.


52 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME
Capitolul 4

Invocarea procedurilor la
distanţă

Invocarea procedurilor la distanţă (Remote Procedure Call – RPC ) ı̂nseamnă


apelarea unei metode a unui obiect aflat pe un alt calculator ca şi cum acesta s-ar
afla pe calculatorul local.
Se vor prezenta două cazuri:

• Invocarea procedurilor la distanţă ı̂n cazul mediului omogen Java. Denumirea


tehnologiei ı̂n acest caz este Invocarea metodelor la distanţă – Remote Method
Invocation (RMI). Prin mediu omogen se ı̂nţelege faptul că atât compontenta
server cât şi componenta client sunt programate ı̂n acelaşi limbaj de progra-
mare, Java ı̂n cazul de faţă.

• Invocarea procedurilor la distanţă ı̂n cazul medii neomogene. Soluţia ı̂n acest
caz este dat de Common Object Request Brocker Arhitecture (CORBA).

4.1 Remote Method Invocation


Regăsirea obiectelor la distanţă. Ideea găsirii unui obiect la distanţă este că
serverul ı̂nscrie un reprezentant al său – numit stub (ciot) – ı̂ntr-un obiect registry -
registru. Acest obiect se crează cu programul rmiregistry.exe din distribuţia java
şi se lansează ı̂n execuţie prin

start rmiregistry [port]

unde valoarea implicită a portului este 1099. Comanda start aparţine sistemului
de operare. rmiregistry este un serviciu de nume JNDI.
Un client obţine din registry stub-ul serverului, prin intermediul căruia realizează
comunicaţia cu programul server.

53
54 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

Când un obiect al clientului apelează o metodă a unui obiect aflat la distanţă,


se va face, de fapt, un apel de metodă a unui obiect care reprezintă serverul. Acesta
este stub-ul, aflat pe aceaşi maşină cu clientul.
Rolul acestui obiect este să ı̂mpacheteze (marshalling) parametrii de apel ai
metodei ı̂ntr-un mesaj ce va fi transferat prin reţea. Împachetarea se face ı̂ntr-o
manieră independentă de calculator, mai precis şirurile de caractere şi obiecte sunt
transmise ı̂ntr-un format care nu se bazează pe referinţe. Pentru obiecte se utilizează
serializarea obiectelor Java.
Serializarea datelor reprezintă transformarea acestora din tipuri de date diferite
ı̂ntr-un şir de octeţi care va fi transportat prin reţea fără interpretare, dar care
păstrează informaţiile despre structura iniţială a datelor.
Deserializarea este procesul invers de refacere a structurilor trimise prin reţea.
Mesajul asamblat este transmis către server, care ştie să desfacă mesajul recepţionat
invocând ı̂n mod corespunzător metoda referită de client.
Atunci când clientul face apel la o metodă aflată pe o altă maşină, este invo-
cat stub-ul client, care ı̂ncepe conversaţia cu serverul. Acest lucru este complet
transparent utilizatorului, care are impresia că invocă o metodă locală.
Metodele apelate la distanţă trebuie declarate ca aparţinând unei interfeţe ce
extinde interfaţa Remote. Fiecare asemenea metodă trebuie să arunce o excepţie
java.rmi.RemoteException. Obiectele care circulă prin reţea trebuie să imple-
menteze interfaţa java.io.Serializable.
Structura unei aplicaţii RMI. O aplicaţie RMI este alcătuită din trei com-
ponente:

1. O interfaţă la distanţă (remote) ı̂n care se declară serviciile puse la dispoziţie


de server;

2. Aplicaţia server care poate implementa serviciile interfeţei la distanţă şi ı̂nscrie
ı̂n registry stub-ul corespunzător;

3. Aplicaţia client ce apelează unul sau mai multe servicii ale serverului.

Nici o clipă nu trebuie scăpat din vedere faptul că cele trei componente evoluează
pe calculatoare diferite.
Registrul rmiregistry implementează interfaţa Registry. Metodele oferite sunt:

• void bind(String numeServiciu, Remote obj )throws


RemoteException, AlreadyBoundException, AccessException
Înregistrează ı̂n registry obiectul obj ce implementează interfaţa Remote sub
numele numeServiciu.

• void rebind(String numeServiciu, Remote obj )throws


RemoteException, AccessException
4.1. REMOTE METHOD INVOCATION 55

Reı̂nregistrează ı̂n registry obiectul obj ce implementează interfaţa Remote sub


numele numeServiciu.
Această metodă poate fi apelată doar dacă programul care face ı̂nregistrarea
se află pe aceaşi maşină ca registrul registry.

• String[] list()throws RemoteException, AccessException


Returnează o listă a tuturor serviciilor ı̂nregistrate ı̂n registry.

• Remote lookup(String numeServiciu)throws


RemoteException, NotBoundException, AccessException
Returnează stub-ul serviciului ı̂nregistrat sub numele numeServiciu.

• void unbind(String numeServiciu)throws


RemoteException, NotBoundException, AccessException
Şterge din registru serviciul.

Localizarea registrului se obţine utilizând metoda statică getRegistry a clasei


LocateRegistry.

• public static Registry getRegistry() throws RemoteException

• public static Registry getRegistry(String host)


throws RemoteException

• public static Registry getRegistry(int port)


throws RemoteException

• public static Registry getRegistry(String host,int port)


throws RemoteException

Metoda public static Registry createRegistry(int port)


throws RemoteException crează un registru la portul specificat pe calculatorul
local.
Într-un registry se pot ı̂nregistra mai multe servicii, dar pe porturi diferite.
Interfaţa Remote serveşte la marcarea interfeţelor ale căror metode urmează a fi
apelate de pe altă maşină virtuală Java.
Un obiect de tip UnicastRemoteObject mijloceşte transmiterea obiectelor şi
serveşte la generarea unui stub unui serviciu. Generarea stub-ului unui serviciu se
obţine prin intermediul metodei statice

static Remote UnicastRemoteObject.exportObject(Remote obj ,int port)

Inregistrarea stub-ului unui serviciu descris de interfaţa IService şi imple-


mentat de clasa ServiceImpl ı̂n registry se face prin
56 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

ServiceImpl obj=new ServiceImpl();


IService stub=(IService)UnicastRemoteObject.exportObject(obj,0);
Registry registry=LocateRegistry.getRegistry(host,port);
registry.bind("MyServiceName",stub);

Un client care doreşte să folosească trebuie să cunoască :

• calculatorul pe care se găseşte obiectul registry şi portul la care ascultă servi-
ciul;

• numele sub care serviciul s-a ı̂nregistrat ı̂n registry;

• metodele puse la dispoziţie de serviciu.

4.1.1 Crearea unei aplicaţii RMI


Exemplificăm construirea unei aplicaţii RMI ı̂n care serviciul asigurat de server
este calculul celui mai mare divizor comun a două numere naturale.
Pentru exemplele1 care urmează, presupunem că textele sursă se reţin ı̂n subcat-
aloage ale unui catalog src, la care are acces doar programatorul, iar clasele obţinute
prin compilare se depun ı̂n subcataloagele unui catalog public\classes, accesibil
prin reţea.
Dezvoltarea unei aplicaţii se va face pe un calculator. În acest sens, celor 3
componente li se asociază cataloagele \i - pentru interfaţa la distanţă, \s - pentru
componenta server şi \c - pentru componenta client. Paşi necesari compilării şi
desfăşurării componentelor aplicaţiei se vor realiza prin intermediul lui ant.
Pentru fiecare componentă se vor executa succesiv obiectivele:

1. Install - crează o structură de cataloage src şi public\classes.

2. Init - crează structura de cataloage specifică aplicaţiei.

3. Compile - compilează programele sursă.

Dezvoltarea unei aplicaţii RMI constă din parcurgerea următorilor paşi:

1. Definitea interfeţei la distanţă.

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

1
Sistemul de operare utilizat este Windows
4.1. REMOTE METHOD INVOCATION 57

Presupunem ca programatorul interfeţei reţine textul sursă


ICmmdc.java ı̂n catalogul \i\src\cmmdc.

2. Compilarea şi arhivarea interfeţei se poate realiza fişierul ant-build


1 <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=” . ”>
2 <description> I n t e r f a c e a c t i o n s </ description>
3 < !−− 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 −−>

5 <property name=” package ” v a l u e=”cmmdc” />

7 <target name=” I n s t a l l ”>


8 < !−− 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 −−>
9 <delete d i r=” s r c ” />
10 <mkdir d i r=” s r c ” />
11 <delete d i r=” p u b l i c ” />
12 <mkdir d i r=” p u b l i c ” />
13 <delete d i r=” p u b l i c / c l a s s e s ” />
14 <mkdir d i r=” p u b l i c / c l a s s e s ” />
15 </ target>

17 <target name=” I n i t ”>


18 < !−− C r e a t e t h e time stamp −−>
19 <tstamp/>
20 <mkdir d i r=” s r c /${ package } ” />
21 <mkdir d i r=” p u b l i c / c l a s s e s /${ package } ” />
22 </ target>

24 <target name=” Compile ” depends=” I n i t ”


25 description=” c o m p i l e t h e s o u r c e ” >
26 <javac s r c d i r=” s r c ” i n c l u d e s=” ${ package }/∗∗ ”
27 d e s t d i r=” p u b l i c / c l a s s e s ” />
28 <j a r b a s e d i r=” p u b l i c / c l a s s e s ”
29 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 ”
30 i n c l u d e s=” ${ package } / ∗ . c l a s s ” />
31 </ target>
32 </ project>

3. Implementarea interfeţei remote prin construirea aplicaţiei server.

1 package s e r v e r ;

3 import cmmdc . ∗ ;
4 import j a v a . rmi . ∗ ;
5 import j a v a . rmi . s e r v e r . ∗ ;
6 // V a r i a n t a d i r e c t a
7 import j a v a . rmi . r e g i s t r y . ∗ ;
8 // V a r i a n t a JNDI
9 /∗
10 i m p o r t j a v a x . naming . ∗ ;
11 ∗/

13 public c l a s s CmmdcImpl implements ICmmdc{

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


58 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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


18 S t r i n g h o s t=” l o c a l h o s t ” ;
19 i n t p o r t =1099;
20 i f ( a r g s . l e n g t h >0)
21 h o s t=a r g s [ 0 ] ;
22 i f ( a r g s . l e n g t h >1)
23 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
24 try {
25 CmmdcImpl o b j=new CmmdcImpl ( ) ;
26 ICmmdc s t u b =(ICmmdc) UnicastRemoteObject . e x p o r t O b j e c t ( obj , 0 ) ;

28 // V a r i a n t a d i r e c t a
29 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 ) ;
30 r e g i s t r y . bind ( ”CmmdcServer” , s t u b ) ;

32 // V a r i a n t a JNDI
33 /∗
34 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 ( ) ;
35 System . s e t P r o p e r t y ( C o n t e x t . INITIAL CONTEXT FACTORY,
36 ”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 ” ) ;
37 System . s e t P r o p e r t y ( C o n t e x t .PROVIDER URL, ” rmi ://”+ h o s t +”:”+ s P o r t ) ;
38 C o n t e x t c t x=new I n i t i a l C o n t e x t ( ) ;
39 c t x . b i n d (” CmmdcServer ” , s t u b ) ;
40 ∗/
41 System . out . p r i n t l n ( ”CmmdcServer r e a d y ” ) ;
42 }
43 catch ( E x c e p t i o n e ) {
44 System . out . p r i n t l n ( ”CmmdcImpl e r r : ” + e . g e t M e s s a g e ( ) ) ;
45 }
46 }
47 }

Textul sursă al programului server CmmdcImpl.java se reţine ı̂n catalogul


\s\src\server

4. Compilarea programului server


1 <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=” . ”>
2 <description> S e r v e r a c t i o n s </ description>
3 < !−− 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 −−>

5 <property name=” package ” v a l u e=” s e r v e r ” />


6 <property name=” i n t e r f a c e −j a r ” l oc a t io n=” \ i \ p u b l i c \ c l a s s e s \cmmdc” />
7 <property name=” j a r − f i l e ” v a l u e=”cmmdc . j a r ” />
8 <property name=” s e r v i c e −c l a s s ” v a l u e=”CmmdcImpl” />

10 <target name=” I n s t a l l ”>


11 < !−− C r e a t e t h e time stamp −−>
12 <tstamp/>
13 < !−− 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 −−>
14 <delete d i r=” s r c ” />
15 <mkdir d i r=” s r c ” />
16 <delete d i r=” p u b l i c ” />
17 <mkdir d i r=” p u b l i c ” />
18 <delete d i r=” p u b l i c / c l a s s e s ” />
19 <mkdir d i r=” p u b l i c / c l a s s e s ” />
20 </ target>
4.1. REMOTE METHOD INVOCATION 59

22 <target name=” I n i t ”>


23 <mkdir d i r=” s r c /${ package } ” />
24 <mkdir d i r=” p u b l i c / c l a s s e s /${ package } ” />
25 <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 ” />
26 </ target>

28 <target name=” Compile ” depends=” I n i t ”


29 description=” c o m p i l e t h e s o u r c e ”>
30 <javac s r c d i r=” s r c ”
31 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 ”
32 classpath=” p u b l i c \ c l a s s e s \${ j a r − f i l e } ” />
33 <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 ” />
34 </ target>
35 </ project>

5. Crearea obiectului registry şi lansarea serverului ı̂n lucru se obţine cu fişierul
de comenzi bat

cd \s\public\classes
start rmiregistry
cd \s\public\classes
start java -cp /s/public/classes -Djava.rmi.server.codebase=
file:/s/public/classes/ server.CmmdcImpl

Parametrul -Djava.rmi.server.codebase fixează locaţia interfeţei la distanţă


de pe calculatorul server.

6. Realizarea programului client

1 package c l i e n t ;

3 import cmmdc . ∗ ;
4 import j a v a . u t i l . Sca nner ;
5 // V a r i a n t a d i r e c t a
6 import j a v a . rmi . r e g i s t r y . ∗ ;
7 // V a r i a n t a JNDI
8 /∗
9 i m p o r t j a v a x . naming . ∗ ;
10 ∗/

12 public c l a s s CmmdcClient {
13 public s t a t i c void main ( S t r i n g a r g s [ ] ) {
14 S t r i n g h o s t=” l o c a l h o s t ” ;
15 i n t p o r t =1099;
16 i f ( a r g s . l e n g t h >0)
17 h o s t=a r g s [ 0 ] ;
18 i f ( a r g s . l e n g t h >1)
19 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
20 Sca nner s c a n n e r=new Sca n n e r ( System . i n ) ;
21 System . out . p r i n t l n ( ” Primul numar : ” ) ;
22 long m=Long . parseLong ( s c a n n e r . n e x t ( ) ) ;
60 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

23 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;


24 long n=Long . p ars eL ong ( s c a n n e r . n e x t ( ) ) ;
25 long x =0;
26 try {
27 // V a r i a n t a d i r e c t a
28 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 ) ;
29 ICmmdc o b j =(ICmmdc) r e g i s t r y . l o o k u p ( ”CmmdcServer” ) ;
30 // V a r i a n t a JNDI
31 /∗
32 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 ( ) ;
33 System . s e t P r o p e r t y ( C o n t e x t . INITIAL CONTEXT FACTORY,
34 ”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 ” ) ;
35 System . s e t P r o p e r t y ( C o n t e x t .PROVIDER URL, ” rmi ://”+ h o s t +”:”+ s P o r t ) ;
36 C o n t e x t c t x=new I n i t i a l C o n t e x t ( ) ;
37 ICmmdc o b j =(ICmmdc) c t x . l o o k u p (” CmmdcServer ” ) ;
38 ∗/
39 x=o b j . cmmdc(m, n ) ;
40 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
41 }
42 catch ( E x c e p t i o n e ) {
43 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 ( ) ) ;
44 }
45 }
46 }

Sursa programului client CmmdcClient.java aparţine catalogului


\c\src\client

7. Compilarea programului client şi lansarea acestuia ı̂n execuţie.


1 <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=” . ”>
2 <description> C l i e n t a c t i o n s </ description>
3 < !−− 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 −−>

5 <property name=” package ” v a l u e=” c l i e n t ” />


6 <property name=” i n t e r f a c e −j a r ” l oc a t io n=” \ i \ p u b l i c \ c l a s s e s \cmmdc” />
7 <property name=” j a r − f i l e ” v a l u e=”cmmdc . j a r ” />
8 <property name=” h o s t ” v a l u e=” l o c a l h o s t ” />
9 <property name=” p o r t ” v a l u e=” 1099 ” />
10 <property name=” c l i e n t −c l a s s ” v a l u e=” CmmdcClient ” />

12 <target name=” I n s t a l l ”>


13 < !−− 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 −−>
14 <delete d i r=” s r c ” />
15 <mkdir d i r=” s r c ” />
16 <delete d i r=” c l a s s e s ” />
17 <mkdir d i r=” c l a s s e s ” />
18 </ target>

20 <target name=” I n i t ”>


21 < !−− C r e a t e t h e time stamp −−>
22 <tstamp/>
23 <mkdir d i r=” s r c /${ package } ” />
24 <mkdir d i r=” c l a s s e s /${ package } ” />
25 <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 ” />
26 </ target>

28 <target name=” Compile ” depends=” I n i t ”


4.1. REMOTE METHOD INVOCATION 61

29 description=” c o m p i l e t h e s o u r c e ”>
30 <javac s r c d i r=” s r c ”
31 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 ”
32 classpath=” c l a s s e s \${ j a r − f i l e } ” />
33 </ target>

35 <target name=”Run” depends=” Compile ”


36 description=” S t a r t t h r c l i e n t ”>
37 <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 ”>
38 <classpath>
39 <pathelement locat io n=” c l a s s e s \${ j a r − f i l e } ” />
40 <pathelement path=” c l a s s e s ” />
41 </ classpath>
42 <arg l i n e=” ${ h o s t } ${ p o r t } ” />
43 </ java>
44 </ target>
45 </ project>

4.1.2 Tipare de programare


Fabrica de obiecte
Tiparul fabrica de obiecte va permite crearea dinamică a unui server, fapt care
nu este posibil pe schema prezentată ı̂n paragraful precedent. Prin aceea schemă,
se va crea o clasă - fabrica de obiecte - care implementează câte o metodă get, ce
returnează o instanţă de server. Aceste metode sunt declarate ı̂ntr-o interfaţă la
distanţă. Un client, apelând o asemenea metodă, va instanţia serverul dorit şi va
obţine stub-ul corespunzător.
Programarea unui server care poate fi lansat dinamic trebuie să satisfacă restricţiile:

• Clasa serverului extinde clasa UnicastRemoteObject.

• Există un constructor fără argumente ce aruncă excepţia java.rmi.Remote


Exception.

Pentru exemplificarea tehnicii de lucru reluăm aplicaţia pentru calculul celui mai
mare divizor comun a două numere naturale, considerând interfaţa
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 p u b l i c i n t e r f a c e ICmmdc0 e x t e n d s Remote{
4 p u b l i c l o n g compute ( l o n g m, l o n g n ) throws RemoteException ;
5 }

Aceasă interfaţă va fi implementată de clasa ServerCmmdc. Metoda compute


este o metodă de calcul a celui mai mare divizor comun a două numere.
Obiecte de tip ServerCmmdc se crează, de la distanţă prin fabrica de obiecte
FabObiecte, o clasă ce implementează interfaţa
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
62 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

3 p u b l i c i n t e r f a c e I F a b O b i e c t e e x t e n d s Remote{
4 p u b l i c ICmmdc0 getCmmdc ( ) throws RemoteException ;
5 }

Codurile claselor ServerCmmdc şi FabObiecte sunt


1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . s e r v e r . ∗ ;
4 import j a v a . i o . ∗ ;
5 import j a v a . u t i l . ∗ ;

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

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

11 p u b l i c l o n g compute ( l o n g m, l o n g n ) throws RemoteException {


12 . . .
13 }
14 }

respectiv
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . s e r v e r . ∗ ;
4 import j a v a . rmi . r e g i s t r y . ∗ ;

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

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


9 ServerCmmdc cmmdc=new ServerCmmdc ( ) ;
10 r e t u r n cmmdc ;
11 }

13 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 [ ] ) {
14 S t r i n g h o s t=” l o c a l h o s t ” ;
15 i n t p o r t =1099;
16 i f ( a r g s . l e n g t h >0)
17 h o s t=a r g s [ 0 ] ;
18 i f ( a r g s . l e n g t h >1)
19 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
20 try {
21 FabObiecte o b j=new FabObiecte ( ) ;
22 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 ) ;
23 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 ) ;
24 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 ) ;
25 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 ” ) ;
26 }
27 catch ( Exception e ){
28 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 ( ) ) ;
29 }
30 }
31 }

Aplicaţia client se compune din două clase

1. RemoteClient
4.1. REMOTE METHOD INVOCATION 63

Clientul obţine stub-ul serviciului, prin intermediul căruia apelează metada


getCmmdc() a fabricii de obiecte, obţinând un obiect remote de tip Server-
Cmmdc, ce implementează interfaţa la distanţă ICmmdc0.
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . s e r v e r . ∗ ;
4 import j a v a . rmi . r e g i s t r y . ∗ ;

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

8 ICmmdc0 remote=n u l l ;

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

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


13 I F a b O b i e c t e f a b r i c a=n u l l ;
14 try {
15 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 ) ;
16 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 ” ) ;
17 remote=o b j . getCmmdc ( ) ;
18 }
19 catch ( Exception e ){
20 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 ( ) ) ;
21 }
22 }
23 }

2. ClientCmmdc0
Apelează metoda compute a obiectului remote.
1 package cmmdc0 ;
2 import j a v a . u t i l . Sc anne r ;

4 p u b l i c c l a s s ClientCmmdc0 {

6 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 [ ] ) {
7 S t r i n g h o s t=” l o c a l h o s t ” ;
8 i n t p o r t =1099;
9 i f ( a r g s . l e n g t h >0)
10 h o s t=a r g s [ 0 ] ;
11 i f ( a r g s . l e n g t h >1)
12 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
13 Sca nner s c a n n e r=new Sca n n e r ( System . i n ) ;
14 try {
15 RemoteClient c t=new RemoteClient ( ho st , p o r t ) ;
16 System . out . p r i n t l n ( ”m=” ) ;
17 l o n g m=s c a n n e r . nextLong ( ) ;
18 System . out . p r i n t l n ( ”n=” ) ;
19 l o n g n=s c a n n e r . nextLong ( ) ;
20 l o n g x=c t . remote . compute (m, n ) ;
21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
22 }
23 catch ( Exception e ){
24 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 ( ) ) ;
25 }
26 System . e x i t ( 0 ) ;
64 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

27 }
28 }

Apelul invers – Callback


Se numeşte apel invers apelarea de către programul server a unei metode a clien-
tului.
În RMI realizarea unui apel invers presupune:
1. definirea unei interfeţe la distanţă ce va fi implementat de programul client;

2. programul client ce implementează interfaţa extinde clasa UnicastRemote Object


şi are un constructor ce aruncă o excepţie java.rmi.RemoteException.
Extindem aplicaţia anterioară cu posibilitatea suplimentară a serverului (Server-
Cmmdc) de a alege metoda de calcul a celui mai mare divizor comun dintre varianta
nerecursivă şi cea recursivă a algorimului lui Euclid.
Extindem interfaţa ICmmdc0 cu metoda
public void setMethod(ICallbackCmmdc obj)throws RemoteException;

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

unde ICallbackCmmdc este interfaţa


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

ce va fi implementată ı̂n clasa RemoteClient.


Programul ServerCmmdc devine
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . s e r v e r . ∗ ;
4 import j a v a . i o . ∗ ;

6 p u b l i c c l a s s ServerCmmdc e x t e n d s UnicastRemoteObject
7 implements ICmmdc0{
8 p r i v a t e S t r i n g method=n u l l ;

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

12 p u b l i c l o n g compute ( l o n g m, l o n g n ) {
13 l o n g x =0;
14 i f ( method . e q u a l s ( ”NERECURSIV” ) )
4.1. REMOTE METHOD INVOCATION 65

15 x=n e r e c u r s i v (m, n ) ;
16 i f ( method . e q u a l s ( ”RECURSIV” ) )
17 x=r e c u r s i v (m, n ) ;
18 return x ;
19 }

21 p u b l i c v o i d setMethod ( ICallbackCmmdc o b j ) throws RemoteException {


22 method=o b j . getMethod ( ) ;
23 }

25 p r i v a t e long r e c u r s i v ( long a , long b){


26 i f ( a==b )
27 return a ;
28 else
29 i f ( a<b )
30 r e t u r n r e c u r s i v ( a , b−a ) ;
31 else
32 r e t u r n r e c u r s i v ( a−b , b ) ;
33 }

35 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 ) {
36 long r , c ;
37 do {
38 c=n ;
39 r=m%n ;
40 m=n ;
41 n=r ;
42 }
43 while ( r !=0);
44 return c ;
45 }
46 }

După obţinerea stub-ului, clientul apelează metoda setMethod a serverului re-


mote, care, prin apel invers, apelează metoda getMethod din RemoteClient. Clientul
stabileşte metoda de calcul şi apelează metoda compute a lui remote.
Programele client devin
1 package cmmdc0 ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . s e r v e r . ∗ ;
4 import j a v a . rmi . r e g i s t r y . ∗ ;
5 import j a v a . u t i l . Sc anne r ;

7 p u b l i c c l a s s RemoteClient e x t e n d s UnicastRemoteObject
8 implements ICallbackCmmdc {
9 ICmmdc0 remote=n u l l ;

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

13 p u b l i c S t r i n g getMethod ( ) {
14 Sc anner s c a n n e r=new Scan ner ( System . i n ) ;
15 System . out . p r i n t l n ( ” A l e g e t i una d i n v a r i a n t e l e a l g o r i t m u l u i l u i E u c l i d ” ) ;
16 System . out . p r i n t l n ( ” 1 − a l g o r i t m u l ne−r e c u r s i v ” ) ;
17 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 ” ) ;
18 i n t x=s c a n n e r . n e x t I n t ( ) ;
19 S t r i n g method=n u l l ;
20 i f ( x==1)
66 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

21 method=”NERECURSIV” ;
22 else
23 method=”RECURSIV” ;
24 r e t u r n method ;
25 }

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


28 I F a b O b i e c t e f a b r i c a=n u l l ;
29 try {
30 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 ) ;
31 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 ” ) ;
32 remote=o b j . getCmmdc ( ) ;
33 }
34 catch ( Exception e ){
35 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 ( ) ) ;
36 }
37 }
38 }

şi
1 package cmmdc0 ;
2 import j a v a . u t i l . Sc anne r ;

4 p u b l i c c l a s s ClientCmmdc0 {
5 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 [ ] ) {
6 S t r i n g h o s t=” l o c a l h o s t ” ;
7 i n t p o r t =1099;
8 i f ( a r g s . l e n g t h >0)
9 h o s t=a r g s [ 0 ] ;
10 i f ( a r g s . l e n g t h >1)
11 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
12 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
13 try {
14 RemoteClient c t=new RemoteClient ( ho st , p o r t ) ;
15 c t . remote . setMethod ( c t ) ;
16 System . out . p r i n t l n ( ”m=” ) ;
17 l o n g m=s c a n n e r . nextLong ( ) ;
18 System . out . p r i n t l n ( ”n=” ) ;
19 l o n g n=s c a n n e r . nextLong ( ) ;
20 l o n g x=c t . remote . compute (m, n ) ;
21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
22 }
23 catch ( Exception e ){
24 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 ( ) ) ;
25 }
26 System . e x i t ( 0 ) ;
27 }
28 }

4.1.3 Obiect activabil la distanţă


O instanţă a clasei UnicastRemoteObject reprezintă un obiect la distanţă care
rulează ı̂n permanenţă, folosind resursele maşinii server.
Începând cu versiunea JDK 1.2, prin ı̂ntroducerea clasei java.rmi.activa-
tion.Activatable şi a programului rmid (...\jdk...\bin\rmid.exe) se pot crea pro-
4.1. REMOTE METHOD INVOCATION 67

grame care ı̂nregistrează informaţii despre obiecte la distanţă ce vor fi create şi
executate la cerere.
Invocarea de la distanţă a unei metode aparţinând unui asemenea obiect are ca
efect activarea obiectului.
Pe fiecare maşină virtuală Java există un grup de activare (activation group),
care realizează activarea. Activarea este făcută de un activator. Un activator conţine
o tabelă care face legătura dintre clasa obiectului cu URL-ul acestuia şi eventual, cu
date necesare iniţializării obiectului. Atunci când activatorul constată că nu există
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 distanţă
nu implică modificări. Modificările intervin numai din punctul de vedere al serverului
şi al ı̂nregistrării sale.
Reluăm aplicaţia dezvoltată la ı̂nceputul capitolului, privind calculul celui mai
mare divizor comun a două numere naturale.
Aplicaţia server este compusă din două clase
1. o clasa ce implementează interfaţa ICmmdc : CmmdcActivabil;
2. clasa Setup, cu metoda main, care face posibilă mecanismul de activare şi
ı̂nscrie serviciul ı̂n registry. Această clasă este preluată din tutorialul dedicat
activării a documentaţiei ce ı̂nsoţeşte distribuţia Java.
Clasa ce implementează interfaţa la distanţă trebuie
1. să extindă clasa Activatable;
2. să aibă 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 MarchalledObject cu date de iniţializare a obiectului
activabil. În cazul nostru, acest parametru nu va fi folosit.
Codul sursă al clasei CmmdcActivabil este
1 package acmmdc ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . a c t i v a t i o n . ∗ ;
4 import cmmdc . ∗ ;

6 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
7 implements ICmmdc{

9 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 )
10 throws RemoteException {
11 s u p e r ( id , 0 ) ;
12 }

14 p u b l i c l o n g cmmdc( l o n g m, l o n g n ) { . . . }
15 }
68 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

Clasa Setup necesită o serie de date furnizare ca proprietăţi:

1. drepturile de securitate ale grupului de activare


myactivation.policy=group.policy;
cu conţinutul

grant codeBase "${myactivation.impl.codebase}" {

// permission to read and write object’s file


permission java.io.FilePermission "${myactivation.file}","read,write";

// permission to listen on an anonymous port


permission java.net.SocketPermission "*:1024-","accept";
};

2. java.class.path=no.classpath
ceea ce previne grupul de activare să ı̂ncarce o clasă din classpath-ul local;

3. localizarea (URL) clasei ce implementează interfaţa


myactivation.impl.codebase;

4. localizarea unui fişier cu date de iniţializare a obiectului activabil


myactivation.file;

5. numele sub care ı̂nregistrează serviciul ı̂n registry


myactivation.name.

Programul Setup realizează:

1. Construirea unui descriptor al grupului de activare. Grupul de activare este


un container ce gestionează obiectele activabile conţinute.

2. Înregistrarea descriptorului grupului de activare şi obţinerea unui identificator


al grupului de activare.

3. Construirea descriptorului de activare. Trebuie cunoscute

• idendificatorul grupului de activare;


• numele clasei ce implementează interfaţa la distanţă;
• localizarea (URL) clasei ce implementează interfaţa la distanţă;
• obiectul de tip MarchalledObject, cu datele de iniţializare a obiectului
activabil.

4. Înregistrarea descriptorului de activare, ı̂n urma căreia se obţine stub-ul obiec-


tului activabil.
4.1. REMOTE METHOD INVOCATION 69

5. Înregistrarea stub-ului ı̂mpreună cu numele serviciului ı̂n registry.


Codul clasei setup este

1 package acmmdc ;

3 import j a v a . rmi . ∗ ;
4 import j a v a . rmi . a c t i v a t i o n . ∗ ;
5 import j a v a . rmi . r e g i s t r y . ∗ ;
6 import java . u t i l . Properties ;

8 p u b l i c c l a s s Setup {

10 p r i v a t e Setup ( ) {}

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

14 // Argumentul l i n i e i de comanda
15 S t r i n g implClass = ”” ;
16 i f ( args . length < 1) {
17 System . e r r . p r i n t l n ( ” u s a g e : j a v a [ o p t i o n s ] examples . a c t i v a t i o n . Setup <i m p l C l a s s >” ) ;
18 System . e x i t ( 1 ) ;
19 }
20 else {
21 implClass = args [ 0 ] ;
22 }

24 // 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
25 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 ” ) ;
26 S t r i n g implCodbase=System . g e t P r o p e r t y ( ” m y a c t i v a t i o n . impl . c o d e b a s e ” ) ;
27 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 ” , ” ” ) ;
28 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 ( ) ;
29 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 ) ;
30 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 ” ) ;
31 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 ) ;
32 i f ( filename != n u l l && ! filename . equals ( ” ” ) ) {
33 p r o p s . put ( ” m y a c t i v a t i o n . f i l e ” , filename ) ;
34 }
35 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 ) ;

37 // I n r e g i s t r a r e a g r u p u l u i de a c t i v a r e p e n t r o b t i n e r e a
38 // 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
39 ActivationGroupID 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 ) ;
40 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 . ” ) ;

42 // 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
43 M a r s h a l l e d O b j e c t data = n u l l ;
44 i f ( filename != n u l l && ! filename . equals ( ” ” ) ) {
45 data = new M a r s h a l l e d O b j e c t ( filename ) ;
46 }

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

50 // 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
51 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 ) ;
52 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 . ” ) ;

54 // 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
55 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” ) ;
70 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

56 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 ) ;
57 System . e r r . p r i n t l n ( ” Stub bound i n r e g i s t r y . ” ) ;
58 }
59 }

Sursele celor două programe CmmdcActivabil.java şi respectiv Setup.java sunt


ı̂n catalogul \c\src\acmmdc.
Lansarea serverului ı̂n execuţie constă din
1. Pornirea demon-ului rmid

start rmid -J-Djava.security.policy=rmid.policy


-J-Dmyactivation.policy=group.policy

unde rmid.policy este

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

iar group.policy are codul

grant codeBase "${myactivation.impl.codebase}" {


// permission to read and write object’s file
permission java.io.FilePermission "${myactivation.file}","read,write";

// permission to listen on an anonymous port


permission java.net.SocketPermission "*:1024-","accept";
};

2. Pornirea registry-ului

start rmiregistry

3. Lansarea programului Setup

set classpath=\s\public\classes\cmmdc.jar;\s\public\classes
java -Djava.rmi.server.codebase=file:/s/public/classes/
-Dmyactivation.impl.codebase=file:/s/public/classes/
-Dmyactivation.name=CmmdcServer
-Dmyactivation.file=""
-Dmyactivation.policy=group.policy
acmmdc.Setup acmmdc.CmmdcActivabil
4.2. CORBA 71

Localizarea (URL) interfeţei la distanţă se precizează prin


java.rmi.server.codebase;
Drept client se utilizează programul realizat ı̂n secţiunea 4.1.

4.2 CORBA
Reţelele de calculatoare sunt eterogene ı̂n timp ce majoritatea interfeţelor de
programare a aplicaţiilor sunt orientate spre platforme omogene.
Pentru a facilita integrarea unor sisteme dezvoltate separat, ı̂ntr-un singur mediu
distribuit eterogen, OMG (Object Management Group – consorţiu cuprinzând peste
800 de firme) a elaborat standardul CORBA (Common Object Request Brocker
Arhitecture): un cadru de dezvoltare a aplicaţiilor distribuite ı̂n medii eterogene.
La CORBA au aderat toate marile firme de software - cu exceptia Microsoft,
firmă care a dezvoltat propriul său model DCOM (Distributed Component Object
Model), incompatibil CORBA.
CORBA conţine programe client care utilizează diferite obiecte distribuite ı̂n
sistem. Deoarece ı̂n multe sisteme de operare prelucrările trebuie să evolueze ı̂ntr-
un proces, orice obiect trebuie să evolueze ı̂ntr-un proces. În alte cazuri, obiectele
pot evolua ı̂n fire de execuţie sau ı̂n biblioteci dll. CORBA omogenizează aceste
posibilităţi prin precizarea că obiectele există ı̂n servere. Fiecare obiect este asociat
cu un singur server.
Interconectarea obiectelor. Implementarea şi localizarea unui obiect sunt as-
cunse clientului. Comunicarea ı̂ntre client şi obiect este facilitată de Object Request
Brocker (ORB) – care permite obiectelor să se regăseacă unele pe altele ı̂n reţea.
El ajută obiectele să facă cereri şi să primească răspunsuri de la alte obiecte aflate
ı̂n reţea. Acestea se desfăşoară transparent pentru client – care nu ştie unde este
localizat obiectul, care este mecanismul utilizat pentru a comunica cu el, cum este
activat sau memorat acesta.
ORB este un pachet de servicii, independent de aplicaţii, dar care permit aplicaţiilor
să interacţioneze prin reţea. ORB face parte din middleware – un intermediar ı̂ntre
softul de reţea şi cel de aplicaţie.
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.
CORBA face o separare ı̂ntre interfaţa unui obiect şi implementarea sa şi foloseşte
un limbaj neutru pentru definirea interfeţelor: IDL -- Interface Defi- nition
Language.
IDL permite realizarea descrierii de interfeţe independent de limbajul de pro-
gramare şi de sistemul de operare folosit. O interfaţă IDL defineşte legătura dintre
client şi server.
72 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

4.2.1 Conexiunea RMI - CORBA


Firma SUN a dezvoltat o soluţie prin care programele RMI pot fi adaptate pentru
a putea accesa obiecte CORBA. Aceasta este cunoscută sub numele de soluţia RMI-
IIOP, concretizată printr-o serie de pachete din distribuţia JDK. În acest fel nu mai
este necesar utilizarea limbajului IDL pentru descrierea interfeţelor la distanţă.
Instrumente necesare utilizării soluţiei RMI-IIOP:
• compilatorul rmic
Opţiunea -iiop genereaza stub-ul şi legătura (tie) din partea serverului.
Cu opţiunea -d se specifică catalogul ı̂n care aceste fişiere sunt scrise.

• serverul care asigură regăsirea resurselor CORBA. Acest server se lansează ı̂n
execuţie prin
start orbd -ORBInitialPort [port]

Transformarea unui program RMI ı̂ntr-un program RMI-IIOP


Exemplificăm prin aplicaţia care implementează un serviciu de calcul a celui mai
mare divizor comun a două numere naturale. Etapele realizării aplicaţiei sunt:

1. Elaborarea interfeţei este identică cu cea a aplicaţiei RMI.

2. Implementarea interfeţei

1 package cmmdciiop ;
2 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 ;
3 import cmmdc . ∗ ;
4 import j a v a . rmi . ∗ ;

6 // 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
7 // s i nu UnicastRemoteObject

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


10 // C o n s t r u c t o r u l c l a s e i
11 p u b l i c CmmdcImpl ( ) throws RemoteException {}

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

3. Realizarea programului server.

1 package cmmdciiop ;
2 import j a v a x . naming . I n i t i a l C o n t e x t ;
3 import j a v a x . naming . Context ;

5 p u b l i c c l a s s CmmdcServer {
6 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 ) {
4.2. CORBA 73

7 try {
8 // 1 : C r e a r e a u n e i i n s t a n t e CmmdcImpl
9 CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ;

11 // 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
12 // u t i l i z a n d JNDI API
13 Context i n i t i a l N a m i n g C o n t e x t = new I n i t i a l C o n t e x t ( ) ;
14 i n i t i a l N a m i n g C o n t e x t . r e b i n d ( ” CmmdcService ” , cmmdcRef ) ;

16 System . out . p r i n t l n ( ”Cmmdc S e r v e r : Ready . . . ” ) ;


17 }
18 catch ( Exception e ) {
19 System . out . p r i n t l n ( ” CmmdcServer: ” + e . g e t M e s s a g e ( ) ) ;
20 }
21 }
22 }

4. Compilarea programelor CmmdcImpl.java şi CmmdcServer.java.

5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunzător interfeţei ICm-


mdc şi a fişierului Tie cmmdciiop. CmmdcImpl Tie.class corespunzător clasei
CmmdcImpl. Acestea se obţin rulând utilitarul rmic - din distrubuţia Java –
cu opţiunea -iiop

rmic -iiop cmmdciiop.CmmdcImpl

6. Pornirea serverului CORBA de regăsire a serviciilor

start orbd -ORBInitialPort 1050

7. Lansarea serverului ı̂n execuţie. Trebuie fixate proprietăţile

java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
java.naming.provider.url=iiop://localhost:1050

Cu excepţia pct. 6, activităţile legate de server se obţin cu fişierul ant-build


1 <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=” . ”>
2 <description> S e r v e r a c t i o n s </ description>
3 < !−− 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 −−>

5 <property name=” package ” v a l u e=” cmmdciiop ” />


6 <property name=” i n t e r f a c e −package ” v a l u e=”cmmdc” />
7 <property name=” i n t e r f a c e −j a r ” l o ca t io n=” \ i \ p u b l i c \ c l a s s e s \cmmdc” />
8 <property name=” j a r − f i l e ” v a l u e=”cmmdc . j a r ” />
9 <property name=” s e r v i c e −c l a s s ” v a l u e=”CmmdcServer” />
10 <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” />
11 <property name=” h o s t ” v a l u e=” l o c a l h o s t ” />
12 <property name=” p o r t ” v a l u e=” 1050 ” />

14 <target name=” I n s t a l l ”>


74 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

15 < !−− C r e a t e t h e time stamp −−>


16 <tstamp/>
17 < !−− 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 −−>
18 <delete d i r=” s r c ” />
19 <mkdir d i r=” s r c ” />
20 <delete d i r=” p u b l i c ” />
21 <mkdir d i r=” p u b l i c ” />
22 <delete d i r=” p u b l i c / c l a s s e s ” />
23 <mkdir d i r=” p u b l i c / c l a s s e s ” />
24 </ target>

26 <target name=” I n i t ”>


27 <mkdir d i r=” s r c /${ package } ” />
28 <mkdir d i r=” p u b l i c / c l a s s e s /${ package } ” />
29 <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 ” />
30 <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 ” />
31 <delete d i r=” p u b l i c / c l a s s e s /META−INF” />
32 </ target>

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


35 <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 ”
36 i n c l u d e s=” ${ package }\∗∗ ”
37 classpath=” p u b l i c \ c l a s s e s \${ j a r − f i l e } ” />
38 <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 } ”
39 s o u r c e b a s e=” s r c ”
40 i i o p=” y e s ”
41 b a s e=” p u b l i c / c l a s s e s ”
42 classpath=” p u b l i c / c l a s s e s ” />
43 </ target>

45 <target name=”Run” depends=” Compile ” description=” S t a r t t h r s e r v e r ” >


46 <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 ”>
47 <classpath>
48 <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 } ” />
49 <pathelement path=” p u b l i c \ c l a s s e s ” />
50 </ classpath>
51 <sysproperty key=” j a v a . naming . f a c t o r y . i n i t i a l ”
52 v a l u e=”com . sun . j n d i . cosnaming . CNCtxFactory ” />
53 <sysproperty key=” j a v a . naming . p r o v i d e r . u r l ”
54 v a l u e=” i i o p : //${ h o s t } : ${ p o r t } ” />
55 </ java>
56 </ target>
57 </ project>

8. Editarea programului client.

1 package cmmdciiop ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . n e t . MalformedURLException ;
4 import j a v a x . rmi . ∗ ;
5 import j a v a x . naming . ∗ ;
6 import cmmdc . ∗ ;
7 import j a v a . u t i l . S c a n n e r ;

9 public c l a s s CmmdcClient {
10 public s t a t i c void main ( S t r i n g a r g s [ ] ) {
4.2. CORBA 75

11 S t r i n g h o s t=” l o c a l h o s t ” ;
12 i n t p o r t =1099;
13 i f ( a r g s . l e n g t h >0)
14 h o s t=a r g s [ 0 ] ;
15 i f ( a r g s . l e n g t h >1)
16 p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;

18 Sca nner s c a n n e r=new Sca n n e r ( System . i n ) ;


19 System . out . p r i n t l n ( ” Primul numar : ” ) ;
20 long m=Long . parseLong ( s c a n n e r . n e x t ( ) ) ;
21 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;
22 long n=Long . parseLong ( s c a n n e r . n e x t ( ) ) ;

24 long x =0;
25 Context i c ;
26 Object o b j r e f ;
27 ICmmdc o b j ;
28 try {
29 i c = new I n i t i a l C o n t e x t ( ) ;

31 // 1 . O b t i n e r e a u n e i r e f e r i n t e de l a s e r v i c i u l CORBA
32 // p r i n a p e l JNDI .
33 o b j r e f = i c . l o o k u p ( ” CmmdcService ” ) ;
34 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 . ” ) ;

36 // 2 . A s o c i e r e a r e f e r i n t e i l a s e r v i c i u cu i n t e r f a t a
37 // s i i n v o c a r e a m e t o d e i
38 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 ) ;
39 x=o b j . cmmdc(m, n ) ;
40 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
41 }
42 catch ( E x c e p t i o n e ) {
43 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 ( ) ) ;
44 }
45 }
46 }

9. Compilarea şi lansarea clientului ı̂n execuţie. Clientul trebuie să dispună de
fişierul stub (cmmdc. ICmmdc Stub.class) şi bineı̂nţeles de interfaţa ICmmdc.jar.
La apelarea clientului trebuie fixate proprietăţile

java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
java.naming.provider.url=iiop://localhost:1050

Fişierul buildfile pentru executarea clientului:


1 <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=” . ”>
2 <description> C l i e n t a c t i o n s </ description>
3 < !−− 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 −−>

5 <property name=” package ” v a l u e=” cmmdciiop ” />


6 <property name=” i n t e r f a c e −j a r ” l oc a t io n=” \ i \ p u b l i c \ c l a s s e s \cmmdc” />
7 <property name=” j a r − f i l e ” v a l u e=”cmmdc . j a r ” />
8 <property name=” s e r v e r −package ” v a l u e=” cmmdciiop ” />
9 <property name=” s e r v e r −stub−l o c a t i o n ”
10 location=” \ s \ p u b l i c \ c l a s s e s \${ s e r v e r −package } ” />
76 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

11 <property name=” i n t e r f a c e −package ” v a l u e=”cmmdc” />


12 <property name=” i n t e r f a c e −stub−l o c a t i o n ”
13 location=” \ s \ p u b l i c \ c l a s s e s \${ i n t e r f a c e −package } ” />
14 <property name=” stub−c l a s s ” v a l u e=” ∗ S t u b . c l a s s ” />
15 <property name=” h o s t ” v a l u e=” l o c a l h o s t ” />
16 <property name=” p o r t ” v a l u e=” 1050 ” />
17 <property name=” c l i e n t −c l a s s ” v a l u e=” CmmdcClient ” />

19 <target name=” I n s t a l l ”>


20 < !−− 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 −−>
21 <delete d i r=” s r c ” />
22 <mkdir d i r=” s r c ” />
23 <delete d i r=” c l a s s e s ” />
24 <mkdir d i r=” c l a s s e s ” />
25 </ target>

27 <target name=” I n i t ”>


28 < !−− C r e a t e t h e time stamp −−>
29 <tstamp/>
30 <mkdir d i r=” s r c /${ package } ” />
31 <mkdir d i r=” c l a s s e s /${ package } ” />
32 <delete d i r=” c l a s s e s /${ s e r v e r −package } ” />
33 <mkdir d i r=” c l a s s e s /${ s e r v e r −package } ” />
34 <delete d i r=” c l a s s e s /${ i n t e r f a c e −package } ” />
35 <mkdir d i r=” c l a s s e s /${ i n t e r f a c e −package } ” />
36 <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 ” />
37 <copy t o d i r=” c l a s s e s /${ s e r v e r −package } ” >
38 < f i l e s e t d i r=” ${ s e r v e r −stub−l o c a t i o n } ” i n c l u d e s=” ${ stub−c l a s s } ” />
39 </copy>
40 <copy t o d i r=” c l a s s e s /${ i n t e r f a c e −package } ” >
41 < f i l e s e t d i r=” ${ i n t e r f a c e −stub−l o c a t i o n } ”
42 i n c l u d e s=” ${ stub−c l a s s } ” />
43 </copy>
44 <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 ” />
45 <delete d i r=” c l a s s e s /META−INF” />
46 </ target>

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


49 <javac s r c d i r=” s r c ” d e s t d i r=” c l a s s e s ”
50 i n c l u d e s=” ${ package } \ ∗ . j a v a ”
51 classpath=” c l a s s e s ” />
52 </ target>

54 <target name=”Run” depends=” Compile ” description=” S t a r t t h r c l i e n t ” >


55 <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 ”>
56 <classpath>
57 <pathelement loc a t io n=” c l a s s e s \${ j a r − f i l e } ” />
58 <pathelement path=” c l a s s e s ” />
59 </ classpath>
60 <sysproperty key=” j a v a . naming . f a c t o r y . i n i t i a l ”
61 v a l u e=”com . sun . j n d i . cosnaming . CNCtxFactory ” />
62 <sysproperty key=” j a v a . naming . p r o v i d e r . u r l ”
63 v a l u e=” i i o p : //${ h o s t } : ${ p o r t } ” />
64 </ java>
65 </ target>
66 </ project>
4.2. CORBA 77

4.2.2 Aplicaţie Java prin CORBA


Scopul acestei secţiuni este prezentarea dezvoltării unei aplicaţii pe baza unei
interfeţe bazat pe IDL.
Pentru dezvoltarea aplicaţiilor ı̂n limbajul de programare Java, translatarea
interfeţei IDL ı̂n Java se realizează cu utilitarul idlj din distribuţia jdk.
Corespondenţa ı̂ntre entităţile IDL şi Java este dată ı̂n Tabelul 4.1

Tip IDL Tip Java


module package
boolean boolean
char, wchar char
octet byte
string, wstring java.lang.String
short, unsigned short short
long, unsigned long int
long long, unsigned long long long
float float
double double
fixed java.math.BigDecimal
enum, struct, union class
sequence, array array
interface (non-abstract) signature interface,
operations interface,
helper class, holder class
Any org.omg.CORBA.Any

Table 4.1: Entităţi IDL şi Java

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

Model cu server temporal


Exemplificăm dezvoltarea unei aplicaţii distribuite CORBA ı̂n cazul ı̂n care ser-
viciul pus la dispoziţie de server este calculul celui mai mare divizor comun a două
numere naturale.
Dezvoltarea unei aplicaţii distribuite CORBA cu mediul nativ Java presupune
parcurgerea următoarelor paşi:

1. Realizarea interfeţei IDL care ı̂nseamnă


(a) Editarea programului de interfaţă:
78 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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

Salvăm acest text ı̂ntr-un fişier denumit Cmmdc.idl.


Cmmdc va fi numele serviciului căutat de un client şi implementat de
server. Serviciul conţine o singură metodă cmmdc.
(b) Translatarea ı̂n Java

idlj -fall Cmmdc.idl

Programul idlj crează un subcatalog CmmdcApp cu un pachet Java CmmdcApp


conţinând fişierele:

• Cmmdc.java
• CmmdcPOA.java ;
• CmmdcOperations.java;
• CmmdcStub.java;
• CmmdcHelper.java;
• CmmdcHolder.java.

2. Realizarea programelor server. Punem ı̂n evidenţa programul servant Cmmd-


cImpl.java ce implementează interfaţa Cmmdc.
1 import CmmdcApp . ∗ ;
2 import o r g . omg .CORBA. ∗ ;

4 p u b l i c c l a s s CmmdcImpl e x t e n d s CmmdcPOA {
5 p r i v a t e ORB orb ;

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


8 t h i s . orb = orb ;
9 }

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

şi programul CmmdcServer.java, care ı̂nscrie ı̂n registrul ORB referinţele ser-
vantului. Activităţile ce trebuie ı̂ntreprinse sunt declarate prin comentarii ı̂n
textul sursă al programului
1 import CmmdcApp . ∗ ;
2 import o r g . omg . CosNaming . ∗ ;
3 import o r g . omg . CosNaming . NamingContextPackage . ∗ ;
4 import o r g . omg .CORBA. ∗ ;
4.2. CORBA 79

5 import o r g . omg . P o r t a b l e S e r v e r . ∗ ;

7 p u b l i c c l a s s CmmdcServer {
8 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 [ ] ) {
9 try {
10 // c r e a r e a s i i n i t i a l i z a r e a ORB
11 ORB orb = ORB. i n i t ( a r g s , n u l l ) ;

13 // o b t i n e r e a u n e i r e f e r i n t e r o o t p o a s i a c t i v a r e a m a n a g e r u l u i POAManager
14 POA r o o t p o a = 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” ) ) ;
15 r o o t p o a . the POAManager ( ) . a c t i v a t e ( ) ;

17 // c r e a r e a unui s e r v a n t
18 CmmdcImpl cmmdcImpl = new CmmdcImpl ( orb ) ;

20 // o b t i n e r e a u n e i r e f e r i n t e a s e r v a n t u l u i
21 o r g . omg .CORBA. O b j e c t r e f = r o o t p o a . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ;
22 Cmmdc h r e f = CmmdcHelper . narrow ( r e f ) ;

24 // O b t i n e r e a s e r v i c i u l u i NameService
25 o r g . omg .CORBA. O b j e c t o b j R e f =
26 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 ” ) ;
27 NamingContextExt ncRef = NamingContextExtHelper . narrow ( o b j R e f ) ;

29 // l e g a r e a r e f e r i n t e i s e r v a n t u l u i i n s e r v i c i u l NameService
30 S t r i n g name = ” CmmdcService ” ;
31 NameComponent path [ ] = ncRef . to name ( name ) ;
32 ncRef . r e b i n d ( path , h r e f ) ;

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

36 // i n a s t e p t a r e a c l i e n t i l o r
37 orb . run ( ) ;
38 }
39 catch ( Exception e ) {
40 System . e r r . p r i n t l n ( ”ERROR: ” + e ) ;
41 e . p r i n t S t a c k T r a c e ( System . out ) ;
42 }
43 System . out . p r i n t l n ( ”CmmdcServer E x i t i n g . . . ”);
44 }
45 }

3. Realizarea programului client CmmdcClient.java:


1 import CmmdcApp . ∗ ;
2 import o r g . omg . CosNaming . ∗ ;
3 import o r g . omg . CosNaming . NamingContextPackage . ∗ ;
4 import o r g . omg .CORBA. ∗ ;
5 import j a v a . u t i l . Sc anne r ;

7 p u b l i c c l a s s CmmdcClient {
8 s t a t i c Cmmdc cmmdcImpl ;

10 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 [ ] ) {
11 try {
12 // 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
13 ORB orb = ORB. i n i t ( a r g s , n u l l ) ;

15 // 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
80 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

16 // s e r v i c i i l o r i n r e g i s t r a t e
17 o r g . omg .CORBA. O b j e c t o b j R e f =
18 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 ” ) ;
19 NamingContextExt ncRef = NamingContextExtHelper . narrow ( o b j R e f ) ;

21 // 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
22 S t r i n g name = ” CmmdcService ” ;
23 cmmdcImpl = CmmdcHelper . narrow ( ncRef . r e s o l v e s t r ( name ) ) ;

25 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 : ” + cmmdcImpl ) ;


26 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
27 l o n g m, n ;
28 System . out . p r i n t l n ( ”m=” ) ;
29 m=s c a n n e r . nextLong ( ) ;
30 System . out . p r i n t l n ( ”n=” ) ;
31 n=s c a n n e r . nextLong ( ) ;
32 System . out . p r i n t l n ( ”Cmmdc=”+cmmdcImpl . cmmdc(m, n ) ) ;
33 }
34 catch ( Exception e ) {
35 System . out . p r i n t l n ( ”ERROR : ” + e ) ;
36 e . p r i n t S t a c k T r a c e ( System . out ) ;
37 }
38 }
39 }

Programele se compilează

javac CmmdcApp\*.java

4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din


distribuţia jdk.

start orbd -ORBInitialHost localhost -ORBInitialPort 1050

5. Pornirea programului server prin

start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050

6. Lansarea programului client prin

java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050

Model cu server persistent


Se consideră aceaşi interfaţă Cmmdc.idl.
4.2. CORBA 81

Partea de server este alcătuită din clasa servant CmmdcImpl.java care imple-
mentează interfaţa Cmmdc -prezentat ı̂n secţiunea anterioară şi clasa PersistentServer
care asigură

• legătura cu serviciile ORB;

• accesul la clasa servantului.

1 import java . u t i l . Properties ;


2 import o r g . omg .CORBA. ∗ ;
3 import o r g . omg . CosNaming . ∗ ;
4 import o r g . omg . P o r t a b l e S e r v e r . ∗ ;

6 public class PersistentServer {


7 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 [ ] ) {
8 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 ( ) ;
9 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 ” ) ;
10 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 ” ) ;
11 try {
12 // Pas 1 : I n s t a n t i e r e ORB
13 ORB orb = ORB. i n i t ( a r g s , p r o p e r t i e s ) ;

15 // Pas 2 : I n s t a n t i e r e a s e r v a n t u l u i
16 CmmdcImpl s e r v a n t = new CmmdcImpl ( orb ) ;

18 // Pas3 3 : C r e a r e a unui o b i e c t POA cu s e c u r i t a t e a P e r s i s t e n t P o l i c y


19 // ∗ ∗ ∗ ∗ ∗∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗
20 // Pas 3−1 : O b t i n e r e a r a d a c i n i i rootPOA
21 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” ) ) ;
22 // Pas 3−2 : 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
23 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 ] ;
24 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 (
25 L i f e s p a n P o l i c y V a l u e . PERSISTENT ) ;
26 // Pas 3−3 : 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
27 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 ) ;
28 // Pas 3−4 : A c t i v a r e a m a n a g e r u l u i PersistentPOA POAManager ,
29 p e r s i s t e n t P O A . the POAManager ( ) . a c t i v a t e ( ) ;
30 // ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

32 // Pas 4 : A s o c i e r e a s e r v a n t u l u i cu PersistentPOA
33 persistentPOA . a c t i v a t e o b j e c t ( servant ) ;

35 // Pas 5 : 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


36 // Numele s e r v i c i u l u i ORBD : ’ NameService ’
37 // Numele s e r v a n t u l u i ’ P e r s i s t e n t C m m d c S e r v e r ’

39 o r g . omg .CORBA. O b j e c t o b j = 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 ” ) ;


40 NamingContextExt r o o t C o n t e x t = NamingContextExtHelper . narrow ( o b j ) ;
41 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 ” ) ;
42 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 ( s e r v a n t ) ) ;

44 // Pas 6 : Gata p e n t r u r e c e p t i a c e r e r i l o r clientilor


45 orb . run ( ) ;
46 }
47 catch ( Exception e ) {
48 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 ) ;
49 }
82 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

50 }
51 }

Programul client
1 import java . u t i l . Properties ;
2 import o r g . omg .CORBA. ∗ ;
3 import o r g . omg . CosNaming . ∗ ;
4 import o r g . omg . P o r t a b l e S e r v e r .POA;

6 import CmmdcApp . CmmdcHelper ;


7 import CmmdcApp . Cmmdc ;
8 import j a v a . u t i l . Sc anne r ;

10 public class PersistentClient {


11 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 [ ] ) {
12 S t r i n g h o s t=” l o c a l h o s t ” ;
13 S t r i n g p o r t=” 1050 ” ;
14 i f ( a r g s . l e n g t h >0)
15 h o s t=a r g s [ 0 ] ;
16 i f ( a r g s . l e n g t h >1)
17 p o r t=a r g s [ 1 ] ;
18 try {
19 // Pas 1 : I n i t i a l i z a r e ORB
20 ORB orb = ORB. i n i t ( a r g s , n u l l ) ;

22 // Pas 2 : R e z o l v a r e a p e r s i s t e n t e i
23 // 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
24 // 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
25 // ” P e r s i s t e n t C m m d c S e r v e r ”
26 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 (
27 ” 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 ” ) ;
28 Cmmdc cmmdc=CmmdcHelper . narrow ( o b j ) ;

30 // Pas 3 : U t i l i z a r e a s e r v i c i u l u i
31 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
32 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 . . ” ) ;
33 i n t m, n , r ;
34 System . out . p r i n t l n ( ”m=” ) ;
35 m=s c a n n e r . n e x t I n t ( ) ;
36 System . out . p r i n t l n ( ”n=” ) ;
37 n=s c a n n e r . n e x t I n t ( ) ;
38 System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ;
39 }
40 catch ( Exception e ) {
41 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 ) ;
42 e . printStackTrace ( ) ;
43 }
44 }
45 }

Serverul trebuie să fie pe acelaşi calculator pe care rulează orbd. Executarea
aplicaţiei presupune:
1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exe din
distribuţia jdk.

start orbd -ORBInitialPort 1050 -serverPollingTime 200


4.2. CORBA 83

2. Activarea serverului:

(a) Se lansează utilitarul servertool


servertool -ORBInitialPort 1050
(b) Se ı̂nregistrează serverul ı̂mpreună cu numele serviciului pe care ı̂l ı̂ndeplineşte:

servertool > register -server PersistentServer


-applicationName PersistentCmmdcServer
-classpath cale_catre_fisierele_server\

3. Executarea clientului
java PersistentClient [hostORB [portORB]]
84 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ
Capitolul 5

Mesaje ı̂n Java

Comunicaţia prin apelul la distanţă - inclusiv RMI - este sincron: programul


apelant se blochează şi aşteaptă ca metoda apelată să se termine şi să furnizeze
rezultatul cerut. Cu alte cuvinte apelul de procedură la distanţă cere atât clientului
cât şi serverului să fie simultan disponibile.
Comunicaţiile asincrone ı̂ntre programe permit realizarea unor sisteme de pro-
grame cu un grad mult mai scăzut de cuplare.

5.1 Java Message Service (JMS)


JMS defineşte un cadru de programare Java (API) pentru realizarea aplicaţiilor
bazate pe comunicaţii asincrone. Există mai multe implementări JMS, dintre care
semnalăm:

• Sun Java System Message Queue a firmei Sun. Versiunea Platform Edition
este gratuită.

• ActiveMQ realizată de fundaţia apache.

O aplicaţie JMS este alcătuită din

• un furnizor JMS (provider JMS) : un sistem de mesagerie ce implementează


specificaţiile JMS;

• client JMS : aplicaţie Java care trimite şi recepţionează mesaje;

• mesaje : obiecte utilizate ı̂n schimbul de informaţii de clienţi JMS;

• obiecte administrator : obiecte (resurse) create de administrator pentru a fi


utilizate de clienţii JMS, precum fabrica de conexiuni, obiectele destinaţie
ı̂mpreună cu resursele lor.

85
86 CAPITOLUL 5. MESAJE ÎN JAVA

Modele de comunicaţie:
• Comunicaţii punctuale : Un mesaj este generat de un producător (expeditor)
şi la care va avea acces un singur consumator (destinatar). Mesajul este depus
ı̂ntr-o coadă, de unde este preluat de către consumatorul care s-a legat de
coadă. Dacă de coadă nu se leagă nici un consumator, atunci mesajul este
păstrat ı̂n coadă.

• Comunicaţii axate pe subiect (topic) : Mesajele sunt depuse (publicate) ı̂n


destinaţii specifice subiectului. Consumatorii ce au subscris la acel subiect
au acces la mesajele respective. Mai multi producători pot genera mesaje
specifice unui subiect, mesaje care pot fi accesate de consumatorii care au
subscris subiectului.
Structura unui mesaj Un mesaj este alcătuit din
• Antet (header) : conţine informaţii pentru identificarea destinaţiei cât şi pentru
identificarea mesajului.

• Proprietăţi : au caracter opţional şi sunt sub forma (nume, valoare). Pro-
prietăţile ajută consumatorii să selecteze mesajele.

• Corpul mesajului : opţional. Potrivit specificaţiilor JMS există 6 tipuri de


mesaje.

– Message : mesaj fără corp;


– StreamMessage : corpul mesajului conţine un flux Java de date de tip
predefinit;
– ByteMessage :
– MapMessage : corpul mesajului conţine o familie de perechi (nume, val-
oare);
– TextMessage : corpul mesajului conţine un string;
– ObjectMessage : corpul mesajului conţine un obiect serializat.

5.2 Sun Java System Message Queue


Instalarea. Funcţie de resursa descărcată, ı̂n mediul Windows, instalarea constă
din
• Se dezarhivează fişierul mq* *-installer-WINNT.zip şi se lansează ı̂n execuţie
programul de instalare.

• Se dezarhivează fişierul mq* *-binary-WINNT*.jar şi se fixează atributele fişierului


mq\etc\imqenv.conf.
5.3. APACHE ACTIVEMQ 87

Lansarea serviciului JMS. Orice aplicaţie JMS necesită funcţionarea servici-


ului JMS. Serviciul JMS se instalează prin
imqbrokerd -tty
Opţiunea -tty are ca efect afişarea mesajelor pe ecran. Funcţionarea corectă este
indicată prin mesajul
imqbroker@hostname:7676 ready
Dacă se doreşte schimbarea portului atunci se foloseşte opţiunea -port port.
Pe un calculator pot coexista mai multe servicii JMS doar dacă folosesc porturi
distincte şi au nume diferite. În acest caz, lansarea unui nou serviciu se face prin
imqbrokerd -tty -port port -name name
Cu utilitarul imqsvcadmin putem
• dezinstala : imqsvcadmin remove
• verifica : imqsvcadmin query
• instala : imqsvcadmin install
serviciul JMS ca serviciu Windows. Dezinstalarea şi instalarea are efect odată cu
repornirea calculatorului.
Compilarea şi executarea unui program necesită completarea variabilei sistem
classpath cu fişierele
• JMS HOME\lib\jms.jar
• JMS HOME\lib\imq.jar

5.3 Apache ActiveMQ


Instalarea se face dezarhivând fişierul descărcat ı̂ntr-un catalog ACTIVEMQ HOME.
Acest fişier este specific sistemului de operare utilizat, Windows sau Linux.
Lansarea serverului JMS se obţine prin
set JAVA_HOME=. . .
set ACTIVEMQ_HOME=. . .
set PATH=%ACTIVEMQ_HOME%\bin;%PATH%
activemq

În cazul unui calculator izolat este nevoie de instalarea driver-ului Microsoft loopback
Adaptor care sinulează existenţa funcţonării unei plăci de reţea active.
Distribuţia apache-activemq-5.*.* conţine, ca exemplu, clasa EmbeddedBroker.java
care lansează serverul JMS ı̂n lucru.
Compilarea unui program necesită prezenţa ı̂n variabila de sistem classpath a
referinţei către fişierul ACTIVEMQ HOME\activemq-all-*.*.*.jar. Pentru execuţie,
variabila de sistem classpath nevoie să conţină referinţele către fişierele jar din
catalogul ACTIVEMQ HOME\lib.
88 CAPITOLUL 5. MESAJE ÎN JAVA

5.4 Elemente de programare - JMS


5.4.1 Trimiterea unui mesaj
Trimiterea unui mesaj necesită:

1. Generarea unei fabrici de conexiuni. Fabrica de conexiuni este un obiect ad-


ministrator. Această operaţie este specifică distribuţiei JMS.

• În cazul de faţa folosim obiectele create prin MessageQueue.


Se poate obţine prin
ConnectionFactory cf=
new com.sun.messaging.ConnectionFactory();
Clasa com.sun.messaging.ConnectionFactory conţine metoda
setProperty( String name, String value) prin intermediul căreia se
precizează calculatorul şi portul furnizorului de servicii JMS, fixând atributele
"imqBrokerHostName" şi respectiv "imqBrokerHostPort".
• Utilizând apache-activemq, fabrica de conexiuni se obţine prin
org.apache.activemq.ActiveMQConnectionFactory cf=
new org.apache.activemq.ActiveMQConnectionFactory
("tcp://host:61616");

2. Generarea conexiunii.
Se realizează prin

Connection conn=cf.createConnection();

Pentru realizarea acestui obiectiv se utilizează metoda createConnection,


după caz, dintr-una din clasele

class ConnectionFactory{
Connection createConnection() throws JMSException;
Connection createConnection(String userName,String password)
throws JMSException;
}
class QueueConnectionFactory{
QueueConnection createQueueConnection() throws JMSException;
QueueConnection createQueueConnection(String userName,
String password) throws JMSException;
}
class TopicConnectionFactory{
5.4. ELEMENTE DE PROGRAMARE - JMS 89

TopicConnection createTopicConnection() throws JMSException;


TopicConnection createTopicConnection(String userName,
String password) throws JMSException;
}

unde Connection, QueueConnection, TopicConnection sunt interfeţe.


Amintim următoarele metode ale unei interfeţe Connection

interface Connection{
Session createSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}
interface QueueConnection{
QueueSession createQueueSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}
interface TopicConnection{
TopicSession createTopicSession(boolean transacted,
int acknowledgeMode) throws JMSException;
void start() throws JMSException;
void close() throws JMSException;
}

Un obiect ce implementează interfaţa Connection asigură legătura clientului


cu furnizorul JMS. Acest obiect este creat de fabrica de conexiuni.
Un client JMS trebuie să ı̂nchidă conexiunile create.
Metoda start() asigură pornirea sau repornirea conexiunii ı̂n vederea recepţionării
mesajelor sosite.

3. Crearea unei sesiuni de lucru se face cu o metodă createSession().

Session session=conn.createSession(false,
Session.AUTO_ACKNOWLEDGE);

Primul argument asigură (true) sau nu (false) caracterul indivizibil al unităţii


de lucru, adică al unei sesiuni.
Al doilea argument indică modul de confirmare al receptării mesajului.
90 CAPITOLUL 5. MESAJE ÎN JAVA

Un obiect de tip Session defineşte un context format dintr-un singur fir de


execuţie ı̂n care are loc producerea şi consumul de mesaje.
Sunt definite

interface Session{
| MessageProducer createProducer(Destination destination);
| MessageConsumer createConsumer(Destination destination);
| Message createMessage();
| TextMessage createTextMessage();
| TextMessage createTextMessage(String s);
| StreamMessage createStreamMessage();
| MapMessage createMapMessage();
| ObjectMessage createObjectMessage();
| ObjectMessage createObjectMessage(Serializable object);
| BytesMessage createBytesMessage();
| }
|->interface QueueSession{
| QueueSender createQueueSender(Queue queue);
| QueueReceiver createQueueReceiver(Queue queue);
| }
|->interface TopicSession{
TopicPublisher createPublisher(Topic topic);
TopicSubscriber createSubscriber(Topic topic);
TopicSubscriber createDurableSubscriber(Topic topic,
String name);
}

4. Generarea obiectului destinaţie.


În cazul comunicaţiilor punctuale obiectul destinaţie este de tip Queue, iar
crearea se face prin

Destination numeDestinatie=sesssion.createQueue(String numeCoada)

iar pentru comunicaţii axate pe subiect obiectul destinaţie, de tip Topic se


instanţiază prin

Destination numeDestinatie=sesssion.createTopic(String numeSubiect)

Sunt definite arborescenţele:

interface Destination
5.4. ELEMENTE DE PROGRAMARE - JMS 91

|
|->interface Queue
|
|->interface Topic

class Destination implements Destination


|
|->class Queue implements Destination, Queue, Serializable
|
|->class Topic implements Destination, Topic, Serializable

Utilizând Sun Java System Message Queue obiecte de tip Queue sau Topic se
pot crea şi prin

Queue q=new com.sun.messaging.Queue(String numeCoada);


Topic t=new com.sun.messaging.Topic(String numeSubiect);

5. Generarea producătorului de mesaje. Se realizează prin

MessageProducer producer=session.createProducer(obiectDestinatie);

Sunt definite interfeţele

interface MessageProducer{
void send(Message mesaj);
}
interface QueueSender{
void send(Message mesaj);
}
interface TopicPublisher{
void publish(Message mesaj);
}

6. Generarea mesajelor. Un mesaj de tip TextMessage se poate crea prin

TextMessage m=session.createTextMessage();
m.setText(string);

7. Expedierea mesajelor se face cu metoda send(...) a producătorului de


mesaje.
92 CAPITOLUL 5. MESAJE ÎN JAVA

Exemplul 5.4.1 Clasa următoare generează ı̂ntr-un fir de execuţie, un număr de


mesaje de tip TextMessage ı̂ntr-o comunicaţie punctuală. Sfârşitul expedierii mesajelor
se indică prin generarea unui mesaj de tip Message. Numărul mesajelor este indicat
de un parametru al constructorului.

1 import j a v a x . jms . ∗ ;

3 public c l a s s MsgSenderT extends Thread {


4 int n ;
5 S t r i n g queueName ;

7 MsgSenderT ( S t r i n g queueName , i n t n ) {
8 t h i s . queueName=queueName ;
9 t h i s . n=n ;
10 }

12 public void run ( ) {


13 try {
14 // V a r i a n t a Sun Message Queue
15 com . sun . m e s s a g i n g . QueueConnectionFactory c f=
16 new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ;

18 // s e t P r o p e r t y e s t e metoda a c l a s e i
19 // com . sun . m e s s a g i n g . QueueConnnectionFactory
20 // ce im plemen tea z a i n t e r f a t a QueueConnectionFactory
21 // dar nu a i n t e r f e t e i QueueConnectionFactory .
22 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
23 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;

25 // V a r i a n t a Apache−MessageQueue
26 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
27 //new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;
28 C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ;
29 S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;

31 D e s t i n a t i o n q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ;

33 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( q ) ;

35 TextMessage m=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ;
36 f o r ( i n t i =0; i <n ; i ++){
37 m. s e t T e x t ( ” H e l l o ”+i ) ;
38 p r o d u c e r . send (m) ;
39 }
40 // indicam s f a r s i t u l t r i m i t e r i i m e s a j e l o r
41 p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ;
42 session . close ();
43 conn . c l o s e ( ) ;
44 }
45 catch ( E x c e p t i o n e ) {
46 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
47 }
48 System . out . p r i n t l n ( ” Sen de r f i n i s h e d ” ) ;
49 }
50 }
5.4. ELEMENTE DE PROGRAMARE - JMS 93

5.4.2 Recepţia sincronă a unui mesaj


Primele patru acţiuni sunt identice cu cele de la trimiterea unui mesaj, adică

1. Generarea unei fabrici de conexiuni.

2. Generarea conexiunii.

3. Crearea unei sesiuni de lucru.

4. Generarea obiectului destinaţie.

5. Generarea consumatorului de mesaje. Se realizează prin

MessageConsumer consumer=session.createConsumer(q);

Sunt definite interfeţele

interface MessageConsumer{
| Message receive();
| Message receive(long timeout);
| Message receiveNoWait();
| }
|-> interface QueueReceiver
|
|-> interface TopicSubscriber

6. Recepţia mesajelor se face cu una din metodele consumatorului de mesaje:

• Message receive()
• Message receive(long timeout)
• Message receiveNoWait()

Exemplul 5.4.2 Recepţia de tip sincron a mesajelor ı̂ntr-un fir de execuţie este
efectuat de clasa următoare:

1 import j a v a x . jms . ∗ ;

3 public c l a s s SyncMsgReceiverT extends Thread {


4 S t r i n g queueName ;

6 SyncMsgReceiverT ( S t r i n g queueName ) {
7 t h i s . queueName=queueName ;
8 }

10 public void run ( ) {


11 try {
94 CAPITOLUL 5. MESAJE ÎN JAVA

12 // V a r i a n t a Sun Message Queue


13 com . sun . m e s s a g i n g . QueueConnectionFactory c f=
14 new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ;
15 // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory
16 // ce im plemen tea z a i n t e r f a t a QueueConnectionFactory
17 // dar nu e s t e a i n t e r f e t e i .
18 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
19 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;

21 // V a r i a n t a Apache−MessageQueue
22 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
23 //new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;
24 C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ;
25 S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
26 D e s t i n a t i o n q=s e s s i o n . c r e a t e Q u e u e ( queueName ) ;
27 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;
28 conn . s t a r t ( ) ;
29 Message msg=n u l l ;
30 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
31 i f ( msg instanceof TextMessage ) {
32 TextMessage m=(TextMessage ) msg ;
33 System . out . p r i n t l n (m. g e t T e x t ( ) ) ;
34 }
35 else
36 break ;
37 }
38 session . close ();
39 conn . c l o s e ( ) ;
40 }
41 catch ( E x c e p t i o n e ) {
42 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
43 }
44 System . out . p r i n t l n ( ” Consumer f i n i s h e d ” ) ;
45 }
46 }

Exemplul 5.4.3 Trimiterea şi recepţia mesajelor se face prin aplicaţia

1 c l a s s MsgHelloT {
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
3 i n t n=3;
4 S t r i n g queueName=”MyQueue” ;
5 i f ( a r g s . l e n g t h >0)
6 queueName=a r g s [ 0 ] ;
7 i f ( a r g s . l e n g t h >1)
8 n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
9 MsgSenderT s e n d e r=new MsgSenderT ( queueName , n ) ;
10 SyncMsgReceiverT r e c e i v e r =new SyncMsgReceiverT ( queueName ) ;
11 receiver . start ();
12 sender . s t a r t ( ) ;
13 }
14 }
5.4. ELEMENTE DE PROGRAMARE - JMS 95

5.4.3 Recepţia asincronă a unui mesaj


Recepţia asincronă a mesajelor presupune implementarea interfeţei
MessageListener ce conţine o singură metodă

public void onMessage(Message mesaj);

care fixează prelucrarea mesajului.


Metoda MessageConsumer.setMessageListener(MessageListener obj ) fixează
obiectul ce implementează interfaţa Messagelistener.

Exemplul 5.4.4 În ideea exemplelor anterioare, un consumator de tip asincron al


mesajelor este dat ı̂n clasa următoare:

1 import j a v a x . jms . ∗ ;
2 public c l a s s AsyncMsgReceiverT extends Thread {
3 S t r i n g queueName ;

5 AsyncMsgReceiverT ( S t r i n g queueName ) {
6 t h i s . queueName=queueName ;
7 }

9 public void run ( ) {


10 try {
11 // V a r i a n t a Sun Message Queue
12 com . sun . m e s s a g i n g . QueueConnectionFactory c f=
13 new com . sun . m e s s a g i n g . QueueConnectionFactory ( ) ;
14 // s e t P r o p e r t y e s t e metoda a c l a s e i QueueConnnectionFactory
15 // ce imp lement eaza i n t e r f a t a QueueConnectionFactory
16 // dar nu e s t e a i n t e r f e t e i .
17 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
18 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;

20 // V a r i a n t a Apache−MessageQueue
21 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
22 // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;

24 C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ;
25 S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
26 D e s t i n a t i o n q==s e s s i o n . c r e a t e Q u e u e ( queueName ) ;
27 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;
28 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 ( ) ;
29 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 ) ;
30 conn . s t a r t ( ) ;
31 t e x t L i s t e n e r . run ( ) ;
32 conn . c l o s e ( ) ;
33 }
34 catch ( E x c e p t i o n e ) {
35 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
36 }
37 System . out . p r i n t l n ( ” Consumer f i n i s h e d ” ) ;
38 }
39 }

41 import j a v a x . jms . ∗ ;
96 CAPITOLUL 5. MESAJE ÎN JAVA

42 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 {
43 boolean s f a r s i t =f a l s e ;
44 public void onMessage ( Message message ) {
45 i f ( message instanceof TextMessage ) {
46 TextMessage m=(TextMessage ) message ;
47 try {
48 System . out . p r i n t l n (m. g e t T e x t ( ) ) ;
49 }
50 catch ( JMSException e ) {
51 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
52 }
53 }
54 else
55 s f a r s i t =true ;
56 }

58 public void run ( ) {


59 while ( ! s f a r s i t ) ;
60 }
61 }

5.4.4 Publicarea mesajelor


Publicarea mesajelor corespunzătoare unui subiect se face asemănător cu trans-
miterea mesajelor ı̂n comunicaţia punctuală, dar folosind instanţe ale claselor dedi-
cate acestui tip de comunicaţie.

Exemplul 5.4.5

1 import j a v a x . jms . ∗ ;

3 public c l a s s MsgPublisherT extends Thread {


4 int n ;
5 String subiect ;

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

12 public void run ( ) {


13 try {
14 // V a r i a n t a Sun Message Queue
15 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=
16 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 ( ) ;
17 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
18 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;

20 // V a r i a n t a Apache−MessageQueue
21 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
22 // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;

24 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
25 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
26 Destination t = session . createTopic ( subiect ) ;
5.4. ELEMENTE DE PROGRAMARE - JMS 97

27 MessageProducer p r o d u c e r = s e s s i o n . c r e a t e P r o d u c e r ( t ) ;

29 // Topic t=new com . sun . m e s s a g i n g . Topic ( s u b i e c t ) ;


30 // T o p i c P u b l i s h e r p u b l i s h e r=s e s s i o n . c r e a t e P u b l i s h e r ( t ) ;

32 TextMessage m=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ;
33 f o r ( i n t i =0; i <n ; i ++){
34 m. s e t T e x t ( ” Despre ”+s u b i e c t+” ”+i ) ;
35 p r o d u c e r . send (m) ;
36 // p u b l i s h e r . p u b l i s h (m) ;
37 }
38 p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ;
39 // p u b l i s h e r . p u b l i s h ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ;
40 session . close ();
41 conn . c l o s e ( ) ;
42 }
43 catch ( E x c e p t i o n e ) {
44 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
45 }
46 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 ” ) ;
47 }
48 }

Varianta comentată este o soluţie specifică implementării Sun Java System Mes-
sage Queue.

5.4.5 Subscrierea şi recepţia mesajelor


Dacă t este obiectul de tip Destination, clienţii se abonează - subscriu - unui
subiect prin

TopicSubscriber consumer=session.createSubscriber((Topic)t);

Subscrierea este este valabilă atâta timp cât clientul este activ. Pentru a primi toate
mesajele specifice subiectului, chiar şi când clientul este inactiv, acesta trebuie să fie
durabil, adică crearea consumatorului să se facă prin

conn.setClientID("myID");
TopicSubscriber consumer=
session.createDurableSubscriber((Topic)t,"nameClient");

În ambele cazuri, clientul primeşte doar mesajele publicate din momentul subscrierii.

Exemplul 5.4.6

1 import j a v a x . jms . ∗ ;

3 public c l a s s MsgSubscriberT extends Thread {


4 String subiect ;
5 String clientID ;
6 S t r i n g clientName ;
98 CAPITOLUL 5. MESAJE ÎN JAVA

8 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 ) {
9 t h i s . s u b i e c t=s u b i e c t ;
10 t h i s . c l i e n t I D=c l i e n t I D ;
11 t h i s . c l i e n t N a m e=c l i e n t N a m e ;
12 }

14 public void run ( ) {


15 try {
16 // V a r i a n t a Sun Message Queue
17 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=
18 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 ( ) ;
19 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
20 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;

22 // V a r i a n t a Apache−MessageQueue
23 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
24 //new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;

26 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
27 conn . s e t C l i e n t I D ( c l i e n t I D ) ;
28 T o p i c S e s s i o n s e s s i o n=
29 conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
30 Destination t = session . createTopic ( subiect ) ;
31 T o p i c S u b s c r i b e r consumer=
32 s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t , c l i e n t N a m e ) ;
33 conn . s t a r t ( ) ;
34 Message msg=n u l l ;
35 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
36 i f ( msg instanceof TextMessage ) {
37 TextMessage m=(TextMessage ) msg ;
38 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 ( ) ) ;
39 }
40 else
41 break ;
42 }
43 session . close ();
44 conn . c l o s e ( ) ;
45 }
46 catch ( E x c e p t i o n e ) {
47 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
48 }
49 }
50 }

Apelarea celor două activităţi se face prin

Exemplul 5.4.7

1 c l a s s MsgPS{
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
3 S t r i n g s u b i e c t=”JMS” ;
4 i n t n=3 , noAbonati =3;
5 i f ( a r g s . l e n g t h >0)
6 s u b i e c t=a r g s [ 0 ] ;
7 i f ( a r g s . l e n g t h >1)
8 n=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
9 MsgPublisherT p u b l i s h e r=new MsgPublisherT ( s u b i e c t , n ) ;
10 MsgSubscriberT [ ] abonat=new MsgSubscriberT [ noAbonati ] ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 99

11 publisher . start ( ) ;
12 f o r ( i n t i =0; i <noAbonati ; i ++){
13 abonat [ i ]=new MsgSubscriberT ( s u b i e c t , ”ID”+i , ” i d ”+i ) ;
14 abonat [ i ] . s t a r t ( ) ;
15 }
16 }
17 }

Observaţie. ActiveMQ conţine un serviciu de nume JNDI care oferă posibili-


tatea creeri şi inregistrării obiectelor administrator de tip Connection Factory şi
Destination.
Contextul iniţial se defişte prin
String queueName=. . .
String subiect=. . .
java.util.Properties props = new java.util.Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL,
"tcp://localhost:61616");
props.setProperty("queue."+queueName,queueName);
props.setProperty("topic."+subiect,subiect);

javax.naming.Context ctx = new javax.naming.InitialContext(props);


sau
javax.naming.Context ctx=new javax.naming.InitialContext();
ı̂mreună cu fişierul jndi.properties
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

# use the following property to configure the default connector


#java.naming.provider.url = vm://localhost
java.naming.provider.url = tcp://localhost:61616

# register some queues in JNDI using the form


# queue.[jndiName] = [physicalName]
queue.MyQueue = MyQueue

# register some topics in JNDI using the form


# topic.[jndiName] = [physicalName]
topic.MyTopic = MyTopic
Obiectele administrator se definesc prin
QueueConnectionFactory cf=(QueueConnectionFactory)ctx.lookup("ConnectionFactory");
Destination q=(Destination)ctx.lookup(queueName);
respectiv
TopicConnectionFactory cf=(TopicConnectionFactory)ctx.lookup("ConnectionFactory");
Destination t=(Destination)ctx.lookup(subiect);

5.5 Mesaje SOAP prin Java Message Service


Rezultatele acestei secţiuni sunt valabile doar ı̂n cazul pachetului Sun Java Sys-
tem Message Queue.
100 CAPITOLUL 5. MESAJE ÎN JAVA

5.5.1 SOAP
SOAP - Simple Object Access Protocol - este un protocol de comunicaţii ı̂ntre
aplicaţii. În prezent SOAP este protocolul standard pentru servicii Web prin Inter-
net. SOAP este independent de platforma de calcul şi de limbajul de programare.
SOAP se bazează pe XML (eXtended Markup Language) şi este un standard
W3C (World Wide Web Consortium).

5.5.2 Mesaje SOAP


Un mesaj SOAP este un document XML constând din

• o ı̂nvelitoare (envelope) care poate conţine

• un număr arbitrar de antete (header );

• un corp (body);

• un număr variabil de obiecte ataşate (attachments) MIME (Multipurpose In-


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

Facilităţile Java de manipulare a mesajelor SOAP sunt conţinute ı̂n pachetul


javax.xml.soap, din distribuţia jdk.
În acestă secţiune vom crea mesaje SOAP, le transformăm ı̂n mesaje JMS pe
care le trimitem furnizorului JMS, de unde un client le recepţionează, după care
transformă mesajul JMS ı̂n mesaj SOAP şi regăseşte datele expediate. Soluţia este
specifică implementării Sun Java System Message Queue.

Crearea unui mesaj SOAP


MessageFactory mf=MessageFactory.newInstance();
SOAPMessage soapMsg=mf.createMessage();

Mesajul creat are definită structura de bază a mesajului SOAP: invelitoarea, un


antetul şi corpul. Aceste elemente pot fi accesate prin
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 101

SOAPPart part=soapMsg.getSOAPPart();
SOAPEnvelope envelope=part.getEnvelope();
SOAPHeader header=envelope.getHeader();
SOAPBody body=envelope.getBody();

Completarea corpului unui mesaj SOAP


Generăm numele elementului, ”e1” ı̂n cazul exemplului,

Name n1=envelope.createName("e1");

În body un element se poate include, pe baza numelui creat prin

SOAPElement e1=body.addBodyElement(n1);

În general, un element se include ı̂n elementul părinte, care pote fi chiar şi body, prin
metoda clasei SOAPElement

SOAPElement addChildElement(Name name)

Completăm elementul e1 cu un text: ”primul”, prin

e1.addTextNode("primul");

Exemplul 5.5.1 Mesajul SOAP


1 <SOAP−ENV:Envelope xmlns:SOAP−ENV=” 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 / ”>
2 <SOAP−ENV:Header />
3 <SOAP−ENV:Body>
4 <e1>
5 primul
6 <e11>
7 al treilea
8 </ e11>
9 </ e1>
10 <e2>
11 al doilea
12 </ e2>
13 </SOAP−ENV:Body>
14 </SOAP−ENV:Envelope>

se obţine cu programul

1 import j a v a x . xml . soap . ∗ ;


2 import j a v a . i o . ∗ ;

4 public c l a s s MsgSOAP{
5 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
6 Name name=n u l l ;
7 try {
8 MessageFactory mf=MessageFac to ry . n e w I n s t a n c e ( ) ;
9 SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ;
10 SOAPPart p a r t=soapMsg . getSOAPPart ( ) ;
102 CAPITOLUL 5. MESAJE ÎN JAVA

11 SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
12 SOAPBody body=e n v e l o p e . getBody ( ) ;
13 Name n1=e n v e l o p e . createName ( ” e1 ” ) ;
14 SOAPElement e1=body . addBodyElement ( n1 ) ;
15 e1 . addTextNode ( ” p r i m u l ” ) ;
16 Name n2=e n v e l o p e . createName ( ” e2 ” ) ;
17 SOAPElement e2=body . addBodyElement ( n2 ) ;
18 e2 . addTextNode ( ” a l d o i l e a ” ) ;
19 Name n11 =e n v e l o p e . createName ( ” e11 ” ) ;
20 SOAPElement e11=e1 . addChildElement ( n11 ) ;
21 e11 . addTextNode ( ” a l t r e i l e a ” ) ;
22 F i l eO u t p u t St r e a m f=new F i l e O u t p u t S t r e a m ( ”MySOAPMessage . xml” ) ;
23 soapMsg . writ eTo ( f ) ;
24 }
25 catch ( E x c e p t i o n e ) {
26 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 ( ) ) ;
27 }
28 }
29 }

Un mesaj SOAP se poate salva ı̂ntr-un fişier text cu

FileOutputStream f=new FileOutputStream(. . .);


soapMsg.writeTo(f);

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

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();
. . .
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 103

}
}

Exemplul 5.5.2 Un client introduce ı̂ntr-un mesaj SOAP două numere ı̂ntregi,
transmite mesajul altui program care calculează cel mai mare divizor comun al celor
două numere şi transmite clientului rezultatul tot sub forma unui mesaj SOAP.

Activitatea clientului este se compune din


• Transmiterea către server a cererii. Mesajul este alcătuit din cele două numere
şi un topic, ı̂n care va găsi răspunsul.
1 import j a v a x . jms . ∗ ;
2 import j a v a x . xml . soap . ∗ ;
3 import com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ;
4 import java . u t i l . ∗ ;

6 public c l a s s MsgSOAPClientSender {

8 long a , b ;
9 String topicResult ;
10 S t r i n g c l i e n t I D , clientName ;

12 MsgSOAPClientSender ( S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) {
13 t h i s . c l i e n t I D=c l i e n t I D ;
14 t h i s . c l i e n t N a m e=c l i e n t N a m e ;
15 Sca nner s c a n n e r=new Sca n n e r ( System . i n ) ;
16 System . out . p r i n t l n ( ” I n t r o d u c e t i m : ” ) ;
17 a=s c a n n e r . nextLong ( ) ;
18 System . out . p r i n t l n ( ” I n t r o d u c e t i n : ” ) ;
19 b=s c a n n e r . nextLong ( ) ;
20 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 ” ) ;
21 t o p i c R e s u l t=s c a n n e r . n e x t ( ) ;
22 }

24 public void s e r v i c e ( ) {
25 MessageFactory mf=n u l l ;
26 SOAPMessage soapMsg=n u l l ;
27 SOAPPart p a r t=n u l l ;
28 SOAPEnvelope e n v e l o p e=n u l l ;
29 SOAPBody body=n u l l ;
30 SOAPElement elem=n u l l ;
31 Name name=n u l l ;
32 try {
33 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=
34 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 ( ) ;
35 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” a t l a n t i s ” ) ;
36 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
37 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
38 conn . s e t C l i e n t I D ( c l i e n t I D ) ;
39 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
40 D e s t i n a t i o n tDate=s e s s i o n . c r e a t e T o p i c ( ”Cmmdc” ) ;
41 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( tDate ) ;
42 mf=MessageFactory . n e w I n s t a n c e ( ) ;
43 soapMsg=mf . c r e a t e M e s s a g e ( ) ;
44 p a r t=soapMsg . getSOAPPart ( ) ;
45 e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
104 CAPITOLUL 5. MESAJE ÎN JAVA

46 body=e n v e l o p e . getBody ( ) ;
47 name=e n v e l o p e . createName ( ” n1 ” ) ;
48 elem=body . addChildElement ( name ) ;
49 elem . addTextNode ( (new Long ( a ) ) . t o S t r i n g ( ) ) ;
50 name=e n v e l o p e . createName ( ” n2 ” ) ;
51 elem=body . addChildElement ( name ) ;
52 elem . addTextNode ( (new Long ( b ) ) . t o S t r i n g ( ) ) ;
53 name=e n v e l o p e . createName ( ” t o p i c ” ) ;
54 elem=body . addChildElement ( name ) ;
55 elem . addTextNode ( t o p i c R e s u l t ) ;
56 D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c R e s u l t ) ;
57 T o p i c S u b s c r i b e r consumer=
58 s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ;
59 Message m=
60 MessageTr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;
61 p r o d u c e r . send (m) ;
62 F i l e Ou t p u t St r e a m f=new F i l e O u t p u t S t r e a m ( ”MySOAPMessage . xml” ) ;
63 soapMsg . writ e T o ( f ) ;
64 conn . c l o s e ( ) ;
65 }
66 catch ( E x c e p t i o n e ) {
67 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 ( ) ) ;
68 }
69 System . out . p r i n t l n ( ” Sen de r f i n i s h e d ” ) ;
70 }

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


73 i f ( a r g s . l e n g t h <2){
74 System . out . p r i n t l n ( ” Usage : ” ) ;
75 System . out . p r i n t l n ( ” j a v a MsgSOAPClientSender c l i e n t I D c l i e n t N a m e ” ) ;
76 System . e x i t ( 0 ) ;
77 }
78 MsgSOAPClientSender c l i e n t=new MsgSOAPClientSender ( a r g s [ 0 ] , a r g s [ 1 ] ) ;
79 client . service ();
80 }
81 }

• Recepţionarea răspunsului.
1 import j a v a x . jms . ∗ ;
2 import j a v a x . xml . soap . ∗ ;
3 import com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ;
4 import java . u t i l . ∗ ;

6 public c l a s s MsgSOAPClientReceiver {

8 String topicResult ;
9 S t r i n g c l i e n t I D , clientName ;

11 MsgSOAPClientReceiver ( S t r i n g c l i e n t I D , S t r i n g c l i e n t N a m e ) {
12 t h i s . c l i e n t I D=c l i e n t I D ;
13 t h i s . c l i e n t N a m e=c l i e n t N a m e ;
14 Sc anne r s c a n n e r=new S c a n n e r ( System . i n ) ;
15 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 ” ) ;
16 t o p i c R e s u l t=s c a n n e r . n e x t ( ) ;
17 }

19 public void s e r v i c e ( ) {
20 MessageFactory mf=n u l l ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 105

21 SOAPMessage soapMsg=n u l l ;
22 SOAPPart p a r t=n u l l ;
23 SOAPEnvelope e n v e l o p e=n u l l ;
24 SOAPBody body=n u l l ;
25 SOAPBodyElement e l e m e n t=n u l l ;
26 Name name=n u l l ;
27 try {
28 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=
29 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 ( ) ;
30 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” a t l a n t i s ” ) ;
31 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
32 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
33 conn . s e t C l i e n t I D ( c l i e n t I D ) ;
34 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e ,
35 S e s s i o n .AUTO ACKNOWLEDGE) ;
36 D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c R e s u l t ) ;
37 T o p i c S u b s c r i b e r consumer=
38 s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ;
39 mf=MessageFactory . n e w I n s t a n c e ( ) ;
40 conn . s t a r t ( ) ;
41 Message msg=consumer . r e c e i v e ( ) ;
42 soapMsg=MessageTransf or m er . SOAPMessageFromJMSMessage ( msg , mf ) ;
43 System . out . p r i n t l n ( ” C l i e n t Mesaj SOAP r e c e p t i o n a t ” ) ;
44 p a r t=soapMsg . getSOAPPart ( ) ;
45 e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
46 body=e n v e l o p e . getBody ( ) ;
47 I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ;
48 S t r i n g s=” ” ;
49 while ( i t e r a t o r . hasNext ( ) ) {
50 e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ;
51 name=e l e m e n t . getElementName ( ) ;
52 i f ( name . getLocalName ( ) . e q u a l s ( ”cmmdc” ) )
53 s=e l e m e n t . g e t V a l u e ( ) ;
54 }
55 System . out . p r i n t l n ( ”Cmmdc : ”+s ) ;
56 conn . c l o s e ( ) ;
57 }
58 catch ( E x c e p t i o n e ) {
59 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 ( ) ) ;
60 }
61 System . out . p r i n t l n ( ” R e c e i v e r f i n i s h e d ” ) ;
62 }

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


65 i f ( a r g s . l e n g t h <2){
66 System . out . p r i n t l n ( ” Usage : ” ) ;
67 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 ” ) ;
68 System . e x i t ( 0 ) ;
69 }
70 MsgSOAPClientReceiver c l i e n t=new MsgSOAPClientReceiver ( a r g s [ 0 ] , a r g s [ 1 ] ) ;
71 client . service ();
72 }
73 }

Programul server este


1 import j a v a x . jms . ∗ ;
2 import j a v a x . xml . soap . ∗ ;
3 import com . sun . m e s s a g i n g . xml . Mes sa g eT ra n sf o rm e r ;
106 CAPITOLUL 5. MESAJE ÎN JAVA

4 import j a v a . u t i l . I t e r a t o r ;

6 public c l a s s MsgSOAPCmmdcServer{

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

10 public void s e r v i c e ( ) {
11 MessageFactory mf=n u l l ;
12 SOAPMessage soapMsg=n u l l ;
13 SOAPPart p a r t=n u l l ;
14 SOAPEnvelope e n v e l o p e=n u l l ;
15 SOAPBody body=n u l l ;
16 SOAPBodyElement e l e m e n t=n u l l ;
17 SOAPElement elem=n u l l ;
18 Name name=n u l l ;
19 try {
20 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
21 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 ( ) ;
22 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” a t l a n t i s ” ) ;
23 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
24 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
25 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e ,
26 S e s s i o n .AUTO ACKNOWLEDGE) ;
27 D e s t i n a t i o n tDate=s e s s i o n . c r e a t e T o p i c ( ”Cmmdc” ) ;
28 T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ;
29 conn . s t a r t ( ) ;
30 Message msg=n u l l ;
31 mf=MessageFactory . n e w I n s t a n c e ( ) ;
32 while ( true ) {
33 msg=consumer . r e c e i v e ( ) ;
34 soapMsg=Message T ra n sf o rm er . SOAPMessageFromJMSMessage ( msg , mf ) ;
35 System . out . p r i n t l n ( ” S e r v e r Mesaj SOAP r e c e p t i o n a t ” ) ;
36 p a r t=soapMsg . getSOAPPart ( ) ;
37 e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
38 body=e n v e l o p e . getBody ( ) ;
39 I t e r a t o r i t e r a t o r=body . g e t C h i l d E l e m e n t s ( ) ;
40 S t r i n g sn1=” ” , sn2=” ” , t o p i c R e s u l t=” ” ;
41 while ( i t e r a t o r . hasNext ( ) ) {
42 e l e m e n t =(SOAPBodyElement ) i t e r a t o r . n e x t ( ) ;
43 name=e l e m e n t . getElementName ( ) ;
44 i f ( name . getLocalName ( ) . e q u a l s ( ” n1 ” ) )
45 sn1=e l e m e n t . g e t V a l u e ( ) ;
46 i f ( name . getLocalName ( ) . e q u a l s ( ” n2 ” ) )
47 sn2=e l e m e n t . g e t V a l u e ( ) ;
48 i f ( name . getLocalName ( ) . e q u a l s ( ” t o p i c ” ) )
49 t o p i c R e s u l t=e l e m e n t . g e t V a l u e ( ) ;
50 }
51 System . out . p r i n t l n ( sn1+” : ”+sn2+” : ”+t o p i c R e s u l t ) ;
52 long a=Long . par se Lon g ( sn1 ) ;
53 long b=Long . pars eL ong ( sn2 ) ;
54 long c=cmmdc( a , b ) ;
55 soapMsg=mf . c r e a t e M e s s a g e ( ) ;
56 p a r t=soapMsg . getSOAPPart ( ) ;
57 e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
58 body=e n v e l o p e . getBody ( ) ;
59 name=e n v e l o p e . createName ( ”cmmdc” ) ;
60 elem=body . addChildElement ( name ) ;
61 elem . addTextNode ( (new Long ( c ) ) . t o S t r i n g ( ) ) ;
62 Message m=
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 107

63 MessageTransformer . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;


64 D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c R e s u l t ) ;
65 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( t R e s u l t ) ;
66 p r o d u c e r . send (m) ;
67 }
68 }
69 catch ( E x c e p t i o n e ) {
70 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 ( ) ) ;
71 }
72 System . out . p r i n t l n ( ” S e r v e r f i n i s h e d ” ) ;
73 }

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


76 MsgSOAPCmmdcServer s e r v e r=new MsgSOAPCmmdcServer ( ) ;
77 server . service ();
78 }
79 }

Mesajul SOAP utilizat de client, pentru n1 = 45, n2 = 35 şi topic = nume este

<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<n1>45</n1>
<n2>35</n2>
<topic>nume</topic>
</soap-env:Body>
</soap-env:Envelope>

5.5.3 Ataşamente SOAP


Crearea ataşamentelor
1. Crearea mesajului SOAP

MessageFactory mf=MessageFactory.newInstance();
SOAPMessage soapMsg=mf.createMessage();

2. • Ataşament text
(a) Crearea unui obiect de tip AttachmentPart
AttachmentPart attachment=soapMsg.createAttachmentPart();
(b) Completarea conţinutului
String stringContent=. . .
attachment.setContent(stringContent, "text/plain");
Conţinutului i se poate ataşa un cod de identificare
attachment.setContentId("Text1");
108 CAPITOLUL 5. MESAJE ÎN JAVA

• Ataşament imagine jpeg/png


(a) Crearea unui obiect de tip AttachmentPart cu ı̂ncărcarea imaginii.
URL url=new URL("file://localhost/c:\\. . .\\***.jpg");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart attachment =
soapMsg.createAttachmentPart(dataHandler);
attachment.setContentId("Imagine1");
• Ataşament cu sunet ı̂n format mp3.
(a) Crearea unui obiect de tip AttachmentPart cu ı̂ncărcarea fişierului
mp3.
URL url=new URL("file://localhost:c:\\. . .\\***.mp3");
DataHandler dataHandler=new DataHandler(url);
AttachmentPart attachment =
soapMsg.createAttachmentPart(dataHandler);
attachment.setContentId("attached_mp3");

3. Includerea ataşamentului ı̂n mesajul SOAP


soapMsg.addAttachmentPart(attachment);

Extragerea ataşamentelor
Tipul unui ataşament se poate deduce din rezultatul metodei getContentId sau
getContentType a clasei AttachmentPart.

Iterator iterator = soapMsg.getAttachments();


while (iterator.hasNext()) {
AttachmentPart attached =
(AttachmentPart)iterator.next();
// Codul de identificare
String id = attached.getContentId();
// Tipul atasamentului
String type = attached.getContentType();

// Preluarea unui string


if (type.equals("text/plain")) {
Object content = attached.getContent();
. . .
}

// Preluarea unei imagini


if (type.equals("image/jpeg")){
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 109

Image image=(Image)attached.getContent();
. . .
}

// Preluarea unei inregistrari mp3


if(type.equals("audio/x-wav")){
System.out.println("Play MP3");
MP3Player mp3Player=new MP3Player(attached.getRawContent());
mp3Player.play();
}
}

Exemplul 5.5.3 Crearea unui mesaj SOAP cu ataşamente text, imagine şi muzică
mp3. Textul, imaginea şi muzica mp3 sunt conţinute ı̂n fişiere. Căile către aceste
fişiere se vor da ca proprietăţi.

1 import j a v a x . jms . ∗ ;
2 import j a v a x . xml . soap . ∗ ;
3 import com . sun . m e s s a g i n g . xml . Mes sa g eT ra n sf o rm e r ;
4 import java . io . ∗ ;
5 import j a v a x . a c t i v a t i o n . DataHandler ;
6 import j a v a . n e t .URL;

8 public c l a s s MsgSOAPPublisher extends Thread {


9 String f i l e l o c a t i o n , image location , mp3 location ;

11 MsgSOAPPublisher ( S t r i n g f i l e l o c a t i o n , S t r i n g i m a g e l o c a t i o n , S t r i n g m p 3 l o c a t i o n ) {
12 this . f i l e l o c a t i o n=f i l e l o c a t i o n ;
13 t h i s . i m a g e l o c a t i o n=i m a g e l o c a t i o n ;
14 t h i s . m p 3 l o c a t i o n=m p 3 l o c a t i o n ;
15 }

17 public void run ( ) {


18 try {
19 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=
20 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 ( ) ;
21 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
22 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e ,
23 S e s s i o n .AUTO ACKNOWLEDGE) ;
24 D e s t i n a t i o n t=s e s s i o n . c r e a t e T o p i c ( ” Date ” ) ;
25 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( t ) ;
26 MessageFactory mf=MessageFac to ry . n e w I n s t a n c e ( ) ;
27 SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ;
28 SOAPPart p a r t=soapMsg . getSOAPPart ( ) ;
29 SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
30 SOAPBody body=e n v e l o p e . getBody ( ) ;
31 Name bodyName=e n v e l o p e . createName ( ” v e r i f ” ) ;
32 SOAPElement e l e m e n t=body . addBodyElement ( bodyName ) ;
33 e l e m e n t . addTextNode ( ” Atasamente ” ) ;

35 // Crearea unui atasament t e x t


36 AttachmentPart attachment1 =
37 soapMsg . c r e a t e A t t a c h m e n t P a r t ( ) ;
110 CAPITOLUL 5. MESAJE ÎN JAVA

38 // Se c o m p l e t e a z a c a l e a l a f i s i e r u l myText . t x t
39 F i l e R e a d e r f r = new F i l e R e a d e r ( f i l e l o c a t i o n ) ) ;
40 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 ) ;

42 S t r i n g stringContent = ”” ;
43 S t r i n g l i n e = br . r e a d L i n e ( ) ;
44 while ( l i n e != n u l l ) {
45 stringContent = stringContent . concat ( l i n e ) ;
46 s t r i n g C o n t e n t = s t r i n g C o n t e n t . c o n c a t ( ” \n” ) ;
47 l i n e = br . r e a d L i n e ( ) ;
48 }

50 attachment1 . s e t C o n t e n t ( s t r i n g C o n t e n t , ” t e x t / p l a i n ” ) ;
51 attachment1 . s e t C o n t e n t I d ( ” a t t a c h e d t e x t ” ) ;
52 soapMsg . addAttachmentPart ( attachment1 ) ;

54 // Crearea unui atasament imagine


55 // Se c o m p l e t e a z u c a l e a l a f i s i e r u l xml−p i c . j p g
56 URL u r l = new URL( ” f i l e : / / ”+i m a g e l o c a t i o n ) ;
57 DataHandler d a t a H a n d l e r = new DataHandler ( u r l ) ;
58 AttachmentPart attachment2 =
59 soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ;
60 attachment2 . s e t C o n t e n t I d ( ” a t t a c h e d i m a g e ” ) ;
61 soapMsg . addAttachmentPart ( attachment2 ) ;

63 // Crearea unui atasament de t i p mp3


64 u r l=new URL( ” f i l e : / / ”+m p 3 l o c a t i o n ) ;
65 d a t a H a n d l e r= new DataHandler ( u r l ) ;
66 AttachmentPart attachment3 =
67 soapMsg . c r e a t e A t t a c h m e n t P a r t ( d a t a H a n d l e r ) ;
68 attachment3 . s e t C o n t e n t I d ( ” attached mp3 ” ) ;
69 soapMsg . addAttachmentPart ( attachment3 ) ;

71 Message m=Message Tr a ns f or m er . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;


72 p r o d u c e r . send (m) ;
73 conn . c l o s e ( ) ;
74 }
75 catch ( E x c e p t i o n e ) {
76 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 ( ) ) ;
77 }
78 System . out . p r i n t l n ( ” P u b l i s h e r f i n i s e d ” ) ;
79 }
80 }

Exemplul 5.5.4 Consumarea unui mesaj SOAP cu ataşamente

1 import j a v a x . jms . ∗ ;
2 import j a v a x . xml . soap . ∗ ;
3 import com . sun . m e s s a g i n g . xml . Me s sa g eT ra n sf o rm e r ;
4 import java . u t i l . I t e r a t o r ;
5 import java . io . ∗ ;
6 import j a v a . awt . ∗ ;

8 public c l a s s MsgSOAPSubscriber extends Thread {

10 public void run ( ) {


11 try {
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 111

12 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=
13 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 ( ) ;
14 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
15 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
16 D e s t i n a t i o n t=s e s s i o n . c r e a t e T o p i c ( ” Date ” ) ;
17 T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ;
18 conn . s t a r t ( ) ;
19 Message msg=n u l l ;
20 MessageFactory mf=MessageFac to ry . n e w I n s t a n c e ( ) ;
21 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
22 SOAPMessage soapMsg=
23 MessageTransformer . SOAPMessageFromJMSMessage ( msg , mf ) ;
24 // E x t r a g e r e a a t a s a m e n t e l o r
25 I t e r a t o r i t e r a t o r = soapMsg . g e t A t t a c h m e n t s ( ) ;
26 while ( i t e r a t o r . hasNext ( ) ) {
27 AttachmentPart a t t a c h e d =(AttachmentPart ) i t e r a t o r . n e x t ( ) ;
28 String id = attached . getContentId ( ) ;
29 S t r i n g t y p e = a t t a c h e d . getContentType ( ) ;
30 System . out . p r i n t l n ( ” Attachment ” + i d +
31 ” has c o n t e n t t y p e ” + t y p e ) ;
32 i f ( type . e q u a l s ( ” t e x t / p l a i n ” ) ) {
33 Object content = attached . getContent ( ) ;
34 System . out . p r i n t l n ( ” Attachment c o n t a i n s : \ n” + c o n t e n t ) ;
35 }
36 i f ( t y p e . e q u a l s ( ” image / j p e g ” ) ) {
37 Image image=(Image ) a t t a c h e d . g e t C o n t e n t ( ) ;
38 ShowImage s=new ShowImage ( image ) ;
39 s . show ( ) ;
40 }
41 i f ( t y p e . e q u a l s ( ” a u d i o /x−wav” ) ) {
42 MP3Player mp3Player=new MP3Player ( a t t a c h e d . getRawContent ( ) ) ;
43 mp3Player . s t a r t ( ) ;
44 }
45 }
46 }
47 conn . c l o s e ( ) ;
48 }
49 catch ( E x c e p t i o n e ) {
50 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 ( ) ) ;
51 }
52 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 ” ) ;
53 }
54 }

Apelarea celor două fire de execuţie se face prin


1 c l a s s MsgAttach {
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
3 S t r i n g f i l e l o c a t i o n =System . g e t P r o p e r t y ( ” f i l e l o c a t i o n ” ) ;
4 S t r i n g i m a g e l o c a t i o n=System . g e t P r o p e r t y ( ” i m a g e l o c a t i o n ” ) ;
5 S t r i n g m p 3 l o c a t i o n=System . g e t P r o p e r t y ( ” m p 3 l o c a t i o n ” ) ;
6 MsgSOAPPublisher p u b l i s h e r=
7 new MsgSOAPPublisher ( f i l e l o c a t i o n , i m a g e l o c a t i o n , m p 3 l o c a t i o n ) ;
8 MsgSOAPSubscriber s u b s c r i b e r=new MsgSOAPSubscriber ( ) ;
9 publisher . start ( ) ;
10 subscriber . start ();
11 }
12 }
112 CAPITOLUL 5. MESAJE ÎN JAVA

Acest program se execută cu comanda


java -Dfile location=... -Dimage location=... -Dmp3 location=... MsgAttach

Programul de afişare a imaginii


1 import j a v a . awt . ∗ ;
2 import j a v a . awt . image . ∗ ;
3 import j a v a x . swing . ∗ ;
4 import java . io . ∗ ;
5 import j a v a x . i m a g e i o . ImageIO ;
6 import java . net . ∗ ;

8 c l a s s MyCanvas extends Canvas {


9 Image image=n u l l ;

11 MyCanvas ( Image image ) {


12 t h i s . image=image ;
13 }

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

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

23 ShowImage ( Image image ) {


24 mc=new MyCanvas ( image ) ;
25 }

27 public void show ( ) {


28 // I n t e r f a t a s w i n g
29 JFrame j f r a m e = new JFrame ( ”The r e c e i v e d image ” ) ;
30 jframe . addNotify ( ) ;
31 j f r a m e . getContentPane ( ) . s e t L a y o u t (new BorderLayout ( ) ) ;
32 j f r a m e . getContentPane ( ) . add (mc , BorderLayout .CENTER) ;
33 j f r a m e . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ;
34 jframe . s e t S i z e (200 ,200);
35 j f r a m e . s e t V i s i b l e ( true ) ;
36 }
37 }

Programul pentru redarea conţinutului unui fişier mp3 necesită prezenţa resursei
jl1.0.jar din pachetul JLayer1.0, descărcabil din internet. Un program de redare este
1 public c l a s s MP3Player extends Thread {
2 private P l a y e r p l a y e r ;

4 public MP3Player ( InputStream i s ) {


5 try {
6 B u f f e r e d I n p u t S t r e a m b i s=new B u f f e r e d I n p u t S t r e a m ( i s ) ;
7 p l a y e r=new P l a y e r ( b i s ) ;
8 }
9 catch ( E x c e p t i o n e ) {
10 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
11 System . e x i t ( 1 ) ;
12 }
13 }
5.6. ADVANCED MESSAGE QUEUE PROTOCOL - QPID 113

15 public void run ( ) {


16 try {
17 player . play ( ) ;
18 }
19 catch ( E x c e p t i o n e ) {
20 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
21 }
22 i f ( p l a y e r != n u l l ) p l a y e r . c l o s e ( ) ;
23 }
24 }

5.6 Advanced Message Queue Protocol - Qpid


Advanced Message Queue Protocol (AMQP) este un protocol dezvoltat de mai
multe firme bazat pe standardele World Wide Web Consortium (W3C) şi Internet
Engineering Task Force (IETF) pentru comunicare cu mesaje prin intermediul unui
serviciu de mesagerie (messaging middleware) şi care se doreşte independent de
limbajul de programare.
Modelul AMQP ı̂nglobează standardul Java Message Servuce - JMS, adică pro-
gramele dezvoltate utilizând Sun Java System Message Queue sau apache-ActiveMQ
se rulează (aproape) fără modificări.
apache-qpid reprezintă o implementare a serviciului de mesagerie care poate fi
folosit de clienti Java, C++, C#, Pyton, Ruby.
Instalatea serviciului de mesagerie revine la

1. Dezarhivarea fişierului descărcat;

2. Generarea unei semnături.


Catalogul QPID HOME\bin conţine fişierul create-example-ssl-stores.bat, care
se adaptează corespunzător iar semnătura generată se depune ı̂n catalogul
QPID HOME\etc.
Următorul exemplu crează semnătura dată de fişierul qpid.keystore.
1 @REM C r e a t e example k e y s t o r e f o r b r o k e r and
2 @REM t r u s t s t o r e f o r c l i e n t /management c o n s o l e .
3 @REM
4 @REM Use g e n e r a t e d q p i d . k e y s t o r e a s t h e b r o k e r s k e y s t o r e
5 @REM Use g e n e r a t e d q p i d . t r u s t s t o r e a s c l i e n t / c o n s o l e s t r u s t s t o r e
6 @REM A l l p a s s w o r d s have v a l u e : password

8 @REM C r e a t e Broker K e y s t o r e :
9 k e y t o o l −genkey − a l i a s q p i d B r o k e r −k e y a l g RSA − v a l i d i t y 365
10 −k e y s t o r e q p i d . k e y s t o r e −s t o r e p a s s password −k e y p a s s password
11 −dname ”CN=unitbv , OU=cs , O=Org , L=Bv , C=R”

13 @REM Export S e l f S i g n e d C e r t :
14 k e y t o o l −e x p o r t − a l i a s q p i d B r o k e r −k e y s t o r e q p i d . k e y s t o r e
15 − f i l e q p i d B r o k e r . c e r −s t o r e p a s s password
114 CAPITOLUL 5. MESAJE ÎN JAVA

17 @REM Import Broker Cert I n t o MC T r u s t S t o r e :


18 k e y t o o l −import − a l i a s q p i d B r o k e r C e r t − f i l e q p i d B r o k e r . c e r
19 −k e y s t o r e q p i d . t r u s t s t o r e −s t o r e p a s s password −noprompt

21 @REM D e l e t e t h e c e r t
22 del qpidBroker . cer

Serviciul de mesagerie se lansează prin


1 s e t JAVA HOME=. . .
2 s e t QPID HOME=. . .
3 s e t QPID WORK=. . .
4 %QPID HOME%\b i n \ qpid−s e r v e r . bat

Catalogul QPID WORK este utilizat de serviciul de mesagerie pentru consemnarea


(logging) evenimentelor, ı̂n catalog fiind prezent un fişier de configurare log4j.xml.
Reluăm aplicaţiile anterioare privind transmiterea / recepţia unui mesaj prin
comunicaţie punctuală utilizând o coadă şi publicarea şi recepţionarea unui mesaj
prin comunicaţie bazată pe subiect ı̂ntr-o variantă independententă de suportul mid-
dleware de serviciu de mesagerie folosit. Regăsirea resurselor gestionate de serviciul
de mesagerie sa va face utilizând JNDI. Da data asta informaţiile necesare regăsirii
resurselor sunt dependente de serviciul de mesagerie. Datele de regăsire sunt fixate
ı̂ntr-un fişier jndi.properties.

Comunicaţia prin coadă - queue


Aplicaţia este alcătuită din clasele MsgHelloT, MsgSenderT, SyncMsgReceiverT,
AsyncMsgReceiverT, TextListener. Faţă de versiunea prezentată se modifică doar
clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgReceiverT.
Clasa MsgSenderT
1 import j a v a x . jms . ∗ ;
2 import j a v a x . naming . ∗ ;
3 import java . u t i l . Properties ;
4 import java . io . ∗ ;

6 public c l a s s MsgSenderT extends Thread {


7 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 ” ;
8 f i n a l S t r i n g QUEUE JNDI NAME = ” queue ” ;
9 private I n i t i a l C o n t e x t c t x ;
10 private i n t n ;
11 private S t r i n g queueName ;

13 MsgSenderT ( S t r i n g queueName , i n t n ) {
14 t h i s . queueName=queueName ;
15 t h i s . n=n ;
16 }

18 public void run ( ) {


19 try {
20 setupJNDI ( ) ;
21 QueueConnectionFactory c f=
5.6. ADVANCED MESSAGE QUEUE PROTOCOL - QPID 115

22 ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ;


23 C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ;
24 S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
25 D e s t i n a t i o n q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ;
26 closeJNDI ( ) ;
27 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( q ) ;

29 TextMessage m=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ;
30 f o r ( i n t i =0; i <n ; i ++){
31 m. s e t T e x t ( ” H e l l o ”+i ) ;
32 p r o d u c e r . send (m) ;
33 }
34 p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ;
35 session . close ();
36 conn . c l o s e ( ) ;
37 }
38 catch ( E x c e p t i o n e ) {
39 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
40 }
41 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;
42 }

44 private void setupJNDI ( ) {


45 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 ( ) ;
46 try {
47 p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream (
48 ” jndi . properties ” ) ) ;
49 }
50 catch ( IOException e ) {
51 System . out . p r i n t l n ( ”JNDI−P r o p e r t i e s E r r o r : ”+e . g e t M e s s a g e ( ) ) ;
52 }
53 try {
54 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 ) ;
55 }
56 catch ( NamingException e ) {
57 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 ) ;
58 }
59 }

61 private void c l o s e J N D I ( ) {
62 try {
63 ctx . c l o s e ( ) ;
64 }
65 catch ( NamingException e ) {
66 System . e r r . p r i n t l n ( ” Unable t o c l o s e JNDI Context : ” + e ) ;
67 }
68 }

70 private O b j e c t lookupJNDI ( S t r i n g name ) {


71 try {
72 return c t x . l o o k u p ( name ) ;
73 }
74 catch ( NamingException e ) {
75 System . e r r . p r i n t l n ( ” E r r o r l o o k i n g up ’ ” + name +
76 ” ’ i n JNDI Context : ” + e ) ;
77 }
78 return n u l l ;
79 }
80 }
116 CAPITOLUL 5. MESAJE ÎN JAVA

Clasa SyncMsgReceiverT
1 import j a v a x . jms . ∗ ;
2 import j a v a x . naming . ∗ ;
3 import java . u t i l . Properties ;
4 import java . io . ∗ ;

6 public c l a s s SyncMsgReceiverT extends Thread {


7 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 ” ;
8 f i n a l S t r i n g QUEUE JNDI NAME = ” queue ” ;
9 private I n i t i a l C o n t e x t c t x ;
10 private S t r i n g queueName ;

12 SyncMsgReceiverT ( S t r i n g queueName ) {
13 t h i s . queueName=queueName ;
14 }

16 public void run ( ) {


17 try {
18 setupJNDI ( ) ;
19 QueueConnectionFactory c f=
20 ( QueueConnectionFactory ) c t x . l o o k u p (CONNECTION JNDI NAME ) ;
21 C o n n e c t i o n conn=c f . c r e a t e C o n n e c t i o n ( ) ;
22 S e s s i o n s e s s i o n=conn . c r e a t e S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
23 D e s t i n a t i o n q=( D e s t i n a t i o n ) c t x . l o o k u p (QUEUE JNDI NAME ) ;
24 closeJNDI ( ) ;
25 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;
26 conn . s t a r t ( ) ;
27 Message msg=n u l l ;
28 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
29 i f ( msg instanceof TextMessage ) {
30 TextMessage m=(TextMessage ) msg ;
31 System . out . p r i n t l n (m. g e t T e x t ( ) ) ;
32 }
33 else {
34 break ;
35 }
36 }
37 session . close ();
38 conn . c l o s e ( ) ;
39 }
40 catch ( E x c e p t i o n e ) {
41 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
42 }
43 System . out . p r i n t l n ( ” Consumer f i n i s h e d ” ) ;
44 }

46 private void setupJNDI ( ) {


47 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 ( ) ;
48 try {
49 p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream (
50 ” jndi . properties ” ) ) ;
51 }
52 catch ( IOException e ) {
53 System . out . p r i n t l n ( ”JNDI−P r o p e r t i e s E r r o r : ”+e . g e t M e s s a g e ( ) ) ;
54 }
55 try {
56 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 ) ;
57 }
58 catch ( NamingException e ) {
5.6. ADVANCED MESSAGE QUEUE PROTOCOL - QPID 117

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


60 }
61 }

63 private void c l o s e J N D I ( ) {
64 try {
65 ctx . c l o s e ( ) ;
66 }
67 catch ( NamingException e ) {
68 System . e r r . p r i n t l n ( ” Unable t o c l o s e JNDI Context : ” + e ) ;
69 }
70 }

72 private O b j e c t lookupJNDI ( S t r i n g name ) {


73 try {
74 return c t x . l o o k u p ( name ) ;
75 }
76 catch ( NamingException e ) {
77 System . e r r . p r i n t l n ( ” E r r o r l o o k i n g up ’ ” + name +
78 ” ’ i n JNDI Context : ” + e ) ;
79 }
80 return n u l l ;
81 }
82 }

Comunicaţia pe bază de subiect - topic


Aplicaţia este alcătuită din clasele MsgPS, MsgPublisherT, MsgSubscriberT.
Faţă de versiunea prezentată se modifică doar clasele MsgPublisherT, MsgSubscrib-
erT.
Clasa MsgPublisherT
1 import j a v a x . jms . ∗ ;
2 import j a v a x . naming . ∗ ;
3 import java . u t i l . Properties ;
4 import java . io . ∗ ;

6 public c l a s s MsgPublisherT extends Thread {


7 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 ” ;
8 private I n i t i a l C o n t e x t c t x ;
9 private i n t n ;
10 private S t r i n g s u b i e c t ;

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

17 public void run ( ) {


18 try {
19 setupJNDI ( ) ;
20 T o p i c C o n n e c t i o n F a c t o r y c f=
21 ( 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 ) ;
22 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
23 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e ,
24 S e s s i o n .AUTO ACKNOWLEDGE) ;
25 conn . s t a r t ( ) ;
118 CAPITOLUL 5. MESAJE ÎN JAVA

26 D e s t i n a t i o n t =( D e s t i n a t i o n ) c t x . l o o k u p ( s u b i e c t ) ;
27 closeJNDI ( ) ;
28 MessageProducer p r o d u c e r = s e s s i o n . c r e a t e P r o d u c e r ( t ) ;
29 TextMessage m=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ;
30 f o r ( i n t i =0; i <n ; i ++){
31 m. s e t T e x t ( ” Despre ”+s u b i e c t+” ”+i ) ;
32 p r o d u c e r . send (m) ;
33 }
34 p r o d u c e r . send ( s e s s i o n . c r e a t e M e s s a g e ( ) ) ;
35 session . close ();
36 conn . c l o s e ( ) ;
37 }
38 catch ( E x c e p t i o n e ) {
39 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
40 }
41 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 ” ) ;
42 }

44 private void setupJNDI ( ) {


45 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 ( ) ;
46 try {
47 p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream ( ”
48 jndi . properties ” ) ) ;
49 }
50 catch ( IOException e ) {
51 System . out . p r i n t l n ( ”JNDI−P r o p e r t i e s E r r o r : ”+e . g e t M e s s a g e ( ) ) ;
52 }
53 try {
54 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 ) ;
55 }
56 catch ( NamingException e ) {
57 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 ) ;
58 }
59 }

61 private void c l o s e J N D I ( ) {
62 try {
63 ctx . c l o s e ( ) ;
64 }
65 catch ( NamingException e ) {
66 System . e r r . p r i n t l n ( ” Unable t o c l o s e JNDI Context : ” + e ) ;
67 }
68 }

70 private O b j e c t lookupJNDI ( S t r i n g name ) {


71 try {
72 return c t x . l o o k u p ( name ) ;
73 }
74 catch ( NamingException e ) {
75 System . e r r . p r i n t l n ( ” E r r o r l o o k i n g up ’ ” + name +
76 ” ’ i n JNDI Context : ” + e ) ;
77 }
78 return n u l l ;
79 }
80 }

Clasa MsgSubscriberT
1 import j a v a x . jms . ∗ ;
2 import j a v a x . naming . ∗ ;
5.6. ADVANCED MESSAGE QUEUE PROTOCOL - QPID 119

3 import j a v a . u t i l . P r o p e r t i e s ;
4 import j a v a . i o . ∗ ;

6 public c l a s s MsgSubscriberT extends Thread {


7 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 ” ;
8 private I n i t i a l C o n t e x t c t x ;
9 private S t r i n g s u b i e c t ;
10 private S t r i n g c l i e n t I D ;
11 private S t r i n g c l i e n t N a m e ;

13 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 ) {
14 t h i s . s u b i e c t=s u b i e c t ;
15 t h i s . c l i e n t I D=c l i e n t I D ;
16 t h i s . c l i e n t N a m e=c l i e n t N a m e ;
17 }

19 public void run ( ) {


20 try {
21 setupJNDI ( ) ;
22 // l o o k u p t h e c o n n e c t i o n f a c t o r y
23 T o p i c C o n n e c t i o n F a c t o r y c f=
24 ( 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 ) ;
25 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
26 // conn . s e t C l i e n t I D ( c l i e n t I D ) ;
27 T o p i c S e s s i o n s e s s i o n=conn . c r e a t e T o p i c S e s s i o n ( f a l s e ,
28 S e s s i o n .AUTO ACKNOWLEDGE) ;
29 D e s t i n a t i o n t =( D e s t i n a t i o n ) c t x . l o o k u p ( s u b i e c t ) ;
30 closeJNDI ( ) ;
31 // T o p i c S u b s c r i b e r consumer=
32 // s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t , c l i e n t N a m e ) ;
33 T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) t ) ;

35 conn . s t a r t ( ) ;
36 Message msg=n u l l ;
37 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
38 i f ( msg instanceof TextMessage ) {
39 TextMessage m=(TextMessage ) msg ;
40 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 ( ) ) ;
41 }
42 else
43 break ;
44 }
45 session . close ();
46 conn . c l o s e ( ) ;
47 }
48 catch ( E x c e p t i o n e ) {
49 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
50 }
51 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 ” ) ;
52 }

54 private void setupJNDI ( ) {


55 // S e t t h e p r o p e r t i e s . . .
56 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 ( ) ;
57 try {
58 p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream (
59 ” jndi . properties ” ) ) ;
60 }
61 catch ( IOException e ) {
120 CAPITOLUL 5. MESAJE ÎN JAVA

62 System . out . p r i n t l n ( ”JNDI−P r o p e r t i e s E r r o r : ”+e . g e t M e s s a g e ( ) ) ;


63 }
64 try {
65 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 ) ;
66 }
67 catch ( NamingException e ) {
68 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 ) ;
69 }
70 }

72 private void c l o s e J N D I ( ) {
73 try {
74 ctx . c l o s e ( ) ;
75 }
76 catch ( NamingException e ) {
77 System . e r r . p r i n t l n ( ” Unable t o c l o s e JNDI Context : ” + e ) ;
78 }
79 }

81 private O b j e c t lookupJNDI ( S t r i n g name ) {


82 try {
83 return c t x . l o o k u p ( name ) ;
84 }
85 catch ( NamingException e ) {
86 System . e r r . p r i n t l n ( ” E r r o r l o o k i n g up ’ ” + name +
87 ” ’ i n JNDI Context : ” + e ) ;
88 }
89 return n u l l ;
90 }
91 }

Fişiere JNDI cu datele de regăsire


Varianta qpid :
1 j a v a . naming . f a c t o r y . i n i t i a l =
2 o r g . apache . q p i d . j n d i . P r o p e r t i e s F i l e I n i t i a l C o n t e x t F a c t o r y

4 # r e g i s t e r some c o n n e c t i o n f a c t o r i e s
5 # c o n n e c t i o n f a c t o r y . [ jndiname ] = [ ConnectionURL ]
6 c o n n e c t i o n f a c t o r y . ConnectionFactory =
7 amqp: // g u e s t : g u e s t @ c l i e n t i d / t e s t ? b r o k e r l i s t= ’ t c p : // l o c a l h o s t : 5 6 7 2 ’

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


10 # queue . [ jndiName ] = [ physicalName ]
11 queue . queue = myqueue

13 # t o p i c . [ jndiName ] = [ physicalName ]
14 t o p i c . JMS = mytopic

Varianta ActiveMQ
1 j a v a . naming . f a c t o r y . i n i t i a l =
2 o r g . apache . a c t i v e m q . j n d i . A c t i v e M Q I n i t i a l C o n t e x t F a c t o r y

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


5 j a v a . naming . p r o v i d e r . u r l = t c p : // l o c a l h o s t : 6 1 6 1 6
5.6. ADVANCED MESSAGE QUEUE PROTOCOL - QPID 121

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


8 # queue . [ jndiName ] = [ physicalName ]
9 queue . queue = myqueue

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


12 # t o p i c . [ jndiName ] = [ physicalName ]
13 t o p i c . t o p i c = mytopic

Varianta Sun Java System Message Queue


1 j a v a . naming . f a c t o r y . i n i t i a l =
2 com . sun . j n d i . f s c o n t e x t . RefFSContextFactory
3 j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp

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

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


8 # queue . [ jndiName ] = [ physicalName ]
9 queue . queue = myqueue

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


12 # t o p i c . [ jndiName ] = [ physicalName ]
13 t o p i c . t o p i c = mytopic

În acest caz este nevoie de crearea ı̂n prealabil a obiectelor corespunzătoare conexi-
unii, a cozii (queue) şi a subiectului (topic). Aceaste obiecte se crează cu utilitarul
imqobjmgr din distribuţia Sun Java System Message Queue.
Obiectele se pot crea cu fişierul de comenzi:
1 s e t PATH=d : \mq\ b i n ;%PATH%
2 imqobjmgr add −t q f − l ” C o n n e c t i o n F a c t o r y ”
3 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
4 −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
5 imqobjmgr add −t q − l ” queue ”
6 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
7 −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
8 imqobjmgr add −t t − l ” t o p i c ”
9 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
10 −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

Obiectele se pot sterge cu fişierul de comenzi:


1 s e t PATH=d : \mq\ b i n ;%PATH%
2 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 ”
3 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
4 −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
5 imqobjmgr d e l e t e −t q − l ” queue ”
6 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
7 −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
8 imqobjmgr d e l e t e −t t − l ” t o p i c ”
9 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
10 −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
122 CAPITOLUL 5. MESAJE ÎN JAVA
Capitolul 6

Servlet

Printre aplicaţiile distribuite de tip client-server, ı̂n care comunicaţiile se bazează


pe protocolul http, se disting

• Aplicaţii Web (site): Cererea adresată serverului este lansată de o persoană


prin intermediul unui site, utilizând un program navigator: Mozilla Firefox,
Opera, Microsoft InternetExplorer, Apple Safari, etc.

• Servicii Web: Cererea către server se face de un program.

Un servlet este un program Java care se excută pe un server Web, compatibil, şi
este capabil să răpundă cererilor formulate de clienţi.
Scrierea şi utilizarea unui servlet necesită

• Cunoaşterea marcajului html <form> pentru realizarea formularelor de in-


troducere a datelor;

• Utilizarea unui server Web, container de servleţi.

6.1 Marcajul <form>

Într-un document html introducerea datelor se poate obţine utilizând marcajul


<form> ...</form> .
Atribute ale marcajului <form> . Reamintim că atributele se prezintă ca
perechi (nume, valoare) şi se scriu ı̂n antetul marcajului sub forma nume = valoare.

123
124 CAPITOLUL 6. SERVLET

Nume Valoare Semnificaţia valorii


action adresa tip URL Resursa care prelucrează formularul.
method GET Mesajul trimis serverului Web conţine după
adresa URL numele şi valorile parametrilor
introduşi. Adăugarea se face potrivit sintaxei
?numeParam1=valoare&numeParam2=valoare. . .
Lungimea mesajului nu poate depăşi 255 caractere.
POST Transmisia datelor se face ı̂n fluxuri de date.
Permite transferul unor fişiere de pe maşina
clientului pe maşina serverului.
id Parametru de identificare a formularului (opţional).
name Nume atribuit formularului (opţional).
onSubmit Metodă JavaScript executată ı̂naintea apelării
serverului Web (opţional).

În conţinutul marcajului <form> putem include elemente de control prin


marcajele

• <input>

• <option>

• <select>

• <textarea>

Atributele marcajului < input> sunt:

Nume Valoare Semnificaţie


type text Se aşteaptă introducerea unui text
number Se aşteaptă introducerea unui număr
password Se aşteaptă introducerea unei parole
submit Se marchează sfârşitul completării formularului
reset Se reiniţializează formularul
file Permite selectarea unui fişier
hidden Transmite mai departe un atribut fără vizualizarea lui
name numele controlului
value valoarea (iniţială) a controlului
size numărul caracterelor ataşat controlului
În cazul marcajului < select> utilizarea este

<select name="nume">
<option value="valoare"> Valoare
6.2. SERVER WEB - CONTAINER DE SERVLET 125

. . . . . . . . . . . . . . . .
</select>
Valoarea atributului nume este dată de valoarea selectată.

6.2 Server Web - container de servlet


În prezent sunt disponibile mai multe servere Web ı̂n care poate fi instalat un
servlet şi un fişier JSP Java server Pages. Se spune că serverul Web este container
de servlet şi JSP. Dintre produsele gratuite amintim
• apache-tomcat

• jetty

• Sun Java System Application Server


Acest server Web este utilizat ı̂n Glassfish - o implementare JEE (Java Enter-
prise Edition).
Geronimo, o alta implementare JEE dezvoltată de apache, poate utiliza con-
tainerul apache-tomcat sau jetty.

Serverul Web apache-tomcat


În continuare se va folosi serverul Web apache-tomcat, pe scurt tomcat.
Serverul Web tomcat este distribuit gratuit, putând fi descărcat de la adresa
www.apache.org.
Instalarea serverului ı̂n mediul Windows revine la dezarhivarea fişierului
descărcat apache-tomcat-***, ı̂ntr-un catalog TOMCAT HOME. Utilizarea serverului
necesită fixarea a doi parametri sistem:
• CATALINA HOME= calea la catalogul ı̂n care s-a instalat produsul - TOMCAT HOME;

• JAVA HOME=calea la distribuţia Java utilizată.


Pachetul conţine cataloagele1 : bin, common, conf, logs, server, shared, temp,
webapps, work.
Serverul se lansează prin comanda
TOMCAT HOME\bin\startup
şi se opreşte cu comanda
TOMCAT HOME\bin\shutdown
1
Numele şi numărul cataloagelor este dependent de distribuţia apache-tomcat.
126 CAPITOLUL 6. SERVLET

Din catalogul TOMCAT HOME, lansarea se poate obţine cu ajutorul fişierului de


comenzi (*.bat)

set CATALINA_HOME=. . .
set JAVA_HOME=. . .
bin\startup

Opţional se poate instala / activa managerul / administatorul serverului Web tom-


cat.
Verificarea funcţionării serverului Web tomcat se face apelând dintr-un navigator
pagina http://host:port unde

• host este numele calculatorului pe care rulează tomcat;

• Portul implicit este 8080.

Reuşita este ilustrată de imaginea motanului

6.3 Realizarea unui servlet


6.3.1 Instalarea unui servlet
Pentru un servlet, ı̂n catalogul webapps, se crează un subcatalog, de exemplu
apphello conţinând

apphello
| |---> WEB-INF
| | |---> classes
| | | web.xml

Catalogul classes conţine fişierele .class ale servletului iar fişierul web.xml
furnizează serverului web informaţii de acces la servlet. Astfel

1. În elementul <servlet> se leagă numele servlet-ului definit ı̂n elementul


<servlet-name> de clasa servlet-ului dat ı̂n elementul
<servlet-class> .

2. În elementul <servlet-mapping> se defineşte numele sub care servlet-ul iden-


tificat prin <servlet-name> nume servlet< /servlet> se invocă din pro-
gramul navigator. Acest identificator - numeApel - se fixează ı̂n elementul
<url-pattern> . Identificatorul are ca prefix caracterul / (slash).
6.3. REALIZAREA UNUI SERVLET 127

Structura unui fişier web.xml este


1 <web−app>
2 < s e r v l e t>
3 <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>
4 <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>
5 </ s e r v l e t>
6 < s e r v l e t>
7 <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>
8 <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>
9 </ s e r v l e t>
10 . . .
11 <s e r v l e t −mapping>
12 <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>
13 <u r l −p a t t e r n>/ numeApel 1</ u r l −p a t t e r n>
14 </ s e r v l e t −mapping>
15 <s e r v l e t −mapping>
16 <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>
17 <u r l −p a t t e r n>/ numeApel 2</ u r l −p a t t e r n>
18 </ s e r v l e t −mapping>
19 . . .
20 </web−app>

Opţional web.xml poate conţine elementul


<welcome-file-list>
<welcome-file>
fisier.html sau jsp
</welcome-file>
</welcome-file-list>

cu precizarea fişierelor html sau jsp care lansează servletul. Declaraţia fişierului
index.html este implicită.
Dacă servlet-ul necesă alte resurse - fişiere jar, atunci acestea se depun ı̂ntr-un
subcatalog lib ı̂n WEB-INF.

O altă variantă de instalare a unui servlet, de exemplu reprezentat prin clasa


HelloServlet.class, ı̂n serverul Web tomcat constă din:

1. Se crează oriunde structura de cataloage şi fişiere

apphello
| |---> WEB-INF
| | |---> classes
| | | | HelloServlet.class
| | | web.xml

2. Din catalogul apphello se realizează arhiva apphello.war


jar cfv apphello.war WEB-INF\∗
care se copiază ı̂n catalogul TOMCAT HOME\webapps.
128 CAPITOLUL 6. SERVLET

3. Se porneşte serverul tomcat, operaţie ı̂n urma căreie arhiva este dezarhivată.
Astfel servlet-ul este instalat.
Dacă serverul tomcat este pornit atunci arhiva se dezarhivează automat şi
servlet-ul este gata de utilizare. Această instalare se numeşte instalare di-
namică - hot deployment.

Dacă fişierul war este creat, atunci ı̂n locul copierii, instalarea se poate face prin
componenta manager a lui tomcat.

O altă posibilitate de instalare a unui servlet ı̂n serverul web tomcat este prin
intermediul produsului apache-tomcat-deployer. apache-tomcat-deployer permite in-
stalarea unui servlet de la distanţă cât şi instalarea comandată dintr-un program.
apache-tomcat-*.*.*-deployer se instalează prin dezarhivarea fişierului apache-tomcat-*.*.*-deployer.
Posibilităţile oferite de apache-tomcat-*.*.*-deployer se obţin rulând ant cu un fişierul build.xml din
distribuţia produsului. Obiectivele care pot fi atinse sunt

• compilarea unui servlet - compile

• instalarea unui servlet - deploy

• dezinstalarea unui servlet - undeploy

În prealabil trebuie completat fişierul de proprietăţi deployer.properties cu

• build=catalogul care va conţine rezultatul compilării şi al arhivării.

• webapp=catalogul cu sursa servlet-ului.

• path=/catalog-ul servlet-ului.

• url=url-ul aplicaţiei manager din Tomcat


http://host:8080/manager

• username=numele de acces ı̂n manager-ul din Tomcat.

• password=parola pentru manager-ul din Tomcat.

Sursa servlet-ului are structura obişnuită, precizată anterior.

6.3.2 Compilarea şi apelarea unui servlet


Compilarea unui program necesită completarea variabilei de mediu classpath
cu fişierul TOMCAT HOME\. . .\servlet-api.jar din distribuţia tomcat. Poziţia
fişierului depinde de versiunea apache-tomcat utilizată.
Un servlet se lansează ı̂n execuţie (se apelează) din

• meniul File/Open a unui program navigator (ex. Mozilla Firefox, Internet


Explorer) prin

http://host:port/catalog/numeApel
6.3. REALIZAREA UNUI SERVLET 129

unde

– catalog este numele catalogului ce conţine servlet-ul - apphello.


– Portul implicit este 8080.
– numeApel este identificatorul fixat ı̂n marcajul url-pattern din fişierul
web.xml.

• ca o referinţă dintr-un document html

<a href="http://host:port/catalog/numeApel "> ...</a>

• ca valoare a atributului action ı̂ntr-un marcaj form

<form action="http://host:port/catalog/numeApel” ... >

Dacă catalog-ul servletului conţine fişierul index.html atunci aplicaţia se poate


apela prin http:// host:port/catalog.
Dacă este prezent elementul <welcome-file-list> ı̂n fişierul web.xml atunci
apelarea aplicaţiei poate fi http:// host:port/catalog/fisier.html—jsp, unde fişier.html
sau jsp este unul din fişierele declarate ı̂ntr-un element <welcome-file> .

6.3.3 Codul unui servlet


Clasele care asigură funcţionalitatea servlet-ului nu fac parte din distribuţia JDK,
ele sunt cuprinse ı̂n distribuţia serverului Web.
Un servlet implementează interfaţa Servlet sau extinde una din clasele GenericServlet
sau HttpServlet. GenericServlet implementează interfaţa Servlet, iar HttpServlet
extinde clasa HttpGeneric. Extinzând clasa GenericServlet nu este nevoie de re-
scrierea tuturor metodelor abstracte ale intrefeţei Servlet.
Metodele interfeţei Servlet sunt

• abstract public void init(ServletConfig config)


Se apelează o singură dată la lansarea servlet-ului.

• abstract public void service(ServletRequest req, ServletResponse res)throws


ServletException,IOException
Metoda este apelată de serverul Web pentru rezolvarea cererii unui client.

• abstract public void destroy()


Se apelează o singură dată la distrugerea servlet-ului.

• public String getServletInfo()


130 CAPITOLUL 6. SERVLET

• public ServletConfig getServletConfig()


În cele ce urmează un servlet va fi o clasă care extinde clasa HttpServlet. În
locul metodei service(...), programatorul suprascrie metodele doGet(...) sau
doPost(...), ı̂n funcţie de metoda utilizată de client la lansarea cererii.
Practic, un servlet constă din scrierea metodelor
• void init(ServletConfig config)
Această metodă este opţională.

public void init(ServletConfig config) throws ServletException{


super.init(config);
// cod de initializare
}

Obiectul config are o metodă String getInitParameter(String numeParam)


cu ajutorul căreia se pot recupera parametri de initializare asociaţi servletului
şi care se dau ı̂n fişierul web.xml prin marcajele

<init-param>
<param-name> NumeleParametrului </param-name>
<param-value> Valoare </param-value>
</init-param>

cuprinse ı̂n marcajul <servlet>.

• protected void doGet(HttpServletRequest req, HttpServletResponse res)


throws IOException, ServletException
Tratează o cerere trimisă cu metoda GET (vezi marcajul <form>).

• protected void doPost(HttpServletRequest req, HttpServletResponse res)


throws IOException, ServletException
Tratează o cerere trimisă cu metoda POST (vezi marcajul <form>).
Activităţile de ı̂ntreprins ı̂ntr-o metodă doGet() sau doPost() sunt
1. Stabilirea naturii răspunsului:
res.setContentType(String tip)
unde tip specifică tipul MIME - Multipurpose Internet Mail Extensions al
răspunsului:

• "text/html" - pagină html;


• "text/xml" - document xml;
6.3. REALIZAREA UNUI SERVLET 131

• "text/plain" - text;
• "image/jpg" - imagine gif;
• "image/gif" - imagine jpg.

2. Se obţine o referinţa către un obiect care realizeaza transmisia datelor către


navigatorul clientului:
ServletOutputStream out = res.getOutputStream();
sau
PrintWriter out=res.getWriter();

3. Se preiau datele cererii cu una din metodele:


String getParameter(String numeParapetru)
java.util.Enumeration getParameterNames()

4. Rezolvă cererea clientului;

5. Formează şi scrie răspunsul;

6. Închide conexiunea obiectului prin care s-a realizat transmisia datelor către
navigatorul clientului prin out.close().

Un utilizator lansează o cerere către servlet. De obicei acest lucru se realizează


prin completarea unui formular al unui document html. Programul navigator trimite
cererea serverului Web prin intermediul căruia este lansat servlet-ul ı̂n acţiune.
Ciclul de viaţă al unui servlet. Când un servlet este apelat prima dată de
către serverul Web se execută metoda init. După aceasta, fiecărei cereri lansate de
un utilizator i se asociază un fir de execuţie ı̂n care se apelează metoda service.
Metoda service apelează apoi metodele doGet(), doPost() sau o altă metodă de
forma doXXX() depinzând de tipul de cerere primit.

Exemplul 6.3.1 Servletul Hello: Clientul transmite numele servet-ului care ı̂i răspunde
cu mesajul de salut ”Hi nume!”.

Formularul html prin care clientul introduce numele este (index.html )


1 <html>
2 <head>
3 < t i t l e> S e r v l e t −u l H e l l o </ t i t l e>
4 </head>
5 <body>
6 <center>
7 <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>
8 <form method=” p o s t ”
9 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 ”>
10 <p>I n t r o d u c e t i numele :
11 <input type=” t e x t ” name=”name” s i z e =20>
12 <p>
13 <input type=” submit ”>
132 CAPITOLUL 6. SERVLET

14 </form>
15 </ center>
16 </body>
17 </html>

Codul servlet-ului este


1 import j a v a . i o . ∗ ;
2 import j a v a x . s e r v l e t . ∗ ;
3 import j a v a x . s e r v l e t . h t t p . ∗ ;

5 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 {
6 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 )
7 throws S e r v l e t E x c e p t i o n , IOException {
8 r e s . setContentType ( ” t e x t / html ” ) ;
9 S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ;
10 S t r i n g nume=r e q . g e t P a r a m e t e r ( ”name” ) ;
11 out . p r i n t l n ( ”<html>” ) ;
12 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>” ) ;
13 out . p r i n t l n ( ”<body>” ) ;
14 out . p r i n t l n ( ”<h1>H e l l o S e r v l e t </h1>” ) ;
15 out . p r i n t l n ( ”<p>” ) ;
16 out . p r i n t l n ( ” Hi ”+ nume+” ! ” ) ;
17 out . p r i n t l n ( ”</p>” ) ;
18 out . p r i n t l n ( ”</body>” ) ;
19 out . p r i n t l n ( ”</html>” ) ;
20 out . c l o s e ( ) ;
21 }

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


24 throws S e r v l e t E x c e p t i o n , IOException {
25 doGet ( req , r e s ) ;
26 }
27 }

Fişierul web.xml pentru acest exemplu este


1 <?xml version=” 1 . 0 ” e n c o d i n g=”ISO−8859−1” ?>

3 < !DOCTYPE web−app


4 PUBLIC ”−//Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN”
5 ” h t t p : // j a v a . sun . com/ dtd /web−a p p 2 3 . dtd ”>

7 <web−app>
8 < s e r v l e t>
9 <s e r v l e t −name> h e l l o</ s e r v l e t −name>
10 <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>
11 </ s e r v l e t>
12 <s e r v l e t −mapping>
13 <s e r v l e t −name> h e l l o</ s e r v l e t −name>
14 <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>
15 </ s e r v l e t −mapping>
16 <welcome−f i l e − l i s t>
17 <welcome− f i l e >i n d e x . html</ welcome− f i l e >
18 </ welcome−f i l e − l i s t>
19 </web−app>

Compilarea şi arhivarea servlet-ului o vom realiza prin intermediul lui apache-
ant. În acest scop se crează structura:
6.3. REALIZAREA UNUI SERVLET 133

hello
| |---> src
| | | HelloServlet.java
| |---> lib
| |---> web
| | | web.xml
| |---> web-files
| | | index.html
| build.xml

cu fişierul build.xml
1 <p r o j e c t b a s e d i r=” . ” default=” g e n e r a t e . war ”>

3 <p r o p e r t y name=”TOMCAT HOME” v a l u e=” . . . / apache−tomcat − ∗ . ∗ . ∗ ” />


4 <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 ” />
5 <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 ” />
6 <p r o p e r t y name=” b u i l d . d i r ” v a l u e=” b u i l d ” />

8 <path i d=” m y c l a s s p a t h ”>


9 < f i l e s e t d i r=” l i b ”>
10 <i n c l u d e name=” ∗ . j a r ” />
11 </ f i l e s e t>
12 <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 ” />
13 </ path>

15 <t a r g e t name=” i n i t ”>


16 <d e l e t e d i r=” ${ d i s t . d i r } ” />
17 <mkdir d i r=” ${ b u i l d . d i r } ” />
18 <mkdir d i r=” ${ d i s t . d i r } ” />
19 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF” />
20 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF/ c l a s s e s ” />
21 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF/ l i b ” />
22 </ t a r g e t>

24 <t a r g e t name=” c o m p i l e ” depends=” i n i t ”>


25 <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 ”
26 s r c d i r=” ${ b a s e d i r }/ s r c ”
27 d e s t d i r=” ${ b u i l d . d i r }/WEB−INF/ c l a s s e s ” />
28 </ t a r g e t>

30 <t a r g e t name=” g e n e r a t e . war ” depends=” c o m p i l e ”>


31 <copy t o d i r=” ${ b u i l d . d i r } ” >
32 < f i l e s e t d i r=” ${ b a s e d i r }/web− f i l e s ” >
33 <i n c l u d e name=” ∗ . html ” />
34 </ f i l e s e t>
35 </ copy>
36 <copy t o d i r=” ${ b u i l d . d i r }/WEB−INF” >
37 < f i l e s e t d i r=” ${ b a s e d i r }/web” >
38 <i n c l u d e name=” ∗ . xml” />
39 </ f i l e s e t>
40 </ copy>
41 <copy t o d i r=” ${ b u i l d . d i r }/WEB−INF/ l i b ” >
42 < f i l e s e t d i r=” ${ b a s e d i r }/ l i b ” >
43 <i n c l u d e name=” ∗ . j a r ” />
44 </ f i l e s e t>
45 </ copy>
46 <copy t o d i r=” ${ b u i l d . d i r } ” >
47 < f i l e s e t d i r=” ${ b a s e d i r } ” >
48 <i n c l u d e name=” ∗ . p r o p e r t i e s ” />
134 CAPITOLUL 6. SERVLET

49 </ f i l e s e t>
50 </ copy>
51 <j a r d e s t f i l e =” ${ d i s t . d i r }/${ d i s t . name } . war ” b a s e d i r=” ${ b u i l d . d i r } ” />
52 </ t a r g e t>
53 </ p r o j e c t>

Observaţie. Valoarea parametrului dist.name trebuie să coincidă cu numele cata-


logului ı̂n atributul action a elementului form, din documentul index.html.
În cazul exemplului de faţă, catalogul lib este gol. Dacă aplicaţia solicită resurse
externe, conţinute ı̂n fişierele jar, atunci aceste fişiere se depun ı̂n catalogul lib.
Se lansează ı̂n execuţie serverul Web tomcat, se ı̂ncarcă servlet-ul ı̂n serverul Web
şi dintr-un navigator se deschide pagina http://localhost:8080/apphello

Exemplul 6.3.2 Servlet pentru calculul celui mai mare divizor comun a două nu-
mere.

1 import j a v a . i o . ∗ ;
2 import j a v a x . s e r v l e t . ∗ ;
3 import j a v a x . s e r v l e t . h t t p . ∗ ;

5 public c l a s s CmmdcServlet extends H t t p S e r v l e t {

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

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


10 throws S e r v l e t E x c e p t i o n , IOException {
11 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” ) ;
12 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 ” ) ;
13 long m=Long . parseLon g ( sm ) , n=Long . par se Lon g ( sn ) ;
14 long x=cmmdc(m, n ) ;
15 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
16 i f ( t i p . e q u a l s ( ” t e x t / html ” ) ) {
17 S t r i n g t i t l e =” CmmdcServlet ” ;
18 r e s . setContentType ( ” t e x t / html ” ) ;
19 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;
20 out . p r i n t l n ( t i t l e ) ;
21 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;
22 out . p r i n t l n ( ”<H1>”+ t i t l e +”</H1>” ) ;
23 out . p r i n t l n ( ”<P>Cmmdc i s ”+x ) ;
24 out . p r i n t l n ( ”</BODY></HTML>” ) ;
25 }
26 else {
27 r e s . setContentType ( ” t e x t / p l a i n ” ) ;
28 out . p r i n t l n ( x ) ;
29 }
30 out . c l o s e ( ) ;
31 }

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


34 throws S e r v l e t E x c e p t i o n , IOException {
35 doGet ( req , r e s ) ;
36 }
37 }

apelabil prin documentul html (index.html )


6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 135

1 <html>
2 <body>
3 <form method=” g e t ”
4 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc”>
5 <p>Primul numar e s t e <input type=” t e x t ” name=”m” s i z e=5>
6 <p>Al d o i l e a numar e s t e <input type=” t e x t ” name=”n” s i z e=5>
7 <p><input type=” submit ” value=” C a l c u l e a z a ”>
8 <input type=” hidden ” name=” t i p ” value=” t e x t / html ” >
9 </form>
10 </body>
11 </html>

Pentru fixarea naturii răspunsului text/html sau text/plain s-a introdus variabila
tip, care ı̂n fişierul de invocare index.html primeşte pe ascuns valoarea text/html.
În cazul ı̂n care vom apela servlet-ul dintr-un program, va fi avantajos să primim
răspunsul ca text/plain.

6.4 Facilităţi de programare cu servlet


6.4.1 Program client al unui servlet
Apelarea unui servlet dintr-un program Java – adică lansarea unei cereri şi
recepţionarea răspunsului furnizat de servlet – se poate realiza cu produsul commons-
httpclient dezvoltat de apache.
Într-un asemenea caz, din punctul de vedere al clientului este mai avantajos ca
răspunsul servlet-ului fie text/plain, ı̂n loc de text/html.
Pe lângă commons-httpclient este nevoie de următoarele produse soft:

• commons-codec de la apache;

• commons-logging de la apache;

Pentru compilare trebuie declarată ı̂n variabila de sistem classpath referinţa către
commons-httpclient, dar pentru execuţie este nevoie şi de referintele către celelalte
două produse.
Dezvoltarea unui client presupune:

1. Resursele utilizate se declară prin

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.params.HttpMethodParams;

2. Crearea unui obiect de tip HttpClient:

HttpClient client=new HttpClient();


136 CAPITOLUL 6. SERVLET

3. Declararea metodei de transmitere a datelor get, post.

• GetMethod method = new GetMethod(url);


unde url este String-ul de apelare a servlet-ului, de forma
http://host:port/catalog/numeApel?numeParam=valParam&. . . ,
• PostMethod method = new PostMethod(url);
cu url=”http://host:port/catalog/numeApel”.
Datele se adaugă cu metoda
method.addParameter(String paramName, String paramValue);
Dacă se transmit atât parametri cât şi fişiere atunci datele se adaugă prin
şablonul
Part[] parts = {
new StringPart(paramName, paramValue),
. . .
new FilePart(file.getName(), file)
. . .
};
method.setRequestEntity(
new MultipartRequestEntity(parts, method.getParams())
);
unde o variabilă file corespunde unui fişier care este ı̂ncărcat.

4. Specificarea modului de reluare a cererii.

DefaultHttpMethodRetryHandler retryhandler=
new DefaultHttpMethodRetryHandler(int numarReluari,
boolean seFacReluari);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
retryhandler);

5. Lansarea cererii.

int statusCode = client.executeMethod(method);

6. Preluarea răspunsului. Există trei căi de realizare a acestui obiectiv:

• Ca şir de octeţi:
byte[] method.getResponseBody();
• Ca String:
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 137

String method.getResponseBodyAsString();
• Prin intermediul unui flux:
InputStream method.getResponseBodyAsStream();

7. Închiderea conexiunii cu servlet-ul.

method.releaseConnection();

Exemplul 6.4.1 Dezvoltăm un program client pentru servlet-ul CmmdcServlet.

1 import java . u t i l . ∗ ;
2 import o r g . apache . commons . h t t p c l i e n t . ∗ ;
3 import o r g . apache . commons . h t t p c l i e n t . methods . ∗ ;
4 import o r g . apache . commons . h t t p c l i e n t . params . HttpMethodParams ;

6 import j a v a . i o . ∗ ;

8 public c l a s s ClientCmmdcServlet {
9 private s t a t i c S t r i n g u r l = ” 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” ;

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


12 Sc anner s c a n n e r=new Sc anner ( System . i n ) ;
13 System . out . p r i n t l n ( ”m=” ) ;
14 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 ( ) ;
15 System . out . p r i n t l n ( ”n=” ) ;
16 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 ( ) ;

18 H t t p C l i e n t c l i e n t = new H t t p C l i e n t ( ) ;
19 PostMethod method = new PostMethod ( u r l ) ;

21 method . addParameter ( ”m” ,m) ;


22 method . addParameter ( ”n” , n ) ;
23 method . addParameter ( ” t i p ” , ” t e x t / p l a i n ” ) ;

25 DefaultHttpMethodRetryHandler r e t r y h a n d l e r=
26 new DefaultHttpMethodRetryHandler ( 3 , true ) ;
27 method . getParams ( ) . s e t P a r a m e t e r ( HttpMethodParams .RETRY HANDLER,
28 retryhandler );
29 try {
30 i n t s t a t u s C o d e = c l i e n t . executeMethod ( method ) ;

32 i f ( s t a t u s C o d e != H t t p S t a t u s . SC OK) {
33 System . e r r . p r i n t l n ( ”Method f a i l e d : ” + method . g e t S t a t u s L i n e ( ) ) ;
34 System . e x i t ( 0 ) ;
35 }
36 byte [ ] re sp on se B od y = method . getResponseBody ( ) ;
37 System . out . p r i n t l n ( ”Cmmdc = ”+(new S t r i n g ( r e s p o n s e B o d y ) ) ) ;
38 }
39 catch ( H t t p E x c e p t i o n e ) {
40 System . e r r . p r i n t l n ( ” Http e r r o r : ” + e . g e t M e s s a g e ( ) ) ;
41 }
42 catch ( IOException e ) {
43 System . e r r . p r i n t l n ( ” I /O e r r o r : ” + e . g e t M e s s a g e ( ) ) ;
44 }
138 CAPITOLUL 6. SERVLET

45 finally {
46 method . r e l e a s e C o n n e c t i o n ( ) ;
47 }
48 }
49 }

6.4.2 Servlete ı̂nlănţuite


Un servlet apelează la un moment dat alt servlet. Şablonul de lucru este

RequestDispatcher dispatcher=
getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat");
if(dispatcher!=null)
dispatcher.include(request,response);

Exemplul 6.4.2 Un servlet VerifServlet verifică parametri cererii. Pentru prob-


lema calculului celui mai mare divizor comun a două numere, dacă cei doi parametri
sunt numere ı̂ntregi, atunci se apelează servletul ComputeServlet, altfel se formează
un mesaj de eroare.

Codurile celor două servlete sunt:


VerifServlet.java
1 package cmmdc ;
2 import j a v a . i o . ∗ ;
3 import j a v a x . s e r v l e t . ∗ ;
4 import j a v a x . s e r v l e t . h t t p . ∗ ;

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

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


9 throws S e r v l e t E x c e p t i o n , IOException {
10 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 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” ) ;
13 S t r i n g message=” ” ;
14 long m, n ;
15 i f ( ( sm==n u l l ) | | ( sm . e q u a l s ( ” ” ) ) ) {
16 message=”Numar a b s e n t ” ;
17 }
18 else {
19 try {
20 m=Long . parseLon g ( sm ) ;
21 }
22 catch ( NumberFormatException e ) {
23 message=”Nu e s t e numar” ;
24 }
25 }
26 i f ( ( sn==n u l l ) | | ( sn . e q u a l s ( ” ” ) ) ) {
27 message=”Numar a b s e n t ” ;
28 }
29 else {
30 try {
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 139

31 n=Long . parseLong ( sn ) ;
32 }
33 catch ( NumberFormatException e ) {
34 message=”Nu e s t e numar” ;
35 }
36 }
37 out . p r i n t l n ( ”<html><body>” ) ;
38 i f ( message . e q u a l s ( ” ” ) ) {
39 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>” ) ;
40 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=
41 getServletContext ( ) . getRequestDispatcher ( ”/ c a l c u l ” ) ;
42 i f ( d i s p a t c h e r != n u l l )
43 d i s p a t c h e r . i n c l u d e ( req , r e s ) ;
44 }
45 else {
46 out . p r i n t l n ( ”<h3> Date e r o n a t e </h3>” ) ;
47 out . p r i n t l n ( message ) ;
48 }
49 out . p r i n t l n ( ”</body></html>” ) ;
50 out . c l o s e ( ) ;
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 )


54 throws S e r v l e t E x c e p t i o n , IOException {
55 doGet ( req , r e s ) ;
56 }
57 }

ComputeServlet.java
1 package cmmdc ;
2 import j a v a . i o . ∗ ;
3 import j a v a x . s e r v l e t . ∗ ;
4 import j a v a x . s e r v l e t . h t t p . ∗ ;

6 public c l a s s ComputeServlet extends H t t p S e r v l e t {

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

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


11 throws S e r v l e t E x c e p t i o n , IOException {
12 long m=Long . parseLong ( r e q . g e t P a r a m e t e r ( ”m” ) ) ;
13 long n=Long . parseLong ( r e q . g e t P a r a m e t e r ( ”n” ) ) ;
14 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
15 out . p r i n t l n ( ”<H1> Cmmdc = ”+cmmdc(m, n)+”</H1>” ) ;
16 }

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


19 throws S e r v l e t E x c e p t i o n , IOException {
20 doGet ( req , r e s ) ;
21 }
22 }

6.4.3 Sesiune de lucru


În cazul protocolului HTTP, de fiecare dată când un client deschide sau revine
la o pagină Web se deschide o nouă conexiune cu serverul Web iar acesta nu reţine
140 CAPITOLUL 6. SERVLET

informaţiile referitoare la client pe perioada conexiunii respective. Perioada de timp


cât un client este ı̂n conexiune cu o pagină Web se numeşte sesiune.
Există posibilitatea păstrării unor informaţii pe durata unei sesiuni (prin mecan-
ismul denumit Session Tracking).
Înaintea satisfacerii unei cereri, servletul verifică existenţa unui obiect HttpSession.
Acest obiect se crează la prima apelare de către un client a servletului prin

HttpSession sesiune=request.getSession(true);

Un obiect HttpSession poate reţine atribute, adică perechi de forma (nume, val-
oare). Introducerea unui atribut se realizează prin

void setAttribute(String nume, Object valoare)

iar extragerea valorii unui atribut se obţine prin

Object getAttribute(String nume)

Metoda String nume[ ] getValueNames() returnează numele tuturor


atributelor definite.
Un atribut se elimină cu metoda void removeAttribute(String nume).

Exemplul 6.4.3 Exemplul următor numără de câte ori se apelează servlet-ul ı̂ntr-o
sesiune. Se defineşte un atribut noAcces, care la prima apelare este iniţializat iar
apoi este mărit cu câte o unitate la fiecare nouă apelare a servlet-ului.

1 import j a v a . i o . ∗ ;
2 import j a v a x . s e r v l e t . ∗ ;
3 import j a v a x . s e r v l e t . h t t p . ∗ ;

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

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


8 throws S e r v l e t E x c e p t i o n , IOException {
9 r e s . setContentType ( ” t e x t / html ” ) ;
10 S t r i n g mesaj ;
11 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
12 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 ) ;
13 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 ” ) ;
14 i f ( c o n t o r==n u l l ) {
15 c o n t o r=new I n t e g e r ( 1 ) ;
16 mesaj=” S a l u t ! ” ;
17 }
18 else {
19 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 ) ;
20 mesaj=” Bine a t i r e v e n i t ! ” ;
21 }
22 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 ) ;
23 out . p r i n t l n ( ”<html><body>” ) ;
24 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;
25 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 ” +
26 contor . intValue ( ) ) ;
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 141

27 out . p r i n t l n ( ”</body></html>” ) ;
28 out . c l o s e ( ) ;
29 }

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 )


32 throws S e r v l e t E x c e p t i o n , IOException {
33 doGet ( req , r e s ) ;
34 }
35 }

Apelarea servletului se face din


1 <html>
2 <head>
3 < t i t l e> S e s i u n e </ t i t l e>
4 </head>
5 <body>
6 <h1> Formular de a c c e s </h1>
7 <form method=” g e t ”
8 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / s e s i u n e ”>
9 <p>
10 <input type=” submit ” value=” A c c e s e a z a ”>
11 </form>
12 </body>
13 </html>

6.4.4 Cookie
Un Cookie este un fişier de mică dimensiune trimis de către programul server
clientului ca parte a header-ului Http.
Acesta conţine informaţii despre sesiunea curentă care salvate pe disc vor putea
fi accesate ı̂n sesiuni ulterioare. Când un navigator emite o cerere către un server,
cookie-urile anterioare primite de către client de la serverul respectiv sunt trimise
din nou serverului ca parte a cererii formulată de client.
Cookie-urile sunt sterse automat ı̂n momentul expirării.
Unii clienţi nu permit memorarea cookie-urilor. În acest caz, clientul este infor-
mat că acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale / accesării
paginii Web. Implicit, durata de viaţă a unui cookie este sesiunea curentă a naviga-
torului (până se ı̂nchide navigatorul).

Clasa Cookie
Contructor
Cookie(String nume, String valoare)
Metode

• void setDomain(String model )


Domeniul este o adresă URL ce restricţionează accesul cookie-urilor la acel
domeniu. model trebuie să conţină cel puţin două caractere ”.”.
142 CAPITOLUL 6. SERVLET

• void setMaxAge(int durată) Fixează durata de existenţă a cookie-ului - ı̂n


secunde. Valoarea implicită este -1, adică cookie-ul există până la ı̂nchiderea
programului navigator.

• void setComment(String comentariu)

• void setSecure(boolean flag)


Valoarea implicită este false.

Trimiterea unui cookie clientului:


public void HttpServletResponse.addCookie(Cookie cookie)
Recunoaşterea cookie-urilor de către 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 6.4.4 În exemplul următor se numără de câte ori se apelează servlet-ul
pe durata de viaţă a cookie-ului.

1 import j a v a . i o . ∗ ;
2 import j a v a x . s e r v l e t . ∗ ;
3 import j a v a x . s e r v l e t . h t t p . ∗ ;

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

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


8 throws S e r v l e t E x c e p t i o n , IOException {
9 r e s . setContentType ( ” t e x t / html ” ) ;
10 S t r i n g mesaj=” ” ;
11 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
12 Cookie myCookie=n u l l ;
13 i n t c o n t o r =1;
14 Cookie [ ] c o o k i e s=r e q . g e t C o o k i e s ( ) ;
15 i f ( c o o k i e s != n u l l ) {
16 f o r ( i n t i =0; i <c o o k i e s . l e n g t h ; i ++){
17 S t r i n g name=c o o k i e s [ i ] . getName ( ) ;
18 i f ( name . e q u a l s ( ” u r m a r i r e ” ) ) {
19 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 ( ) ) ;
20 c o n t o r ++;
21 mesaj=” Bine a t i r e v e n i t ! ” ;
22 }
23 }
24 }
25 else {
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 143

26 mesaj=” S a l u t ! ” ;
27 }
28 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 ( ) ) ;
29 myCookie . setMaxAge ( 1 0 0 0 0 0 0 ) ;
30 r e s . addCookie ( myCookie ) ;
31 out . p r i n t l n ( ”<html><body>” ) ;
32 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;
33 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 ) ;
34 out . p r i n t l n ( ”</body></html>” ) ;
35 out . c l o s e ( ) ;
36 }

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


39 throws S e r v l e t E x c e p t i o n , IOException {
40 doGet ( req , r e s ) ;
41 }
42 }

6.4.5 Autorizarea accesului prin parola


Parolele celor ı̂ndreptăţiţi să acceseze servletul sunt cuprinşe ı̂ntr-un fişier. În
servlet accesul la fişier se realizează prin preluarea unui parametru a cărei valoare
este numele fişierului.
Servlet-ul solicită afişarea pe maşina clientului a unei căsuţe de dialog prin care
clientul introduce numele şi parola. Dacă datele coincid cu cele ı̂nregistrate ı̂n fişier
atunci se autorizează accesul la servlet.
Date transmise de client sunt codificate. Decodificarea se poate realiza cu clasa
Base64Coder : www.source-code.biz, Christian d’Heureuse, Inventec Informatik AG,
Switzerland.

Exemplul 6.4.5

1 import java . io . ∗ ;
2 import javax . s e r v l e t . ∗ ;
3 import javax . s e r v l e t . http . ∗ ;
4 import java . u t i l . Properties ;

6 public c l a s s P r o t e c t e d P a g e extends H t t p S e r v l e t {
7 private P r o p e r t i e s p a s s w o r d s ;
8 private S t r i n g p a s s w o r d F i l e ;

10 // P a r o l e l e s u n t i n t r −un f i s i e r ” p a r o l e ”
11 // s u b forma nume=p a r o l a .
12 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 {
13 super . i n i t ( c o n f i g ) ;
14 try {
15 passwordFile = config . getInitParameter ( ” passwordFile ” ) ;
16 p a s s w o r d s = new P r o p e r t i e s ( ) ;
17 p a s s w o r d s . l o a d (new F i l e I n p u t S t r e a m ( p a s s w o r d F i l e ) ) ;
18 }
19 catch ( IOException i o e ) {}
20 }
144 CAPITOLUL 6. SERVLET

22 public void doGet ( 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 s p o n s e r e s p o n s e )


23 throws S e r v l e t E x c e p t i o n , IOException {
24 r e s p o n s e . setContentType ( ” t e x t / html ” ) ;
25 P r i n t W r i t e r out = r e s p o n s e . g e t W r i t e r ( ) ;
26 S t r i n g a u t h o r i z a t i o n = r e q u e s t . getHeader ( ” Authorization ” ) ;
27 i f ( a u t h o r i z a t i o n == n u l l ) {
28 cerParola ( response ) ;
29 }
30 else {
31 S t r i n g u s e r I n f o = a u t h o r i z a t i o n . s u b s t r i n g ( 6 ) . trim ( ) ;
32 S t r i n g nameAndPassword = Base64Coder . d e c o d e S t r i n g ( u s e r I n f o ) ;
33 System . out . p r i n t l n ( nameAndPassword ) ;
34 i n t i n d e x = nameAndPassword . i n d e x O f ( ” : ” ) ;
35 S t r i n g u s e r = nameAndPassword . s u b s t r i n g ( 0 , i n d e x ) ;
36 S t r i n g password = nameAndPassword . s u b s t r i n g ( i n d e x +1). t r i m ( ) ;
37 p a s s w o r d s . l i s t ( System . out ) ;
38 S t r i n g realPassword = passwords . getProperty ( user ) ;
39 System . out . p r i n t l n ( u s e r+” ”+password+” ”+r e a l P a s s w o r d ) ;
40 i f ( ( r e a l P a s s w o r d != n u l l )&&( r e a l P a s s w o r d . e q u a l s ( password ) ) ) {
41 S t r i n g t i t l e = ”Welcome t o t h e P r o t e c t e d Page ” ;
42 out . p r i n t l n ( ”<HTML><HEAD><TITLE>”+ t i t l e +”</TITLE></HEAD>” +
43 ”<BODY BGCOLOR=\”#AABBAA\”>\n”+”<H1 ALIGN=CENTER>” + t i t l e +
44 ”</H1>\n” + ” A v e t i a c c e s l a p a g i n a ”+”</BODY></HTML>” ) ;
45 }
46 else {
47 cerParola ( response ) ;
48 }
49 }
50 }

52 // Cererea a f o s t f a r a a u t o r i z a r e
53 private void c e r P a r o l a ( H t t p S e r v l e t R e s p o n s e r e s p o n s e ) {
54 r e s p o n s e . s e t S t a t u s ( r e s p o n s e . SC UNAUTHORIZED ) ; // I e 401
55 r e s p o n s e . s e t H e a d e r ( ”WWW −A u t h e n t i c a t e ” ,
56 ”BASIC realm =\” p r i v i l e g e d −few \” ” ) ;
57 }

59 public void doPost ( 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 s p o n s e r e s p o n s e )


60 throws S e r v l e t E x c e p t i o n , IOException {
61 doGet ( r e q u e s t , r e s p o n s e ) ;
62 }
63 }

Parolele se reţin ı̂ntr-un fişier denumit parole.properties alcătuit din ı̂nregistrări


de forma nume=parolă, câte o ı̂nregistrare pe linie. Localizarea fişierului se obţine
prin intermediul datelor din elementul

<init-param>
<param-name>passwordFile</param-name>
<param-value>d:\\apache-tomcat-*.*.*\\. . .\\parole.properties</param-value>
</init-param>

Acest element apare ı̂n corpul elementului <servlet> ataşat servlet-ului. Servletul
se apelează prin http://host:port/context/numeApel.
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 145

6.4.6 Servlet cu conexiune la o bază de date


Folosind Anexa C considerăm

Exemplul 6.4.6 Consultarea unei agende telefonice. Se utilizează o bază de date


AgendaTelefonica alcătuită dintr-un singur tabel telef (nume varchar(20), numar
varchar(20)).

Utilizând SGBD derby servletul este


1 import java . io . ∗ ;
2 import javax . s e r v l e t . ∗ ;
3 import javax . s e r v l e t . http . ∗ ;
4 import java . s q l . ∗ ;

6 public c l a s s T e l e f extends H t t p S e r v l e t {
7 Statement i n s t r u c t i u n e=n u l l ;

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


10 super . i n i t ( c o n f i g ) ;
11 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 ” ;
12 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 / A g e n d a T e l e f o n i c a ” ;
13 /∗
14 // Cazul SGBD Access
15 S t r i n g j d b c D r i v e r =”sun . j d b c . odbc . JdbcOdbcDriver ” ;
16 S t r i n g URLBazaDate=” j d b c : odbc : A g e n d a T e l e f o n i c a ” ;

18 // Cazul SGBD Mysql


19 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 ” ;
20 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 / AgendaT? u s e r=r o o t ” ;
21 ∗/
22 C o n n e c t i o n con=n u l l ;
23 try {
24 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 ( ) ;
25 con=DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ;
26 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 ( ) ;
27 }
28 catch ( ClassNotFoundException e ) {
29 System . out . p r i n t l n ( ”N−am g a s i t d r i v e r u l JDBC : ”+j d b c D r i v e r ) ;
30 }
31 catch ( SQLException e ) {
32 System . out . p r i n t l n ( ” E r o a r e c a u t a r e d a t e d i n ”+URLBazaDate ) ;
33 }
34 catch ( E x c e p t i o n e ) {
35 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 ( ) ) ;
36 }
37 }

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


40 throws S e r v l e t E x c e p t i o n , IOException {
41 S t r i n g myAtribut , myVal ;
42 r e s . setContentType ( ” t e x t / html ” ) ;
43 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;

45 // P r e l u a r e a v a l o r i i unui parametru

47 myAtribut=r e q . g e t P a r a m e t e r ( ” c r i t e r i u ” ) ;
48 myVal=r e q . g e t P a r a m e t e r ( ” termen ” ) ;
146 CAPITOLUL 6. SERVLET

49 myVal= ’ \ ’ ’+myVal+ ’ \ ’ ’ ;
50 try {
51 S t r i n g s q l=” s e l e c t ∗ from t e l e f where ”+ myAtribut+” = ”
52 +myVal ;
53 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 ) ;
54 out . p r i n t l n ( ”<html>” ) ;
55 out . p r i n t l n ( ”<head><t i t l e >A g e n d a T e l e f o n i c a </ t i t l e ></head>” ) ;
56 out . p r i n t l n ( ”<body>” ) ;
57 out . p r i n t l n ( ”<h1>Agenda T e l e f o n i c a </h1>” ) ;
58 while ( r s . n e x t ( ) ) {
59 out . p r i n t ( r s . g e t S t r i n g ( ”nume”)+” a r e numarul de t e l e f o n : ”+
60 r s . g e t S t r i n g ( ”numar” ) ) ;
61 }
62 out . p r i n t l n ( ”</body>” ) ;
63 out . p r i n t l n ( ”</html>” ) ;
64 out . c l o s e ( ) ;
65 }
66 catch ( SQLException e ) {
67 System . out . p r i n t l n ( ” SQLException : ”+e . g e t M e s s a g e ( ) ) ;
68 }
69 catch ( E x c e p t i o n e ) {
70 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 ( ) ) ;
71 }
72 }

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


75 throws S e r v l e t E x c e p t i o n , IOException {
76 doGet ( req , r e s ) ;
77 }
78 }

Utilizarea servlet-ului se face din


1 <html>
2 <head>
3 < t i t l e>
4 Cautare i n baza de d a t e t e l e f i c a
5 </ t i t l e>
6 </head>
7 <body>
8 <h1>
9 Cautare i n baza de d a t e a S o c i e t a t i i de t e l e f o a n e
10 </h1>
11 <form method=” g e t ”
12 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / t e l e f ”>
13 <p>C r i t e r i u de c a u t a r e :
14 <s e l e c t name=” c r i t e r i u ” >
15 <option value=”nume”>dupa Nume
16 <option value=”numar”>dupa Numar
17 </ s e l e c t>
18 <br>
19 <p>E n t i t a t e a c a u t a t a
20 <input type=” t e x t ” name=” termen ” s i z e =20>
21 <p>
22 <input type=” submit ” value=” Cauta ”>
23 </form>
24 </body>
25 </html>
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 147

Testarea aplicaţiei presupune:

1. Realizarea bazei de date:

2. Testarea servlet-ului:

(a) Pornirea serverului bazei de date.


(b) Se verifică prezenţa ı̂n catalogul servlet-ului ...\WEB-INF\lib a fişierului
derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar.
(c) Pornirea serverului tomcat sau reı̂ncărcarea servlet-ului.
(d) Apelarea servlet-ului din pagina Web.

6.4.7 Imagini furnizate de servlet


Indicăm două modalităţi prin care un client obţine o imagine furnizată de un
servlet. Imaginea poate proveni dintr-un fişier extern sau poate fi creată de servlet.

• Imaginea este transmisă direct clientului, tipul MIME al răspunsului fiind

response.setContentType("image/gif");

În cazul unui fişier extern imaginea este refăcută ı̂n memorie şi ı̂n fluxul de ieşire
de tip ServletOutputStream se transmite recodarea imaginii ı̂n format gif.
Această recodare se poate face cu pachetul Acme.JPM.Encoders, disponibil
gratuit la adresa web http://www.acme.com.
Preluarea imaginii dintr-un fişier se programează

Image image=Toolkit.getDefaultToolkit().getImage(String
referinţăFişier );

Textul sursă al servlet-ului este:

1 import java . io . ∗ ;
2 import j a v a . awt . ∗ ;
3 import javax . s e r v l e t . ∗ ;
4 import javax . s e r v l e t . http . ∗ ;
5 import Acme .JPM. Encoders . G i f E n c o d e r ;

7 public c l a s s MyGraphG extends H t t p S e r v l e t {

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


10 throws S e r v l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” image / g i f ” ) ;
12 // i e s i r e p r i n f l u x de o c t e t i
13 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
148 CAPITOLUL 6. SERVLET

15 // R e f e r i n t a l a f i s i e r u l g r a f i c
16 S t r i n g f=”d : \ \ apache−tomcat − ∗ . ∗ . ∗ \ \ webapps \\ m y s e r v l e t \\
17 WEB−INF\\ c l a s s e s \\ w a l k i n g s a n t a . g i f ” ;
18 // P r e l u a r e a i m a g i n i i g r a f i c e
19 Image image=T o o l k i t . g e t D e f a u l t T o o l k i t ( ) . getImage ( f ) ;
20 // Transmiterea i m a g i n i i u t i l i z a n d p a c h e t u l
21 G i f E n c o d e r e n c o d e r = new G i f E n c o d e r ( image , out ) ;
22 e n c o d e r . encode ( ) ;
23 }
24 }

• Pe calculatorul serverului Web, imaginea se salvează ı̂ntr-un fişier jpg sau png,
după care servlet-ul scrie ı̂n fluxul de ieşire un document html cu o legătură
(link) către fişierul cu imaginea creată anterior. Navigatorul clientului va
descărca şi vizualiza imaginea.
Textul sursă al servlet-ului este:

1 import java . io . ∗ ;
2 import j a v a . awt . ∗ ;
3 import javax . s e r v l e t . ∗ ;
4 import javax . s e r v l e t . http . ∗ ;
5 import javax . imageio . ∗ ;
6 import j a v a . awt . image . ∗ ;
7 import j a v a x . i m a g e i o . stream . ∗ ;
8 import java . u t i l . ∗ ;

10 public c l a s s MyGraphP extends H t t p S e r v l e t {

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 )


13 throws S e r v l e t E x c e p t i o n , IOException {
14 r e s . setContentType ( ” t e x t / html ” ) ;
15 P r i n t W r i t e r out=r e s . g e t W r i t e r ( ) ;
16 S t r i n g numeFis=” d e s e n ” ;
17 S t r i n g e x t=” j p g ” ; // sau ” png ”

19 // Formarea i m a g i n i i
20 Frame frame = n u l l ;
21 Graphics g = null ;
22 B u f f e r e d I m a g e image=n u l l ;
23 try {
24 frame = new Frame ( ) ;
25 // a d d N o t i f y : Cadrul Frame d e v i n e a f i s a b i l p r i n
26 // l e g a r e a l u i l a o r e s u r s a n a t i v a a e c r a n u l u i .
27 // P r o p r i e t a t e a s e m o s t e n e s t e de t o t i d e s c e n d e n t i i
28 // c a d r u l u i
29 frame . a d d N o t i f y ( ) ;
30 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 ) ;
31 g = image . g e t G r a p h i c s ( ) ;

33 // F i x a r e a f o n t u l u i
34 g . s e t F o n t (new Font ( ” S e r i f ” , Font . ITALIC , 4 8 ) ) ;

36 // E d i t a r e a unui t e x t
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 149

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

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


40 F i l e f=new F i l e ( numeFis+” . ”+e x t ) ;
41 ImageIO . w r i t e ( image , ” j p g ” , f ) ;

43 // Raspunsul c a t r e c l i e n t
44 out . p r i n t l n ( ”<HTML><BODY>” ) ;
45 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>” ) ;
46 out . p r i n t l n ( ”<p><a h r e f =\”d : \ \ apache−tomcat − ∗ . ∗ . ∗ \ \ ”
47 +numeFis+” . ”+e x t+”\”>” ) ;
48 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>” ) ;
49 out . p r i n t l n ( ”</BODY></HTML>” ) ;
50 out . c l o s e ( ) ;
51 }
52 finally {
53 // E l i b e r a r e a r e s u r s e l o r
54 i f ( g != n u l l ) g . d i s p o s e ( ) ;
55 i f ( frame != n u l l ) frame . r e m o v e N o t i f y ( ) ;
56 }
57 }
58 }

6.4.8 Servlet cu RMI


Un servlet poate fi client al unei aplicaţii RMI. Interfaţa la diatanţă se depune
ı̂n catalogul WEB-INF\lib al servletului. Apelarea programului server RMI se face
prin

InterfataDistanta obj=(InterfataDistanta)
Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");

Exemplul 6.4.7 Client servlet pentru aplicaţia RMI de calcul al celui mai mare
divizor comun a două numere naturale.

1 import java . io . ∗ ;
2 import j a v a . rmi . ∗ ;
3 import j a v a . rmi . r e g i s t r y . ∗ ;
4 import javax . s e r v l e t . ∗ ;
5 import javax . s e r v l e t . http . ∗ ;
6 import cmmdc . ∗ ;

8 public c l a s s ServletRMI extends H t t p S e r v l e t {

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


11 throws S e r v l e t E x c e p t i o n , IOException {
12 r e s . setContentType ( ” t e x t / html ” ) ;
13 P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;

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


16 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 ( ) ;
17 long x =0;
150 CAPITOLUL 6. SERVLET

19 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 ( ) ;
20 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 ” ) ;
21 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 try {
24 ICmmdc o b j =(ICmmdc) Naming . l o o k u p ( ” // ”+h o s t+” : ”+p o r t+” /CmmdcServer” ) ;
25 x=o b j . cmmdc(m, n ) ;
26 }
27 catch ( E x c e p t i o n e ) {
28 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 ( ) ) ;
29 }
30 S t r i n g t i t l e =” CmmdcServlet ” ;
31 r e s . setContentType ( ” t e x t / html ” ) ;
32 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;
33 out . p r i n t l n ( t i t l e ) ;
34 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;
35 out . p r i n t l n ( ”<H1>”+ t i t l e +”</H1>” ) ;
36 out . p r i n t l n ( ”<P>Cmmdc : ”+x ) ;
37 out . p r i n t l n ( ”</BODY></HTML>” ) ;
38 out . c l o s e ( ) ;
39 }

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


42 throws S e r v l e t E x c e p t i o n , IOException {
43 doGet ( req , r e s ) ;
44 }
45 }

6.4.9 Servlet cu JMS


De data aceasta cererea clientului se rezolva asincron:

• In prima fază se apelează un servlet care apelează un server JMS. Soluţia este
reţinută de furnizorul serviciului de mesagerie pe o destinaţie cu un subiect
furnizat de client. Pentru regăsirea rezultatului, servlet-ul crează clientului un
abonament durabil, funcţie de numele subiectului.

• În faza a doua, clientul apelează un alt servlet, a cărei funcţie este preluarea
rezultatului. Clientul trebuie sa furnizeze subiectul destinaţiei rezultatului.

Exemplul 6.4.8

Codul serverului JMS


1 import j a v a x . jms . ∗ ;
2 import j a v a . i o . ∗ ;
3 import j a v a . u t i l . S t r i n g T o k e n i z e r ;

5 public c l a s s MsgCmmdcServer{

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

9 public void s e r v i c e ( ) {
10 try {
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 151

11 // V a r i a n t a Apache−MessageQueue
12 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
13 // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (
14 // ” tcp :// l o c a l h o s t :61616”);

16 // V a r i a n t a Sun MessageQueue
17 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=
18 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 ( ) ;
19 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
20 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
21 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
22 T o p i c S e s s i o n s e s s i o n=
23 conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
24 D e s t i n a t i o n tDate=s e s s i o n . c r e a t e T o p i c ( ”Cmmdc” ) ;
25 T o p i c S u b s c r i b e r consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ;
26 conn . s t a r t ( ) ;
27 TextMessage txtMsg=n u l l ;
28 S t r i n g sm=” ” , sn=” ” , t o p i c=” ” ;
29 while ( true ) {
30 txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;
31 S t r i n g msg=txtMsg . g e t T e x t ( ) ;
32 S t r i n g T o k e n i z e r s t=new S t r i n g T o k e n i z e r ( msg , ” ” ) ;
33 i n t i =0;
34 while ( s t . hasMoreElements ( ) ) {
35 i ++;
36 i f ( i ==1) sm=s t . nextToken ( ) ;
37 i f ( i ==2) sn=s t . nextToken ( ) ;
38 i f ( i ==3) t o p i c=s t . nextToken ( ) ;
39 }
40 System . out . p r i n t l n ( sm+” : ”+sn+” : ”+t o p i c ) ;
41 long a=Long . parseLong ( sm ) ;
42 long b=Long . parseLong ( sn ) ;
43 long c=cmmdc( a , b ) ;
44 D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ;
45 MessageProducer p r o d u c e r=s e s s i o n . c r e a t e P r o d u c e r ( t R e s u l t ) ;
46 txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( (new Long ( c ) ) . t o S t r i n g ( ) ) ;
47 p r o d u c e r . send ( txtMsg ) ;
48 System . out . p r i n t l n ( ” E x p e d i a t r a s p u n s ” ) ;
49 }
50 }
51 catch ( E x c e p t i o n e ) {
52 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 ( ) ) ;
53 }
54 System . out . p r i n t l n ( ” S e r v e r f i n i s h e d ” ) ;
55 }

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


58 MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ;
59 server . service ();
60 }
61 }

Codul servlet-ului care transmite datele problemei serverului JMS


1 package jms ;
2 import j a v a x . jms . ∗ ;
3 import j a v a . i o . ∗ ;
4 import j a v a x . s e r v l e t . ∗ ;
5 import j a v a x . s e r v l e t . h t t p . ∗ ;
152 CAPITOLUL 6. SERVLET

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

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


10 throws S e r v l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
13 S t r i n g m=r e q . g e t P a r a m e t e r ( ”m” ) ;
14 S t r i n g n=r e q . g e t P a r a m e t e r ( ”n” ) ;
15 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 ” ) ;
16 S t r i n g c l i e n t I D=”JMSCmmdc” ;
17 S t r i n g c l i e n t N a m e=”JMSCmmdc” ;
18 try {
19 // V a r i a n t a Apache−MessageQueue
20 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
21 // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (
22 // ” tcp :// l o c a l h o s t :61616”);

24 // V a r i a n t a Sun MessageQueue
25 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=
26 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 ( ) ;
27 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
28 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
29 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
30 conn . s e t C l i e n t I D ( c l i e n t I D ) ;
31 T o p i c S e s s i o n s e s s i o n=
32 conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
33 D e s t i n a t i o n t R e s u l t=s e s s i o n . c r e a t e T o p i c ( t o p i c ) ;
34 T o p i c S u b s c r i b e r consumer=
35 s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ;
36 D e s t i n a t i o n t = s e s s i o n . c r e a t e T o p i c ( ”Cmmdc” ) ;
37 MessageProducer p r o d u c e r = s e s s i o n . c r e a t e P r o d u c e r ( t ) ;
38 TextMessage txtMsg=s e s s i o n . c r e a t e T e x t M e s s a g e ( ) ;
39 S t r i n g mesaj=m+” ”+n+” ”+t o p i c ;
40 txtMsg . s e t T e x t ( mesaj ) ;
41 p r o d u c e r . send ( txtMsg ) ;
42 session . close ();
43 conn . c l o s e ( ) ;
44 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 >” ) ;
45 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;
46 out . p r i n t l n ( ”<p>” ) ;
47 out . p r i n t l n ( ” D a t e l e au f o s t e x p e d i a t e s e r v e r u l u i ” ) ;
48 out . p r i n t l n ( ”</ c e n t e r ></body></html>” ) ;
49 }
50 catch ( E x c e p t i o n e ) {
51 out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
52 }
53 out . c l o s e ( ) ;
54 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 ” ) ;
55 }

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


58 throws S e r v l e t E x c e p t i o n , IOException {
59 doGet ( req , r e s ) ;
60 }
61 }

Codul servlet-ului care preia rezultatul


1 package jms ;
2 import j a v a x . jms . ∗ ;
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 153

3 import j a v a . i o . ∗ ;
4 import j a v a x . s e r v l e t . ∗ ;
5 import j a v a x . s e r v l e t . h t t p . ∗ ;

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

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


10 throws S e r v l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
13 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 ” ) ;
14 S t r i n g c l i e n t I D=”JMSCmmdc” ;
15 S t r i n g c l i e n t N a m e=”JMSCmmdc” ;
16 try {
17 // V a r i a n t a Apache−MessageQueue
18 // o r g . apache . a c t i v e m q . ActiveMQConnectionFactory c f=
19 // new o r g . apache . a c t i v e m q . ActiveMQConnectionFactory (
20 // ” tcp :// l o c a l h o s t :61616”);

22 // V a r i a n t a Sun MessageQueue
23 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=
24 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 ( ) ;
25 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” h o s t ” ) ;
26 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
27 T o p i c C o n n e c t i o n conn=c f . c r e a t e T o p i c C o n n e c t i o n ( ) ;
28 conn . s e t C l i e n t I D ( c l i e n t I D ) ;
29 T o p i c S e s s i o n s e s s i o n=
30 conn . c r e a t e T o p i c S e s s i o n ( f a l s e , S e s s i o n .AUTO ACKNOWLEDGE) ;
31 Destination tResult = session . createTopic ( topic ) ;
32 T o p i c S u b s c r i b e r consumer=
33 s e s s i o n . c r e a t e D u r a b l e S u b s c r i b e r ( ( Topic ) t R e s u l t , c l i e n t N a m e ) ;
34 conn . s t a r t ( ) ;
35 TextMessage txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;
36 S t r i n g cmmdc=txtMsg . g e t T e x t ( ) ;
37 session . close ();
38 conn . c l o s e ( ) ;
39 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 >” ) ;
40 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;
41 out . p r i n t l n ( ”<p>” ) ;
42 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 ) ;
43 out . p r i n t l n ( ”</ c e n t e r ></body></html>” ) ;
44 }
45 catch ( E x c e p t i o n e ) {
46 out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
47 }
48 out . c l o s e ( ) ;
49 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 }

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 )


53 throws S e r v l e t E x c e p t i o n , IOException {
54 doGet ( req , r e s ) ;
55 }
56 }
154 CAPITOLUL 6. SERVLET

6.5 FileUpload
Deseori clientul trebuie să furnizeze unui servlet un volum mare de date, de-
pozitate ı̂ntr-un fişier. Un produs care ne ajută să ı̂ndeplinim acest obiectiv este
commons-fileupload - dezvoltat de apache.
Commons-FileUpload - dezvoltat ı̂n cadrul apache - este un produs care simplifică
transferul unui fişier de la un client la programul server (file upload). Interfaţa de
programare a produsului se referă la partea de server - ı̂n cazul de faţă reprezentat
prin servlet.
Instalarea produsului constă din dezarhivarea fişierului descărcat din Internet.
În plus este nevoie de

• commons-io

Fişierele

• commons-fileupload-*.*.jar

• commons-io-*.*.jar

se depun ı̂n catalogul lib al servlet-ului.


Transferarea unui fişier, din partea clientului nu ridică nici o problemă. În fişierul
html de apelare, se defineşte un formular

<form
action=. . .
enctype="multipart/form-data"
method="post">

iar un fişier de ı̂ncărcat se fixează prin intermediul marcajului

<input type="file" name=. . . size=. . .>

Programul navigator afişează o fereastră de căutare, prin care clientul selectează


fişierul pe care doreşte să-l ı̂ncarce.
Dacă partea de client este un program, atunci se utilizează commons-httpclient.
6.4.1
De partea serverului, programarea ı̂ncărcării revine la

1. Crearea unei fabrici pentru manipularea fişierelor pe disc

FileItemFactory factory = new DiskFileItemFactory();

2. Crearea unei unelte de ı̂ncărcare

ServletFileUpload upload = new ServletFileUpload(factory);


6.5. FILEUPLOAD 155

3. Analiza (parsarea) mesajului furnizat de client

List fileItems = upload.parseRequest(req);

Fiecare element al listei implementează interfaţa FileItem.


Se pot fixa parametrii

• dimensiunea zonei de pe disc destinată datelor de ı̂ncărcat


DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(maxMemorySize);
• catalogul temporar de reţinere a datelor de ı̂ncărcat
factory.setRepositoryPath(tempDirectory);
sau direct
DiskFileItemFactory factory = new DiskFileItemFactory(
maxMemorySize, tempDirectory);
• dimensiunea maximă a unui fişier
upload.setSizeMax(maxRequestSize);

4. Prelucrarea elementelor ı̂ncărcate

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. În cazul unui element care nu este de tip fişier putem obţine numele şi valoarea
atributului furnizat de client

String name = item.getFieldName();


String value = item.getString();

6. În cazul unui fişier putem afla numele câmpului input, numele fişierului, di-
mensiunea fişierului
156 CAPITOLUL 6. SERVLET

String fieldName = item.getFieldName();


String fileName = item.getName();
long sizeInBytes = item.getSize();

7. Dacă dorim să salvăm fişierul pe calculatorul server atunci prelucrarea este

File uploadedFile = new File(...);


item.write(uploadedFile);

8. Dacă datele fişierului se ı̂ncarcă ı̂n memoria calculatorului atunci prelucrarea


este

InputStream in = item.getInputStream();
//preluarea datelor din fluxul in
. . .
in.close();

Alternativ, datele se pot reţine ca un şir de octeţi prin

byte[] data = item.get();

Exemplul 6.5.1 Să se obţină ı̂n memoria serverului matricea conţinută ı̂ntr-un
fişier text. În fişierul text, fiecare linie conţine o linie a matricei, iar elementele
sunt separate prin spaţii.

Metoda getMatrix utilizată reface matricea din datele fişierului.


1 package upload ;
2 import j a v a . i o . ∗ ;
3 import j a v a x . s e r v l e t . ∗ ;
4 import j a v a x . s e r v l e t . h t t p . ∗ ;
5 import j a v a . u t i l . ∗ ;
6 import o r g . apache . commons . f i l e u p l o a d . d i s k . ∗ ;
7 import o r g . apache . commons . f i l e u p l o a d . s e r v l e t . ∗ ;
8 import o r g . apache . commons . f i l e u p l o a d . ∗ ;

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

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


13 throws S e r v l e t E x c e p t i o n , IOException {
14 r e s . setContentType ( ” t e x t / p l a i n ” ) ;
15 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;
16 try {
17 boolean i s M u l t i p a r t = S e r v l e t F i l e U p l o a d . i s M u l t i p a r t C o n t e n t ( r e q ) ;
18 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 ( ) ;
19 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 ) ;
20 L i s t i t e m s = uplo ad . p a r s e R e q u e s t ( r e q ) ;
21 upload . s e t S i z e M a x ( 1 0 0 0 0 0 0 ) ;
22 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 ( ) ;
23 while ( i t e r . hasNext ( ) ) {
6.5. FILEUPLOAD 157

24 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 ( ) ;
25 i f ( ! item . i s F o r m F i e l d ( ) ) {
26 S t r i n g f i l e N a m e = item . getName ( ) ;
27 out . p r i n t l n ( f i l e N a m e ) ;
28 long s i z e I n B y t e s = item . g e t S i z e ( ) ;
29 out . p r i n t l n ( s i z e I n B y t e s ) ;
30 InputStream i n=item . g e t I n p u t S t r e a m ( ) ;
31 InputStreamReader i s r =new InputStreamReader ( i n ) ;
32 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 ) ;
33 double [ ] [ ] m a t r i x=g e t M a t r i x ( br ) ;
34 i n t m=m a t r i x . l e n g t h ;
35 i n t n=m a t r i x [ 0 ] . l e n g t h ;
36 f o r ( i n t i =0; i <m; i ++){
37 f o r ( i n t j =0; j <n ; j ++)
38 out . p r i n t ( m a t r i x [ i ] [ j ]+ ” ” ) ;
39 out . p r i n t l n ( ) ;
40 }
41 br . c l o s e ( ) ;
42 isr . close ();
43 in . close ( ) ;
44 out . c l o s e ( ) ;
45 }
46 }
47 }
48 catch ( E x c e p t i o n e ) {
49 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 ( ) ) ;
50 }
51 }

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


54 Vector<Double> v=new Vector<Double > ( 1 0 ) ;
55 double [ ] [ ] m a t r i x=n u l l ;
56 try {
57 String line , s ;
58 i n t m=0 ,n , mn ;
59 do{
60 l i n e=br . r e a d L i n e ( ) ;
61 i f ( l i n e != n u l l ) {
62 m++;
63 S t r i n g T o k e n i z e r s t=new S t r i n g T o k e n i z e r ( l i n e , ” ” ) ;
64 while ( s t . hasMoreElements ( ) ) {
65 s=s t . nextToken ( ) ;
66 v . addElement (new Double ( s ) ) ;
67 }
68 }
69 }
70 while ( l i n e != n u l l ) ;
71 i f ( v . s i z e () >0){
72 mn=v . s i z e ( ) ;
73 n=mn/m;
74 m a t r i x=new double [m ] [ n ] ;
75 f o r ( i n t i =0; i <m; i ++){
76 f o r ( i n t j =0; j <n ; j ++){
77 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 ( ) ;
78 System . out . p r i n t ( m a t r i x [ i ] [ j ]+ ” ” ) ;
79 }
80 System . out . p r i n t l n ( ) ;
81 }
82 }
158 CAPITOLUL 6. SERVLET

83 }
84 catch ( E x c e p t i o n e ) {
85 throw new E x c e p t i o n ( e . g e t M e s s a g e ( ) ) ;
86 }
87 return m a t r i x ;
88 }
89 }

Pentru compilare se completează variabila de sistem classpath cu referinţa către


fişierul commons-fileupload-*.*.jar.
Formularul clientului este
1 <html>
2 <head>
3 <s c r i p t l a n g u a g e=” j a v a s c r i p t ” >
4 < !−−
5 function checkIt (){
6 var f i s =document . l i n e a r . m y f i l e . value ;
7 i f ( f i s==” ” ) {
8 a l e r t (” S e l e c t a t i f i s i e r u l corespunzator matricei ” );
9 return f a l s e ;
10 }
11 return true ;
12 }
13 //−−>
14 </ s c r i p t>
15 </head>
16 <body>
17 <h1> I n c &#259; r c a r e a unui f i &#351; i e r </h1>
18 <form
19 action=” 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 ”
20 e n c t y p e=” m u l t i p a r t / form−data ” method=” p o s t ”
21 name=” l i n e a r ” onSubmit=” r e t u r n c h e c k I t ( ) ”>
22 <p>
23 S e l e c t a &#355; i f i &#351; i e r u l
24 <p>
25 <input type=” f i l e ” name=” m y f i l e ” s i z e =30>
26 <p>
27 <input type=” submit ” value=” Expediaza f i s i e r u l ”>
28 </form>
29 </body>
30 </html>
Capitolul 7

Java Server Page – JSP

7.1 Tehnologia JSP


Tehnologia JSP este de tip procesare de şabloane (template engine), similară cu
PHP, ASP.NET, etc. JSP permite includerea codului Java ı̂ntr-un document html.
Un asemenea document se depozitează pe un server Web, container de servleţi, cu
extensia jsp, eventual jspx.
Apelarea documentului JSP se realizează prin

• meniul File/Open a unui navigator, cu


http://host:port/contex/doc.jsp

• referinţă html
<a href="http://host:port/context/doc.jsp">

• valoare a atributului action ı̂ntr-un marcaj form


<form action="http://host:port/context/doc.jsp" ... >

Prin context se ı̂nţelege calea de la catalogul webapps până la catalogul ce conţine


fişierul jsp.
În cazul serverului Web tomcat vom depozita fişierele JSP ı̂ntr-un catalog jsp
din arborele

webapps
|--> JSPApp
|--> WEB-INF
|--> classes
|--> web.xml
|--> jsp
|--> doc.jsp

159
160 CAPITOLUL 7. JAVA SERVER PAGE – JSP

caz ı̂n care contextul va fi JSPApp/jsp.


Astfel, schimbând numele fişierului Hello.html
1 <html>
2 <body>
3 Hello
4 </body>
5 </html>

ı̂n Hello.jsp şi plasându-l ı̂n catalogul jsp se obţine acelaşi efect, dar prelucrarea
paginilor / documentelor este diferită. Fişierul html este prelucrat doar de progra-
mul navigator şi poate fi deschis ca fişier, ı̂n timp ce fişierul JSP este prelucrat de
serverul Web cu afişarea prin intermediul navigatorului. Prelucrarea efectuată de
serverul Web constă din transformarea paginii / documentului JSP ı̂ntr-un servlet,
care este compilat şi lansat ı̂n execuţie. Din aceastră cauză prima invocare a paginii
/ documentului JSP durează mai mult decât apelările ulterioare.
Apelarea paginii / documentului JSP se face prin
http://localhost:8080/JSPApp/jsp/Hello.jsp
Există două moduri de a include elemente JSP ı̂ntr-un text html:

• prin elemente specifice JSP.


Fişierul are extensia jsp şi se numeşte pagină JSP.

• prin marcaje xml aparţinând spaţiului de nume

http://java.sun.com/JSP/Page

Fişierul poate avea extensia jsp sau jspx şi se numeşte document JSP.

Comentariile JSP se scriu de forma

<%-- Comentariu --%>

Considerăm următoarul exemplu introductiv:

Exemplul 7.1.1 Putem afişa valoarea unei variabile Java (de exemplu data calen-
daristică) prin

• Varianta paginii JSP

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

7 <p>
8 <% j a v a . u t i l . Date data1=new j a v a . u t i l . Date ( ) ; %>
9 Data c a l e n d a r i s t i c a 2 :
7.1. TEHNOLOGIA JSP 161

10 <%= data1 %>

12 <p>
13 <% j a v a . u t i l . Date data2=new j a v a . u t i l . Date ( ) ; %>
14 Data c a l e n d a r i s t i c a 3 :
15 <% out . p r i n t ( data2 ) ; %>
16 </body>
17 </html>

Dacă se utilizează operatorul de afişare = atunci după expresia de afişat nu se


pune ;.
Variabila predefinită out este de tip javax.servlet.jsp.JspWriter.

• Varianta documentului JSP

1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>


2 <html x m l n s : j s p=” h t t p : // j a v a . sun . com/JSP/ Page ”>
3 <body>
4 < j s p : d e c l a r a t i o n>
5 j a v a . u t i l . Date d=new j a v a . u t i l . Date ( ) ;
6 </ j s p : d e c l a r a t i o n>
7 < 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>
8 </ body>
9 </ html>

Codul Java inglobat ı̂ntr-un text html se numeşte scriptlet. Sintaxa utilizată este

• Varianta paginii JSP

<% cod Java %>

• Varianta documentului JSP

<jsp:scriptlet> codJava </jsp:scriptlet>

Domeniul de valabilitate. Domeniul de valabilitate defineşte intervalul de


timp, de existenţă al unui obiect. În cadrul unei pagini / document JSP sunt definite
domeniile de valabilitate prin valorile:

Valoare Domeniu de vizibilitate


page pagina curentă
request ı̂n pagina curentă,
ı̂n paginile incluse şi
ı̂n paginile către care se face o redirectare
session ı̂n sesiunea curentă
application pe durata rulării aplicaţiei
162 CAPITOLUL 7. JAVA SERVER PAGE – JSP

În orice pagină / document JSP sunt predefinite variabilele:


Variabila Tip/Clasa
out javax.servlet.jsp.JspWriter
request javax.servlet.ServletRequest
response javax.servlet.ServletResponse
session javax.servlet.http.HttpSession
page java.lang.Object, this
pageContext javax.servlet.jsp.PageContext
application javax.servlet.ServletContext
ServletContext.getServletConfig().getContext()
exception java.lang.Throwable

Astfel

String request.getParameter(String numeParametru)

furnizează valoarea parametrului numeParametru dintr-un formular html.

Exemplul 7.1.2 Pagina JSP Hello: Clientul transmite numele paginii care ı̂i răspunde
cu mesajul de salut ”Hi nume!”.

Codul paginii JPS (hello.jsp) este


1 <html>
2 <head>
3 < t i t l e> j s p h e l l o </ t i t l e>
4 </head>
5 <body>
6 <center>
7 <h1> Pagina de r &#259; spuns </h1>
8 <p>
9 <%
10 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”)+” ! ” ) ;
11 %>
12 </ center>
13 </body>
14 </html>

apelat din (index.html )

1 <html>
2 <head>
3 < t i t l e> JSP H e l l o </ t i t l e>
4 </head>
5 <body bgcolor=”#bbeebb ”>
6 <center>
7 <h1> Pagina de a p e l a r e JSP </h1>
8 <form method=” p o s t ”
9 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / j s p h e l l o / j s p / h e l l o . j s p ”>
10 <p> Numele :
7.1. TEHNOLOGIA JSP 163

11 <input type=” t e x t ” name=”name” s i z e =20>


12 <p>
13 <input type=” submit ”>
14 </form>
15 </ center>
16 </body>
17 </html>

Compilarea şi arhivarea servlet-ului o vom realiza prin intermediul lui apache-
ant. În acest scop se crează structura:
jsphello
| |---> jsp
| | | hello.jsp
| |---> lib
| |---> src
| |---> web
| | | web.xml
| |---> web-files
| | | index.html
| build.xml

Fişierul web.xml este simplu


1 <?xml version=” 1 . 0 ” e n c o d i n g=”ISO−8859−1” ?>

3 < !DOCTYPE web−app


4 PUBLIC ”−//Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN”
5 ” h t t p : // j a v a . sun . com/ dtd /web−a p p 2 3 . dtd ”>

7 <web−app>
8 <welcome−f i l e − l i s t>
9 <welcome− f i l e >i n d e x . html</ welcome− f i l e >
10 <welcome− f i l e >i n d e x . j s p</ welcome− f i l e >
11 </ welcome−f i l e − l i s t>
12 </web−app>

Fişierul build.xml prelucrat de apache-ant folosit este


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

3 <p r o p e r t y name=”TOMCAT HOME” v a l u e=” d : / apache−tomcat − 5 . 5 . 2 6 ” />


4 <p r o p e r t y name=” d i s t . name” v a l u e=” j s p h e l l o ” />
5 <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 ” />
6 <p r o p e r t y name=” b u i l d . d i r ” v a l u e=” b u i l d ” />

8 <path i d=” m y c l a s s p a t h ”>


9 < f i l e s e t d i r=” l i b ”>
10 <i n c l u d e name=” ∗ . j a r ” />
11 </ f i l e s e t>
12 <p a t h e l e m e n t path=” ${TOMCAT HOME}/common/ l i b / s e r v l e t −a p i . j a r ” />
13 </ path>

15 <t a r g e t name=” i n i t ”>


16 <d e l e t e d i r=” ${ d i s t . d i r } ” />
17 <mkdir d i r=” ${ b u i l d . d i r } ” />
18 <mkdir d i r=” ${ d i s t . d i r } ” />
19 <mkdir d i r=” ${ b u i l d . d i r }/ j s p ” />
20 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF” />
164 CAPITOLUL 7. JAVA SERVER PAGE – JSP

21 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF/ c l a s s e s ” />


22 <mkdir d i r=” ${ b u i l d . d i r }/WEB−INF/ l i b ” />
23 </ t a r g e t>

25 <t a r g e t name=” c o m p i l e ” depends=” i n i t ”>


26 <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 ”
27 s r c d i r=” ${ b a s e d i r }/ s r c ”
28 d e s t d i r=” ${ b u i l d . d i r }/WEB−INF/ c l a s s e s ” />
29 </ t a r g e t>

31 <t a r g e t name=” g e n e r a t e . war ” depends=” c o m p i l e ”>


32 <copy t o d i r=” ${ b u i l d . d i r } ” >
33 < f i l e s e t d i r=” ${ b a s e d i r }/web− f i l e s ” >
34 <i n c l u d e name=” ∗ . html ” />
35 </ f i l e s e t>
36 </ copy>
37 <copy t o d i r=” ${ b u i l d . d i r }/ j s p ” >
38 < f i l e s e t d i r=” ${ b a s e d i r }/ j s p ” >
39 <i n c l u d e name=” ∗ . j s p ” />
40 <i n c l u d e name=” ∗ . j s p x ” />
41 </ f i l e s e t>
42 </ copy>
43 <copy t o d i r=” ${ b u i l d . d i r }/WEB−INF” >
44 < f i l e s e t d i r=” ${ b a s e d i r }/web” >
45 <i n c l u d e name=” ∗ . xml” />
46 </ f i l e s e t>
47 </ copy>
48 <copy t o d i r=” ${ b u i l d . d i r }/WEB−INF/ l i b ” >
49 < f i l e s e t d i r=” ${ b a s e d i r }/ l i b ” >
50 <i n c l u d e name=” ∗ . j a r ” />
51 </ f i l e s e t>
52 </ copy>
53 <copy t o d i r=” ${ b u i l d . d i r } ” >
54 < f i l e s e t d i r=” ${ b a s e d i r } ” >
55 <i n c l u d e name=” ∗ . p r o p e r t i e s ” />
56 </ f i l e s e t>
57 </ copy>
58 <j a r d e s t f i l e =” ${ d i s t . d i r }/${ d i s t . name } . war ” b a s e d i r=” ${ b u i l d . d i r } ” />
59 </ t a r g e t>
60 </ p r o j e c t>

7.1.1 Declaraţii JSP


Într-un scriplet, printr-o declaraţie JSP, putem defini câmpuri(variabile) şi metode
Java ce pot fi apoi folosite, respectiv apelate ı̂n documentul respectiv. O declaraţie
JSP se defineşte printr-un marcaj
<%! . . . %>
sau, ı̂n format XML
<jsp:declaration> . . . </jsp:declaration>

Exemplul 7.1.3 Calculul celui mai mare divizor comun a două numere naturale
cu metoda de calcul este definită ı̂ntr-o declaraţie JSP.
7.1. TEHNOLOGIA JSP 165

1 <html>
2 <body>
3 <H1> CMMDC </H1>
4 <%!
5 l o n g cmmdc( l o n g m, l o n g n ) {
6 long c , r ;
7 do {
8 c=n ;
9 r=m%n ;
10 m=n ;
11 n=r ;
12 } while ( r !=0);
13 return c ;
14 }
15 %>
16 Rezultatul este
17 <%
18 String sm=r e q u e s t . g e t P a r a m e t e r ( ”m” ) ;
19 String sn=r e q u e s t . g e t P a r a m e t e r ( ”n” ) ;
20 l o n g m=Long . parseLong ( sm ) , n=Long . pa rse Lo ng ( sn ) ;
21 out . p r i n t l n (cmmdc(m, n ) ) ;
22 %>
23 </body>
24 </html>

apelat din documentul html


1 <html>
2 <body>
3 <h1> C a l c u l u l Cmmdc </h1>
4 <form method=” p o s t ”
5 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / JSPApp/ j s p /BeanCmmdc . j s p ”>
6 <p>
7 Primul numar e s t e
8 <input type=” t e x t ” name=”m” value=” ” s i z e=5>
9 <p>
10 Al d o i l e a numar e s t e
11 <input type=” t e x t ” name=”n” value=” ” s i z e=5>
12 <p>
13 <input type=” submit ” value=” C a l c u l e a z a ”>
14 <input type=” r e s e t ” value=”Abandon”>
15 </form>
16 </body>
17 </html>

Există două metode jspInit() - utilizată pentru iniţializarea datelor -, şi jspDestroy()
- utilizată pentru eliberarea resurselor -, care dacă sunt declarate de programator
atunci sunt executate la ı̂nceputul şi la sfârşitul ciclului de execuţie a paginii /
documentului JSP.

7.1.2 Directive JSP


Directivele JSP fixează informaţii pentru tot documentul jsp. O directivă jsp se
indică prin marcajul
<%@ directivă atribut1 atribut2 . . . %>
166 CAPITOLUL 7. JAVA SERVER PAGE – JSP

sau ı̂n format XML

<jsp:directive.directiva atribut1 atribut2 . . . />

unde fiecare atribut are sintaxa nume=valoare.


Directivele pot fi: page, include, taglib.

• Directiva page are atributele


extends= ”numeClasă” Servlet-ul corespunzător paginii jsp extinde
clasa numeClasă.
import= ”listă de pachete separate prin ,”
session= "true | false"
info= ”text” Informaţia se poate regăsi apelând metoda
Servlet.getServletInfo()
errorPage= ”adresa url a paginii ce tratează excepţia”
isErrorPage= "true | false"
• Directiva include permite includerea unor fişiere .html sau .jsp ı̂n document

<%@ include file= fişier html, jsp %>

• Directiva taglib indică bibliotecile de marcaje utilizate ı̂n documentul jsp,


având atributele
uri= ”uri - Universal Resource Identifier - a bibliotecii de marcaje”
prefix= ”prefixul marcajului”

7.1.3 Marcaje JSP predefinite


Un marcaj JSP defineşte o acţiune care se execută ı̂n timpul procesării paginii
jsp. Sintaxa marcajelor JSP seamănă cu cea a marcajelor html sau xml

<prefix : marcaj atribute />

Dintre marcajele JSP predefinite – adică cu prefixul JSP – amintim:

• <jsp : include page=”numeFişier jsp sau html” />

• <jsp : forward page=”numeFişier jsp sau html” />


În 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 "/>
7.1. TEHNOLOGIA JSP 167

. . . . . .
</jsp:params>

• <jsp : useBean id=”numeComponentăJava”


class=”numeClasa”
scope=”domeniu” />
unde domeniu precizează domeniul de vizibilitate al componentei Java, adică
page, request, session, application.
• <jsp : setProperty name=”numeComponentăJava”
property=”numeProp”
value=”valoare”/>
Acest marcaj este echivalent cu codul Java
numeComponentăJava.setNumeProp(valoare).
• <jsp : getProperty name=”numeComponentăJava”
property=”numeProp”/>
Dacă numeProp=”*” atunci acţiunea vizează toate proprietăţile componentei
Java.

7.1.4 Componentă Java (Java Bean)


O componentă Java este o clasă care poate interacţiona cu alte componente Java,
cu un document jsp, etc.
O componenta Java conţine cel puţin
• Un constructor fără nici un argument;
• O mulţime de câmpuri declarate private;
• Pentru fiecare asemenea câmp

private Tip xyz;

trebuie definite metodele

public void setXyz(Tip xyz){


this.xyz=xyz;
}

public Tip getXyz(){


return xyz;
}
168 CAPITOLUL 7. JAVA SERVER PAGE – JSP

7.1.5 Pagini JSP cu componente Java


Clasa componentei Java care se va utiliza ı̂ntr-o pagină JSP trebuie inclusă ı̂ntr-
un pachet.
Numele parametrilor din formularelele de introducere a datelor trebuie să coin-
cidă cu identificatorii câmpurilor din componenta Java corespunzătoare.
Reluăm exemplul 7.1.2 cu o componentă Java corespunzătoare numelui din for-
mularul index.html.

Exemplul 7.1.4

1 package j s p ;
2 public c l a s s Hel loBe an {
3 private S t r i n g name=” ” ;
4 public S t r i n g getName ( ) {
5 return name ;
6 }
7 public void setName ( S t r i n g name ) {
8 t h i s . name=name ;
9 }
10 }

În acest caz, pagina JSP este


1 <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 ” />
2 <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=” ∗ ” />
3 <html>
4 <head>
5 < t i t l e> j s p h e l l o </ t i t l e>
6 </head>
7 <body>
8 <h1> Pagina de r &#259; spuns </h1>
9 <center>
10 <%
11 out . p r i n t l n ( ” Hi ”+o b j . getName ()+ ” ! ” ) ;
12 %>
13 </ center>
14 </body>
15 </html>

Mai mult, se poate include formularul ı̂n pagina JSP, bineı̂nţeles ştergându-l din
fişierul html:
1 <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 ” />
2 <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=” ∗ ” />
3 <html>
4 <head>
5 < t i t l e> j s p h e l l o </ t i t l e>
6 </head>
7 <body>
8 <center>
9 <h1> Pagina JSP − a p l i c a &#355; i a H e l l o </h1>
10 <form method=” p o s t ”>
11 <p> <h3> I n t r o d u c e t i numele : </h3>
12 <input type=” t e x t ” name=”name” s i z e =20>
7.1. TEHNOLOGIA JSP 169

13 <p>
14 <input type=” submit ”>
15 </form>
16 <p>
17 <%
18 out . p r i n t l n ( ” Hi ”+o b j . getName ()+ ” ! ” ) ;
19 %>
20 </ center>
21 </body>
22 </html>

În vederea generării arhivei war, desfăşurarea aplicaţiei va fi


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

Exemplul 7.1.5 Pagină JSP pentru calculul celui mai mare divizor comun cu metoda
de calcul definită ı̂ntr-o componentă Java.
Utilizând documentului html din Exemplul 7.1.3 se defineşte componenta Java
1 package cmmdc ;
2 public c l a s s CmmdcBean{
3 private S t r i n g m=” ” ;
4 private S t r i n g n=” ” ;
5 private S t r i n g cmmdc ;

7 public void setM ( S t r i n g m) {


8 t h i s .m=m;
9 }
10 public void setN ( S t r i n g n ) {
11 t h i s . n=n ;
12 }
13 public S t r i n g getM ( ) {
14 return m;
15 }
16 public S t r i n g getN ( ) {
17 return n ;
18 }

20 public S t r i n g getCmmdc ( ) {
21 long m=Long . parseLong ( getM ( ) ) ;
22 long n=Long . parseLong ( getN ( ) ) ;
23 return (new Long (cmmdc(m, n ) ) ) . t o S t r i n g ( ) ;
24 }

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

28 }
170 CAPITOLUL 7. JAVA SERVER PAGE – JSP

Instanţiem o componenta Java şi ı̂i fixăm proprietăţile (adică ı̂i transmitem
parametri problemei) după care apelăm metoda ce calculează rezultatul dorit ı̂n
pagina JSP:
1 <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 ” />
2 <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=” ∗ ” />
3 <html>
4 <body>
5 Cel mai mare d i v i z o r comun a l n u m e r e l o r
6 <p>
7 <%=o b j . getM ( ) %> s i <%=o b j . getN ( ) %>
8 e s t e <%=o b j . getCmmdc ( ) %>
9 </body>
10 </html>

Exemplul 7.1.6 Generarea unei excepţii (errhandler.jsp):

1 <%@ page e r r o r P a g e=” e r r o r p a g e . j s p ” %>


2 <html>
3 <body>
4 <%
5 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 ( ) ;
6 i f ( m a t e r i a . e q u a l s ( ”AN” ) ) {
7 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 >” ) ;
8 }
9 else{
10 throw new E x c e p t i o n ( ”N−a t i f a c u t a l e g e r e a c o r e c t a ” ) ;
11 }
12 %>
13 </body>
14 </html>

cu pagina de tratare a excepţiei (errorpage.jsp)

1 < !−−
2 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
3 n a v i g a t o r u l u i IE s i a l u i apache−tomcat − 5 . ∗ . ∗ . / 6 . ∗ . ∗ . In l i p s a
4 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 .
5 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 .

7 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
8 o p t i u n e a ”Show f r i e n d l y HTTP e r r o r message ”

10 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 .
11 −−>

13 <%@ page i s E r r o r P a g e=” t r u e ” %>


14 <html>
15 <body>
16 <div a l i g n=” c e n t e r ”>
17 <%= e x c e p t i o n . g e t M e s s a g e ( ) %>
18 </ div>
7.2. JSP STANDARD TAG LIBRARY JSTL 171

20 </body>
21 </html>

apelate prin

1 <html>
2 <body>
3 <form method=p o s t
4 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / j s p / e r r h a n d l e r . j s p ”>
5 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 ?
6 <p>
7 A l g o r i t m i c a s i programare
8 <input type=” r a d i o ” name=” m a t e r i a ” value=”AP” checked>
9 <p>
10 A n a l i z a numerica
11 <input type=” r a d i o ” name=” m a t e r i a ” value=”AN”>
12 <p>
13 Inteligenta artificiala
14 <input type=” r a d i o ” name=” m a t e r i a ” value=”IA”>
15 <p>
16 <input type=submit>
17 </form>
18 </body>
19 </html>

7.2 JSP Standard Tag Library JSTL


JSTL este o familie de biblioteci de marcaje ce oferă o serie de facilităţi activităţii
de realizare a paginilor Web. JSTL ajută la separarea activităţii de programare de
aceea a proiectare (design) a paginii Web.
JSTL este alcătuită din 5 biblioteci:
URI Descriere
http://java.sun.com/jsp/jstl/core Biblioteca de bază
http://java.sun.com/jsp/jstl/xml Biblioteca de prelucrare
a documentelor xml
http://java.sun.com/jsp/jstl/fmt Biblioteca de formatare a datelor
http://java.sun.com/jsp/jstl/sql Biblioteca de lucru cu baze de date
http://java.sun.com/jsp/jstl/functions Biblioteca de funcţii ajutătoare

Instalarea bibliotecilor. Bibliotecile sunt livrate ı̂mpreună cu apache-tomcat-*


ı̂n catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin fişierele jstl.jar
şi standard.jar.

Utilizarea bibliotecilor. În vederea utilizării, cele două fişiere trebuie copiate
ı̂n catalogul apache-tomcat-*.*\lib sau ı̂n catalogul lib al aplicaţiei care uti-
lizează bibliotecile.
172 CAPITOLUL 7. JAVA SERVER PAGE – JSP

În pagina / documentul JSP, o bibliotecă utilizată trebuie declarată printr-o


directivă taglib.

7.2.1 Biblioteca de bază


<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

Marcaje din biblioteca de bază:

• c:set Fixează o valoare ı̂ntr-o variabilă.


Atribute ale marcajului:
Atribut Fel Descriere
var obligatoriu Numele variabilei ce va stoca valoarea
expresiei.
value opţional Expresia care va fi evaluată şi atribuită
variabilei
scope opţional Domeniul de vizibilitate al variabilei.
Unul din valorile:
page, request, session, application.
Referirea la o variabilă se face prin sintaxa ${numeVariabilă}
Referirea la valoarea unui câmp dintr-un formular se face prin sintaxa ${param.numeCâmp}
Alături de obiectul param, alte obiecte predefinite sunt cookie, header,
initParam, pageContext.
Se pot defini variabile cu acelaşi nume dar având domenii de vizibilitate
diferită. Referirea se face prin ${pageScope.numeVariabilă},
${requestScope.numeVariabilă}, ${sessionScope.numeVariabilă},
${applicationScope.numeVariabilă}.
Plasând clauza empty ı̂naintea unei variabile, ${empty numeVariabilă}, se
obţine false sau true după cum variabila are sau nu atribuită o valoare.

• c:remove Şterge o variabilă.


Atribute ale marcajului:
Atribut Fel Descriere
var obligatoriu Numele variabilei ce se şterge.
scope opţional Domeniul de vizibilitate al variabilei.
Unul din valorile:
page, request, session, application.
7.2. JSP STANDARD TAG LIBRARY JSTL 173

• c:out Afişează o valoare.


Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Valoarea ce se evaluează şi se afişează.
default opţional Cea ce se afişează ı̂n cazul ı̂n care
expresia nu poate fi evaluată.
escapeXml opţional true / false. Valoarea implicită este true.
Pe false interpretează caracterele din value
ca şi cod html.

• c:if Test, verificarea unei condiţii.


Atribute ale marcajului:
Atribut Fel Descriere
test obligatoriu Condiţia de test.
var opţional Numele variabilei ce va stoca valoarea
testului.
scope opţional Domeniul de vizibilitate al variabilei
definită anterior.

În cazul ı̂n care condiţia are valoarea true se prelucrează corpul marcajului,
ı̂n caz contrar, acesta este ignorat.

Exemplul 7.2.1 Preluarea datelor unui formular cu câmpurile de intrare nume,


prenume şi email se face prin pagina JSP

1 <HTML>
2 <%@ 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 ” %>
3 <BODY>
4 <p>
5 <c : i f t e s t=” $ {empty param . nume} ” var=” testNume ” >
6 <c : out value=”Numele l i p s e s t e ! ” />
7 </ c : i f>
8 <c : i f t e s t=” $ { not testNume } ” >
9 Nume :<c : out value=” $ {param . nume} ” />
10 </ c : i f>
11 <p>
12 <c : i f t e s t=” $ {empty param . prenume } ” var=” testPrenume ” >
13 <c : out value=” Prenumele l i p s e s t e ! ” />
14 </ c : i f>
15 <c : i f t e s t=” $ { not testPrenume } ” >
16 Prenume :<c : out value=” $ {param . prenume } ” />
17 </ c : i f>
18 <p>
19 <c : i f t e s t=” $ {empty param . e m a i l } ” var=” t e s t E m a i l ”>
20 <c : out value=” Adresa E−Mail l i p s e s t e ! ” />
21 </ c : i f>
22 <c : i f t e s t=” $ { not t e s t E m a i l } ” >
174 CAPITOLUL 7. JAVA SERVER PAGE – JSP

23 E−m a i l :<c : out value=” $ {param . e m a i l } ” />


24 </ c : i f>
25 </BODY>
26 </HTML>

• c:choose Marcajul de selecţie poate conţine oricâte marcaje c:when şi cel mult
un marcaj c:otherwise. Fiecare marcaj c:when conţine obligatoriu atributul
test. Dacă ı̂ntr-un marcaj c:when condiţia are valoarea true, atunci se
prelucrează corpul acelui marcaj. În cazul ı̂n care toate marcajele c:when au
fost evaluate cu false atunci se va prelucra marcajul c:otherwise (marcaj
fără atribute).

• c:forEach Ciclu.
Atribute ale marcajului:
Atribut Fel Descriere
items opţional Colecţia care se parcurge.
var opţional Numele variabilei ı̂n care se stochează
valoarea elementului curent.
begin opţional Valoarea iniţială a variabilei var.
end opţional Valoarea finală a variabilei var.
step opţional Valoarea pasului de iterare. Implicit este 1.
varStatus opţional Informaţii despre elementul curent.
Variabila varStatus are câmpurile:

– index valoarea curentă a elementului după care se realizează ciclarea;


– count numărul iteraţiei curente;
– first are valoarea true dacă este primul element al ciclului;
– last are valoarea true dacă este ultimul element al ciclului;

Exemplul 7.2.2 Lista parametrilor formularului de apelare a exemplului an-


terior se afişează prin:

<h2> Lista parametrilor din formular </h2>


<ul>
<c:forEach items="${param}" var="p">
<li>
<c:out value="${p}" />
</li>
</c:forEach>
</ul>

Exemplul 7.2.3 Lista parametrilor unui header se afişează prin:


7.2. JSP STANDARD TAG LIBRARY JSTL 175

<h2> Lista campurilor din antet </h2>


<ul>
<c:forEach items="${header}" var="h">
<li>
<c:out value="${h}" />
</li>
</c:forEach>
</ul>

Exemplul 7.2.4 Verificarea fontului cu care se scriu titlurile ı̂ntr-un docu-


ment html:

<c:forEach begin="1" end="6" var="i" >


<c:out value="<h${i}> Heading ${i} </h${i}>" escapeXml="false" />
</c:forEach>

• c:forTokens Asigură aceaşi funcţionalitate ca şi clasei java.util.String


Tokenizer.
Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Valoarea ce se evaluează şi se afişează.
expresiei.
default opţional Cea ce se afişează ı̂n cazul ı̂n care
expresia nu poate fi evaluată.
escapeXml opţional true / false. Valoarea implicită este true.
Pe false interpretează caracterele din value
ca şi cod html.

• c:import Permite includerea altor pagini JSP ı̂n pagina curentă.


Atribute ale marcajului:
Atribut Fel Descriere
url obligatoriu Adresa documentului importat.
context opţional Context-ul paginii / documentului importat.
Simbolul /, urmat de numele unei aplicaţii
de pe acelaşi server.
var opţional Numele variabilei ı̂n care va fi stocat
documentul importat.
scope opţional Domeniul de vizibilitate al variabilei var.
Unul din valorile:
page, request, session, application.
Cu marcajul c:param se pot fixa parametri pentru pagina importată. Acest
marcaj are două atribute name şi value. Acesti parametri se transmit cu
metoda get.
176 CAPITOLUL 7. JAVA SERVER PAGE – JSP

• c:redirect Redirectarea activitatea către o altă pagină.


Atribute ale marcajului:
Atribut Fel Descriere
url obligatoriu Adresa paginii către care se face redirectarea.
context opţional Context-ul paginii către care se face redirectarea.
Simbolul /, urmat de numele unei aplicaţii
de pe acelaşi server.
Prin redirectare, parametrii nu sunt retransmişi automat mai departe.

• c:url Reţine adrese URL.


Atribute ale marcajului:
Atribut Fel Descriere
value obligatoriu Adresa documentului de reţinut.
context opţional Context-ul documentului.
Simbolul /, urmat de numele unei aplicaţii
de pe acelaşi server.
var opţional Numele variabilei ı̂n care va fi stocată
adresa documentului.
scope opţional Domeniul de vizibilitate al variabilei var.
Unul din valorile:
page, request, session, application.

7.2.2 Biblioteca de lucru cu baze de date


<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>

Marcaje din biblioteca de bază:

• sql:setDataSource Fixează referinţa la baza de date.


Atribute ale marcajului:
Atribut Fel Descriere
dataSource opţional Referinţa la baza de date
driver opţional Driver-ul bazei de date
url opţional url-ul bazei de date
username opţional nume utilizatorului bazei de date
password opţional parola de acces la baza de date
var opţional variabila cu referinţa la baza de date
scope opţional Domeniul de vizibilitate al variabilei var.
7.2. JSP STANDARD TAG LIBRARY JSTL 177

• sql:query O interogare a bazei de date.


Atribute ale marcajului:
Atribut Fel Descriere
sql obligatoriu Fraza sql
dataSource opţional Referinţa la baza de date
startRow opţional Linia de la care se ı̂ncepe interogarea
maxRows opţional Numărul maxim de rezultate acceptate
var obligatoriu Variabila cu rezultatele interogării
bazei de date
scope opţional Domeniul de vizibilitate al variabilei var.

• sql:update Actualizarea a bazei de date.


Atribute ale marcajului:
Atribut Fel Descriere
sql obligatoriu Fraza sql
dataSource opţional Referinţa la baza de date

Exemplul 7.2.5 Să se afişeze lista din agenda telefonică creată ı̂n exemplul din
Cap. Servlet.

1 <HTML>
2 <%@ 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 ” %>
3 <%@ 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 ” %>
4 <BODY>
5 <p>
6 <s q l : s e t D a t a S o u r c e
7 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 ”
8 u r l=” j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / A g e n d a T e l e f o n i c a ”
9 var=”db” />
10 <s q l : query
11 d a t a S o u r c e=” $ {db} ”
12 var=” r e z u l t ”
13 s q l=” s e l e c t ∗ from t e l e f ” />
14 <c : i f t e s t=” $ { r e z u l t . rowCount g t 0} ” >
15 <table>
16 <tr>
17 <c : f o r E a c h i t e m s=” $ { r e z u l t . columnNames} ” var=” c o l ”>
18 <th>
19 <c : out value=” $ { c o l } ” />
20 </th>
21 </ c : f o r E a c h>
22 </ tr>
23 <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 ” >
24 <tr>
25 <c : f o r E a c h i t e m s=” $ { l i n e } ” var=” elem ” >
26 <td>
27 <c : out value=” $ { elem } ” />
28 </td>
29 </ c : f o r E a c h>
178 CAPITOLUL 7. JAVA SERVER PAGE – JSP

30 </ tr>
31 </ c : f o r E a c h>
32 </ table>
33 </ c : i f>
34 </BODY>
35 </HTML>

7.3 Marcaje JSP personale


Programatorul poate crea marcaje JSP proprii care se grupează ı̂n colecţii numite
biblioteci de marcaje.

7.3.1 Marcaje fără atribute şi fără corp.


Pentru a crea unui asemenea marcaj JSP propriu este necesară definirea a patru
componente:

1. O clasă de definiţie a comportamentului marcajului JSP (tag handler class).

2. Descriptorul de bibliotecă de marcaje JSP, care leagă clasa de definiţie a mar-


cajului cu numele simbolic de utilizare.

3. Marcajul taglib a fişierului web.xml a lui tomcat, care permite serverului


Web să găsească descriptorul de bibliotecă de marcaje şi clasele de definiţie a
comportamentului marcajelor JPS.

4. Fişierul JSP ce utilizează marcajul JSP (clientul).

Exemplificăm acestă tehnologie prin

Exemplul 7.3.1 Să se realizeze un marcaj dateTag, a cărui efect să fie afişarea
datei calendaristice.

1. Clasa de definiţie a comportamentului marcajului. Programul constă din:

(a) Importul pachetelor


import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
Aceste pachete se găsesc ı̂n fişierul jsp-api.jar.
(b) Un marcaj fără atribute şi fără corp trebuie să extindă clasa TagSupport
şi să suprascrie metoda doStartTag, care defineşte activitatea intreprinsă
când este ı̂ntâlnit marcajul ı̂ntr-un document jsp. Metoda trebuie să
returneze constanta SKIP BODY.
7.3. MARCAJE JSP PERSONALE 179

public class NumeClasa extends TagSupport{


public int doStartTag(){
. . .
return SKIP_BODY;
}
}

(c) Scrierea ı̂n fluxul de ieşire se face cu un obiect JspWriter, care se obţine
cu pageContext.getOut(). Metoda print a clasei JspWriter poate
genera o excepţie IOException.

Textul sursă al clasei de definiţie a comportamentului marcajului dateTag este:

1 package j s p ;
2 import j a v a x . s e r v l e t . j s p . ∗ ;
3 import j a v a x . s e r v l e t . j s p . t a g e x t . ∗ ;
4 import j a v a . i o . ∗ ;
5 import j a v a . u t i l . ∗ ;

7 public c l a s s DateTag extends TagSupport {


8 public i n t doStartTag ( ) {
9 try {
10 J s p W r i t e r out=pageContext . getOut ( ) ;
11 out . p r i n t l n (new Date ( ) ) ;
12 }
13 catch ( IOException e ) {
14 System . out . p r i n t l n ( ” DateTagException ”+e . g e t M e s s a g e ( ) ) ;
15 }
16 return SKIP BODY ;
17 }
18 }

2. Descriptorul de bibliotecă de marcaje JSP este dependent de versiunea tomcat


folosită. Acest fişier trebuie să aibă extensia tld (Taglib Language Definition).
Localizarea acestui fişier este definită ı̂n elementul taglib din web.xml. În
cazul unei distribuţii ≥ apache-tomcat-5.*, acest fişier este (mylibtag.tld):

1 <?xml version=” 1 . 0 ” e n c o d i n g=”ISO−8859−1” ?>


2 < !DOCTYPE t a g l i b
3 PUBLIC ”−//Sun Microsystems , I n c . / /DTD JSP Tag L i b r a r y 1 . 2 / /EN”
4 ” h t t p : // j a v a . sun . com/ j 2 e e / dtd /web−j s p t a g l i b r a r y 1 2 . dtd ”>

6 < !−− a t a g l i b r a r y d e s c r i p t o r −−>


7 < t a g l i b>
8 <t l i b −version> 1 . 0 </ t l i b −version>
9 <j s p −version> 1 . 2 </ j s p −version>
10 <s h o r t −name> mytags </ s h o r t −name>
180 CAPITOLUL 7. JAVA SERVER PAGE – JSP

11 <u r i>h t t p : // j a v a . apache . o r g / tomcat / m y t a g l i b</ u r i>


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

14 <t a g>
15 <name> dateTag </name>
16 <tag−c l a s s> j s p . DateTag </ tag−c l a s s>
17 <body−c o n t e n t> EMPTY </body−c o n t e n t>
18 <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>
19 </ t a g>
20 </ t a g l i b>

Pentru fiecare marcaj propriu se completează un marcaj tag. Pentru un mar-


caj propriu fără atribute elementele acestui marcaj sunt

(a) name Numele simbolic al marcajului.


(b) tag-class Referinţa la fişierul class al clasei de definiţie a comportamen-
tului marcajului propriu. Referinţa se face relativ la catalogul ...\WEB-INF\classes
(c) description Descrierea marcajului propriu.
(d) body-content În cazul nostru are valoarea EMPTY. În cazul unui marcaj
cu corp se dă valoarea JSP.

3. Marcajul taglib din fişierul web.xml

<taglib>
<taglib-uri>
http://java.apache.org/tomcat/mytaglib
</taglib-uri>
<taglib-location>
/WEB-INF/jsp/mylibtag.tld
</taglib-location>
</taglib>

Elementele marcajului taglib sunt:

(a) taglib-uri Referinţă a subcatalogului din catalogul webapps ı̂n care se


găseşte descriptorul de bibliotecă de marcaje.
(b) taglib-location Numele complet al fişierului descriptor de bibliotecă
de marcaje.

Astfel elementele constitutive se vor găsi ı̂n:

webapps
|--> mytag
| |--> WEB-INF
| | |--> classes
| | | |--> jsp
| | | | |--> DateTag.class
7.3. MARCAJE JSP PERSONALE 181

| | | web.xml
| | |--> jsp
| | | |--> mylibtag.tld
| |--> jsp
| | | dateTag.jsp

4. Marcajele proprii se utilizează cu sintaxa

<prefix : NumeMarcaj />

Referinţa la catalogul cu toate componentele necesare marcajului şi prefixul


se fixează ı̂n directiva taglib.
Un fişier jsp care utilizează marcajul realizat este (dateTag.jsp):

1 <html>
2 <head>
3 < t i t l e>
4 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
5 </ t i t l e>
6 </head>
7 <body>
8 <%@ t a g l i b u r i=” h t t p : / / j a v a . apache . o r g / tomcat / m y t a g l i b ”
9 p r e f i x=”mk” %>
10 <p>
11 Data c u r e n t a e s t e :
12 <mk : dateTag />
13 </body>
14 </html>

7.3.2 Marcaje cu atribute şi fără corp.


Realizăm un marcaj ziuaTag cu un atribut ziua care va fi afişat ı̂n momentul
prelucrării marcajului.

1. Pentru fiecare atribut clasa ce defineşte acţiunea marcajului trebuie să conţină
o metodă

public void setNumeAtribut(String value){...}

care preia valoarea atributului dată de parametrul value.

Exemplul 7.3.2

Pentru exemplul enunţat această clasă este


182 CAPITOLUL 7. JAVA SERVER PAGE – JSP

1 package j s p ;
2 import j a v a x . s e r v l e t . j s p . ∗ ;
3 import j a v a x . s e r v l e t . j s p . t a g e x t . ∗ ;
4 import j a v a . i o . ∗ ;

6 public c l a s s ZiuaTag extends TagSupport {


7 String ziua ;

9 public void s e t Z i u a ( S t r i n g v a l u e ) {
10 z i u a=v a l u e ;
11 }

13 public i n t doStartTag ( ) {
14 try {
15 J s p W r i t e r out=pageContext . getOut ( ) ;
16 out . p r i n t l n ( z i u a ) ;
17 }
18 catch ( IOException e ) {
19 System . out . p r i n t l n ( ” ZiuaTagException ”+e . g e t M e s s a g e ( ) ) ;
20 }
21 return SKIP BODY ;
22 }
23 }

2. În descriptorul bibliotecii de marcaje pentru fiecare atribut se defineşte un


marcaj <attribute>...< /attribute> având incluse marcajele
Nume marcaj Semnificaţie Fel
name numele atributului obligatoriu
required true | false după cum atributul e obligatoriu
obligatoriu sau nu
rtexprvalue true | false după cum atributul opţional
se poate utiliza ı̂ntr-o expresie
< %= numeAtribut % >
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


7.3. MARCAJE JSP PERSONALE 183

1 <html>
2 <body>
3 <form method=” g e t ”
4 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ j s p / ziuaTag . j s p ”>
5 <p>A s t a z i , e s t e
6 <s e l e c t name=” z i u a ”>
7 <option value=” l u n i ”> Luni
8 <option value=” m a r t i ”> Marti
9 <option value=” m i e r c u r i ”> M i e r c u r i
10 <option value=” j o i ”> J o i
11 <option value=” v i n e r i ”> V i n e r i
12 <option value=” simb at a ”> Simbata
13 <option value=” duminica ”> Duminica
14 </ s e l e c t>
15 <p><input type=” submit ” value=” A f i s e a z a ”>
16 </form>
17 </body>
18 </html>

unde ziuaTag.jsp este

1 <html>
2 <head>
3 < t i t l e> Tag cu marcaj </ t i t l e>
4 </head>
5 <body>
6 <%@ t a g l i b u r i=” h t t p : / / j a v a . apache . o r g / tomcat / m y t a g l i b ”
7 p r e f i x=”mk” %>
8 <p>
9 <%
10 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 ” ) ;
11 %>
12 Ziua e s t e :
13 <mk : ziuaTag z i u a=”<%= z i %>” />
14 </body>
15 </html>

7.3.3 Marcaje cu corp.


În metoda doStartTag valoarea returnată trebuie să fie EVAL BODY INCLUDE, ı̂n
loc de SKIP BODY.
În descriptorul bibliotecii de marcaje apare

<body-content> JSP </body-content>

ı̂n loc de EMPTY.


Dacă se doreşte ca marcajul să execute acţiuni după interpretarea corpului,
atunci acele activităţi sunt definite ı̂n metoda doEndTag. Această metodă re-
turnează valoarea EVAL PAGE sau SKIP PAGE după cum se doreşte sau nu continuarea
procesării paginii jsp.
184 CAPITOLUL 7. JAVA SERVER PAGE – JSP

Exemplul 7.3.3 Fie marcajul modTag care modifica un text ı̂n caractere mari sau
mici după valoarea atributului trans. Acest marcaj poate include ale elemente.

Codul clasei ce prelucrează marcajul este

1 package j s p ;
2 import j a v a x . s e r v l e t . j s p . ∗ ;
3 import j a v a x . s e r v l e t . j s p . t a g e x t . ∗ ;
4 import j a v a . i o . ∗ ;

6 public c l a s s ModTag extends TagSupport {


7 String text ;
8 boolean toUpperCase ;

10 public void s e t T e x t ( S t r i n g v a l u e ) {
11 t e x t=v a l u e ;
12 }

14 public void s e t T r a n s ( S t r i n g v a l u e ) {
15 toUpperCase=(new Boolean ( v a l u e ) ) . b o o l e a n V a l u e ( ) ;
16 }

18 public i n t doStartTag ( ) {
19 try {
20 J s p W r i t e r out=pageContext . getOut ( ) ;
21 i f ( toUpperCase )
22 out . p r i n t l n ( t e x t . toUpperCase ( ) ) ;
23 else
24 out . p r i n t l n ( t e x t . toLowerCase ( ) ) ;
25 }
26 catch ( IOException e ) {
27 System . out . p r i n t l n ( ” ModTagException ”+e . g e t M e s s a g e ( ) ) ;
28 }
29 return EVAL BODY INCLUDE ;
30 }
31 }

Descriptorul bibliotecii de marcaje se completează 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 pagină de utilizare a marcajului modTag cu un corp nevid este


7.3. MARCAJE JSP PERSONALE 185

1 <html>
2 <body>
3 <form method=” g e t ”
4 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / mytag/ j s p / modtextTag . j s p ”>
5 I n t r o d u c e o f r a z &#259;
6 <input type=” t e x t ” name=” t e x t ” s i z e=” 40 ” >
7 <p>
8 Se t r a n s f o r m &#259; &#238;n l i t e r e
9 <s e l e c t name=” t r a n s ”>
10 <option value=” upperCase ”> mari
11 <option value=” l o w e r C a s e ”> m i c i
12 </ s e l e c t>
13 <p><input type=” submit ” value=” A f i s e a z a ”>
14 </form>
15 </body>
16 </html>

ı̂mpreună cu modtextTag.jsp
1 <html>
2 <body>
3 <%@ t a g l i b u r i=” h t t p : / / j a v a . apache . o r g / tomcat / m y t a g l i b ” p r e f i x=”mk” %>
4 <%
5 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 ” ) ;
6 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 ” ) ;
7 String t ;
8 i f ( t r a n s . e q u a l s ( ” upperCase ” ) )
9 t=” t r u e ” ;
10 else
11 t=” f a l s e ” ;
12 %>
13 <p>
14 <mk : modTag text=”<%= t e x t %>” t r a n s=”<%=t%>”>
15 <mk : dateTag />
16 </mk : modTag>
17 </body>
18 </html>
186 CAPITOLUL 7. JAVA SERVER PAGE – JSP
Capitolul 8

Portlet

Prezentarea termenului de portlet se face ı̂mpreună cu cea de portal. Portalul


ca şi portletul sunt aplicaţii Web. Practic, un portal accesat afişează portlete ı̂n
ferestre distincte, portletele fiind aplicaţii pe care clientul le poate folosi (Fig. 8.1,
Fig. 8.2).

Figure 8.1: Portal - Portlet.

Această prezentare se raportează la JSR (Java Specification Request) 168. JSR


286 este următorul standard pe care trebuie să le ı̂ndeplinească un portlet.
Portalul este o aplicaţie Web cu funcţionalităţile:

• Container de portleţi. Containerul este responsabil de iniţializarea şi dis-


trugerea portleţilor, de transmiterea cererilor către portleţi şi de colectarea
răspunsurilor.

• Agregarea conţinuturilor (Content aggregator). Permite afişarea şi gestionarea


mai multor portlete.

• Asigură servicii dintre care amintim:

187
188 CAPITOLUL 8. PORTLET

Figure 8.2: Apariţia portlet-etelor ı̂ntr-o pagină a unui portal.

– acces la portal pe bază de autentificare şi autorizare. Odată autorizat,


un client are acces la orice portlet.
– posibilitatea personalizării portletelor de către clienţi.

Varietatea serviciilor variază de la un portal la altul.

Portletul este o aplicaţie Web care se aseamănă cu servletul prin:

• Se instalează ı̂ntr-un container.

• Generează conţinut dinamic.

• Ciclul de viaţă este gestionat de container.

• Interacţionează cu clientul prin modelul request/reply.

Deosebirile unui portlet faţă de un server sunt:

• Portletul posedă mai multe variante de tratare a cererilor.

• Prin conceptul de mod (mode) se specifică variante distincte prin care portle-
tul reacţionează. Sunt definite modurile VIEW, EDIT, HELP. Acţiunile core-
spunzătoare sunt definite ı̂n metodele doView, doEdit, doHelp.
8.1. APACHE-PLUTO 189

• Prin WindowState se fixează spaţiul utilizat de portlet. Valorile variabilei Win-


dowState sunt NORMAL, MAXIMIZED, MINIMIZED. În varianta MAXIMIZED
portletul ocupă ı̂ntreaga fereastră, ı̂n timp ce ı̂n varianta MINIMIZED portle-
tul apare ı̂ntr-o bară de titluri.

8.1 Apache-pluto
Pentru dezvoltarea unui portlet vom folosi produsul Apache-pluto care generează
un portal ı̂n care se pot instala / dezinstala uşor portlete.
Instalarea produsului. Dacă se descarcă varianta ı̂ncorporată ı̂n serverul Web
apache-tomcat, denumită pluto-bundle, atunci instalarea la dezarhivarea fişierului
descărcat.
Utilizarea produsului. Dintr-un navigator, portalul se apelează prin
http://host:8080/pluto/portal
Accesul se face cu User name = password = pluto.
Instalarea unui portlet se face ı̂n 2 paşi:
1. Desfăşurarea portlet-ului: Fişierul arhivat al portletului, având estensia war,
se depune ı̂n catalogul PlutoDomain. Apelând managerul lui apache-tomcat
din componenta Pluto admin se obţine instalarea portletului.
Alternativ, desfăşurarea portlet-lui se va obţine cu apache-ant cu utilizarea
unui fişier build.xml dedicat.
2. Publicarea portlet-ului se face prin componenta Pluto admin.

8.2 Portlet container JSR 286


portlet-container-configurator(.jar) instalează un container de portlete ı̂n apache-
tomcat-5.5.* / glassfish v2, container care suportă portlete potrivit specificaţiei JSR
286. Containerului ı̂i este ataşat un portal simplu.
Instalarea containerului de portlete JSR 286. Presupunem că serverul
Web apache-tomcat-5.5.* este instalat ı̂mpreună cu componenta manager. Con-
tainerul de portlete se instalează prin
java -jar portlet-container-configurator.jar
În interfaţa grafică, se fixează serverul Web (Glassfish / Tomcat), locaţia apache-ant
(Ant-Home) şi locaţia serverului Web Select Install Directory).
Utilizarea portalului. Portalul se apelează prin
http://host:port/portletdriver
Prin administratorul portalului (Admin) se pot ı̂ncărca / sterge portlete. Acestea
sunt vizibile pe pagina Portlets.
190 CAPITOLUL 8. PORTLET

8.3 Dezvoltarea unui portlet


Compilarea şi arhivarea unui portlet ı̂n vederea desfăşurării se va face rulând ant
cu fişierul build.xml:
1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 <p r o j e c t name=” p o r t l e t −b u i l d ” default=” b u i l d ” b a s e d i r=” . ”>

4 <p r o p e r t y environment=” env ” />


5 < !−−
6 S e t CATALINA HOME or u s e −D p l u t o . home=/p a t h / t o / tomcat−w i t h −p l u t o
7 on command l i n e
8 −−>
9 <p r o p e r t y name=” p l u t o . home” v a l u e=” ${ env .CATALINA HOME} ” />
10 <p r o p e r t y f i l e =” b u i l d . p r o p e r t i e s ” />

12 < !−−
13 A l l j a r s used by your p o r t l e t need t o be i n l i b i n a d d i t i o n t o t h e
14 p l u t o −ant−t a s k s j a r
15 −−>
16 <path i d=” p r o j e c t . c l a s s p a t h ”>
17 < f i l e s e t d i r=” l i b ”>
18 <i n c l u d e name=” ∗ . j a r ” />
19 </ f i l e s e t>
20 </ path>

22 <t a s k d e f
23 name=” a s s e m b l e ”
24 c l a s s n a m e=” o r g . apache . p l u t o . ant . AssembleTask ”
25 c l a s s p a t h r e f=” p r o j e c t . c l a s s p a t h ”
26 />

28 <t a r g e t name=” a s s e m b l e ”>


29 <a s s e m b l e
30 webxml=” ${web−i n f . d i r }/web . xml”
31 p o r t l e t x m l=” ${web−i n f . d i r }/ p o r t l e t . xml”
32 d e s t f i l e =” ${ b u i l d . d i r }/web . xml”
33 />
34 </ t a r g e t>

36 <t a r g e t name=” i n i t ” d e s c r i p t i o n=” C r e a t e s b u i l d d i r s ”>


37 <echo message=”Ant v e r s i o n = ${ ant . v e r s i o n } ” />
38 <mkdir d e s c r i p t i o n=” C r e a t e s b u i l d d i r e c t o r y i f needed ”
39 d i r=” ${ b u i l d . d i r } ” />
40 <mkdir d e s c r i p t i o n=” C r e a t e s war d i r e c t o r y i f needed ”
41 d i r=” ${ w e b b u i l d . d i r } ” />
42 <mkdir d e s c r i p t i o n=” C r e a t e s WEB−INF d i r e c t o r y i f needed ”
43 d i r=” ${ w e b b u i l d . d i r }/WEB−INF” />
44 <mkdir d e s c r i p t i o n=” C r e a t e s WEB−INF/ c l a s s e s d i r e c t o r y i f needed ”
45 d i r=” ${ c l a s s b u i l d . d i r } ” />
46 <mkdir d e s c r i p t i o n=” C r e a t e s WEB−INF/ l i b d i r e c t o r y i f needed ”
47 d i r=” ${ w e b b u i l d . d i r }/WEB−INF/ l i b ” />
48 </ t a r g e t>

50 <t a r g e t name=” c o m p i l e ” depends=” i n i t ” d e s c r i p t i o n=” Compiles s o u r c e ”>


51 <j a v a c c l a s s p a t h r e f=” p r o j e c t . c l a s s p a t h ”
52 f o r k=” y e s ”
53 debug=” t r u e ”
54 d e b u g l e v e l=” l i n e s , v a r s , s o u r c e ”
8.3. DEZVOLTAREA UNUI PORTLET 191

55 d e s t d i r=” ${ c l a s s b u i l d . d i r } ”
56 s r c d i r=” ${ j a v a . s r c . d i r } ” />
57 </ t a r g e t>

59 <t a r g e t name=” war ” depends=” c o m p i l e ”>


60 < !−− Move web f i l e s e x c l u d i n g web . xml −−>
61 <copy t o d i r=” ${ w e b b u i l d . d i r }/ ”>
62 < f i l e s e t d i r=” ${web . d i r } ” e x c l u d e s=” ∗∗/ web . xml” />
63 </ copy>

65 < !−− Move o t h e r n e c c e s s a r y l i b r a r i e s −−>


66 <copy t o d i r=” ${ w e b b u i l d . d i r }/WEB−INF/ l i b / ”>
67 < f i l e s e t d i r=” ${ l i b . d i r } ”>
68 <i n c l u d e name=” ∗ ∗ / ∗ . j a r ” />
69 <e x c l u d e name=” c a s t o r ∗ . j a r ” />
70 <e x c l u d e name=” p l u t o ∗ . j a r ” />
71 <e x c l u d e name=” p o r t l e t ∗ . j a r ” />
72 <e x c l u d e name=” s e r v l e t ∗ . j a r ” />
73 <e x c l u d e name=” j u n i t ∗ . j a r ” />
74 </ f i l e s e t>
75 </ copy>

77 < a n t c a l l t a r g e t=” a s s e m b l e ” />

79 < !−− C r e a t e war i n de p l oy m e n t d i r e c t o r y −−>


80 <war b a s e d i r=” ${ w e b b u i l d . d i r } ” update=” f a l s e ”
81 w a r f i l e=” ${ app . name } . war ”
82 webxml=” ${ b u i l d . d i r }/web . xml” />
83 </ t a r g e t>

85 <t a r g e t name=” b u i l d ” depends=” c l e a n , war ” />

87 <t a r g e t name=” d e p l o y ” depends=” b u i l d ”>


88 <echo message=” D e p l o y i n g t o p l u t o . home=${ p l u t o . home} ” />
89 < !−−
90 Remove former d ep l o y me n t b e c a u s e sometimes
91 tomcat d o e s n o t f u l l y r e d e p l o y a war
92 −−>
93 <d e l e t e
94 d i r=” ${ p l u t o . home}/ webapps /${ app . name} ”
95 f a i l o n e r r o r=” t r u e ”
96 />
97 < !−− Deploy war f i l e −−>
98 <copy
99 f i l e =” ${ app . name } . war ”
100 t o d i r=” ${ p l u t o . home}/ PlutoDomain ”
101 o v e r w r i t e=” t r u e ”
102 />
103 < !−− Deploy c o n t e x t d ep l o ym e n t d e s c r i p t o r f o r Tomcat −−>
104 <copy
105 f i l e =” ${ c o n f . d i r }/${ app . name } . xml”
106 t o d i r=” ${ p l u t o . home}/ c o n f / C a t a l i n a / l o c a l h o s t ”
107 o v e r w r i t e=” f a l s e ”
108 />

110 </ t a r g e t>

112 <t a r g e t name=” c l e a n ” d e s c r i p t i o n=” C l e a n s b u i l d ”>


113 <d e l e t e d i r=” ${ b u i l d . d i r } ” f a i l o n e r r o r=” f a l s e ” />
192 CAPITOLUL 8. PORTLET

114 </ t a r g e t>

116 </ p r o j e c t>

Fişierul de proprietăţi build.properties este


1 #b u i l d . p r o p e r t i e s
2 #Standard p r o p e r t i e s f o r Ant b u i l d o f a P l u t o 1 . 1 p o r t l e t

4 #module name
5 app . name=NumePortlet

7 #D i r e c t o r y t h a t h o l d s s o u r c e code
8 s r c . d i r = s r c / main
9 j a v a . s r c . d i r = ${ s r c . d i r }/ j a v a

11 #D i r e c t o r y t h a t h o l d s documentation
12 doc . d i r = d o c s

14 #D i r e c t o r y t h a t h o l d s f i l e s t o be b u i l t i n t o a j a r , war o r e a r
15 build . dir = build
16 w e b b u i l d . d i r = ${ b u i l d . d i r }/ webapp
17 c l a s s b u i l d . d i r = ${ w e b b u i l d . d i r }/WEB−INF/ c l a s s e s

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

22 #D i r e c t o r y t h a t h o l d s l i b r a r i e s r e q u i r e d t o b u i l d and run t h e c l a s s e s
23 lib . dir = lib

25 #D i r e c t o r y t h a t h o l d s webapp f i l e s
26 web . d i r = ${ s r c . d i r }/ webapp

28 #WEB−INF d i r e c t o r y
29 web−i n f . d i r = ${web . d i r }/WEB−INF

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

Pentru utilizarea acestui build.xml este nevoie de structura următoare de cat-


aloage

NumePortlet
|--> lib
| | castor-1.1.1.jar
| | commons-logging-*.jar
| | pluto-ant-tasks-*.jar
| | pluto-descriptor-api-*-dev.jar
| | pluto-descriptor-impl-*-dev.jar
| | pluto-util-*-dev.jar
| | portlet-api-*.jar
| | servlet-api-*.jar
|--> src
8.4. ELEMENTE DE PROGRAMARE 193

| |--> main
| | |--> java
| | | |--> pachetul portletului
| | |--> resource
| | | | NumePortlet.xml
| | |--> webapp
| | | |--> jsp
| | | | | fisierele jsp ale portletului
| | | |--> WEB-INF
| | | | | portlet.xml
| | | | | web.xml
Fişierele castor.1.1.1.jar, pluto-descriptor-api-*.jar, pluto-descriptor-impl-*.jar, portlet-
api.jar se copiază din catalogul PLUTO HOME\shared\lib, iar fişierul servlet-api-
*.jar se ia din PLUTO HOME\common\lib.
Fişierul web.xml de mai sus este

2 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>

4 <web−app xmlns=” h t t p : // j a v a . sun . com/xml/ ns / j 2 e e ”


5 x m l n s : x s i=” h t t p : //www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
6 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
7 h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /web−a p p 2 4 . xsd ”
8 version=” 2 . 4 ”>

10 </web−app>

Conţinutul final al acestui fişier rezultă ı̂n urma obiectivului ant assemple, ı̂n
care se preiau date din fişierul de configurare al portletului portlet.xml. Editarea
fişierului portlet.xml este sarcina programatorului.
Fişierul NumePortlet.xml este utilizat la desfăşurarea aplicaţie, fiind copiat ı̂n
catalogul conf\Catalina\localhost al lui apache-tomcat sau Apache-pluto. Acest
fişier are conţinutul:
1 <Context path=” NumePortlet ” docBase=” . . \ PlutoDomain \ NumePortlet . war ”
2 c r o s s C o n t e x t=” t r u e ” />

8.4 Elemente de programare


Orice portlet implementează interfaţa Portlet. Interfaţa Portlet declară 4
metode
public interface Portlet{
public void init(PortletConfig config) throws PortletException;

public void processAction(ActionRequest request, ActionResponse


194 CAPITOLUL 8. PORTLET

response) throws PortletException, java.io.IOException;

public void render(RenderRequest request, RenderResponse


response) throws PortletException, java.io.IOException;

public void destroy();


}
Metoda processAction prelucrează cererea emisă de containerul de portlete. La
solicitarea containerului, metoda render regenerează conţinutul unui portlet.
Clasa GenericPortlet este implementarea iniţială a interfeţei Portlet. Ex-
tinzând clasa GenericPortlet, sarcina programatorului este să suprascrie metodele
• doView pentru tratarea modului VIEW;
protected void doView(RenderRequest req,RenderResponse res)
throws PortletException, IOException

• doEdit pentru tratarea modului EDIT;


protected void doEdit(RenderRequest req,RenderResponse res)
throws PortletException, IOException

• doHelp pentru tratarea modului HELP;


protected void doHelp(RenderRequest req,RenderResponse res)
throws PortletException, IOException

• init, destroy pentru iniţializarea, respectiv oprirea portletului.


void init() throws PortletException
void init(PortletConfig config) throws PortletException
void destroy()
şi eventual, să definească conţinutul metodei
public void processAction(ActionRequest request,ActionResponse response)
throws PortletException, java.io.IOException;

Exemplul 8.4.1 Portletul HelloWorld.

1 package h e l l o ;
2 import j a v a . i o . ∗ ;
3 import j a v a x . p o r t l e t . ∗ ;

5 public c l a s s H e l l o W o r l d P o r t l e t extends G e n e r i c P o r t l e t {
6 protected void doView ( RenderRequest r e q u e s t , RenderResponse r e s p o n s e )
7 throws P o r t l e t E x c e p t i o n , IOException {
8 r e s p o n s e . setContentType ( ” t e x t / html ” ) ;
9 r e s p o n s e . g e t W r i t e r ( ) . p r i n t l n ( ” H e l l o World ! ” ) ;
8.4. ELEMENTE DE PROGRAMARE 195

10 }

12 // A l t a v a r i a n t a de programare
13 /∗
14 p u b l i c v o i d doView ( RenderRequest req , RenderResponse r e s )
15 t h r o w s P o r t l e t E x c e p t i o n , IOException {
16 r e s . s e t C o n t e n t T y p e (” t e x t / html ” ) ;
17 P r i n t W r i t e r o u t=r e s . g e t W r i t e r ( ) ;
18 o u t . p r i n t l n (”<h2 >”);
19 o u t . p r i n t l n (” H e l l o World ! ” ) ;
20 o u t . p r i n t l n (”</h2 >”);
21 }
22 ∗/
23 }

Fişierul portlet.xml este


1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 <p o r t l e t −app xmlns=” h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd ”
3 x m l n s : x s i=” h t t p : //www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
4 x s i : s c h e m a L o c a t i o n=” h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd
5 h t t p : // j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd ”
6 i d=” myPortletApp ” version=” 2 . 0 ”>

8 < p o r t l e t>
9 <d e s c r i p t i o n>H e l l o World a s a p o r t l e t app</ d e s c r i p t i o n>
10 <p o r t l e t −name>H e l l o W o r l d 1 P o r t l e t</ p o r t l e t −name>
11 <d i s p l a y −name>H e l l o World P o r t l e t</ d i s p l a y −name>
12 <p o r t l e t −c l a s s> h e l l o . H e l l o W o r l d 1 P o r t l e t</ p o r t l e t −c l a s s>
13 <s u p p o r t s>
14 <mime−t y p e>t e x t / html</mime−t y p e>
15 <p o r t l e t −mode>VIEW</ p o r t l e t −mode>
16 </ s u p p o r t s>
17 <p o r t l e t −i n f o>
18 < t i t l e>H e l l o World P o r t l e t</ t i t l e>
19 </ p o r t l e t −i n f o>
20 </ p o r t l e t>
21 </ p o r t l e t −app>

Exemplul 8.4.2 Evidenţierea modurilor VIEW, EDIT şi HELP.

1 package h e l l o p l u t o ;
2 import j a v a . i o . ∗ ;
3 import j a v a x . p o r t l e t . ∗ ;

5 public c l a s s H e l l o P l u t o P o r t l e t extends G e n e r i c P o r t l e t {
6 public void doView ( RenderRequest req , RenderResponse r e s )
7 throws P o r t l e t E x c e p t i o n , IOException {
8 r e s . setContentType ( ” t e x t / html ” ) ;
9 W r i t e r out=r e s . g e t W r i t e r ( ) ;
10 out . w r i t e ( ”<s t r o n g >H e l l o P l u t o i n view mode</s t r o n g >” ) ;
11 }

13 public void doEdit ( RenderRequest req , RenderResponse r e s )


14 throws P o r t l e t E x c e p t i o n , IOException {
15 r e s . setContentType ( ” t e x t / html ” ) ;
16 W r i t e r out=r e s . g e t W r i t e r ( ) ;
196 CAPITOLUL 8. PORTLET

17 out . w r i t e ( ”<i >H e l l o P l u t o i n e d i t mode</i >” ) ;


18 }

20 public void doHelp ( RenderRequest req , RenderResponse r e s )


21 throws P o r t l e t E x c e p t i o n , IOException {
22 r e s . setContentType ( ” t e x t / html ” ) ;
23 W r i t e r out=r e s . g e t W r i t e r ( ) ;
24 out . w r i t e ( ”<u>H e l l o P l u t o i n h e l p mode</u>” ) ;
25 }
26 }

Fişierul portlet.xml este


1 <?xml v e r s i o n=” 1 . 0 ” e n c o d i n g=”UTF−8”?>
2 <p o r t l e t −app xmlns=” h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd ”
3 xmlns : x s i=” h t t p : / /www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
4 x s i : s c h e m a L o c a t i o n=” h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd
5 h t t p : / / j a v a . sun . com/xml/ ns / p o r t l e t / p o r t l e t −a p p 2 0 . xsd ”
6 i d=” myPortletApp ” v e r s i o n=” 2 . 0 ”>

8 <p o r t l e t >
9 <d e s c r i p t i o n >H e l l o P l u t o a s a p o r t l e t app</ d e s c r i p t i o n >
10 <p o r t l e t −name>H e l l o P l u t o P o r t l e t </ p o r t l e t −name>
11 <d i s p l a y −name>H e l l o Pluto </ d i s p l a y −name>
12 <p o r t l e t −c l a s s >h e l l o p l u t o . H e l l o P l u t o P o r t l e t </ p o r t l e t −c l a s s >
13 <s u p p o r t s >
14 <mime−type>t e x t / html</mime−type>
15 <p o r t l e t −mode>VIEW</ p o r t l e t −mode>
16 <p o r t l e t −mode>EDIT</ p o r t l e t −mode>
17 <p o r t l e t −mode>HELP</ p o r t l e t −mode>
18 </s u p p o r t s >
19 <p o r t l e t −i n f o >
20 < t i t l e >H e l l o P l u t o P o r t l e t </ t i t l e >
21 </ p o r t l e t −i n f o >
22 </ p o r t l e t >
23 </ p o r t l e t −app>

Exemplul 8.4.3 Portletul Hello. Portletul afişează o zonă text de introducere a


unui nume şi un buton. Odată introdus numele, la apăsarea butonului se afişaeză
textul Hello nume şi un buton de reluare.

1 package h e l l o n a m e ;

3 import j a v a . i o . ∗ ;
4 import j a v a x . p o r t l e t . ∗ ;
5 import j a v a . u t i l . Enumeration ;

7 public c l a s s H e l l o N a m e P o r t l e t extends G e n e r i c P o r t l e t {

9 public void doView ( RenderRequest req , RenderResponse r e s )


10 throws P o r t l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 S t r i n g nume=( S t r i n g ) r e q . g e t P a r a m e t e r ( ”name” ) ;
13 P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ;
14 i f ( nume==n u l l ) {
15 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p / i n p u t . j s p ” ) ;
8.4. ELEMENTE DE PROGRAMARE 197

16 prd . i n c l u d e ( req , r e s ) ;
17 }
18 else {
19 // V a r i a n t a cu a f i s a r e p r i n View
20 /∗
21 Writer o u t=r e s . g e t W r i t e r ( ) ;
22 o u t . w r i t e (” H e l l o ”+ nume ) ;
23 PortletURL renderURL=r e s . createRenderURL ( ) ;
24 renderURL . s e t P o r t l e t M o d e ( P o r t l e t M o d e .VIEW) ;
25 renderURL . setWindowState ( WindowState .NORMAL) ;
26 o u t . w r i t e (”<p><a h r e f =\””+renderURL . t o S t r i n g ()+”\”> R e l u a r e </a >”);
27 ∗/
28 // V a r i a n t a cu a f i s a r e p r i n t r −un f i s i e r j s p
29 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p / ou tp ut . j s p ” ) ;
30 prd . i n c l u d e ( req , r e s ) ;
31 }
32 }

34 public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s )


35 throws IOException , P o r t l e t E x c e p t i o n {
36 // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a
37 Enumeration params=r e q . getParameterNames ( ) ;
38 while ( params . hasMoreElements ( ) ) {
39 S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ;
40 S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ;
41 r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ;
42 }
43 }
44 }

Fişierele input.jsp şi putput.jsp au codurile


1 <%@ t a g l i b u r i=” h t t p : / / j a v a . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>
2 < p o r t l e t : d e f i n e O b j e c t s />
3 <div a l i g n=” c e n t e r ”>
4 I n t r o d u c e &#355; i numele :
5 <br/>
6 <form action=”< p o r t l e t : actionURL />”
7 method=”POST”>
8 <br>
9 <input type=” t e x t ” name=”name” />
10 <br>
11 <input type=” submit ” name=” submitButton ” value=”Apasa−ma” />
12 </form>
13 </ div>

şi respectiv
1 <%@ t a g l i b u r i=” h t t p : // j a v a . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>
2 < p o r t l e t : d e f i n e O b j e c t s />
3 <p>
4 <%
5 S t r i n g r e s u l t=” H e l l o ”+r e n d e r R e q u e s t . g e t P a r a m e t e r ( ”name”)+” ! ” ;
6 out . p r i n t l n ( r e s u l t ) ;
7 %>
8 <p><a h r e f=”<p o r t l e t : r e n d e r U R L p o r t l e t M o d e=” view ” windowState=” normal ” />”>
9 Reluare
10 </ a> .
198 CAPITOLUL 8. PORTLET

Exemplul 8.4.4 Cel mai mare divizor comun a două numere naturale ı̂ntr-un port-
let.

Variantă ı̂n care calculul este programat ı̂n portlet.


1 package cmmdc ;

3 import j a v a . i o . ∗ ;
4 import j a v a x . p o r t l e t . ∗ ;
5 import j a v a . u t i l . Enumeration ;

7 public c l a s s CmmdcPortlet extends G e n e r i c P o r t l e t {

9 public void doView ( RenderRequest req , RenderResponse r e s )


10 throws P o r t l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ;
13 S t r i n g r e z=r e q . g e t P a r a m e t e r ( ” r e z ” ) ;
14 i f ( r e z==n u l l ) {
15 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p / i n p u t . j s p ” ) ;
16 prd . i n c l u d e ( req , r e s ) ;
17 }
18 else {
19 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p / ou tp ut . j s p ” ) ;
20 prd . i n c l u d e ( req , r e s ) ;
21 }
22 }

24 public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s )


25 throws IOException , P o r t l e t E x c e p t i o n {
26 // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a
27 S t r i n g sm=r e q . g e t P a r a m e t e r ( ”m” ) ;
28 S t r i n g sn=r e q . g e t P a r a m e t e r ( ”n” ) ;
29 long m=Long . parseLon g ( sm ) ;
30 long n=Long . parseLong ( sn ) ;
31 long c=cmmdc(m, n ) ;
32 r e s . s e t R e n d e r P a r a m e t e r ( ” r e z ” , (new Long ( c ) ) . t o S t r i n g ( ) ) ;
33 }

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

37 }

Fişierele inputCmmdc.jsp şi outputCmmdc.jsp au codurile


1 <%@ t a g l i b u r i=” h t t p : / / j a v a . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>
2 < p o r t l e t : d e f i n e O b j e c t s />
3 <div a l i g n=” c e n t e r ”>
4 <form action=”< p o r t l e t : actionURL />”
5 method=”POST”>
6 <table border=” 1 ” >
7 <tr>
8 <td> Primul num&#259; r </td>
9 <td> <input type=” t e x t ” name=”m” /> </td>
10 </ tr>
11 <tr>
12 <td> Al d o i l e a num&#259; r </td>
13 <td> <input type=” t e x t ” name=”n” /> </td>
14 </ tr>
8.4. ELEMENTE DE PROGRAMARE 199

15 <tr>
16 <td>
17 <input type=” submit ” name=” submitButton ” value=” C a l c u l e a z a ” />
18 </td>
19 </ tr>
20 </ table>
21 </form>

23 </ div>

şi respectiv
1 <%@ t a g l i b u r i=” h t t p : / / j a v a . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>
2 < p o r t l e t : d e f i n e O b j e c t s />

4 <P>
5 <%
6 String r e s u l t=”Cmmdc ”+r e n d e r R e q u e s t . g e t P a r a m e t e r ( ” r e z ”)+” ! ” ;
7 out . p r i n t l n ( r e s u l t ) ;
8 %>

10 <P>
11 <a href=”< p o r t l e t : renderURL p o r t l e t M o d e=” view ” windowState=” normal ” />”>
12 Reluare
13 </a>

Variantă ı̂n care calculul este programat ı̂ntr-o componentă Java (bean)
şi care este apelat ı̂n pagina jsp de afişare a rezultatului.
1 package cmmdc ;

3 import j a v a . i o . ∗ ;
4 import j a v a x . p o r t l e t . ∗ ;
5 import j a v a . u t i l . Enumeration ;

7 public c l a s s CmmdcPortlet extends G e n e r i c P o r t l e t {

9 public void doView ( RenderRequest req , RenderResponse r e s )


10 throws P o r t l e t E x c e p t i o n , IOException {
11 r e s . setContentType ( ” t e x t / html ” ) ;
12 P o r t l e t R e q u e s t D i s p a t c h e r prd=n u l l ;
13 S t r i n g sb=r e q . g e t P a r a m e t e r ( ” submitButton ” ) ;
14 i f ( sb==n u l l ) {
15 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p /inputCmmdc . j s p ” ) ;
16 prd . i n c l u d e ( req , r e s ) ;
17 }
18 else {
19 prd=g e t P o r t l e t C o n t e x t ( ) . g e t R e q u e s t D i s p a t c h e r ( ” / j s p /outputCmmdc . j s p ” ) ;
20 prd . i n c l u d e ( req , r e s ) ;
21 }
22 }

24 public void p r o c e s s A c t i o n ( A c t i o n R e q u e s t req , A c t i o n R e s p o n s e r e s )


25 throws IOException , P o r t l e t E x c e p t i o n {
26 // P r e i a p a r a m e t r i i s i l e t r i m i t e c e l u i c a r e a emis c e r e r e a
27 Enumeration params=r e q . getParameterNames ( ) ;
28 while ( params . hasMoreElements ( ) ) {
29 S t r i n g parameterName = ( S t r i n g ) params . nextElement ( ) ;
30 S t r i n g p a r a m e t e r V a l u e=r e q . g e t P a r a m e t e r ( parameterName ) ;
200 CAPITOLUL 8. PORTLET

31 System . out . p r i n t l n ( ” >> parameterName = ” + parameterName +


32 ” <=> p a r a m e t e r V a l u e = ” + p a r a m e t e r V a l u e ) ;
33 r e s . s e t R e n d e r P a r a m e t e r ( parameterName , p a r a m e t e r V a l u e ) ;
34 }
35 }
36 }

Codul componentei Java


1 public c l a s s CmmdcBean{

3 private S t r i n g m=” ” ;
4 private S t r i n g n=” ” ;

6 public void setM ( S t r i n g m) {


7 t h i s .m=m;
8 }
9 public void setN ( S t r i n g n ) {
10 t h i s . n=n ;
11 }
12 public S t r i n g getM ( ) {
13 return m;
14 }
15 public S t r i n g getN ( ) {
16 return n ;
17 }
18 public S t r i n g cmmdc ( ) {
19 long m0=Long . parseL ong (m) ;
20 long n0=Long . parse Lo ng ( n ) ;
21 long c , r ;
22 do{
23 c=n0 ;
24 r=m0%n0 ;
25 m0=n0 ;
26 n0=r ;
27 }
28 while ( r ! = 0 ) ;
29 return (new Long ( c ) ) . t o S t r i n g ( ) ;
30 }
31 }

Pagina outputCmmdc.jsp
1 <%@ t a g l i b u r i=” h t t p : / / j a v a . sun . com/ p o r t l e t ” p r e f i x=” p o r t l e t ” %>
2 <j s p : useBean id=”myCmmdcBean” c l a s s=”cmmdc . CmmdcBean” scope=” s e s s i o n ” />
3 <j s p : s e t P r o p e r t y name=”myCmmdcBean” p r o p e r t y=” ∗ ” />

5 < p o r t l e t : d e f i n e O b j e c t s />

7 <P>
8 <%
9 String r e s u l t=”Cmmdc ”+myCmmdcBean . cmmdc ( ) ;
10 out . p r i n t l n ( r e s u l t ) ;
11 %>
12 <P>
13 <a href=”< p o r t l e t : renderURL p o r t l e t M o d e=” view ” windowState=” normal ” />”>
14 Reluare
15 </a>
8.4. ELEMENTE DE PROGRAMARE 201

Variantă ı̂n care care calculul este programat ı̂ntr-un servlet. Servletul
utilizat este cel prezentat ı̂n capitolul Servlet, (6.3.2), dar inclus ı̂n pachetul portlet-
ului. Fişierul inputCmmdc.jsp are ı̂n plus linia
<input type="hidden" name="tip" value="text/html"/>

iar ı̂n codul clasei CmmdcPortlet, ı̂n locul liniei


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

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

adică ı̂n locul invocării paginii JSP, dispecerul apelează servletul. În servlet este
esenţială furnizarea rezultatului ı̂n format html. Pagina html generată se ı̂ncarcă ı̂n
fereastra portlet-ului.
Fişierul web.xml, ı̂naintea completării prin ant, este
1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>

3 <web−app xmlns=” h t t p : // j a v a . sun . com/xml/ ns / j 2 e e ”


4 x m l n s : x s i=” h t t p : //www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
5 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
6 h t t p : // j a v a . sun . com/xml/ ns / j 2 e e /web−a p p 2 4 . xsd ”
7 version=” 2 . 4 ”>

9 < s e r v l e t>
10 <s e r v l e t −name>CmmdcServlet</ s e r v l e t −name>
11 <s e r v l e t −c l a s s>cmmdc . CmmdcServlet</ s e r v l e t −c l a s s>
12 </ s e r v l e t>

14 <s e r v l e t −mapping>
15 <s e r v l e t −name>CmmdcServlet</ s e r v l e t −name>
16 <u r l −p a t t e r n>/cmmdc</ u r l −p a t t e r n>
17 </ s e r v l e t −mapping>
18 </web−app>

Interfaţa PortletPreferences
Atribute, adică perechi de tip String (nume,valoare) definite ı̂n fişierul portlet.xml
prin

<portlet-preferences>
<preference>
<name>nume_atribut</name>
<value>valoare_atribut</value>
<read-only>true|false</read-only>
</preference>
. . .
</portlet-preferences>
202 CAPITOLUL 8. PORTLET

Atributele se transmit metodelor doView, doEdit şi doHelp. Suportul este


oferit prin interfaţa PortletPreferences.

Metode

• String getValue(String key, String def )


Returnează valoarea primului atribut având numele key. În lipsa atributului
sau a valurii returnează valoarea def.

• String[] getValues(String key, String[] def )


Returnează toate valorile atributului key.

• Enumeration<String> getNames()
Suport pentru acces la numele atributelor care au valoare.

• Map<String,String[]> getMap()
Suport pentru acces la atribute.

Un obiect care implementează interfaţa PortletPreferences se obţine prin


metoda getPreferences() a clasei RenderRequest.

Exemplul 8.4.5 Portlet ı̂n care se preiau şi se afişează valori ale atributelor.

Codul portletului este


1 package p r e f ;

3 import j a v a . i o . ∗ ;
4 import j a v a x . p o r t l e t . ∗ ;

6 public c l a s s P r e f P o r t l e t extends G e n e r i c P o r t l e t {

8 public void doView ( RenderRequest req , RenderResponse r e s )


9 throws P o r t l e t E x c e p t i o n , IOException {
10 P o r t l e t P r e f e r e n c e s p r e f s = req . g e tP r e f e re n c e s ( ) ;
11 S t r i n g a t t r 1 = p r e f s . g e t V a l u e ( ”ATTR1” , ” a t t r 1 ” ) ;
12 S t r i n g a t t r 2 = p r e f s . g e t V a l u e ( ”ATTR2” , ” a t t r 2 ” ) ;
13 r e s . setContentType ( ” t e x t / html ” ) ;
14 W r i t e r out=r e s . g e t W r i t e r ( ) ;
15 out . w r i t e ( ”<s t r o n g >”+a t t r 1+” <−−> ”+a t t r 2+”</s t r o n g >” ) ;
16 }
17 }

iar atributele din fişierul portlet.xml sunt


<portlet-preferences>
<preference>
<name>ATTR1</name>
<value>Programare distribuita</value>
<read-only>true</read-only>
</preference>
<preference>
8.5. PRODUSE PORTAL 203

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

Al doilea atribut nu are valoare.Portletul afişează textul Programare distribuita <–>


attr2.

8.5 Produse Portal


Termenul portal va desemna

• aplicaţia informatică prin care o instituţie comunică cu lumea exterioară

• produsul informatic care realizează aplicaţia amintită la pct. anterior

În cele ce urmează ne vom referi doar la produse portal care sunt containere de
portlete.
Dezvoltarea unui portal al unei organizaţii se face pe produse specializate acestui
scop. Dintre asemenea produsele gratuite amintim:

• uPortal;

• jetspeed-2;

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

8.5.1 uPortal
uPortal este un portal cadru, dezvoltat de JA-SIG (Java Architecture Special
Interest Group) şi a fost utilizat de mai multe universităţi ca suport ı̂n construcţia
portalului specific.
Instalarea produsului. Distribuţia produsului se face ı̂n două variante

• uPortal-*.*.* - uPortal-only;

• uPortal-*.*.*-quick-start care ı̂nglobează toate resursele necesare funcţionării


(apache-ant, apache-tomcat, apache-maven, HypersonicSQLDB).

În cele ce urmează utilizăm varianta uPortal-quick-start. Instalarea produsului


revine la dezarhivarea fişierului descărcat.
204 CAPITOLUL 8. PORTLET

Lansarea portalului. În urma dezarhivării, ı̂n catalogul uPortal HOME se


găseşte un fişier build.xml, ale cărei obiective asigură lansarea portalului1 .
Se completează fişierul ant.bat cu referinţa set JAVA HOME=...
Lansarea portalului constă ı̂n executarea comenzii

ant start

De fapt se porneşte SGBD HypersonicSQLDB şi serverul Web apache-tomcat.


Oprirea portalului se face prin executarea comenzii

ant stop

Dintr-un navigator, portalul se accesează prin

http://host:8080/uPortal

Accesarea portalului se poate face doar de deţinătorii unui cont (UserName,


Password). Administratorul (UserName=Password=admin) poate crea conturi noi.
Instalarea unui portlet constă ı̂n desfăşurarea şi publicarea lui.
Compilarea şi arhivarea portletului se poate face cu apache-ant În acest scop se
crează structura
|--> lib
| | portlet-api-1.0.jar
|--> pachetul portlet-ului
| |--> jsp
| | | *.jsp
| |--> WEB-INF
| | |--> classes
| | | | *.java
| | | web.xml
| | | portlet.xml
| build.xml

cu fişierele *.java, *.jsp şi portlet.xml corespunzătoare portletului iar web.xml este
generic
1 <?xml version=” 1 . 0 ” e n c o d i n g=”ISO−8859−1” ?>
2 < !DOCTYPE web−app PUBLIC
3 ”−//Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN”
4 ” h t t p : // j a v a . sun . com/ dtd /web−a p p 2 3 . dtd ”>
5 <web−app>
6 </web−app>

Fişierul build.xml, compilare şi arhivare este


1 <p r o j e c t name=” p o r t l e t −b u i l d ” default=” war ” b a s e d i r=” . ”>

3 <p r o p e r t y name=” package ” v a l u e=” h e l l o ” />


4 <p r o p e r t y name=” p o r t l e t . name” v a l u e=” H e l l o N a m e P o r t l e t ” />

1
La prima executare a unei operaţii asupra portalului, calculatorul trebuie să fie conectat la
internet, deoarece mai multe resurse sunt descărcate prin apache-maven. Aceste resurse se depun
ı̂n c:\Documents and Settings\adminName\.m2\repository.
8.5. PRODUSE PORTAL 205

5 <p r o p e r t y name=” b u i l d . d i r ” v a l u e=” b u i l d ” />

7 <path i d=” p r o j e c t . c l a s s p a t h ”>


8 < f i l e s e t d i r=” l i b ”>
9 <i n c l u d e name=” ∗ . j a r ” />
10 </ f i l e s e t>
11 </ path>

13 <t a r g e t name=” i n i t ” >


14 <d e l e t e d i r=” ${ package }/${ b u i l d . d i r } ” />
15 <mkdir d i r=” ${ package }/${ b u i l d . d i r } ” />
16 <mkdir d i r=” ${ package }/${ b u i l d . d i r }/ j s p ” />
17 <mkdir d i r=” ${ package }/${ b u i l d . d i r }/WEB−INF” />
18 <mkdir d i r=” ${ package }/${ b u i l d . d i r }/WEB−INF/ c l a s s e s ” />
19 </ t a r g e t>

21 <t a r g e t name=” c o m p i l e ” depends=” i n i t ” d e s c r i p t i o n=” Compiles s o u r c e ”>


22 <j a v a c c l a s s p a t h r e f=” p r o j e c t . c l a s s p a t h ”
23 d e s t d i r=” ${ package }/${ b u i l d . d i r }/WEB−INF/ c l a s s e s ”
24 s r c d i r=” ${ package }/WEB−INF/ c l a s s e s ” />
25 </ t a r g e t>

27 <t a r g e t name=” war ” depends=” c o m p i l e ”>


28 <copy t o d i r=” ${ package }/${ b u i l d . d i r }/WEB−INF/ ”
29 f i l e =” ${ package }/WEB−INF/ p o r t l e t . xml” />
30 <copy t o d i r=” ${ package }/${ b u i l d . d i r }/ j s p ”>
31 < f i l e s e t d i r=” ${ package }/ j s p ”>
32 <i n c l u d e name=” ∗ . j s p ” />
33 </ f i l e s e t>
34 </ copy>

36 <war b a s e d i r=” ${ package }/${ b u i l d . d i r } ” update=” f a l s e ”


37 w a r f i l e=” ${ p o r t l e t . name } . war ”
38 webxml=” ${ package }/WEB−INF/web . xml” />
39 </ t a r g e t>

41 <t a r g e t name=” b u i l d ” depends=” c l e a n , war ” />

43 <t a r g e t name=” c l e a n ” d e s c r i p t i o n=” C l e a n s b u i l d ”>


44 <d e l e t e d i r=” ${ b u i l d . d i r } ” f a i l o n e r r o r=” f a l s e ” />
45 </ t a r g e t>

47 </ p r o j e c t>

Desfăşurarea portlet-ului se face cu apache-ant utilizând fişierul build.xml din


uPortal HOME\uPortal-*.*.* prin
ant deployPortletApp -DportletApp=arhiva portlet-ului.war
În urma acestei operaţii, portlet-ul se dezarhivează ı̂n uPortal HOME\apache-
tomcat-*.*.*\webapps iar fişierul web.xml este actualizat.
Publicarea portlet-ului se face cu rolul de administrator. După conectare la
uPortal
1. AdminTools → Portlet Manager → Publish a new channel
2. Se parcurg meniurile Channel Manager
206 CAPITOLUL 8. PORTLET

(a) Din meniul Channel Type se selectează opţiunea Portlet. Clic Next.
(b) În meniul General Settings se fixează toţi parametrii indicaţi. Clic Next.
(c) În meniul Portlet Descriptor se fixează
• Contextul portlet-ului, adică catalogul din webapps care conţine portlet-
ul. În mod obligatoriu primul caracter este / (slash);
• Numele portlet-ului aşa cum este definit ı̂n fişierul portlet.xml.
Clic Next.
(d) În meniul Portlet Preferences, clic Next.
(e) În meniul Channel Controls, clic Next.
(f) În meniul Categories se fixează categoria canalului şi cel putin un mem-
bru.
Select Marked → Next.
(g) În meniul Groups se fixează grupul şi cel putin un membru.
Select Marked → Next
Grupul desemnează clienţii care pot publica portlet-ul.
(h) În meniul Review, clic Finish.

Canalul portlet-ului apare ı̂n lista afişată.

3. Fiecare client care poate utiliza portlet-ul, ı̂l publică prin componenta Cus-
tomize.
Pentru administrator: AdminTools → Customize urmat de

(a) Clic pe un buton Add Channel corespunzător locului unde vrem să fie
poziţionat portlet-ul.
(b) În User Preferences,
i. se alege categoria portlet-ului, clic go;
ii. se alege numele portlet-ului, clic Add Channel.
(c) Clic pe numele canalului corespunzător portlet-ului. Canalul este afişat
ı̂n meniul Welcome.
(d) Clic pe numele canalului din meniul Welcome lansează portlet-ul.

Un client elimină un portlet stergând canalul corespunzător ı̂n componenta


Costumize (clic pe butonul de ı̂nchidere).
Administratorul portalului şterge un portlet prin clic pe butonul de ı̂nchidere
ı̂n lista portlet-elor publicate din AdminTools → Portlet Manager → Modify a
currently published channel.
Asemănător, se pot publica ı̂n uPortal aplicaţii Web. Deosebirea esenţială este
că tipul canalului (Channel Type) este WebProxy sau Inline Frame.
8.5. PRODUSE PORTAL 207

8.5.2 Jetspeed-2
Jetspeed-2 este un portal cadru dezvoltat de apache.
Instalarea se execută rulând distribuţia jetspeed-2.*.*-installer.jar.
Versiunea instalată a platformei jetspeed este construită peste o distribuţie apache-tomcat-5.5.*.
Astfel, lansarea se face apelând bin\startup.bat.
Portalul se accesează, dintr-un navigator, prin

http://localhost:8080/jetspeed

Desfăşurarea unui portlet constă ı̂n copierea arhivei war corespunzătoare, re-
alizat ı̂n 8.5.1, ı̂n catalogul

Jetspeed HOME \webapps\jetspeed\WEB-INF\deploy

Pe rol de admin, publicarea portlet-ului presupune

1. Clic pe icon-ul butonului Edit - aflat ı̂n dreapta butonului logout.

2. Clic pe un buton Add Portlet, stabilind astfel şi poziţia ı̂n care va fi afişată
fereastra portlet-ului.

3. Clic pe butonul Add al portlet-ului care se doreşte publicat.

4. Clic pe săgeata de reı̂ntoarcere, urmat de clic pe iconul butonului View - aflat


pe poziţia butonului Edit.

Pentru a şterge un portlet, după primul pas anterior, se apasă butonul de


ı̂nchidere din zona portlet-ului.
208 CAPITOLUL 8. PORTLET
Capitolul 9

Java Web Start

9.1 Java Web Start


Java oferă posibilitatea apelării unei aplicaţii prin intermediul unui navigator.
Această posibilitate se bazează pe tehnologia Java Web Start. Aplicaţia se integrează
ı̂ntr-un servlet sub forma unei resurse arhivate.
Aplicaţia Java trebuie să satisfacă restricţiile:
• Aplicaţia trebuie arhivată cu jar;
• Toate resursele externe utilizate, fişiere jar, imagini trebuie incluse ı̂n arhiva
jar. Imaginile se ı̂ncarcă cu metoda getResource a clasei ClassLoader;
• Dacă aplicaţia are arhive jar, atunci toate arhivele trebuie semnate cu jarsigner
şi ı̂n fişierul jnlp se introduce marcajul

<security>
<all-permissions/>
</security>

• Este permisă utilizarea metodei System.exit;


• Toate resursele se descarcă de la aceaşi adresă Web;
• Singura conexiune permisă ı̂n reţea este la adresa web de unde s-a descărcat
aplicaţia;
• Aplicaţia nu utilizează resursele calculatorului client.
• Acces limitat la proprietăţile sistemului client.
Arătăm modul de lucru utilizând un exemplu simplu.
Presupunem că aplicaţia este definită de programul VisualCmmdc.java şi de
clasa corespunzătoare VisualCmmdc.class.

209
210 CAPITOLUL 9. JAVA WEB START

1 public c l a s s VisualCmmdc extends j a v a x . swing . JFrame {


2 public VisualCmmdc ( ) {
3 initComponents ( ) ;
4 }

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

8 private void i n i t C o m p o n e n t s ( ) {
9 // cod g e n e r a t de Netbeans
10 }

12 private void cmmdcButtonMouseClicked ( j a v a . awt . e v e n t . MouseEvent e v t ) {


13 try {
14 S t r i n g sm=mTextField . g e t T e x t ( ) ;
15 S t r i n g sn=n T e x t F i e l d . g e t T e x t ( ) ;
16 long m=Long . parse Lon g ( sm ) ;
17 long n=Long . parseL ong ( sn ) ;
18 long c=cmmdc(m, n ) ;
19 S t r i n g s =(new Long ( c ) ) . t o S t r i n g ( ) ;
20 cmmdcTextField . s e t T e x t ( s ) ;
21 }
22 catch ( E x c e p t i o n e ) {
23 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 ( ) ) ;
24 }
25 }

27 private void exitForm ( j a v a . awt . e v e n t . WindowEvent e v t ) {


28 System . e x i t ( 0 ) ;
29 }

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


32 new VisualCmmdc ( ) . s e t V i s i b l e ( true ) ;
33 }

35 private j a v a x . swing . JButton cmmdcButton ;


36 private j a v a x . swing . J L a b e l mLabel ;
37 private j a v a x . swing . J L a b e l nLabel ;
38 private j a v a x . swing . J T e x t F i e l d mTextField ;
39 private 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 ;
40 private j a v a x . swing . J T e x t F i e l d cmmdcTextField ;
41 }

Interfaţa grafică a programului este ilustrată ı̂n Fig. 9.1

Figure 9.1: Interfaţa grafică pentru rezolvarea ecuaţiei algebrice.


9.1. JAVA WEB START 211

Pentru integrarea aplicaţiei ı̂ntr-o aplicaţie Web, se parcurg paşii:

1. Arhivarea aplicaţiei
jar cfv cmmdc.jar *.class

2. Se editează fişierul launch.jnlp (Java Network Launching Protocol ) cu datele


aplicaţiei.
1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 <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/ app ”>
3 <i n f o r m a t i o n>
4 < t i t l e> . . . </ t i t l e>
5 <vendor> . . . </ vendor>
6 <d e s c r i p t i o n> . . . </ d e s c r i p t i o n>
7 </ i n f o r m a t i o n>
8 <r e s o u r c e s>
9 <j 2 s e version=” 1.2+ ” />
10 <j a r h r e f=”cmmdc . j a r ” />
11 </ r e s o u r c e s>
12 <a p p l i c a t i o n −d e s c main−c l a s s=”VisualCmmdc” />
13 </ j n l p>

Atributul codebase a elementului jnlp are valoarea referinţiei către acest


fişier.
Atributul href a elementului jar are ca valoare numele arhivei programului
creat la pasul 1.
Atributul main-class a elementului application-desc fixează clasa care
conţine metoda main. Acest element poate lipsi, dar atunci fişierul MANIFEST.MF
trebuie să conţină clauza Main-class: cu numele clasei cu metoda main() -
ı̂n cazul exemplului VisualCmmdc–, fişierul jar devenind executabil. În acest
caz comanda de arhivare este
jar cfvm cmmdc.jar myManifest.mf *.class
unde myManifest.mf conţine linia Main-class: VisualCmmdc

3. Într-un catalog de lucru se crează structura de cataloage şi fişiere:

app
|--- cmmdc.jar
|--- launch.jnlp
WEB-INF
|--- lib
| |--- jnlp-servlet.jar
|--- web.xml

Fişierul jnlp-servlet.jar se copiază din distribuţia jdk, din catalogul sam-


ple/jnlp/servlet.
Fişierul web.xml este
212 CAPITOLUL 9. JAVA WEB START

1 ? xml v e r s i o n=” 1 . 0 ” e n c o d i n g=” i s o −8859−1”?>


2 < !DOCTYPE web−app
3 PUBLIC ”−//Sun Microsystems , I n c . / /DTD Web A p p l i c a t i o n 2 . 3 / /EN”
4 ” h t t p : // j a v a . sun . com/ dtd /web−a p p 2 3 . dtd ”>
5 <web−app>
6 < !−− 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 ) −−>
7 <web−app>
8 < s e r v l e t>
9 <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>
10 <s e r v l e t −c l a s s>
11 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
12 </ s e r v l e t −c l a s s>
13 </ s e r v l e t>
14 <s e r v l e t −mapping>
15 <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>
16 <u r l −p a t t e r n>∗ . j n l p</ u r l −p a t t e r n>
17 </ s e r v l e t −mapping>
18 </web−app>
19 </web−app>

4. Conţinutul catalogului de lucru se arhivează ı̂ntr-un fişier war.


jar cfv cmmdc.war app/* WEB-INF/*

5. Fişierul war se copiază ı̂n TOMCAT HOME\webapps.

6. Se completează fişierul html de apelare a aplicaţiei cu datele servlet-ului in-


stalat la pasul 5.
1 <HTML>
2 <BODY bgcolor=”#AAEEAA”>
3 <CENTER>
4 <p>
5 Java Web S t a r t Auto−I n s t a l l f o r I n t e r n e t E x p l o r e r on Windows
6 <p>
7 <h3>V i s u a l Cmmdc A p p l i c a t i o n </h3>
8 <A href=” h t t p : / / l o c a l h o s t : 8 0 8 0 / cmmdc/ app / l a u n c h . j n l p ”>
9 Launch t h e a p p l i c a t i o n </A>
10 </CENTER>
11 </BODY>
12 </HTML>

Dacă interfaţa grafică a aplicaţiei utilizează imagini grafice acestea trebuie arhi-
vate ı̂mpreună cu aplicaţia, de exemplu ı̂ntr-un catalog images.
Încărcarea şi afişarea unei imagini programându-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);
Pentru utilizarea unor pachete arhivate jar, fişierele respective se includ ı̂ntr-un
catalog app\lib şi ı̂n fişierul jnlp-servlet ı̂n elementul jnlp se introduc declaraţiile
9.1. JAVA WEB START 213

<resources>
<jar href="lib/NumeFisier.jar"/>
. . .
</resources>

Dacă aplicaţia foloseşte resurse suplimentare, date prin fişiere jar ı̂n catalogul
lib, atunci fiecare arhivă jar trebuie certificată.
Certificarea resurselor se realizează rulând succesiv

1. keytool -genkey -keystore myKeystore -alias myself

2. keytool -selfcert -alias myself -keystore myKeystore

3. jarsigner -keystore myKeystore myapp.jar myself

keytool.exe şi jarsigner.exe se găsesc ı̂n distribuţia jdk.


Primele două acţiuni au ca rezultat obţinerea certificatului myKeystore iar ultima
acţiune reprezintă ı̂nglobarea certificării ı̂n arhiva jar.
Toate fişierele jar trebuie să poarte aceaşi certificare.
În plus, fişierul jnlp-servlet ataşat aplicaţiei conţine elementele

<security>
<all-permissions />
</security>
214 CAPITOLUL 9. JAVA WEB START
Capitolul 10

Java Management Extensions

Java Management Extensions (JMX) face posibilă ca un obiect Java să permită
gestionarea metodelor şi a anumitor câmpuri de către alte obiecte. Obiectele Java
care ı̂şi expun astfel resursele se numesc MBean - uri şi formează temelia cadrului
de lucru JMX.
Există mai multe tipuri de MBean-uri:
• Standard MBean;
• Dynamic MBean;
• Open MBean;
• Model MBean;
• MXBean;
Un obiect care gestionează resursele unui MBean se numeşte agent sau server MBean.
Agentul dispune de mijloace care interacţionează cu un MBean, permiţându-i:
• accesul la valorile unui câmp şi la modificarea lor;
• invocarea metodelor.
În general, un agent poate fi definit ca
• autorul unei acţiuni;
• factor care provoacă acţiuni;
• reprezentant al unei instituţii ı̂nsărcinat cu ı̂ndeplinirea unor acţiuni.
Terminologia server MBean se justifică prin faptul că poate fi invocat de un
program client. În această ipostază, serverul MBean are rolul unui container de
MBean-uri şi de gestionare şi execuţie a apelurilor clienţilor.
Structura unei aplicaţii JMX conţine două nivele:

215
216 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

• componentele MBean;

• agentul (serverul MBean).

10.1 Standard MBean


10.1.1 Crearea unui Standard MBean
O componentă MBean este alcătuită dintr-o interfaţă şi o clasă care imple-
mentează interfaţa satisfăcând următoarele restricţii:

1. interfaţa are numele clasei care o implementează având ı̂n plus sufixul MBean;

2. Interfaţa şi clasa care o implementează aparţin aceluiaşi pachet;

3. constructorii şi metodele expuse trebuie să fie publice.

În continuare câmpurile şi metodele destinate expunerii se vor denumi atribute,
respectiv operaţii. Fiecărui atribut xxx i se ataşează cel puţin una din metodele

public void setXxx(tip xxx){


this.xxx=xxx;
}

şi / sau

public tip getXxx(){


return xxx;
}

Un atribut se precizează doar prin aceste metode, fără definirea / declararea câmpului
corespunzător. Câmpul se defineşte ı̂n clasa ce implementează interfaţa MBean-ului.
Astfel, un MBean este caracterizat de

• atribute
care pot fi consultate (citite), modificate (scrise) sau cu ambele opţiuni.

• operaţii

• notificări
cu evidenţa modificărilor suferite de atribute.

Exemplul 10.1.1

Construim un MBean cu
10.1. STANDARD MBEAN 217

• atributele

– label
ce poate fi numai citit;
– cursEuro
care poate fi consultat şi modificat;

• operaţiile

– public String sayHello()


afişează un mesaj;
– public long cmmdc(long m, long n);
de calcul a celui mai mare divizor comun a două numere naturale.
Interfaţa IntroMBean este
1 package b a s i c ;

3 public i n t e r f a c e IntroMBean {
4 // O p e r a t i i
5 public S t r i n g s a y H e l l o ( ) ;
6 public long cmmdc( long m, long n ) ;

8 // A t r i b u t e
9 // read−o n l y
10 public S t r i n g g e t L a b e l ( ) ;
11 // read−w r i t e
12 public double getCursEuro ( ) ;
13 public void s e t C u r s E u r o ( double c u r s E u r o ) ;
14 }

fiind implementat de clasa Intro


1 package b a s i c ;
2 import j a v a x . management . ∗ ;

4 public c l a s s I n t r o implements IntroMBean {

6 // A t r i b u t e
7 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 ” ;
8 private double c u r s E u r o = 3 . 5 0 ;

10 public S t r i n g g e t L a b e l ( ) {
11 return l a b e l ;
12 }

14 public double getCursEuro ( ) {


15 return c u r s E u r o ;
16 }

18 public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) {


19 this . cursEuro = cursEuro ;
20 }
218 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

22 // O p e r a t i i
23 public S t r i n g s a y H e l l o ( ) {
24 S t r i n g message=” H e l l o World ! ” ;
25 System . out . p r i n t l n ( message ) ;
26 return message ;
27 }

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


30 }

În acest caz nu s-a implementat posibilitatea notificărilor atributului cursEuro.

10.1.2 Crearea unui MBeanServer


Un agent sau MBean server implementează interfaţa MBeanServer. Un aseme-
nea obiect se obţine printr-una din metodele statice

• static MBeanServer ManagementFactory.getPlatformMBeanServer()

• static MBeanServer MBeanServerFactory.createMBeanServer()

În agent se ı̂nregistrează componente MBean. Un obiect MBean este caracterizat


de un nume, un obiect de tip ObjectName. Înregistrarea şi / sau crearea unei
componente MBean necesită definirea ı̂n prealabil a acestui nume. Structura unei
nume este

domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . .

unde

• domeniu
este un nume simbolic (String). Dacă domeniul este stringul vid atunci se
consideră valoarea implicită DefaultDomain.

• atribute uzuale:

– type=numele MBean-ului
– index=număr de identificare a MBean-ului

Cel puţin un atribut este obligatoriu.

Clasa ObjectName
Constructori

• ObjectName(String nume)
Parametrul nume are structura descrisă mai sus.
10.1. STANDARD MBEAN 219

• ObjectName(String domeniu, Hashtable<String,String> tabel )

• ObjectName(String domeniu, String numeAtribut, String


valAtribut)

Metode

• static ObjectName getInstance(String nume)

Înregistrarea şi utilizarea MBean-ului face apel la metodele interfeţei MBeanServer.

ObjectInstance
Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansamblu-
lui alcătuit de un obiect ObjectName asociat unui MBean şi numele clasei core-
spunzătoare.

Interfaţa MBeanServer
Metode

• ObjectInstance registerMBean(Object obj , ObjectName nume)


Inregistrează pe platformă, instanţa obj a unui MBean având numele nume.

• void unregister(ObjectName nume)

• ObjectInstance createMBean(String numeClasă, ObjectName nume)


Crează şi ı̂nregistrează un MBean de clasă numeClasă şi de nume nume.

• ObjectInstance createMBean(String numeClasă, ObjectName nume, Object[]


param, String[] sign)
În plus, şirul param conţine parametri constructorului, de tip, respectiv sign.

• String getDefaultDomain()

• Object invoke(ObjectName mbeanName, String operationName, Object[]


param, String[] paramTip)
Se invocă operaţia operationName a MBean-ului mbeanName. Parametri nece-
sari operaţiei ı̂mpreună cu tipurile corespunzătoare sunt daţi ı̂n variabilele
param şi respectiv paramTip.

• Object getAttribute(ObjectName mbeanName,String atribut)


Returnează valoarea atributului atribut a mbean-ului mbeanName.
220 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

• void setAttribute(ObjectName mbeanName,Attribute atribut)


Fixează valoarea atributului atribut a MBean-ului mbeanName. Reţinem doar
constructorul clasei Attribute prin
Attribute(String nume, Object valoare)

• MBeanInfo getMBeanInfo(ObjectName mbeanName)


Returnează un obiect de tip MBeanInfo util inspectării resurselor unui MBean.

Există mai multe şabloane de programare a ı̂nregistrării unei componente MBean.

Exemplul 10.1.2 Se crează două componente MBean de tip Intro care vor fi in-
spectate prin intermediul utilitarului jconsole1 - distribuţia Sun.
Utilitarul jconsole permite apelarea operaţiilor, modificarea atributelor şi sem-
nalează notificările.

1 package b a s i c ;
2 import j a v a . l a n g . management . ∗ ;
3 import j a v a x . management . ∗ ;

5 public c l a s s Main{
6 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
7 S t r i n g domeniu=” ” ;
8 i f ( a r g s . l e n g t h >0) domeniu=a r g s [ 0 ] ;
9 try {
10 // S e r v e r u l p l a t f o r m e i
11 MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ;
12 // MBeanServer mbs = MBeanServerFactory . createMBeanServer ( ) ;

14 // V a r i a n t a 1
15 // C o n s t r u i r e a ObjectName c o r e s p u n z a t o r MBean−u l u i
16 ObjectName mbeanObjectName =
17 new ObjectName ( domeniu+” : t y p e=I n t r o , i n d e x=1” ) ;

19 // Crearea MBean−u l u i
20 I n t r o mbean = new I n t r o ( ) ;

22 // I n r e g i s t r a r e a MBean−u l u i
23 mbs . r e g i s t e r M B e a n ( mbean , mbeanObjectName ) ;

25 // V a r i a n t a 2
26 mbeanObjectName=new ObjectName ( domeniu+” : t y p e=I n t r o , i n d e x=2” ) ;
27 mbs . createMBean ( ” b a s i c . I n t r o ” , mbeanObjectName ) ;

29 // A s t e p t a r e n e d e f i n i t a
30 System . out . p r i n t l n ( ” Waiting f o r e v e r . . . ” ) ;
31 while ( true ) ;
32 }
33 catch ( E x c e p t i o n e ) {
34 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 ( ) ) ;

1
În acest caz, este nevoie ca variabilele de tip clasă acoperitoare Double, Long să fie ı̂nlocuite
prin tipuri predefinite.
10.1. STANDARD MBEAN 221

35 }
36 }
37 }

Executarea aplicaţiei revine la

1. Într-o fereastră DOS se lansează agentul Main prin


java -Dcom.sun.manager.jmxremote basic.Main

2. Într-o altă fereastră DOS se lansează


jconsole
pornind utilitarul jconsole.

3. În fereastra de dialog jconsole:Connect to Agent se dă clic pe Connect.

4. În panoul Tree găsim domeniul dat. Prin clic pe domeniu apar MBean-urile
de indice 1 şi 2.

5. Prin clic pe unul din aceste MBean-uri, ı̂n panoul central avem acces la atributele
şi la operaţiile lor.

Rezultatul unei operaţii apare ı̂ntr-o fereastră de informare (Fig. 10.1).

10.1.3 Notificări
Pentru implementarea reţinerii de către un agent MBean a notificărilor, clasa
ce implementează interfaţa MBean-ului trebuie să extindă clasa Notification-
BroadcasterSupport.
Modificările unui atribut se reţin ı̂ntr-un obiect de tip Notification şi este
transmis prin metoda

sendNotification(Notification notification)

a clasei NotificationBroadcasterSupport.
Suplimentar se defineşte metoda

public MBeanNotificationInfo[] getNotificationInfo()

ı̂n care se precizează

• tipul notificării - (constantă definită de clasa AttributeChangeNotification);

• clasa ı̂n care s-a generat notificarea


String name = AttributeChangeNotification.class.getName();

• o descriere a modificării.
222 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

Figure 10.1: Rezultatele furnizate de jcluster.

Astfel, introducerea notificărilor presupune familiarizarea cu clasele

• NotificationBroadcasterSupport
Constructori

– NotificationBroadcasterSupport()

Metode

– void sendNotification(Notification notificare)

• Notification
Constructori

– Notification(String type, Object source, long sequenceNumber )


10.1. STANDARD MBEAN 223

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

• AttributeChangeNotification extends Notification


Constructori

– AttributeChangeNotification(Object source, long sequenceNumber ,


long timeStamp, String msg, String attributeName, String attribute-
Type, Object oldValue, Object newValuE )

Câmpuri

– static String ATTRIBUTE CHANGE


Semnalează schimbarea atributului

Exemplul 10.1.3 Extinderea MBean-ului Intro cu notificarea modificărilor atributelor


ı̂n jconsole.

Implementarea notificărilor ı̂n clasa Intro presupune modificarea metodei setCursEuro.


Totodată se adaugă metoda getNotificationInfo, ce furnizează informaţii referitoare
la modificarea apărută. Codul clasei care implementează interfaţa devine
1 package agentn ;
2 import j a v a x . management . ∗ ;

4 public c l a s s IntroN 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


5 implements IntroNMBean {
6 private long sequenceNumber =1;

8 // A t r i b u t e
9 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 ” ;
10 private double c u r s E u r o = 3 . 5 0 ;

12 public S t r i n g g e t L a b e l ( ) { . . . }

14 public double getCursEuro ( ) { . . . }

16 public synchronized void s e t C u r s E u r o ( double c u r s E u r o ) {


17 double oldCursEuro=t h i s . c u r s E u r o ;
18 this . cursEuro = cursEuro ;
224 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

19 // System . o u t . p r i n t l n (” Curs de schimb euro : ” + euro+” ron . ” ) ;


20 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 (
21 this ,
22 sequenceNumber++,
23 System . c u r r e n t T i m e M i l l i s ( ) ,
24 ” Schimbarea c u r s u l u i Euro ” ,
25 ” cursEuro ” ,
26 ” double ” ,
27 oldCursEuro ,
28 cursEuro ) ;
29 sendNotification (n ) ;
30 }

32 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 ( ) {
33 S t r i n g [ ] t y p e s = new S t r i n g [ ] {
34 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
35 };
36 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 ( ) ;
37 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 ” ;
38 MBeanNotificationInfo info =
39 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 ) ;
40 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 } ;
41 }

43 // O p e r a t i i
44 public S t r i n g s a y H e l l o ( ) { . . . }

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


47 }

În jconsole pentru notificare, ı̂n prealabil este nevoie de subscriere.

10.1.4 Agent MBean


În exemplelele anterioare rezursele unui MBean au fost utilizate prin jconsole.
Valorificarea resurselor unui MBean Intro, dintr-un MBeanServer (agent) se pro-
gramează prin

Exemplul 10.1.4

1 package a g e n t ;
2 import j a v a . i o . IOException ;
3 import j a v a x . management . ∗ ;
4 import j a v a x . management . remote . ∗ ;
5 import j a v a . u t i l . Sca nne r ;

7 public c l a s s Agent {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
9 try {
10 // Crearea A g e n t u l u i − MBeanServer
11 MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;

13 // Crearea unui MBean


14 S t r i n g domain = mbs . g e t D e f a u l t D o m a i n ( ) ;
15 S t r i n g className=” a g e n t . I n t r o ” ;
10.1. STANDARD MBEAN 225

16 S t r i n g sObjectName=domain+” : t y p e=”+className ;
17 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
18 mbs . createMBean ( className , mbeanObjectName ) ;

20 // U t i l i z a r e a MBean−u l u i
21 // A p e l a r e a o p e r a t i i l o r
22 S t r i n g o p e r a t i a=” s a y H e l l o ” ;
23 mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ;

25 o p e r a t i a=”cmmdc” ;
26 System . out . p r i n t l n ( ”Cmmdc a l n u m e r e l o r : ” ) ;
27 Sc anner s c a n n e r=new Sc anne r ( System . i n ) ;
28 System . out . p r i n t l n ( ” Primul numar : ” ) ;
29 long m=s c a n n e r . nextLong ( ) ;
30 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;
31 long n=s c a n n e r . nextLong ( ) ;
32 O b j e c t [ ] param={m, n } ;
33 S t r i n g [ ] s i g n ={” l o n g ” , ” l o n g ” } ;
34 Long r =(Long ) mbs . i n v o k e ( mbeanObjectName , o p e r a t i a , param , s i g n ) ;
35 System . out . p r i n t l n ( ”cmmdc=”+r . t o S t r i n g ( ) ) ;

37 // U t i l i z a r e a A t r i b u t e l o r
38 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 ” ) ;
39 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 ) ;

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 ” ) ;
42 double c u r s E u r o=s c a n n e r . nextDouble ( ) ;
43 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 ) ;
44 mbs . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
45 Double e u r o =(Double ) mbs . g e t A t t r i b u t e ( mbeanObjectName , ” CursEuro ” ) ;
46 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 ) ;
47 }
48 catch ( E x c e p t i o n e ) {
49 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
50 }
51 }
52 }

10.1.5 Invocarea la distanţă


Din punct de vedere al programării distribuite, cazul interesant este cel ı̂n care
clasa ce implementează MBean-ul şi clientul (agentul MBean) care o utilizează se
află pe calculatoare diferite.
În acest caz:

• Este nevoie de o clasa server (agent) al cărui rol este

– Instanţierea unui MBeanServer


– Instanţiarea unui server de conexiune, obiect de tip MBeanServerConnection.
Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestionează comunicaţia
dintre un client şi serverul MBeanServer.
– Lansarea ı̂n execuţie a serverului de conexiune.
226 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

• Clientul dispune de interfaţa MBeanu-ului


Interfaţa MBeanServerConnection este implementată de clasa MBeanServer Şablonul
de programare pentru instanţierea obiectului de tip MBeanServerConnection şi
lansarea sa ı̂n execuţie poate fi:
String surl="service:jmx:rmi:///jndi/rmi://host:port/numeServer"
// String surl="service:jmx:iiop:///jndi/iiop://host:port/numeServer";

// Crearea unui RMI server-conector


JMXServiceURL url = new JMXServiceURL(surl);
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url,null,MBeanServer);
//
// Pornirea server-conectorului RMI
cs.start();
System.out.println("Press Enter to finish !");
System.in.read();
cs.stop();

Serverul de conexiune are un nume, numeServer care trebuie cunoscut de către


client.
Lansarea ı̂n execuţie a serverului este precedată de pornirea registrului rmireg-
istry, respectiv orbd.

Exemplul 10.1.5

1 package s e r v e r ;
2 import j a v a . i o . IOException ;
3 import j a v a x . management . ∗ ;
4 import j a v a x . management . remote . ∗ ;

6 public c l a s s MBServer {
7 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
8 S t r i n g h o s t=” l o c a l h o s t ” ;
9 S t r i n g p o r t=” 1099 ” ;
10 i f ( a r g s . l e n g t h ==0){
11 System . out . p r i n t l n ( ”The S e r v i c e name i s r e q u i r e d ” ) ;
12 System . e x i t ( 0 ) ;
13 }
14 i f ( a r g s . l e n g t h >=2)
15 h o s t=a r g s [ 1 ] ;
16 i f ( a r g s . l e n g t h >=3)
17 p o r t=a r g s [ 2 ] ;
18 try {
19 // Crearea MBeanServer
20 MBeanServer mbs = MBeanServerFactory . c r e a t e M B e a n S e r v e r ( ) ;

22 // Crearea unui RMI s e r v e r −c o n e c t o r


23 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ”+
24 h o s t+” : ”+p o r t+” / ”+a r g s [ 0 ] ;
25 // 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 ://”+
26 // h o s t +”:”+ p o r t +”/”+ a r g s [ 0 ] ;
27 JMXServiceURL u r l=new JMXServiceURL ( s u r l ) ;
28 JMXConnectorServer c s=
10.1. STANDARD MBEAN 227

29 JMXConnectorServerFactory . newJMXConnectorServer ( u r l , null , mbs ) ;

31 // 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 RMI
32 cs . st art ( ) ;
33 System . out . p r i n t l n ( ” P r e s s Enter t o f i n i s h ! ” ) ;
34 System . i n . r e a d ( ) ;
35 cs . stop ( ) ;
36 }
37 catch ( E x c e p t i o n e ) {
38 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
39 e . printStackTrace ( ) ;
40 }
41 }
42 }

Primul argument care trebuie furnizat programului anterior (args[0] ) este numele
serverului.
Clientul, la rândul lui, este nevoit să creeze un conector RMI către server (agent),
prin intermediul căruia obţine un obiect ce implementează interfaţa MBeanServerConnection.
Prin acest obiect, clientul va putea crea MBean-uri - ı̂n agent - şi le va putea utiliza
resursele.
Şablonul 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 interfeţei MBeanServerConnection

• crearea unui reprezentant local al MBean-ului prin metoda statică

mbeanClass proxy =
(mbeanClass)MBeanServerInvocationHandler.newProxyInstance(
mbeanServerConnection,mbeanObjectName,mbeanClass.class,true);

În final, MBean-ul se şterge din serverul de conexiune, prin


cs.unregisterMBean(mbeanObjectName).

Exemplul 10.1.6 Client ce utilizează un MBean Intro, definit ı̂n Exemplul 10.1.1

1 package c l i e n t ;
2 import j a v a . i o . IOException ;
3 import j a v a . u t i l . ∗ ;
4 import j a v a x . management . ∗ ;
5 import j a v a x . management . remote . ∗ ;
228 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

7 public c l a s s C l i e n t {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
9 S t r i n g h o s t=” l o c a l h o s t ” ;
10 S t r i n g p o r t=” 1099 ” ;
11 i f ( a r g s . l e n g t h ==0){
12 System . out . p r i n t l n ( ”The S e r v i c e name i s r e q u i r e d ” ) ;
13 System . e x i t ( 0 ) ;
14 }
15 i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ;
16 i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ;
17 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
18 try {
19 // Crearea unui c o n e c t o r RMI 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
20 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ”+
21 h o s t+” : ”+p o r t+” / ”+a r g s [ 0 ] ;
22 // 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 ://”+
23 // h o s t +”:”+ p o r t +”/”+ a r g s [ 0 ] ;
24 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
25 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
26 MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;

28 // Domeniile a g e n t u l u i s u n t
29 System . out . p r i n t l n ( ” Domains : ” ) ;
30 S t r i n g domains [ ] = c s . getDomains ( ) ;
31 f o r ( i n t i = 0 ; i < domains . l e n g t h ; i ++) {
32 System . out . p r i n t l n ( ” \ tDomain [ ” + i + ” ] = ” + domains [ i ] ) ;
33 }

35 // i a r domeniul i m p l i c i t
36 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 ( ) ;
37 System . out . p r i n t l n ( ” DefaultDomain : ” +domain ) ;
38 // Crearea unui MBean I n t r o
39 S t r i n g className=” b a s i c . I n t r o ” ;
40 S t r i n g sObjectName=domain+” : t y p e=”+className ;
41 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
42 c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;

44 double c u r s E u r o ;
45 long m, n ;

47 // U t i l i z a r e a MBean−u l u i
48 // 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
49 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 ” ) ;
50 IntroMBean proxy=
51 ( 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 (
52 cs ,
53 mbeanObjectName ,
54 c l i e n t . IntroMBean . c l a s s ,
55 true ) ;

57 // U t i l i z a r e a o p e r a t i i l o r
58 // o p e r a t i a ” s a y H e l l o ”
59 proxy . s a y H e l l o ( ) ;

61 // o p e r a t i a cmmdc
62 System . out . p r i n t l n ( ”Cmmdc a l n u m e r e l o r : ” ) ;
63 System . out . p r i n t l n ( ” Primul numar : ” ) ;
64 m=s c a n n e r . nextLong ( ) ;
10.1. STANDARD MBEAN 229

65 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;


66 n=s c a n n e r . nextLong ( ) ;
67 System . out . p r i n t l n ( ”Cmmdc=”+proxy . cmmdc(m, n ) ) ;

69 // U t i l i z a r e a a t r i b u t e l o r
70 System . out . p r i n t l n ( ”Numele : ”+proxy . g e t L a b e l ( ) ) ;
71 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 ” ) ;
72 c u r s E u r o=s c a n n e r . nextDouble ( ) ;
73 proxy . s e t C u r s E u r o ( c u r s E u r o ) ;
74 System . out . p r i n t l n ( ” Euro : ”+proxy . getCursEuro ( ) ) ;

76 // 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
77 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 ” ) ;
78 // A p e l a r e a o p e r a t i i l o r
79 S t r i n g o p e r a t i a=” s a y H e l l o ” ;
80 c s . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ;
81 o p e r a t i a=”cmmdc” ;
82 System . out . p r i n t l n ( ”Cmmdc a l n u m e r e l o r : ” ) ;
83 System . out . p r i n t l n ( ” Primul numar : ” ) ;
84 m=s c a n n e r . nextLong ( ) ;
85 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;
86 n=s c a n n e r . nextLong ( ) ;
87 O b j e c t [ ] param={m, n } ;
88 S t r i n g [ ] s i g n ={” l o n g ” , ” l o n g ” } ;
89 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 ) ;
90 System . out . p r i n t l n ( ”Cmmdc=”+r . t o S t r i n g ( ) ) ;

92 // U t i l i z a r e a A t r i b u t e l o r
93 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 ” ) ;
94 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 ) ;

96 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 ” ) ;
97 c u r s E u r o=s c a n n e r . nextDouble ( ) ;
98 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 ) ;
99 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
100 Double newEuro=(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , ” CursEuro ” ) ;
101 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 ) ;
102 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
103 }
104 catch ( E x c e p t i o n e ) {
105 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
106 }
107 }
108 }

Inspectarea şi valorificarea resurselor unei componente MBean se poate


face şi prin intermediul metodei
1 private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) {
2 System . out . p r i n t l n ( ”CLASA: \ t ” + i n f o . getClassName ( ) ) ;
3 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 ( ) ) ;
4 System . out . p r i n t l n ( ”ATTRIBUTE” ) ;
5 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 ( ) ;
6 i f ( a t t r I n f o . length > 0) {
7 f o r ( i n t i = 0 ; i < a t t r I n f o . l e n g t h ; i ++) {
8 System . out . p r i n t l n ( ” \tNUME: \ t ” + a t t r I n f o [ i ] . getName ( ) ) ;
9 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 ( ) ) ;
10 System . out . p r i n t l n ( ” \ tTIP : \ t ” + a t t r I n f o [ i ] . getType ( ) +
11 ” READ: ”+ a t t r I n f o [ i ] . i s R e a d a b l e ( ) +
230 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

12 ” WRITE: ”+ a t t r I n f o [ i ] . i s W r i t a b l e ( ) ) ;
13 }
14 }
15 else
16 System . out . p r i n t l n ( ” \ t F a r a a t r i b u t e ! ” ) ;
17 System . out . p r i n t l n ( ”CONSTRUCTORI” ) ;
18 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 ( ) ;
19 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 ++) {
20 System . out . p r i n t l n ( ” \tNUME: \ t ” + c o n s t r I n f o [ i ] . getName ( ) ) ;
21 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 ( ) ) ;
22 System . out . p r i n t l n ( ” \tPARAM: \ t ” +
23 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 ” ) ;
24 }
25 System . out . p r i n t l n ( ”OPERATII” ) ;
26 MBeanOperationInfo [ ] o p I n f o = i n f o . g e t O p e r a t i o n s ( ) ;
27 i f ( opInfo . length > 0) {
28 f o r ( i n t i = 0 ; i < o p I n f o . l e n g t h ; i ++) {
29 System . out . p r i n t l n ( ” \tNUME: \ t ” + o p I n f o [ i ] . getName ( ) ) ;
30 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 ( ) ) ;
31 System . out . p r i n t l n ( ” \tPARAM: \ t ” +
32 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 ” ) ;
33 }
34 }
35 else
36 System . out . p r i n t l n ( ” \ t F a r a o p e r a t i i ” ) ;
37 System . out . p r i n t l n ( ”NOTIFICARI” ) ;
38 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 ( ) ;
39 i f ( n o t i f I n f o . length > 0) {
40 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 ++) {
41 System . out . p r i n t l n ( ” \tNUME: ” + n o t i f I n f o [ i ] . getName ( ) ) ;
42 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 ( ) ) ;
43 String notifTypes [ ] = n o t i f I n f o [ i ] . getNotifTypes ( ) ;
44 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 ++) {
45 System . out . p r i n t l n ( ” \ tTIP : ” + n o t i f T y p e s [ j ] ) ;
46 }
47 }
48 }
49 else
50 System . out . p r i n t l n ( ” \ t F a r a n o t i f i c a r i ” ) ;
51 }

Această metodă poate fi inserată ı̂n oricare din programele agent sau client.

Notificarea la distanţă
Notificarea la distanţă presupune utilizarea unui MBean posedând această fa-
cilitate. Pe partea de client trebuie implementat interfaţa NotificationListener
care declară metoda

public void handleNotification(Notification notification, Object


handback )

Ataşarea şi disponibilizarea clasei ce implementează interfaţa Notification


Listener se obţin prin metodele interfeţei MBeanServerConnection:
10.1. STANDARD MBEAN 231

• void addNotificationListener(ObjectName name, NotificationListener


listener , NotificationFilter filter , Object handback )throws Instance-
NotFoundException, IOException

• void removeNotificationListener(ObjectName name, ObjectName listener


)throws InstanceNotFoundException, ListenerNotFoundException, IOException

Exemplul 10.1.7 Folosind exemplul 10.1.6 - dar cu MBean-ul creat pentru 10.1.3
se crează un client cu notificare, care sesisează modificarea valoarii atributului cursEuro
a MBean-ului IntroN.

Implementarea interfeţei NotificationListener este


1 package c l i e n t ;
2 import j a v a x . management . N o t i f i c a t i o n ;
3 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 ;
4 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 ;

6 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 {
7 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 ,
8 O b j e c t handback ) {
9 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 ) ;
10 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=
11 ( AttributeChangeNotification ) n o t i f i c a t i o n ;
12 System . out . p r i n t l n ( ” Curs i n i t i a l : ” +
13 myNotif . getOldValue ( ) . t o S t r i n g ( ) ) ;
14 System . out . p r i n t l n ( ” Curs c u r e n t : ” +
15 myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ;
16 }
17 }

Codul clasei client este


1 package c l i e n t ;
2 import j a v a . i o . IOException ;
3 import j a v a . u t i l . ∗ ;
4 import j a v a x . management . ∗ ;
5 import j a v a x . management . remote . ∗ ;

7 public c l a s s C l i e n t N o t i f {
8 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
9 S t r i n g h o s t=” l o c a l h o s t ” ;
10 S t r i n g p o r t=” 1099 ” ;
11 i f ( a r g s . l e n g t h ==0){
12 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 ” ) ;
13 System . e x i t ( 0 ) ;
14 }
15 i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ;
16 i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ;
17 Sc anner s c a n n e r=new Sc anner ( System . i n ) ;
18 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 ( ) ;
19 try {
20 // Crearea unui c o n e c t o r RMI s i a o b i e c t u l u i
21 // de t i p MBeanServerConnection
22 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ” +
23 h o s t+” : ”+p o r t+” / ”+a r g s [ 0 ] ;
232 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

24 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;


25 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
26 MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;

28 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 ( ) ;
29 System . out . p r i n t l n ( ” DefaultDomain : ” +domain ) ;
30 // Crearea unui MBean I n t r o
31 S t r i n g className=” b a s i c n . I nt r oN ” ;
32 S t r i n g sObjectName=domain+” : t y p e=”+className ;
33 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

35 MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


36 getMBeanResources ( i n f o ) ;

38 // U t i l i z a r e a n o t i f i c a r i i
39 // Crearea unui a s c u l t a t o r
40 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 ( ) ;
41 // A c t i v a r e a n o t i f i c a t o r u l u i
42 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 ) ;

44 Thread . s l e e p ( 5 0 0 ) ;
45 // 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
46 System . out . p r i n t l n ( ” P r e s s Enter t o f i n i s h ! ” ) ;
47 try {
48 System . i n . r e a d ( ) ;
49 }
50 catch ( j a v a . i o . IOException e ) { }
51 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 ) ;
52 // 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
53 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
54 }
55 catch ( E x c e p t i o n e ) {
56 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
57 e . printStackTrace ( ) ;
58 }
59 }

61 private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }

63 }

Clasa Client care crează MBean-ul trebuie lansată ı̂naintea clasei ClientNotif. Aceste
două clase pot rula pe calculatoare distincte.

Exemplul 10.1.8 O aplicaţie servlet ı̂ntreţine un cont. Acţiunile ce pot fi ı̂ntreprinse


sunt: depunerea unei sume, extragerea unei sume ı̂n limita soldului şi consultarea
contului. Contul este implementat ca un MBean standard. Se cere urmărirea la
distanţa a modificărilor suferite de cont.
Interfaţa contului (a MBean-ului) este
1 public i n t e r f a c e ContMBean {
2 // A t r i b u t e
3 // read−w r i t e
4 public double getCont ( ) ;
5 public void s e t C o n t ( double c o n t ) ;
6 }
10.1. STANDARD MBEAN 233

implementat prin
1 import j a v a x . management . ∗ ;

3 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


4 implements ContMBean{
5 private long sequenceNumber =1;
6 private double c o n t ;

8 public synchronized double getCont ( ) {


9 return c o n t ;
10 }

12 public synchronized void s e t C o n t ( double c o n t ) {


13 double oldCont=t h i s . c o n t ;
14 t h i s . c o n t=c o n t ;
15 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 (
16 this ,
17 sequenceNumber++,
18 System . c u r r e n t T i m e M i l l i s ( ) ,
19 ” Schimbarea Cont ” ,
20 ” cont ” ,
21 ” double ” ,
22 oldCont ,
23 cont ) ;
24 sendNotification (n ) ;
25 }

27 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 ( ) {
28 S t r i n g [ ] t y p e s = new S t r i n g [ ] {
29 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
30 };
31 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 ( ) ;
32 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 ” ;
33 MBeanNotificationInfo info =
34 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 ) ;
35 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 }

Codul servletului este


1 import java . io . ∗ ;
2 import javax . s e r v l e t . ∗ ;
3 import javax . s e r v l e t . http . ∗ ;
4 import j a v a x . management . ∗ ;
5 import j a v a x . management . remote . ∗ ;

7 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 {
8 MBeanServerConnection c s=n u l l ;
9 ObjectName mbeanObjectName=n u l l ;
10 String host ;
11 S t r i n g p o r t=” 1099 ” ;
12 S t r i n g s e r v e r=” s e r v e r ” ;

14 public void i n i t ( ) {
15 try {
16 super . i n i t ( c o n f i g ) ;
17 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 ” ) ;
18 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ” +
234 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

19 h o s t+” : ”+p o r t+” / ”+s e r v e r ;


20 // 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 : / / ” +
21 // h o s t +”:”+ p o r t +”/”+ s e r v e r ;
22 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
23 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
24 c s = jmxc . getMBeanServerConnection ( ) ;
25 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 ( ) ;
26 S t r i n g className=” Cont ” ;
27 S t r i n g sObjectName=domain+” : t y p e=”+className ;
28 mbeanObjectName = new ObjectName ( sObjectName ) ;
29 c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;
30 }
31 catch ( E x c e p t i o n e ) {
32 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
33 System . e x i t ( 0 ) ;
34 }
35 }

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


38 throws S e r v l e t E x c e p t i o n , IOException {
39 S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ;
40 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 ” ) ;
41 S t r i n g s=r e q . g e t P a r a m e t e r ( ”suma” ) ;
42 S t r i n g message=” ” ;
43 double suma=Double . p a r s e D o u b l e ( s ) ;
44 Double o b j V a l u e=n u l l ;
45 try {
46 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 ” ) ;
47 }
48 catch ( E x c e p t i o n e ) {
49 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
50 }
51 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 ( ) ;
52 i n t i n d e x =−1;
53 i f ( o p e r . e q u a l s ( ” dep ” ) ) i n d e x =0;
54 i f ( o p e r . e q u a l s ( ” e x t ” ) ) i n d e x =1;
55 i f ( o p e r . e q u a l s ( ” con ” ) ) i n d e x =2;
56 double x ;
57 A t t r i b u t e c u r s=n u l l ;
58 switch ( i n d e x ) {
59 case 0 :
60 x=v a l u e+suma ;
61 c u r s=new A t t r i b u t e ( ” Cont ” , x ) ;
62 try {
63 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
64 message=”S−a depus suma” ;
65 }
66 catch ( E x c e p t i o n e ) {
67 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
68 }
69 break ;
70 case 1 :
71 i f ( v a l u e>=suma ) {
72 x=v a l u e −suma ;
73 c u r s=new A t t r i b u t e ( ” Cont ” , x ) ;
74 try {
75 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
76 message=”S−a e x t r a s suma” ;
77 }
10.1. STANDARD MBEAN 235

78 catch ( E x c e p t i o n e ) {
79 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
80 }
81 }
82 else {
83 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 ” ;
84 }
85 break ;
86 case 2 :
87 message=”Suma d i n c o n t e s t e ”+v a l u e+” u n i t . ” ;
88 break ;
89 }
90 r e s . setContentType ( ” t e x t / html ” ) ;
91 out . p r i n t l n ( ”<html>” ) ;
92 out . p r i n t l n ( ”<head><t i t l e >Depozit </ t i t l e ></head>” ) ;
93 out . p r i n t l n ( ”<body>” ) ;
94 out . p r i n t l n ( ”<h1>O p e r a t i u n i Cont</h1>” ) ;
95 out . p r i n t l n ( ”<p>” ) ;
96 out . p r i n t l n ( message ) ;
97 out . p r i n t l n ( ”</p>” ) ;
98 out . p r i n t l n ( ”</body></html>” ) ;
99 out . c l o s e ( ) ;
100 }

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


103 throws S e r v l e t E x c e p t i o n , IOException {
104 doGet ( req , r e s ) ;
105 }
106 }

Pagina de apelare a servletului fiind (index.html )


1 <html>
2 <head>
3 < t i t l e> S e r v l e t −u l H e l l o </ t i t l e>
4 </head>
5 <body bgcolor=”#a a e e a a ”>
6 <center>
7 <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>
8 <form method=” p o s t ”
9 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 ”>
10 <p>I n t r o d u c e &#355; i :
11 <p>Opera&#355; i a : <s e l e c t name=” o p e r ” >
12 <option value=” dep ”>Depunere
13 <option value=” e x t ”>E x t r a g e r e
14 <option value=” con ”>C o n s u l t a r e
15 </ s e l e c t>
16 <p>
17 <input type=” t e x t ” name=”suma” value=” 0 ”>
18 <p>
19 <input type=” submit ” value=” Executa ”>
20 </form>
21 </ center>
22 </body>
23 </html>

Clientlul care urmăreşte de la distanţa contul are codul


1 import j a v a . i o . IOException ;
2 import j a v a . u t i l . ∗ ;
236 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

3 import j a v a x . management . ∗ ;
4 import j a v a x . management . remote . ∗ ;

6 public c l a s s C l i e n t N o t i f {
7 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
8 S t r i n g h o s t=” l o c a l h o s t ” ;
9 S t r i n g p o r t=” 1099 ” ;
10 i f ( a r g s . l e n g t h ==0){
11 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 ” ) ;
12 System . e x i t ( 0 ) ;
13 }
14 i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ;
15 i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ;
16 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
17 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 ( ) ;
18 try {
19 // Crearea unui c o n e c t o r RMI s i a o b i e c t u l u i de
20 // t i p MBeanServerConnection
21 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ” +
22 h o s t+” : ”+p o r t+” / ”+a r g s [ 0 ] ;
23 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
24 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
25 MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;

27 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 ( ) ;
28 System . out . p r i n t l n ( ” DefaultDomain : ” +domain ) ;
29 // Crearea unui MBean I n t r o
30 S t r i n g className=” Cont ” ;
31 S t r i n g sObjectName=domain+” : t y p e=”+className ;
32 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

34 MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


35 getMBeanResources ( i n f o ) ;

37 // U t i l i z a r e a n o t i f i c a r i i
38 // Crearea unui a s c u l t a t o r
39 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 ( ) ;
40 // A c t i v a r e a n o t i f i c a t o r u l u i
41 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 Thread . s l e e p ( 5 0 0 ) ;
44 // 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
45 System . out . p r i n t l n ( ” P r e s s Enter t o f i n i s h ! ” ) ;
46 try {
47 System . i n . r e a d ( ) ;
48 }
49 catch ( j a v a . i o . IOException e ) { }
50 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 ) ;
51 // 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
52 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
53 }
54 catch ( E x c e p t i o n e ) {
55 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
56 e . printStackTrace ( ) ;
57 }
58 }

60 private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }


61 }
10.1. STANDARD MBEAN 237

63 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 {
64 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 ,
65 O b j e c t handback ) {
66 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 ) ;
67 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=
68 ( AttributeChangeNotification ) n o t i f i c a t i o n ;
69 System . out . p r i n t l n ( ” S o l d i n i t i a l : ” +
70 myNotif . getOldValue ( ) . t o S t r i n g ( ) ) ;
71 System . out . p r i n t l n ( ” S o l d c u r e n t : ” +
72 myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ;
73 }
74 }

Serverul MBean este cel utilizat ı̂n exemplele anterioare.


Serverul MBean este plasat ı̂n servlet (ı̂n catalogul WEB-INF/classes al aplicaţiei)
iar clientul care urmăreşte de la distanţa se poate afla oriunde.
După instalarea servlet-ului se lansează pe maşina acestuia server-ul MBean.
Deoarece notificarea presupune existenţa MBean-ului, iar acesta se instanţează prin
metoda init a servlet-ului este nevoie de apelarea servlet-ului, depunând 0 unităţi.
După această operaţie se lansează ı̂n execuţie programul ClientNotif.
238 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS
Capitolul 11

Teme de laborator

11.1 Probleme propuse


1. Să se realizeze conversia temperaturii exprimată ı̂n grade Celsius ı̂n grade
Fahrenheit şi invers. Formula de transformare este

tF = 1.8tC + 32o F

Eventual, programul server implementează interfaţa (la distanţă)

package conversie;
public interface Grade extends java.rmi.Remote{
public double celsiusToFahrenheit(double celsius)
// throws java.rmi.RemoteException;
public double fahrenheitToCelsius(double fahrenheit)
// throws java.rmi.RemoteException;
}

2. Să se realizeze conversia a unei sume de bani ı̂ntre USD, EURO şi RON.
Ratele de schimb sunt fixate de un obiect ce implementează interfaţa

public interface IRataSchimb{


double OneEuroIsRon();
double OneUsdIsRon();
}

accesibil programului server.


Programul server implementează interfaţa

239
240 CAPITOLUL 11. TEME DE LABORATOR

package exchange;
public interface IConversie extends java.rmi.Remote{
public double usdToEuro(double usd)
// throws java.rmi.RemoteException;
public double usdToRol(double usd)
// throws java.rmi.RemoteException;
public double euroToUsd(double euro)
// throws java.rmi.RemoteException;
public double euroToRol(double euro)
// throws java.rmi.RemoteException;
public double rolToEuro(double rol)
// throws java.rmi.RemoteException;
public double rolToUsd(double rol)
// throws java.rmi.RemoteException;
}

Rata zilnică de schimb se poate prelua dinamic sub forma unui fişier xml,
apelând http://www.bnr.ro/nbrfxrates.xml.

3. Să se realizeze conversia unui număr natural, cuprins ı̂ntre 1 şi 3999, din cifre
arabe ı̂n cifre romane şi invers.

4. Să se realizeze conversia unui număr dintr-o bază ı̂n alta.

5. Unui client ı̂i corespunde un număr ı̂ntreg, valoarea iniţială fiind 0. La o apelare
a serverului, clientul transmite un număr care este adunat la numărul care ı̂i
corespunde clientului. Serverul retransmite clientului valoarea actualizată a
numărului. Să se implementeze serviciul descris.

6. Aplicaţia producător – consumator.


Fie un sistem format din două procese P1 şi P2 , primul producând nişte date
care apoi vor fi preluate de cel de al doilea. Comunicarea ı̂ntre cele două
procese se realizează prin intermediul unei zone de memorie – tampon, – de o
anumită dimensiune, ı̂n care procesul P1 introduce informaţii (sub forma unor
ı̂nregistrări), pe care apoi P2 le extrage.
Procesul P2 nu este nevoit să aştepte pentru fiecare ı̂nregistrare ı̂n parte, iar
P1 nu aşteptă până ce P2 este gata să recepţioneze ı̂nregistrarea produsă.
Procesele evoluează independent unul de celălat, P1 introducând ı̂n tampon
ı̂nregistrarea produsă, de unde P2 o va extrage la nevoie.
Se impun următoarele restricţii:

• Procesul P1 ı̂ncearcă să introducă o ı̂nregistrare ı̂n tampon şi constată


că acesta s-a umplut. În acest caz, el va trebui să aştepte până ce se
iveşte un loc ı̂n tampon (ceea ce se va ı̂ntâmpla ca urmare a extrageri
unei ı̂nregistrări de către P2 ).
11.1. PROBLEME PROPUSE 241

• Procesul P2 ı̂ncearcă să extragă o ı̂nregistrare şi constată că tamponul


este gol. În acest caz el va trebui să aştepte până ce apare o ı̂nregistrare
ca urmare a introduceri unei ı̂nregistrări ı̂n tampon de câtre P1 .

Se defineşte interfaţa

package iprodcons;
public interface IBoundedBuffer extends java.rmi.Remote{
public void put(Object obj) throws java.rmi.RemoteException;
public Object get() throws java.rmi.RemoteException;
}

Se cere:

(a) Implementarea interfeţei IBoundedBuffer.


(b) Realizarea a două programe client Producator, care introduce obiecte ı̂n
tampon şi Consumator pentru extragerea lor.

7. Aplicaţie de e-mail.
Un e-mail este definit printr-un ansamblu de 4 variabile de tip String

(de la (from), catre (to), subiect (subject), mesaj (body)).

package iemail;
import java.io.Serializable;

public class Email implements Serializable {


public String from = "";
public String subject = "";
public String to = "";
public String body = "";

public Email() {}

public Email(String from, String to, String subject, String body) {


this.from =from;
this.subject =subject;
this.to =to;
this.body =body;
}
}

Interfaţa aplicaţiei IEmailServer este

package iemail;
import java.rmi.*;

public interface IEmailServer extends Remote {


public boolean login(String name, String password)
throws RemoteException;
public void createUser(String name, String password)
242 CAPITOLUL 11. TEME DE LABORATOR

throws RemoteException;
public void writeEmail(String from, String to,
String subject, String body) throws RemoteException,
UnknownUserException;
public void readEmail(String userName,ICallbackEmail ce)
throws RemoteException;
}

Un client / utilizator al serviciului sau serverului de e-mail este o instanţă a


clasei User.

package email;
import java.util.*;
import iemail.*;

public class User implements java.io.Serializable{

String name, password;


Vector emails = new Vector();

public User(String name, String password) {


this.name = name;
this.password = password;
}

public void addEmail(Email email) {


emails.addElement(email);
}
}

Pentru a putea folosi serverul de e-mail, un client trebuie ı̂n prealabil să se
ı̂nregistreze (createUser).
Un client ı̂nregistrat se poate conecta la serverul de e-mail (login) după care
poate scrie (trimite) sau citi (recepţiona) mesaje.
Se cere ca la adăgarea unui mesaj (deci ı̂naintea apelării metodei User.addEmail)
să se verifice dacă emitentul este conectat şi dacă destinatarul este ı̂nregistrat.
ı̂n caz contrar se generează excepţia UnknownUserException

package iemail;
public class UnknownUserException extends Exception {

public UnknownUserException() {
super();
}

public UnknownUserException(String exception) {


super(exception);
}
}

Citirea mesajelor este lăsată la latitudinea clienţilor ı̂n sensul că clientul im-
plementează metoda printEmail al interfeţei ICallbackEmail.
11.1. PROBLEME PROPUSE 243

package iemail;
import java.rmi.*;
import java.rmi.server.*;

public interface ICallbackEmail extends Remote {


public void printEmail(Email email) throws RemoteException;
}

Solicitarea recepţionării mesajelor se realizează de către server prin apelarea


metodei printEmail pentru fiecare mesaj primit de client.
Se cere:

(a) Implementarea interfeţei IEmailServer.


(b) Realizarea a două programe client AddClient pentru ı̂nregistrarea utiliza-
torilor şi ClientEmail pentru exploatarea serviciului de e-mail. Fiecare
din cele două programe are ca parametri numele (identificatorul) clientu-
lui, parola şi referinţa serverului.

8. Integrare numerică.
Scopul aplicaţiei este calculul unei integrale de un program server cu funcţia
de integrat deţinută de către client. Evaluările funcţiei cerute de formula de
integrare numerică se vor realiza prin apel invers. Integrarea numerică va
fi executat de un server disponibil clienţilor prin mecanismul de fabrică de
obiecte.
Interfaţa fabricii de obiecte este

package integ;
import java.rmi.*;
public interface IFabIntegrator extends Remote{
IIntegrator getIntegrator() throws RemoteException;
}

iar interfaţa IIntegrator este

package integ;
import java.rmi.*;
public interface IIntegrator extends Remote{
double adaptiveSimpson(double leftEnd, double rightEnd,
double epsilon, int initParam) throws RemoteException;
}

declară o metodă ce calculează un şir (Imk )k până ı̂n momentul |Imk −Imk−1 | <
ε.
Propunem utilizarea formulei lui Simpson

b m−1 m−1
b−a
Z X X
f (x)dx ≈ Im = [f (a) + 2 f (a2i ) + 4 f (a2i+1 ) + f (b)]
a 6m i=1 i=0
244 CAPITOLUL 11. TEME DE LABORATOR

unde ai = a + i b−a
2m .
Şirul (mk )k este definit prin mk = 2k m0 .
Semnificaţia parametrilor metodei adaptiveSimpson este

leftEnd a
rightEnd b
epsilon ε
initParam m0

Interfaţa apelului invers este

package integ;
import java.rmi.*;
double function(double x)throws RemoteException;
}

Se cere implementarea aplicaţiei cu minimizarea numărului de apelări a metodei


function.

9. Agendă telefonică.
Pentru crearea şi ı̂ntreţinerea unei agende telefonice considerăm:
Un ServerCarteTelefon realizează următoarele operaţii:

• adaugă o ı̂nregisrare ı̂n agenda telefonică;


O ı̂nregistrare este alcătuită dintr-o pereche (nume, număr).
package itelef;
import java.io.Serializable;
public class Entry implements Serializable{
public String nume,numar;

public Entry(String nume,String numar){


this.nume=nume;
this.numar=numar;
}
}

• sterge ı̂nregistrarea corespunzătoare unui nume din agenda telefonică.


• interogarea agendei: furnizează numărul de telefon al unui nume;
• modificarea numărului de telefon corespunzător unui nume;
• afişarea ı̂nregistrărilor;
• salvarea ı̂nregistrărilor ı̂ntr-un fişier;
• restaurarea ı̂nregistrărilor dintr-un fişier.

Interfaţa corespunzătoare ICarteTelefon este


11.1. PROBLEME PROPUSE 245

package itelef;
import java.rmi.*;
public interface ICarteTelefon extends Remote{
void addEntry(Entry e)throws RemoteException;
String lookupNumber(String p)throws RemoteException;
void deleteEntry(Entry e)throws RemoteException;
Entry[] list() throws RemoteException;
void save(String file)throws RemoteException;
void restore(String file)throws RemoteException,ClassNotFoundException;
void modifyEntry(Entry e)throws RemoteException;
}

Interfaţa fabricii de obiecte IFabCarteTelefon este

package itelef;
import java.rmi.*;
public interface IFabCarteTelefon extends Remote{
ICarteTelefon getCarteTelefon() throws RemoteException;
}

Se cere implementarea aplicaţiei de creare şi ı̂ntreţinere a agendei telefonice.


Se extinde aplicaţia anterioară cu funcţiunea suplimentară a serverului de a
reţine toate modificările efectuate de către un client şi care la solicitare pot fi
afişate.
Modificările se reţin ı̂ntr-o variabilă mod de tip Vector. La solicitarea clien-
tului, pentru fiecare modificare memorată, programul server apelează metoda
schimbStare declarată ı̂n interfaţa

package itelef;
import java.rmi.*;

public interface IApelInvers extends Remote{


void schimbStare(Entry e) throws RemoteException;
}

Metoda schimbStare(Entry e) nu face altceva decât afişează câmpurile vari-


abilei e.
Interfaţa ICarteTelefon declară ı̂n plus metoda

void apelInvers(IApelInvers obj)throws RemoteException;

Această metodă va fi implementată ı̂n programul ServerCarteTelefon.java.


Elementelor reţinute ı̂n vectorul mod li se aplică metoda schimbStare().
Să se implementeze acestă funcţiune utilizând tehnica apelului invers.
Se poate utiliza baza de date AGENDATELEFONICA formată din tabelul
246 CAPITOLUL 11. TEME DE LABORATOR

TELEF
ID
NUME
NUMAR

10. Să se realizeze programe client având o interfaţă grafică. Recomandăm uti-
lizarea produsului NetBeans.
R. Exemplu de client pentru problema calculului celui mai mare divizor comun
a două numere cu soclu TCP.

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

public class VisualCmmdcClient extends javax.swing.JFrame {


public VisualCmmdcClient() {
initComponents();
}

private void initComponents(){


// cod generat de Netbeans
}

private void jButton1MouseClicked(java.awt.event.MouseEvent evt){


long m=(new Long(jTextField1.getText())).longValue();
long n=(new Long(jTextField2.getText())).longValue();
String host=jTextField4.getText();
int port=(new Integer(jTextField5.getText())).intValue();
Socket cmmdcSocket = null;
DataInputStream in=null;
DataOutputStream out=null;
try {
cmmdcSocket = new Socket(host, port);
out=new DataOutputStream(cmmdcSocket.getOutputStream());
in=new DataInputStream(cmmdcSocket.getInputStream());
}
catch(UnknownHostException e) {
System.err.println("Server necunoscut: "+host);
System.exit(1);
}
catch (IOException e) {
System.err.println("Eroare I/O : "+host+" la portul "+port);
System.exit(1);
}
try{
out.writeLong(m);
out.writeLong(n);
long r=in.readLong();
jTextField3.setText(new Long(r).toString());
out.close();
in.close();
cmmdcSocket.close();
}
catch(IOException e){
System.err.println("Imposibilitate de comunicare");
11.1. PROBLEME PROPUSE 247

}
}

private void exitForm(java.awt.event.WindowEvent evt) {


System.exit(0);
}

public static void main(String args[]) {


new VisualCmmdcClient().setVisible(true);
}

private javax.swing.JButton jButton1;


private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JTextField jTextField1;
private javax.swing.JTextField jTextField2;
private javax.swing.JTextField jTextField3;
private javax.swing.JTextField jTextField4;
private javax.swing.JTextField jTextField5;
}

11. Să se determine zodia (chinezească) corespunzătoare unei date calendaristice.

12. Să se convertească unităţile de masură pentru masă şi lungime ı̂ntre sistemul
internaţional şi sistemul anglo-saxon.

13. Se consideră baza de date NORME-DIDACTICE formată din tabelele

CADRU-DIDACTIC MATERIA CURSURI


COD-CADRU-DIDACTIC COD-MATERIE COD-CURS
NUME DENUMIRE COD-CADRU-DIDACTIC
COD-MATERIE

Să se elaboreze programe de ı̂ntreţinere şi interogare a bazei de date.

14. Se consideră baza de date APROVIZIONARE formată din tabelele

RESURSA FURNIZOR CONTRACT


COD-RESURSA COD-FURNIZOR COD-CONTRACT
DENUMIRE NUME COD-FURNIZOR
CANTITATE COD-RESURSA
CANTITATE

Să se elaboreze programe de ı̂ntreţinere şi interogare a bazei de date.

15. Se consideră baza de date DESFACERE formată din tabelele


248 CAPITOLUL 11. TEME DE LABORATOR

PRODUSE BENEFICIAR CONTRACT


COD-PRODUS COD-BENEFICIAR COD-CONTRACT
DENUMIRE NUME COD-BENEFICIAR
CANTITATE COD-PRODUS
CANTITATE

Să se elaboreze programe de ı̂ntreţinere şi interogare a bazei de date.


Appendix A

XML

Extended Markup Language (XML) reprezintă un limbaj pentru definirea mar-


cajelor de semantică care ı̂mpart un document ı̂n părţi şi permit identificarea lor ı̂n
document.
Totodată XML este un meta-limbaj pentru definirea sintaxei de utilizat ı̂n alte
domenii.
XML descrie structura şi semantica şi nu formatarea.
Structura unui document xml este

<?xml version="1.0" encoding="ISO-8859-1"?>


corpul documentului alcatuit din elemente

Prima linie reprezintă declaraţia de document XML.


Corpul documentului este alcătuit din elemente. Începutul unui element este
indicat printr-un marcaj. Textul marcajului constituie denumirea elementului. El-
ementele pot fi cu corp, alcătuit din alte elemente, având sintaxa

<marcaj>
corpul elementului
</marcaj>

sau fără corp, caz ı̂n care sintaxa este

<marcaj/>

Un marcaj poate avea atribute date prin sintaxa


numeAtribut="valoareAtribut"
Valoarea unui atribut este cuprinsă ı̂ntre ghilimele (””).
Există un singur element rădăcină. Elementele unui document XML formează un
arbore. Fiecărui marcaj de ı̂nceput unui element trebuie să-i corespundă un marcaj

249
250 APPENDIX A. XML

de sfârşit. Caracterele mari şi mici din denumirea unui element sunt distincte (case
sensitive).
Elementele ı̂ncuibărite (nested )- incluse ı̂ntr-un alt element - nu se pot amesteca.
Un comentariu se indică prin
<!--
Text comentariu
-->

Exemplul A.0.1

1 <?xml version=” 1 . 0 ” e n c o d i n g=” u t f −8” ?>


2 <c u r s u r i>
3 < d i s c i p l i n a f e l =” o b l i g a t o r i u ”>
4 <nume> A n a l i z a numerica </nume>
5 <fond−de−timp>
6 <c u r s> 2 </ c u r s>
7 <s e m i n a r> 1 </ s e m i n a r>
8 <l a b o r a t o r> 1 </ l a b o r a t o r>
9 </ fond−de−timp>
10 </ d i s c i p l i n a>
11 < d i s c i p l i n a f e l =” o b l i g a t o r i u ”>
12 <nume> Programare d i s t r i b u i t a </nume>
13 <fond−de−timp>
14 <c u r s> 2 </ c u r s>
15 <s e m i n a r> 0 </ s e m i n a r>
16 <l a b o r a t o r> 2 </ l a b o r a t o r>
17 </ fond−de−timp>
18 </ d i s c i p l i n a>
19 < d i s c i p l i n a f e l =” o b l i g a t o r i u ”>
20 <nume> S o f t matematic </nume>
21 <fond−de−timp>
22 <c u r s> 2 </ c u r s>
23 <s e m i n a r> 0 </ s e m i n a r>
24 <l a b o r a t o r> 1 </ l a b o r a t o r>
25 </ fond−de−timp>
26 </ d i s c i p l i n a>
27 </ c u r s u r i>

Spaţii de nume – Namespace. Pentru rezolvarea problemei coliziunii iden-


tificatorilor ı̂n documente XML s-a introdus mecanismul numelor (identificatorilor)
calificaţi:
Nume calificat= Spaţiu de nume + Nume local
Un spaţiu de nume se indică printr-un identificator de resursă uniformă - URI
(Uniform Resourse Identifier). Sintaxa unui spaţiu de nume coincide cu cea a unui
URL (Uniform Resource Locator). Adresa respectivă nu trebuie să corespundă unei
resurse ı̂n Internet.
Spaţiul de nume se specifică prin intermediul atributului xmlns
<element xmlns=identidicatorul spatiului de nume >
251

sau

<prefix:element xmlns:prefix=identidicatorul spatiului de nume >

Dacă un element se declară ca aparţinând unui spaţiu de nume, atunci şi el-
ementele incluse aparţin aceluiaşi spaţiu de nume, exceptând cazurile ı̂n care se
specifică explicit, prin prefix, alt spaţiu de nume.

Exemplul A.0.2

1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>


2 <m a t e r i i xmlns=” h t t p : // c s . u n i t b v . r o / i n f o ”
3 xmlns:math=” h t m l : // c s . u n i t b v . r o /math” >
4 <AnalizaNumerica>
5 <an> 2 </ an>
6 <fond−de−timp> 2−1−1 </ p l a n>
7 </ AnalizaNumerica>
8 <math:AnalizaNumerica>
9 <an> 2 </ an>
10 <fond−de−timp> 2−1−1 </ p l a n>
11 </ math:AnalizaNumerica>
12 </ m a t e r i i>

Legat de un document XML se ridică problemele:

• Verificarea corectitudinii;

• Validarea documentului relativ la elementele folosite;

• Utilizarea / prelucrarea / consultarea datelor documentului XML ı̂ntr-un lim-


baj de programare.
252 APPENDIX A. XML
Appendix B

Apache-ant

Utilitarul Apache-ant asigură executarea unui şir de comenzi de operare. Aceste


comenzi se ı̂nregistrează ı̂ntr-un fişier de tip xml, cu denumirea build.xml. Astfel
Apache-ant se substituie unui fişier de comenzi bat. Avantajul obţinut constă ı̂n
independenţa faţă de platforma de calcul (Windows, Linux).

Instalarea constă ı̂n dezarhivarea fişierului descărcat de pe pagina Web www.apache.org.


Lansarea ı̂n execuţie necesită fixarea parametrului JAVA HOME, ce conţine
calea la distribuţia Java. Lansarea se poate face prin următorul fişier de comenzi

set ANT_HOME=. . .
set JAVA_HOME=. . .
set PATH=%ANT_HOME%\bin;%PATH%
ant.bat %1

Parametrul acestui fişier de comenzi reprezintă obiectivul care se doreşte a fi


atins.
Fişierul build.xml. Un fişier build.xml corespunde unui proiect (project),
alcătuit din una sau mai multe obiective (target). Atingerea fiecarărui obiectiv
constă din indeplinirea uneia sau mai multor sarcini (task). Apache-ant conţine o
familie de sarcini. Programatorul are datoria fixării atributelor sarcinilor. Manu-
alul din documentaţia produsului conţine descrierea atributelor cât şi exemple. În
general, o sarcină reprezintă o operaţie executată uzual ı̂n linia de comandă.
Atributele se dau, respectând sintaxa xml

numeAtribut = ”valoareAtribut”

Astfel, un proiect apare sub forma

<project name="numeProiect"
default="obiectiv"

253
254 APPENDIX B. APACHE-ANT

basedir="catalogDeReferinta">

<target name="numeObiectiv">
sarcini
</target>
. . . . . . .
</project>

Dacă la apelarea lui Apache-ant lipseşte parametrul opţional atunci se va executa


obiectivul default.
Într-un proiect se pot defini variabile prin marcajul

<property name=”numeVariabila” value=”valoareVariabila” />

O variabilă se utilizează prin sintaxa ${numeVariabila}

Exemplul B.0.3 Fişierul build pentru execuţia programelor din §1.2.

1 <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=” . ”>


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

4 < !−− 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 −−>


5 <p r o p e r t y name=” b u i l d ” l o c a t i o n=” work ” />
6 <p r o p e r t y name=” s r c ” l o c a t i o n=” . ” />

8 <t a r g e t name=” i n i t ”>


9 < !−− C r e a t e t h e time stamp −−>
10 <tstamp />
11 < !−− 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 −−>
12 <d e l e t e d i r=” ${ b u i l d } ” />
13 <mkdir d i r=” ${ b u i l d } ” />
14 <copy f i l e =” ${ s r c }\ CmmdcClient . j a v a ” t o d i r=” ${ b u i l d } ” />
15 <copy f i l e =” ${ s r c }\ MyMServer . j a v a ” t o d i r=” ${ b u i l d } ” />
16 <copy f i l e =” ${ s r c }\ AppThread . j a v a ” t o d i r=” ${ b u i l d } ” />
17 <copy f i l e =” ${ s r c }\App . j a v a ” t o d i r=” ${ b u i l d } ” />
18 <copy f i l e =” ${ s r c }\ VisualCmmdcClient . j a v a ” t o d i r=” ${ b u i l d } ” />
19 </ t a r g e t>

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


22 <j a v a c s r c d i r=” ${ b u i l d } ” d e s t d i r=” ${ b u i l d } ” />
23 </ t a r g e t>

25 <t a r g e t name=” S e r v e r ” depends=” Compile ”>


26 <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 ” />
27 </ t a r g e t>

29 <t a r g e t name=” C l i e n t ”>


30 <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 ” />
31 </ t a r g e t>
32 </ p r o j e c t>

Utilizarea lui apache-ant presupune că toate resursele utilizate, cuprinse uzual
ı̂n fişiere cu extensia jar (j ava ar hive) sunt disponibile pe calculatorul local. Dacă
255

calculatorul este conectat la Internet, atunci resursele publice pot fi descărcate


ı̂mpreună cu toate dependinţele şi utilizate prin apache-ant, folosind suplimentar
apache-ivy 1 .
Fişierul build.xml conţine ı̂n plus

<project name="Proiect" basedir="." default="obiectiv_final"


xmlns:ivy="antlib:org.apache.ivy.ant">

. . .
<!-- =================================
target: resolve
================================= -->
<target name="resolve" depends="init"
description="--> retreive dependencies with ivy">
<ivy:retrieve/>
</target>

<!-- =================================
target: report
================================= -->
<target name="report" depends="resolve"
description="--> generates a report of dependencies">
<ivy:report todir="${report.dir}"/>
</target>
. . .
</project>

la care se adaugă un fişier ivy.xml, cu dependinţele necesare aplicaţiei care urmează


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>

1
Asemănător cu maven, un alt produs de dezvoltare.
256 APPENDIX B. APACHE-ANT
Appendix C

Utilizarea SGBD ı̂n Java

Scopul acestei anexe este prezentarea bazelor utilizării unui sistem de gestiune a
bazelor de date (SGBD) din Java. Exemplificăm modul de operare şi utilizare pentru
crearea şi exploatarea unei baze de date corespunzătoare unei agende telefonice.

C.1 Derby
Instalarea produsului constă ı̂n dezarhivarea fişierului descărcat ı̂n catalogul
jdk*.*.*\db.
Utilizarea produsului. Va fi utilizată varianta de reţea bazată pe un server al
SGBD care utilizează implicit portul 1527.
Se ı̂ntreprind următoarele operaţii:
1. Lansarea serverului Derby:
set JAVA_HOME=. . .
set DERBY_HOME=. . .
set PATH=%DERBY_HOME%\bin;%PATH%
startNetworkServer.bat

2. Crearea bazei de date se va face utilizând utilitarul ij din distribuţia Derby.


Acesta se lansează prin:
set JAVA_HOME=. . .
set DERBY_HOME=. . .
set PATH=%DERBY_HOME%\bin;%PATH%
ij.bat

Exemplul C.1.1

Baza de date AgendaTelefonica se crează executând


run ’CreateAgendaT.sql’;

unde fişierul CreateAgendaT.sql este

257
258 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

1 connect ’ j d b c : derby : A g e n d a T e l e f o n i c a ; c r e a t e=t r u e ’ ;


2 create table t e l e f (
3 i d i n t g e n e r a t e d a l w a y s as i d e nt i t y ( s t a r t with 1 , i n c r e m e n t by 1 )
4 primary key ,
5 nume char ( 2 0 ) not null ,
6 numar char ( 1 3 ) not n u l l
7 );

şi ı̂ncărcarea cu date


run ’ValuesAgendaT.sql’;

cu fişierul ValuesAgendaT.sql
1 i n s e r t into t e l e f values ( ’ aaa ’ , ’ 111111 ’ ) , ( ’ bbb ’ , ’ 222222 ’ ) ,
2 ( ’ c c c ’ , ’ 333333 ’ ) ;

C.2 mysql
Instalarea produsului. Pentru instalare s-a descărcat varianta fără instalare
automată mysql-noinstall-*.*.*-win32.zip. Acest fişier se dezarhivează ı̂ntr-un cata-
log MYSQL HOME.
Implicit, serverul mysql utilizează portul 3306, iar fişierele bazelor de date vor fi
găzduite ı̂n catalogul MYSQL HOME\data.
Pentru utilizarea ı̂n aplicaţii Java trebuie descărcat un conector mysql-connector-
java-*.*.*.tar.gz, conţinând fişierul mysql-connector-java-
*.*.*-bin.jar.
Utilizarea produsului.
Se ı̂ntreprind următoarele operaţii:

1. Lansarea serverului mysql :

set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld

2. Exemplul C.2.1
Crearea bazei de date AgendaTelefonica se va face prin intermediul fişierului
de comenzi

set MYSQL_HOME=d:\mysql-*-win32\bin
set path=%MYSQL_HOME%;%PATH%
mysql -u root < CreateAgendaT.sql
mysql -u root < ValuesAgendaT.sql

unde scriptul CreateAgendaT.sql este


C.3. POSTGRSQL 259

1 create d a t a b a s e A g e n d a T e l e f o n i c a ;
2 use AgendaTelefonica ;

4 create table t e l e f (
5 i d i n t primary key a u t o i n c r e m e n t not null ,
6 nume char ( 2 0 ) not null ,
7 numar char ( 1 3 ) not n u l l
8 );

iar scriptul de populare cu date (ValuesAgendaT.sql ) este


1 use AgendaTelefonica ;
2 i n s e r t t e l e f values ( ” aaa ” , ” 111111 ” ) ;
3 i n s e r t t e l e f values ( ”bbb” , ” 222222 ” ) ;
4 i n s e r t t e l e f values ( ” c c c ” , ” 333333 ” ) ;

3. Serverul mysql se opreşte prin

set MYSQL_HOME=d:\mysql-5.0.45-win32
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqladmin -u root shutdown

C.3 PostgrSQL
Instalarea produsului. PostgreSQL este distribuit gratuit. Pentru sistemul de
operare Windows se descarcă o distribuţie cu instalare. Cu drepturi de administrator
al sistemului gazdă, se execută instalarea cu serverul PostgreSQL drept serviciu
Windows. Comunicaţia cu acest server se face prin portul 5432.
Pentru utilizarea ı̂n aplicaţii Java trebuie descărcat un conector postgresql-*.*-
*.jdbc4.jar.
Utilizarea produsului.

Exemplul C.3.1

Crearea aceleiaşi baze de date AgendaTelefonică se face cu fişierul de comenzi


set PGHOME=d:\PostgreSQL
set PATH=%PGHOME%\8.3\bin;%PATH%
psql -U postgres -f createdb.sql
psql -U user -d AgendaTelefonica -f createtable.sql
psql -U user -d AgendaTelefonica -f insertvalues.sql

user este numele unui cont PostgreSQL care se poate crea cu componenta de
administrare pgAdmin III, prin meniul Login Role / New Login Role.
Script-urile sql sunt
createdb.sql
create database "AgendaTelefonica" encoding ’utf8’ owner user;
260 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

createtable.sql
create table telef(id int4 primary key,
nume varchar(20) not null, numar varchar(15) not null);

insertvalues.sql
insert into telef values(1,’aaa’,’111111’);
insert into telef values(2,’bbb’,’222222’);
insert into telef values(3,’ccc’,’333333’);

C.4 Şablonul de utilizare a unei baze de date ı̂ntr-un


program Java
Pentru a avea acces la o bază de date trebuie stabilită o conexiune la acea bază
de date. În acest sens este necesar cunoaşterea:

• driver-ului de acces la sistemul de gestiune a bazei de date (SGBD) (String


jdbcDriver)
Tip SGBD Driver Fişierul
driver-ului
access sun.jdbc.odbc.JdbcOdbcDriver
mysql com.mysql.jdbc.Driver mysql-connector-java-*.*.*-bin.jar
(www.mysql.com)
derby org.apache.derby.jdbc.ClientDriver derbyclient.jar
(distribuţia derby)
postgrsql org.postgresql.Driver postgresql-*.*-*.jdbc4.jar

Dacă ı̂ntr-un servlet se realizează o conexiune la o bază de date atunci fişierul


driver-ului trebuie copiat ı̂n catalogul lib al aplicaţiei.

• adresa URL a bazei de date (String URLBazaDate), sub forma

jdbc:protocol://host:port/numeBazaDate

unde protocol este


Tip SGBD Protocol
access odbc
mysql mysql
derby derby
postgresql postgresql

Şablonul de prelucrare este


C.4. ŞABLONUL DE UTILIZARE ÎNTR-UN PROGRAM JAVA 261

String jdbcDriver=. . .
String URLBazaDate=. . .
Connection con=null;
try{
//Class.forName(jdbcDriver).newInstance();
con=DriverManager.getConnection(URLBazaDate);
...
}
//catch(ClassNotFoundException e){. . .}
catch(SQLException e){. . .}

Liniile comentate sunt necesare doar ı̂n cazul ı̂n care se lucrează cu o distribuţie
Java mai mică decât 1.6.0.
Odată conexiunea cu baza de date stabilită se generează un obiect de tip Statement
prin intermediul căruia se execută interogarea SQL.

Statement instructiune=con.createStatement();
String sql=. . . //fraza select;

Rezultatele interogării bazei de date se obţine prin

try{
ResultSet rs=instructiune.executeQuery(sql);
while(rs.next()){
prelucrarea rezultatului
}
}
catch(SQLException e){...}

Exemplul C.4.1

O interogare simplă a bazei de date AgendaTelefonica se realizează cu programul


1 import java . io . ∗ ;
2 import java . s q l . ∗ ;
3 import java . net . ∗ ;
4 import java . u t i l . ∗ ;

6 public c l a s s AgendaT {
7 Statement i n s t r u c t i u n e=n u l l ;

9 public void i n i t ( ) {
10 // SGBD Derby
11 /∗
12 S t r i n g j d b c D r i v e r =”o r g . apache . d e r b y . j d b c . C l i e n t D r i v e r ” ;
13 S t r i n g URLBazaDate=” j d b c : d e r b y : / / l o c a l h o s t : 1 5 2 7 / A g e n d a T e l e f o n i c a ” ;
14 ∗/
15 // SGBD mysql
262 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

16 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 ” ;
17 S t r i n g URLBazaDate=
18 ” j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / A g e n d a T e l e f o n i c a ? u s e r=r o o t ” ;

20 // PostgreSQL
21 /∗
22 S t r i n g j d b c D r i v e r =”o r g . p o s t g r e s q l . D r i v e r ” ;
23 S t r i n g URLBazaDate=” j d b c : p o s t g r e s q l : / / l o c a l h o s t : 5 4 3 2 / A g e n d a T e l e f o n i c a ” ;
24 S t r i n g username =”. . . ” ;
25 S t r i n g password =”. . . ” ;
26 ∗/

28 C o n n e c t i o n con=n u l l ;
29 try {
30 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 ( ) ;
31 con=DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ;
32 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 ( ) ;
33 }
34 catch ( ClassNotFoundException e ) {
35 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 ) ;
36 }
37 catch ( SQLException e ) {
38 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 ) ;
39 }
40 catch ( E x c e p t i o n e ) {
41 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 ( ) ) ;
42 }
43 }

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


46 AgendaT agenda=new AgendaT ( ) ;
47 agenda . i n i t ( ) ;
48 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
49 i n t p r e l , no ;
50 S t r i n g ch=”Y” , nume=” ” , numar=” ” , s q l=” ” ;
51 R e s u l t S e t r s=n u l l ;
52 try {
53 while ( ch . s t a r t s W i t h ( ”Y” ) ) {
54 do{
55 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;
56 ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
57 }
58 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” ) ) ) ;
59 i f ( ch . s t a r t s W i t h ( ”Y” ) ) {
60 System . out . p r i n t l n ( ” Natura i n t e r o g a r i i ? ” ) ;
61 System . out . p r i n t l n ( ” ( Dupa nume : 1 , Dupa numar : 2 ) ” ) ;
62 do{
63 p r e l =0;
64 try {
65 p r e l=s c a n n e r . n e x t I n t ( ) ;
66 }
67 catch ( InputMismatchException e ) { }
68 }
69 while ( ( p r e l <1)&&( p r e l > 2 ) ) ;
70 switch ( p r e l ) {
71 case 1 :
72 System . out . p r i n t l n ( ”Numele” ) ;
73 nume= ’ \ ’ ’+s c a n n e r . n e x t ( ) . t r i m ()+ ’ \ ’ ’ ;
74 s q l=” s e l e c t ∗ from t e l e f where nume=”+nume ;
C.4. ŞABLONUL DE UTILIZARE ÎNTR-UN PROGRAM JAVA 263

75 r s=agenda . i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ;
76 i f ( r s != n u l l ) {
77 System . out . p r i n t l n ( ”S−au g a s i t n u m e r e l e de t e l e f o n : ” ) ;
78 while ( r s . n e x t ( ) ) {
79 System . out . p r i n t l n ( r s . g e t S t r i n g ( ”numar” ) ) ;
80 }
81 }
82 else {
83 System . out . p r i n t l n ( ” Fara t e l e f o n ! ” ) ;
84 }
85 break ;
86 case 2 :
87 System . out . p r i n t l n ( ”Numar” ) ;
88 numar= ’ \ ’ ’+s c a n n e r . n e x t ( ) . t r i m ()+ ’ \ ’ ’ ;
89 s q l=” s e l e c t ∗ from t e l e f where numar=”+numar ;
90 r s=agenda . i n s t r u c t i u n e . e x e c u t e Q u e r y ( s q l ) ;
91 i f ( r s != n u l l ) {
92 System . out . p r i n t l n ( ”S−a g a s i t numeley ” +
93 ”y : ” ) ;
94 while ( r s . n e x t ( ) ) {
95 System . out . p r i n t l n ( r s . g e t S t r i n g ( ”nume” ) ) ;
96 }
97 }
98 else {
99 System . out . p r i n t l n ( ”Numar i n e x i s t e n t ! ” ) ;
100 }
101 break ;
102 default : System . out . p r i n t l n ( ”Comanda e r o n a t a ” ) ;
103 }
104 }
105 }
106 }
107 catch ( E x c e p t i o n e ) {
108 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 ( ) ) ;
109 }
110 }
111 }

Fraza select şi interogarea se mai putea programa prin


String sql="select * from telef where nume =?";
PreparedStatement prepStmt=con.prepareStatement(sql);
prepStmt.setString(1,nume);
RezultSet rs=prepStmt.executeQuery();
. . .
prepStmt.close();
În acest caz, valoarea variabilei nume este fără apostroafe.
Compilarea şi execuţia programului necesită declararea ı̂n variabila classpath
a fişierelor
• Varianta Derby
derby.jar, derbytools.jar, derbyclient.jar, derbynet.jar din cata-
logul %DERBY INSTALL%\lib.
264 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

• Varianta mysql
%MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar

Execuţia programului presupune serverul SGBD activ.

C.5 Java Persistence API - JPA


Interfaţa JPA este standardizarea accesului din Java la un SGBD relaţional. JPA
este un strat care se interpune ı̂ntre programul Java şi SGBD. Avantajul oferit de
JPA constă ı̂n independenţa programelor Java de SGBD utilizat.
Din punct de vedere al programării, rezultatul interogării unei baze de date este
un obiect.
JPA conţine:

• Persistence: Clasa javax.persistence.Persistence conţine metode statice


pentru obţinerea unei instanţe a clasei EntityManagerFactory, ı̂ntr-o manieră
independentă de producătorul JPA.

• EntityManagerFactory: Clasa javax.persistence.EntityManagerFactory


este producătorul obiectelor EntityManager.

• EntityManager : javax.persistence.EntityManager este actorul JPA prin-


cipal ı̂ntr-o aplicaţie. Un obiect EntityManager mijloceşte ı̂ntreţinerea şi in-
terogarea unei baze de date. Fiecărui obiect de tip EntityManager i se asociază
un obiect de tip javax.persistence.EntityTransaction.

• Entity: Obiectele Entity corespund ı̂nregistrărilor ı̂n tabelele bazei de date.

• EntityTransaction: asigură integritatea bazei de date. Operaţiile care privesc


persistenţa datelor sunt grupate ı̂n unităţi de lucru care sunt executate cu
succes sau deloc.

• Query: Interfaţa javax.persistence.Query este specifică implementării. Prin


obiecte de tip Query se asigură accesul la baza de date. Portivit standardu-
lui JPA este suportat atât limbajul Structured Query Language (SQL) cât şi
Java Persistence Query Language (JPQL). Un obiect Query este instanţiat
prin obiecte EntityManager.

Există mai multe implementări a interfeţei JPA.

C.5.1 apache-openjpa
Aşa cum sugerează numele produsului, openjpa este implementarea oferită de
apache.
C.5. JAVA PERSISTENCE API - JPA 265

Instalarea revine la dezarhivarea fişierului descărcat.


Utilizarea. Compilarea şi execuţia unei aplicaţii o vom face prin intermediul
lui apache-ant. Construim structura de cataloage şi fişiere:
|--> catalogul_aplicatiei
|--> META-INF
| | persistence.xml
| build.xml
Fişierul persistence.xml specifică unităţile de persistenţă. Fiecare unitate de
persistenţă corespunde unui tabel al bazei de date şi i se asociază o clasă Entity,
de fapt o componentă Java. Clasa şi tabelul au acelaşi nume. Doar tabelele cărora
li s-a declarat o unitate de persistenţă pot fi accesate prin apache-openjpa.
Principial fişierul persistence.xml este
1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 < 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 ”
3 x m l n s : x s i=” h t t p : //www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
4 version=” 1 . 0 ”>

6 < !−−
7 We need t o enumerate each p e r s i s t e n t c l a s s f i r s t i n t h e p e r s i s t e n c e . xml
8 S e e : h t t p : // i s s u e s . apache . o r g / j i r a / browse /OPENJPA−78
9 −−>
10 <p e r s i s t e n c e −u n i t name=” none ” t r a n s a c t i o n −t y p e=”RESOURCE LOCAL”>
11 < c l a s s>E n t i t y c l a s s n a m e</ c l a s s>
12 </ p e r s i s t e n c e −u n i t>

14 < !−−
15 A p e r s i s t e n c e u n i t i s a s e t o f l i s t e d p e r s i s t e n t e n t i t i e s as w e l l
16 t h e c o n f i g u r a t i o n o f an E n t i t y M a n a g e r F a c t o r y . We c o n f i g u r e each
17 example i n a s e p a r a t e p e r s i s t e n c e −u n i t .
18 −−>
19 <p e r s i s t e n c e −u n i t name=” P e r s i s t e n c e u n i t n a m e ”
20 t r a n s a c t i o n −t y p e=”RESOURCE LOCAL”>
21 < !−−
22 The default p r o v i d e r can be OpenJPA , or some o t h e r p r o d u c t .
23 This e l e m e n t i s o p t i o n a l i f OpenJPA i s t h e o n l y JPA p r o v i d e r
24 i n t h e c u r r e n t c l a s s l o a d i n g environment , b u t can be s p e c i f i e d
25 i n c a s e s where t h e r e a r e m u l t i p l e JPA i m p l e m e n t a t i o n s a v a i l a b l e .
26 −−>
27 < !−−
28 <p r o v i d e r>
29 o r g . apache . o p e n j p a . p e r s i s t e n c e . P e r s i s t e n c e P r o v i d e r I m p l
30 </ p r o v i d e r>
31 −−>

33 < !−− We must enumerate each e n t i t y i n t h e p e r s i s t e n c e u n i t −−>


34 < c l a s s>appagenda . T e l e f</ c l a s s>

36 <p r o p e r t i e s>
37 < !−−
38 We can c o n f i g u r e t h e default OpenJPA p r o p e r t i e s h e r e . They
39 happen t o be commented o u t h e r e s i n c e t h e p r o v i d e d e x a m p l e s
40 a l l s p e c i f y t h e v a l u e s v i a System p r o p e r t i e s .
41 −−>
266 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

43 < !−−
44 <p r o p e r t y name=” o p e n j p a . ConnectionURL ”
45 v a l u e=” j d b c : d e r b y : o p e n j p a −d a t a b a s e ; c r e a t e=t r u e ” />
46 <p r o p e r t y name=” o p e n j p a . ConnectionDriverName ”
47 v a l u e=” o r g . apache . derby . j d b c . EmbeddedDriver ” />
48 <p r o p e r t y name=” o p e n j p a . ConnectionUserName ”
49 v a l u e=” u s e r ” />
50 <p r o p e r t y name=” o p e n j p a . ConnectionPassword ”
51 v a l u e=” s e c r e t ” />
52 −−>
53 </ p r o p e r t i e s>
54 </ p e r s i s t e n c e −u n i t>
55 </ p e r s i s t e n c e>

Atributele ce apar ı̂n comentarii, pot fi specificate şi prin proprietăţi System.
Şablonul de prelucrare este

EntityManagerFactory factory=
Persistence.createEntityManagerFactory("nume_unitate_de_persistenta",
System.getProperties());
EntityManager em=factory.createEntityManager();
em.getTransaction().begin();
String sql=fraza SQL sau JPQL
Query query=em.createQuery(sql);

// introducerea unei inregistrari


em.persist(obiect_Entity)

// actualizarea sau stergerea unei inregistrari


query.executeUpdate();

// interogare bazei de date


List result=query.getResultList();

em.getTransaction().commit();
em.close();
factory.close();

Dacă fraza SQL este specifică unui SGBD atunci obiectul de tip Query se instanţiază
prin

Query query=em.createNativeQuery(sql,clasa_Entity_utilizata.class);

Exemplul C.5.1 Aplicaţie pentru ı̂ntreţinerea şi interogarea bazei de date Agen-
daTelefonica.

Tabelei telef a bazei de date ı̂i corespunde clasa Entity


C.5. JAVA PERSISTENCE API - JPA 267

1 package appagenda ;
2 import j a v a x . p e r s i s t e n c e . ∗ ;

4 @Entity
5 public c l a s s T e l e f implements j a v a . i o . S e r i a l i z a b l e {
6 private i n t i d ;
7 private S t r i n g nume ;
8 private S t r i n g numar ;

10 T e l e f ( ) {}

12 public i n t g e t I d ( ) {
13 return i d ;
14 }
15 public void s e t I d ( i n t i d ) {
16 t h i s . i d=i d ;
17 }

19 public S t r i n g getNume ( ) {
20 return nume ;
21 }
22 public void setNume ( S t r i n g nume ) {
23 t h i s . nume = nume ;
24 }

26 public S t r i n g getNumar ( ) {
27 return numar ;
28 }
29 public void setNumar ( S t r i n g numar ) {
30 t h i s . numar = numar ;
31 }
32 }

Accessarea bazei de date se face prin clasa AgendaTDAO


1 package appagenda ;
2 import j a v a x . p e r s i s t e n c e . ∗ ;
3 import j a v a . u t i l . ∗ ;

5 @SuppressWarnings ( ” unchecked ” )
6 p u b l i c c l a s s AgendaTDAO{
7 Entit yManagerFactory f a c t o r y=n u l l ;
8 EntityManager em ;

10 p u b l i c AgendaTDAO( EntityManage rF a c t or y f a c t o r y ) {
11 t h i s . f a c t o r y=f a c t o r y ;
12 }

14 p u b l i c v o i d addAgendaT ( T e l e f a ) {
15 em=f a c t o r y . c r e a t e E n t i t y M a n a g e r ( ) ;
16 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
17 //em . p e r s i s t ( a ) ;
18 S t r i n g s q l=” i n s e r t i n t o t e l e f ( nume , numar ) v a l u e s ( \ ’ ” +
19 a . getNume ()+ ” \ ’ , \ ’ ”+a . getNumar ()+ ” \ ’ ) ” ;
20 Query query=em . c r e a t e N a t i v e Q u e r y ( s q l ) ;
21 query . e x e c u t e U p d a t e ( ) ;
22 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
23 em . c l o s e ( ) ;
24 }
268 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

26 p u b l i c v o i d deleteAgendaT ( S t r i n g nume ) {
27 em=f a c t o r y . c r e a t e E n t i t y M a n a g e r ( ) ;
28 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
29 S t r i n g s q l=” d e l e t e from T e l e f a where a . nume=\ ’ ”+nume+” \ ’ ” ;
30 Query query=em . c r e a t e Q u e r y ( s q l ) ;
31 query . e x e c u t e U p d a t e ( ) ;
32 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
33 em . c l o s e ( ) ;
34 }

36 p u b l i c L i s t i n t e r o g a r e A g e n d a T ( S t r i n g nume ) {
37 em=f a c t o r y . c r e a t e E n t i t y M a n a g e r ( ) ;
38 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
39 S t r i n g s q l=” s e l e c t a from T e l e f a where a . nume=\ ’ ”+nume+” \ ’ ” ;
40 Query query=em . c r e a t e Q u e r y ( s q l ) ;
41 // S t r i n g s q l=” s e l e c t ∗ from t e l e f where nume=\ ’ ”+nume+” \ ’ ” ;
42 // Query query=em . c r e a t e N a t i v e Q u e r y ( s q l , appagenda . T e l e f . c l a s s ) ;
43 L i s t r e s u l t=query . g e t R e s u l t L i s t ( ) ;
44 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
45 em . c l o s e ( ) ;
46 return r e s u l t ;
47 }

49 p ub l ic L i s t listAgendaT ( ) {
50 em=f a c t o r y . c r e a t e E n t i t y M a n a g e r ( ) ;
51 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
52 S t r i n g s q l=” s e l e c t a from T e l e f a ” ;
53 Query query=em . c r e a t e Q u e r y ( s q l ) ;
54 // S t r i n g s q l=” s e l e c t ∗ from t e l e f ” ;
55 // Query query=em . c r e a t e N a t i v e Q u e r y ( s q l , appagenda . T e l e f . c l a s s ) ;
56 L i s t r e s u l t=query . g e t R e s u l t L i s t ( ) ;
57 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
58 em . c l o s e ( ) ;
59 return r e s u l t ;
60 }
61 }

iar clientul este AgendaTClient


1 package appagenda ;
2 import j a v a . u t i l . ∗ ;
3 import j a v a x . p e r s i s t e n c e . ∗ ;

5 public c l a s s AgendaTClient {
6 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
7 EntityManagerFactor y f a c t o r y=
8 P e r s i s t e n c e . c r e a t e E n t i t y M a n a g e r F a c t o r y ( ” appagenda ” ,
9 System . g e t P r o p e r t i e s ( ) ) ;
10 AgendaTDAO dao=new AgendaTDAO( f a c t o r y ) ;
11 S t r i n g ch=”Y” ;
12 int p r e l ;
13 Sca nner s c a n n e r=new S c a n n e r ( System . i n ) ;
14 T e l e f a=n u l l ;

16 while ( ch . s t a r t s W i t h ( ”Y” ) ) {
17 do{
18 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;
19 ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
20 }
C.5. JAVA PERSISTENCE API - JPA 269

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


22 i f ( ch . s t a r t s W i t h ( ”Y” ) ) {
23 System . out . p r i n t l n ( ” Natura p r e l u c r a r i i ? ” ) ;
24 System . out . p r i n t l n ( ” ( Adaug : 1 , S t e r g : 2 , I n t e r : 3 , L i s t : 4 ) ” ) ;
25 p r e l=s c a n n e r . n e x t I n t ( ) ;
26 S t r i n g nume , numar ;
27 switch ( p r e l ) {
28 case 1 :
29 System . out . p r i n t l n ( ”ADAUG” ) ;
30 System . out . p r i n t l n ( ”Numele : ” ) ;
31 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
32 System . out . p r i n t l n ( ”Numar t e l e f o n : ” ) ;
33 numar=s c a n n e r . n e x t ( ) . t r i m ( ) ;
34 a=new T e l e f ( ) ;
35 a . setNume ( nume ) ;
36 a . setNumar ( numar ) ;
37 dao . addAgendaT ( a ) ;
38 break ;
39 case 2 :
40 System . out . p r i n t l n ( ”STERG” ) ;
41 System . out . p r i n t l n ( ”Numele : ” ) ;
42 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
43 dao . deleteAgendaT ( nume ) ;
44 break ;
45 case 3 :
46 System . out . p r i n t l n ( ”INTEROGARE” ) ;
47 System . out . p r i n t l n ( ”Numele : ” ) ;
48 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
49 L i s t l i s t I n t e r =dao . i n t e r o g a r e A g e n d a T ( nume ) ;
50 f o r ( T e l e f t : ( L i s t <T e l e f >) l i s t I n t e r ) {
51 System . out . p r i n t l n ( ”Numele : ”+t . getNume ()+ ” Numar : ” +
52 t . getNumar ( ) ) ;
53 }
54 break ;
55 case 4 :
56 L i s t d a t a s=dao . l i s t A g e n d a T ( ) ;
57 f o r ( T e l e f t : ( L i s t <T e l e f >) d a t a s ) {
58 System . out . p r i n t l n ( ”Numele : ”+t . getNume ()+ ” Numar : ” +
59 t . getNumar ( ) ) ;
60 }
61 break ;
62 default : System . out . p r i n t l n ( ”Comanda e r o n a t a ” ) ;
63 }
64 }
65 else
66 System . e x i t ( 0 ) ;
67 }
68 factory . close ( ) ;
69 }
70 }

Fişierul persistence.xml pentru exemplul de mai sus este


1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 < 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 ”
3 x m l n s : x s i=” h t t p : //www. w3 . o r g /2001/XMLSchema−i n s t a n c e ”
4 version=” 1 . 0 ”>

6 <p e r s i s t e n c e −u n i t name=” none ” t r a n s a c t i o n −t y p e=”RESOURCE LOCAL”>


7 < c l a s s>appagenda . T e l e f</ c l a s s>
270 APPENDIX C. UTILIZAREA SGBD ÎN JAVA

8 </ p e r s i s t e n c e −u n i t>

10 <p e r s i s t e n c e −u n i t name=” appagenda ” t r a n s a c t i o n −t y p e=”RESOURCE LOCAL”>


11 < c l a s s>appagenda . T e l e f</ c l a s s>
12 </ p e r s i s t e n c e −u n i t>
13 </ p e r s i s t e n c e>

Fişierul build.xml pentru procesarea prin ant are codul


1 <?xml version=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>
2 <p r o j e c t default=” run ”>
3 <p r o p e r t y name=” package ” v a l u e=” appagenda ” />
4 <p r o p e r t y name=”dbname” v a l u e=” A g e n d a T e l e f o n i c a ” />
5 <p r o p e r t y name=” c l a s s n a m e ” v a l u e=” AgendaTClient ” />

7 <p r o p e r t y name=”db−d r i v e r −l o c a t i o n ”
8 l o c a t i o n=” d : /db−derby −∗−b i n ” />
9 < !−−
10 <p r o p e r t y name=”db−d r i v e r −l o c a t i o n ”
11 l o c a t i o n=” d : / mysql−c o n n e c t o r −j a v a − 5 . 1 . 5 ” />
12 −−>
13 <p r o p e r t y name=” o p e n j p a ” l o c a t i o n=” d : /JavaApp/ apache−openjpa − 1 . 1 . 0 ” />

15 < !−− d a t a b a s e c o n n e c t i o n p r o p e r t i e s −−>

17 <p r o p e r t y name=” d b 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 ” />


18 <p r o p e r t y name=” d b u r l ”
19 v a l u e=” j d b c : d e r b y : // l o c a l h o s t : 1 5 2 7 /${ dbname} ” />
20 < !−−
21 <p r o p e r t y name=” d b d r i v e r ” v a l u e=”com . mysql . j d b c . D r i v e r ” />
22 <p r o p e r t y name=” d b u r l ”
23 v a l u e=” j d b c : m y s q l : // l o c a l h o s t : 3 3 0 6 / A g e n d a T e l e f o n i c a ? u s e r=r o o t ” />
24 −−>
25 <p r o p e r t y name=” d b u s e r ” v a l u e=” ” />
26 <p r o p e r t y name=” dbpass ” v a l u e=” ” />

28 <path i d=” c l a s s p a t h ”
29 d e s c r i p t i o n=”The c l a s s p a t h t o u s e f o r c o m p i l i n g and r u n n i n g ”>
30 <p a t h e l e m e n t path=” ${ b a s e d i r } ” />
31 <p a t h e l e m e n t path=” ${db−d r i v e r −l o c a t i o n }/ l i b / d e r b y c l i e n t . j a r ” />
32 <p a t h e l e m e n t path=” ${db−d r i v e r −l o c a t i o n }/ mysql−c o n n e c t o r −j a v a −5.1.5 − b i n . j a r ” />
33 < f i l e s e t d i r=” ${ o p e n j p a }/ l i b ”>
34 <i n c l u d e name=” ∗ ∗ / ∗ . j a r ” />
35 </ f i l e s e t>
36 </ path>

38 <path i d=” j a v a a g e n t ”>


39 < f i l e s e t d i r=” ${ o p e n j p a } ”>
40 <i n c l u d e name=” openjpa −∗. j a r ” />
41 </ f i l e s e t>
42 </ path>
43 <p a t h c o n v e r t p r o p e r t y=” j a v a a g e n t ” r e f i d=” j a v a a g e n t ” />

45 <t a r g e t name=” c o m p i l e ”
46 d e s c r i p t i o n=” Compile t h e package j a v a f i l e s ”>
47 <j a v a c s r c d i r=” ${ package } ” c l a s s p a t h r e f=” c l a s s p a t h ” debug=” y e s ” />
48 </ t a r g e t>

50 <t a r g e t name=” run ” depends=” c o m p i l e ”>


51 <j a v a c l a s s n a m e=” ${ package } . $ { c l a s s n a m e } ” c l a s s p a t h r e f=” c l a s s p a t h ”
C.5. JAVA PERSISTENCE API - JPA 271

52 f o r k=” y e s ” f a i l o n e r r o r=” y e s ”>


53 < !−−
54 S p e c i f y i n g t h e o p e n j p a j a r as t h e j a v a a g e n t argument i s
55 n e c e s s a r y i n o r d e r f o r a u t o m a t i c c l a s s −enhancement t o work .
56 −−>
57 <jvmarg v a l u e=”−j a v a a g e n t : ${ j a v a a g e n t } ” />

59 < !−−
60 S p e c i f y t h e system p r o p e r t i e s t o u s e when c o n f i g u r i n g
61 OpenJPA . Note t h a t t h e s e w i l l o n l y be used b e c u a s e i n t h e
62 packages , the c a l l to ” P e r s i s t e n c e . createEntityManagerFactory ”
63 i s p a s s e d ” System . g e t P r o p e r t i e s ( ) ” .
64 −−>

66 <s y s p r o p e r t y key=” o p e n j p a . ConnectionDriverName ”


67 v a l u e=” ${ d b d r i v e r } ” />
68 <s y s p r o p e r t y key=” o p e n j p a . ConnectionURL ” v a l u e=” ${ d b u r l } ” />
69 <s y s p r o p e r t y key=” o p e n j p a . ConnectionUserName ” v a l u e=” ${ d b u s e r } ” />
70 <s y s p r o p e r t y key=” o p e n j p a . ConnectionPassword ” v a l u e=” ${ dbpass } ” />

72 < !−−
73 T e l l OpenJPA t o a u t o m a t i c a l l y c r e a t e t a b l e s i n t h e d a t a b a s e
74 f o r e n t i t i e s . Note t h a t t h i s s h o u l d be d i s a b l e d when
75 running a g a i n s t a p r o d u c t i o n d a t a b a s e , s i n c e you p r o b a b l y
76 don ’ t want t o be a l t e r i n g t h e schema a t r u n t i m e .
77 −−>
78 <s y s p r o p e r t y key=”o p e n j p a . j d b c . S y n c h r o n i z e M a p p i n g s ”
79 v a l u e=”buildSchema”/>

81 <!−−
82 Output a l l t h e SQL f o r e d u c a t i o n a l p u r p o s e s , but s e t t h e
83 g e n e r a l l o g g i n g l e v e l t o o n l y show w a r n i n g s .
84 −−>
85 <s y s p r o p e r t y key=”o p e n j p a . Log”
86 v a l u e=” D e f a u l t L e v e l=WARN, SQL=TRACE”/>
87 </j av a >
88 </ t a r g e t >
89 </ p r o j e c t >
272 APPENDIX C. UTILIZAREA SGBD ÎN JAVA
Bibliografie

[1] ATHANASIU I., COSTINESCU B., DRĂGOI O.A., POPOVICI F.I., 1998,
Limbajul Java. O perspectivă pragmatică. Ed. Computer Libris Agora, Cluj-
Napoca.

[2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru
aplicaţii Web. Ed. Albastră, Cluj-Napoca.

[3] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucureşti.

[4] BURAGA S. (ed), 2007, Programarea ı̂n Web 2.0., Ed. Polirom, Iaşi.

[5] JURCĂ I., 2000, Programarea reţelelor de calculatoare. Ed. de Vest, Timişoara.

[6] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming. O’Reilly.

[7] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iaşi.

[8] SCHEIBER E., 2007, Programare concurentă şi paralel distribuită ı̂n Java. Ed.
Albastră, Cluj-Napoca.

[9] TANASĂ Ş., OLARU C., 2005, Dezvoltarea aplicaţiilor Web folosind Java. Ed.
Polirom, Bucureşti.

[10] * * * , Java 2 SDK /docs/, Sun Microsystems.

[11] * * * , JavaWS Tutorial 1.*, Sun Microsystems.

[12] * * * , J2EE Tutorial, Sun Microsystems.

[13] * * * , Java 2 Tutorial, Sun Microsystems.

273

S-ar putea să vă placă și