Sunteți pe pagina 1din 303

Universitatea Transilvania din Braşov

Facultatea de Matematică–Informatică
Catedra de Informatică

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. Există multe abordări de programere a aplicaţiilor
dispecer-lucrător.
Scopul acestui curs este prezentarea tehnologiilor de programare Java care permit
programarea aplicaţiilor client - server:

3
4

• 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/Javadb sau mysql.
Cuprins

1 Applet - Miniaplicaţie Java 9


1.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2 Desfăşurarea unui applet . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Comunicare Java - JavaScript ı̂ntr-un applet . . . . . . . . . . . . . . 17

2 Programare cu socluri Java 19


2.1 Aplicaţii client – server . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 Noţiuni despre reţele . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.1 Clasa java.net.Socket . . . . . . . . . . . . . . . . . . . . . 21
2.3.2 Clasa java.net.ServerSocket . . . . . . . . . . . . . . . . . 21
2.4 Aplicaţie client – server cu socluri . . . . . . . . . . . . . . . . . . . 22
2.5 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.1 Clasa java.net.DatagramPacket. . . . . . . . . . . . . . . . 26
2.5.2 Clasa java.net.DatagramSocket . . . . . . . . . . . . . . . 27
2.5.3 Clasa java.net.InetAddress . . . . . . . . . . . . . . . . . 29
2.5.4 Aplicaţii client – server cu datagrame. . . . . . . . . . . . . . 31
2.5.5 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . . . . 35
2.6 Canale de comunicaţie . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.6.1 Clasa java.nio.Buffer . . . . . . . . . . . . . . . . . . . . . 36
2.6.2 Clasa java.nio.ByteBuffer . . . . . . . . . . . . . . . . . . 39
2.6.3 Clasa java.net.InetSocketAddress . . . . . . . . . . . . . 40
2.6.4 Clasa java.nio.channels.ServerSocketChannel . . . . . . 40
2.6.5 Clasa java.nio.channels.SocketChannel . . . . . . . . . . 41
2.6.6 Clasa java.nio.channels.DatagramChannel . . . . . . . . . 43
2.7 Conexiuni HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3 Regăsirea obiectelor prin servicii de nume 49


3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . . . . 49
3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5
6 CUPRINS

4 Invocarea procedurilor la distanţă 57


4.1 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . . . . 57
4.1.1 Crearea unei aplicaţii RMI . . . . . . . . . . . . . . . . . . . 60
4.1.2 Tipare de programare . . . . . . . . . . . . . . . . . . . . . . 65
4.1.3 Obiect activabil la distanţă . . . . . . . . . . . . . . . . . . . 71
4.2 CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2.1 Conexiunea RMI - CORBA . . . . . . . . . . . . . . . . . . . 76
4.2.2 Aplicaţie Java prin CORBA . . . . . . . . . . . . . . . . . . . 81

5 Mesaje ı̂n Java 89


5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . . . . 89
5.2 Open Message Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.4 Elemente de programare - JMS . . . . . . . . . . . . . . . . . . . . . 92
5.4.1 Trimiterea unui mesaj . . . . . . . . . . . . . . . . . . . . . . 92
5.4.2 Recepţia sincronă a unui mesaj . . . . . . . . . . . . . . . . . 97
5.4.3 Recepţia asincronă a unui mesaj . . . . . . . . . . . . . . . . 99
5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . . 100
5.4.5 Subscrierea şi recepţia mesajelor . . . . . . . . . . . . . . . . 101
5.5 Mesaje SOAP prin Java Message Service . . . . . . . . . . . . . . . . 103
5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.5.3 Ataşamente SOAP . . . . . . . . . . . . . . . . . . . . . . . . 111
5.6 Programe JMS prin apache-qpid . . . . . . . . . . . . . . . . . . . . 119
5.7 Protocolul AMQP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
5.7.1 Crearea unei cozi . . . . . . . . . . . . . . . . . . . . . . . . . 128
5.7.2 Expedierea / publicarea unui mesaj . . . . . . . . . . . . . . 129
5.7.3 Recepţionarea mesajelor . . . . . . . . . . . . . . . . . . . . . 131

6 Servlet 137
6.1 Marcajul <form> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
6.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . . . . 139
6.3 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . . . . 140
6.3.1 Instalarea unui servlet . . . . . . . . . . . . . . . . . . . . . . 140
6.3.2 Compilarea şi apelarea unui servlet . . . . . . . . . . . . . . . 142
6.3.3 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . . . . 143
6.4 Facilităţi de programare cu servlet . . . . . . . . . . . . . . . . . . . 149
6.4.1 Program client al unui servlet . . . . . . . . . . . . . . . . . . 149
6.4.2 Servlete ı̂nlănţuite . . . . . . . . . . . . . . . . . . . . . . . . 152
6.4.3 Sesiune de lucru . . . . . . . . . . . . . . . . . . . . . . . . . 154
6.4.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
6.4.5 Autorizarea accesului prin parola . . . . . . . . . . . . . . . . 157
CUPRINS 7

6.4.6 Servlet cu conexiune la o bază de date . . . . . . . . . . . . . 159


6.4.7 Imagini furnizate de servlet . . . . . . . . . . . . . . . . . . . 161
6.4.8 Servlet cu RMI . . . . . . . . . . . . . . . . . . . . . . . . . . 163
6.4.9 Servlet cu JMS . . . . . . . . . . . . . . . . . . . . . . . . . . 164
6.5 FileUpload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
6.6 Descărcarea unui fişier . . . . . . . . . . . . . . . . . . . . . . . . . . 172
6.7 Filtru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

7 Java Server Page – JSP 177


7.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
7.1.1 Declaraţii JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 182
7.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
7.1.3 Marcaje JSP predefinite . . . . . . . . . . . . . . . . . . . . . 184
7.1.4 Componentă Java (Java Bean) . . . . . . . . . . . . . . . . . 185
7.1.5 Pagini JSP cu componente Java . . . . . . . . . . . . . . . . 186
7.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . . . . 189
7.2.1 Biblioteca de bază . . . . . . . . . . . . . . . . . . . . . . . . 190
7.2.2 Biblioteca de lucru cu baze de date . . . . . . . . . . . . . . . 195
7.3 Marcaje JSP personale . . . . . . . . . . . . . . . . . . . . . . . . . . 196
7.3.1 Marcaje fără atribute şi fără corp. . . . . . . . . . . . . . . . 196
7.3.2 Marcaje cu atribute şi fără corp. . . . . . . . . . . . . . . . . 200
7.3.3 Marcaje cu corp. . . . . . . . . . . . . . . . . . . . . . . . . . 202

8 Portlet 205
8.1 Apache-pluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
8.2 Dezvoltarea unui portlet . . . . . . . . . . . . . . . . . . . . . . . . . 207
8.3 Elemente de programare . . . . . . . . . . . . . . . . . . . . . . . . . 211
8.4 Produse Portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
8.4.1 uPortal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
8.4.2 Jetspeed-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

9 Java Web Start 227


9.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

10 Java Management Extensions 233


10.1 Standard MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
10.1.1 Crearea unui Standard MBean . . . . . . . . . . . . . . . . . 234
10.1.2 Crearea unui MBeanServer . . . . . . . . . . . . . . . . . . . 236
10.1.3 Notificări . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
10.1.4 Agent MBean . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
10.1.5 Invocarea la distanţă . . . . . . . . . . . . . . . . . . . . . . . 243
8 CUPRINS

11 Teme de laborator 257


11.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257

A Unealta de dezvoltare apache-ant 269

B Utilizarea SGBD ı̂n Java 275


B.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
B.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
B.3 PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
B.4 HyperSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
B.5 Oracle XE 10g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
B.6 Şablonul de utilizare a unei baze de date . . . . . . . . . . . . . . . . 282
B.7 Modelul DAO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
B.8 Java Persistence API - JPA . . . . . . . . . . . . . . . . . . . . . . . 294
B.8.1 apache-openjpa . . . . . . . . . . . . . . . . . . . . . . . . . . 295

Bibliografie 303
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, Google Chrome, Microsoft InternetExplorer,
Opera, Apple 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 unei resurse
Deployment Toolkit(DT) - o bibliotecă de funcţii javascript. Resursa DT este apela-
bilă la adresa http://java.com/js/deployJava.js iar codul se poate consulta la
www.java.com/js/deployJava.js.
DT utilizează protocolul Java Network Launching Protocol (jnlp) şi evită prob-
lemele de compatibilitate cu programul navigator. Această resursă realizează descărcarea
applet-ului cât şi lansarea ı̂n execuţie. Pe calculatorul client, adică pe care rulează
applet-ul, trebuie să fie instalat jre - Java Runtime Environment - versiunea pe 32
biţi.
Programarea unui applet se face prin extinderea clasei java.applet.Applet
sau javax.swing.JApplet. Clasa Applet extinde clasa java.awt.Panel iar clasa
JApplet extinde clasa Applet.
Interfaţa grafică, ı̂n cazul extinderii clasei Applet, va utiliza controlurile aparţinând
interfeţei de programare AWT (Abstract Window Toolkit), iar ı̂n cazul extinderii cla-
sei JApplet se vor utiliza controluri Swing.

9
10 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

1.1 Clasa Applet


Structura unui applet este

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

public classNumeClasă extends Applet{


public void init(){
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 realizarea structurilor de
cataloage şi fişiere dar şi a operaţiilor care trebuie ı̂ntreprinse ı̂n vederea funcţionării
unei aplicaţii distribuite.
Desfăşurarea unui applet se poate face ı̂n mai multe feluri:

Varianta 1
1. Arhivarea fişierelor class ale applet-ului.
1.2. DESFĂŞURAREA UNUI APPLET 11

2. 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_clasei_Applet’,
archive:’numele_arhivei_jar’,width:...,height:...};
var parameters={. . .};
var minimumVersion=’1.6’;
deployJava.runApplet(attributes, parameters, minimumVersion);
</script>
. . .
</BODY>

3. Cele două fişiere se depun ı̂ntr-un catalog al unui server Web, asigurând viz-
ibilitatea aplicaţiei ı̂n Internet.
Verificarea aplicaţiei se poate face, dintr-un program navigator, prin simpla
apelare a fişierului html. În acest caz, calculatorul trebuie să fie conectat la
internet.
Dacă dispunem de deployJava.js atunci acest fişier se alătură celorlalte două
resurse, iar atributul src al elementului script va fi src="deployJava.js".

Exemplul 1.2.1 ”Hello ”+nume. Numele se transmite miniaplicaţiei ca parametru.

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 S t r i n g name=g e t P a r a m e t e r ( ”nume” ) ;
9 g . d r a w S t r i n g ( ” H e l l o ”+name+” ! ! ” , 5 0 , 60 ) ;
10 }
11 }

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 . c l a s s ’ , a r c h i v e : ’ i n c e p u t . j a r ’ ,
9 width : 3 0 0 , h e i g h t : 3 0 0 } ;
12 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

10 v a r p a r a m e t e r s={nume : ’ XYZ’ } ;
11 v a r minimumVersion = ’ 1 . 6 . 0 ’ ;
12 d e p l o y J a v a . runApplet ( a t t r i b u t e s , p a r a m e t e r s , minimumVersion ) ;
13 </ s c r i p t>
14 </BODY>
15 </HTML>

Varianta 2
Pe această cale se va edita un fişier de configurare cu extensia jnlp. Realizarea
applet-ului constă din:

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

2. Editarea unui fişier de configurare jnlp. Structura acestui fişier este

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


<jnlp spec="1.0+" codebase="http://host:port/cale_applet" href="">
<information>
<title>. . .</title>
<vendor>. . .</vendor>
</information>
<resources>
<!-- Application Resources -->
<j2se version="1.6+"
href="http://java.sun.com/products/autodl/j2se"
max-heap-size="128m" />

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


</resources>
<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>
1.2. DESFĂŞURAREA UNUI APPLET 13

<script>
var attributes={code:’numele_arhivei_jar’,width:...,height:...};
var parameters={jnlp_href: ’cmmdc.jnlp’};
var minimumVersion=’1.6’;
deployJava.runApplet(attributes, parameters, minimumVersion);
</script>
. . .
</BODY>

4. Cele trei fişiere (eventual patru cu deployJava.js) se depun ı̂ntr-un catalog al


unui server Web, asigurând vizibilitatea aplicaţiei ı̂n Internet.

Exemplul 1.2.2 Calculul celui mai mare divizor comun a două naturale.
Introducerea datelor exterioare se face prin intermediul unei interfeţe grafice.
Applet-ul extinzând clasa Applet are codul
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 VisualCmmdc 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 ;

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 . par se Lo ng ( sm ) ;
31 S t r i n g sn=tn . g e t T e x t ( ) ;
32 long n=Long . pa rs eL ong ( 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 }
14 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

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


42 }

iar ı̂n cazul extinderii clasei JApplet


1 import j a v a . awt . ∗ ;
2 import j a v a x . swing . ∗ ;
3 import j a v a . awt . e v e n t . ∗ ;

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


6 J T e x t F i e l d tm , tn , r e z ;

8 public void i n i t ( ) {
9 C o n t a i n e r c o n t e n t = getContentPane ( ) ;
10 content . setBackground ( Color . yellow ) ;
11 s e t L a y o u t (new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ) ;
12 J L a b e l lm=new J L a b e l ( ” Primul numar : ” ) ;
13 c o n t e n t . add ( lm ) ;
14 tm=new J T e x t F i e l d ( ” 1 ” , 5 ) ;
15 c o n t e n t . add ( tm ) ;
16 J L a b e l l n=new J L a b e l ( ” Al d o i l e a numar : ” ) ;
17 c o n t e n t . add ( l n ) ;
18 tn=new J T e x t F i e l d ( ” 1 ” , 5 ) ;
19 c o n t e n t . add ( tn ) ;
20 JButton compute=new JButton ( ” 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 c o n t e n t . add ( compute ) ;
23 r e z=new J T e x t F i e l d ( ” 1 ” , 5 ) ;
24 rez . setEditable ( false ) ;
25 c o n t e n t . add ( r e z ) ;
26 s e t V i s i b l e ( true ) ;
27 }

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

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


39 repaint ( ) ;
40 }

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


43 }

Fişierul de configurare jnlp (cmmdc.jnlp) este


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 t t p : // l o c a l h o s t : 8 0 8 0 /cmmdc” h r e f=” ”>
3 <i n f o r m a t i o n>
4 < t i t l e>V i s u a l Cmmdc</ 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 −−>
1.2. DESFĂŞURAREA UNUI APPLET 15

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=”cmmdc . 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=”VisualCmmdc Applet ”
17 main−c l a s s=”VisualCmmdc”
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>

iar apelarea se face din (VisualCmmdc.html )


1 <html>
2 <body b g c o l o r=”#AAEEAA”>
3 <c e n t e r>
4 <h1> Cel mai mare d i v i z o r comun </ h1>
5 < s c r i p t s r c=” d e p l o y J a v a . j s ”></ s c r i p t>
6 < s c r i p t>
7 v a r a t t r i b u t e s = { c o d e : ’cmmdc ’ , w i d t h : 3 0 0 , h e i g h t : 3 0 0 } ;
8 v a r p a r a m e t e r s = { j n l p h r e f : ’cmmdc . j n l p ’ } ;
9 v a r minimumVersion = ’ 1 . 6 ’ ;
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 , minimumVersion ) ;
11 </ s c r i p t>
12 </ c e n t e r>
13 </ body>
14 </ html>

sau cu descărcarea fişierului jnlp1


1 <HTML>
2 <BODY BGCOLOR=”#AAEEAA”>
3 <CENTER>
4 <h1> Cel mai mare d i v i z o r comun </ h1>
5 < s c r i p t s r c=” h t t p : // j a v a . com/ j s / d e p l o y J a v a . j s ”></ s c r i p t>
6 < s c r i p t>
7 d e p l o y J a v a . l a u n c h ( ’cmmdc . j n l p ’ ) ;
8 </ s c r i p t>
9 </CENTER>
10 </BODY>
11 </HTML>

O alternativă (depăşită) la modurile de apelare al applet-ului descrise anterior


este prin utilizarea elementului html <applet>.

Atributele obligatorii ale unui element applet sunt


• code
Valoarea atributului este numele clasei applet-ului.
• width
Valoarea atributului este lăţimea ferestrei atribuită de navigator applet-ului la
afişarea documentului html.
1
Funcţionează ı̂n navigatoarele Mozilla Firefox, Microsoft Internet Explorer.
16 CAPITOLUL 1. APPLET - MINIAPLICAŢIE JAVA

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

Atribute opţionale sunt

• 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>
1.3. COMUNICARE JAVA - JAVASCRIPT ÎNTR-UN APPLET 17

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.

1.3 Comunicare Java - JavaScript ı̂ntr-un applet


Dintr-un applet set apela funcţii JavaScript definite ı̂n documentul html din care
se apelează applet-ul.
Prin intermnediul unui obiect de tip netscape.javascript.JSObject, creat
prin
static JSObject getWindow(java.applet.Applet applet)
se apelează metoda
call(String numeFuncţieJavaScript, java.lang.Object[] args).
Şablonul de utilizare este

import netscape.javascript.*;

public void init(){


. . .
JSObject window=JSObject.getWindow(null);
window.call("numeFunctieJavaScript",args);
. . .
}

Pachetul netscape.javascript se află ı̂n distribuţia jdk ı̂n catalogul JAVA HOME\
jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath trebuie să
conţină această referinţă.
18 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 / persistenţei
datelor pentru fiecare client ı̂n parte.

19
20 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ă datagramele
ajung 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 protocolul HTTP (Hyper Text Transfer Protocol ) reprezintă
un mecanism de nivel ı̂nalt pentru accesarea 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 21

Î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 java.net.Socket


Resursele clasei Socket sunt destinate clientului.
Constructori

• public Socket(String host, int port) throws UnknownHostException,


IOException
Crează un soclu conectat la calculatorul cu portul 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şat soclului, pentru citirea (preluarea) informaţiilor
de la soclu.

• public OutputStream getOutputStream() throws IOException


Returnează un flux de ieşire ataşat soclului, pentru scrierea (transmiterea)
informaţiilor la soclu.

• public synchronized void close() throws IOException


ı̂nchide soclul de referinţă.

2.3.2 Clasa java.net.ServerSocket


Resursele clasei ServerSocket sunt destinate serverului.
Constructori
22 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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

• 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.4. APLICAŢIE CLIENT – SERVER CU SOCLURI 23

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.

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 . S c a n n e r ;

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 }
24 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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:

• 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 }
2.4. APLICAŢIE CLIENT – SERVER CU SOCLURI 25

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


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 }
26 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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.

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 java.net.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. Primirea 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 şi necesită specificarea adresei des-
tinatarului.

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


2.5. DATAGRAME 27

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 poate coexista cu un server TCP care ascultă acelaşi port.

Metode

• InetAddress getAddress()
returnează adresa IP a pachetului.

• 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 java.net.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
28 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• 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ă;

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.
2.5. DATAGRAME 29

• void setSendBufferSize(int lungime) throws SocketException


Fixează lungimea tamponului de trimitere a soclului la valoarea specificată.
Nu poate fi trimis mesaj UDP de lungime mai mare de această valoare.
• 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ă. Nu
poate fi primit un mesaj UDP de lungime mai mare de această valoare.
• 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 java.net.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”).
30 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• 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ţă.

• 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 ]+ ” . ” ) ;
2.5. DATAGRAME 31

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.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(obj);
byte[] bout=baos.toByteArray();

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


address,port);
socket.send(packet);
unde address şi port sunt adresa şi portul 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
32 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

byte[] bin=new byte[256];


packet=new DatagramPacket(bin,bin.length);
socket.receive(packet);

ByteArrayInputStream bais=new ByteArrayInputStream(bin);


ObjectInputStream in=new ObjectInputStream(bais);
obj=in.readObject();

Dacă mesajul este un obiect String atunci el se transformă ı̂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 . S c a n n e 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 ) ;
2.5. DATAGRAME 33

20 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 ) ;
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 ( ) ) ;
34 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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 ) {
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. DATAGRAME 35

2.5.5 Clasa java.net.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
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.
36 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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.

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 java.nio.Buffer


Ierarhia claselor Buffer
abstract Buffer
ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer
Un obiect de tip typeBuffer este un tampon (container) care 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

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.


38 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

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.


2.6. CANALE DE COMUNICAŢIE 39

2.6.2 Clasa java.nio.ByteBuffer


Instanţierea unui obiect se obţine prin metoda statică

static ByteBuffer allocate(capacitate)

Introducerea şi extragerea datelor din tampon se poate face ı̂n 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.
40 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 java.net.InetSocketAddress


Clasa InetSocketAddress extinde clasa SocketAddress şi ı̂ncapsulează adresa
unui calculator din Internet ı̂mpreună cu un port ı̂n vederea legării la un ServerSocket.
Constructori:
• InetSocketAddress(InetAddress addr ,int port)
• InetSocketAddress(String numeCalculator ,int port)
• InetSocketAddress(int port)

2.6.4 Clasa java.nio.channels.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 41

2.6.5 Clasa java.nio.channels.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 SocketChannel sc = null ;
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 ( ) ;
42 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 java . u t i l . Scanner ;

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 o c k e t C h a n n e 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 o c k e t C h a n n 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 43

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 java.nio.channels.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
44 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 45

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 java . u t i l . Scanner ;

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 ( ) ;
46 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 java.net.URL permite realizarea unei conexiuni cu un server Web1 potrivit
protocolului 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 // System . s e t P r o p e r t y (” h t t p . p r o x y H o s t ” , ” 1 0 . 3 . 5 . 1 3 3 ” ) ;
9 // System . s e t P r o p e r t y (” h t t p . p r o x y P o r t ” , ” 3 1 2 8 ” ) ;

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

10 URL u r l=new URL( adr ) ;


11 InputStream i n=u r l . openStream ( ) ;
12 InputStreamReader i s r =new InputStreamReader ( i n ) ;
13 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 ) ;
14 String s ;
15 do{
16 s=br . r e a d L i n e ( ) ;
17 i f ( s != n u l l )
18 System . out . p r i n t l n ( s ) ;
19 }
20 while ( s != n u l l ) ;
21 br . c l o s e ( ) ;
22 isr . close ();
23 in . close ( ) ;
24 }
25 catch ( E x c e p t i o n e ) {
26 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
27 }
28 }
29 }
48 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.

49
50 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 defineşte un protocol pentru


accesarea datelor reţinute ı̂ntr-un catalog LDAP (LDAP directory, informa-
tion directory). Un catalog LDAP permite reţinerea şi regăsirea referinţelor
obiectelor definite pe un calculator.

Interfaţa javax.naming.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
javax.naming.InitialContext, clasă ce implementează interfaţa Context.
Constructori.

• public InitialContext() throws NamingException

• public void InitialContext(Hashtable<?,?> environment)throws


NamingException
3.1. JAVA NAMING AND DIRECTORY INTERFACE 51

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:

• 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
52 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME

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.

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 java . u t i l . Scanner ;

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 }

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

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


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

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


3.1. JAVA NAMING AND DIRECTORY INTERFACE 53

56 NamingEnumeration l s t 1 = c t x . l i s t B i n d i n g s (myName ) ;
57 while ( l s t 1 . hasMore ( ) ) {
58 B i n d i n g bd = ( B i n d i n g ) l s t 1 . n e x t ( ) ;
59 System . out . p r i n t l n ( bd ) ;
60 }
61 ctx . c l o s e ( ) ;
62 }
63 catch ( NamingException e ) {
64 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 ( ) ) ;
65 }
66 }
67 }

Apelarea clasei, ı̂n varianta dată, constă din


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

sau
java Lookup

caz, ı̂n care, ı̂n catalogul curent se găseşte fişierul jndi.properties cu conţinutul
java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory

Serviciul de nume Filesystem este dat de fişierele: fscontext.jar şi


providerutil.jar.

3.1.1 LDAP
LDAP poate fi privit ca un sistem de gestiune a unei baze de date (ne relaţional).
Baza de date este alcătuită din atribute ale căror nume este precizat de protocolul
LDAP.
Punctele de intrare (rădăcinile) sunt date de DN (Distinguished Name). Uzual
DN se defineşte printr-una din variantele

1. o=”organization”,c=”country”

2. o=”organization”

3. dc=”domain content 1”,c=”domain content 2”


De exemplu, dc=”example”,dc=”com”

Un utilizator este caracterizat prin atributul cn - common name şi are acces la
LDAP prin precizarea simultană a atributelor DN şi cn.
Vom utiliza produsul OpenDS (Directory Service), ce implementează protocolul
LDAP.
Instalarea constă din:

1. dezarhivarea distribuţiei;
54 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME

2. se completează sursa fişierului OpenDS-*\setup.bat cu


set OPENDS JAVA HOME=... ca prima linie;

3. se execută OpenDS-*\setup.bat. Prin intermediul unei interfeţe grafice se


fixează

• o parola pentru cn=Directory Manager. Fie 1q2w3e această parolă.


• un punct de intrare, fie acesta DN: dc=example,dc=com.

Implicit, serverul OpenDS utilizează portul 389.


Operaţiile de configurare se fac utilizând interfaţa grafică a componentei OpenDS
Directory Server Control Panel, lansat prin
set OPENDS_JAVA_HOME=. . .
set OpenDS_HOME=. . .\OpenDS-*
%OpenDS_HOME%\bat\control-panel.bat

Declararea unui utilizator se face prin Manage Entries → Entries → New User,
urmat de completarea datelor cerute.
Schimbarea parolei unui utilizator se face tot din Manage Entries urmat de clic-
dreapta pe DN şi Reset User Password.
Prin această componentă se poate porni şi opri serverul OpenDS, ambele operaţii
putând fi executate şi apelând start-ds, stop-ds din catalogul
OpenDS HOME\bat.

Exemplul 3.1.2 Program pentru ı̂nregistrarea şi ştergerea referinţei unui obiect de
tip Cmmdc.

Prin intermediul OpenDS Directory Server Control Panel se crează se crează


o intrare/utilizator care va fi legat de un obiect Cmmdc. Presupunem că această
intrare este cn=info.
1 import java . u t i l . Hashtable ;
2 import java . u t i l . Scanner ;
3 import j a v a x . naming . Context ;
4 import j a v a x . naming . NamingException ;
5 import j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ;
6 import j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;

8 public c l a s s LDAPServerCmmdc {
9 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
10 H a s h t a b l e env = new H a s h t a b l e ( ) ;
11 env . put ( Context . INITIAL CONTEXT FACTORY,
12 ”com . sun . j n d i . l d a p . LdapCtxFactory ” ) ;
13 env . put ( Context . PROVIDER URL,
14 ” l d a p : / / l o c a l h o s t : 3 8 9 / cn=i n f o , dc=example , dc=com” ) ;
15 env . put ( Context . SECURITY PRINCIPAL , ” cn=D i r e c t o r y Manager ” ) ;
16 env . put ( Context . SECURITY CREDENTIALS, ” 1 q2w3e ” ) ; // p a r o l a
17 DirContext ctx = null ;

19 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
3.1. JAVA NAMING AND DIRECTORY INTERFACE 55

20 System . out . p r i n t l n ( ” A l e g e t i o p e r a t i a : 1− bind ; 2− unbind ” ) ;


21 i n t o p e r=s c a n n e r . n e x t I n t ( ) ;
22 System . out . p r i n t l n ( ” I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \” cn \” ” +
23 ” a o b i e c t u l u i Cmmdc” ) ;
24 System . out . p r i n t l n ( ” cn=” ) ;
25 S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ;

27 try {
28 c t x = new I n i t i a l D i r C o n t e x t ( env ) ;
29 c t x . unbind ( ” cn=”+cmmdcObj ) ;
30 i f ( o p e r ==1){
31 Cmmdc o b j=new Cmmdc ( ) ;
32 S t r i n g s t r=” cn=”+cmmdcObj ;
33 c t x . bind ( s t r , o b j ) ;
34 }
35 ctx . c l o s e ( ) ;
36 }
37 catch ( NamingException e ) {
38 System . out . p r i n t l n ( ”LDAPserverCmmdc : ”+e . g e t M e s s a g e ( ) ) ;
39 }
40 }
41 }

Codul clasei Cmmdc este


1 public c l a s s Cmmdc implements j a v a . i o . S e r i a l i z a b l e {
2 public long cmmdc( long a , long b ) {
3 while ( b != 0 ) {
4 long r = a % b ;
5 a = b;
6 b = r;
7 }
8 return a ;
9 }
10 }

Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc regăsit pe baza referintei din
serverul LDAP.

1 import java . u t i l . Hashtable ;


2 import j a v a x . naming . Context ;
3 import j a v a x . naming . NamingException ;
4 import j a v a x . naming . d i r e c t o r y . D i r C o n t e x t ;
5 import j a v a x . naming . d i r e c t o r y . I n i t i a l D i r C o n t e x t ;
6 import java . u t i l . Scanner ;

8 public c l a s s LDAPClientCmmdc {
9 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
10 H a s h t a b l e env = new H a s h t a b l e ( ) ;
11 env . put ( Context . INITIAL CONTEXT FACTORY,
12 ”com . sun . j n d i . l d a p . LdapCtxFactory ” ) ;
13 env . put ( Context . PROVIDER URL,
14 ” l d a p : / / l o c a l h o s t : 3 8 9 / cn=i n f o , dc=example , dc=com” ) ;
15 env . put ( Context . SECURITY PRINCIPAL , ” cn=D i r e c t o r y Manager ” ) ;
16 env . put ( Context . SECURITY CREDENTIALS, ” 1 q2w3e ” ) ;
17 DirContext ctx = null ;
18 try {
56 CAPITOLUL 3. REGĂSIREA OBIECTELOR PRIN SERVICII DE NUME

19 c t x=new I n i t i a l D i r C o n t e x t ( env ) ;
20 i f ( c t x != n u l l ) {
21 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
22 System . out . p r i n t l n ( ” I n t r o d u c e t i v a l o a r e a a t r i b u t u l u i \” cn \” ” +
23 ” a o b i e c t u l u i Cmmdc” ) ;
24 System . out . p r i n t l n ( ” cn=” ) ;
25 S t r i n g cmmdcObj=s c a n n e r . n e x t ( ) . t r i m ( ) ;
26 O b j e c t o b j e c t = c t x . l o o k u p ( ” cn=”+cmmdcObj ) ;
27 System . out . p r i n t l n ( ” Primul numar” ) ;
28 long a=s c a n n e r . n e x t I n t ( ) ;
29 System . out . p r i n t l n ( ” Al d o i l e a numar” ) ;
30 long b=s c a n n e r . n e x t I n t ( ) ;
31 Cmmdc o b j =(Cmmdc) o b j e c t ;
32 System . out . p r i n t l n ( ” R e z u l t a t u l cmmdc e s t e : ”+o b j . cmmdc( a , b ) ) ;
33 }
34 }
35 catch ( NamingException e ) {
36 System . out . p r i n t l n ( ”LDAPClientCmmdc : ”+e . g e t M e s s a g e ( ) ) ;
37 }
38 }
39 }
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 Broker 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.

57
58 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 java.rmi.Remote. Fiecare asemenea metodă trebuie să arunce o
excepţie java.rmi.RemoteException. Obiectele care circulă prin reţea trebuie să
implementeze 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 java.rmi.registry.Registry1 .
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.
1
Varianta directă, fără a folosi facilităţile JNDI pentru rmiregistry.
4.1. REMOTE METHOD INVOCATION 59

• void rebind(String numeServiciu, Remote obj )throws


RemoteException, AccessException
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


java.rmi.registry.LocateRegistry.

• public static Registry getRegistry() throws RemoteException

• public static Registry getRegistry(String host)


throws RemoteException

• public static Registry getRegistry(int port)


throws RemoteException

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


throws RemoteException

Metoda public static Registry createRegistry(int port)


throws RemoteException crează un registru la portul specificat pe calculatorul
local.
Ansamblul (host,port) determină ı̂n mod univoc o aplicaţie / serviciu.
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 java.rmi.server.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)


60 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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


mentat de clasa ServiceImpl ı̂n registry se face prin

ServiceImpl obj=new ServiceImpl();


IService stub=(IService)UnicastRemoteObject.exportObject(obj,0);

// Varianta cu apel rmiregistry direct


/*
Registry registry=LocateRegistry.getRegistry(host,port);
registry.bind("MyServiceName",stub);
*/
// Varianta JNDI
String sPort=(new Integer(port)).toString();
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL,"rmi://"+host+":"+sPort);
Context ctx=new InitialContext();
ctx.bind("MyServiceName",stub);

Un client care doreş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 exemplele2 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
Sistemul de operare utilizat este Windows
4.1. REMOTE METHOD INVOCATION 61

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 }

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.


62 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 // i m p o r t j a v a . rmi . r e g i s t r y . ∗ ;
8 // V a r i a n t a JNDI
9 import j a v a x . naming . ∗ ;

11 public c l a s s CmmdcImpl implements ICmmdc{

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

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


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

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

32 // V a r i a n t a JNDI
33 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 ( ) ;
34 System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY,
35 ”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 ” ) ;
36 System . s e t P r o p e r t y ( Context . PROVIDER URL, ” rmi : / / ”+h o s t+” : ”+s P o r t ) ;
37 Context c t x=new I n i t i a l C o n t e x t ( ) ;
38 c t x . bind ( ”CmmdcServer” , s t u b ) ;

40 System . out . p r i n t l n ( ”CmmdcServer r e a d y ” ) ;


41 }
42 catch ( E x c e p t i o n e ) {
43 System . out . p r i n t l n ( ”CmmdcImpl e r r : ” + e . g e t M e s s a g e ( ) ) ;
44 }
45 }
46 }

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


\s\src\server

4. (a) Compilarea programului server;


(b) Crearea obiectului registry;
(c) Lansarea serverului ı̂n lucru
se obţin cu ant cu
4.1. REMOTE METHOD INVOCATION 63

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>
3 Server actions
4 </ description>
5 < !−− 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 −−>

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


8 <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” />
9 <property name=” j a r − f i l e ” v a l u e=”cmmdc . j a r ” />
10 <property name=” s e r v i c e −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=” 1099 ” />

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


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

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


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

40 <target name=”Rmi”>
41 <exec e x e c u t a b l e=” r m i r e g i s t r y ”>
42 <arg v a l u e=” 1099 ” />
43 </ exec>
44 </ target>

46 <target name=” S e r v e r ”>


47 <java c l a s s n a m e=” ${ package } . $ { s e r v i c e −c l a s s } ”
48 classpath=” / s / p u b l i c / c l a s s e s ” f o r k=” t r u e ”>
49 <jvmarg
50 v a l u e=”−Djava . rmi . s e r v e r . c o d e b a s e= f i l e : / s / p u b l i c / c l a s s e s / ” />
51 <arg l i n e=” ${ h o s t } ${ p o r t } ” />
52 </ java>
53 </ target>
54 </ project>

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


de pe calculatorul server.
64 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

Obiectivele Rmi şi Server se lansează ı̂n ferestre dos distincte care rămân
active pe durata de viaţă a aplicaţiei server.

5. Realizarea programului client

1 package c l i e n t ;

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

10 public c l a s s CmmdcClient {
11 public s t a t i c void 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 i n t p o r t =1099;
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=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
18 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
19 System . out . p r i n t l n ( ” Primul numar : ” ) ;
20 long m=Long . par se Lon g ( 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 . p ars eL ong ( s c a n n e r . n e x t ( ) ) ;
23 long x =0;
24 try {
25 // V a r i a n t a d i r e c t a
26 /∗
27 R e g i s t r y r e g i s t r y=L o c a t e R e g i s t r y . g e t R e g i s t r y ( h o s t , p o r t ) ;
28 ICmmdc o b j =(ICmmdc) r e g i s t r y . l o o k u p (” CmmdcServer ” ) ;
29 ∗/
30 // V a r i a n t a JNDI
31 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 ( ) ;
32 System . s e t P r o p e r t y ( Context . INITIAL CONTEXT FACTORY,
33 ”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 ” ) ;
34 System . s e t P r o p e r t y ( Context . PROVIDER URL, ” rmi : / / ”+h o s t+” : ”+s P o r t ) ;
35 Context c t x=new I n i t i a l C o n t e x t ( ) ;
36 ICmmdc o b j =(ICmmdc) c t x . l o o k u p ( ”CmmdcServer” ) ;

38 x=o b j . cmmdc(m, n ) ;
39 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
40 }
41 catch ( E x c e p t i o n e ) {
42 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 ( ) ) ;
43 }
44 }
45 }

Sursa programului client CmmdcClient.java aparţine catalogului


\c\src\client

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


4.1. REMOTE METHOD INVOCATION 65

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 o ca 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 ”


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 l oc a t 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
66 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 im po rt 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 im po rt j a v a . rmi . ∗ ;
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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . s e r v e r . ∗ ;
4 im po rt j a v a . i o . ∗ ;
5 im po rt 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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . s e r v e r . ∗ ;
4 im po rt 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 {
4.1. REMOTE METHOD INVOCATION 67

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 os t , 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
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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . s e r v e r . ∗ ;
4 im po rt 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 }
68 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

2. ClientCmmdc0
Apelează metoda compute a obiectului remote.
1 package cmmdc0 ;
2 im po rt j a v a . u t i l . S c a n n e 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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 ) ;
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 im po rt j a v a . rmi . ∗ ;
4.1. REMOTE METHOD INVOCATION 69

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 im po rt 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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . s e r v e r . ∗ ;
4 im po rt 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” ) )
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);
70 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . s e r v e r . ∗ ;
4 im po rt j a v a . rmi . r e g i s t r y . ∗ ;
5 im po rt j a v a . u t i l . S c a n n e 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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
15 System . out . p r i n t l n ( ” A l e g e t i v a r i a n t a a l g o r i t m u l u i l u i E u c l i d ” ) ;
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)
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 im po rt j a v a . u t i l . S c a n n e 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)
4.1. REMOTE METHOD INVOCATION 71

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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-
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.
72 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 MarshalledObject 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 im po rt j a v a . rmi . ∗ ;
3 im po rt j a v a . rmi . a c t i v a t i o n . ∗ ;
4 im po rt 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 }

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

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 MarshalledObject, 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.

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

Codul clasei setup este

1 package acmmdc ;

3 im po rt j a v a . rmi . ∗ ;
4 im po rt j a v a . rmi . a c t i v a t i o n . ∗ ;
5 im po rt j a v a . rmi . r e g i s t r y . ∗ ;
6 im po rt 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 . out . p r i n t l n ( ” u s a g e : ” ) ;
18 System . out . p r i n t l n ( ” j a v a [ o p t i o n s ] examples . a c t i v a t i o n . Setup <i m p l C l a s s >” ) ;
19 System . e x i t ( 1 ) ;
20 }
21 else {
74 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

22 implClass = args [ 0 ] ;
23 }

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

38 // 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
39 // 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
40 Act ivat ionG roupI D groupID=
41 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 ) ;
42 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 . ” ) ;

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

50 A c t i v a t i o n D e s c d e s c=
51 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 ) ;

53 // 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
54 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 ) ;
55 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 . ” ) ;

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

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

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

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 Broker Arhi-
tecture): 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.
76 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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
Broker (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 Definition 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.

4.2.1 Conexiunea RMI - CORBA


Firma Oracle - Sun Microsystems 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.
• serviciul ORB care asigură regăsirea resurselor CORBA. Acest server se lansează
ı̂n execuţie prin
start orbd -ORBInitialPort [port]
Programele orbd, rmic sunt ı̂n distribuţia jdk.
4.2. CORBA 77

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 im po rt j a v a x . rmi . P o r t a b l e R e m o t e O b j e c t ;
3 im po rt cmmdc . ∗ ;
4 im po rt 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 im po rt j a v a x . naming . I n i t i a l C o n t e x t ;
3 im po rt j a v a x . naming . Context ;

6 p u b l i c c l a s s CmmdcServer {
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 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=” 1050 ” ;
10 i f ( a r g s . l e n g t h >0)
11 h o s t=a r g s [ 0 ] ;
12 i f ( a r g s . l e n g t h >1)
13 p o r t=a r g s [ 1 ] ;
14 try {
15 // 1 : C r e a r e a u n e i i n s t a n t e CmmdcImpl
16 CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ;

18 // 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
19 // u t i l i z a n d JNDI API
20 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 ” ,
21 ”com . sun . j n d i . cosnaming . CNCtxFactory ” ) ;
22 System . s e t P r o p e r t y ( ” j a v a . naming . p r o v i d e r . u r l ” ,
23 ” i i o p : // ”+h o s t+” : ”+p o r t ) ;
24 Context c t x = new I n i t i a l C o n t e x t ( ) ;
25 c t x . r e b i n d ( ” CmmdcService ” , cmmdcRef ) ;
26 System . out . p r i n t l n ( ”Cmmdc S e r v e r : Ready . . . ” ) ;
27 }
28 catch ( Exception e ) {
78 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

29 System . out . p r i n t l n ( ” CmmdcServer: ” + e . g e t M e s s a g e ( ) ) ;


30 }
31 }
32 }

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.


Activităţile legate de server se obţin prin ant cu fişierul 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 oc a 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 ”>


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” />
4.2. CORBA 79

32 </ target>

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


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

46 <target name=”Orb”>
47 <exec e x e c u t a b l e=” orbd ”>
48 <arg l i n e=”−O R B I n i t i a l P o r t ${ p o r t } −O R B I n i t i a l H o s t ${ h o s t } ” />
49 </ exec>
50 </ target>

52 <target name=” S e r v e r ” description=” S t a r t t h r s e r v e r ” >


53 <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 ”>
54 <classpath>
55 <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 } ” />
56 <pathelement path=” p u b l i c / c l a s s e s ” />
57 </ classpath>
58 <arg l i n e=” ${ h o s t } ${ p o r t } ” />
59 </ java>
60 </ target>
61 </ project>

8. Editarea programului client.

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

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 [ ] ) {
11 S t r i n g h o s t=” l o c a l h o s t ” ;
12 S t r i n g p o r t=” 1050 ” ;
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=a r g s [ 1 ] ;

18 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
19 System . out . p r i n t l n ( ” Primul numar : ” ) ;
20 long m=Long . par se Lon g ( 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 . p ars eL ong ( s c a n n e r . n e x t ( ) ) ;
23 try {
80 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

24 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 ” ,
25 ”com . sun . j n d i . cosnaming . CNCtxFactory ” ) ;
26 System . s e t P r o p e r t y ( ” j a v a . naming . p r o v i d e r . u r l ” ,
27 ” i i o p : / / ”+h o s t+” : ”+p o r t ) ;
28 Context c t x = new I n i t i a l C o n t e x t ( ) ;

30 // STEP 1 : Get t h e O b j e c t r e f e r e n c e from t h e Name S e r v c t x e


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

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


36 // i n v o k e t h e method .
37 ICmmdc o b j = (ICmmdc) P o r t a b l e R e m o t e O b j e c t . narrow ( o b j r e f , ICmmdc . c l a s s ) ;
38 long x=o b j . cmmdc(m, n ) ;
39 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;
40 }
41 catch ( E x c e p t i o n e ) {
42 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 ( ) ) ;
43 }
44 }
45 }

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.
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=” i n t e r f a c e −package ” v a l u e=”cmmdc” />
10 <property name=” i n t e r f a c e −stub−l o c a t i o n ”
11 l oc a t io n=” / s / p u b l i c / c l a s s e s /${ i n t e r f a c e −package } ” />
12 <property name=” stub−c l a s s ” v a l u e=” ∗ S t u b . c l a s s ” />
13 <property name=” h o s t ” v a l u e=” l o c a l h o s t ” />
14 <property name=” p o r t ” v a l u e=” 1050 ” />
15 <property name=” c l i e n t −c l a s s ” v a l u e=” CmmdcClient ” />

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


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

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


26 < !−− C r e a t e t h e time stamp −−>
27 <tstamp/>
28 <mkdir d i r=” s r c /${ package } ” />
29 <mkdir d i r=” c l a s s e s /${ package } ” />
30 <delete d i r=” c l a s s e s /${ s e r v e r −package } ” />
4.2. CORBA 81

31 <mkdir d i r=” c l a s s e s /${ s e r v e r −package } ” />


32 <delete d i r=” c l a s s e s /${ i n t e r f a c e −package } ” />
33 <mkdir d i r=” c l a s s e s /${ i n t e r f a c e −package } ” />
34 <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 ” />
35 <copy t o d i r=” c l a s s e s /${ i n t e r f a c e −package } ” >
36 < 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 } ”
37 i n c l u d e s=” ${ stub−c l a s s } ” />
38 </copy>
39 <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 ” />
40 <delete d i r=” c l a s s e s /META−INF” />
41 </ target>

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


44 description=” c o m p i l e t h e s o u r c e ” >
45 <javac s r c d i r=” s r c ” d e s t d i r=” c l a s s e s ”
46 i n c l u d e s=” ${ package } \ ∗ . j a v a ” classpath=” c l a s s e s ” />
47 </ target>

49 <target name=”Run” depends=” Compile ” description=”Run t h e c l i e n t ” >


50 <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 ”>
51 <classpath>
52 <pathelement l oc a t io n=” c l a s s e s /${ j a r − f i l e } ” />
53 <pathelement path=” c l a s s e s ” />
54 </ classpath>
55 <arg l i n e=” ${ h o s t } ${ p o r t } ” />
56 </ java>
57 </ target>
58 </ project>

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
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ţă:


82 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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

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;
4.2. CORBA 83

• 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 im po rt CmmdcApp . ∗ ;
2 im po rt 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 im po rt CmmdcApp . ∗ ;
2 im po rt o r g . omg . CosNaming . ∗ ;
3 im po rt o r g . omg . CosNaming . NamingContextPackage . ∗ ;
4 im po rt o r g . omg .CORBA. ∗ ;
5 im po rt 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 ) ;
84 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 im po rt CmmdcApp . ∗ ;
2 im po rt o r g . omg . CosNaming . ∗ ;
3 im po rt o r g . omg . CosNaming . NamingContextPackage . ∗ ;
4 im po rt o r g . omg .CORBA. ∗ ;
5 im po rt java . u t i l . Scanner ;

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
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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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ă
4.2. CORBA 85

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.
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 im po rt java . u t i l . Properties ;
2 im po rt o r g . omg .CORBA. ∗ ;
3 im po rt o r g . omg . CosNaming . ∗ ;
4 im po rt 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
86 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

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 }
50 }
51 }

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

6 im po rt CmmdcApp . CmmdcHelper ;
7 im po rt CmmdcApp . Cmmdc ;
8 im po rt j a v a . u t i l . S c a n n e 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 (
4.2. CORBA 87

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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

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\

Îndeplinirea acţiunii de ı̂nregistrare a serverului este indicat printr-un mesaj


de forma server registered (serverid=257).

Serviciul se sterge prin comanda


servertool > unregister -serverid 257

Programul de ı̂nregistrare servertool se ı̂nchide prin


servertool > quit
88 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANŢĂ

3. Executarea clientului
java PersistentClient [hostORB [portORB]]
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. Asemenea aplicaţii se pot realiza
prin comunicaţii de mesaje, mesaje care sunt reţinute de un intermediar (serviciu
de mesagerie, server, broker, messaging middleware).
În prezent protocolul pentru realizarea aplicaţiilor bazate pe comunicaţii de
mesaje este Advanced Message Queue Protocol - AMQP. AMQP este un proto-
col 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 şi care se doreşte independent de limbajul de
programare.
Modelul AMQP ı̂nglobează standardul Java Message Servuce - JMS, dezvoltat
de Oracle - Sun Microsystems.
Comunicaţia se realizează prin socluri TCP.

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:
• Open Message Queue a firmei Oracle. Numele anterior al produsului a fost
Sun Java System Message Queue
• ActiveMQ realizată de fundaţia apache.
• qpid realizată de fundaţia apache.

89
90 CAPITOLUL 5. MESAJE ÎN JAVA

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.
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. OPEN MESSAGE QUEUE 91

5.2 Open Message Queue


Instalarea. Funcţie de resursa descărcată, ı̂n mediul Windows, instalarea constă
din

• Se dezarhivează fişierul openmq* *-installer-WINNT.zip şi se lansează ı̂n execuţie


programul de instalare.

• Se dezarhivează fişierul openmq* *-binary-WINNT.zip şi se fixează atributele


fişierului mq\etc\imqenv.conf.

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
92 CAPITOLUL 5. MESAJE ÎN JAVA

set JAVA_HOME=. . .
set ACTIVEMQ_HOME=. . .
%ACTIVEMQ_HOME%\bin\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.

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
5.4. ELEMENTE DE PROGRAMARE - JMS 93

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{
TopicConnection createTopicConnection() throws JMSException;
TopicConnection createTopicConnection(String userName,
String password) throws JMSException;
}

unde Connection, QueueConnection, TopicConnection sunt interfeţe din


javax.jms.
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.
94 CAPITOLUL 5. MESAJE ÎN JAVA

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.
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
5.4. ELEMENTE DE PROGRAMARE - JMS 95

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
|
|->interface Queue
|
|->interface Topic

class Destination implements Destination


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

Utilizând Oracle-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);
}
96 CAPITOLUL 5. MESAJE ÎN JAVA

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.

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 Oracle−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 i m p l e m e n t e a 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 .
28 // ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;
29 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 ( ) ;
30 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) ;

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

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

36 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 ( ) ;
37 f o r ( i n t i =0; i <n ; i ++){
38 m. s e t T e x t ( ” H e l l o ”+i ) ;
39 p r o d u c e r . send (m) ;
40 }
41 // 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
5.4. ELEMENTE DE PROGRAMARE - JMS 97

42 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 ( ) ) ;
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 System . out . p r i n t l n ( ” Sen de r f i n i s h e d ” ) ;
50 }
51 }

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

q desemnând obiectul destinaţie.


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()
98 CAPITOLUL 5. MESAJE ÎN JAVA

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 {
12 // V a r i a n t a Oracle−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 i m p l e m e n t e a 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 .
24 // ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;
25 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 ( ) ;
26 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) ;
27 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 ) ;
28 MessageConsumer consumer=s e s s i o n . createConsumer ( q ) ;
29 conn . s t a r t ( ) ;
30 Message msg=n u l l ;
31 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
32 i f ( msg instanceof TextMessage ) {
33 TextMessage m=(TextMessage ) msg ;
34 System . out . p r i n t l n (m. g e t T e x t ( ) ) ;
35 }
36 else
37 break ;
38 }
39 session . close ();
40 conn . c l o s e ( ) ;
41 }
42 catch ( E x c e p t i o n e ) {
43 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
44 }
45 System . out . p r i n t l n ( ” Consumer f i n i s h e d ” ) ;
46 }
47 }

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;
5.4. ELEMENTE DE PROGRAMARE - JMS 99

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.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.
Astfel, caracterul asincron constă din faptul că mesajele sunt preluate de as-
cultător - adică obiectul ce implementează interfaţa MessageListener şi nu de
clientul JMS.

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 Oracle−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 i m p l e m e n t e a z a 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 .
23 // ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;
100 CAPITOLUL 5. MESAJE ÎN JAVA

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

ı̂mpreună cu ascultătorul
1 import j a v a x . jms . ∗ ;
2 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 {
3 boolean s f a r s i t =f a l s e ;
4 public void onMessage ( Message message ) {
5 i f ( message instanceof TextMessage ) {
6 TextMessage m=(TextMessage ) message ;
7 try {
8 System . out . p r i n t l n (m. g e t T e x t ( ) ) ;
9 }
10 catch ( JMSException e ) {
11 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
12 }
13 }
14 else
15 s f a r s i t =true ;
16 }

18 public void run ( ) {


19 while ( ! s f a r s i t ) ;
20 }
21 }

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 ;
5.4. ELEMENTE DE PROGRAMARE - JMS 101

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 Oracle−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 .
23 // ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 6 ” ) ;

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 TopicSession session =
27 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) ;
28 Destination t = session . createTopic ( subiect ) ;
29 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 ) ;

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


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

34 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 ( ) ;
35 f o r ( i n t i =0; i <n ; i ++){
36 m. s e t T e x t ( ” Despre ”+s u b i e c t+” ”+i ) ;
37 p r o d u c e r . send (m) ;
38 // p u b l i s h e r . p u b l i s h (m) ;
39 }
40 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 ( ) ) ;
41 // 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 ( ) ) ;
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 ( ” P u b l i s h e r f i n i s h e d ” ) ;
49 }
50 }

Varianta comentată este o soluţie specifică implementării Oracle-Sun Java Sys-


tem Message 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);
102 CAPITOLUL 5. MESAJE ÎN JAVA

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 ;

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 Oracle−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 .
25 // ActiveMQConnectionFactory (” t c p : / / l o c a l h o s t : 6 1 6 1 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 t = session . createTopic ( subiect ) ;
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 , c l i e n t N a m e ) ;
34 conn . s t a r t ( ) ;
35 Message msg=n u l l ;
36 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
37 i f ( msg instanceof TextMessage ) {
38 TextMessage m=(TextMessage ) msg ;
39 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 ( ) ) ;
40 }
41 else
42 break ;
43 }
44 session . close ();
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 103

45 conn . c l o s e ( ) ;
46 }
47 catch ( E x c e p t i o n e ) {
48 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
49 }
50 }
51 }

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

5.5 Mesaje SOAP prin Java Message Service


Rezultatele acestei secţiuni sunt valabile doar ı̂n cazul pachetului Oracle-Sun
Java System Message Queue.

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).
Execuţia programelor utilizând resurse SOAP necesită declararea ı̂n variabila de
sistem classpath a referinţei către saaj-impl.jar.

5.5.2 Mesaje SOAP


Un mesaj SOAP este un document XML constând din
• o ı̂nvelitoare (envelope) care poate conţine
104 CAPITOLUL 5. MESAJE ÎN JAVA

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

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

Î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
2 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 / ”>
3 <SOAP−ENV:Header />
4 <SOAP−ENV:Body>
5 <e1>
6 primul
7 <e11>
8 al treilea
9 </ e11>
10 </ e1>
11 <e2>
12 al doilea
13 </ e2>
14 </SOAP−ENV:Body>
15 </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 Me ss age Fa cto ry mf=Mes sa ge Fac 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 ( ) ;
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 e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( ”MySOAPMessage . xml” ) ;
23 soapMsg . w r i t e T o ( 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 }
106 CAPITOLUL 5. MESAJE ÎN JAVA

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

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, indicativ după care se 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 {
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 107

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 Me ss age Fa ct ory 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 TopicSession session =
40 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) ;
41 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” ) ;
42 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 ) ;
43 mf=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ;
44 soapMsg=mf . c r e a t e M e s s a g e ( ) ;
45 p a r t=soapMsg . getSOAPPart ( ) ;
46 e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
47 body=e n v e l o p e . getBody ( ) ;
48 name=e n v e l o p e . createName ( ” n1 ” ) ;
49 elem=body . addChildElement ( name ) ;
50 elem . addTextNode ( (new Long ( a ) ) . t o S t r i n g ( ) ) ;
51 name=e n v e l o p e . createName ( ” n2 ” ) ;
52 elem=body . addChildElement ( name ) ;
53 elem . addTextNode ( (new Long ( b ) ) . t o S t r i n g ( ) ) ;
54 name=e n v e l o p e . createName ( ” t o p i c ” ) ;
55 elem=body . addChildElement ( name ) ;
56 elem . addTextNode ( t o p i c R e s u l t ) ;
57 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 ) ;
58 T o p i c S u b s c r i b e r consumer=
59 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 ) ;
60 Message m=
61 M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;
62 p r o d u c e r . send (m) ;
63 F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( ”MySOAPMessage . xml” ) ;
64 soapMsg . w r i t e T o ( f ) ;
65 conn . c l o s e ( ) ;
108 CAPITOLUL 5. MESAJE ÎN JAVA

66 }
67 catch ( E x c e p t i o n e ) {
68 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 ( ) ) ;
69 }
70 System . out . p r i n t l n ( ” Sen de r f i n i s h e d ” ) ;
71 }

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


74 i f ( a r g s . l e n g t h <2){
75 System . out . p r i n t l n ( ” Usage : ” ) ;
76 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 ” ) ;
77 System . e x i t ( 0 ) ;
78 }
79 MsgSOAPClientSender c l i e n t=new MsgSOAPClientSender ( a r g s [ 0 ] , a r g s [ 1 ] ) ;
80 client . service ();
81 }
82 }

• 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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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 Me ss age Fa ct ory mf=n u l l ;
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=Me ss age Fa cto ry . n e w I n s t a n c e ( ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 109

40 conn . s t a r t ( ) ;
41 Message msg=consumer . r e c e i v e ( ) ;
42 soapMsg=Me s sa ge T ra n sf 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 . 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 ;

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 Mess ag eFa ct ory 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 ” ) ;
110 CAPITOLUL 5. MESAJE ÎN JAVA

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=Me ss age Fa cto ry . 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=Me s sa ge 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 . p ars 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=
63 M es s ag e Tr an s fo r me r . 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
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 111

<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");
• 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");
112 CAPITOLUL 5. MESAJE ÎN JAVA

• Ataşament video.
(a) Fişierele video au de obicei dimensiuni mari. Pentru a putea in-
clude asemenea fişiere trebuie mărită dimensiunea maximă a unui
ataşament prin includerea setării
imq.autocreate.destination.maxBytesPerMsg=35M
ı̂n fişierul mq\lib\props\broker\install.properties.
(b) Crearea unui obiect de tip AttachmentPart cu ı̂ncărcarea fişierului
cu conţinut video.
String video_location="c:\\. . .’’;
URL url=new URL("file://"+video_location);
dataHandler= new DataHandler(url);
AttachmentPart attachment =
soapMsg.createAttachmentPart(dataHandler);
(c) Pentru redarea conţinutului video vom avem nevoie de tipul conţinutului
video, informaţie dată de extensia fişierului video. Aceată dată este
furnizată prin metoda setContentId.
File videoFile = new File(video_location);
String fileName = videoFile.getName();
int index=fileName.lastIndexOf(".");
String ext=fileName.substring(index+1);
attachment.setContentId("attached_video"+ext);

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

. . .
}

// Preluarea unei imagini


if (type.equals("image/jpeg")){
Image image=(Image)attached.getContent();
. . .
}

// Preluarea unei inregistrari mp3


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

// Preluarea continutului video


if(id.startsWith("attached_video")){
String videoFileName = "videoFile."+id.substring(14);
// Salvarea continutului video intr-un fisier local
InputStream inputStream = attached.getRawContent();
File f=new File(videoFileName);
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0) out.write(buf,0,len);
out.close();
// Redarea continutului video utilizand FMJ
String[]arguments = new String[1];
arguments[0]=URLUtils.createUrlStr(f);
System.out.println("Video show");
FmjStudio.main(arguments);
}
Valoarea rezultată din metoda getContentType ı̂n cazul unui ataşament video diferă
de tipul acesteia. Astfel pentru tipul avi valoarea retunată este application/x-troff-msvideo,
iar pentru wmv se obţine content/unknown. Redarea conţinutului video se face uti-
lizând produsul Free Media for Java - FMJ.

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

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

10 String f i l e l o c a t i o n , image location , mp3 location , v i d e o l o c a t i o n ;


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 ,
12 String mp3 location , String v i d e o l o c a t i o n ){
13 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 ;
14 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 ;
15 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 ;
16 t h i s . v i d e o l o c a t i o n=v i d e o l o c a t i o n ;
17 }

19 public void run ( ) {


20 try {
21 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=
22 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 ( ) ;
23 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” j o n a t h a n ” ) ;
24 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
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 T o p i c S e s s i o n s e s s i o n=
27 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) ;
28 // Topic t=new com . sun . m e s s a g i n g . Topic (” Date ” ) ;
29 // 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 ) ;
30 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 ” ) ;
31 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 ) ;

33 Me ss age Fa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ;


34 SOAPMessage soapMsg=mf . c r e a t e M e s s a g e ( ) ;
35 SOAPPart p a r t=soapMsg . getSOAPPart ( ) ;
36 SOAPEnvelope e n v e l o p e=p a r t . g e t E n v e l o p e ( ) ;
37 SOAPBody body=e n v e l o p e . getBody ( ) ;
38 Name bodyName=e n v e l o p e . createName ( ” v e r i f ” ) ;
39 SOAPElement e l e m e n t=body . addBodyElement ( bodyName ) ;
40 e l e m e n t . addTextNode ( ”MyAttachment” ) ;

42 // Crearea a t a s a m e n t u l u i de t i p t e x t

44 AttachmentPart attachment1=soapMsg . c r e a t e A t t a c h m e n t P a r t ( ) ;

46 F i l e R e a d e r f r = new F i l e R e a d e r (new F i l e ( f i l e l o c a t i o n ) ) ;
47 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 ) ;

49 S t r i n g stringContent = ”” ;
50 S t r i n g l i n e = br . r e a d L i n e ( ) ;
51 while ( l i n e != n u l l ) {
52 stringContent = stringContent . concat ( l i n e ) ;
53 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” ) ;
54 l i n e = br . r e a d L i n e ( ) ;
55 }

57 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 ” ) ;
58 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 ” ) ;
59 soapMsg . addAttachmentPart ( attachment1 ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 115

61 // Crearea a t a s a m e n t u l u i de t i p imagine
62 URL u r l = new URL( ” f i l e : / / ”+i m a g e l o c a t i o n ) ;
63 DataHandler d a t a H a n d l e r = new DataHandler ( u r l ) ;
64 AttachmentPart attachment2 =
65 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 ) ;

67 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 ” ) ;
68 soapMsg . addAttachmentPart ( attachment2 ) ;

70 // Crearea unui atasament de t i p mp3


71 u r l=new URL( ” f i l e : / / ”+m p 3 l o c a t i o n ) ;
72 d a t a H a n d l e r= new DataHandler ( u r l ) ;
73 AttachmentPart attachment3 =
74 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 ) ;

76 attachment3 . s e t C o n t e n t I d ( ” attached mp3 ” ) ;


77 soapMsg . addAttachmentPart ( attachment3 ) ;

79 // Crearea unui atasament v i d e o


80 u r l=new URL( ” f i l e : / / ”+v i d e o l o c a t i o n ) ;
81 d a t a H a n d l e r= new DataHandler ( u r l ) ;
82 AttachmentPart attachment4 =
83 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 ) ;
84 F i l e v i d e o F i l e = new F i l e ( v i d e o l o c a t i o n ) ;
85 S t r i n g f i l e N a m e = v i d e o F i l e . getName ( ) ;
86 i n t i n d e x=f i l e N a m e . l a s t I n d e x O f ( ” . ” ) ;
87 S t r i n g e x t=f i l e N a m e . s u b s t r i n g ( i n d e x +1);
88 attachment4 . s e t C o n t e n t I d ( ” a t t a c h e d v i d e o ”+e x t ) ;
89 soapMsg . addAttachmentPart ( attachment4 ) ;

91 Message m=
92 M es s ag e Tr an s fo r me r . SOAPMessageIntoJMSMessage ( soapMsg , s e s s i o n ) ;
93 // p u b l i s h e r . p u b l i s h (m) ;
94 p r o d u c e r . send (m) ;
95 F i l e O u t p u t S t r e a m f=new F i l e O u t p u t S t r e a m ( ”MySOAPMessage . xml” ) ;
96 soapMsg . w r i t e T o ( f ) ;
97 conn . c l o s e ( ) ;
98 }
99 catch ( E x c e p t i o n e ) {
100 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 ( ) ) ;
101 }
102 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 ” ) ;
103 }
104 }

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 . ∗ ;
7 import n e t . s f . fmj . u t i l i t y . URLUtils ;
8 import n e t . s f . fmj . u i . FmjStudio ;
116 CAPITOLUL 5. MESAJE ÎN JAVA

10 public c l a s s MsgSOAPSubscriber extends Thread {

12 public void run ( ) {


13 try {
14 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=
15 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 ( ) ;
16 // c f . s e t P r o p e r t y (” imqBrokerHostName ” ,” j o n a t h a n ” ) ;
17 // c f . s e t P r o p e r t y (” imqBrokerHostPort ” , ” 7 6 7 6 ” ) ;
18 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 ( ) ;
19 T o p i c S e s s i o n s e s s i o n=
20 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) ;
21 // Topic t=new com . sun . m e s s a g i n g . Topic (” Date ” ) ;
22 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 ” ) ;
23 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 ) ;

25 conn . s t a r t ( ) ;
26 Message msg=n u l l ;
27 Me ss age Fa ct ory mf=Me ssa ge Fac to ry . n e w I n s t a n c e ( ) ;
28 while ( ( msg=consumer . r e c e i v e ( ) ) ! = n u l l ) {
29 SOAPMessage soapMsg =
30 M es s ag e Tr an s fo r me r . SOAPMessageFromJMSMessage ( msg , mf ) ;
31 System . out . p r i n t l n ( ” Mesaj SOAP r e c e p t i o n a t ” ) ;
32 // E x t r a g e r e a a t a s a m e n t e l o r
33 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 ( ) ;
34 while ( i t e r a t o r . hasNext ( ) ) {
35 AttachmentPart a t t a c h e d =(AttachmentPart ) i t e r a t o r . n e x t ( ) ;
36 String id = attached . getContentId ( ) ;
37 S t r i n g t y p e = a t t a c h e d . getContentType ( ) ;
38 System . out . p r i n t l n ( ” Attachment ” + i d +
39 ” has c o n t e n t t y p e ” + t y p e ) ;
40 i f ( type . e q u a l s ( ” t e x t / p l a i n ” ) ) {
41 S t r i n g content = ( S t r i n g ) attached . getContent ( ) ;
42 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 ) ;
43 }
44 i f ( t y p e . e q u a l s ( ” image / j p e g ” ) ) {
45 Image image=(Image ) a t t a c h e d . g e t C o n t e n t ( ) ;
46 ShowImage s=new ShowImage ( image ) ;
47 s . show ( ) ;
48 }
49 i f ( t y p e . e q u a l s ( ” a u d i o /x−wav” ) ) {
50 System . out . p r i n t l n ( ” Play MP3” ) ;
51 MP3Player mp3Player=new MP3Player ( a t t a c h e d . getRawContent ( ) ) ;
52 mp3Player . s t a r t ( ) ;
53 }
54 i f ( id . startsWith ( ” attached video ” )){
55 S t r i n g vi d e o F il e N a m e = ” v i d e o F i l e . ”+i d . s u b s t r i n g ( 1 4 ) ;
56 InputStream i n p u t S t r e a m = a t t a c h e d . getRawContent ( ) ;
57 F i l e f=new F i l e ( v i de o F i l eN a m e ) ;
58 OutputStream out=new F i l e O u t p u t S t r e a m ( f ) ;
59 byte b u f [ ] =new byte [ 1 0 2 4 ] ;
60 int l e n ;
61 while ( ( l e n=i n p u t S t r e a m . r e a d ( b u f )) >0) out . w r i t e ( buf , 0 , l e n ) ;
62 out . c l o s e ( ) ;
63 S t r i n g [ ] arguments = new S t r i n g [ 1 ] ;
64 arguments [ 0 ] = URLUtils . c r e a t e U r l S t r ( f ) ;
65 System . out . p r i n t l n ( ” P r e s s Enter t o c o n t i n u e ! ” ) ;
66 System . i n . r e a d ( ) ;
67 System . out . p r i n t l n ( ” Video show ” ) ;
68 FmjStudio . main ( arguments ) ;
5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 117

69 }
70 }
71 }
72 conn . c l o s e ( ) ;
73 }
74 catch ( E x c e p t i o n e ) {
75 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 ( ) ) ;
76 }
77 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 ” ) ;
78 }
79 }

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 }

Utilizarea aplicaţiei se face prin ant pe structura iniţială de cataloage şi fişiere
app
|--> resources
| | resursele text, imagine, mp3, video
|--> src
| | MsgAttach.java
| | MsgSOAPPublisher.java
| | MsgSOAPSubscriber.java
| | MP3Player.java
| | ShowImage.java
| logging.properties (din FMJ)
| build.xml

şi cu 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 default=” run ” b a s e d i r=” . ”>
3 <p r o p e r t y name=”mq . home” v a l u e=” d : /mq” />
4 <p r o p e r t y name=” r e s o u r c e s . home” l o c a t i o n=” ${ b a s e d i r }/ r e s o u r c e s ” />
5 <p r o p e r t y name=” fmj . home” l o c a t i o n=” d : /JavaApp/ fmj ” />

7 <path i d=” c l a s s p a t h ” >


8 <p a t h e l e m e n t path=” b u i l d / c l a s s e s ” />
9 <p a t h e l e m e n t path=” ${ fmj . home}/ fmj . j a r ” />
10 < f i l e s e t d i r=” ${mq . home}/ l i b ”>
11 <i n c l u d e name=” ∗ . j a r ” />
12 </ f < i l e s e t>
13 < f i l e s e t d i r=” ${ fmj . home}/ l i b ”>
14 <i n c l u d e name=” ∗ . j a r ” />
15 </ f i l e s e t>
16 </ path>
118 CAPITOLUL 5. MESAJE ÎN JAVA

18 <t a r g e t name=” i n i t ”>


19 <mkdir d i r=” b u i l d ” />
20 <mkdir d i r=” b u i l d / c l a s s e s ” />
21 </ t a r g e t>

23 <t a r g e t name=” c o m p i l e ” depends=” i n i t ”>


24 <j a v a c s r c d i r=” s r c ” c l a s s p a t h r e f=” c l a s s p a t h ”
25 d e s t d i r=” b u i l d / c l a s s e s ” debug=” y e s ” />
26 </ t a r g e t>

28 <t a r g e t name=” s e r v e r ”>


29 <e x e c e x e c u t a b l e=” ${mq . home}/ b i n / imqbrokerd . e x e ” d i r=” ${mq . home}/ b i n ” />
30 </ t a r g e t>

32 <t a r g e t name=” run ” depends=” c o m p i l e ”>


33 <j a v a c l a s s n a m e=” MsgAttach ” c l a s s p a t h r e f=” c l a s s p a t h ”
34 f o r k=” y e s ” f a i l o n e r r o r=” y e s ”>
35 <s y s p r o p e r t y key=” f i l e l o c a t i o n ”
36 v a l u e=” ${ r e s o u r c e s . home}/ c a p i t o l . t x t ” />
37 <s y s p r o p e r t y key=” i m a g e l o c a t i o n ”
38 v a l u e=” l o c a l h o s t /${ r e s o u r c e s . home}/ xml−p i c . j p g ” />
39 <s y s p r o p e r t y key=” m p 3 l o c a t i o n ”
40 v a l u e=” l o c a l h o s t /${ r e s o u r c e s . home}/ Tomjones . mp3” />
41 <s y s p r o p e r t y key=” v i d e o l o c a t i o n ”
42 v a l u e=” l o c a l h o s t /${ r e s o u r c e s . home}/ c l o c k . a v i ” />
43 <s y s p r o p e r t y key=” j a v a . l i b r a r y . path ”
44 v a l u e=” ${ fmj . home}/ n a t i v e / win32−x86 ” />
45 </ j a v a>
46 </ t a r g e t>

48 </ p r o j e c t>

Programul de afişare a imaginii


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

8 c l a s s MyCanvas e x t e n d s Canvas {
9 Image image=n u l l ;

11 MyCanvas ( Image image ) {


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

15 p u b l i c void paint ( Graphics g ){


16 g . drawImage ( image , 0 , 0 , t h i s ) ;
17 }
18 }

20 p u b l i c c l a s s ShowImage{
21 MyCanvas mc=n u l l ;

23 ShowImage ( Image image ) {


24 mc=new MyCanvas ( image ) ;
25 }
5.6. PROGRAME JMS PRIN APACHE-QPID 119

27 p u b l i c v o i d show ( ) {
28 // I n t e r f a t a swing
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 jframe . 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 im po rt j a v a . i o . ∗ ;
2 im po rt javazoom . j l . p l a y e r . P l a y e r ;

4 p u b l i c c l a s s MP3Player e x t e n d s Thread {
5 private Player player ;

7 p u b l i c MP3Player ( InputStream i s ) {
8 try {
9 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 ) ;
10 p l a y e r=new P l a y e r ( b i s ) ;
11 }
12 catch ( Exception e ){
13 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
14 System . e x i t ( 1 ) ;
15 }
16 }

18 p u b l i c v o i d run ( ) {
19 try {
20 player . play ( ) ;
21 }
22 catch ( Exception e ){
23 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
24 }
25 i f ( p l a y e r != n u l l ) p l a y e r . c l o s e ( ) ;
26 }
27 }

5.6 Programe JMS prin apache-qpid


apache-qpid reprezintă o implementare a protocolului AMQP care poate fi folosit
de clienti Java, C++, C#, Pyton, Ruby. Programele dezvoltate utilizând Oracle-
Sun Java System Message Queue sau apache-ActiveMQ se rulează (aproape) fără
modificări. Acest fapt dorim să-l prezentăm ı̂n continuare.
Instalarea serviciului de mesagerie revine la

1. Dezarhivarea fişierului descărcat;


120 CAPITOLUL 5. MESAJE ÎN JAVA

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

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 −im po rt − a l i a s q p i d B r o k e r C e r t − f i l e q p i d B r o k e r . c e r
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

Eventual trebuie fixată locatia fişierului qpid.keystore ı̂n elementul keyStorePath


din fişierul QPID HOME\etc\config.xml.
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. De 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 1 .
1
Aplicaţiile pot fi executate utilizând oricare din implementările JMS, schimbând doar fişierul
jndi.properties.
5.6. PROGRAME JMS PRIN APACHE-QPID 121

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.
În clasa MsgHelloT câmpul queueName reprezintă numele JNDI al cozii.
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 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 ;

12 MsgSenderT ( S t r i n g queueName , i n t n ) {
13 QUEUE JNDI NAME=queueName ;
14 t h i s . n=n ;
15 }

17 public void run ( ) {


18 try {
19 setupJNDI ( ) ;
20 // 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
21 QueueConnectionFactory c f=
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 ( ” Sen de r f i n i s h e d ” ) ;
42 }

44 private void setupJNDI ( ) {


45 // S e t t h e p r o p e r t i e s . . .
46 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 ( ) ;
47 try {
48 p r o p e r t i e s . load ( this . g e t C l a s s ( ) . getResourceAsStream ( ” j n d i . p r o p e r t i e s ” ) ) ;
49 }
50 catch ( IOException e ) {
122 CAPITOLUL 5. MESAJE ÎN JAVA

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 // C r e a t e t h e i n i t i a l c o n t e x t
54 try {
55 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 ) ;
56 }
57 catch ( NamingException e ) {
58 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 ) ;
59 }
60 }

62 private void c l o s e J N D I ( ) {
63 try {
64 ctx . c l o s e ( ) ;
65 }
66 catch ( NamingException e ) {
67 System . e r r . p r i n t l n ( ” Unable t o c l o s e JNDI Context : ” + e ) ;
68 }
69 }
70 }

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

11 SyncMsgReceiverT ( S t r i n g queueName ) {
12 QUEUE JNDI NAME=queueName ;
13 }

15 public void run ( ) {


16 try {
17 setupJNDI ( ) ;
18 // 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
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 ( ) ;

26 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 }
5.6. PROGRAME JMS PRIN APACHE-QPID 123

38 }
39 session . close ();
40 conn . c l o s e ( ) ;
41 }
42 catch ( E x c e p t i o n e ) {
43 System . out . p r i n t l n ( ” JMSException : ”+e . g e t M e s s a g e ( ) ) ;
44 }
45 System . out . p r i n t l n ( ” Consumer f i n i s h e d ” ) ;
46 }

48 private void setupJNDI ( ) { . . . }

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

52 }

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.
În clasa MsgPS câmpul subiect reprezintă numele JNDI ataşat topic-ului.
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 S t r i n g TOPIC JNDI NAME = ” t o p i c ” ;
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 ;

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 TOPIC JNDI NAME=s u b i e c t ;
15 }

17 public void run ( ) {


18 try {
19 setupJNDI ( ) ;
20 // 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
21 T o p i c C o n n e c t i o n F a c t o r y c f=
22 ( 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 ) ;
23 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 ( ) ;
24 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 ,
25 S e s s i o n .AUTO ACKNOWLEDGE) ;
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 (TOPIC JNDI NAME ) ;
27 closeJNDI ( ) ;

29 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 ) ;
30 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 ( ) ;
31 f o r ( i n t i =0; i <n ; i ++){
32 m. s e t T e x t ( ” Despre JMS”+” ”+i ) ;
124 CAPITOLUL 5. MESAJE ÎN JAVA

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

45 private void setupJNDI ( ) { . . . }

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

49 }

Clasa MsgSubscriberT
1 j a v a x . jms . ∗ ;
2 import j a v a x . naming . ∗ ;
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 S t r i n g TOPIC JNDI NAME = ” t o p i c ” ;
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 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 TOPIC JNDI NAME=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 (TOPIC JNDI NAME ) ;
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 ( ) ) ;
5.6. PROGRAME JMS PRIN APACHE-QPID 125

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

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

58 }

Fişiere JNDI cu datele de regăsire


Programele secţiunii anterioare se pot utiliza cu oricare de distribuţiile JMS
Oracle-Sun Message Queue, apache-actimemq, qpid.
Fişierele jndi.properties specifice fiecărei distribuţii sunt
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 . t o p i c = 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

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
126 CAPITOLUL 5. MESAJE ÎN JAVA

Varianta Oracle-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 Oracle-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 rem imqobjmgr add −t t f − l ” C o n n e c t i o n F a c t o r y ”
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 q − l ” queue ”
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
11 rem imqobjmgr add −t t − l ” t o p i c ”
12 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
13 −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 t f − l ” C o n n e c t i o n F a c t o r y ”
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 q − l ” queue ”
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
11 imqobjmgr d e l e t e −t t − l ” t o p i c ”
12 −j j a v a . naming . p r o v i d e r . u r l= f i l e : /// c : /Temp
13 −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.7 Protocolul AMQP


Punem ı̂n evidenţă un alt model de aplicaţie, specific protocolului AMQP.
Modelul prevede existenţa a trei entităţi:
5.7. PROTOCOLUL AMQP 127

• exchange – Dispecer de direcţionare ce primeşte mesaje de la un producător


de mesaje şi le distribuie unor cozi pe baza unui criteriu;

• message queue – coadă ı̂n care se păstrează mesaje până ce acestea sunt con-
sumate de o aplicaţie client.
Proprietăţile unei cozi sunt:

– numele, alcătuit din litere, cifre, caracterul de subliniere, cel mult 255 de
caracter.
– persistenţa mesajului ı̂n cazul ı̂ncetării funcţionării serverului (durable
message queue, temporary message queue).
– modul de ştergere a mesajelor după consumarea acestora (auto-delete).

• binding – criteriul după care un mesaj este distribuit de dispecerul de mesaje


unei cozi.

O coadă comunică dispecerului de direcţionare o cheie denumită cheie de legare


(binding key) K, ı̂n timp ce orice mesaj va conţine o cheie de rutare (routing key)
R.
AMPQ defineşte trei criterii de distribuire a mesajelor de către dispecerul de
direcţionare:

• distribuirea directă realizează o distribuire 1:1 a mesajelor:

1. o coadă se leagă de dispecerul de direcţionare cu cheia de legare K;


2. un mesaj conţine cheia de rutare R;
3. dispecerul de direcţionare trimite mesajul către toate cozile care satisfac
condiţia R = K.

• distribuirea fanout realizează o distribuire 1:N a mesajelor:

1. o coadă se leagă de dispecerul de direcţionare fără cheie de legare;


2. un mesaj nu conţine cheie de rutare (eventual cheia de rutare este negli-
jată);
3. dispecerul de direcţionare trimite necondiţional mesajul către toate cozile
ı̂nregistrate.

• distribuirea publicare-abonare

1. o coadă se leagă de dispecerul de direcţionare cu cheia de legare K;


2. un mesaj conţine cheia de rutare R;
128 CAPITOLUL 5. MESAJE ÎN JAVA

3. dispecerul de direcţionare trimite mesajul către toate cozile a căror cheie


de legare se potriveşte cu cheia de rutare.
Cheia de legare este alcătuită din mai multe cuvinte (token) separate de
caracterul ’.’ (punct). Cheia de rutare poate conţine caracterele
– # - va presupune potrivirea cu un cuvânt sau nu.
– * - va presupune potrivirea cu cel puţin un cuvânt.
Astfel *.abc se potriveşte cu x.abc dar nu se potriveşte cu abc, ı̂n timp
ce #.abc se potriveşte cu x.abc şi abc.

Corespunzător celor trei criterii de distribuire a mesajelor, serverul AMQP conţine


dispecerii de direcţionare

• amq.direct

• amq.fanout

• amq.topic

Un mesaj este expediat de client către un dispecer de direcţionare aflat pe un


server AMQP. Preluarea unui mesaj dintr-o coadă de către un client are ca urmare
ştergerea mesajului ı̂n coadă.
Resursele necesare aparţin pachetului org.apache.qpid.transport.

5.7.1 Crearea unei cozi


Crearea unei cozi constă din

1. Realizarea conexiunii cu serverul AMQP

Connection con = new Connection();


con.connect(broker,port,login,passworg,clientId,false);

2. Instanţierea sesiunii

Session session = con.createSession(0);

3. Declararea cozii

session.queueDeclare(numeCoada, null, null);


session.exchangeBind(numeCoada, dispecerulDeDirectionare,
binding_key, null);

4. Aşteptarea confirmării acţiunii de realizare a cozii


5.7. PROTOCOLUL AMQP 129

session.sync();

5. Închiderea sesiunii şi a conexiunii

session.close();
con.close();

Exemplul 5.7.1 Crearea unei cozi care să primească mesaje prin distribuire directă
şi fanout.

1 import o r g . apache . q p i d . t r a n s p o r t . ∗ ;

3 public c l a s s DeclareQueue {
4 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
5 i f ( a r g s . l e n g t h <5){
6 System . out . p r i n t l n ( ” Usage j a v a DeclareQueue b r o k e r ” +
7 ” p o r t queueName exchange bindingKey ” ) ;
8 System . e x i t ( 1 ) ;
9 }
10 S t r i n g b r o k e r=a r g s [ 0 ] ;
11 i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
12 S t r i n g queueName=a r g s [ 2 ] ;
13 S t r i n g exchange=a r g s [ 3 ] ;
14 S t r i n g bindingKey=a r g s [ 4 ] ;

16 // Crearea c o n e x i u n i i
17 C o n n e c t i o n con = new C o n n e c t i o n ( ) ;
18 con . c o n n e c t ( b r o k e r , p o r t , ” t e s t ” , ” g u e s t ” , ” g u e s t ” , f a l s e ) ;

20 // Crearea s e s i u n i i
21 S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;

23 // D e c l a r a r e a c o z i i
24 s e s s i o n . q u e u e D e c l a r e ( queueName , null , n u l l ) ;
25 s e s s i o n . exchangeBind ( queueName , exchange , bindingKey , n u l l ) ;

27 // Confirmarea c r e e r i i c o z i i
28 s e s s i o n . sync ( ) ;

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

5.7.2 Expedierea / publicarea unui mesaj


Expedierea / publicarea unui mesaj constă din
1. Realizarea conexiunii cu serverul AMQP

Connection con = new Connection();


con.connect(broker,port,login,passworg,clientId,false);
130 CAPITOLUL 5. MESAJE ÎN JAVA

2. Instanţierea sesiunii

Session session = con.createSession(0);

3. Precizarea (dacă este nevoie) a cheii de rutare

DeliveryProperties deliveryProps = new DeliveryProperties();


deliveryProps.setRoutingKey(routing_key);

4. Crearea şi expedierea mesajului

session.messageTransfer(dispecerulDeDirectionare,
MessageAcceptMode.EXPLICIT,
MessageAcquireMode.PRE_ACQUIRED,
new Header(deliveryProps),
mesaj_text);

5. Aşteptarea confirmării recepţiei mesajului decătre serverul AMQP

session.sync();

6. Închiderea sesiunii şi a conexiunii

session.close();
con.close();

Exemplul 5.7.2 Expedierea unui număr de mesaje cu conţinut text, urmat de un


mesaj fără conţinut, fapt care marchează sfârşitul trimiterii de date.

1 import o r g . apache . q p i d . t r a n s p o r t . ∗ ;

3 public c l a s s Se nd er {
4 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
5 i f ( a r g s . l e n g t h <5){
6 System . out . p r i n t l n ( ” Usage j a v a S en der b r o k e r p o r t ” +
7 ” exchange r o u t i n g K e y messagesNumber ” ) ;
8 System . e x i t ( 1 ) ;
9 }
10 S t r i n g b r o k e r=a r g s [ 0 ] ;
11 i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
12 S t r i n g exchange=a r g s [ 2 ] ;
13 S t r i n g r o u t i n g K e y=a r g s [ 3 ] ;
14 i n t n=I n t e g e r . p a r s e I n t ( a r g s [ 4 ] ) ;

16 // Crearea c o n e x i u n i i
17 C o n n e c t i o n con = new C o n n e c t i o n ( ) ;
18 con . c o n n e c t ( b r o k e r , p o r t , ” t e s t ” , ” g u e s t ” , ” g u e s t ” , f a l s e ) ;
5.7. PROTOCOLUL AMQP 131

20 // Crearea s e s i u n i i
21 S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;

23 // P r e c i z a r e a ( daca e s t e n e v o i e ) a c h e i i de r u t a r e
24 D e l i v e r y P r o p e r t i e s d e l i v e r y P r o p s = new D e l i v e r y P r o p e r t i e s ( ) ;
25 d e l i v e r y P r o p s . s etR ou ti ngK ey ( r o u t i n g K e y ) ;

27 // Formarea s i e x p e d i e r e a m e s a j e l o r
28 f o r ( i n t i =0; i <n ; i ++){
29 s e s s i o n . m e s s a g e T r a n s f e r ( exchange ,
30 MessageAcceptMode . EXPLICIT ,
31 MessageAcquireMode . PRE ACQUIRED,
32 new Header ( d e l i v e r y P r o p s ) ,
33 ” Message ” + i ) ;
34 }
35 s e s s i o n . m e s s a g e T r a n s f e r ( exchange ,
36 MessageAcceptMode . EXPLICIT ,
37 MessageAcquireMode . PRE ACQUIRED,
38 new Header ( d e l i v e r y P r o p s ) ,
39 ”” ) ;

41 // Confirmarea r e c e p t i e i m e s a j e l o r
42 s e s s i o n . sync ( ) ;

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

5.7.3 Recepţionarea mesajelor


Mesaje se recepţionează asincron, adică de o clasă ascultătoare care implementează
interfaţa SessionListener.
Interfaţa SessionListener declară metodele:
public void opened(Session session)
public void resumed(Session session)
public void message(Session session, MessageTransfer xfr)
public void exception(Session session, SessionException e)
public void closed(Session session)
Recepţionarea de mesaje constă din
1. Realizarea conexiunii cu serverul AMQP

Connection con = new Connection();


con.connect(broker,port,login,passworg,clientId,false);

2. Instanţierea sesiunii

Session session = con.createSession(0);


132 CAPITOLUL 5. MESAJE ÎN JAVA

3. Precizarea ascultătorului de mesaje (Fie Listener o clasa care implementează


interfaţa SessionListener)

Listener listener = new Listener();


session.setSessionListener(listener);

4. Crearea abonatului care urmează să recepţioneaze mesaje. Ascultătorul va fi


caracterizat de un nume - listener destination.

session.messageSubscribe(numeCoada,
"listener_destination",
MessageAcceptMode.NONE,
MessageAcquireMode.PRE_ACQUIRED,
null, 0, null);
session.messageFlow("listener_destination",
MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT);
session.messageFlow("listener_destination",
MessageCreditUnit.MESSAGE, 11);

5. Aşteptarea confirmării trimiterii tuturor mesajelor disponibile de către serverul


AMQP

session.sync();

6. Oprirea ascultătorului

session.messageCancel("listener_destination");

7. Închiderea sesiunii şi a conexiunii

session.close();
con.close();

Exemplul 5.7.3 Recepţia mesajelor expediate ı̂n clasa Sender, creata anterior. Pro-
gramul se va termina ı̂n momentul ı̂n care ascultătorul primeşte un mesaj fără
conţinut.

1 import o r g . apache . q p i d . t r a n s p o r t . ∗ ;

3 c l a s s L i s t e n e r implements S e s s i o n L i s t e n e r {
4 boolean s f a r s i t =f a l s e ;

6 public void opened ( S e s s i o n s e s s i o n ) { }


7 public void resumed ( S e s s i o n s e s s i o n ) { }
5.7. PROTOCOLUL AMQP 133

8 public void message ( S e s s i o n s e s s i o n , M e s s a g e T r a n s f e r x f r ) {


9 System . out . p r i n t l n ( ” Message : ” + x f r ) ;
10 S t r i n g sMsg=x f r . t o S t r i n g ( ) ;
11 i f ( sMsg . endsWith ( ” body=\”\”” ) ) s f a r s i t =true ;
12 }
13 public void e x c e p t i o n ( S e s s i o n ssn , S e s s i o n E x c e p t i o n e ) {
14 System . out . p r i n t l n ( ” S e s s i o n L i s t e n e r E x c e p t i o n : ”+e . g e t M e s s a g e ( ) ) ;
15 }
16 public void c l o s e d ( S e s s i o n s e s s i o n ) {}

18 public void run ( ) {


19 while ( ! s f a r s i t ) ;
20 }
21 }

23 public c l a s s R e c e i v e r {
24 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws I n t e r r u p t e d E x c e p t i o n {
25 i f ( a r g s . l e n g t h <3){
26 System . out . p r i n t l n ( ” Usage j a v a S en der b r o k e r p o r t queueName” ) ;
27 System . e x i t ( 1 ) ;
28 }
29 S t r i n g b r o k e r=a r g s [ 0 ] ;
30 i n t p o r t=I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ;
31 S t r i n g queueName=a r g s [ 2 ] ;

33 // Crearea c o n e x i u n i i
34 C o n n e c t i o n con = new C o n n e c t i o n ( ) ;
35 con . c o n n e c t ( b r o k e r , p o r t , ” t e s t ” , ” g u e s t ” , ” g u e s t ” , f a l s e ) ;

37 // Crearea s e s i u n i i
38 S e s s i o n s e s s i o n = con . c r e a t e S e s s i o n ( 0 ) ;

40 // Generarea u n e i i n s t a n t e a a s c u l t a t o r u l u i
41 L i s t e n e r l i s t e n e r = new L i s t e n e r ( ) ;
42 session . setSessionListener ( listener );

44 // Crearea a b o n a t u l u i c a r e r e c e p t i o n e a z e m e s a j e l e
45 s e s s i o n . m e s s a g e S u b s c r i b e ( queueName ,
46 ”listener destination” ,
47 MessageAcceptMode .NONE,
48 MessageAcquireMode . PRE ACQUIRED,
49 null , 0 , n u l l ) ;
50 s e s s i o n . messageFlow ( ” l i s t e n e r d e s t i n a t i o n ” ,
51 M e s s a g e C r e d i t U n i t .BYTE, S e s s i o n . UNLIMITED CREDIT ) ;
52 s e s s i o n . messageFlow ( ” l i s t e n e r d e s t i n a t i o n ” ,
53 M e s s a g e C r e d i t U n i t .MESSAGE, 1 1 ) ;

55 // Confirmarea t e r m i n a r i i t r a n s m i t e r i i m e s a j e l o r
56 s e s s i o n . sync ( ) ;

58 // A b o n a t u l a s t e a p t a r e c e p t i o n a r e a t u t u r o r m e s a j e l o
59 l i s t e n e r . run ( ) ;

61 // O p r i r e a a s c u l t a t o r u l u i
62 System . out . p r i n t l n ( ” S h u t t i n g down l i s t e n e r f o r l i s t e n e r d e s t i n a t i o n ” ) ;
63 s e s s i o n . messageCancel ( ” l i s t e n e r d e s t i n a t i o n ” ) ;

65 // I n c h i d e r e a s e s i u n i i s i a c o n e x i u n i i
66 session . close ();
134 CAPITOLUL 5. MESAJE ÎN JAVA

67 con . c l o s e ( ) ;
68 }
69 }

Utilizând clasele prezentate mai sus, prin fixarea convenabilă a parametrilor şi
a ordinii de lansare a programelor se poate exemplifica specificul celor trei dispeceri
de direcţionare:
Codurile pentru execuţie prin ant sunt

• Distribuirea directă:

<target name="run" depends="compile">


<java classname="DeclareQueue" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 message_queue amq.direct routing_key"/>
</java>
<sleep seconds="15" />
<java classname="Sender" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 amq.direct routing_key 5"/>
</java>
<sleep seconds="5" />
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 message_queue"/>
</java>
</target>

• Distribuirea fanout:

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

<target name="sender">
<java classname="Sender" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 amq.fanout zzz 2"/>
</java>
</target>

<target name="receiver">
<sleep seconds="5" />
<parallel>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1"/>
</java>
<java classname="Receiver" fork="yes" maxmemory="100M">
5.7. PROTOCOLUL AMQP 135

<classpath refid="qpid.classpath" />


<arg line="localhost 5672 q2"/>
</java>
</parallel>
</target>

• Distribuirea bazată pe publicare-abonare:

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

<target name="receiver">
<parallel>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q1"/>
</java>
<java classname="Receiver" fork="yes" maxmemory="100M">
<classpath refid="qpid.classpath" />
<arg line="localhost 5672 q2"/>
</java>
</parallel>
</target>

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

În cazul distribuirii fanout şi a celei bazate pe publicare-abonare sunt lansate ı̂n
ordine două cozi cu câte un receptor de mesaje (Receiver ) urmat de producătorul
de mesaje (Sender ).
136 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: Google Chrome,
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.
Programarea ş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.

137
138 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
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
. . . . . . . . . . . . . . . .
</select>
6.2. SERVER WEB - CONTAINER DE SERVLET 139

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

• Oracle-Sun Java System Application Server


Acest server Web este utilizat ı̂n Glassfish - o implementare JEE (Java Enter-
prise Edition).

• JBoss

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.
140 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 141

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.
142 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 prin

http://host:port/context/numeApel
6.3. REALIZAREA UNUI SERVLET 143

unde

– context este dat de numele catalogului ce conţine servlet-ul - ı̂n exemplul


anterior acesta este 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/context/numeApel "> ...</a>

• ca valoare a atributului action ı̂ntr-un marcaj form

<form action="http://host:port/context/numeApel” ... >

Contextul este legat de fişierul web.xml şi poate conţine o mulţime de servleţi, fiecare
identificându-se prin numeApel.
Dacă context-ul servletului conţine fişierul index.html atunci aplicaţia se poate
apela prin http:// host:port/context.
Dacă este prezent elementul <welcome-file-list> ı̂n fişierul web.xml atunci
apelarea aplicaţiei poate fi http:// host:port/context/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 GenericServlet. Extinzând clasa GenericServlet nu este nevoie de
rescrierea 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.
144 CAPITOLUL 6. SERVLET

• abstract public void destroy()


Se apelează o singură dată la distrugerea servlet-ului.
• public String getServletInfo()
• 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:
6.3. REALIZAREA UNUI SERVLET 145

• "text/html" - pagină html;


• "text/xml" - document xml;
• "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().

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>
146 CAPITOLUL 6. SERVLET

12 <p>
13 <input type=” submit ”>
14 </form>
15 </ center>
16 </body>
17 </html>

Servlet-ului are codul


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>
6.3. REALIZAREA UNUI SERVLET 147

Compilarea şi arhivarea servlet-ului o vom realiza prin intermediul lui apache-
ant. În acest scop se crează structura:
hello
| |---> src
| | | HelloServlet.java
| |---> lib
| |---> web
| | | web.xml
| |---> web-files
| | | index.html
| build.xml

şi se utilizează 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” f i l e =” ${ b a s e d i r }/web/web . xml” />
37 <copy t o d i r=” ${ b u i l d . d i r }/WEB−INF/ l i b ” >
38 < f i l e s e t d i r=” ${ b a s e d i r }/ l i b ” >
39 <i n c l u d e name=” ∗ . j a r ” />
40 </ f i l e s e t>
41 </ copy>
42 <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 } ” />
43 </ t a r g e t>
44 </ p r o j e c t>
148 CAPITOLUL 6. SERVLET

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 . par se Lon 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 )


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.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 149

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=” h id de n ” 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 obţine cu produsul httpcomponents-
client 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.
Catalogul lib din httpcomponents-client conţine, printre altele, fişierele httpcore-
*.jar, httpclient-*.jar, commons-logging-*.jar.
Pentru compilare trebuie declarată ı̂n variabila de sistem classpath referinţa
către httpclient-*.jar şi httpcore-*.jar dar pentru execuţie este nevoie şi de referinta
către commons-logging-*.jar.
Dezvoltarea unui client presupune:

1. Crearea unui obiect de tip org.apache.http.client.HttpClient:

HttpClient client=new DefaultHttpClient();

DefaultHttpClient aparţine pachetului org.apache.http.impl.client.

2. Declararea metodei de transmitere a datelor get, post.

• GET

HttpGet httpget = new HttpGet(uri);

unde uri este String-ul de apelare a servlet-ului, de forma


http://host:port/catalog/numeApel?numeParam=valParam&. . . ,
O soluţie mai elegentă este
150 CAPITOLUL 6. SERVLET

List<NameValuePair> qparams = new ArrayList<NameValuePair>();


qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/catalog/numeApel",URLEncodedUtils.format(qparams,"UTF-8"),
null);
HttpGet httpget = new HttpGet(uri);
. . .
}
catch(. . .){. . .}

• POST

List<NameValuePair> qparams = new ArrayList<NameValuePair>();


qparams.add(new BasicNameValuePair("param_1", value_1));
qparams.add(new BasicNameValuePair("param_2", value_2));
. . .
try{
UrlEncodedFormEntity params=new UrlEncodedFormEntity(qparams,
"UTF-8");
HttpPost httppost=new HttpPost(uri);
httppost.setEntity(params);
. . .
}
catch(. . .){. . .}

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

Clasele HttpGet, HttpPost aparţin pachetului


import org.apache.http.client.methods.

3. Lansarea cererii.

HttpResponse response=httpclient.execute(httpget);

respectiv

HttpResponse response=httpclient.execute(httppost);

4. Preluarea răspunsului.
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 151

HttpEntity entity=response.getEntity();
if(entity!=null){
InputStream is=entity.getContent();
int l;
byte[] tmp=new byte[2048];
while((l=is.read(tmp))!=-1){}
. . .
}

Exemplul 6.4.1 Dezvoltăm un program client pentru servlet-ul CmmdcServlet (post).

1 import j a v a . u t i l . S c a n n e r ;
2 import j a v a . u t i l . L i s t ;
3 import j a v a . u t i l . A r r a y L i s t ;

5 import o r g . apache . h t t p . H t t p E n t i t y ;
6 import o r g . apache . h t t p . HttpResponse ;
7 import o r g . apache . h t t p . c l i e n t . H t t p C l i e n t ;
8 import o r g . apache . h t t p . c l i e n t . methods . HttpPost ;
9 import o r g . apache . h t t p . impl . c l i e n t . D e f a u l t H t t p C l i e n t ;
10 import o r g . apache . h t t p . NameValuePair ;
11 import o r g . apache . h t t p . message . BasicNameValuePair ;
12 import o r g . apache . h t t p . c l i e n t . e n t i t y . UrlEncodedFormEntity ;

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

16 public c l a s s ClientCmmdcServlet2 {
17 s t a t i c S t r i n g u r i=” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t /cmmdc” ;

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


20 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
21 System . out . p r i n t l n ( ”m=” ) ;
22 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 ( ) ;
23 System . out . p r i n t l n ( ”n=” ) ;
24 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 ( ) ;

26 // C r e a t e an i n s t a n c e o f H t t p C l i e n t .
27 H t t p C l i e n t h t t p c l i e n t = new D e f a u l t H t t p C l i e n t ( ) ;

29 // C r e a t e a method i n s t a n c e .
30 L i s t <NameValuePair> qparams = new A r r a y L i s t <NameValuePair > ( ) ;
31 qparams . add (new BasicNameValuePair ( ”m” , m) ) ;
32 qparams . add (new BasicNameValuePair ( ”n” , n ) ) ;
33 qparams . add (new BasicNameValuePair ( ” t i p ” , ” t e x t / p l a i n ” ) ) ;
34 try {
35 UrlEncodedFormEntity params=new UrlEncodedFormEntity ( qparams , ”UTF−8” ) ;
36 HttpPost h t t p p o s t=new HttpPost ( u r i ) ;
37 h t t p p o s t . s e t E n t i t y ( params ) ;
38 HttpResponse r e s p o n s e=h t t p c l i e n t . e x e c u t e ( h t t p p o s t ) ;
39 H t t p E n t i t y e n t i t y=r e s p o n s e . g e t E n t i t y ( ) ;
40 i f ( e n t i t y != n u l l ) {
41 InputStream i s=e n t i t y . g e t C o n t e n t ( ) ;
42 int l ;
43 byte [ ] tmp=new byte [ 2 0 4 8 ] ;
44 while ( ( l=i s . r e a d ( tmp))!= −1){}
152 CAPITOLUL 6. SERVLET

45 System . out . p r i n t l n ( ”Cmmdc = ”+(new S t r i n g ( tmp ) . t r i m ( ) ) ) ;


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

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 . par se Lon 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 ” ;
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 153

28 }
29 else {
30 try {
31 n=Long . p ars eL ong ( 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 . par se Lo ng ( r e q . g e t P a r a m e t e r ( ”m” ) ) ;
13 long n=Long . pa rs eL ong ( 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 }
154 CAPITOLUL 6. SERVLET

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
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 }
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 155

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 ( ) ) ;
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
156 CAPITOLUL 6. SERVLET

• 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 ”.”.

• 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 ( ) ) ;
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 157

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 {
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 {
158 CAPITOLUL 6. SERVLET

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 }

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>
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 159

Acest element apare ı̂n corpul elementului <servlet> ataşat servlet-ului. Servletul
se apelează prin http://host:port/context/numeApel.

6.4.6 Servlet cu conexiune la o bază de date


Folosind Anexa C considerăm

Exemplul 6.4.6 Consultarea unei agende de adrese e-mail. Se utilizează o bază de


date AgendaEMail alcătuită dintr-un singur tabel adrese (id int, nume varchar(20),
numar varchar(30)).

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 . ∗ ;
5 import java . net . ∗ ;

7 public c l a s s A g e n d a E M a i l S e r v l e t extends H t t p S e r v l e t {
8 Statement i n s t r u c t i u n e=n u l l ;

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


11 super . i n i t ( c o n f i g ) ;
12 // SGBD Derby
13 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 ” ;
14 S t r i n g URLBazaDate=” j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ” ;
15 C o n n e c t i o n con=n u l l ;
16 try {
17 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 ( ) ;
18 con=DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ;
19 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 ( ) ;
20 }
21 catch ( ClassNotFoundException e ) {
22 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 ) ;
23 }
24 catch ( SQLException e ) {
25 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 ) ;
26 }
27 catch ( E x c e p t i o n e ) {
28 System . out . p r i n t l n ( ” E r o a r e : ”+e . g e t M e s s a g e ( ) ) ;
29 }
30 }

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


33 throws S e r v l e t E x c e p t i o n , IOException {
34 S t r i n g myAtribut , myVal ;
35 r e s . setContentType ( ” t e x t / html ” ) ;
36 S e r v l e t O u t p u t S t r e a m out = r e s . getOutputStream ( ) ;

38 myAtribut=r e q . g e t P a r a m e t e r ( ” c r i t e r i u ” ) ;
39 myVal=r e q . g e t P a r a m e t e r ( ” termen ” ) ;
40 myVal= ’ \ ’ ’+myVal+ ’ \ ’ ’ ;
41 try {
42 S t r i n g s q l=” s e l e c t ∗ from a d r e s e where ”+ myAtribut+” = ”+myVal ;
43 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 ) ;
160 CAPITOLUL 6. SERVLET

44 out . p r i n t l n ( ”<html>” ) ;
45 out . p r i n t l n ( ”<head><t i t l e >AgendaEMail</ t i t l e ></head>” ) ;
46 out . p r i n t l n ( ”<body>” ) ;
47 out . p r i n t l n ( ”<h1>Agenda de Adrese e−m a i l </h1>” ) ;
48 out . p r i n t l n ( ”<p/>” ) ;
49 out . p r i n t l n ( ”<b> Nume <−−> Adresa e−m a i l </b>” ) ;
50 out . p r i n t l n ( ”<br/>” ) ;
51 while ( r s . n e x t ( ) ) {
52 out . p r i n t ( r s . g e t S t r i n g ( ”nume”)+” <−−> ”+r s . g e t S t r i n g ( ” e m a i l ” ) ) ;
53 out . p r i n t l n ( ”<br/>” ) ;
54 }
55 out . p r i n t l n ( ”</body>” ) ;
56 out . p r i n t l n ( ”</html>” ) ;
57 out . c l o s e ( ) ;
58 }
59 catch ( SQLException e ) {
60 System . out . p r i n t l n ( ” SQLException : ”+e . g e t M e s s a g e ( ) ) ;
61 }
62 catch ( E x c e p t i o n e ) {
63 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 ( ) ) ;
64 }
65 }

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


68 throws S e r v l e t E x c e p t i o n , IOException {
69 doGet ( req , r e s ) ;
70 }
71 }

Apelarea servlet-ului se face din


1 <html>
2 <body>
3 <h1> Cautare i n baza de d a t e AgendaEMail</h1>
4 <form method=” g e t ”
5 action=” h t t p : / / l o c a l h o s t : 8 0 8 0 / agendae / a d r e s e ”>
6 <p>C r i t e r i u de c a u t a r e :
7 <s e l e c t name=” c r i t e r i u ” >
8 <option value=”nume”>dupa Nume
9 <option value=” e m a i l ”>dupa Email
10 </ s e l e c t>
11 <br>
12 <p>E n t i t a t e a c a u t a t a
13 <input type=” t e x t ” name=” termen ” s i z e =30>
14 <p><input type=” submit ” value=” Cauta ”>
15 </form>
16 </body>
17 </html>

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.
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 161

(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 ı̂n fluxul de ieşire de tip
ServletOutputStream, tipul MIME al răspunsului fiind

response.setContentType("image/ext");

ext∈ {gif, jpg, png, . . .}.


Textul sursă al 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 MyGraphG 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 ( ” image / g i f ” ) ;
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 ( ) ;

11 // 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
12 String f =
13 ”d : \ \ apache−tomcat − 6 . 0 . 2 0 \ \ webapps \\ m y s e r v l e t \\WEB−INF\\ ”+
14 ” c l a s s e s \\ w a l k i n g s a n t a . g i f ” ;
15 // T r a n f e r a r e a f i s i e r u l u i g r a f i c
16 F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f ) ;
17 B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ;
18 byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ;
19 i n t nread = 0 ;
20 while (−1 != ( nread = b i s . r e a d ( b y t e s ) ) ) {
21 out . w r i t e ( b y t e s , 0 , nread ) ;
22 }
23 }
24 }

• Pe calculatorul serverului Web, imaginea se salvează ı̂ntr-un fişier grafic, 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.
Dacă tipul fişierului grafic este jpg sau png atunci textul sursă al servlet-ului
este:
162 CAPITOLUL 6. SERVLET

1 mport j a v a . i o . ∗ ;
2 import j a v a . awt . ∗ ;
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 x . i m a g e i o . ∗ ;
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 j a v a . u t i l . ∗ ;

10 public c l a s s MyGraphP extends H t t p S e r v l e t {


11 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 )
12 throws S e r v l e t E x c e p t i o n , IOException {
13 r e s . setContentType ( ” t e x t / html ” ) ;
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 S t r i n g f i l e R e f=”d : \ \ apache−tomcat − 6 . 0 . 2 0 \ \ webapps \\ m y s e r v l e t \\ ” ;
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 ”
18 // Formarea i m a g i n i i
19 Frame frame = n u l l ;
20 Graphics g = null ;
21 B u f f e r e d I m a g e image=n u l l ;
22 try {
23 frame = new Frame ( ) ;
24 frame . a d d N o t i f y ( ) ;
25 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 ) ;
26 g = image . g e t G r a p h i c s ( ) ;
27 // F i x a r e a f o n t u l u i
28 g . s e t F o n t (new Font ( ” S e r i f ” , Font . ITALIC , 4 8 ) ) ;
29 // E d i t a r e a unui t e x t
30 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 ) ;

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


33 F i l e f=new F i l e ( f i l e R e f+numeFis+” . ”+e x t ) ;
34 ImageIO . w r i t e ( image , ” j p g ” , f ) ;

36 // Raspunsul c a t r e c l i e n t
37 out . p r i n t l n ( ”<HTML><BODY>” ) ;
38 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>” ) ;
39 out . p r i n t l n ( ”<p><a h r e f =\” h t t p : / / l o c a l h o s t : 8 0 8 0 / m y s e r v l e t / ”+
40 numeFis+” . ”+e x t+”\”>” ) ;
41 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>” ) ;
42 out . p r i n t l n ( ”</BODY></HTML>” ) ;
43 out . c l o s e ( ) ;
44 }
45 finally {
46 // E l i b e r a r e a r e s u r s e l o r
47 i f ( g != n u l l ) g . d i s p o s e ( ) ;
48 i f ( frame != n u l l ) frame . r e m o v e N o t i f y ( ) ;
49 }
50 }
51 }

Dacă tipul fişierului grafic va fi gif atunci linia 34 se ı̂nlocuieşte cu

FileOutputStream fos=new FileOutputStream(f);


GifEncoder encoder = new GifEncoder(image,fos);
encoder.encode();
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 163

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

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;

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 }
164 CAPITOLUL 6. SERVLET

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 {
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 Oracle−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 ( ) ;
6.4. FACILITĂŢI DE PROGRAMARE CU SERVLET 165

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 . par se Lon g ( sm ) ;
42 long b=Long . p ars eL ong ( 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 . ∗ ;

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 Oracle−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 ” ) ;
166 CAPITOLUL 6. SERVLET

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 . ∗ ;
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 Oracle−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=
6.5. FILEUPLOAD 167

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 }

În catalogul lib al servlet-ului trebuie incluse fişierele jar ale serviciului JMS folosit.

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
168 CAPITOLUL 6. SERVLET

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

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
6.5. FILEUPLOAD 169

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

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();
170 CAPITOLUL 6. SERVLET

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 up l oad ;
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 = up lo ad . p a r s e R e q u e s t ( r e q ) ;
21 up l oad . 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 ( ) ) {
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 }
6.5. FILEUPLOAD 171

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 [ ] s t=l i n e . s p l i t ( ” ” ) ;
64 for ( S t r i n g s : s t ){
65 v . addElement (new Double ( s ) ) ;
66 }
67 }
68 }
69 while ( l i n e != n u l l ) ;
70 i f ( v . s i z e () >0){
71 mn=v . s i z e ( ) ;
72 n=mn/m;
73 m a t r i x=new double [m ] [ n ] ;
74 f o r ( i n t i =0; i <m; i ++){
75 f o r ( i n t j =0; j <n ; j ++){
76 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 ( ) ;
77 System . out . p r i n t ( m a t r i x [ i ] [ j ]+ ” ” ) ;
78 }
79 System . out . p r i n t l n ( ) ;
80 }
81 }
82 }
83 catch ( E x c e p t i o n e ) {
84 throw new E x c e p t i o n ( e . g e t M e s s a g e ( ) ) ;
85 }
86 return m a t r i x ;
87 }
88 }

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 //−−>
172 CAPITOLUL 6. SERVLET

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>

6.6 Descărcarea unui fişier


Considerăm cazul:

Exemplul 6.6.1 Fişierul ales de client dintr-o lista disponibilă este descărcat fiind
transmis navigatorului.

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 D o w n l o a d S e r v l e t extends H t t p S e r v l e t {
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 S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ;
9 S t r i n g f i l e =r e q . g e t P a r a m e t e r ( ” f i l e ” ) ;
10 S t r i n g c a l e=” webapps / download / r e s o u r c e s / ” ;
11 try {
12 F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( c a l e+ f i l e ) ;
13 B u f f e r e d I n p u t S t r e a m b i s = new B u f f e r e d I n p u t S t r e a m ( f i s ) ;
14 byte [ ] b y t e s = new byte [ b i s . a v a i l a b l e ( ) ] ;
15 r e s . setContentType ( ” A p p l i c a t i o n / Octet−stream ” ) ;
16 b i s . read ( bytes ) ;
17 out . w r i t e ( b y t e s ) ;
18 bis . close ( );
19 f i s . close ();
20 out . c l o s e ( ) ;
21 }
22 catch ( E x c e p t i o n e ) {
23 r e s . setContentType ( ” t e x t / p l a i n ” ) ;
24 out . p r i n t l n ( ” C e r e r e a d−v o a s t r a nu p o a t e f i s a t i s f a c u t a ” ) ;
25 }
26 out . c l o s e ( ) ;
27 }

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


30 throws S e r v l e t E x c e p t i o n , IOException {
6.7. FILTRU 173

31 doGet ( req , r e s ) ;
32 }
33 }

6.7 Filtru
Un filtru se asemeană unui servlet, dar activitatea ı̂ntreprinsă vizează uzual
contextul, adică ansamblul servleţilor care fac parte din aplicaţia Web.
Un filtru se declară ı̂n fişierul web.xml prin

<web-app>
. . .
<filter>
<filter-name>nume_filtru</filter-name>
<filter-class>clasa_filtrului</filter-class>
</filter>
<filter-mapping>
<filter-name>nume_filtru</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
. . .

</web-app>

Clasa filtrului implementează interfaţa Filter, adică metodele

• public void init(FilterConfig filterConfig) throws ServletException

• public void destroy()

• public void doFilter(ServletRequest request,


ServletResponse response, FilterChain filterChain)
throws IOException, ServletException

Exemplul 6.7.1 Contextul myservlet conţine doi servleţi HelloServlet şi Cmmdc-
Servlet, apelabili respectiv din hello.html, cmmdc.html. Să se programeze un filtru
care

• Redirectează solicitarea “/myservlet/hello” către “/cmmdc.html”.

• Dacă se cere ca natura răspunsului să fie “text/xml” atunci invalidează cererea.

Servleţii HelloServlet şi CmmdcServlet sunt cei dezvoltaţi la ı̂nceputul acestui


capitol. Filtrul are codul
174 CAPITOLUL 6. SERVLET

1 import j a v a . i o . IOException ;
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 M y F i l t e r D i s p a t c h e r implements F i l t e r {
6 private F i l t e r C o n f i g f i l t e r C o n f i g ;

8 public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws S e r v l e t E x c e p t i o n {


9 this . f i l t e r C o n f i g = f i l t e r C o n f i g ;
10 }

12 public void d e s t r o y ( ) {
13 this . f i l t e r C o n f i g = null ;
14 }

16 public void d o F i l t e r ( S e r v l e t R e q u e s t r e q u e s t , S e r v l e t R e s p o n s e r e s p o n s e ,
17 F i l t e r C h a i n f i l t e r C h a i n ) throws IOException , S e r v l e t E x c e p t i o n {
18 HttpServletRequest req = ( HttpServletRequest ) request ;
19 HttpServletResponse res = ( HttpServletResponse ) response ;
20 S t r i n g u r i = r e q . getRequestURI ( ) ;
21 i f ( u r i . equals ( ”/ myservlet ” ) | | u r i . equals ( ”/ myservlet /” ) )
22 f i l t e r C h a i n . doFilter ( request , response ) ;
23 else {
24 i f ( u r i . equals ( ”/ myservlet / h e l l o ” )){
25 S t r i n g d i s p a t c h e r U r i=” /cmmdc . html ” ;
26 R e q u e s t D i s p a t c h e r rd=r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( d i s p a t c h e r U r i ) ;
27 rd . f o r w a r d ( r e q u e s t , r e s p o n s e ) ;
28 }
29 else {
30 i n t i n d e x=u r i . l a s t I n d e x O f ( ” . ” ) ;
31 i f ( i n d e x==−1){
32 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 ” ) ;
33 i f ( t i p . e q u a l s ( ” t e x t /xml” ) ) {
34 r e s . s e n d E r r o r ( H t t p S e r v l e t R e s p o n s e . SC FORBIDDEN ) ;
35 }
36 }
37 f i l t e r C h a i n . doFilter ( request , response ) ;
38 }
39 }
40 }
41 }

Fişierul web.xml este


1 <?xml version=” 1 . 0 ” e n c o d i n g=”ISO−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 ”>

6 <web−app>
7 < f i l t e r>
8 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>
9 < f i l t e r −c l a s s>M y F i l t e r D i s p a t c h e r</ f i l t e r −c l a s s>
10 </ f i l t e r >

12 < f i l t e r −mapping>
13 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>
14 <u r l −p a t t e r n>/∗</ u r l −p a t t e r n>
15 </ f i l t e r −mapping>
6.7. FILTRU 175

17 < s e r v l e t>
18 <s e r v l e t −name>cmmdc</ s e r v l e t −name>
19 <s e r v l e t −c l a s s>CmmdcServlet</ s e r v l e t −c l a s s>
20 </ s e r v l e t>

22 < s e r v l e t>
23 <s e r v l e t −name> h e l l o</ s e r v l e t −name>
24 <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>
25 </ s e r v l e t>

27 <s e r v l e t −mapping>
28 <s e r v l e t −name> h e l l o</ s e r v l e t −name>
29 <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>
30 </ s e r v l e t −mapping>

32 <s e r v l e t −mapping>
33 <s e r v l e t −name>cmmdc</ s e r v l e t −name>
34 <u r l −p a t t e r n>/cmmdc</ u r l −p a t t e r n>
35 </ s e r v l e t −mapping>

37 </web−app>

Pentru ı̂nţelegerea aplicaţiei prezentăm şi codul fişierului cmmdc.html


1 <html>
2 <head>
3 < t i t l e>
4 Cmmdc S e r v l e t
5 </ t i t l e>
6 </head>
7 <body bgcolor=”#c c b b c c ”>
8 <center>
9 <h1> Cmmdc S e r v l e t </h1>
10 <form method=” g e t ”
11 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”>
12 <table border=” 1 ”>
13 <tr>
14 <td> Primul numar </td>
15 <td> <input type=” t e x t ” name=”m” s i z e =10> </td>
16 </ tr>
17 <tr>
18 <td> Al d o i l e a numar </td>
19 <td> <input type=” t e x t ” name=”n” s i z e =10> </td>
20 </ tr>
21 <tr>
22 <td> Natura r a s p u n s u l u i </td>
23 <td> <s e l e c t name=” t i p ” >
24 <option value=” t e x t / html ”> t e x t / html
25 <option value=” t e x t / p l a i n ”> t e x t / p l a i n
26 <option value=” t e x t /xml”> t e x t /xml
27 </ s e l e c t> </td>
28 </ tr>
29 <tr>
30 <td> <input type=” submit ” value=” C a l c u l e a z a ”> </td>
31 <td></td>
32 </ tr>
33 </ table>
34 </form>
35 </ center>
176 CAPITOLUL 6. SERVLET

36 </body>
37 </html>
Capitolul 7

Java Server Page – JSP

7.1 Tehnologia JSP


Tipul tehnologiei JSP este denumit procesare de şabloane (template engine). JSP
este o tehnologie similară cu PHP, ASP.NET, apache-velocity, etc. JSP permite in-
cluderea de cod Java ı̂ntr-un document html. Un asemenea document se depozitează
ı̂ntr-un server Web, container de servlet, cu extensia jsp, eventual jspx.
Apelarea documentului JSP se realizează prin
• meniul File/Open a unui navigator, cu
http://host:port/cale/doc.jsp
• referinţă html
<a href="http://host:port/cale/doc.jsp">
• valoare a atributului action ı̂ntr-un marcaj form
<form action="http://host:port/cale/doc.jsp" ... >
Prin cale se ı̂nţelege calea de la catalogul webapps până la catalogul ce conţine
fişierul jsp.
Vom depozita fişierele JSP ı̂ntr-un catalog jsp din arborele
webapps
|--> JSPApp
| |--> WEB-INF
| | |--> classes
| | | web.xml
| |--> jsp
| | | doc.jsp
caz ı̂n care cale=JSPApp/jsp.
Astfel, schimbând numele fişierului Hello.html

177
178 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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ătorul 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 :
10 <%= data1 %>
7.1. TEHNOLOGIA JSP 179

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 v e r s i o n=” 1 . 0 ” e n c o d i n g=”UTF−8” ?>


2 <html xmlns : 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, fiind definit prin valorile:

Valoare Domeniu de valabilitate


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

În orice pagină / document JSP sunt predefinite obiectele:


180 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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 :
11 <input type=” t e x t ” name=”name” s i z e =20>
12 <p>
13 <input type=” submit ”>
7.1. TEHNOLOGIA JSP 181

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 este


1 <project b a s e d i r=” . ” d e f a u l t=” g e n e r a t e . war ”>

3 <property name=”TOMCAT HOME” v a l u e=” d : / apache−tomcat − 5 . 5 . 2 6 ” />


4 <property name=” d i s t . name” v a l u e=” j s p h e l l o ” />
5 <property name=” d i s t . d i r ” v a l u e=” d i s t ” />
6 <property 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 <include name=” ∗ . j a r ” />
11 </ f i l e s e t>
12 <pathelement path=” ${TOMCAT HOME}/ l i b / s e r v l e t −a p i . j a r ” />
13 </path>

15 <target name=” i n i t ”>


16 <delete 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” />
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 </ target>
182 CAPITOLUL 7. JAVA SERVER PAGE – JSP

25 <target name=” c o m p i l e ” depends=” i n i t ”>


26 <javac 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 </ target>

31 <target 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 <include 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 <include name=” ∗ . j s p ” />
40 <include 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 <include 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 <include 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 <include 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 </ target>
60 </ project>

7.1.1 Declaraţii JSP


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.

Pagina JSP a aplicaţiei cmmdc.jsp:


7.1. TEHNOLOGIA JSP 183

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 . pa rse Lo ng ( 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 cmmdc.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 /cmmdc . 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 . . . %>
184 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. Menţionăm atributele


import= ”listă de pachete separate prin ,”
info= ”text” Informaţia se poate regăsi apelând metoda
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” %>

Includerea are loc ı̂n locul ı̂n care apare directiva.


Referinţa la fişierul html sau jsp se face relativ la catalogul paginii JSP iniţiale
(adică cea ı̂n care apare directiva).

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


Prelucrarea care urmează va fi cea din fişierul menţional. Diferenţa dintre cele
două elemente constă ı̂n faptul că include prevede revenirea ı̂n pagina JSP
iniţială iar forward nu.
Referinţa la fişierul html sau jsp se face relativ la catalogul paginii JSP iniţiale.
7.1. TEHNOLOGIA JSP 185

Î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 "/>
. . . . . .
</jsp:params>

• <jsp : useBean id=”numeComponentăJava”


class=”numeClasa”
scope=”domeniu” />
unde domeniu precizează domeniul de valabilitate al componentei Java, adică
page, request, session, application.
Crează un obiect ”numeComponentăJava” de tip ”numeClasa” având dome-
niul de valabilitate dată de ”domeniu”.

• <jsp : setProperty name=”numeComponentăJava”


property=”numeProp”
value=”valoare”/>
Acest marcaj este echivalent cu codul Java
numeComponentăJava.setNumeProp(valoare).
<jsp : setProperty name=”numeComponentăJava” property="*" />
vizează toate proprietăţile componentei Java, fixarea valorilor făcându-se cu
datele unui formular. Numele parametrilor din formularele de introducere a
datelor trebuie să coincidă cu identificatorii câmpurilor din componenta Java
corespunzătoare.

• <jsp : getProperty name=”numeComponentăJava”


property=”numeProp”/>
Preia şi afişează valoarea câmpului numeComponentăJava.numeProp.

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;


186 CAPITOLUL 7. JAVA SERVER PAGE – JSP

• Pentru fiecare asemenea câmp

private Tip xyz;

trebuie definite metodele

public void setXyz(Tip xyz){


this.xyz=xyz;
}

public Tip getXyz(){


return xyz;
}

7.1.5 Pagini JSP cu componente Java


Clasa componentei Java care se va utiliza ı̂ntr-o pagină JSP trebuie inclusă ı̂ntr-
un pachet.
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 H e l l o B e a n {
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 (hello.jsp)


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>
7.1. TEHNOLOGIA JSP 187

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>
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 }
188 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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 . par se Lon g ( getM ( ) ) ;
22 long n=Long . p ars eL ong ( 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 }

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)


7.2. JSP STANDARD TAG LIBRARY JSTL 189

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>

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:
190 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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 lib al aplicaţiei care utilizează bibliotecile.
Î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 valabilitate 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
${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 valabilitate
diferită. Referirea se face prin ${pageScope.numeVariabilă},
7.2. JSP STANDARD TAG LIBRARY JSTL 191

${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 valabilitate al variabilei.
Unul din valorile:
page, request, session, application.

• 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 valabilitate 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
192 CAPITOLUL 7. JAVA SERVER PAGE – 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 } ” >
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;
7.2. JSP STANDARD TAG LIBRARY JSTL 193

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

<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 Evidenţierea 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.
194 CAPITOLUL 7. JAVA SERVER PAGE – JSP

• 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 valabilitate 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.

• 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 valabilitate al variabilei var.
Unul din valorile:
page, request, session, application.
7.2. JSP STANDARD TAG LIBRARY JSTL 195

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 valabilitate al variabilei var.

• 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 valabilitate 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>
196 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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>
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. O bibliotecă de marcaje este reprezentat de o identificator
dat sub forma unui URI —textitUniversal Resource Identifier).

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 identificatorul bibliotecii de marcaje.

3. Marcajul taglib a fişierului web.xml, care permite serverului Web să găsească
descriptorul bibliotecii de marcaje.

4. Fişierul JSP ce utilizează marcajul JSP (clientul).


7.3. MARCAJE JSP PERSONALE 197

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.
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 }
198 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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>
11 <u r i>h t t p : // c s . u n i t b v . r o / m y t a g l i b</ u r i>
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>

Elementul uri conţine identificatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib.


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://cs.unitbv.ro/mytaglib
</taglib-uri>
<taglib-location>
/WEB-INF/mylibtag.tld
</taglib-location>
</taglib>
7.3. MARCAJE JSP PERSONALE 199

Elementele marcajului taglib sunt:

(a) taglib-uri Identificatorul bibliotecii de marcaje.


(b) taglib-location Locaţia fişierului descriptor de bibliotecă de marcaje
(numele calificat al fişierului, adică alcătuit din cale plus numele fişierului).

Astfel elementele constitutive se vor găsi ı̂n:

webapps
|--> mytag
| |--> WEB-INF
| | |--> classes
| | | |--> jsp
| | | | |--> DateTag.class
| | | web.xml
| | | 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 : / / c s . u n i t b v . r o / 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>
200 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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

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 % >
7.3. MARCAJE JSP PERSONALE 201

Marcajul <tag> din descriptorul bibliotecii de marcaje devine

<tag>
<name> ziuaTag </name>
<tag-class> jsp.ZiuaTag </tag-class>
<body-content> EMPTY </body-content>
<description> furnizeaza argumentul ziua curenta </description>
<attribute>
<name> ziua </name>
<required> true </required>
<rtexprvalue> true </rtexprvalue>
</attribute>
</tag>

3. Utilizarea acestui marcaj este exemplificat ı̂n

1 <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=” s i mb 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 : / / c s . u n i t b v . r o / 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>
202 CAPITOLUL 7. JAVA SERVER PAGE – JSP

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.

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


7.3. MARCAJE JSP PERSONALE 203

<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

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 : / / c s . u n i t b v . r o / m y t a g l i b ” p r e f i x=”mk” %>
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>
204 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.

O aplicaţie portlet ı̂ndeplineşte standardele JSR (Java Specification Request)


168 şi JSR 286.
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:

205
206 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 servlet 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 207

• 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 extensia 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 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=” d e p l o y ” b a s e d i r=” . ”>

4 <p r o p e r t y e n v i ro n m e nt=” 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 −−>
208 CAPITOLUL 8. PORTLET

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 < f i l e s e t d i r=” ${ p l u t o . home}/ l i b ”>
21 <i n c l u d e name=” ∗ . j a r ” />
22 </ f i l e s e t>
23 </ path>

25 <t a s k d e f
26 name=” a s s e m b l e ”
27 c l a s s n a m e=” o r g . apache . p l u t o . ant . AssembleTask ”
28 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 ”
29 />

31 <t a r g e t name=” a s s e m b l e ”>


32 <a s s e m b l e
33 webxml=” ${web−i n f . d i r }/web . xml”
34 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”
35 d e s t f i l e =” ${ b u i l d . d i r }/web . xml”
36 />
37 </ t a r g e t>

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


40 <echo message=”Ant v e r s i o n = ${ ant . v e r s i o n } ” />
41 <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 ”
42 d i r=” ${ b u i l d . d i r } ” />
43 <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 ”
44 d i r=” ${ w e b b u i l d . d i r } ” />
45 <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 ”
46 d i r=” ${ w e b b u i l d . d i r }/WEB−INF” />
47 <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 ”
48 d i r=” ${ c l a s s b u i l d . d i r } ” />
49 <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 ”
50 d i r=” ${ w e b b u i l d . d i r }/WEB−INF/ l i b ” />
51 </ t a r g e t>

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


54 <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 ”
55 f o r k=” y e s ”
56 debug=” t r u e ”
57 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 ”
58 d e s t d i r=” ${ c l a s s b u i l d . d i r } ”
59 s r c d i r=” ${ j a v a . s r c . d i r } ” />
60 </ t a r g e t>

62 <t a r g e t name=” war ” depends=” c o m p i l e ”>


63 < !−− Move web f i l e s e x c l u d i n g web . xml −−>
64 <copy t o d i r=” ${ w e b b u i l d . d i r }/ ”>
65 < f i l e s e t d i r=” ${web . d i r } ” e x c l u d e s=” ∗∗/ web . xml” />
66 </ copy>

68 < !−− 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 −−>


69 <copy t o d i r=” ${ w e b b u i l d . d i r }/WEB−INF/ l i b / ”>
70 < f i l e s e t d i r=” ${ l i b . d i r } ”>
71 <i n c l u d e name=” ∗ ∗ / ∗ . j a r ” />
72 <e x c l u d e name=” c a s t o r ∗ . j a r ” />
73 <e x c l u d e name=” p l u t o ∗ . j a r ” />
74 <e x c l u d e name=” p o r t l e t ∗ . j a r ” />
8.2. DEZVOLTAREA UNUI PORTLET 209

75 <e x c l u d e name=” s e r v l e t ∗ . j a r ” />


76 <e x c l u d e name=” j u n i t ∗ . j a r ” />
77 </ f i l e s e t>
78 </ copy>

80 < a n t c a l l t a r g e t=” a s s e m b l e ” />

82 < !−− C r e a t e war i n d e p l o y m e n t d i r e c t o r y −−>


83 <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 ”
84 w a r f i l e=” ${ app . name } . war ”
85 webxml=” ${ b u i l d . d i r }/web . xml” />
86 </ t a r g e t>

88 <t a r g e t name=” b u i l d ” depends=” c l e a n , war ” />

90 <t a r g e t name=” d e p l o y ” depends=” b u i l d ”>


91 <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} ” />
92 < !−−
93 Remove former d e p l o y m e n t b e c a u s e sometimes
94 tomcat d o e s n o t f u l l y r e d e p l o y a war
95 −−>
96 <d e l e t e
97 d i r=” ${ p l u t o . home}/ webapps /${ app . name} ”
98 f a i l o n e r r o r=” t r u e ”
99 />
100 < !−− Deploy war f i l e −−>
101 <copy
102 f i l e =” ${ app . name } . war ”
103 t o d i r=” ${ p l u t o . home}/ PlutoDomain ”
104 o v e r w r i t e=” t r u e ”
105 />
106 < !−− Deploy c o n t e x t d e p l o y m e n t d e s c r i p t o r f o r Tomcat −−>
107 <copy
108 f i l e =” ${ c o n f . d i r }/${ app . name } . xml”
109 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 ”
110 o v e r w r i t e=” f a l s e ”
111 />

113 </ t a r g e t>

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


116 <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 ” />
117 </ t a r g e t>

119 </ 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
210 CAPITOLUL 8. PORTLET

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-1.0.4.jar
| | pluto-ant-tasks-2.0.*.jar
| | pluto-descriptor-api-1.1.6.jar
| | pluto-descriptor-impl-1.1.6.jar
| | pluto-util-2.0.*.jar
| | pluto-container-2.0.0.jar
| | jaxb-api-2.1.jar
| | jaxb-impl-2.1.9.jar
|--> src
| |--> main
| | |--> java
| | | |--> pachetul portletului
| | |--> resource
| | | | NumePortlet.xml
| | |--> webapp
| | | |--> jsp
| | | | | fisierele jsp ale portletului
| | | |--> WEB-INF
| | | | | portlet.xml
| | | | | web.xml
8.3. ELEMENTE DE PROGRAMARE 211

Fişierele castor.1.1.1.jar, pluto-descriptor-api-*.jar, pluto-descriptor-impl-*.jar, portlet-


container-*.jar se copiază din catalogul PLUTO HOME\shared\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.3 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


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
212 CAPITOLUL 8. PORTLET

• 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;
Metoda processAction este apelată de metoda include(request, response) a clasei
PortletRequestDispatcher.

Exemplul 8.3.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 ! ” ) ;
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 }
8.3. ELEMENTE DE PROGRAMARE 213

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.3.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 ( ) ;
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 ”
214 CAPITOLUL 8. PORTLET

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.3.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 ” ) ;
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 ) ;
8.3. ELEMENTE DE PROGRAMARE 215

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

Exemplul 8.3.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 )


216 CAPITOLUL 8. PORTLET

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 . par se Lon g ( sm ) ;
30 long n=Long . p ars eL ong ( 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>
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 />
8.3. ELEMENTE DE PROGRAMARE 217

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


218 CAPITOLUL 8. PORTLET

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 . pa rs eL ong (m) ;
20 long n0=Long . pa rse 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>

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");
8.3. ELEMENTE DE PROGRAMARE 219

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>

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 valorii returnează valoarea def.

• String[] getValues(String key, String[] def )


Returnează toate valorile atributului key.
220 CAPITOLUL 8. PORTLET

• 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.3.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>
<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.4. PRODUSE PORTAL 221

8.4 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.4.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.
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
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.
222 CAPITOLUL 8. PORTLET

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


8.4. PRODUSE PORTAL 223

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

(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) Pentru fixarea
acestui parametru se va consulta fişierul web.xml.
• Numele portlet-ului aşa cum este definit ı̂n fişierul portlet.xml.
Clic Next.
(d) În meniul Portlet Preferences, clic Next.
224 CAPITOLUL 8. PORTLET

(e) În meniul Display Settings, clic Next.


(f) În meniul Channel Controls, clic Next.
(g) În meniul Categories se fixează categoria canalului şi cel puţin un mem-
bru.
Select Marked → Next.
(h) În meniul Groups se fixează grupul şi cel puţin un membru.
Select Marked → Next
Grupul desemnează clienţii care pot publica portlet-ul.
(i) În meniul Review, clic Finish.

Canalul portlet-ului apare ı̂n lista afişată.

3. Fiecare client care poate utiliza portlet-ul - adică cei din grupul selectat, ı̂l
publică prin componenta Add Content.
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 prin clic pe butonul Remove din fereastra portlet-
ului.
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.4.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-*. Astfel, lansarea se face apelând bin\startup.bat.
Portalul se accesează, dintr-un navigator, prin
8.4. PRODUSE PORTAL 225

http://localhost:8080/jetspeed

Desfăşurarea unui portlet constă ı̂n copierea arhivei war corespunzătoare, re-
alizat ı̂n 8.4.1, ı̂n catalogul

Jetspeed HOME \webapps\jetspeed\WEB-INF\deploy

Pe rol de admin (acces cu valorile iniţiale username=password=admin), publi-


carea portlet-ului presupune

1. Clic pe icon-ul butonului Edit - aflat sub butonul logout.

2. Clic pe butonul Add Portlet, aflat sub butonul Edit.

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.
226 CAPITOLUL 8. PORTLET
Capitolul 9

Java Web Start

9.1 Java Web Start


O aplicaţie Java destinată a fi utilizată pe un calculator poate fi valorificată
şi ı̂ntr-o reţea, pe baza protocolului Java Network Launching Protocol - JNLP.
Tehnologia poartă numele de Java Web Start.
Aplicaţia Java trebuie să satisfacă o serie de restricţii:

• Aplicaţia trebuie arhivată cu jar;

• Eventualele date necesare aplicaţiei se introduc prin intermediul unei interfeţe


grafice (swing, SWT, apache-pivot);

• Acces limitat la proprietăţile şi resursele sistemului client.

Aplicaţiei i se ataşează un fişier xml, dar cu extensia jnlp, care se va apela


dintr-un navigator. Pentru acest fişier folosim terminologia de fişier jnlp.
Fişierul jnlp fixează:

• referinţa URL a aplicaţie (prin atributul codebase);

• arhivele jar utilizate (prin atributul href);

• clasa cu metoda main (prin atributul main-class).

Ansamblul de resurse formează o aplicaţie Web care poate fi desfăşurată ı̂ntr-


un server Web (Microsoft Internet Information Service (IIS), apache) sau poate fi
incorporat ı̂ntr-un servlet, caz ı̂n care desfăşurarea va fi ı̂ntr-un server Web container
de servlet.
Arătăm activităţile care trebuie ı̂ntreprinse ı̂n cazul unui exemplu simplu dat de
clasa VisualCmmdc.java.

227
228 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 . par se Lon g ( sm ) ;
17 long n=Long . p ars eL 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 229

Instalare ı̂ntr-un server Web


Pentru instalarea aplicaţiei ı̂ntr-un server Web, se parcurg paşii:

1. Se arhivează aplicaţia
jar cfv cmmdc.jar *.class

2. Se editează fişierul launch.jnlp


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

host se ı̂nlocuieşte cu numele calculatorului care găzduieşte serverul Web.

3. Se crează fişier de apelare a aplicaţiei (cmmdc.html )


1 <html>
2 <body bgcolor=”#AAEEAA”>
3 <center>
4 <h3>V i s u a l Cmmdc A p p l i c a t i o n </h3>
5 <a href=” h t t p : / / h o s t /cmmdc/ l a u n c h . j n l p ”>
6 Launch t h e a p p l i c a t i o n </a>
7 </ center>
8 </body>
9 </html>

4. Ansamblul

cmmdc
| cmmdc.jar
| cmmdc.html
| launch.jnlp

se copiază ı̂n serverul Web (ı̂n cazul IIS acest loc este catalogul
InetPub\wwwroot).
Dintr-un navigator, apelarea aplicaţiei este http://host/cmmdc/cmmdc.html.
230 CAPITOLUL 9. JAVA WEB START

Aplicaţia Java ca servlet


Pentru includerea aplicaţie Java ı̂ntr-un servlet, primii trei paşi prezentaţi mai
sus coincid. Singura diferenţă constă ı̂n conţinutul referintelor, după host va apare
portul utilizat de serverul Web container de servlet, uzual host:8080.

4. Î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
cmmdc.html

Fişierul jnlp-servlet.jar se preia din distribuţia JDK, din catalogul sam-


ple/jnlp/servlet.
Fişierul web.xml este
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>

5. Conţinutul catalogului de lucru se arhivează ı̂ntr-un fişier war.


jar cfv cmmdc.war app/* WEB-INF/* cmmdc.html

6. Utilizând apache-tomcat sau jetty, de exemplu, fişierul war se copiază ı̂n cat-
alogul webapps al serverului web.
Dintr-un navigator, apelarea aplicaţiei se obţine prin
http://host:8080/cmmdc/cmmdc.html.
9.1. JAVA WEB START 231

Dacă aplicaţia Java utilizează imagini grafice acestea trebuie arhivate ı̂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);
Dacă aplicaţia Java utilizează resurse externe date prin fişiere jar atunci:
1. Toate fişierele jar se certifică.
Certificarea resurselor se realizează rulând succesiv
(a) keytool -genkey -keystore myKeystore -alias myself
(b) keytool -selfcert -alias myself -keystore myKeystore
(c) jarsigner -keystore myKeystore resource.jar myself
keytool.exe şi jarsigner.exe se 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 resource.jar.
Toate fişierele jar trebuie să poarte aceaşi certificare.
2. Fişierele jar certificate se depun ı̂n catalogul app\lib.
3. În fişierul jnlp, ı̂n elementul resources, pentru fiecare fişier jar utilizat se
introduce declaraţia

<jar href=”lib/resource.jar”/>

4. În plus, fişierul jnlp ataşat aplicaţiei conţine elementele

<security>
<all-permissions />
</security>

Dacă arhiva jar a aplicaţiei Java este executabilă atunci, ı̂n fişierul jnlp, elemen-
tul application-desc poate lipsi.
Într-o arhivă jar executabilă, fişierul MANIFEST.MF indică clasa cu metoda main
şi eventualele resurse externe utilizate (fişiere jar) prin proprietăţile
Main-class: numeClasa
Class-path: lib/resursa1.jar lib/resursa2.jar . . .
Pentru a obţine fişierul MANIFEST.MF cu aceste proprietăţi se editează un fişier text
cu conţinutul de mai sus, denumit de exemplu myManifest.mf, şi se arhivează prin

jar cfvm numeArhiva.jar myManifest.mf *.class lib


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

233
234 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 235

• 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 }
236 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()
Utilitarul jconsole permite conectarea la serverul MBean.

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

• 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.
238 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 jdk .
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 ( ) ;

13 // V a r i a n t a 1
14 // 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
15 ObjectName mbeanObjectName =
16 new ObjectName ( domeniu+” : t y p e=I n t r o , i n d e x=1” ) ;

18 // Crearea MBean−u l u i
19 I n t r o mbean = new I n t r o ( ) ;

21 // I n r e g i s t r a r e a MBean−u l u i
22 mbs . r e g i s t e r M B e a n ( mbean , mbeanObjectName ) ;

24 // V a r i a n t a 2
25 mbeanObjectName=new ObjectName ( domeniu+” : t y p e=I n t r o , i n d e x=2” ) ;
26 mbs . createMBean ( ” b a s i c . I n t r o ” , mbeanObjectName ) ;

28 // A s t e p t a r e n e d e f i n i t a
29 System . out . p r i n t l n ( ” Waiting f o r e v e r . . . ” ) ;
30 while ( true ) ;
31 }
32 catch ( E x c e p t i o n e ) {
33 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 ( ) ) ;
34 }
35 }
36 }

1
În acest caz, este nevoie ca variabilele de tip clasă acoperitoare Double, Long să fie ı̂nlocuite
prin tipuri predefinite.
10.1. STANDARD MBEAN 239

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.

Astfel, introducerea notificărilor presupune familiarizarea cu clasele


240 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

Figure 10.1: Rezultatele furnizate de jcluster.

• NotificationBroadcasterSupport
Constructori
– NotificationBroadcasterSupport()
Metode
– void sendNotification(Notification notificare)
• Notification
Constructori
– Notification(String type, Object source, long sequenceNumber )
– Notification(String type, Object source, long sequenceNumber , long
timeStamp)
10.1. STANDARD MBEAN 241

– 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 a ge nt n ;
2 import j a v a x . management . ∗ ;

4 public c l a s s I nt r oN extends N o t i f i c a t i o n B r o a d c a s t e r S u p p o r t
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 ;
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 ,
242 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

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 . S c a n n e 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 ” ;
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 ) ;
10.1. STANDARD MBEAN 243

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 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
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. Serverul de conexiune şi serverul
MBeanServer aparţin aceleiacsi clase.
– Lansarea ı̂n execuţie a serverului de conexiune.

• Clientul dispune de interfaţa MBeanu-ului.


244 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

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 name o f t h e s e r v e r 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=
29 JMXConnectorServerFactory . newJMXConnectorServer ( u r l , null , mbs ) ;
10.1. STANDARD MBEAN 245

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 . ∗ ;
246 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 <=1){
12 System . out . p r i n t l n ( ”The s e r v e r and domain names a r e r e q u i r e d ” ) ;
13 System . e x i t ( 0 ) ;
14 }
15 S t r i n g serverName=a r g s [ 0 ] ;
16 S t r i n g domain=a r g s [ 1 ] ;
17 i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ;
18 i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 4 ] ;
19 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
20 try {
21 // 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
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 ] ;
24 // 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 ://”+
25 // h o s t +”:”+ p o r t +”/”+ a r g s [ 0 ] ;
26 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
27 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
28 MBeanServerConnection c s = jmxc . getMBeanServerConnection ( ) ;

30 // Domeniile a g e n t u l u i s u n t
31 System . out . p r i n t l n ( ” Domains : ” ) ;
32 S t r i n g domains [ ] = c s . getDomains ( ) ;
33 f o r ( i n t i = 0 ; i < domains . l e n g t h ; i ++) {
34 System . out . p r i n t l n ( ” \ tDomain [ ” + i + ” ] = ” + domains [ i ] ) ;
35 }

37 // i a r domeniul i m p l i c i t
38 System . out . p r i n t l n ( ” DefaultDomain : ” +c s . g e t D e f a u l t D o m a i n ( ) ) ;
39 System . out . p r i n t l n ( ”Domain : ” +domain ) ;

41 // Crearea unui MBean I n t r o


42 S t r i n g className=” b a s i c . I n t r o ” ;
43 S t r i n g sObjectName=domain+” : t y p e=”+className ;
44 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;
45 c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;

47 double c u r s E u r o ;
48 long m, n ;

50 // U t i l i z a r e a MBean−u l u i
51 // 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
52 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 ” ) ;
53 IntroMBean proxy=
54 ( 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 (
55 cs ,
56 mbeanObjectName ,
57 c l i e n t . IntroMBean . c l a s s ,
58 true ) ;

60 // U t i l i z a r e a o p e r a t i i l o r
61 // o p e r a t i a ” s a y H e l l o ”
62 proxy . s a y H e l l o ( ) ;

64 // o p e r a t i a cmmdc
65 System . out . p r i n t l n ( ”Cmmdc a l n u m e r e l o r : ” ) ;
10.1. STANDARD MBEAN 247

66 System . out . p r i n t l n ( ” Primul numar : ” ) ;


67 m=s c a n n e r . nextLong ( ) ;
68 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;
69 n=s c a n n e r . nextLong ( ) ;
70 System . out . p r i n t l n ( ”Cmmdc=”+proxy . cmmdc(m, n ) ) ;

72 // U t i l i z a r e a a t r i b u t e l o r
73 System . out . p r i n t l n ( ”Numele : ”+proxy . g e t L a b e l ( ) ) ;
74 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 ” ) ;
75 c u r s E u r o=s c a n n e r . nextDouble ( ) ;
76 proxy . s e t C u r s E u r o ( c u r s E u r o ) ;
77 System . out . p r i n t l n ( ” Euro : ”+proxy . getCursEuro ( ) ) ;

79 // 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
80 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 ” ) ;
81 // A p e l a r e a o p e r a t i i l o r
82 S t r i n g o p e r a t i a=” s a y H e l l o ” ;
83 c s . i n v o k e ( mbeanObjectName , o p e r a t i a , null , n u l l ) ;
84 o p e r a t i a=”cmmdc” ;
85 System . out . p r i n t l n ( ”Cmmdc a l n u m e r e l o r : ” ) ;
86 System . out . p r i n t l n ( ” Primul numar : ” ) ;
87 m=s c a n n e r . nextLong ( ) ;
88 System . out . p r i n t l n ( ” Al d o i l e a numar : ” ) ;
89 n=s c a n n e r . nextLong ( ) ;
90 O b j e c t [ ] param={m, n } ;
91 S t r i n g [ ] s i g n ={” l o n g ” , ” l o n g ” } ;
92 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 ) ;
93 System . out . p r i n t l n ( ”Cmmdc=”+r . t o S t r i n g ( ) ) ;

95 // U t i l i z a r e a A t r i b u t e l o r
96 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 ” ) ;
97 System . out . p r i n t l n ( ” V a l o a r e a a t r i b u t u l u i l a b e l : ”+l a b e l ) ;

99 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 ” ) ;
100 c u r s E u r o=s c a n n e r . nextDouble ( ) ;
101 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 ) ;
102 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
103 Double newEuro=(Double ) c s . g e t A t t r i b u t e ( mbeanObjectName , ” CursEuro ” ) ;
104 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 ) ;
105 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
106 }
107 catch ( E x c e p t i o n e ) {
108 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
109 }
110 }
111 }

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 ( ) ) ;
248 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

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 ( ) +
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 249

• 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 . g e tO l d V a l u e ( ) . 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 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 <=1){
11 System . out . p r i n t l n ( ”The s e r v e r and domain names a r e r e q u i r e d ” ) ;
12 System . e x i t ( 0 ) ;
13 }
14 S t r i n g serverName=a r g s [ 0 ] ;
15 S t r i n g domain=a r g s [ 1 ] ;
16 i f ( a r g s . l e n g t h >=3) h o s t=a r g s [ 2 ] ;
17 i f ( a r g s . l e n g t h >=4) p o r t=a r g s [ 3 ] ;
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 ] ;
250 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 // Crearea unui MBean I n t r o


29 S t r i n g className=” b a s i c n . I nt r oN ” ;
30 S t r i n g sObjectName=domain+” : t y p e=”+className ;
31 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

33 MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


34 getMBeanResources ( i n f o ) ;

36 // U t i l i z a r e a n o t i f i c a r i i
37 // Crearea unui a s c u l t a t o r
38 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 ( ) ;
39 // A c t i v a r e a n o t i f i c a t o r u l u i
40 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 ) ;

42 Thread . s l e e p ( 5 0 0 ) ;
43 // 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
44 System . out . p r i n t l n ( ” P r e s s Enter t o f i n i s h ! ” ) ;
45 try {
46 System . i n . r e a d ( ) ;
47 }
48 catch ( j a v a . i o . IOException e ) { }
49 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 ) ;
50 // 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
51 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
52 }
53 catch ( E x c e p t i o n e ) {
54 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
55 e . printStackTrace ( ) ;
56 }
57 }

59 private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }

61 }

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 }

implementat prin
10.1. STANDARD MBEAN 251

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 mport 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 . ∗ ;
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 ( S e r v l e t C o n f i g c o n f i g ) {
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 : / / ”+h o s t+” : ”+p o r t+” / ”+s e r v e r ;
19 // S t r i n g s u r l =” s e r v i c e : jmx : i i o p : / / / j n d i / i i o p ://”+ h o s t +”:”+ p o r t +”/”+ s e r v e r ;
252 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

20 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;


21 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
22 c s = jmxc . getMBeanServerConnection ( ) ;
23 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 ( ) ;
24 S t r i n g className=” Cont ” ;
25 S t r i n g sObjectName=domain+” : t y p e=”+className ;
26 mbeanObjectName = new ObjectName ( sObjectName ) ;
27 c s . createMBean ( className , mbeanObjectName , null , n u l l ) ;
28 }
29 catch ( E x c e p t i o n e ) {
30 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
31 System . e x i t ( 0 ) ;
32 }
33 }

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


36 throws S e r v l e t E x c e p t i o n , IOException {
37 S e r v l e t O u t p u t S t r e a m out=r e s . getOutputStream ( ) ;
38 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 ” ) ;
39 S t r i n g message=” ” ;
40 double suma=0;
41 i f ( ! o p e r . e q u a l s ( ” con ” ) ) {
42 S t r i n g s=r e q . g e t P a r a m e t e r ( ”suma” ) ;
43 suma=Double . p a r s e D o u b l e ( s ) ;
44 }
45 Double o b j V a l u e=n u l l ;
46 try {
47 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 ” ) ;
48 }
49 catch ( E x c e p t i o n e ) {
50 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
51 }
52 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 ( ) ;
53 i n t i n d e x =−1;
54 i f ( o p e r . e q u a l s ( ” dep ” ) ) i n d e x =0;
55 i f ( o p e r . e q u a l s ( ” e x t ” ) ) i n d e x =1;
56 i f ( o p e r . e q u a l s ( ” con ” ) ) i n d e x =2;
57 double x ;
58 A t t r i b u t e c u r s=n u l l ;
59 switch ( i n d e x ) {
60 case 0 :
61 x=v a l u e+suma ;
62 c u r s=new A t t r i b u t e ( ” Cont ” , x ) ;
63 try {
64 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
65 message=”S−a depus suma” ;
66 }
67 catch ( E x c e p t i o n e ) {
68 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
69 }
70 break ;
71 case 1 :
72 i f ( v a l u e>=suma ) {
73 x=v a l u e −suma ;
74 c u r s=new A t t r i b u t e ( ” Cont ” , x ) ;
75 try {
76 c s . s e t A t t r i b u t e ( mbeanObjectName , c u r s ) ;
77 message=”S−a e x t r a s suma” ;
78 }
10.1. STANDARD MBEAN 253

79 catch ( E x c e p t i o n e ) {
80 message=”JMX−E r r o r : ”+e . g e t M e s s a g e ( ) ;
81 }
82 }
83 else {
84 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 ” ;
85 }
86 break ;
87 case 2 :
88 message=”Suma d i n c o n t e s t e ”+v a l u e+” u n i t . ” ;
89 break ;
90 }
91 r e s . setContentType ( ” t e x t / html ” ) ;
92 out . p r i n t l n ( ”<html>” ) ;
93 out . p r i n t l n ( ”<head><t i t l e >Depozit </ t i t l e ></head>” ) ;
94 out . p r i n t l n ( ”<body>” ) ;
95 out . p r i n t l n ( ”<h1>O p e r a t i u n i Cont</h1>” ) ;
96 out . p r i n t l n ( ”<p>” ) ;
97 out . p r i n t l n ( message ) ;
98 out . p r i n t l n ( ”</p>” ) ;
99 out . p r i n t l n ( ”</body></html>” ) ;
100 out . c l o s e ( ) ;
101 }

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


104 throws S e r v l e t E x c e p t i o n , IOException {
105 doGet ( req , r e s ) ;
106 }
107 }

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>

Serverul MBean este cel prezentat ı̂n Exemplul 10.1.5. Clientlul care urmăreşte de
la distanţa contul are codul
254 CAPITOLUL 10. JAVA MANAGEMENT EXTENSIONS

1 import j a v a . i o . IOException ;
2 import j a v a x . management . ∗ ;
3 import j a v a x . management . remote . ∗ ;

5 public c l a s s C l i e n t N o t i f {
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 h o s t=” l o c a l h o s t ” ;
8 S t r i n g p o r t=” 1099 ” ;
9 i f ( a r g s . l e n g t h ==0){
10 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 ” ) ;
11 System . e x i t ( 0 ) ;
12 }
13 i f ( a r g s . l e n g t h >=2) h o s t=a r g s [ 1 ] ;
14 i f ( a r g s . l e n g t h >=3) p o r t=a r g s [ 2 ] ;
15 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 ( ) ;
16 try {
17 // 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
18 // t i p MBeanServerConnection
19 S t r i n g s u r l=” s e r v i c e : jmx : rmi : / / / j n d i / rmi : / / ” +
20 h o s t+” : ”+p o r t+” / ”+a r g s [ 0 ] ;
21 JMXServiceURL u r l = new JMXServiceURL ( s u r l ) ;
22 JMXConnector jmxc = JMXConnectorFactory . c o n n e c t ( u r l , n u l l ) ;
23 MBeanServerConnection 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 System . out . p r i n t l n ( ” DefaultDomain : ” +domain ) ;
27 // Crearea unui MBean I n t r o
28 S t r i n g className=” Cont ” ;
29 S t r i n g sObjectName=domain+” : t y p e=”+className ;
30 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

32 MBeanInfo i n f o=c s . getMBeanInfo ( mbeanObjectName ) ;


33 getMBeanResources ( i n f o ) ;

35 // U t i l i z a r e a n o t i f i c a r i i
36 // Crearea unui a s c u l t a t o r
37 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 ( ) ;
38 // A c t i v a r e a n o t i f i c a t o r u l u i
39 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 ) ;

41 Thread . s l e e p ( 5 0 0 ) ;
42 // 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
43 System . out . p r i n t l n ( ” P r e s s Enter t o f i n i s h ! ” ) ;
44 try {
45 System . i n . r e a d ( ) ;
46 }
47 catch ( j a v a . i o . IOException e ) { }
48 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 ) ;
49 // 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
50 c s . u n r e g i s t e r M B e a n ( mbeanObjectName ) ;
51 }
52 catch ( E x c e p t i o n e ) {
53 System . out . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
54 e . printStackTrace ( ) ;
55 }
56 }

58 private s t a t i c void getMBeanResources ( MBeanInfo i n f o ) { . . . }


59 }
10.1. STANDARD MBEAN 255

61 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 {
62 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 ,
63 O b j e c t handback ) {
64 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 ) ;
65 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=
66 ( AttributeChangeNotification ) n o t i f i c a t i o n ;
67 System . out . p r i n t l n ( ” S o l d i n i t i a l : ” +
68 myNotif . g e tO l d V a l u e ( ) . t o S t r i n g ( ) ) ;
69 System . out . p r i n t l n ( ” S o l d c u r e n t : ” +
70 myNotif . getNewValue ( ) . t o S t r i n g ( ) ) ;
71 }
72 }

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

În RMI, 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.
Programul server (RMI) implementează interfaţa

package exchange;
public interface IConversie extends java.rmi.Remote{
public double usdToEuro(double usd)
// throws java.rmi.RemoteException;
public double usdToRol(double usd)
// throws java.rmi.RemoteException;
public double euroToUsd(double euro)
// throws java.rmi.RemoteException;
public double euroToRol(double euro)
// throws java.rmi.RemoteException;
public double rolToEuro(double rol)
// throws java.rmi.RemoteException;
public double rolToUsd(double rol)
// throws java.rmi.RemoteException;
}

257
258 CAPITOLUL 11. TEME DE LABORATOR

Rata zilnică de schimb preia dinamic sub forma unui fişier xml, apelând
http://www.bnr.ro/nbrfxrates.xml.

3. Să se realizeze conversia unui număr natural, din cifre arabe ı̂n cifre romane
şi invers.
Pentru numere x ∈ (3999, 3999999], x = a ∗ 1000 + b se va folosi scrierea sub
forma (A)B, unde A, B reprezintă conversiile lui a, respectiv b.
Exemplu: Conversia numărului 2289463 este (MMCCLXXXIX)CDLXIII.
Pentru numere x ∈ (4000000, 3999999999], x = a ∗ 1000000 + b ∗ 1000 + c se
va folosi scrierea sub forma [A](B)C, unde A, B, C reprezintă conversiile lui
a, b, c.

4. Să se realizeze conversia unui număr dintr-o bază ı̂n alta.

5. Un server adună la un număr (iniţializat cu 0) o valoare trimisă de un client


returnând rezultatul. Există o singură instanţă a numărului, acelaşi pentru
orice client.
Să se programeze serviciul descris mai sus.

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 ).
• 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 RMI


11.1. PROBLEME PROPUSE 259

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 RMI 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)
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;
}
260 CAPITOLUL 11. TEME DE LABORATOR

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.

package iemail;
import java.rmi.*;
import java.rmi.server.*;

public interface ICallbackEmail extends Remote {


public void printEmail(Email email) throws RemoteException;
}
11.1. PROBLEME PROPUSE 261

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. În cazul aplicaţiei RMI, evaluările funcţiei
cerute de formula de integrare numerică se vor realiza prin apel invers. Inte-
grarea numerică va fi executat de un server disponibil clienţilor prin mecanis-
mul 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
Z b m−1 m−1
b−a X X
f (x)dx ≈ Im = [f (a) + 2 f (a2i ) + 4 f (a2i+1 ) + f (b)]
a 6m i=1 i=0

unde ai = a + i b−a
2m .
Şirul (mk )k este definit prin mk = 2k m0 .
Semnificaţia parametrilor metodei adaptiveSimpson este
262 CAPITOLUL 11. TEME DE LABORATOR

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 utilizând RMI 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

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;
11.1. PROBLEME PROPUSE 263

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

TELEF
ID
NUME
NUMAR
264 CAPITOLUL 11. TEME DE LABORATOR

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

private void exitForm(java.awt.event.WindowEvent evt) {


System.exit(0);
}

public static void main(String args[]) {


11.1. PROBLEME PROPUSE 265

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.


Obs. Începutul anului nou chinezesc nu coincide cu ı̂nceputul anului nou cal-
endaristic.
Se va crea baza de date AN CHINEZESC alcătuită din tabelul
INCEPUT
AN
LUNA
ZI

12. Se consideră baza de date UNITAŢI DE MĂSURĂ formată din tabelul


CONVERSIE
UM SI
UM SIMBOL
DENUMIRE (ROM)
VAL
Exemplu:
1 M INCH Ţol 0.0254
2 M FEET (FT) Picior 0.3048
3 KG UK ONCE Uncie (UK) 0.031103
4 KG UK POUND Livra (UK) 0.373
Să se realizeze o aplicaţie pentru conversia unităţilor de măsură extinzând
conţinutul bazei de date.
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
266 CAPITOLUL 11. TEME DE LABORATOR

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

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.

16. Validarea codului numeric personal.


Codul Numeric Personal (CNP) constituie numărul de ordine atribuit de Evidenţa
populaţiei unei persoane la naştere, de cetăţenie română, care se ı̂nscrie ı̂n actele şi
certificatele de stare civilă şi se preia ı̂n celelate acte cu caracter oficial.
Structura unui CMP este

S AA LL ZZ JJ ZZZ C
| | | | | | |-> cifra de control
| | | | | |-> numar de ordine atribuit persoanei
| | | | |-> codul judetului
| | | |-> ziua nasterii
| | |-> Luna nasterii
| |-> Anul nasterii
|-> Cifra sexului (M/F)
1/2 nascuti intre 1 ian 1900 si 31 dec 1999
3/4 nascuti intre 1 ian 1800 si 31 dec 1899
5/6 nascuti intre 1 ian 2000 si 31 dec 2099
7/8 rezidenti
11.1. PROBLEME PROPUSE 267

Verificarea cifrei de control: Se foloseşte cheia de testare 279146358279. Primele


12 cifre ale CNP se ı̂nmulţesc pe rând de la stâga spre dreapta cu cifra core-
spunzătoare a cheii de testare. Cele 12 produse se adună, iar suma se ı̂mparte
la 11. Dacă restul ı̂mpărţirii este mai mic decât 10, atunci acesta va fi cifra de
control. Dacă restul ı̂mpărţirii este 10 atunci cifra de control este 1.

Să se elaboreze un program pentru verificarea CNP.

17. Informaţiile unui aeroport civil privind decolările(plecări) şi aterizări(sosiri)


pe parcursul unei perioade sunt cuprinse ı̂n tabelul activitate al bazei de date
aeroport
ACTIVITATE
ID
FEL aterizare/decolare
ZI
TIMP ora/minut
COMPANIE
OBSERVATIE
Să se realizeze o aplicaţie de furnizare a datelor către clienţi.
268 CAPITOLUL 11. TEME DE LABORATOR
Appendix A

Unealta de dezvoltare
apache-ant

Începem această secţiune prin a introduce câteva elemente privind sintaxa ı̂ntr-
un document xml pentru că apache-ant va face apel la un fişier xml.

XML
EXtensible Markup Language (XML) reprezintă un limbaj pentru definirea mar-
cajelor de semantică, care ı̂mpart un document ı̂n părţi identificabile ı̂n document.
Din 1998, XML este un standard World Wide Web Consortium (W3C).
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="tip_codare" [standalone="yes"]?>


corpul documentului alcatuit din elemente

Prima linie - preambulul - reprezintă declaraţia de document XML. Tipul codării


poate fi utf-8, iso-8859-1.
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

269
270 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT

<marcaj/>
Un marcaj poate avea atribute date prin sintaxa
numeAtribut="valoareAtribut"
Valoarea unui atribut este cuprinsă ı̂ntre ghilimele (””).
<marcaj numeAtribut="valoareAtribut" . . .>
corpul elementului
</marcaj>
Există un singur element rădăcină. Elementele unui document XML formează
un arbore. Fiecărui marcaj de ı̂nceput al unui element trebuie să-i corespundă un
marcaj 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,
adică un marcaj de sfârşit corespunde ultimului marcaj de ı̂nceput.
Un comentariu se indică prin
<!--
Text comentariu
-->
Exemplul A.0.1 Fişier XML - denumirile elementelor şi conţinutul lor permit ı̂nţelegerea
simplă a semanticii introduse ı̂n document.

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

Un document XML este bine formatat dacă:

• există preambul;

• fiecare element este ı̂nchis sau ı̂i corespunde un marcaj de inchidere;

• marcajele ı̂ncuibărite nu se amestecă.

Un document XML este valid dacă

• este bine formatat;

• ı̂n cazul că există o referinţă către XML Schema atunci documentul XML este
conform schemei.

Prelucrarea unui document XML ı̂n Java se poate face pe baza interfeţelor de
programare:

• Document Object Model - DOM;

• Simple API for XML - SAX;

• Stream API for XML - StAX;

• Java Architecture for XML Binding - JAXB.

Se recomandă utilizarea interfeţelor de programare StAX şi JAXB.


Amintim faptul că reprezentarea obiectelor matematice prin elemente XML con-
stituie subiectul a două proiecte MathML şi OpenMath. Obiectivul limbajului MathML
este reprezentarea unui text matematic ı̂ntr-un document HTML, ı̂n timp ce obiec-
tivul proiectului OpenMath este reprezentarea semantică a datelor matematice pen-
tru realizarea de aplicaţii cooperante ı̂ntre sisteme de calcul simbolic - CAS (Com-
puter Algebra System).

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 ı̂n Windows sau unui script shell
din Linux/Unix. Avantajul obţinut constă ı̂n independenţa faţă de platforma de
calcul (Windows, Linux).

Instalarea constă ı̂n dezarhivarea fişierului descărcat din Internet.


Lansarea ı̂n execuţie necesită fixarea variabilei de mediu JAVA HOME, ce conţine
calea la distribuţia Java. Lansarea se poate face prin următorul fişier de comenzi
272 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT

set JAVA_HOME=. . .
set ANT_HOME=. . .
%ANT_HOME%\bin\ant.bat %1
Parametrul %1 acestui fişier de comenzi reprezintă obiectivul care se doreşte a
fi atins. Dacă se modifică denumirea sau locaţia fişierului build.xml atunci fişierul
de comenzi se invocă cu opţiunea -buildfile.
Un fişier build.xml corespunde unui proiect (project), alcătuit din unul sau mai
multe obiective (target). Atingerea fiecarărui obiectiv constă din ı̂ndeplinirea uneia
sau mai multor sarcini (task). Apache-ant conţine o familie predefinită de sarcini.
Programatorul are datoria fixării atributelor sarcinilor. Manualul 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"
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ă definită se va utiliza cu sintaxa ${numeVariabila}.

Exemplul A.0.2 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 ”>


273

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 </ t a r g e t>

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


17 <j a v a c s r c d i r=” ${ s r c } ” d e s t d i r=” ${ b u i l d } ” i n c l u d e a n t r u n t i m e=” f a l s e ” />
18 </ t a r g e t>

20 <t a r g e t name=” S e r v e r ” depends=” Compile ”>


21 <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 ” />
22 </ t a r g e t>

24 <t a r g e t name=” C l i e n t ”>


25 <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 ” />
26 </ t a r g e t>
27 </ 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ă
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 .
In vederea utilizării lui apache-ivy se copiază fişierul ivy-*.jar din distribuţia
apache-ivy ı̂n ANT HOME\lib.
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">
1
Asemănător cu maven, un alt produs de dezvoltare.
274 APPENDIX A. UNEALTA DE DEZVOLTARE APACHE-ANT

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

Utilizarea SGBD ı̂n Java

Scopul acestei anexe este prezentarea bazelor utilizării unui Sistem de Gestiune
a Bazelor de Date (SGBD - Data Bases Management System - DBMS) din Java.
Exemplificăm modul de operare şi utilizare pentru crearea şi exploatarea unei baze
de date corespunzătoare unei agende telefonice.

B.1 Derby / Javadb


Instalarea produsului constă ı̂n dezarhivarea fişierului descărcat.
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 / Javadb:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
startNetworkServer.bat

2. Crearea bazei de date se va face utilizând utilitarul ij din distribuţia Derby /


Javadb. Acesta se lansează prin:
set JAVA_HOME=. . .
set DB_HOME=. . .
set PATH=%DB_HOME%\bin;%PATH%
ij.bat

Exemplul B.1.1

Baza de date AgendaEMail se crează executând


run ’CreateAgendaE.sql’;

unde fişierul CreateAgendaE.sql este

275
276 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

1 connect ’ j d b c : derby : AgendaEMail ; c r e a t e=t r u e ’ ;


2 create table a d r e s e (
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 e m a i l char ( 3 0 ) not n u l l
7 );

şi ı̂ncărcarea cu date


run ’ValuesAgendaE.sql’;

cu fişierul ValuesAgendaE.sql
1 i n s e r t into a d r e s e ( nume , e m a i l ) values ( ’ aaa ’ , ’ aaa@yahoo . com ’ ) ,
2 ( ’ bbb ’ , ’ bbb@gmail . com ’ ) , ( ’ c c c ’ , ’ cc c@un itb v . r o ’ ) ,
3 ( ’ aaa ’ , ’ xyz@unitbv . r o ’ ) ;

Putem crea tabele şi le ı̂ncărca cu valori prin ant. În acest caz, ı̂n prealabil
trebuie creată baza de date prin intermediul utilitarului ij:

connect ’jdbc:derby:AgendaEMail;create=true’;

Fişierul build.xml are codul

<?xml version="1.0"?>
<project name="db" basedir="." default="usage">
<property file="build.properties"/>

<path id="master-classpath">
<pathelement path="${db}"/>
</path>

<target name="createTables">
<echo message="CREATE TABLES USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
src="${createTable}">
<classpath refid="master-classpath"/>
</sql>
</target>

<target name="dropTables">
<echo message="DROP TABLES USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue">
<classpath refid="master-classpath"/>
B.2. MYSQL 277

DROP TABLE adrese;

</sql>
</target>

<target name="loadData">
<echo message="LOAD DATA USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
src="${valuesTable}">
<classpath refid="master-classpath"/>
</sql>
</target>

<target name="printData">
<echo message="PRINT DATA USING: ${db.driver} ${db.url}"/>
<sql driver="${db.driver}"
url="${db.url}"
userid="${db.user}"
password="${db.pw}"
onerror="continue"
print="true">
<classpath refid="master-classpath"/>

SELECT * FROM adrese;

</sql>
</target>

</project>

Resursele externe utilizate se fixează ı̂n fişierul de proprietăţi build.properties


db.driver=org.apache.derby.jdbc.ClientDriver
db.url=jdbc:derby://localhost:1527/AgendaEMail
db.user=. . .
db.pw=. . .

createTable=AntCreateAdrese.sql
valuesTable=ValuesAgendaE.sql
db=. . ./db-derby-10.5.3.0-bin/lib/derbyclient.jar

B.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.
278 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

Utilizarea produsului.
Se ı̂ntreprind următoarele operaţii:
1. Lansarea serverului mysql :
set MYSQL_HOME=. . .
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqld

2. Unui utilizator i se poate atasa o parolă, executând ı̂ntr-o sesiune mysql comen-
zile
set password for ’root’@’localhost’=password(’parola’);
set password for ’root’@’127.0.01’=password(’parola’);

Parola se şterge prin


set password for ’root’@’localhost’=password(’’);
set password for ’root’@’127.0.01’=password(’’);

Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va fi prezentă


şi opţiunea -p.
3. Exemplul B.2.1
Crearea bazei de date AgendaEMail se va face prin intermediul fişierului de
comenzi
set MYSQL_HOME=d:\mysql-*-win32\bin
set path=%MYSQL_HOME%;%PATH%
mysql -u root < CreateAgendaE.sql
mysql -u root < ValuesAgendaE.sql

unde scriptul CreateAgendaE.sql este


1 create d a t a b a s e AgendaEMail ;
2 u s e AgendaEMail ;

4 create table a d r e s e (
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 e m a i l char ( 3 0 ) not n u l l
8 );

iar scriptul de populare cu date (ValuesAgendaE.sql ) este


1 u s e AgendaEMail ;
2 i n s e r t a d r e s e values ( 1 , ” aaa ” , ” aaa@yahoo . com” ) ;
3 i n s e r t a d r e s e values ( 2 , ”bbb” , ” bbb@gmail . com” ) ;
4 i n s e r t a d r e s e values ( 3 , ” c c c ” , ” ccc @uni tbv . r o ” ) ;
5 i n s e r t a d r e s e values ( 1 , ” aaa ” , ” xyz@unitbv . r o ” ) ;

4. Serverul mysql se opreşte prin


set MYSQL_HOME=d:\mysql-*-win32
set PATH=%MYSQL_HOME%\bin;%PATH%
mysqladmin -u root shutdown
B.3. POSTGRESQL 279

B.3 PostgreSQL
Instalarea produsului. PostgreSQL este distribuit gratuit. Vom folosi o ver-
siune fără instalare automată, care se dezarhivează ı̂n catalogul ...\pgsql.
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.

• Crearea bazei de date a SGBD (initpg.bat)

set PG_HOME=. . .\pgsql


%PG_HOME%\bin\initdb -D %PG_HOME%\Data

• Lansarea serverului postgresql (server.bat)

set PG_HOME=. . .\pgsql


%PG_HOME%\bin\pg_ctl -D %PG_HOME%\Data start

Serverul se opreşte tastând Ctrl+c.


• Crearea unui utilizator (inituser.bat)

set PG_HOME=d:\pgsql
%PG_HOME%\bin\createuser

În cele ce urmează vom presupune că utilizatorul are numele postgres. Nu-
mele utilizatorul postgres este predefinit. Dacă se alege alt nume atunci se va
executa suplimentar

%PG_HOME%\bin\createdb nume_utilizator

• Exemplul B.3.1
Crearea aceleiaşi baze de date AgendaTelefonică se face cu fişierul de comenzi
(agendat.bat)

set PG_HOME=d:\pgsql
%PG_HOME%\bin\psql -U postgres -f createdb.sql
%PG_HOME%\bin\psql -U postgres -d AgendaEMail -f createtable.sql
%PG_HOME%\bin\psql -U postgres -d AgendaEMail -f insertvalues.sql

Script-urile sql sunt

createdb.sql

create database "AgendaEMail" owner postgres;

createtable.sql
280 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

create table adrese(id int4 primary key,


nume varchar(20) not null, email varchar(30) not null);

insertvalues.sql

insert adrese values(1,"aaa","aaa@yahoo.com");


insert adrese values(2,"bbb","bbb@gmail.com");
insert adrese values(3,"ccc","ccc@unitbv.ro");
insert adrese values(1,"aaa","xyz@unitbv.ro");

B.4 HyperSQL
Instalarea produsului. Instalarea constă din dezarhivarea fişierului descărcat
ı̂ntr-un catalog pe care-l notăm HSQL HOME. HypereSQL se distribuie gratuit.
Comunicaţia cu acest serverul se face prin portul 9001.
Conectorul Java este conţinut ı̂n distribuţia produsului şi este fişierul hsqldb.jar.
Utilizarea produsului.

• Pornirea serverului şi crearea bazei de date AgendaTelefonica

set HSQL_HOME=. . .\hsqldb


set JAVA_HOME=. . .
java -cp %HSQL_HOME%/lib/hsqldb.jar org.hsqldb.server.Server
--database.0 file:AgendaEMail --dbname.0 AgendaEMail

• Crearea tabelei telef şi inserarea valorilor iniţiale

set HSQL_HOME=. . .\hsqldb


set JAVA_HOME=. . .
java -cp %HSQL_HOME%/lib/sqltool.jar org.hsqldb.cmdline.SqlTool
--inlineRc URL=jdbc:hsqldb:hsql://localhost/AgendaEMail,
USER=SA,password= CreateTable.sql
java -cp %HSQL_HOME%/lib/sqltool.jar org.hsqldb.cmdline.SqlTool
--inlineRc URL=jdbc:hsqldb:hsql://localhost/AgendaEMail,
USER=SA,password= InsertValues.sql

unde script-urile sql sunt

CreateTable.sql

\c true
DROP TABLE adrese;
\c false

\p Creating Table adrese


create table adrese(
id integer primary key not null,
nume varchar(20) not null,
email varchar(30) not null
);
B.5. ORACLE XE 10G 281

InsertValues.sql

\p Interting values into telef


insert INTO adrese ("ID","NUME","EMAIL") values(1,’aaa’,’aaa@yahoo.com’);
insert INTO adrese ("ID","NUME","EMAIL") values(2,’bbb’,’bbb@gmail.com’);
insert INTO adrese ("ID","NUME","EMAIL") values(3,’ccc’,’ccc@unitbv.ro’);
insert INTO adrese ("ID","NUME","EMAIL") values(4,’aaa’,’aaa@unitbv.ro’);
commit;

B.5 Oracle XE 10g


Utilizarea produsului ı̂n linie de comandă:

• Într-o fereastră DOS se lansează sqlplus.

• Start → Programs → Oracle Database 10g Express Edition → Run SQL Com-
mand Line. În fereastra DOS se lansează connect.

Ca user : system putem schimba portul HTTP din 8080 ı̂n 9090(de exemplu),
prin

exec dbms_xdb.sethttpport(9090)

Exemplul B.5.1

Baza de date AgendaEMail se crează executând

1. @CreateAgendaE.sql

unde fişierul CreateAgendaE.sql este


1 create table a d r e s e (
2 i d i n t primary key ,
3 nume varchar2 ( 2 0 ) ,
4 e m a i l varchar2 ( 3 0 )
5 );

şi ı̂ncărcarea cu date

2. @ValuesAgendaE.sql

cu fişierul ValuesAgendaE.sql
1 insert into adrese values (1 , ’ aaa ’ , ’ aaa@unitbv . r o ’ );
2 insert into adrese values (2 , ’ bbb ’ , ’ bbb@yahoo . com ’ );
3 insert into adrese values (3 , ’ ccc ’ , ’ ccc@gmail . com ’ );
4 insert into adrese values (4 , ’ aaa ’ , ’ xyz@yahoo . com ’ );
282 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

B.6 Şablonul de utilizare a unei baze de date ı̂ntr-un


program Java
Înteracţiunea cu baze de date relaţionale implică:
1. Stabilirea corespondenţei dintre date aflate ı̂n obiecte şi atribute / tabele (ob-
ject to relational database mapping).
2. Apelarea acţiunilor CRUD (Create, Read, Update, Delete).
Pentru realizarea acestor activităţi sunt cunoscute mai multe modele:
• Data Access Object DAO
• Java Data Object JDO
Limbajul SQL (Structured Query Language) este dependent de SGBD utilizat.
Dezvoltarea modelelor de interacţiune dintre un program Java cu o bază de date
dintr-un SGBD s-a născut din dorinţa de a asigura independenţa stratului Java de
SGBD. Soluţia găsită constă ı̂n introducerea unui strat suplimentar, ı̂ntre Java şi
SGBD care asigură corespondenţa ı̂ntre obiectele Java cu tabelele unei baze de date
şi permite o configurare simplă la schimbarea SGBD.
Materializarea acestor idei (Object Relational Mapping - ORM) se află ı̂n
• interfaţa de programare (API) Java Persistence API (JPA);
• produsul Hibernate.
Pentru ı̂nceput vom face abstracţie de modelele menţionate anterior şi vom trata
ı̂n modul cel mai simplu realizarea unei aplicaţii care interacţionează cu o bază de
date gestionată de un SGBD.

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
javadb
(distribuţia derby)
postgresql org.postgresql.Driver postgresql-*.*-*.jdbc4.jar
hypeqsql org.hsqldb.jdbcDriver hsqldb.jar
oraclexe oracle.jdbc.driver.OracleDriver ojdbc14.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.
B.6. ŞABLONUL DE UTILIZARE A UNEI BAZE DE DATE 283

• adresa URL a bazei de date (String URLBazaDate), sub forma


Tip SGBD Referinţă Baza de Date
mysql jdbc:mysql://host:3306/numeBazaDate
derby / javadb jdbc:derby://host:1527/numeBazaDate
postgresql jdbc:postgresql://host:5432/numeBazaDate
hypersql jdbc:hsqldb:hsql://host/numeBazaDate
oracle jdbc:oracle:thin:@host:1521:XE

Şablonul de prelucrare este

String jdbcDriver=. . .
String URLBazaDate=. . .
Connection con=null;
try{
Class.forName(jdbcDriver).newInstance();
con=DriverManager.getConnection(URLBazaDate);
...
}
catch(ClassNotFoundException e){. . .}
catch(SQLException e){. . .}

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 B.6.1

O interogare simplă a bazei de date AgendaEMail se realizează cu programul


1 import j a v a . i o . ∗ ;
2 import j a v a . s q l . ∗ ;
3 import j a v a . n e t . ∗ ;
284 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

4 import j a v a . u t i l . ∗ ;

6 public c l a s s AgendaE {
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 t r i n g username , S t r i n g password ) {


10 // SGBD Derby
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 / AgendaEMail ” ;

14 // SGBD mysql
15 /∗
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=” j d b c : mysql : / / l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ” ;
18 ∗/

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 / AgendaEMail ” ;
24 // S t r i n g username=p o s t g r e s ” ;
25 // S t r i n g password =”;
26 ∗/

28 // HyperSQL
29 /∗
30 S t r i n g j d b c D r i v e r =”o r g . h s q l d b . j d b c D r i v e r ” ;
31 S t r i n g URLBazaDate=” j d b c : h s q l d b : h s q l : / / l o c a l h o s t / AgendaEMail ” ;
32 // S t r i n g username=”SA” ;
33 // S t r i n g password =””;
34 ∗/

36 // O r a c l e 10 g E x p r e s s E d i t i o n
37 /∗
38 S t r i n g j d b c D r i v e r =” o r a c l e . j d b c . d r i v e r . O r a c l e D r i v e r ” ;
39 S t r i n g URLBazaDate=” j d b c : o r a c l e : t h i n : @ l o c a l h o s t : 1 5 2 1 :XE” ;
40 ∗/

42 C o n n e c t i o n con=n u l l ;
43 try {
44 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 ( ) ;
45 i f ( username != n u l l )
46 con = DriverManager . g e t C o n n e c t i o n ( URLBazaDate , username , password ) ;
47 else
48 con = DriverManager . g e t C o n n e c t i o n ( URLBazaDate ) ;
49 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 ( ) ;
50 }
51 catch ( ClassNotFoundException e ) {
52 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 ) ;
53 }
54 catch ( SQLException e ) {
55 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 ) ;
56 }
57 catch ( E x c e p t i o n e ) {
58 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 ( ) ) ;
59 }
60 }

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


B.6. ŞABLONUL DE UTILIZARE A UNEI BAZE DE DATE 285

63 AgendaE agenda=new AgendaE ( ) ;


64 i f ( a r g s . l e n g t h >0)
65 agenda . i n i t ( a r g s [ 0 ] , a r g s [ 1 ] ) ;
66 else
67 agenda . i n i t ( null , n u l l ) ;
68 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
69 i n t p r e l , no ;
70 S t r i n g ch=”Y” , nume=” ” , e m a i l=” ” , s q l=” ” ;
71 R e s u l t S e t r s=n u l l ;
72 try {
73 while ( ch . s t a r t s W i t h ( ”Y” ) ) {
74 do{
75 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;
76 ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
77 }
78 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” ) ) ) ;
79 i f ( ch . s t a r t s W i t h ( ”Y” ) ) {
80 System . out . p r i n t l n ( ” Natura i n t e r o g a r i i ? ” ) ;
81 System . out . p r i n t l n ( ” ( Dupa nume : 1 , Dupa e m a i l : 2 ) ” ) ;
82 do{
83 p r e l =0;
84 try {
85 p r e l=s c a n n e r . n e x t I n t ( ) ;
86 }
87 catch ( InputMismatchException e ) { }
88 }
89 while ( ( p r e l <1)&&( p r e l > 2 ) ) ;
90 switch ( p r e l ) {
91 case 1 :
92 System . out . p r i n t l n ( ”Numele” ) ;
93 nume= ’ \ ’ ’+s c a n n e r . n e x t ( ) . t r i m ()+ ’ \ ’ ’ ;
94 s q l=” s e l e c t ∗ from a d r e s e where nume=”+nume ;
95 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 ) ;
96 i f ( r s != n u l l ) {
97 System . out . p r i n t l n ( ”S−au g a s i t a d r e s e l e de e−m a i l : ” ) ;
98 while ( r s . n e x t ( ) ) {
99 System . out . p r i n t l n ( r s . g e t S t r i n g ( ” e m a i l ” ) ) ;
100 }
101 }
102 else {
103 System . out . p r i n t l n ( ” Fara a d r e s a de e−m a i l ! ” ) ;
104 }
105 break ;
106 case 2 :
107 System . out . p r i n t l n ( ” Email ” ) ;
108 e m a i l= ’ \ ’ ’+s c a n n e r . n e x t ( ) . t r i m ()+ ’ \ ’ ’ ;
109 s q l=” s e l e c t ∗ from a d r e s e where e m a i l=”+e m a i l ;
110 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 ) ;
111 i f ( r s != n u l l ) {
112 System . out . p r i n t l n ( ”S−a g a s i t numele ” +
113 ”:”);
114 while ( r s . n e x t ( ) ) {
115 System . out . p r i n t l n ( r s . g e t S t r i n g ( ”nume” ) ) ;
116 }
117 }
118 else {
119 System . out . p r i n t l n ( ”Numar i n e x i s t e n t ! ” ) ;
120 }
121 break ;
286 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

122 default : System . out . p r i n t l n ( ”Comanda e r o n a t a ” ) ;


123 }
124 }
125 }
126 }
127 catch ( E x c e p t i o n e ) {
128 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 ( ) ) ;
129 }
130 }
131 }

Fraza select şi interogarea se mai putea programa prin

String sql="select * from adrese where nume =?";


PreparedStatement prepStmt=con.prepareStatement(sql);
prepStmt.setString(1,nume);
RezultSet rs=prepStmt.executeQuery();
. . .
prepStmt.close();

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

• Varianta mysql
%MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar

Execuţia programului presupune serverul SGBD activ.

B.7 Modelul DAO


Prezentarea va exemplifica modelul DAO ı̂n cazul bazei de date amintite anterior
(AgendaEMail ): o agendă de adrese e-mail alcătuită dintr-un singur tabel adrese,
cu atributele

id: int, cheia primara


nume: String
email: String
Conexiunea cu baza de date se separă de activităţile care se ı̂ntreprind asupra
bazei de date. Pentru stabilirea conexiunii este nevoie doar de adresa URI a bazei
de date. Alegem soluţia simplă:
B.7. MODELUL DAO 287

1 package agendae . dao ;


2 import j a v a . s q l . C o n n e c t i o n ;
3 import j a v a . s q l . SQLException ;
4 import j a v a . s q l . DriverManager ;
5 public c l a s s DAOBase{
6 public C o n n e c t i o n g e t C o n n e c t i o n ( ) throws E x c e p t i o n {
7 S t r i n g URLDB=” j d b c : derby : / / l o c a l h o s t : 1 5 2 7 / AgendaEMail ” ;
8 Connection connection = null ;
9 try {
10 c o n n e c t i o n=DriverManager . g e t C o n n e c t i o n (URLDB) ;
11 }
12 catch ( SQLException e ) {
13 throw new E x c e p t i o 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 ( ) ) ;
14 }
15 return c o n n e c t i o n ;
16 }
17 }

Fiecărui tabel al bazei de date i se asociază:


• O componentă Java (bean) a cărei instanţă reţine (total sau parţial) datele
corespunzătoare unei linii a tabelei.
1 package agendae . dao ;
2 import j a v a . i o . S e r i a l i z a b l e ;

4 public c l a s s Adrese implements S e r i a l i z a b l e {


5 private i n t i d ;
6 private S t r i n g nume ;
7 private S t r i n g e m a i l ;

9 public Adrese ( ) { }

11 public Adrese ( i n t id , S t r i n g nume , S t r i n g e m a i l ) {


12 this . id = id ;
13 t h i s . nume = nume ;
14 this . email = email ;
15 }
16 public S t r i n g getNume ( ) {
17 return nume ;
18 }
19 public void setNume ( S t r i n g nume ) {
20 t h i s . nume = nume ;
21 }
22 public S t r i n g g e t E m a i l ( ) {
23 return e m a i l ;
24 }
25 public void s e t E m a i l ( S t r i n g e m a i l ) {
26 this . email = email ;
27 }
28 public i n t g e t I d ( ) {
29 return i d ;
30 }
31 public void s e t I d ( i n t i d ) {
32 this . id = id ;
33 }
34 }
288 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

• O interfaţă Java cu acţiunile care se ı̂ntreprind asupra tabelei respective.


Uzual, dacă tabela are numele xyz atunci numele interfeţei va fi XyzDAO.java.
Prentru cazul exemplificat considerăm interfaţa
1 package agendae . dao ;
2 import j a v a . u t i l . L i s t ;

4 public i n t e r f a c e AdreseDAO {
5 public void c r e a t e A d r e s e ( Adrese i n r e g ) throws E x c e p t i o n ;
6 public void u p d a t eA d r e s e ( Adrese i n r e g ) throws E x c e p t i o n ;
7 public Adrese r e a d A d r e s e ( i n t i n r e g I d ) throws E x c e p t i o n ;
8 public void d e l e t e A d r e s e ( i n t i n r e g I d ) throws E x c e p t i o n ;
9 public L i s t <Adrese> s e a r c h A d r e s e ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a )
10 throws E x c e p t i o n ;
11 }

Căutarea unei ı̂nregistrări se poate face după nume sau după adresa de email.
Unui nume ı̂i pot corespunde mai multe adrese de email, iar dintr-o adresă nu
putem şti cui ı̂i aparţine. Clasa SearchCriteria este o componentă prin care se
fixează criteriul de cătare.
1 package agendae . dao ;
2 import j a v a . i o . S e r i a l i z a b l e ;

4 public c l a s s S e a r c h C r i t e r i a implements S e r i a l i z a b l e {
5 private S t r i n g nume=n u l l ;
6 private S t r i n g e m a i l=n u l l ;

8 public S t r i n g getNume ( ) {
9 return nume ;
10 }
11 public void setNume ( S t r i n g nume ) {
12 t h i s . nume = nume ;
13 }
14 public S t r i n g g e t E m a i l ( ) {
15 return e m a i l ;
16 }
17 public void s e t E m a i l ( S t r i n g e m a i l ) {
18 this . email = email ;
19 }
20 }

Dacă nume=null atunci se cere lista numelor care corespund la o adresă email,
iar dacă email=null atunci se cere lista adreselor de email corespunzătoare
unui nume.

Deoarece fiecare SGBD are propriul dialect SQL clasa ce implementează interfaţa
DAO este specifică SGBD-ului. Utilizând Derby / JavaDB codul implementării
AdreseDAODerbyImpl este
1 package agendae . dao ;
2 import j a v a . s q l . SQLException ;
3 import j a v a . s q l . C o n n e c t i o n ;
4 import j a v a . s q l . P r e p a r e d S t a t e m e n t ;
5 import j a v a . s q l . R e s u l t S e t ;
6 import j a v a . s q l . Statement ;
B.7. MODELUL DAO 289

7 import j a v a . u t i l . A r r a y L i s t ;
8 import j a v a . u t i l . L i s t ;

10 public c l a s s AdreseDAODerbyImpl extends DAOBase implements AdreseDAO {


11 private s t a t i c f i n a l S t r i n g CREATE Adrese SQL =
12 ”INSERT INTO a d r e s e ( nume , e m a i l ) VALUES ( ? , ? ) ” ;
13 public void c r e a t e A d r e s e ( Adrese i n r e g ) throws E x c e p t i o n {
14 Connection connection = null ;
15 P r e p a r e d S t a t e m e n t pStatement = n u l l ;
16 try {
17 connection = getConnection ( ) ;
18 pStatement = c o n n e c t i o n . p r e p a r e S t a t e m e n t ( CREATE Adrese SQL ) ;
19 pStatement . s e t S t r i n g ( 1 , i n r e g . getNume ( ) ) ;
20 pStatement . s e t S t r i n g ( 2 , i n r e g . g e t E m a i l ( ) ) ;
21 pStatement . e x e c u t e U p d a t e ( ) ;
22 pStatement . c l o s e ( ) ;
23 }
24 catch ( E x c e p t i o n e ) {
25 throw new E x c e p t i o n ( ”AdreseDAODerbyImpl : ”+e . g e t M e s s a g e ( ) ) ;
26 }
27 finally {
28 try {
29 connection . clos e ( ) ;
30 }
31 catch ( SQLException ex ) {}
32 }
33 }

35 private s t a t i c f i n a l S t r i n g UPDATE Adrese SQL =


36 ”UPDATE a d r e s e SET nume=? , e m a i l =? WHERE i d = ? ” ;
37 public void u p d a te A d r e s e ( Adrese i n r e g ) throws E x c e p t i o n {
38 Connection connection = null ;
39 P r e p a r e d S t a t e m e n t pStatement = n u l l ;
40 try {
41 connection = getConnection ( ) ;
42 pStatement = c o n n e c t i o n . p r e p a r e S t a t e m e n t ( UPDATE Adrese SQL ) ;
43 pStatement . s e t S t r i n g ( 1 , i n r e g . getNume ( ) ) ;
44 pStatement . s e t S t r i n g ( 2 , i n r e g . g e t E m a i l ( ) ) ;
45 pStatement . s e t I n t ( 3 , i n r e g . g e t I d ( ) ) ;
46 pStatement . e x e c u t e U p d a t e ( ) ;
47 pStatement . c l o s e ( ) ;
48 }
49 catch ( SQLException e ) {
50 throw new E x c e p t i o n ( ”AdreseDAODerbyImpl : ”+e . g e t M e s s a g e ( ) ) ;
51 }
52 finally {
53 try {
54 connection . clos e ( ) ;
55 }
56 catch ( SQLException ex ) {}
57 }
58 }

60 private s t a t i c f i n a l S t r i n g READ Adrese SQL =


61 ”SELECT nume , e m a i l FROM a d r e s e WHERE i d = ? ” ;
62 public Adrese r e a d A d r e s e ( i n t i n r e g I d ) throws E x c e p t i o n {
63 Connection connection = null ;
64 P r e p a r e d S t a t e m e n t pStatement = n u l l ;
65 ResultSet r s = null ;
290 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

66 Adrese i n r e g = new Adrese ( ) ;


67 try {
68 connection = getConnection ( ) ;
69 pStatement = c o n n e c t i o n . p r e p a r e S t a t e m e n t ( READ Adrese SQL ) ;
70 pStatement . s e t I n t ( 1 , i n r e g I d ) ;
71 r s = pStatement . e x e c u t e Q u e r y ( ) ;
72 i f ( r s . next ( ) ) {
73 i n r e g . setNume ( r s . g e t S t r i n g ( ”nume” ) ) ;
74 inreg . setEmail ( rs . getString ( ” email ” ) ) ;
75 inreg . setId ( inregId );
76 }
77 rs . close ( ) ;
78 pStatement . c l o s e ( ) ;
79 }
80 catch ( SQLException e ) {
81 throw new E x c e p t i o n ( ”AdreseDAODerbyImpl : ”+e . g e t M e s s a g e ( ) ) ;
82 }
83 finally {
84 try {
85 connection . clos e ( ) ;
86 } catch ( SQLException ex ) {}
87 }
88 return i n r e g ;
89 }

91 private s t a t i c f i n a l S t r i n g DELETE Adrese SQL =


92 ”DELETE FROM a d r e s e WHERE i d = ? ” ;
93 public void d e l e t e A d r e s e ( i n t i n r e g I d ) throws E x c e p t i o n {
94 Connection connection = null ;
95 P r e p a r e d S t a t e m e n t pStatement = n u l l ;
96 try {
97 connection = getConnection ( ) ;
98 pStatement = c o n n e c t i o n . p r e p a r e S t a t e m e n t ( DELETE Adrese SQL ) ;
99 pStatement . s e t I n t ( 1 , i n r e g I d ) ;
100 pStatement . e x e c u t e U p d a t e ( ) ;
101 pStatement . c l o s e ( ) ;
102 }
103 catch ( SQLException e ) {
104 throw new E x c e p t i o n ( ”AdreseDAODerbyImpl : ”+e . g e t M e s s a g e ( ) ) ;
105 }
106 finally {
107 try {
108 connection . clo se ( ) ;
109 }
110 catch ( SQLException ex ) {}
111 }
112 }

114 private s t a t i c f i n a l S t r i n g SEARCH Adrese SQL =


115 ”SELECT id , nume , e m a i l FROM a d r e s e WHERE ” ;
116 public L i s t <Adrese> s e a r c h A d r e s e ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a )
117 throws E x c e p t i o n {
118 L i s t <Adrese> l i s t = new A r r a y L i s t <Adrese > ( ) ;
119 Connection connection = null ;
120 Statement s t a t e m e n t = n u l l ;
121 ResultSet r e s u l t S e t = null ;
122 S t r i n g searchSQL ;
123 S t r i n g nume=s e a r c h C r i t e r i a . getNume ( ) ;
124 S t r i n g e m a i l=s e a r c h C r i t e r i a . g e t E m a i l ( ) ;
B.7. MODELUL DAO 291

125 // System . o u t . p r i n t l n (” C r i t e r i a : ”+nume+” ”+e m a i l ) ;


126 i f ( nume==n u l l ) {
127 searchSQL=SEARCH Adrese SQL+” e m a i l=”+ ’ \ ’ ’+e m a i l+ ’ \ ’ ’ ;
128 }
129 else {
130 searchSQL=SEARCH Adrese SQL+”nume=”+ ’ \ ’ ’+nume+ ’ \ ’ ’ ;
131 }
132 // System . o u t . p r i n t l n ( searchSQL ) ;
133 try {
134 connection = getConnection ( ) ;
135 statement = connection . createStatement ( ) ;
136 r e s u l t S e t = s t a t e m e n t . e x e c u t e Q u e r y ( searchSQL ) ;
137 while ( r e s u l t S e t . n e x t ( ) ) {
138 Adrese i n r e g = new Adrese ( ) ;
139 inreg . setId ( resultSet . getInt (” id ” ) ) ;
140 i n r e g . setNume ( r e s u l t S e t . g e t S t r i n g ( ”nume” ) ) ;
141 inreg . setEmail ( r e s u l t S e t . getString ( ” email ” ) ) ;
142 l i s t . add ( i n r e g ) ;
143 }
144 resultSet . close ();
145 statement . c l o s e ( ) ;
146 }
147 catch ( SQLException e ) {
148 throw new E x c e p t i o n ( ”AdreseDAODerbyImpl : ”+e . g e t M e s s a g e ( ) ) ;
149 }
150 finally {
151 try {
152 connection . clos e ( ) ;
153 }
154 catch ( SQLException ex ) {}
155 }
156 return l i s t ;
157 }
158 }

Apelarea unei aţiuni CRUD necesită o instanţă a clasei AdreseDAODerbyImpl.


Crearea acestei instanţe va fi făcută utilizând şablonul singleton, prin clasa
1 package agendae . dao ;

3 public c l a s s DAOFactory {
4 private s t a t i c DAOFactory i n s t a n c e ;
5 private s t a t i c AdreseDAODerbyImpl adreseDAODerbyImpl=n u l l ;
6 static {
7 i n s t a n c e = new DAOFactory ( ) ;
8 }
9 private DAOFactory ( ) {
10 adreseDAODerbyImpl=new AdreseDAODerbyImpl ( ) ;
11 }
12 public s t a t i c DAOFactory g e t I n s t a n c e ( ) {
13 return i n s t a n c e ;
14 }

16 public AdreseDAO getAdreseDAO ( ) {


17 return adreseDAODerbyImpl ;
18 }
19 }

Un client fără interfaţaă grafică este


292 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

1 package agendae ;
2 import j a v a . u t i l . ∗ ;
3 import agendae . dao . ∗ ;

5 public c l a s s AgendaEClient {
6 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
7 AdreseDAO dao=DAOFactory . g e t I n s t a n c e ( ) . getAdreseDAO ( ) ;
8 Adrese e n t i t y=n u l l ;
9 L i s t <Adrese> l i s t =n u l l ;
10 I t e r a t o r <Adrese> i t e r a t o r=n u l l ;
11 S e a r c h C r i t e r i a s c=n u l l ;
12 S t r i n g ch=”Y” ;
13 int p r e l ;
14 S c a n n e r s c a n n e r=new S c a n n e r ( System . i n ) ;
15 while ( ch . s t a r t s W i t h ( ”Y” ) ) {
16 do{
17 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;
18 ch=s c a n n e r . n e x t ( ) . toUpperCase ( ) ;
19 }
20 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” ) ) ) ;
21 i f ( ch . s t a r t s W i t h ( ”Y” ) ) {
22 System . out . p r i n t l n ( ” Natura p r e l u c r a r i i ? ” ) ;
23 System . out . p r i n t l n ( ” Adaugare ( C r e a t e ) : 1 ”);
24 System . out . p r i n t l n ( ” S t e r g e r e ( D e l e t e ) : 2 ”);
25 System . out . p r i n t l n ( ” A c t u a l i z a r e ( Update ) : 3 ”);
26 System . out . p r i n t l n ( ” Cautare dupa c h e i e ( Read ) : 4 ” ) ;
27 System . out . p r i n t l n ( ” Cautare ( Read ) : 5 ”);
28 p r e l=s c a n n e r . n e x t I n t ( ) ;
29 S t r i n g nume , e m a i l ;
30 int id ;
31 switch ( p r e l ) {
32 case 1 :
33 System . out . p r i n t l n ( ”ADAUGARE” ) ;
34 System . out . p r i n t l n ( ”Numele : ” ) ;
35 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
36 System . out . p r i n t l n ( ” Adresa e−m a i l : ” ) ;
37 e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ;
38 e n t i t y=new Adrese ( ) ;
39 e n t i t y . setNume ( nume ) ;
40 e n t i t y . setEmail ( email ) ;
41 try {
42 dao . c r e a t e A d r e s e ( e n t i t y ) ;
43 System . out . p r i n t l n ( ” O p e r a t i a a f o s t e x e c u t a t a cu s u c c e s ! ” ) ;
44 }
45 catch ( E x c e p t i o n e ) {
46 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
47 }
48 break ;
49 case 2 :
50 System . out . p r i n t l n ( ”STERGERE” ) ;
51 System . out . p r i n t l n ( ” I d : ” ) ;
52 i d=s c a n n e r . n e x t I n t ( ) ;
53 try {
54 dao . d e l e t e A d r e s e ( i d ) ;
55 System . out . p r i n t l n ( ” O p e r a t i a a f o s t e x e c u t a t a cu s u c c e s ! ” ) ;
56 }
57 catch ( E x c e p t i o n e ) {
58 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
59 }
B.7. MODELUL DAO 293

60 break ;
61 case 3 :
62 System . out . p r i n t l n ( ”ACTUALIZARE” ) ;
63 System . out . p r i n t l n ( ”Numele : ” ) ;
64 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
65 System . out . p r i n t l n ( ” Adresa e−m a i l : ” ) ;
66 e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ;
67 System . out . p r i n t l n ( ” Cheia i n r e g i s t r a r i i ( I d ) : ” ) ;
68 i d=s c a n n e r . n e x t I n t ( ) ;
69 e n t i t y=new Adrese ( ) ;
70 e n t i t y . setNume ( nume ) ;
71 e n t i t y . setEmail ( email ) ;
72 entity . setId ( id ) ;
73 try {
74 dao . u p d a t eA d r e s e ( e n t i t y ) ;
75 System . out . p r i n t l n ( ” O p e r a t i a a f o s t e x e c u t a t a cu s u c c e s ! ” ) ;
76 }
77 catch ( E x c e p t i o n e ) {
78 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
79 }
80 break ;
81 case 4 :
82 System . out . p r i n t l n ( ”CAUTARE DUPA CHEIE” ) ;
83 System . out . p r i n t l n ( ” I d : ” ) ;
84 i d=s c a n n e r . n e x t I n t ( ) ;
85 try {
86 e n t i t y=dao . r e a d A d r e s e ( i d ) ;
87 System . out . p r i n t l n ( ”Nume : ”+e n t i t y . getNume ( ) ) ;
88 System . out . p r i n t l n ( ” Email : ”+e n t i t y . g e t E m a i l ( ) ) ;
89 }
90 catch ( E x c e p t i o n e ) {
91 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
92 }
93 break ;
94 case 5 :
95 System . out . p r i n t l n ( ” C r i t e r i u l de c a u t a r e : ” ) ;
96 System . out . p r i n t l n ( ”Dupa nume : 1 ” ) ;
97 System . out . p r i n t l n ( ”Dupa e m a i l : 2 ” ) ;
98 i n t c r i t e r i u=s c a n n e r . n e x t I n t ( ) ;
99 switch ( c r i t e r i u ) {
100 case 1 :
101 System . out . p r i n t l n ( ”Numele : ” ) ;
102 nume=s c a n n e r . n e x t ( ) . t r i m ( ) ;
103 s c=new S e a r c h C r i t e r i a ( ) ;
104 s c . setNume ( nume ) ;
105 try {
106 l i s t =dao . s e a r c h A d r e s e ( s c ) ;
107 i t e r a t o r= l i s t . i t e r a t o r ( ) ;
108 while ( i t e r a t o r . hasNext ( ) ) {
109 Adrese i n r e g =( Adrese ) i t e r a t o r . n e x t ( ) ;
110 System . out . p r i n t l n ( i n r e g . g e t I d ()+ ” : ”+
111 i n r e g . getNume ()+ ” : ”+i n r e g . g e t E m a i l ( ) ) ;
112 }
113 }
114 catch ( E x c e p t i o n e ) {
115 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
116 }
117 break ;
118 case 2 :
294 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

119 System . out . p r i n t l n ( ” Adresa e−m a i l : ” ) ;


120 e m a i l=s c a n n e r . n e x t ( ) . t r i m ( ) ;
121 s c=new S e a r c h C r i t e r i a ( ) ;
122 sc . setEmail ( email ) ;
123 try {
124 l i s t =dao . s e a r c h A d r e s e ( s c ) ;
125 i t e r a t o r= l i s t . i t e r a t o r ( ) ;
126 while ( i t e r a t o r . hasNext ( ) ) {
127 Adrese i n r e g =( Adrese ) i t e r a t o r . n e x t ( ) ;
128 System . out . p r i n t l n ( i n r e g . g e t I d ()+ ” : ”+
129 i n r e g . getNume ()+ ” : ”+i n r e g . g e t E m a i l ( ) ) ;
130 }
131 }
132 catch ( E x c e p t i o n e ) {
133 System . out . p r i n t l n ( ” E x c e p t i e : ”+e . g e t M e s s a g e ( ) ) ;
134 }
135 break ;
136 default :
137 System . out . p r i n t l n ( ” C r i t e r i u de c a u t a r e e r o n a t ” ) ;
138 }
139 break ;
140 default : System . out . p r i n t l n ( ”Comanda e r o n a t a ” ) ;
141 }
142 }
143 else
144 System . e x i t ( 0 ) ;
145 }
146 }
147 }

B.8 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. JPA este dezvoltat
pe modelul dat modelul pachetului javax.persistence iniţiat de Oracle-Sun Mi-
croSystems, din Java Enterprise Edition (JEE), dar pentru care există mai multe
implemaentări. De asemenea, există mai multe implementări a interfeţei JPA.
O alternativă la JPA ı̂l reprezintă produsul Hibernate.
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.
B.8. JAVA PERSISTENCE API - JPA 295

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

B.8.1 apache-openjpa
Aşa cum sugerează numele produsului, openjpa este implementarea oferită de
apache.
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 ”
296 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

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

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();
B.8. JAVA PERSISTENCE API - JPA 297

// 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 B.8.1 Aplicaţie pentru ı̂ntreţinerea şi interogarea bazei de date Agen-
daEMail.
Tabelei adrese a bazei de date ı̂i corespunde clasa Adrese
1 package agendae . dao ;
2 import j a v a . i o . S e r i a l i z a b l e ;
3 import j a v a x . p e r s i s t e n c e . ∗ ;

5 @Entity
6 public c l a s s Adrese implements S e r i a l i z a b l e {
7 private i n t i d ;
8 private S t r i n g nume ;
9 private S t r i n g e m a i l ;

11 public Adrese ( ) { }

13 public Adrese ( i n t id , S t r i n g nume , S t r i n g e m a i l ) {


14 this . id = id ;
15 t h i s . nume = nume ;
16 this . email = email ;
17 }

19 public i n t g e t I d ( ) {
20 return i d ;
21 }
22 public void s e t I d ( i n t i d ) {
23 this . id = id ;
24 }

26 public S t r i n g getNume ( ) {
27 return nume ;
28 }
29 public void setNume ( S t r i n g nume ) {
30 t h i s . nume = nume ;
31 }

33 public S t r i n g g e t E m a i l ( ) {
34 return e m a i l ;
35 }
36 public void s e t E m a i l ( S t r i n g e m a i l ) {
37 this . email = email ;
298 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

38 }
39 }

Accessarea bazei de date se face prin clasa AdreseDAOImpl. Această clasă im-
plementează interfaţa AdreseDAO, dată ı̂n secţiunea anterioară.
1 package agendae . dao ;
2 im po rt j a v a . u t i l . L i s t ;
3 im po rt j a v a x . p e r s i s t e n c e . ∗ ;

5 @SuppressWarnings ( ” unchecked ” )
6 p u b l i c c l a s s AdreseDAOImpl implements AdreseDAO{
7 E n ti t y M an a g e rF a c t or y f a c t o r y=n u l l ;
8 EntityManager em ;

10 p u b l i c AdreseDAOImpl ( E n ti t y M an a g e 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 c r e a t e A d r e s e ( Adrese i n r e g ) {
15 S t r i n g name=i n r e g . getNume ( ) ;
16 S t r i n g e m a i l=i n r e g . g e t E m a i l ( ) ;
17 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 ( ) ;
18 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
19 S t r i n g s q l=”INSERT INTO a d r e s e ( nume , e m a i l ) VALUES( \ ’ ”+name+” \ ’ , \ ’ ”+e m a i l+” \ ’ ) ” ;
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 }

26 p u b l i c v o i d up d a t e A d r e s e ( Adrese i n r e g ) {
27 S t r i n g nume=” \ ’ ”+i n r e g . getNume ()+ ” \ ’ ” ;
28 S t r i n g e m a i l=” \ ’ ”+i n r e g . g e t E m a i l ()+ ” \ ’ ” ;
29 i n t i n r e g I d=i n r e g . g e t I d ( ) ;
30 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 ( ) ;
31 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
32 S t r i n g s q l=”UPDATE Adrese e n t i t y SET e n t i t y . nume=”+nume+
33 ” , e n t i t y . e m a i l=”+e m a i l+” WHERE e n t i t y . i d=”+i n r e g I d ;
34 Query query=em . c r e a t e Q u e r y ( s q l ) ;
35 query . e x e c u t e U p d a t e ( ) ;
36 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
37 em . c l o s e ( ) ;
38 }

40 p u b l i c Adrese r e a d A d r e s e ( i n t i n r e g I d ) {
41 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 ( ) ;
42 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
43 S t r i n g s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . i d=”+i n r e g I d ;
44 Query query=em . c r e a t e Q u e r y ( s q l ) ;
45 Adrese i n r e g =( Adrese ) query . g e t S i n g l e R e s u l t ( ) ;
46 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
47 em . c l o s e ( ) ;
48 return inreg ;
49 }

51 public void deleteAdrese ( i n t i n r e g I d ){


52 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 ( ) ;
53 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
54 S t r i n g s q l=”DELETE FROM Adrese e n t i t y WHERE e n t i t y . i d=”+i n r e g I d ;
B.8. JAVA PERSISTENCE API - JPA 299

55 Query query=em . c r e a t e Q u e r y ( s q l ) ;
56 query . e x e c u t e U p d a t e ( ) ;
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 }

61 p u b l i c L i s t<Adrese> s e a r c h A d r e s e ( S e a r c h C r i t e r i a s e a r c h C r i t e r i a ) {
62 S t r i n g nume=s e a r c h C r i t e r i a . getNume ( ) ;
63 S t r i n g e m a i l=s e a r c h C r i t e r i a . g e t E m a i l ( ) ;
64 S t r i n g searchSQL ;
65 i f ( nume==n u l l ) {
66 searchSQL=” e n t i t y . e m a i l =\ ’ ”+e m a i l+” \ ’ ” ;
67 }
68 else{
69 searchSQL=” e n t i t y . nume=\ ’ ”+nume+” \ ’ ” ;
70 }
71 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 ( ) ;
72 em . g e t T r a n s a c t i o n ( ) . b e g i n ( ) ;
73 S t r i n g s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE ”+searchSQL ;
74 System . out . p r i n t l n ( s q l ) ;
75 Query query=em . c r e a t e Q u e r y ( s q l ) ;
76 L i s t<Adrese> l i s t =( L i s t<Adrese>) query . g e t R e s u l t L i s t ( ) ;
77 em . g e t T r a n s a c t i o n ( ) . commit ( ) ;
78 em . c l o s e ( ) ;
79 return l i s t ;
80 }
81 }

Programul client este acelaşi cu cel utilizat anterior (AgendaEClient). iar clientul
este AgendaTClient
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>agendae . dao . Adrese</ c l a s s>
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=” agendae ” t r a n s a c t i o n −t y p e=”RESOURCE LOCAL”>


11 < c l a s s>agendae . dao . Adrese</ 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>

Structura desfăşurată a aplicaţiei este


agendae
|--> dao
| | *.class
| AgendaEClient.class
META-INF
| persistence.xml

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 ”>
300 APPENDIX B. UTILIZAREA SGBD ÎN JAVA

3 <p r o p e r t y name=” package ” v a l u e=” agendae ” />


4 <p r o p e r t y name=”dbname” v a l u e=” AgendaEMail ” />
5 <p r o p e r t y name=” c l a s s n a m e ” v a l u e=” AgendaEClient ” />
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 < !−− 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 −−>

10 <p r o p e r t y name=” d b d r i v e r ”
11 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 ” />
12 <p r o p e r t y name=” d b u r l ”
13 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} ” />

15 < !−−
16 <p r o p e r t y name=” d b d r i v e r ”
17 v a l u e=”com . mysql . j d b c . 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 : m y s q l : // l o c a l h o s t : 3 3 0 6 / AgendaEMail ? u s e r=r o o t ” />
20 −−>

22 <p r o p e r t y name=” d b u s e r ” v a l u e=” ” />


23 <p r o p e r t y name=” dbpass ” v a l u e=” ” />

25 <path i d=” c l a s s p a t h ” >


26 <p a t h e l e m e n t path=” ${ b u i l d . d i r } ” />
27 < f i l e s e t d i r=” ${ o p e n j p a }/ l i b ”>
28 <i n c l u d e name=” ∗ . j a r ” />
29 </ f i l e s e t>
30 < f i l e s e t d i r=” l i b ”>
31 <i n c l u d e name=” ∗ . j a r ” />
32 </ f i l e s e t>
33 </ path>

35 <path i d=” j a v a a g e n t ”>


36 < f i l e s e t d i r=” ${ o p e n j p a } ”>
37 <i n c l u d e name=” openjpa −∗. j a r ” />
38 </ f i l e s e t>
39 </ path>
40 <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 ” />

42 <t a r g e t name=” i n i t ”>


43 <d e l e t e d i r=” b u i l d ” />
44 <mkdir d i r=” ${ b u i l d . d i r } ” />
45 </ t a r g e t>

47 <t a r g e t name=” c o m p i l e ” depends=” i n i t ”>


48 <j a v a c s r c d i r=” s r c ” c l a s s p a t h r e f=” c l a s s p a t h ”
49 d e s t d i r=” ${ b u i l d . d i r } ”
50 i n c l u d e a n t r u n t i m e=” f a l s e ” debug=” y e s ” />
51 </ t a r g e t>

53 <t a r g e t name=” run ” depends=” c o m p i l e ”>


54 <mkdir d i r=” ${ b u i l d . d i r }/META−INF” />
55 <copy t o d i r=” ${ b u i l d . d i r }/META−INF” f i l e =”META−INF/ p e r s i s t e n c e . xml” />
56 <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 ”
57 f o r k=” y e s ” f a i l o n e r r o r=” y e s ”>
58 < !−−
59 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
60 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 .
61 −−>
B.8. JAVA PERSISTENCE API - JPA 301

62 <jvmarg v a l u e=”−j a v a a g e n t : ${ j a v a a g e n t } ” />

64 < !−−
65 S p e c i f y t h e sy s te m 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
66 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
67 packages , the c a l l to ” P e r s i s t e n c e . createEntityManagerFactory ”
68 i s p a s s e d ” System . g e t P r o p e r t i e s ( ) ” .
69 −−>

71 < !−−
72 By default , u s e t h e stand −a l o n e Derby d a t a b a s e ( p r o v i d e d ) .
73 This can e a s i l y be c h a n g e s t o u s e your own d a t a b a s e ’ s d r i v e r ,
74 p r o v i d e d you e n s u r e i t i s a c c e s s i b l e i n t h e c l a s s p a t h .
75 −−>
76 <s y s p r o p e r t y key=”o p e n j p a . ConnectionDriverName ”
77 v a l u e =”${ d b d r i v e r }”/>
78 <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 }”/>
79 <!−−
80 <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 }”/>
81 <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 }”/>
82 −−>
83 <!−−
84 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
85 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
86 r u n n i n g 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
87 don ’ t want t o be a l t e r i n g t h e schema a t runtime .
88 −−>
89 <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 ”
90 v a l u e=” buildSchema ” />

92 < !−−
93 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 , b u t s e t t h e
94 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 .
95 −−>
96 <s y s p r o p e r t y key=” o p e n j p a . Log”
97 v a l u e=” D e f a u l t L e v e l=WARN, SQL=TRACE” />
98 </ j a v a>
99 </ t a r g e t>
100 </ p r o j e c t>
302 APPENDIX B. 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.

303

S-ar putea să vă placă și