14.06.2013 Views

Universitatea Transilvania din Brasov Facultatea de Matematic˘a ...

Universitatea Transilvania din Brasov Facultatea de Matematic˘a ...

Universitatea Transilvania din Brasov Facultatea de Matematic˘a ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Universitatea</strong> <strong>Transilvania</strong> <strong>din</strong> Bra¸sov<br />

<strong>Facultatea</strong> <strong>de</strong> Matematică–Informatică<br />

Catedra <strong>de</strong> Informatică Teoretică<br />

ERNEST SCHEIBER<br />

PROGRAMARE DISTRIBUITĂ ÎN<br />

JAVA<br />

Bra¸sov


Introducere<br />

Ret¸elele locale, internetul, răspândirea pe o arie geografică a resurselor ¸si a<br />

locat¸iilor în care se petrec act¸iuni ce t¸in <strong>de</strong> o activitate bine <strong>de</strong>finită sau sunt<br />

urmărite, gestionate <strong>din</strong> alte locuri au drept consecint¸ă existent¸a aplicat¸iilor<br />

distribuite. Termenul distribuit se referă tocmai la faptul că componente ale<br />

aplicat¸iei se află pe calculatoare diferite dar între care au loc schimburi <strong>de</strong> date.<br />

Dacă părt¸ile unei aplicat¸ii sau resursele utilizate se găsesc pe calculatoare distincte<br />

atunci aplicat¸ia se nume¸ste distribuită.<br />

Între părt¸ile sau resursele unei aplicat¸ii distribuite au loc schimburi <strong>de</strong> date,<br />

ceea ce se face utilizând diferite mecanisme la realizarea cărora concură sistemul<br />

<strong>de</strong> calcul, sistemul <strong>de</strong> operare ¸si limbajul <strong>de</strong> programare.<br />

Astfel se vorbe¸ste <strong>de</strong> programare distribuită ca mijloc <strong>de</strong> realizare a aplicat¸iilor<br />

distribuite. Pe lângă algoritm, structuri <strong>de</strong> date, limbaj <strong>de</strong> programare, la realizarea<br />

unei aplicat¸ii distribuite intervin comunicat¸iile: schimbul <strong>de</strong> date <strong>din</strong>tre<br />

două componente aflate pe calculatoare diferite.<br />

Punem în evi<strong>de</strong>nt¸ă două mo<strong>de</strong>le <strong>de</strong> aplicat¸ii distribuite:<br />

• client-server: Programul server execută cererile client¸ilor. Amintim următoarele<br />

tehnologii Java pentru realizarea aplicat¸iilor client-server:<br />

– RMI (Remote Method Invocation)<br />

– CORBA (Common Object Request Brocker Arhitecture)<br />

– JMS (Java Message Service)<br />

– Servlet ¸si JSP (Java Server Pages)<br />

– Portlet<br />

• dispecer-lucrător: Programul dispecer distribuie sarcinile <strong>de</strong> executat<br />

lucrătorilor ¸si le coordonează activitatea. Pentru programarea unei aplicat¸ii<br />

bazată pe mo<strong>de</strong>lul dispecer-lucrător se poate utiliza<br />

– un soft ce implementează una <strong>din</strong> interfet¸ele:<br />

∗ PVM (Parallel Virtual Machine)<br />

∗ MPI (Message Passing Interface)<br />

3


4<br />

∗ BSP (Bulk Synchronous Parallel)<br />

– produse bazate pe mo<strong>de</strong>lul Linda:<br />

∗ TSpaces<br />

∗ JavaSpaces cont¸inut în jini.<br />

– Alte abordări:<br />

∗ Java Parallel Distribute Framework (JPPF);<br />

∗ Terracotta;<br />

∗ ProActive.<br />

Lista opt¸iunilor este <strong>de</strong>parte <strong>de</strong> a fi completă.<br />

Scopul acestui curs este prezentarea tehnologiilor <strong>de</strong> programare Java care<br />

permit programarea aplicat¸iilor client - server:<br />

• socluri Java;<br />

• apelarea meto<strong>de</strong>lor <strong>de</strong> la distant¸ă (Remote Method Invocation - RMI );<br />

• CORBA - Common Object Request Brocker Arhitecture;<br />

• mesageria Java;<br />

• servlet;<br />

• Java Server Pages - JSP;<br />

• Portlet ¸si Portal.<br />

Meto<strong>de</strong>le ¸si instrumentele <strong>de</strong> programare vor fi exemplificate pe problema<br />

foarte simplă <strong>de</strong> calcul a celui mai mare divizor comun a două numere naturale.<br />

Codul meto<strong>de</strong>i <strong>de</strong> calcul este<br />

public long cmmdc(long m,long n){<br />

long r,c;<br />

do{<br />

c=n;<br />

r=m%n;<br />

m=n;<br />

n=r;<br />

}<br />

while(r!=0);<br />

return c;<br />

}<br />

Pentru aplicat¸iile care utilizează o bază <strong>de</strong> date, sistemul <strong>de</strong> gestiune a bazei<br />

<strong>de</strong> date (SGBD) va fi una <strong>din</strong>tre sistemele Derby, mysql sau postgresql.


Cuprins<br />

1 Miniaplicat¸ie (applet) 9<br />

1.1 Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

2 Programare cu socluri Java 15<br />

2.1 Aplicat¸ii client – server . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

2.2 Not¸iuni <strong>de</strong>spre ret¸ele . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.3 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.3.1 Clasa Socket . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

2.3.2 Clasa ServerSocket . . . . . . . . . . . . . . . . . . . . . . 17<br />

2.4 Aplicat¸ie client – server cu socluri . . . . . . . . . . . . . . . . . . 18<br />

2.5 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

2.5.1 Clasa DatagramPacket. . . . . . . . . . . . . . . . . . . . . 22<br />

2.5.2 Clasa DatagramSocket . . . . . . . . . . . . . . . . . . . . . 23<br />

2.5.3 Clasa InetAddress . . . . . . . . . . . . . . . . . . . . . . . 25<br />

2.5.4 Aplicat¸ii client – server cu datagrame. . . . . . . . . . . . . 27<br />

2.5.5 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . . . 30<br />

2.6 Canale <strong>de</strong> comunicat¸ie . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

2.6.1 Clasa Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

2.6.2 Clasa ByteBuffer . . . . . . . . . . . . . . . . . . . . . . . 34<br />

2.6.3 Clasa InetSocketAddress . . . . . . . . . . . . . . . . . . . 35<br />

2.6.4 Clasa ServerSocketChannel . . . . . . . . . . . . . . . . . 35<br />

2.6.5 Clasa SocketChannel . . . . . . . . . . . . . . . . . . . . . 36<br />

2.7 Conexiuni HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

3 Programare distribuită cu RMI 41<br />

3.1 Structura RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41<br />

3.2 Crearea unei aplicat¸ii RMI . . . . . . . . . . . . . . . . . . . . . . . 44<br />

3.3 Tipare <strong>de</strong> programare . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

3.3.1 Fabrica <strong>de</strong> obiecte . . . . . . . . . . . . . . . . . . . . . . . 48<br />

3.3.2 Apeluri inverse – Callback . . . . . . . . . . . . . . . . . . . 51<br />

3.4 Obiecte activabile la distant¸ă . . . . . . . . . . . . . . . . . . . . . 53<br />

5


6 CUPRINS<br />

3.5 RMI ¸si sistemul CORBA . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

3.6 RMI-IIOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

3.6.1 Transformarea într-un program RMI-IIOP . . . . . . . . . . 59<br />

4 Programare distribuită prin CORBA 65<br />

4.1 Sistemul CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />

4.2 Aplicat¸ie Java distribuită prin CORBA . . . . . . . . . . . . . . . 65<br />

4.2.1 Mo<strong>de</strong>l cu server temporal . . . . . . . . . . . . . . . . . . . 65<br />

4.2.2 Mo<strong>de</strong>l cu server persistent . . . . . . . . . . . . . . . . . . . 69<br />

5 Mesaje în Java 73<br />

5.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . . . 73<br />

5.2 Sun Java System Message Queue . . . . . . . . . . . . . . . . . . . 74<br />

5.3 Apache ActiveMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

5.4 Elemente <strong>de</strong> programare - JMS . . . . . . . . . . . . . . . . . . . . 76<br />

5.4.1 Trimiterea unui mesaj . . . . . . . . . . . . . . . . . . . . . 76<br />

5.4.2 Recept¸ia sincronă a unui mesaj . . . . . . . . . . . . . . . . 81<br />

5.4.3 Recept¸ia asincronă a unui mesaj . . . . . . . . . . . . . . . 82<br />

5.4.4 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . . . 84<br />

5.4.5 Subscrierea ¸si recept¸ia mesajelor . . . . . . . . . . . . . . . 85<br />

5.5 Mesaje SOAP prin Java Message Service . . . . . . . . . . . . . . . 87<br />

5.5.1 SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />

5.5.2 Mesaje SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />

5.5.3 Ata¸samente SOAP . . . . . . . . . . . . . . . . . . . . . . . 94<br />

6 Servlet 101<br />

6.1 Marcajul . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

6.2 Server Web - container <strong>de</strong> servlet . . . . . . . . . . . . . . . . . . . 103<br />

6.3 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />

6.3.1 Instalarea unui servlet . . . . . . . . . . . . . . . . . . . . . 104<br />

6.3.2 Compilarea ¸si apelarea unui servlet . . . . . . . . . . . . . . 106<br />

6.3.3 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . . . 107<br />

6.4 Facilităt¸i <strong>de</strong> programare cu servlet . . . . . . . . . . . . . . . . . . 113<br />

6.4.1 Program client al unui servlet . . . . . . . . . . . . . . . . . 113<br />

6.4.2 Servlete înlănt¸uite . . . . . . . . . . . . . . . . . . . . . . . 116<br />

6.4.3 Sesiune <strong>de</strong> lucru . . . . . . . . . . . . . . . . . . . . . . . . 117<br />

6.4.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119<br />

6.4.5 Autorizarea accesului prin parola . . . . . . . . . . . . . . . 121<br />

6.4.6 Servlet cu conexiune la o bază <strong>de</strong> date . . . . . . . . . . . . 122<br />

6.4.7 Imagini furnizate <strong>de</strong> servlet . . . . . . . . . . . . . . . . . . 125<br />

6.4.8 Servlet cu RMI . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

6.5 FileUpload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128


CUPRINS 7<br />

7 Java Server Page – JSP 133<br />

7.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />

7.1.1 Declarat¸ii JSP . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />

7.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 139<br />

7.1.3 Marcaje JSP pre<strong>de</strong>finite . . . . . . . . . . . . . . . . . . . . 139<br />

7.1.4 Componentă Java (Java Bean) . . . . . . . . . . . . . . . . 140<br />

7.1.5 Pagini JSP cu componente Java . . . . . . . . . . . . . . . 141<br />

7.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . . . 144<br />

7.2.1 Biblioteca <strong>de</strong> bază . . . . . . . . . . . . . . . . . . . . . . . 145<br />

7.2.2 Biblioteca <strong>de</strong> lucru cu baze <strong>de</strong> date . . . . . . . . . . . . . . 150<br />

7.3 Marcaje JSP personale . . . . . . . . . . . . . . . . . . . . . . . . . 151<br />

7.3.1 Marcaje fără atribute ¸si fără corp. . . . . . . . . . . . . . . 151<br />

7.3.2 Marcaje cu atribute ¸si fără corp. . . . . . . . . . . . . . . . 154<br />

7.3.3 Marcaje cu corp. . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

8 Portlet 159<br />

8.1 Apache-pluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161<br />

8.2 Portlet container JSR 286 . . . . . . . . . . . . . . . . . . . . . . . 162<br />

8.3 Dezvoltarea unui portlet . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

8.4 Elemente <strong>de</strong> programare . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

8.5 Produse Portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />

8.5.1 uPortal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176<br />

8.5.2 Jetspeed-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179<br />

9 Teme <strong>de</strong> laborator 181<br />

9.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181<br />

A XML 191<br />

B Apache-ant 193<br />

C Utilizarea SGBD în Java 195<br />

C.1 Derby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

C.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196<br />

C.3 PostgrSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />

C.4 S¸ablonul <strong>de</strong> utilizare într-un program Java . . . . . . . . . . . . . . 198<br />

C.5 Java Persistence API - JPA . . . . . . . . . . . . . . . . . . . . . . 202<br />

C.5.1 apache-openjpa . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />

Bibliografie 211


8 CUPRINS


Capitolul 1<br />

Miniaplicat¸ie (applet)<br />

O categorie <strong>de</strong>osebită <strong>de</strong> programe Java îl reprezintă miniaplicat¸iile (appleturi),<br />

care se execută prin intermediul unui program <strong>de</strong> navigare în WWW (World<br />

Wi<strong>de</strong> Web) – browser. Navigatoarele uzuale <strong>de</strong> WWW (Firefox, Microsoft Internet<br />

Explorer, Opera) ¸stiu Java, în sensul că pot executa codul compilat al unui<br />

applet.<br />

Astfel, applet-ul este o resursă <strong>de</strong>pusă într-o zona publică, accesibilă prin Internet.<br />

Un program <strong>de</strong> navigare preia codul applet-ului ¸si îl execută. Apelarea<br />

unui applet se face <strong>din</strong>tr-un fi¸sier html. Acest ansamblu (clasa Java cu documentul<br />

html <strong>de</strong> apelare) formează miniaplicat¸ia.<br />

Datorită acestui mod <strong>de</strong> folosire, applet-urile au o structură specială ¸si sunt<br />

supuse la reguli stricte <strong>de</strong> securitate : nu pot scrie informat¸ii pe calculatorul pe<br />

care se execută.<br />

Distribut¸ia jdk (Java Development Kit) cont¸ine un program appletviewer cu<br />

ajutorul căruia se pot executa pe calculatorul propriu miniaplicat¸iile. Utilizarea<br />

acestui program este<br />

appletviewer numeFi¸sier html<br />

un<strong>de</strong> numeFi¸sier este fi¸sierul html care apelează applet-ul.<br />

Elementul applet <strong>din</strong> HTML<br />

Un program <strong>de</strong> navigare în WWW interpretează cont¸inutul (textul) unui fi¸sier<br />

html (Hyper Text Markup Language) ¸si-l redă.<br />

Limbajul HTML constă <strong>din</strong>tr-o colectie <strong>de</strong> elemente (marcaje, ancore, taguri)<br />

inserate într-un text ASCII (American Standard Co<strong>de</strong>s for Information Interchange).<br />

Elementele au rolul <strong>de</strong> a <strong>de</strong>scrie modul în care va apărea afi¸sat textul, <strong>de</strong><br />

asemenea pot comanda programul <strong>de</strong> navigare să utilizeze ¸si alte resurse Internet,<br />

aflate în fi¸siere diferite, în particular codul compilat al unui applet.<br />

9


10 CAPITOLUL 1. MINIAPLICAT¸ IE (APPLET)<br />

Sintaxa unui element html este<br />

<br />

<br />

text<br />

Element ∗<br />

Un atribut se scrie sub forma: NumeAtribut = valoare<br />

Structura unui document html este<br />

<br />

<br />

<br />

titlul documentului<br />

<br />

<br />

<br />

corpul documentului<br />

<br />

<br />

<br />

<br />

Elementul . Atributele obligatorii ale unui element applet sunt<br />

• co<strong>de</strong><br />

Valoarea atributului este numele clasei applet-ului.<br />

• width<br />

Valoarea atributului este lăt¸imea ferestrei atribuită <strong>de</strong> navigator applet-ului<br />

la afi¸sarea documentului html.<br />

• height<br />

Valoarea atributului este înălt¸imea ferestrei atribuită <strong>de</strong> navigator appletului<br />

la afi¸sarea documentului html.<br />

Atribute opt¸ionale sunt<br />

• co<strong>de</strong>base<br />

Valoarea atributului este adresa URL ( Universal Resource Locator) sau<br />

calea la fi¸sierul cu clasa applet-ului. În lipsa acestui parametru, căutarea<br />

clasei are loc în catalogul <strong>din</strong> care a fost încărcată sursa html.<br />

• vspace<br />

Valoarea atributului este lungimea, exprimată în pixeli, care se lasă liberă<br />

<strong>de</strong>asupra ¸si <strong>de</strong><strong>de</strong>suptul ferestrei miniaplicat¸iei.


1.1. APPLET 11<br />

• hspace<br />

Valoarea parametrului este lungimea, exprimată în pixeli, care se lasă liberă<br />

la stânga ¸si la dreapta ferestrei applet-ului.<br />

În marcajul prin intermediul elementului pot fi inclu¸si<br />

parametri ce pot fi preluat¸i <strong>de</strong> applet. Un parametru se <strong>de</strong>fine¸ste prin atributele:<br />

• name<br />

Valoarea atributului este numele variabilei recunoscut în applet.<br />

• value<br />

Valoarea atributului este valoarea recept¸ionat <strong>de</strong> applet ¸si este <strong>de</strong> tip String.<br />

Preluarea se realizează cu metoda<br />

1.1 Applet<br />

public String getParameter(String name)<br />

Clasa Applet extin<strong>de</strong> clasa java.awt.Panel.<br />

Structura unui applet este<br />

import java.applet.*;<br />

import java.awt.*;<br />

public classNumeClasă extends Applet{<br />

public void init(){<br />

Act¸iuni efectuate la instant¸ierea clasei applet-ului.<br />

}<br />

public void start(){<br />

Act¸iuni efectuate la lansarea applet-ului în execut¸ie sau la<br />

reîntoarcerea în pagina applet-ului.<br />

}<br />

public void paint(Graphics g){<br />

Act¸iuni efectuate ori <strong>de</strong> câte ori este necesară re<strong>de</strong>senarea<br />

ferestrei applet-ului.<br />

}<br />

public void stop(){<br />

Act¸iuni efectuate la oprirea applet-ului, ca urmare a<br />

închi<strong>de</strong>rii ferestrei corespunzătoare applet-ului.<br />

}<br />

public void <strong>de</strong>stroy(){<br />

Act¸iuni efectuate la distrugerea applet-ului, ce au loc când<br />

navigatorul părăse¸ste documentul html <strong>din</strong> care s-a apelat<br />

applet-ul.


12 CAPITOLUL 1. MINIAPLICAT¸ IE (APPLET)<br />

}<br />

}<br />

Executarea applet-ului <strong>de</strong> către programul navigator revine la apelarea meto<strong>de</strong>lor<br />

init, start, stop.<br />

Astfel controlul asupra applet-ului este <strong>de</strong>t¸inut <strong>de</strong> programul navigator. Acest<br />

fenomen se nume¸ste inversarea controlului.<br />

Dacă fi¸sierul class al applet-ului nu se află în acela¸si catalog cu documentul<br />

html atunci localizarea clasei se face cu valoarea atributului co<strong>de</strong>base =<br />

"file://host/calea către catalogul clasei applet-ului"<br />

Observat¸ie 1.1.1<br />

Elementul applet activează ma¸sina virtuală Java utilizată <strong>de</strong> programul navigator.<br />

Această ma¸sină virtuală s-ar putea să nu fie compatibilă cu ma¸sina virtuală<br />

Java <strong>de</strong> la Sun. Dacă pe calculatorul clientului este instalat Java atunci<br />

documentul html se poate converti astfel încât execut¸ia applet-ului să fie executată<br />

<strong>de</strong> ma¸sina virtuală Java a distribut¸iei jdk. Convertirea se face cu utilitarul<br />

HtmlConverter, <strong>din</strong> distribut¸ia jdk.<br />

Exemplul 1.1.1 Miniaplicat¸ia HelloWorld.<br />

1. HelloWorld. Codul applet-ului este:<br />

import java.awt.*;<br />

import java.applet.*;<br />

public class Inceput extends Applet{<br />

public void init(){}<br />

public void paint(Graphics g){<br />

g.drawString("Hello World !!", 50, 60 );<br />

}<br />

}<br />

Documentul html <strong>de</strong> apelare este:<br />

<br />

<br />

Hello <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


1.1. APPLET 13<br />

2. Exemplul 1.1.2 Calculul celui mai mare divizor comun a două naturale.<br />

Codul sursă este:<br />

import java.awt.*;<br />

import java.applet.*;<br />

import java.awt.event.*;<br />

public class Cmmdc extends Applet implements ActionListener{<br />

TextField tm,tn,rez;<br />

public void init(){<br />

setBackground(Color.yellow);<br />

GridLayout gl=new GridLayout(3,2,30,20);<br />

setLayout(gl);<br />

Label lm=new Label("Primul numar:");<br />

add(lm);<br />

tm=new TextField("1",5);<br />

add(tm);<br />

Label ln=new Label("Al doilea numar:");<br />

add(ln);<br />

tn=new TextField("1",5);<br />

add(tn);<br />

Button compute=new Button("Calculeaza");<br />

compute.addActionListener(this);<br />

add(compute);<br />

rez=new TextField("1",5);<br />

rez.setEditable(false);<br />

add(rez);<br />

}<br />

public void paint(Graphics g){<br />

String sm=tm.getText();<br />

long m=Long.parseLong(sm);<br />

String sn=tn.getText();<br />

long n=Long.parseLong(sn);<br />

long c=cmmdc(m,n);<br />

rez.setText((new Long(c)).toString());<br />

}<br />

public void actionPerformed(ActionEvent ae){<br />

repaint();<br />

}<br />

long cmmdc(long m, long n){. . .}<br />

}<br />

Documentul html corespunzător este:<br />

<br />

<br />

<br />

<br />


14 CAPITOLUL 1. MINIAPLICAT¸ IE (APPLET)<br />

<br />

<br />

<br />

Să se ruleze miniaplicat¸ia în mediu distribuit, adica apelarea prin intermediul<br />

navigatorului, fi¸sierul html ¸si fi¸sierul Cmmdc.class sunt pe trei calculatoare<br />

diferite.


Capitolul 2<br />

Programare cu socluri Java<br />

Limbajul <strong>de</strong> programare Java oferă facilităt¸i <strong>de</strong> elaborare ale unor programe<br />

care utilizează ¸si interact¸ionează cu resurse <strong>din</strong> Internet ¸si <strong>din</strong> World Wi<strong>de</strong> Web.<br />

În plus limbajul Java permite utilizarea URL-ului (Universal Resource Locator<br />

– adresa resurselor în Internet), a soclurilor (socket) ¸si a datagramelor.<br />

2.1 Aplicat¸ii client – server<br />

O aplicat¸ie client – server se compune <strong>din</strong>:<br />

• componenta server - alcătuită <strong>din</strong> programe / clase ce asigură una sau mai<br />

multe funct¸iuni (servicii), care pot fi apelate <strong>de</strong> către client¸i.<br />

• componenta client - alcătuită <strong>din</strong> programe / clase care permit accesul la<br />

server ¸si apelarea serviciilor acestuia.<br />

Serverul ¸si clientul (client¸ii) rulează, <strong>de</strong> obicei, pe calculatoare distincte. Un<br />

server trebuie să satisfacă cererile mai multor client¸i.<br />

Durata <strong>de</strong> viat¸ă a unei aplicat¸ii client – server este dată <strong>de</strong> durata funct¸ionării<br />

serverului. Această durată poate fi alcătuită <strong>din</strong> intervale disjuncte <strong>de</strong> timp, între<br />

acele intervale, <strong>din</strong> diverse motive, serverul este inactiv.<br />

Intervalul <strong>de</strong> timp <strong>de</strong>terminat <strong>de</strong> conectarea unui client la server ¸si până la<br />

<strong>de</strong>conectare poartă numele <strong>de</strong> sesiune.<br />

În această perioadă, clientul poate invoca<br />

mai multe servicii ale serverului. Un client poate init¸ia mai multe sesiuni.<br />

Un client trebuie să-¸si regăsească datele în cadrul unei sesiuni, între sesiuni,<br />

pe toată durata <strong>de</strong> viat¸ă a aplicat¸iei. Astfel se pune problema ret¸inerii datelor<br />

pentru fiecare client în parte.<br />

15


16 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

Autentificare ¸si autorizare<br />

Uzual, pentru a folosi serviciul unui server, un client trebuie să se înregistreze,<br />

moment în care i se stabilesc drepturile <strong>de</strong> care dispune la utilizarea serviciilor<br />

oferite <strong>de</strong> server.<br />

La apelarea serverului, clientul este autentificat - adică i se recunoa¸ste i<strong>de</strong>ntitatea<br />

- ¸si apoi i se asigură accesul la servicii în limita drepturilor pe care le<br />

are.<br />

2.2 Not¸iuni <strong>de</strong>spre ret¸ele<br />

Calculatoarele ce rulează în Internet comunică între ele folosind protocolul<br />

TCP (Transport Control Protocol) sau UDP (User Datagram Protocol).<br />

Într-un program Java se utilizează clasele pachetului java.net prin intermediul<br />

cărora se accesează nivelele <strong>de</strong>servite <strong>de</strong> protocoalele TCP sau UDP. În<br />

felul acesta se pot realiza comunicat¸ii in<strong>de</strong>pen<strong>de</strong>nte <strong>de</strong> platforma <strong>de</strong> calcul. Pentru<br />

a alege care clasă Java să fie utilizată trebuie cunoscută diferent¸a <strong>din</strong>tre TCP<br />

¸si UDP.<br />

TCP Când două aplicat¸ii comunică între ele se stabile¸ste o conexiune prin<br />

intermediul căreia se schimbă date. Folosind protocolul TCP, comunicat¸ia garantează<br />

că datele trimise <strong>din</strong>tr-un capăt ajung în celălalt capăt cu păstrarea or<strong>din</strong>ii<br />

în care au fost trimise. Acest tip <strong>de</strong> comunicat¸ie seamănă cu o convorbire telefonică.<br />

TCP furnizează un canal sigur <strong>de</strong> comunicat¸ie între aplicat¸ii.<br />

UDP Utilizarea protocolului UDP presupune trimiterea unor pachete <strong>de</strong> date<br />

– numite datagrame – <strong>de</strong> la o aplicat¸ie la alta fără să se asigure faptul că datagrameleajung<br />

la <strong>de</strong>stinat¸ie ¸si nici or<strong>din</strong>ea lor <strong>de</strong> sosire. Acest tip <strong>de</strong> comunicat¸ie<br />

seamănă cu trimiterea scrisorilor prin po¸stă.<br />

2.3 Soclu TCP<br />

Conexiunile bazate pe URL reprezintă un mecanism <strong>de</strong> nivel înalt pentru<br />

accesarea resurselor <strong>din</strong> Internet.<br />

Aplicat¸ii <strong>de</strong> tip client – server se pot realiza utilizând comunicat¸ii <strong>de</strong> nivel<br />

scăzut. Pentru a comunica utilizând TCP programul client ¸si programul server<br />

stabilesc o conexiune sigură. Fiecare program se leagă la conexiune printr-un<br />

soclu (socket). Un soclu este capătul unei căi <strong>de</strong> comunicat¸ie bidirect¸ional între<br />

două programe ce rulează în ret¸ea. Un soclu este legat <strong>de</strong> un port – prin care<br />

nivelul TCP poate i<strong>de</strong>ntifica aplicat¸ia căreia îi sunt transmise datele. Din punct<br />

<strong>de</strong> ve<strong>de</strong>re fizic, un port este o adresă <strong>de</strong> memorie cuprinsă între 0 ¸si 65535.


2.3. SOCLU TCP 17<br />

Pentru a comunica atât clientul cât ¸si serverul citesc date <strong>de</strong> la ¸si scriu date<br />

la soclul legat la conexiunea <strong>din</strong>tre ele.<br />

În pachetul java.net clasele Socket ¸si ServerSocket implementează un soclu<br />

<strong>din</strong> partea clientului ¸si respectiv <strong>din</strong> partea serverului.<br />

Clientul cunoa¸ste numele calculatorului pe care rulează serverul cât ¸si portul<br />

la care acesta este conectat. Pentru stabilirea conexiunii, clientul încearcă un<br />

ren<strong>de</strong>z-vous cu serverul <strong>de</strong> pe ma¸sina serverului ¸si la portul serverului. Dacă<br />

totul <strong>de</strong>curge bine, serverul acceptă conexiunea. După acceptare, serverul crează<br />

pentru client un nou soclu legat la un alt port în a¸sa fel încât ascultarea cererilor<br />

la soclul init¸ial să poată continua în timp ce sunt satisfăcute cererile clientului<br />

conectat. Din partea clientului, după acceptarea conexiunii soclul este creat ¸si<br />

este utilizat pentru comunicat¸ia cu serverul.<br />

2.3.1 Clasa Socket<br />

Resursele clasei Socket sunt <strong>de</strong>stinate clientului.<br />

Constructori<br />

• public Socket(String host, int port) throws UnknownHostException,<br />

IOException<br />

Crează un soclu conectat la calculatorul cu portul specificat.<br />

• public Socket(InetAddress host, int port) throws IOException<br />

Crează un soclu conectat la calculatorul cu portul specificat.<br />

Meto<strong>de</strong><br />

• public InputStream getInputStream() throws IOException<br />

Returnează un flux <strong>de</strong> intrare ata¸st soclului, pentru citirea (preluarea)<br />

informat¸iilor <strong>de</strong> la soclu.<br />

• public OutputStream getOutputStream() throws IOException<br />

Returnează un flux <strong>de</strong> ie¸sire ata¸st soclului, pentru scrierea (transmiterea)<br />

informat¸iilor la soclu.<br />

• public synchronized void close() throws IOException<br />

închi<strong>de</strong> soclul <strong>de</strong> referint¸ă.<br />

2.3.2 Clasa ServerSocket<br />

Resursele clasei ServerSocket sunt <strong>de</strong>stinate serverului.<br />

Constructori


18 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

• public ServerSocket(int port) throws IOException<br />

Crează un soclu la portul specificat. Dacă port=0, atunci va fi utilizat<br />

orice port disponibil. Capacitatea ¸sirului (tamponului) <strong>de</strong> a¸steptare pentru<br />

cererile <strong>de</strong> conectare se fizează la valoarea implicită 50. Cererile în exces<br />

vor fi refuzate.<br />

• public ServerSocket(int port, int lung) throws IOException<br />

În plus fixează lungimea ¸sirului (tamponului) <strong>de</strong> a¸steptare.<br />

• public ServerSocket(int port, int lung, InetAddress adr)<br />

throws IOException<br />

Se specifică în plus calculatorul <strong>de</strong> la care se a¸steaptă cereri. Dacă adr=null,<br />

atunci se acceptă cereri <strong>de</strong> la orice calculator.<br />

Meto<strong>de</strong><br />

• public Socket accept() throws IOException<br />

Metoda blochează procesul (firul <strong>de</strong> execut¸ie) apelant până la sosirea unei<br />

cereri <strong>de</strong> conectare ¸si crează un soclu client prin care se va <strong>de</strong>sfă¸sura comunicarea<br />

cu solicitantul acceptat.<br />

• public synchronized void close() throws IOException<br />

închi<strong>de</strong> soclul <strong>de</strong> referint¸ă.<br />

2.4 Aplicat¸ie client – server cu socluri<br />

Serverul trebuie să satisfacă simultan solicitările mai multor client¸i. Fiecare<br />

client apelează programul server la acela¸si port ¸si în consecint¸ă cererile <strong>de</strong> conectare<br />

sunt recept¸ionate <strong>de</strong> acela¸si ServerSocket. Serverul recept¸ionează apelurile secvent¸ial.<br />

La un apel, se crează <strong>de</strong> partea severului un soclu prin care se va face schimbul<br />

<strong>de</strong> date cu clientul. Cererile client¸ilor pot fi satisface concurent/paralel, utilizând<br />

fire <strong>de</strong> execut¸ie ce implementează serviciul oferit sau secvent¸ial - în cazul unor<br />

servicii <strong>de</strong> durată scurtă.<br />

Exemplul 2.4.1 Sistem client - server pentru calculul celui mai mare divizor<br />

comun a două numere naturale. Portul obiectului <strong>de</strong> tip ServerSocket este 7999.<br />

Programul client CmmdcClient se conectează la server, transmite serverului<br />

cele două numere naturale ¸si recept¸ionează rezultatul pe care apoi îl afi¸sează.<br />

În esent¸ă orice program client trebuie să execute:<br />

1. Deschi<strong>de</strong>/crează un soclu.


2.4. APLICAT¸ IE CLIENT – SERVER CU SOCLURI 19<br />

2. Deschi<strong>de</strong>/crează fluxuri <strong>de</strong> date pentru comunicat¸ia cu serverul.<br />

3. Transmite ¸si recept¸ionează date potrivit specificului aplicat¸iei (protocolului<br />

serverului). Acest pas variază <strong>de</strong> la un program client la altul.<br />

4.<br />

5.<br />

Închi<strong>de</strong>rea fluxurilor <strong>de</strong> date.<br />

Închi<strong>de</strong>rea soclului.<br />

import java.io.*;<br />

import java.net.*;<br />

import java.util.Scanner;<br />

public class CmmdcClient {<br />

public static void main(String[] args) throws IOException {<br />

String host="localhost";<br />

int port=7999;<br />

if (args.length>0)<br />

host=args[0];<br />

if (args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

Socket cmmdcSocket = null;<br />

DataInputStream in=null;<br />

DataOutputStream out=null;<br />

try {<br />

cmmdcSocket = new Socket(host, port);<br />

out=new DataOutputStream(cmmdcSocket.getOutputStream());<br />

in=new DataInputStream(cmmdcSocket.getInputStream());<br />

}<br />

catch (Exception e) {<br />

System.err.println("Connection Error : "+e.getMessage());<br />

System.exit(1);<br />

}<br />

Scanner scanner=new Scanner(System.in);<br />

long m,n,r;<br />

System.out.println("m=");<br />

m=scanner.nextLong();<br />

System.out.println("n=");<br />

n=scanner.nextLong();<br />

try{<br />

out.writeLong(m);<br />

out.writeLong(n);<br />

r=in.readLong();<br />

System.out.println("Cmmdc : "+r);<br />

}<br />

catch(IOException e){<br />

System.err.println("Comunication error"+e.getMessage());<br />

}<br />

out.close();<br />

in.close();<br />

cmmdcSocket.close();<br />

}<br />

}


20 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

Se presupune că programul server rulează pe calculatorul local ¸si utilizează<br />

portul 7999. Dacă ace¸sti parametri se modifică - <strong>de</strong> exemplu serverul rulează în<br />

ret¸ea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitem ace¸sti<br />

parametri prin java CmmdcClient atlantis 8200<br />

Partea server este alcătuită <strong>din</strong> mai multe clase:<br />

• Clasa MyMServer, in<strong>de</strong>pen<strong>de</strong>ntă <strong>de</strong> un serviciu anume, preia apelurile client¸ilor<br />

¸si lansează satisfacerea cererii.<br />

import java.net.*;<br />

import java.io.*;<br />

public class MyMServer {<br />

public static void main(String[] args) throws IOException {<br />

int port=7999;<br />

boolean listening=true;<br />

ServerSocket serverSocket = null;<br />

try {<br />

serverSocket = new ServerSocket(port);<br />

}<br />

catch (IOException e) {<br />

System.err.println("Could not listen on port: "+port);<br />

System.out.println(e.getMessage());<br />

System.exit(1);<br />

}<br />

while(listening)<br />

// varianta 1<br />

new AppThread(serverSocket.accept()).start();<br />

// varianta 2<br />

/*<br />

{<br />

Socket socket=serverSocket.accept();<br />

try{<br />

DataOutputStream out = new DataOutputStream(socket.getOutputStream());<br />

DataInputStream in = new DataInputStream(socket.getInputStream());<br />

long m=0,n=0,r;<br />

App app=new App();<br />

m=in.readLong();<br />

n=in.readLong();<br />

r=app.cmmdc(m,n);<br />

out.writeLong(r);<br />

out.close();<br />

in.close();<br />

socket.close();<br />

}<br />

catch(IOException e){<br />

System.err.println("Server comunication error : "+e.getMessage());<br />

}<br />

}<br />

*/<br />

serverSocket.close();<br />

}<br />

}<br />

• Clasa AppTread - fir <strong>de</strong> execut¸ie responsabil <strong>de</strong> preluarea datelor ¸si <strong>de</strong>


2.5. DATAGRAME 21<br />

transmitere a rezultatului.<br />

import java.net.*;<br />

import java.io.*;<br />

public class AppThread extends Thread{<br />

Socket socket=null;<br />

public AppThread(Socket socket){<br />

this.socket=socket;<br />

}<br />

public void run(){<br />

try{<br />

DataOutputStream out = new DataOutputStream(socket.getOutputStream());<br />

DataInputStream in = new DataInputStream(socket.getInputStream());<br />

long m=0,n=0,r;<br />

App app=new App();<br />

m=in.readLong();<br />

n=in.readLong();<br />

r=app.cmmdc(m,n);<br />

out.writeLong(r);<br />

out.close();<br />

in.close();<br />

socket.close();<br />

}<br />

catch(IOException e){<br />

System.err.println("Server comunication error : "+e.getMessage());<br />

}<br />

}<br />

}<br />

• Clasa App corespunzătoare calcului celui mai mare divizor comul a două<br />

numere naturale.<br />

public class App{<br />

public long cmmdc(long m,long n){. . .}<br />

}<br />

Rularea programelor. Se porne¸ste la început programul server MyMServer<br />

iar apoi clientul CmmdcClient. Clientul se poate rula <strong>de</strong> pe orice calculator al<br />

ret¸elei. Dacă programul client se execută pe alt calculator <strong>de</strong>cât cel pe care<br />

rulează programul server, atunci la apelarea clientului trebuie precizat numele<br />

calculatorului server ¸si eventual portul utilizat.<br />

2.5 Datagrame<br />

Pentru utilizarea datagramelor pachetul java.net pune la dispozit¸ie clasele


22 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

• DatagramSocket<br />

• DatagramPacket<br />

• MulticastSocket<br />

O aplicat¸ie trimite ¸si recept¸ionează pachete DatagramPacket prin intermediul<br />

unui DatagramSocket. Un pachet DatagramPacket poate fi trimis la mai mult¸i<br />

<strong>de</strong>stinatari prin intermediul unui MulticastSocket.<br />

Reamintim că o datagramă este un mesaj trimis prin ret¸ea a cărei sosire nu<br />

este garantat iar momentul <strong>de</strong> sosire este neprecizat.<br />

2.5.1 Clasa DatagramPacket.<br />

Trimiterea unui pachet UDP necesită crearea unui obiect<br />

DatagramPachet care cont¸ine corpul mesajului ¸si adresa <strong>de</strong>stinat¸iei. Apoi acest<br />

obiect DatagramPacket poate fi pus în ret¸ea în ve<strong>de</strong>rea trimiterii sale. Primirea<br />

unui pachet UDP necesită crearea unui obiect DatagramPacket ¸si apoi acceptarea<br />

unui pachet UDP <strong>din</strong> ret¸ea. După primire, se poate extrage <strong>din</strong> obiectul<br />

DatagramPacket adresa sursă ¸si cont¸inutul mesajului.<br />

Constructori<br />

Există doi constructori pentru datagrame UDP. Primul constructor este folosit<br />

pentru primirea <strong>de</strong> pachete ¸si necesită doar furnizarea unei memorii tampon, iar<br />

celălalt este folosit pentru trimiterea <strong>de</strong> pachete necesită ¸si specificarea adresei.<br />

• DatagramPacket(byte[ ] buffer,int lung)<br />

Acest contructor este folosit pentru primirea pachetelor. Un pachet se memorează<br />

în tamponul buffer având lung octet¸i. Dacă lungimea pachetului<br />

<strong>de</strong>pă¸se¸ste această lungime, atunci pachetul este trunchiat iar octet¸ii în plus<br />

se pierd.<br />

• DatagramPacket(byte[ ] buffer,int lung ,InetAddress adresa ,int port)<br />

Acest constructor este folosit pentru crearea unui pachet în ve<strong>de</strong>rea expedierii.<br />

Corpul pachetului este cont¸inut în tamponul buffer având lung<br />

octet¸i. Pachetul va fi trimis către adresa ¸si portul specificat. Trebuie să<br />

existe un server UDP care ascultă la portul specificat pentru trimiterea pachetelor.<br />

Un server UDP ¸si un server TCP care ascultă acela¸si port pot<br />

coexista.<br />

Meto<strong>de</strong><br />

• InetAddress getAddress()<br />

returnează adresa IP a pachetului.


2.5. DATAGRAME 23<br />

• int getPort()<br />

returnează portul.<br />

• byte[] getData()<br />

returnează cont¸inutul pachetului.<br />

• int getLength()<br />

returnează lungimea pachetului.<br />

• void setAddress(InetAddress adresa)<br />

fixează adresa IP a pachetului.<br />

• void setPort(int port)<br />

fixează portul.<br />

• void setData(byte[] buffer)<br />

fixează cont¸inutul pachetului.<br />

• void setLength(int lung)<br />

fixează lungimea pachetului.<br />

2.5.2 Clasa DatagramSocket<br />

Această clasă se folose¸ste atât pentru trimiterea, cât ¸si pentru primirea obiectelor<br />

DatagramPacket. Un obiect DatagramSocket ascultă la un port cuprins între 1<br />

¸si 65535 (porturile cuprinse între 1 ¸si 1023 sunt rezervate pentru aplicat¸iile sistem).<br />

Deoarece UDP nu este orientat pe conexiune, se va crea un singur obiect<br />

DatagramSocket pentru trimiterea pachetelor către diferite <strong>de</strong>stinat¸ii ¸si primirea<br />

pachetelor <strong>de</strong> la diferite surse.<br />

Constructori<br />

• DatagramSocket() throws SocketException<br />

Crează un obiect DatagramSocket cu un număr <strong>de</strong> port aleator;<br />

• DatagramSocket(int port) throws SocketException<br />

Crează un obiect DatagramSocket cu numărul <strong>de</strong> port specificat;<br />

• DatagramSocket(int port, InetAddress adresă) throws SocketException<br />

Crează un obiect DatagramSocket cu numărul <strong>de</strong> port specificat la adresa<br />

specificată;


24 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

Meto<strong>de</strong><br />

Clasa DatagramSocket cont¸ine meto<strong>de</strong> pentru trimiterea ¸si primirea <strong>de</strong> obiecte<br />

DatagramPacket, închi<strong>de</strong>rea soclului, <strong>de</strong>terminarea informat¸iilor adresei locale<br />

¸si setarea timpului <strong>de</strong> primire.<br />

• void send(DatagramPacket pachet) throws IOException<br />

Trimite pachetul prin ret¸ea. Dacă se trimit pachete la o <strong>de</strong>stinat¸ie necunoscută<br />

sau care nu ascultă, în cele <strong>din</strong> urmă se generează o except¸ie<br />

IOException.<br />

• void receive(DatagramPacket pachet) throws IOException<br />

Metoda prime¸ste un singur pachet UDP în obiectul pachet specificat. Apoi,<br />

pachetul poate fi inspectat pentru <strong>de</strong>terminarea adresei IP sursă, portul<br />

sursă ¸si lungimea mesajului. Execut¸ia meto<strong>de</strong>i este blocată până când se<br />

prime¸ste cu succes un pachet sau se scurge timpul <strong>de</strong> a¸steptare.<br />

• InetAddress getLocalAddress()<br />

Returnează adresa locală către care este legat acest DatagramSocket;<br />

• int getLocalPort()<br />

Returnează numărul <strong>de</strong> port un<strong>de</strong> ascultă DatagramSocket.<br />

• void close()<br />

Închi<strong>de</strong> DatagramSocket.<br />

• void setSoTimeout(int timpDeA¸steptere) throws SocketException<br />

Metoda fixează timpul <strong>de</strong> a¸steptare (în milisecun<strong>de</strong>) a soclului. Metoda<br />

receive() se va bloca pentru timpul <strong>de</strong> a¸steptare specificat pentru primirea<br />

unui pachet UDP, după care va arunca o except¸ie Interrupted Exception.<br />

Dacă valoarea parametrului este 0, atunci soclul este blocat.<br />

• int getSoTimeout() throws SocketException<br />

Returnează timpul <strong>de</strong> a¸steptare.<br />

• void setSendBufferSize(int lungime) throws SocketException<br />

Fixează lungimea tamponului <strong>de</strong> trimitere a soclului la valoarea specificată.<br />

Mesaj UDP <strong>de</strong> lungime mai mare <strong>de</strong> această valoare nu pot fi trimis.<br />

• int getSendBufferSize() throws SocketException<br />

Returnează lungimea tamponului <strong>de</strong> trimitere a soclului.


2.5. DATAGRAME 25<br />

• void setReceiveBufferSize(int lungime) throws SocketException<br />

Fixează lungimea tamponului <strong>de</strong> primire a soclului la valoarea specificată.<br />

Mesaj UDP <strong>de</strong> lungime mai mare <strong>de</strong> această valoare nu pot fi primit.<br />

• int getReceiveBufferSize() throws SocketException<br />

Returnează lungimea tamponului <strong>de</strong> primire a soclului.<br />

• void connect(InetAddress adresa, int port) throws SocketException<br />

Conectează soclul la adresa ¸si portul specificat. Această metodă nu este<br />

cerută pentru operat¸iile uzuale UDP.<br />

• void disconnect()<br />

Deconectează soclul conectat.<br />

• InetAddress getInetAddress()<br />

Returnează obiectul InetAddress către care este conectat soclul sau null<br />

dacă acesta nu este conectat.<br />

• int getPort()<br />

Returnează portul la care este conectat soclul sau -1 dacă acesta nu este<br />

conectat.<br />

2.5.3 Clasa InetAddress<br />

Datele pot fi trimise prin ret¸ea indicând adresa IP corespunzătoare ma¸sinii<br />

<strong>de</strong>stinat¸ie. Clasa InetAddress furnizează acces la adresele IP.<br />

Nu există constructori pentru această clasă. Instant¸ele trebuie create folosind<br />

meto<strong>de</strong>le statice:<br />

• InetAddress getLocalHost() throws UnknownHostException<br />

Returnează un obiect InetAddress corespunzător ma¸sinii locale.<br />

• InetAddress getByName(String host) throws UnknownHostException<br />

Returnează un obiect InetAddress corespunzător ma¸sinii host, parametru<br />

care poate fi specificat prin nume (<strong>de</strong> exemplu ”atlantis”) sau prin adresa<br />

IP (”168.192.0.1”).<br />

• InetAddress [ ]getAllByName(String host)<br />

throws UnknownHostException<br />

Returnează un ¸sir <strong>de</strong> obiecte InetAddress corespunzător fiecărei adrese IP<br />

a ma¸sinii host.<br />

Meto<strong>de</strong>le clasei InetAddress


26 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

• byte [ ] getAddress()<br />

Returnează ¸sirul <strong>de</strong> octet¸i corespunzător obiectului InetAddress <strong>de</strong> referint¸ă.<br />

• String getHostName()<br />

Returnează numele ma¸sinii gazdă.<br />

• String getHostAddress()<br />

Returnează adresa IP a ma¸sinii gazdă.<br />

• boolean isMulticastAddress()<br />

Returnează true dacă obiectul InetAddress reprezintă o adresă IP multicast<br />

(primul octet cuprins între 224 ¸si 239).<br />

Exemplul următor afi¸sează numele ¸si adresa calculatorului gazdă cât ¸si acela<br />

al calculatoarelor ale căror nume este transmis programului ca parametru.<br />

Exemplul 2.5.1<br />

import java.net.*;<br />

public class AdreseIP{<br />

public static void main(String arg[]){<br />

InetAddress adresa=null;<br />

try{<br />

adresa=InetAddress.getLocalHost();<br />

System.out.println("Calculatorul gazda are:");<br />

System.out.println("numele : "+adresa.getHostName());<br />

System.out.println("adresa IP : "+adresa.getHostAddress());<br />

}<br />

catch(UnknownHostException e){<br />

System.out.println("UnknownHostException : "+e.getMessage());<br />

}<br />

if(arg.length>0){<br />

for(int i=0;i


2.5. DATAGRAME 27<br />

2.5.4 Aplicat¸ii client – server cu datagrame.<br />

Un pachet <strong>de</strong> tip DatagramPacket este alcătuit <strong>din</strong>tr-un ¸sir <strong>de</strong> octet¸i. Este<br />

datoria programatorului să transforme datele (mesajul) în ¸siruri <strong>de</strong> octet¸i la expediere<br />

¸si la recept¸ie.<br />

Transformarea unui obiect serializabil într-un ¸sir <strong>de</strong> octet¸i ¸si invers se poate<br />

realiza cu schema<br />

Object Object<br />

❄<br />

ObjectOutputStream<br />

✻<br />

ObjectInputStream<br />

❄<br />

ByteArrayOutputStream<br />

✻<br />

ByteArrayInputStream<br />

❄<br />

output - DatagramPacket<br />

✻<br />

input - DatagramPacket<br />

❄ ✻<br />

Fie socket un obiect <strong>de</strong> tip DatagramSocket prin intermediul căruia se execută<br />

expedierea / recept¸ionarea pachetelor <strong>de</strong> tip DatagramPacket.<br />

În principiu expedierea ¸si transformarea obiectului obj într-un ¸sir <strong>de</strong> octet¸i se<br />

poate realiza cu secvent¸a <strong>de</strong> cod<br />

ByteArrayOutputStream baos=new ByteArrayOutputStream(256);<br />

ObjectOutputStream out=new ObjectOutputStream(baos);<br />

out.writeObject(p);<br />

byte[] bout=baos.toByteArray();<br />

DatagramPacket packet=new DatagramPacket(bout,bout.length,<br />

address,port);<br />

socket.send(packet);<br />

un<strong>de</strong> address ¸si port sunt adresa ¸si portul utilizat <strong>de</strong> expeditorul mesajului. Dacă<br />

packet este un obiect DatagramPacket recept¸ionat atunci meto<strong>de</strong>le getAddress()<br />

¸si getPort() furnizează adresa ¸si portul expeditorului<br />

Recept¸ionarea ¸si transformarea inversă este<br />

byte[] bin=new byte[256];<br />

packet=new DatagramPacket(bin,bin.length);<br />

socket.receive(packet);<br />

ByteArrayInputStream bais=new ByteArrayInputStream(bin);<br />

ObjectInputStream in=new ObjectInputStream(bais);<br />

obj=in.readObject();


28 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

Dacă mesajul este un obiect String atunci el se transformă într-un ¸sir <strong>de</strong><br />

octet¸i cu metoda byte[] String.getByte() ¸si invers, el se obt¸ine prin new<br />

String(bin) sau new String(packet.getData()).<br />

Exemplul 2.5.2 Programăm serviciul calculului celui mai mare divizor comun<br />

a două numere.<br />

În ve<strong>de</strong>rea transportului <strong>de</strong>finim clasa<br />

import java.io.*;<br />

public class Protocol implements Serializable{<br />

long x,y;<br />

Protocol(long x,long y){<br />

this.x=x;<br />

this.y=y;<br />

}<br />

}<br />

Clientul va trimite un obiect Protocol, care va cont¸ine datele problemei ¸si va<br />

recept¸iona un obiect <strong>de</strong> acela¸si tip cu rezultatul (cel mai mare divizor comun) în<br />

primul câmp al obiectului.<br />

Programul client este<br />

import java.net.*;<br />

import java.io.*;<br />

import java.util.Scanner;<br />

public class ClientCmmdc{<br />

public static void main(String []args){<br />

String hostServer="localhost";<br />

int portServer=7999;<br />

if(args.length>0)<br />

hostServer=args[0];<br />

if(args.length>1)<br />

portServer=Integer.parseInt(args[1]);<br />

try{<br />

// Crearea unui soclu Datagramsocket<br />

DatagramSocket socket=new DatagramSocket();<br />

// Formarea mesajului<br />

Protocol p=new Protocol(0,0);<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("Introduceti primul numar: ");<br />

p.x=scanner.nextLong();<br />

System.out.println("Introduceti al doilea numar: ");<br />

p.y=scanner.nextLong();<br />

// Transformarea mesajului intr-un sir <strong>de</strong> octeti<br />

ByteArrayOutputStream baos=new ByteArrayOutputStream(256);<br />

ObjectOutputStream out=new ObjectOutputStream(baos);<br />

out.writeObject(p);


2.5. DATAGRAME 29<br />

byte[] bout=baos.toByteArray();<br />

// Expedierea mesajului<br />

InetAddress address=InetAddress.getByName(hostServer);<br />

DatagramPacket packet=new<br />

DatagramPacket(bout,bout.length,address,portServer);<br />

socket.send(packet);<br />

// Asteptarea raspunsului<br />

byte[] bin=new byte[256];<br />

packet=new DatagramPacket(bin,bin.length);<br />

socket.receive(packet);<br />

// Prelucrarea raspunsului<br />

ByteArrayInputStream bais=new ByteArrayInputStream(bin);<br />

ObjectInputStream in=new ObjectInputStream(bais);<br />

p=(Protocol)in.readObject();<br />

System.out.println("Cmmdc = "+p.x);<br />

socket.close();<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

}<br />

}<br />

}<br />

Programul server este<br />

import java.net.*;<br />

import java.io.*;<br />

public class ServerCmmdc{<br />

public static void main(String []args){<br />

DatagramSocket socket=null;<br />

int serverPort=7999;<br />

try{<br />

// Crearea unui soclu DatagramSocket<br />

socket=new DatagramSocket(serverPort);<br />

}<br />

catch(Exception e){<br />

System.out.println("DatagramSocket-error-"+e.getMessage());<br />

System.exit(0);<br />

}<br />

// Activitatea serverului<br />

boolean listening=true;<br />

DatagramPacket packet=null;<br />

App app=new App();<br />

Protocol p=null;<br />

while(listening){


30 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

try{<br />

// Receptionarea unui mesaj<br />

byte[] bin=new byte[256];<br />

packet=new DatagramPacket(bin,bin.length);<br />

socket.receive(packet);<br />

// Prelucrarea datelor<br />

ByteArrayInputStream bais=new ByteArrayInputStream(bin);<br />

ObjectInputStream in=new ObjectInputStream(bais);<br />

p=(Protocol)in.readObject();<br />

// Rezolvarea cererii clientului<br />

p.x=app.cmmdc(p.x,p.y);<br />

p.y=0;<br />

// Transformarea mesajului <strong>de</strong> raspuns intr-un sir <strong>de</strong> octeti<br />

ByteArrayOutputStream baos=new ByteArrayOutputStream(256);<br />

ObjectOutputStream out=new ObjectOutputStream(baos);<br />

out.writeObject(p);<br />

byte[] bout=baos.toByteArray();<br />

// Expedierea mesajului necesita cunoasterea expeditorului<br />

InetAddress address=packet.getAddress();<br />

int port=packet.getPort();<br />

packet=new DatagramPacket(bout,bout.length,address,port);<br />

socket.send(packet);<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

}<br />

}<br />

socket.close();<br />

}<br />

}<br />

Clasa App este cea utilizată la exemplul cu socluri TCP.<br />

2.5.5 Clasa MulticastSocket<br />

Multicast vs. Broadcast<br />

Prin intermediul unui soclu <strong>de</strong> tip MulticastSocket se pot recept¸iona datagrame<br />

expediate <strong>de</strong> un server către tot¸i client¸ii cu un asemenea soclu.<br />

Constructori<br />

• MulticastSocket(int port) throws SocketException<br />

Meto<strong>de</strong><br />

• void joinGroup(InetAddress adresă) throws SocketException


2.5. DATAGRAME 31<br />

Soclul se ”conectează” la grupul <strong>de</strong>finit <strong>de</strong> adresa IP (<strong>de</strong> tip D, adică cuprins<br />

între 224.0.0.0 ¸si 239.255.255.255).<br />

• void leaveGroup(InetAddress adresă) throws SocketException<br />

Soclul se ”<strong>de</strong>conectează” la grupul <strong>de</strong>finit <strong>de</strong> adresa IP.<br />

• void close()<br />

Pregătirea clientului în ve<strong>de</strong>rea recept¸ionării datagramelor printr-un soclu <strong>de</strong><br />

tip MulticastSocket constă <strong>din</strong><br />

MulticastSocket socket= new MulticastSocket(port);<br />

InetAddress adresa=InetAddress.getByName("230.0.0.1");<br />

socket.joinGroup(adresa);<br />

În final, clientul se <strong>de</strong>conectează ¸si închi<strong>de</strong> soclul.<br />

socket.leaveGroup(adresa);<br />

socket.close();<br />

Pachetele trimise <strong>de</strong> programul server trebuie să se adreseze grupului, i<strong>de</strong>ntificat<br />

prin adresa IP <strong>de</strong> tip D.<br />

Astfel prin multicast serverul trimite pachete la o adresă <strong>de</strong> grup ¸si la un<br />

port fixat. Pachetele emise <strong>de</strong> server sunt recept¸ionate <strong>de</strong> orice client ce crează<br />

un soclu <strong>de</strong> tip MulticastSocket pentru portul la care emite serverul ¸si care se<br />

alătură grupului.<br />

Prin broadcast serverul emite datagrame către orice calculator al ret¸elei locale<br />

la un anumit port. Faptul că emiterea datagramelor este <strong>de</strong> tip broadcast se indică<br />

prin<br />

DatagramSocket.setBroadcast(true)<br />

Orice client care î¸si crează un soclu la portul la care emite serverul recept¸ionează<br />

datagramele trimise <strong>de</strong> server. Adresa utilizată <strong>de</strong> server la crearea datagramelor<br />

trebuie să i<strong>de</strong>ntifice ret¸eaua.<br />

Observat¸ie. În cazul unui calculator ”izolat” este nevoie <strong>de</strong> instalarea driverului<br />

Microsoft Loopback Adapter, care simulează existent¸a unei plăci <strong>de</strong> ret¸ea active.<br />

În exemplele următoare, programele server emit <strong>din</strong> cinci în cinci secun<strong>de</strong> ora<br />

exactă. Un client va recept¸iona câte cinci datagrame.


32 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

MulticastServer BroadcastServer<br />

import java.io.*; import java.io.*;<br />

import java.net.*; import java.net.*;<br />

import java.util.*; import java.util.*;<br />

import java.text.DateFormat; import java.text.DateFormat;<br />

public class MulticastServer{ public class BroadcastServer{<br />

public static void main(String[] args){ public static void main(String[] args){<br />

long FIVE_SECONDS = 5000; long FIVE_SECONDS = 5000;<br />

boolean sfarsit=false; boolean sfarsit=false;<br />

DatagramSocket socket = null; DatagramSocket socket = null;<br />

int serverPort=7000; int serverPort=7000;<br />

int clientPort=7001; int clientPort=7001;<br />

byte[] buf = new byte[256]; byte[] buf = new byte[256];<br />

Date data=null; Date data = null;<br />

DatagramPacket packet = null; DatagramPacket packet = null;<br />

try{ try{<br />

socket=new DatagramSocket(serverPort); socket=new DatagramSocket(serverPort);<br />

} }<br />

catch(SocketException e){ catch(SocketException e){<br />

System.out.println(e.getMessage()); System.out.println(e.getMessage());<br />

} }<br />

while (! sfarsit){ while (! sfarsit) {<br />

try{ try{<br />

data=new Date(); data=new Date();<br />

String df=DateFormat. String df=DateFormat.<br />

getTimeInstance().format(data); getTimeInstance().format(data);<br />

buf = df.getBytes(); buf = df.getBytes();<br />

// send it<br />

InetAddress group = InetAddress group =<br />

InetAddress.getByName("230.0.0.1"); InetAddress.getByName("192.168.0.255");<br />

packet=new DatagramPacket(buf, packet=new DatagramPacket(buf,<br />

buf.length,group,clientPort); buf.length,group,clientPort);<br />

socket.setBroadcast(true);<br />

socket.send(packet); socket.send(packet);<br />

// sleep for a while<br />

Thread.sleep(FIVE_SECONDS); Thread.sleep(FIVE_SECONDS);<br />

} }<br />

catch (Exception e) { catch (Exception e) {<br />

System.out.println(e.getMessage()); System.out.println(e.getMessage());<br />

} }<br />

} }<br />

socket.close(); socket.close();<br />

} }<br />

} }


2.6. CANALE DE COMUNICAT¸ IE 33<br />

MulticastClient BroadcastClient<br />

import java.io.*; import java.io.*;<br />

import java.net.*; import java.net.*;<br />

public class MulticastClient { public class BroadcastClient {<br />

public static void main(String[] args) public static void main(String[] args)<br />

throws IOException { throws IOException {<br />

DatagramPacket packet; DatagramPacket packet;<br />

byte[] buf = new byte[256]; byte[] buf = new byte[256];<br />

int clientPort=7001; int clientPort=7001;<br />

MulticastSocket socket= DatagramSocket socket=<br />

new MulticastSocket(clientPort); new DatagramSocket(clientPort);<br />

InetAddress address=<br />

InetAddress.getByName("230.0.0.1");<br />

socket.joinGroup(address);<br />

int i=-1; int i=-1;<br />

do{ do{<br />

i++; i++;<br />

packet=new DatagramPacket(buf, buf.length); packet=new DatagramPacket(buf, buf.length);<br />

socket.receive(packet); socket.receive(packet);<br />

String received=new String(packet.getData()); String received=new String(packet.getData());<br />

System.out.println("Am primit: "+received); System.out.println("Am primit: "+received);<br />

} }<br />

while(i


34 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

Un obiect <strong>de</strong> tip typeBuffer este un tampon (container) care cont¸ine date<br />

<strong>de</strong> tipul specificat <strong>de</strong> <strong>de</strong>numirea clasei.<br />

Un obiect <strong>de</strong> tip Buffer este caracterizat <strong>de</strong><br />

• capacitate numărul elementelor care pot fi înmagazitate în tampon;<br />

• limită marginea superioră a indicelui;<br />

• indice valoarea curentă a indicelui.<br />

Meto<strong>de</strong> generale<br />

• clear() permite unui obiect <strong>de</strong> tip Buffer să fie reîncărcat. Fixează limita =<br />

capacitate ¸si indice = 0.<br />

• flip() pregăte¸ste obiectul <strong>de</strong> tip Buffer pentru consultare (citire). Fixează<br />

limita =numărul elementelor <strong>din</strong> tampon ¸si indice = 0.<br />

• rewind() pregăte¸ste obiectul <strong>de</strong> tip Buffer pentru re-citire.<br />

2.6.2 Clasa ByteBuffer<br />

Instant¸ierea unui obiect se obt¸ine prin fabrica<br />

static ByteBuffer allocate(capacitate)<br />

Introducerea elementelor se face prin metoda put(byte număr) iar accesul<br />

la elementul corespunzător indicelui se obt¸ine prin metoda byte get().<br />

S¸ablonul <strong>de</strong> prelucrare este<br />

ByteBuffer bb=ByteBuffer.allocate(10);<br />

byte elem;<br />

while(bb.hasRemaining()){<br />

elem=. . .<br />

bb.put(elem);<br />

}<br />

bb.flip();<br />

while(bb.hasRemaining()){<br />

. . .<br />

byte x=bb.get();<br />

. . .<br />

}<br />

Metoda public final boolean hasRemaining() reîntoarce true dacă între valoarea<br />

curentă a indicelui ¸si limită există elemente.<br />

Un obiect <strong>de</strong> tip ByteBuffer se poate percepe ca un obiect <strong>de</strong> tip LongBuffer,<br />

DoubleBuffer, etc prin


2.6. CANALE DE COMUNICAT¸ IE 35<br />

ByteBuffer bb=ByteBuffer.allocate(10);<br />

LongBuffer lb=bb.asLongBuffer();<br />

DoubleBuffer db=bb.asDoubleBuffer();<br />

2.6.3 Clasa InetSocketAddress<br />

Clasa InetSocketAddress încapsulează adresa unui calculator <strong>din</strong> Internet<br />

împreună cu un port în ve<strong>de</strong>rea legării la un ServerSocket. Extin<strong>de</strong> clasa<br />

SocketAddress<br />

Constructori:<br />

• InetSocketAddress(InetAddress addr,int port)<br />

• InetSocketAddress(String numeCalculator,int port)<br />

2.6.4 Clasa ServerSocketChannel<br />

Crearea unui obiect <strong>de</strong> tip ServerSocketChannel se realizează prin<br />

static ServerSocketChannel open() throws IOException<br />

Unui asemenea obiect i se asociază un ServerSocket prin metoda<br />

ServerSocket socket() throws IOException.<br />

Obiectul <strong>de</strong> tip ServerSocket trebuie leagat la un port <strong>de</strong> comunicat¸ie prin<br />

metoda<br />

void bind(InetSocketAddress endpoint) throws IOException.<br />

S¸ablonul <strong>de</strong> utilizare este<br />

try{<br />

ServerSocketChannel ssc=ServerSocketChannel.open();<br />

ServerSocket ss=ssc.socket();<br />

InetSocketAddress isa=new InetSocketAddress(addr,port);<br />

ss.bind(isa);<br />

}<br />

catch(Exception e){. . .}<br />

La apelul unui client, serverul trebuie să genereze un obiect <strong>de</strong> tip Socket<br />

Channel prin care se vor <strong>de</strong>rula comunicat¸iile cu clientul. Acest canal <strong>de</strong> comunicat¸ie<br />

se obt¸ine cu metoda accept().


36 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

2.6.5 Clasa SocketChannel<br />

Crearea unui obiect <strong>de</strong> tip SocketChannel se realizează prin<br />

static SocketChannel open() throws IOException<br />

Acest obiect trebuie conectat la obiectul ServerSocketChannel al serverului cu<br />

metoda connect(InetSocketAddress addr).<br />

Datele vehiculate printr-un SocketChannel sunt <strong>de</strong> tip ByteBuffer. Datele<br />

se transmit prin metoda<br />

¸si se recept¸ionează prin metoda<br />

int write(ByteBuffer sursă)<br />

int read(ByteBuffer <strong>de</strong>stinat¸ie)<br />

Valoarea returnată <strong>de</strong> cele două meto<strong>de</strong> reprezintă numărul octet¸ilor trimi¸si<br />

/ recept¸ionat¸i.<br />

Canalul se închi<strong>de</strong> cu metoda close().<br />

Exemplul 2.6.1 Calculul celui mai mare divizor comun a două numere naturale.<br />

Aplicat¸ie client-server bazat pe canale <strong>de</strong> comunicat¸ie prin socluri are programul<br />

server<br />

import java.io.*;<br />

import java.net.*;<br />

import java.nio.*;<br />

import java.nio.channels.*;<br />

public class ChannelCmmdcServer {<br />

// Serviciul asigurat<br />

private static void serviciu(ServerSocketChannel ssc){<br />

SocketChannel sc = null;<br />

try {<br />

sc=ssc.accept();<br />

ByteBuffer bb = ByteBuffer.allocate(16);<br />

LongBuffer lb = bb.asLongBuffer();<br />

sc.read(bb);<br />

bb.flip();<br />

long m=lb.get();<br />

long n=lb.get();<br />

App app=new App();<br />

long r=app.cmmdc(m,n);<br />

lb.clear();<br />

lb.put(r);<br />

sc.write(bb);<br />

sc.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("Server error : "+e.getMessage());


2.6. CANALE DE COMUNICAT¸ IE 37<br />

}<br />

}<br />

public static void main(String[] args){<br />

int port=7999;<br />

ServerSocketChannel ssc=null;<br />

try{<br />

ssc = ServerSocketChannel.open();<br />

InetSocketAddress isa=new InetSocketAddress(InetAddress.getLocalHost(), port);<br />

ServerSocket ss=ssc.socket();<br />

ss.bind(isa);<br />

}<br />

catch(IOException e){<br />

System.out.println("ServerSocketChannelError : "+e.getMessage());<br />

System.exit(0);<br />

}<br />

while(true){<br />

serviciu(ssc);<br />

}<br />

}<br />

}<br />

¸si clientul<br />

import java.io.*;<br />

import java.net.*;<br />

import java.nio.*;<br />

import java.nio.channels.*;<br />

import java.util.Scanner;<br />

public class ChannelCmmdcClient {<br />

public static void main(String[] args) {<br />

String host="localhost";<br />

int port=7999;<br />

if (args.length>0)<br />

host=args[0];<br />

if (args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

SocketChannel sc=null;<br />

try{<br />

InetSocketAddress isa=new InetSocketAddress(host,port);<br />

sc=SocketChannel.open();<br />

sc.connect(isa);<br />

}<br />

catch (UnknownHostException e) {<br />

System.err.println("Server necunoscut: "+host+" "+e.getessage());<br />

System.exit(1);<br />

}<br />

catch (IOException e) {<br />

System.err.println("Conectare imposibila la: "+<br />

host+" pe portul "+port+" "+e.getessage());<br />

System.exit(1);<br />

}<br />

Scanner scanner=new Scanner(System.in);<br />

long m,n,r;<br />

System.out.println("m=");<br />

m=scanner.nextLong();<br />

System.out.println("n=");


38 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA<br />

n=scanner.nextLong();<br />

ByteBuffer bb=ByteBuffer.allocate(16);<br />

LongBuffer lb=bb.asLongBuffer();<br />

lb.put(m);<br />

lb.put(n);<br />

try{<br />

sc.write(bb);<br />

bb.clear();<br />

sc.read(bb);<br />

lb.flip();<br />

r=lb.get();<br />

System.out.println("Cmmdc : "+r);<br />

sc.close();<br />

}<br />

catch(Exception e){<br />

System.err.println("Eroare <strong>de</strong> comunicatie : "+e.getMessage());<br />

}<br />

}<br />

}<br />

2.7 Conexiuni HTTP<br />

Clasa URL permite realizarea unei conexiuni cu un server Web 1 potrivit protocolului<br />

HTTP (Hyper Text Transport Protocol) ¸si accesarea fi¸sierelor - uzual<br />

html - <strong>din</strong> zona publică.<br />

Constructori<br />

• URL(String spec) throws MalformedURLException<br />

Crează un obiect URL legat <strong>de</strong> resursa specificată <strong>de</strong> spec, care trebuie să fie<br />

o referint¸ă URL validă.<br />

Meto<strong>de</strong><br />

• InputStream openStream() throws IOException<br />

Returnează fluxul <strong>de</strong> intrare pentru citirea resursei.<br />

Exemplul 2.7.1 Pe baza referint¸ei către un fi¸sier html <strong>din</strong>tr-un catalog vizibil<br />

al unui server Web, să se afi¸seze cont¸inutul fi¸sierului.<br />

În codul reprodus mai jos, fi¸sierul Hello.html se află pe un server apachetomcat,<br />

în catalogul webapps\myservlet.<br />

import java.net.*;<br />

import java.io.*;<br />

public class ReadHTTP{<br />

public static void main(String[] args){<br />

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


2.7. CONEXIUNI HTTP 39<br />

try{<br />

String adr="http://localhost:8080/myservlet/Hello.html";<br />

URL url=new URL(adr);<br />

InputStream in=url.openStream();<br />

InputStreamRea<strong>de</strong>r isr=new InputStreamRea<strong>de</strong>r(in);<br />

BufferedRea<strong>de</strong>r br=new BufferedRea<strong>de</strong>r(isr);<br />

String s;<br />

do{<br />

s=br.readLine();<br />

if(s!=null)<br />

System.out.println(s);<br />

}<br />

while(s!=null);<br />

br.close();<br />

isr.close();<br />

in.close();<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

}<br />

}<br />

}


40 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA


Capitolul 3<br />

Programare distribuită cu RMI<br />

3.1 Structura RMI<br />

Remote Method Invocation (RMI) este un mecanism <strong>de</strong> <strong>de</strong>zvoltare a unei<br />

aplicat¸ii distribuite în mediul omogen Java, bazat pe mecanismului invocării la<br />

distant¸ă. RMI permite <strong>de</strong>zvoltarea <strong>de</strong> aplicat¸ii bazate pe client – server.<br />

Invocarea la distant¸ă (Remote Procedure Call – RPC) înseamnă apelarea<br />

meto<strong>de</strong>i unui obiect aflat pe un alt calculator ca ¸si cum acesta s-ar afla pe calculatorul<br />

local. RMI reprezintă materializarea acestei i<strong>de</strong>i în mediul Java.<br />

Modul cum <strong>de</strong> regăsire a obiectele la distant¸ă. I<strong>de</strong>ea găsirii unui<br />

obiect la distant¸ă este că serverul înscrie un reprezentant al său – numit stub<br />

(ciot) – într-un obiect registry - registru. Acest obiect se crează cu programul<br />

rmiregistry.exe <strong>din</strong> distribut¸ia java ¸si se lansează în execut¸ie prin<br />

start rmiregistry [port]<br />

un<strong>de</strong> valoarea implicită a portului este 1099. Comanda start apart¸ine sistemului<br />

<strong>de</strong> operare.<br />

Un client obt¸ine <strong>din</strong> registry stub-ul serverului, prin intermediul căruia realizează<br />

comunicat¸ia cu programul server.<br />

Când un obiect al clientului apelează o metodă a unui obiect aflat la distant¸ă,<br />

se va face, <strong>de</strong> fapt, un apel <strong>de</strong> metodă a unui obiect care reprezintă serverul.<br />

Acesta este stub-ul, aflat pe acea¸si ma¸sină cu clientul.<br />

Rolul acestui obiect este să împacheteze (marshalling) parametrii <strong>de</strong> apel ai<br />

meto<strong>de</strong>i într-un mesaj ce va fi transferat prin ret¸ea.<br />

Împachetarea se face într-o<br />

manieră in<strong>de</strong>pen<strong>de</strong>ntă <strong>de</strong> calculator, mai precis ¸sirurile <strong>de</strong> caractere ¸si obiecte<br />

sunt transmise într-un format care nu se bazează pe referint¸e. Pentru obiecte se<br />

utilizează serializarea obiectelor Java.<br />

Serializarea datelor reprezintă transformarea acestora <strong>din</strong> tipuri <strong>de</strong> date diferite<br />

într-un ¸sir <strong>de</strong> octet¸i care va fi transportat prin ret¸ea fără interpretare, dar care<br />

păstrează informat¸iile <strong>de</strong>spre structura init¸ială a datelor.<br />

41


42 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

Deserializarea este procesul invers <strong>de</strong> refacere a structurilor trimise prin ret¸ea.<br />

Mesajul asamblat este transmis către server, care ¸stie să <strong>de</strong>sfacă mesajul<br />

recept¸ionat invocând în mod corespunzător metoda referită <strong>de</strong> client.<br />

Atunci când clientul face apel la o metodă aflată pe o altă ma¸sină, este invocat<br />

stub-ul client, care începe conversat¸ia cu serverul. Acest lucru este complet<br />

transparent utilizatorului, care are impresia că invocă o metodă locală.<br />

Meto<strong>de</strong>le apelate la distant¸ă trebuie <strong>de</strong>clarate ca apart¸inând unei interfet¸e ce<br />

extin<strong>de</strong> interfat¸a Remote. Fiecare asemenea metodă trebuie să arunce o except¸ie<br />

java.rmi.RemoteException. Obiectele care circulă prin ret¸ea trebuie să implementeze<br />

interfat¸a java.io.Serializable.<br />

Structura unei aplicat¸ii RMI. O aplicat¸ie RMI este alcătuită <strong>din</strong> trei<br />

componente:<br />

1. O interfat¸ă la distant¸ă (remote) în care se <strong>de</strong>clară serviciile puse la dispozit¸ie<br />

<strong>de</strong> server;<br />

2. Aplicat¸ia server care poate implementa serviciile interfet¸ei la distant¸ă ¸si<br />

înscrie în registry stub-ul corespunzător;<br />

3. Aplicat¸ia client ce apelează unul sau mai multe servicii ale serverului.<br />

Nici o clipă nu trebuie scăpat <strong>din</strong> ve<strong>de</strong>re faptul că cele trei componente<br />

evoluează pe calculatoare diferite.<br />

Registrul rmiregistry implementează interfat¸a Registry. Meto<strong>de</strong>le oferite<br />

sunt:<br />

• void bind(String numeServiciu, Remote obj )throws<br />

RemoteException, AlreadyBoundException, AccessException<br />

Înregistrează în registry obiectul obj ce implementează interfat¸a Remote sub<br />

numele numeServiciu.<br />

• void rebind(String numeServiciu, Remote obj )throws<br />

RemoteException, AccessException<br />

Reînregistrează în registry obiectul obj ce implementează interfat¸a Remote<br />

sub numele numeServiciu.<br />

Această metodă poate fi apelată doar dacă programul care face înregistrarea<br />

se află pe acea¸si ma¸sină ca registrul registry.<br />

• String[] list()throws RemoteException, AccessException<br />

Returnează o listă a tuturor serviciilor înregistrate în registry.<br />

• Remote lookup(String numeServiciu)throws<br />

RemoteException, NotBoundException, AccessException<br />

Returnează stub-ul serviciului înregistrat sub numele numeServiciu.


3.1. STRUCTURA RMI 43<br />

• void unbind(String numeServiciu)throws<br />

RemoteException, NotBoundException, AccessException<br />

S¸terge <strong>din</strong> registru serviciul.<br />

Localizarea registrului se obt¸ine utilizând metoda statică getRegistry a clasei<br />

LocateRegistry.<br />

• public static Registry getRegistry() throws RemoteException<br />

• public static Registry getRegistry(String host)<br />

throws RemoteException<br />

• public static Registry getRegistry(int port)<br />

throws RemoteException<br />

• public static Registry getRegistry(String host,int port)<br />

throws RemoteException<br />

Metoda public static Registry createRegistry(int port)<br />

throws RemoteException crează un registru la portul specificat pe calculatorul<br />

local.<br />

Într-un registry se pot înregistra mai multe servicii, dar pe porturi diferite.<br />

Interfat¸a Remote serve¸ste la marcarea interfet¸elor ale căror meto<strong>de</strong> urmează<br />

a fi apelate <strong>de</strong> pe altă ma¸sină virtuală Java.<br />

Un obiect <strong>de</strong> tip UnicastRemoteObject mijloce¸ste transmiterea obiectelor ¸si<br />

serve¸ste la generarea unui stub unui serviciu. Generarea stub-ului unui serviciu<br />

se obt¸ine prin intermediul meto<strong>de</strong>i statice<br />

static Remote UnicastRemoteObject.exportObject(Remote obj ,int port)<br />

Inregistrarea stub-ului unui serviciu <strong>de</strong>scris <strong>de</strong> interfat¸a IService ¸si implementat<br />

<strong>de</strong> clasa ServiceImpl în registry se face prin<br />

ServiceImpl obj=new ServiceImpl();<br />

IService stub=(IService)UnicastRemoteObject.exportObject(obj,0);<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

registry.bind("MyServiceName",stub);<br />

Un client care dore¸ste să folosească trebuie să cunoască :<br />

• calculatorul pe care se găse¸ste obiectul registry ¸si portul la care ascultă<br />

serviciul;<br />

• numele sub care serviciul s-a înregistrat în registry;<br />

• meto<strong>de</strong>le puse la dispozit¸ie <strong>de</strong> serviciu.


44 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

3.2 Crearea unei aplicat¸ii RMI<br />

Exemplificăm construirea unei aplicat¸ii RMI în care serviciul asigurat <strong>de</strong><br />

server este calculul celui mai mare divizor comun a două numere naturale.<br />

Pentru exemplele1 care urmează, presupunem că textele sursă se ret¸in în<br />

subcataloage ale unui catalog src, la care are acces doar programatorul, iar clasele<br />

obt¸inute prin compilare se <strong>de</strong>pun în subcataloagele unui catalog public\classes,<br />

accesibil prin ret¸ea.<br />

Dezvoltarea unei aplicat¸ii se va face pe un calculator.<br />

În acest sens, celor 3<br />

componente li se asociază cataloagele \i - pentru interfat¸a la distant¸ă, \s - pentru<br />

componenta server ¸si \c - pentru componenta client. Pa¸si necesari compilării ¸si<br />

<strong>de</strong>sfă¸surării componentelor aplicat¸iei se vor realiza prin intermediul lui ant.<br />

Pentru fiecare componentă se vor executa succesiv obiectivele:<br />

1. Install - crează o structură <strong>de</strong> cataloage src ¸si public\classes.<br />

2. Init - crează structura <strong>de</strong> cataloage specifică aplicat¸iei.<br />

3. Compile - compilează programele sursă.<br />

Dezvoltarea unei aplicat¸ii RMI constă <strong>din</strong> parcurgerea următorilor pa¸si:<br />

1. Definitea interfet¸ei la distant¸ă.<br />

package cmmdc;<br />

public interface ICmmdc extends java.rmi.Remote{<br />

long cmmdc(long a,long b) throws java.rmi.RemoteException;<br />

}<br />

Presupunem ca programatorul interfet¸ei ret¸ine textul sursă<br />

ICmmdc.java în catalogul \i\src\cmmdc.<br />

2. Compilarea ¸si arhivarea interfet¸ei se poate realiza fi¸sierul ant-build<br />

<br />

Interface actions <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

1 Sistemul <strong>de</strong> operare utilizat este Windows


3.2. CREAREA UNEI APLICAT¸ II RMI 45<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

3. Implementarea interfet¸ei remote prin construirea aplicat¸iei server.<br />

package server;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

import java.rmi.registry.*;<br />

import cmmdc.*;<br />

public class CmmdcImpl implements ICmmdc{<br />

public long cmmdc(long a,long b){. . .}<br />

public static void main(String args[]) {<br />

String host="localhost";<br />

int port=1099;<br />

if (args.length>0)<br />

host=args[0];<br />

if (args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

try {<br />

CmmdcImpl obj=new CmmdcImpl();<br />

ICmmdc stub=(ICmmdc)UnicastRemoteObject.exportObject(obj,0);<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

registry.bind("CmmdcServer",stub);<br />

System.out.println("CmmdcServer ready");<br />

}<br />

catch (Exception e) {<br />

System.out.println("CmmdcImpl err: " + e.getMessage());<br />

}<br />

}<br />

}<br />

Textul sursă al programului server CmmdcImpl.java se ret¸ine în catalogul<br />

\s\src\server<br />

4. Compilarea programului server


46 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

<br />

Server actions <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

5. Crearea obiectului registry ¸si lansarea serverului în lucru se obt¸ine cu fi¸sierul<br />

<strong>de</strong> comenzi bat<br />

cd \s\public\classes<br />

start rmiregistry<br />

cd \s\public\classes<br />

start java -cp /s/public/classes -Djava.rmi.server.co<strong>de</strong>base=<br />

file:/s/public/classes/ server.CmmdcImpl<br />

Parametrul -Djava.rmi.server.co<strong>de</strong>base fixează locat¸ia interfet¸ei la distant¸ă<br />

<strong>de</strong> pe calculatorul server.<br />

6. Realizarea programului client<br />

package client;<br />

import cmmdc.*;


3.2. CREAREA UNEI APLICAT¸ II RMI 47<br />

import java.rmi.registry.*;<br />

import java.util.Scanner;<br />

public class CmmdcClient {<br />

public static void main(String args[]) {<br />

String host="localhost";<br />

int port=1099;<br />

if (args.length>0)<br />

host=args[0];<br />

if (args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("Primul numar :");<br />

long m=Long.parseLong(scanner.next());<br />

System.out.println("Al doilea numar :");<br />

long n=Long.parseLong(scanner.next());<br />

long x=0;<br />

try {<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

ICmmdc obj=(ICmmdc)registry.lookup("CmmdcServer");<br />

x=obj.cmmdc(m,n);<br />

System.out.println("Cmmdc="+x);<br />

}<br />

catch (Exception e) {<br />

System.out.println("CmmdcClient exception: "+e.getMessage());<br />

}<br />

}<br />

}<br />

Sursa programului client CmmdcClient.java apart¸ine catalogului<br />

\c\src\client<br />

7. Compilarea programului client ¸si lansarea acestuia în execut¸ie.<br />

<br />

Client actions <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


48 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

3.3 Tipare <strong>de</strong> programare<br />

3.3.1 Fabrica <strong>de</strong> obiecte<br />

Tiparul fabrica <strong>de</strong> obiecte va permite crearea <strong>din</strong>amică a unui server, fapt care<br />

nu este posibil pe schema prezentată în paragraful prece<strong>de</strong>nt. Prin aceea schemă,<br />

se va crea o clasă - fabrica <strong>de</strong> obiecte - care implementează câte o metodă get, ce<br />

returnează o instant¸ă <strong>de</strong> server. Aceste meto<strong>de</strong> sunt <strong>de</strong>clarate într-o interfat¸ă la<br />

distant¸ă. Un client, apelând o asemenea metodă, va instant¸ia serverul dorit ¸si va<br />

obt¸ine stub-ul corespunzător.<br />

Programarea unui server care poate fi lansat <strong>din</strong>amic trebuie să satisfacă<br />

restrict¸iile:<br />

• Clasa serverului extin<strong>de</strong> clasa UnicastRemoteObject.<br />

• Există un constructor fără argumente ce aruncă except¸ia java.rmi.Remote<br />

Exception.<br />

Pentru exemplificarea tehnicii <strong>de</strong> lucru reluăm aplicat¸ia pentru calculul celui<br />

mai mare divizor comun a două numere naturale, consi<strong>de</strong>rând interfat¸a<br />

package cmmdc0;<br />

import java.rmi.*;<br />

public interface ICmmdc0 extends Remote{<br />

public long compute(long m,long n) throws RemoteException;<br />

}<br />

Aceasă interfat¸ă va fi implementată <strong>de</strong> clasa ServerCmmdc. Metoda compute<br />

este o metodă <strong>de</strong> calcul a celui mai mare divizor comun a două numere.<br />

Obiecte <strong>de</strong> tip ServerCmmdc se crează, <strong>de</strong> la distant¸ă prin fabrica <strong>de</strong> obiecte<br />

FabObiecte, o clasă ce implementează interfat¸a


3.3. TIPARE DE PROGRAMARE 49<br />

package cmmdc0;<br />

import java.rmi.*;<br />

public interface IFabObiecte extends Remote{<br />

public ICmmdc0 getCmmdc() throws RemoteException;<br />

}<br />

Codurile claselor ServerCmmdc ¸si FabObiecte sunt<br />

package cmmdc0;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

import java.io.*;<br />

import java.util.*;<br />

public class ServerCmmdc extends UnicastRemoteObject implements ICmmdc0{<br />

public ServerCmmdc()throws RemoteException{}<br />

public long compute(long m,long n)throws RemoteException{<br />

. . .<br />

}<br />

}<br />

respectiv<br />

package cmmdc0;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

import java.rmi.registry.*;<br />

public class FabObiecte implements IFabObiecte{<br />

public ICmmdc0 getCmmdc() throws RemoteException{<br />

ServerCmmdc cmmdc=new ServerCmmdc();<br />

return cmmdc;<br />

}<br />

public static void main(String args[]){<br />

String host="localhost";<br />

int port=1099;<br />

if(args.length>0)<br />

host=args[0];<br />

if(args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

try{<br />

FabObiecte obj=new FabObiecte();<br />

IFabObiecte stub=(IFabObiecte)UnicastRemoteObject.exportObject(obj,0);<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

registry.bind("ObjectFactory",stub);<br />

System.out.println("ObjectFactory ready");<br />

}<br />

catch(Exception e){<br />

System.out.println("Factory err "+e.getMessage());<br />

}<br />

}<br />

}<br />

Aplicat¸ia client se compune <strong>din</strong> două clase


50 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

1. RemoteClient<br />

Clientul obt¸ine stub-ul serviciului, prin intermediul căruia apelează metada<br />

getCmmdc() a fabricii <strong>de</strong> obiecte, obt¸inând un obiect remote <strong>de</strong> tip Server-<br />

Cmmdc, ce implementează interfat¸a la distant¸ă ICmmdc0.<br />

package cmmdc0;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

import java.rmi.registry.*;<br />

public class RemoteClient extends UnicastRemoteObject{<br />

ICmmdc0 remote=null;<br />

public RemoteClient() throws RemoteException{}<br />

public RemoteClient(String host,int port)throws RemoteException{<br />

IFabObiecte fabrica=null;<br />

try{<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

IFabObiecte obj=(IFabObiecte)registry.lookup("ObjectFactory");<br />

remote=obj.getCmmdc();<br />

}<br />

catch(Exception e){<br />

System.out.println("ClientException: "+e.getMessage());<br />

}<br />

}<br />

}<br />

2. ClientCmmdc0<br />

Apelează metoda compute a obiectului remote.<br />

package cmmdc0;<br />

import java.util.Scanner;<br />

public class ClientCmmdc0{<br />

public static void main(String args[]){<br />

String host="localhost";<br />

int port=1099;<br />

if(args.length>0)<br />

host=args[0];<br />

if(args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

Scanner scanner=new Scanner(System.in);<br />

try{<br />

RemoteClient ct=new RemoteClient(host,port);<br />

System.out.println("m=");<br />

long m=scanner.nextLong();<br />

System.out.println("n=");<br />

long n=scanner.nextLong();<br />

long x=ct.remote.compute(m,n);<br />

System.out.println("Cmmdc="+x);<br />

}<br />

catch(Exception e){


3.3. TIPARE DE PROGRAMARE 51<br />

System.out.println("ClientException: "+e.getMessage());<br />

}<br />

System.exit(0);<br />

}<br />

}<br />

3.3.2 Apeluri inverse – Callback<br />

Se nume¸ste apel invers apelarea <strong>de</strong> către programul server a unei meto<strong>de</strong> a<br />

clientului.<br />

În RMI realizarea unui apel invers presupune:<br />

1. <strong>de</strong>finirea unei interfet¸e la distant¸ă ce va fi implementat <strong>de</strong> programul client;<br />

2. programul client ce implementează interfat¸a extin<strong>de</strong> clasa UnicastRemote<br />

Object ¸si are un constructor ce aruncă o except¸ie java.rmi.RemoteException.<br />

Extin<strong>de</strong>m aplicat¸ia anterioară cu posibilitatea suplimentară a serverului (Server-<br />

Cmmdc) <strong>de</strong> a alege metoda <strong>de</strong> calcul a celui mai mare divizor comun <strong>din</strong>tre<br />

varianta nerecursivă ¸si cea recursivă a algorimului lui Euclid.<br />

Extin<strong>de</strong>m interfat¸a ICmmdc0 cu metoda<br />

public void setMethod(ICallbackCmmdc obj)throws RemoteException;<br />

package cmmdc0;<br />

import java.rmi.*;<br />

public interface ICmmdc0 extends Remote{<br />

public long compute(long m,long n) throws RemoteException;<br />

public void setMethod(ICallbackCmmdc obj)throws RemoteException;<br />

}<br />

un<strong>de</strong> ICallbackCmmdc este interfat¸a<br />

package cmmdc0;<br />

import java.rmi.*;<br />

public interface ICallbackCmmdc extends Remote{<br />

public String getMethod() throws RemoteException;<br />

}<br />

ce va fi implementată în clasa RemoteClient.<br />

Programul ServerCmmdc <strong>de</strong>vine<br />

package cmmdc0;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

import java.io.*;<br />

public class ServerCmmdc extends UnicastRemoteObject implements ICmmdc0{<br />

private String method=null;<br />

public ServerCmmdc()throws RemoteException{}<br />

public long compute(long m,long n){


52 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

long x=0;<br />

if(method.equals("NERECURSIV"))<br />

x=nerecursiv(m,n);<br />

if(method.equals("RECURSIV"))<br />

x=recursiv(m,n);<br />

return x;<br />

}<br />

public void setMethod(ICallbackCmmdc obj)throws RemoteException{<br />

method=obj.getMethod();<br />

}<br />

private long recursiv(long a,long b){<br />

if (a==b)<br />

return a;<br />

else<br />

if (a


3.4. OBIECTE ACTIVABILE LA DISTANT¸ Ă 53<br />

String method=null;<br />

if(x==1)<br />

method="NERECURSIV";<br />

else<br />

method="RECURSIV";<br />

return method;<br />

}<br />

public RemoteClient(String host,int port)throws RemoteException{<br />

IFabObiecte fabrica=null;<br />

try{<br />

Registry registry=LocateRegistry.getRegistry(host,port);<br />

IFabObiecte obj=(IFabObiecte)registry.lookup("ObjectFactory");<br />

remote=obj.getCmmdc();<br />

}<br />

catch(Exception e){<br />

System.out.println("ClientException: "+e.getMessage());<br />

}<br />

}<br />

}<br />

¸si<br />

package cmmdc0;<br />

import java.util.Scanner;<br />

public class ClientCmmdc0{<br />

public static void main(String args[]){<br />

String host="localhost";<br />

int port=1099;<br />

if(args.length>0)<br />

host=args[0];<br />

if(args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

Scanner scanner=new Scanner(System.in);<br />

try{<br />

RemoteClient ct=new RemoteClient(host,port);<br />

ct.remote.setMethod(ct);<br />

System.out.println("m=");<br />

long m=scanner.nextLong();<br />

System.out.println("n=");<br />

long n=scanner.nextLong();<br />

long x=ct.remote.compute(m,n);<br />

System.out.println("Cmmdc="+x);<br />

}<br />

catch(Exception e){<br />

System.out.println("ClientException: "+e.getMessage());<br />

}<br />

System.exit(0);<br />

}<br />

}<br />

3.4 Obiecte activabile la distant¸ă<br />

O instant¸ă a clasei UnicastRemoteObject reprezintă un obiect la distant¸ă<br />

care rulează în permanent¸ă, folosind resursele ma¸sinii server.


54 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

Începând cu versiunea JDK 1.2, prin întroducerea clasei java.rmi.activation.Activatable<br />

¸si a programului rmid (...\jdk...\bin\rmid.exe) se pot crea<br />

programe care înregistrează informat¸ii <strong>de</strong>spre obiecte la distant¸ă ce vor fi create<br />

¸si executate la cerere.<br />

Invocarea <strong>de</strong> la distant¸ă a unei meto<strong>de</strong> apart¸inând unui asemenea obiect are<br />

ca efect activarea obiectului.<br />

Pe fiecare ma¸sină virtuală Java există un grup <strong>de</strong> activare (activation group),<br />

care realizează activarea. Activarea este făcută <strong>de</strong> un activator. Un activator<br />

cont¸ine o tabelă care face legătura <strong>din</strong>tre clasa obiectului cu URL-ul acestuia ¸si<br />

eventual, cu date necesare init¸ializării obiectului. Atunci când activatorul constată<br />

că nu există un obiect referit, face apel la grupul <strong>de</strong> activare care va produce<br />

activarea obiectului.<br />

Din punctul <strong>de</strong> ve<strong>de</strong>re al clientului utilizarea mecanismului <strong>de</strong> activare la<br />

distant¸ă nu implică modificări. Modificările intervin numai <strong>din</strong> punctul <strong>de</strong> ve<strong>de</strong>re<br />

al serverului ¸si al înregistrării sale.<br />

Reluăm aplicat¸ia <strong>de</strong>zvoltată la începutul capitolului, privind calculul celui<br />

mai mare divizor comun a două numere naturale.<br />

Aplicat¸ia server este compusă <strong>din</strong> două clase<br />

1. o clasa ce implementează interfat¸a ICmmdc : CmmdcActivabil;<br />

2. clasa Setup, cu metoda main, care face posibilă mecanismul <strong>de</strong> activare<br />

¸si înscrie serviciul în registry. Această clasă este preluată <strong>din</strong> tutorialul<br />

<strong>de</strong>dicat activării a documentat¸iei ce însot¸e¸ste distribut¸ia Java.<br />

Clasa ce implementează interfat¸a la distant¸ă trebuie<br />

1. să extindă clasa Activatable;<br />

2. să aibă un constructor ce are doi parametrii<br />

(a) un i<strong>de</strong>ntificator al grupului <strong>de</strong> activare, <strong>de</strong> tip ActivationID, utilizat<br />

<strong>de</strong> <strong>de</strong>monul <strong>de</strong> activare rmid;<br />

(b) un obiect <strong>de</strong> tip MarchalledObject cu date <strong>de</strong> init¸ializare a obiectului<br />

activabil. În cazul nostru, acest parametru nu va fi folosit.<br />

Codul sursă al clasei CmmdcActivabil este<br />

package acmmdc;<br />

import java.rmi.*;<br />

import java.rmi.activation.*;<br />

import cmmdc.*;<br />

public class CmmdcActivabil extends Activatable implements ICmmdc{<br />

public CmmdcActivabil(ActivationID id,MarshalledObject data) throws RemoteException{<br />

super(id, 0);


3.4. OBIECTE ACTIVABILE LA DISTANT¸ Ă 55<br />

}<br />

public long cmmdc(long m,long n){. . .}<br />

}<br />

Clasa Setup necesită o serie <strong>de</strong> date furnizare ca proprietăt¸i:<br />

1. drepturile <strong>de</strong> securitate ale grupului <strong>de</strong> activare<br />

myactivation.policy=group.policy;<br />

cu cont¸inutul<br />

grant co<strong>de</strong>Base "${myactivation.impl.co<strong>de</strong>base}" {<br />

// permission to read and write object’s file<br />

permission java.io.FilePermission "${myactivation.file}","read,write";<br />

// permission to listen on an anonymous port<br />

permission java.net.SocketPermission "*:1024-","accept";<br />

};<br />

2. java.class.path=no.classpath<br />

ceea ce previne grupul <strong>de</strong> activare să încarce o clasă <strong>din</strong> classpath-ul local;<br />

3. localizarea (URL) clasei ce implementează interfat¸a<br />

myactivation.impl.co<strong>de</strong>base;<br />

4. localizarea unui fi¸sier cu date <strong>de</strong> init¸ializare a obiectului activabil<br />

myactivation.file;<br />

5. numele sub care înregistrează serviciul în registry<br />

myactivation.name.<br />

Programul Setup realizează:<br />

1. Construirea unui <strong>de</strong>scriptor al grupului <strong>de</strong> activare. Grupul <strong>de</strong> activare este<br />

un container ce gestionează obiectele activabile cont¸inute.<br />

2.<br />

Înregistrarea <strong>de</strong>scriptorului grupului <strong>de</strong> activare ¸si obt¸inerea unui i<strong>de</strong>ntificator<br />

al grupului <strong>de</strong> activare.<br />

3. Construirea <strong>de</strong>scriptorului <strong>de</strong> activare. Trebuie cunoscute<br />

• i<strong>de</strong>ndificatorul grupului <strong>de</strong> activare;<br />

• numele clasei ce implementează interfat¸a la distant¸ă;<br />

• localizarea (URL) clasei ce implementează interfat¸a la distant¸ă;


56 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

4.<br />

5.<br />

• obiectul <strong>de</strong> tip MarchalledObject, cu datele <strong>de</strong> init¸ializare a obiectului<br />

activabil.<br />

Înregistrarea <strong>de</strong>scriptorului <strong>de</strong> activare, în urma căreia se obt¸ine stub-ul<br />

obiectului activabil.<br />

Înregistrarea stub-ului împreună cu numele serviciului în registry.<br />

Codul clasei setup este<br />

package acmmdc;<br />

import java.rmi.*;<br />

import java.rmi.activation.*;<br />

import java.rmi.registry.*;<br />

import java.util.Properties;<br />

public class Setup{<br />

private Setup() {}<br />

public static void main(String[] args) throws Exception {<br />

// Argumentul liniei <strong>de</strong> comanda<br />

String implClass = "";<br />

if (args.length < 1) {<br />

System.err.println("usage: java [options] examples.activation.Setup ");<br />

System.exit(1);<br />

}<br />

else {<br />

implClass = args[0];<br />

}<br />

// Construirea <strong>de</strong>scriptorului grupului <strong>de</strong> activare<br />

String policy=System.getProperty("myactivation.policy","group.policy");<br />

String implCodbase=System.getProperty("myactivation.impl.co<strong>de</strong>base");<br />

String filename=System.getProperty("myactivation.file", "");<br />

Properties props = new Properties();<br />

props.put("java.security.policy", policy);<br />

props.put("java.class.path", "no_classpath");<br />

props.put("myactivation.impl.co<strong>de</strong>base", implCo<strong>de</strong>base);<br />

if (filename != null && !filename.equals("")) {<br />

props.put("myactivation.file", filename);<br />

}<br />

ActivationGroupDesc groupDesc = new ActivationGroupDesc(props, null);<br />

// Inregistrarea grupului <strong>de</strong> activare pentr obtinerea<br />

// i<strong>de</strong>ntificatorului <strong>de</strong> activare<br />

ActivationGroupID groupID=ActivationGroup.getSystem().registerGroup(groupDesc);<br />

System.err.println("Activation group <strong>de</strong>scriptor registered.");<br />

// Construirea <strong>de</strong>scriptorului <strong>de</strong> activare<br />

MarshalledObject data = null;<br />

if (filename != null && !filename.equals("")) {<br />

data = new MarshalledObject(filename);<br />

}


3.4. OBIECTE ACTIVABILE LA DISTANT¸ Ă 57<br />

ActivationDesc <strong>de</strong>sc=new ActivationDesc(groupID,implClass,implCo<strong>de</strong>base,data);<br />

// Inregistrarea <strong>de</strong>scriptorului <strong>de</strong> activare<br />

Remote stub = Activatable.register(<strong>de</strong>sc);<br />

System.err.println("Activation <strong>de</strong>scriptor registered.");<br />

// Inregistrarea serviciului in registry<br />

String name = System.getProperty("myactivation.name");<br />

LocateRegistry.getRegistry().rebind(name, stub);<br />

System.err.println("Stub bound in registry.");<br />

}<br />

}<br />

Sursele celor două programe CmmdcActivabil.java ¸si respectiv Setup.java<br />

sunt în catalogul \c\src\acmmdc.<br />

Lansarea serverului în execut¸ie constă <strong>din</strong><br />

1. Pornirea <strong>de</strong>mon-ului rmid<br />

start rmid -J-Djava.security.policy=rmid.policy<br />

-J-Dmyactivation.policy=group.policy<br />

un<strong>de</strong> rmid.policy este<br />

grant {<br />

// allow activation groups to use certain system properties<br />

permission com.sun.rmi.rmid.ExecOptionPermission<br />

"-Djava.security.policy=${myactivation.policy}";<br />

permission com.sun.rmi.rmid.ExecOptionPermission<br />

"-Djava.class.path=no_classpath";<br />

permission com.sun.rmi.rmid.ExecOptionPermission<br />

"-Dmyactivation.impl.co<strong>de</strong>base=*";<br />

permission com.sun.rmi.rmid.ExecOptionPermission<br />

"-Dmyactivation.file=*";};<br />

iar group.policy are codul<br />

grant co<strong>de</strong>Base "${myactivation.impl.co<strong>de</strong>base}" {<br />

// permission to read and write object’s file<br />

permission java.io.FilePermission "${myactivation.file}","read,write";<br />

// permission to listen on an anonymous port<br />

permission java.net.SocketPermission "*:1024-","accept";<br />

};<br />

2. Pornirea registry-ului<br />

start rmiregistry<br />

3. Lansarea programului Setup


58 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

set classpath=\s\public\classes\cmmdc.jar;\s\public\classes<br />

java -Djava.rmi.server.co<strong>de</strong>base=file:/s/public/classes/<br />

-Dmyactivation.impl.co<strong>de</strong>base=file:/s/public/classes/<br />

-Dmyactivation.name=CmmdcServer<br />

-Dmyactivation.file=""<br />

-Dmyactivation.policy=group.policy<br />

acmmdc.Setup acmmdc.CmmdcActivabil<br />

Localizarea (URL) interfet¸ei la distant¸ă se precizează prin<br />

java.rmi.server.co<strong>de</strong>base;<br />

Drept client se utilizează programul realizat în sect¸iunea 3.1.<br />

3.5 RMI ¸si sistemul CORBA<br />

Ret¸elele <strong>de</strong> calculatoare sunt eterogene în timp ce majoritatea interfet¸elor <strong>de</strong><br />

programare a aplicat¸iilor sunt orientate spre platforme omogene.<br />

Pentru a orienta ¸si facilita integrarea unor sisteme <strong>de</strong>zvoltate separat, într-un<br />

singur mediu distribuit eterogen, OMG (Object Management Group – consort¸iu<br />

cuprinzând peste 800 <strong>de</strong> firme) a elaborat standardul CORBA (Common Object<br />

Request Brocker Arhitecture): un cadru <strong>de</strong> <strong>de</strong>zvoltare a aplicat¸iilor distribuite în<br />

medii eterogene.<br />

La CORBA au a<strong>de</strong>rat toate marile firme <strong>de</strong> software - cu exceptia Microsoft,<br />

firmă care a <strong>de</strong>zvoltat propriul său mo<strong>de</strong>l DCOM (Distributed Component Object<br />

Mo<strong>de</strong>l), incompatibil CORBA.<br />

CORBA cont¸ine programe client care utilizează diferite obiecte distribuite în<br />

sistem. Deoarece în multe sisteme <strong>de</strong> operare prelucrările trebuie să evolueze într-<br />

un proces, orice obiect trebuie să evolueze într-un proces.<br />

În alte cazuri, obiectele<br />

pot evolua în fire <strong>de</strong> execut¸ie sau în biblioteci dll. CORBA omogenizează aceste<br />

posibilităt¸i prin precizarea că obiectele există în servere. Fiecare obiect este<br />

asociat cu un singur server.<br />

Interconectarea obiectelor. Implementarea ¸si localizarea unui obiect sunt<br />

ascunse clientului. Comunicarea între client ¸si obiect este facilitată <strong>de</strong> Object<br />

Request Brocker (ORB) – care permite obiectelor să se regăseacă unele pe altele<br />

în ret¸ea. El ajută obiectele să facă cereri ¸si să primească răspunsuri <strong>de</strong> la alte<br />

obiecte aflate în ret¸ea. Acestea se <strong>de</strong>sfă¸soară transparent pentru client – care nu<br />

¸stie un<strong>de</strong> este localizat obiectul, care este mecanismul utilizat pentru a comunica<br />

cu el, cum este activat sau memorat acesta.<br />

ORB este un pachet <strong>de</strong> servicii, in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> aplicat¸ii, dar care permit<br />

aplicat¸iilor să interact¸ioneze prin ret¸ea. ORB face parte <strong>din</strong> middleware – un<br />

intermediar între softul <strong>de</strong> ret¸ea ¸si cel <strong>de</strong> aplicat¸ie.


3.6. RMI-IIOP 59<br />

Un ORB se poate executa local pe un singur calculator sau poate fi conectat<br />

cu oricare alt ORB <strong>din</strong> Internet, folosind protocolul IIOP -- Internet Inter<br />

ORB Protocol, <strong>de</strong>finit <strong>de</strong> CORBA 2 .<br />

CORBA face o separare între interfat¸a unui obiect ¸si implementarea sa ¸si<br />

folose¸ste un limbaj neutru pentru <strong>de</strong>finirea interfet¸elor: IDL -- Interface Definition<br />

Language.<br />

IDL permite realizarea <strong>de</strong>scrierii <strong>de</strong> interfet¸e in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> limbajul <strong>de</strong> programare<br />

¸si <strong>de</strong> sistemul <strong>de</strong> operare folosit.<br />

Firma SUN a <strong>de</strong>zvoltat o solut¸ie prin care programele RMI pot fi adaptate<br />

pentru a putea accesa obiecte CORBA. Aceasta este cunoscută sub numele<br />

<strong>de</strong> solut¸ia RMI-IIOP, concretizată printr-o serie <strong>de</strong> pachete <strong>din</strong> distribut¸ia<br />

JDK. În acest fel nu mai este necesar utilizarea limbajului IDL pentru <strong>de</strong>scrierea<br />

interfet¸elor la distant¸ă.<br />

3.6 RMI-IIOP<br />

Instrumente necesare utilizării solut¸iei RMI-IIOP:<br />

• compilatorul rmic<br />

Opt¸iunea -iiop genereaza stub-ul ¸si legătura (tie) <strong>din</strong> partea serverului.<br />

Cu opt¸iunea -d se specifică catalogul în care aceste fi¸siere sunt scrise.<br />

• serverul care asigură regăsirea resurselor CORBA. Acest server se lansează<br />

în execut¸ie prin<br />

start orbd -ORBInitialPort [port]<br />

3.6.1 Transformarea unui program RMI într-un program RMI-<br />

IIOP<br />

Exemplificăm prin aplicat¸ia care implementează un serviciu <strong>de</strong> calcul a celui<br />

mai mare divizor comun a două numere naturale. Etapele realizării aplicat¸iei<br />

sunt:<br />

1. Elaborarea interfet¸ei este i<strong>de</strong>ntică cu cea a aplicat¸iei RMI.<br />

2. Implementarea interfet¸ei<br />

package cmmdciiop;<br />

import javax.rmi.PortableRemoteObject;<br />

import cmmdc.*;<br />

import java.rmi.*;<br />

// Se extin<strong>de</strong> clasa PortableRemoteObject


60 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

// si nu UnicastRemoteObject<br />

public class CmmdcImpl extends PortableRemoteObject implements ICmmdc{<br />

// Constructorul clasei<br />

public CmmdcImpl() throws RemoteException {}<br />

public long cmmdc(long a,long b){. . .}<br />

}<br />

3. Realizarea programului server.<br />

package cmmdciiop;<br />

import javax.naming.InitialContext;<br />

import javax.naming.Context;<br />

public class CmmdcServer {<br />

public static void main(String[] args) {<br />

try {<br />

// 1: Crearea unei instante CmmdcImpl<br />

CmmdcImpl cmmdcRef = new CmmdcImpl();<br />

// 2: Inregistrarea unei referinte a serviciului<br />

// utilizand JNDI API<br />

Context initialNamingContext = new InitialContext();<br />

initialNamingContext.rebind("CmmdcService", cmmdcRef );<br />

System.out.println("Cmmdc Server: Ready...");<br />

}<br />

catch (Exception e) {<br />

System.out.println("CmmdcServer: " + e.getMessage());<br />

}<br />

}<br />

}<br />

4. Compilarea programelor CmmdcImpl.java ¸si CmmdcServer.java.<br />

5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunzător interfet¸ei<br />

ICmmdc ¸si a fi¸sierului Tie cmmdciiop. CmmdcImpl Tie.class corespunzător<br />

clasei CmmdcImpl. Acestea se obt¸in rulând utilitarul rmic - <strong>din</strong> distrubut¸ia<br />

Java – cu opt¸iunea -iiop<br />

rmic -iiop cmmdciiop.CmmdcImpl<br />

6. Pornirea serverului CORBA <strong>de</strong> regăsire a serviciilor<br />

start orbd -ORBInitialPort 1050<br />

7. Lansarea serverului în execut¸ie. Trebuie fixate proprietăt¸ile<br />

java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory<br />

java.naming.provi<strong>de</strong>r.url=iiop://localhost:1050


3.6. RMI-IIOP 61<br />

Cu except¸ia pct. 6, activităt¸ile legate <strong>de</strong> server se obt¸in cu fi¸sierul ant-build<br />

<br />

Server actions <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


62 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

8. Editarea programului client.<br />

package cmmdciiop;<br />

import java.rmi.*;<br />

import java.net.MalformedURLException;<br />

import javax.rmi.*;<br />

import javax.naming.*;<br />

import cmmdc.*;<br />

import java.util.Scanner;<br />

public class CmmdcClient {<br />

public static void main( String args[] ) {<br />

String host="localhost";<br />

int port=1099;<br />

if (args.length>0)<br />

host=args[0];<br />

if (args.length>1)<br />

port=Integer.parseInt(args[1]);<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("Primul numar :");<br />

long m=Long.parseLong(scanner.next());<br />

System.out.println("Al doilea numar :");<br />

long n=Long.parseLong(scanner.next());<br />

long x=0;<br />

Context ic;<br />

Object objref;<br />

ICmmdc obj;<br />

try {<br />

ic = new InitialContext();<br />

// 1. Obtinerea unei referinte <strong>de</strong> la serviciul CORBA<br />

// prin apel JNDI.<br />

objref = ic.lookup("CmmdcService");<br />

System.out.println("Client: Obtained a ref. to Cmmdc server.");<br />

// 2. Asocierea referintei la serviciu cu interfata<br />

// si invocarea meto<strong>de</strong>i<br />

obj = (ICmmdc) PortableRemoteObject.narrow(objref,ICmmdc.class);<br />

x=obj.cmmdc(m,n);<br />

System.out.println("Cmmdc="+x);<br />

}<br />

catch( Exception e ) {<br />

System.err.println( "Exception " + e.getMessage());<br />

}<br />

}<br />

}<br />

9. Compilarea ¸si lansarea clientului în execut¸ie. Clientul trebuie să dispună<br />

<strong>de</strong> fi¸sierul stub (cmmdc. ICmmdc Stub.class) ¸si bineînt¸eles <strong>de</strong> interfat¸a<br />

ICmmdc.jar. La apelarea clientului trebuie fixate proprietăt¸ile<br />

java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory<br />

java.naming.provi<strong>de</strong>r.url=iiop://localhost:1050


3.6. RMI-IIOP 63<br />

Fi¸sierul buildfile pentru executarea clientului:<br />

<br />

Client actions <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


64 CAPITOLUL 3. PROGRAMARE DISTRIBUITĂ CU RMI<br />

<br />

<br />

<br />

<br />

<br />


Capitolul 4<br />

Elemente <strong>de</strong> programare<br />

distribuită prin CORBA<br />

4.1 Sistemul CORBA<br />

Introdus ¸si prezentat în capitolul Programare distribuită cu RMI, CORBA face<br />

o separare între interfat¸a unui obiect ¸si implementarea sa ¸si folose¸ste un limbaj<br />

neutru pentru <strong>de</strong>finirea interfet¸elor: IDL -- Interface Definition Language.<br />

O interfat¸ă IDL <strong>de</strong>fine¸ste legătura <strong>din</strong>tre client ¸si server.<br />

Scopul acestei sect¸iuni este prezentarea <strong>de</strong>zvoltării unei aplicat¸ii pe baza unei<br />

interfet¸e bazat pe IDL.<br />

IDL permite realizarea <strong>de</strong>scrierii <strong>de</strong> interfet¸e in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> limbajul <strong>de</strong> programare<br />

¸si <strong>de</strong> sistemul <strong>de</strong> operare folosit.<br />

Pentru <strong>de</strong>zvoltarea aplicat¸iilor în limbajul <strong>de</strong> programare Java, translatarea<br />

interfet¸ei IDL în Java se realizează cu utilitarul idlj <strong>din</strong> distribut¸ia jdk.<br />

Corespon<strong>de</strong>nt¸a între entităt¸ile IDL ¸si Java este dată în Tabelul 4.1<br />

4.2 Aplicat¸ie Java distribuită prin CORBA<br />

Mecanismul care leagă cererea unui client <strong>de</strong> codul serviciului care satisface<br />

cererea poartă numele Portable Object Adapter (POA).<br />

4.2.1 Mo<strong>de</strong>l cu server temporal<br />

Exemplificăm <strong>de</strong>zvoltarea unei aplicat¸ii distribuite CORBA în cazul în care<br />

serviciul pus la dispozit¸ie <strong>de</strong> server este calculul celui mai mare divizor comun a<br />

două numere naturale.<br />

Dezvoltarea unei aplicat¸ii distribuite CORBA cu mediul nativ Java presupune<br />

parcurgerea urmatoarelor pa¸si:<br />

65


66 CAPITOLUL 4. PROGRAMARE DISTRIBUITĂ PRIN CORBA<br />

Tip IDL Tip Java<br />

module package<br />

boolean boolean<br />

char, wchar char<br />

octet byte<br />

string, wstring java.lang.String<br />

short, unsigned short short<br />

long, unsigned long int<br />

long long, unsigned long long long<br />

float float<br />

double double<br />

fixed java.math.BigDecimal<br />

enum, struct, union class<br />

sequence, array array<br />

interface (non-abstract) signature interface,<br />

operations interface,<br />

helper class, hol<strong>de</strong>r class<br />

Any org.omg.CORBA.Any<br />

Table 4.1: Entităt¸i IDL ¸si Java<br />

1. Realizarea interfet¸ei IDL care înseamnă<br />

(a) Editarea programului <strong>de</strong> interfat¸ă:<br />

module CmmdcApp{<br />

interface Cmmdc{<br />

long long cmmdc(in long long a,in long long b);<br />

};<br />

};<br />

Salvăm acest text într-un fi¸sier <strong>de</strong>numit Cmmdc.idl.<br />

Cmmdc va fi numele serviciului căutat <strong>de</strong> un client ¸si implementat <strong>de</strong><br />

server. Serviciul cont¸ine o singură metodă cmmdc.<br />

(b) Translatarea în Java<br />

idlj -fall Cmmdc.idl<br />

Programul idlj crează un subcatalog CmmdcApp cu un pachet Java CmmdcApp<br />

cont¸inând fi¸sierele:<br />

• Cmmdc.java


4.2. APLICAT¸ IE JAVA DISTRIBUITĂ PRIN CORBA 67<br />

• CmmdcPOA.java ;<br />

• CmmdcOperations.java;<br />

• CmmdcStub.java;<br />

• CmmdcHelper.java;<br />

• CmmdcHol<strong>de</strong>r.java.<br />

2. Realizarea programelor server. Punem în evi<strong>de</strong>nt¸a programul servant CmmdcImpl.java<br />

ce implementează interfat¸a Cmmdc.<br />

import CmmdcApp.*;<br />

import org.omg.CORBA.*;<br />

public class CmmdcImpl extends CmmdcPOA {<br />

private ORB orb;<br />

public CmmdcImpl(ORB orb){<br />

this.orb = orb;<br />

}<br />

public long cmmdc(long a,long b){. . .}<br />

}<br />

¸si programul CmmdcServer.java, care înscrie în registrul ORB referint¸ele<br />

servantului. Activităt¸ile ce trebuie întreprinse sunt <strong>de</strong>clarate prin comentarii<br />

în textul sursă al programului<br />

import CmmdcApp.*;<br />

import org.omg.CosNaming.*;<br />

import org.omg.CosNaming.NamingContextPackage.*;<br />

import org.omg.CORBA.*;<br />

import org.omg.PortableServer.*;<br />

public class CmmdcServer {<br />

public static void main(String args[]) {<br />

try{<br />

// crearea si initializarea ORB<br />

ORB orb = ORB.init(args, null);<br />

// obtinerea unei referinte rootpoa si activarea managerului POAManager<br />

POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));<br />

rootpoa.the_POAManager().activate();<br />

// crearea unui servant<br />

CmmdcImpl cmmdcImpl = new CmmdcImpl(orb);<br />

// obtinerea unei referinte a servantului<br />

org.omg.CORBA.Object ref = rootpoa.servant_to_reference(cmmdcImpl);<br />

Cmmdc href = CmmdcHelper.narrow(ref);<br />

// Obtinerea serviciului NameService<br />

org.omg.CORBA.Object objRef =<br />

orb.resolve_initial_references("NameService");


68 CAPITOLUL 4. PROGRAMARE DISTRIBUITĂ PRIN CORBA<br />

NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);<br />

// legarea referintei servantului in serviciul NameService<br />

String name = "CmmdcService";<br />

NameComponent path[] = ncRef.to_name( name );<br />

ncRef.rebind(path, href);<br />

System.out.println("CmmdcServer ready and waiting ...");<br />

// in asteptarea clientilor<br />

orb.run();<br />

}<br />

catch (Exception e) {<br />

System.err.println("ERROR: " + e);<br />

e.printStackTrace(System.out);<br />

}<br />

System.out.println("CmmdcServer Exiting ...");<br />

}<br />

}<br />

3. Realizarea programului client CmmdcClient.java:<br />

import CmmdcApp.*;<br />

import org.omg.CosNaming.*;<br />

import org.omg.CosNaming.NamingContextPackage.*;<br />

import org.omg.CORBA.*;<br />

import java.util.Scanner;<br />

public class CmmdcClient{<br />

static Cmmdc cmmdcImpl;<br />

public static void main(String args[]){<br />

try{<br />

// crearea si initializarea unui reprezentant ORB<br />

ORB orb = ORB.init(args, null);<br />

// obtinerea unei referinte pentru serviciul <strong>de</strong>numirilor<br />

// serviciilor inregistrate<br />

org.omg.CORBA.Object objRef =<br />

orb.resolve_initial_references("NameService");<br />

NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);<br />

// obtinerea unei referinte la serviciul dorit<br />

String name = "CmmdcService";<br />

cmmdcImpl = CmmdcHelper.narrow(ncRef.resolve_str(name));<br />

System.out.println("Obtained a handle on server object: " + cmmdcImpl);<br />

Scanner scanner=new Scanner(System.in);<br />

long m,n;<br />

System.out.println("m=");<br />

m=scanner.nextLong();<br />

System.out.println("n=");<br />

n=scanner.nextLong();<br />

System.out.println("Cmmdc="+cmmdcImpl.cmmdc(m,n));<br />

}<br />

catch (Exception e) {<br />

System.out.println("ERROR : " + e) ;<br />

e.printStackTrace(System.out);


4.2. APLICAT¸ IE JAVA DISTRIBUITĂ PRIN CORBA 69<br />

}<br />

}<br />

}<br />

Programele se compilează<br />

javac CmmdcApp\*.java<br />

4. Pornirea serviciului <strong>de</strong> intregistrare a numelor cu programul orbd.exe <strong>din</strong><br />

distribut¸ia jdk.<br />

start orbd -ORBInitialHost localhost -ORBInitialPort 1050<br />

5. Pornirea programului server prin<br />

start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050<br />

6. Lansarea programului client prin<br />

java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050<br />

4.2.2 Mo<strong>de</strong>l cu server persistent<br />

Se consi<strong>de</strong>ră acea¸si interfat¸ă Cmmdc.idl.<br />

Partea <strong>de</strong> server este alcătuită <strong>din</strong> clasa servant CmmdcImpl.java care implementează<br />

interfat¸a Cmmdc -prezentat în sect¸iunea anterioară ¸si clasa PersistentServer<br />

care asigură<br />

• legătura cu serviciile ORB;<br />

• accesul la clasa servantului.<br />

import java.util.Properties;<br />

import org.omg.CORBA.*;<br />

import org.omg.CosNaming.*;<br />

import org.omg.PortableServer.*;<br />

public class PersistentServer{<br />

public static void main( String args[] ) {<br />

Properties properties = System.getProperties();<br />

properties.put( "org.omg.CORBA.ORBInitialHost","localhost" );<br />

properties.put( "org.omg.CORBA.ORBInitialPort","1050" );<br />

try {<br />

// Pas 1: Instantiere ORB<br />

ORB orb = ORB.init(args, properties);


70 CAPITOLUL 4. PROGRAMARE DISTRIBUITĂ PRIN CORBA<br />

// Pas 2: Instantierea servantului<br />

CmmdcImpl servant = new CmmdcImpl(orb);<br />

// Pas3 3 : Crearea unui obiect POA cu securitatea Persistent Policy<br />

// *******************<br />

// Pas 3-1: Obtinerea radacinii rootPOA<br />

POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));<br />

// Pas 3-2: Create securitatii Persistent Policy<br />

Policy[] persistentPolicy = new Policy[1];<br />

persistentPolicy[0] = rootPOA.create_lifespan_policy(<br />

LifespanPolicyValue.PERSISTENT);<br />

// Pas 3-3: Crearea obiectului POA cu securitatea the Persistent Policy<br />

POA persistentPOA = rootPOA.create_POA("childPOA",null,persistentPolicy );<br />

// Pas 3-4: Activarea managerului PersistentPOA POAManager,<br />

persistentPOA.the_POAManager().activate( );<br />

// ***********************<br />

// Pas 4: Asocierea servantului cu PersistentPOA<br />

persistentPOA.activate_object( servant );<br />

// Pas 5: Fixarea contextului RootNaming si legarea <strong>de</strong> numele servantului<br />

// Numele serviciului ORBD : ’NameService’<br />

// Numele servantului ’PersistentCmmdcServer’<br />

org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService");<br />

NamingContextExt rootContext = NamingContextExtHelper.narrow( obj );<br />

NameComponent[] nc = rootContext.to_name("PersistentCmmdcServer");<br />

rootContext.rebind( nc, persistentPOA.servant_to_reference( servant ) );<br />

// Pas 6: Gata pentru receptia cererilor clientilor<br />

orb.run();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println( "Exception in Persistent Server Startup " + e );<br />

}<br />

}<br />

}<br />

Programul client<br />

import java.util.Properties;<br />

import org.omg.CORBA.*;<br />

import org.omg.CosNaming.*;<br />

import org.omg.PortableServer.POA;<br />

import CmmdcApp.CmmdcHelper;<br />

import CmmdcApp.Cmmdc;<br />

import java.util.Scanner;<br />

public class PersistentClient {<br />

public static void main(String args[]) {<br />

String host="localhost";<br />

String port="1050";<br />

if(args.length>0)<br />

host=args[0];<br />

if(args.length>1)<br />

port=args[1];<br />

try {


4.2. APLICAT¸ IE JAVA DISTRIBUITĂ PRIN CORBA 71<br />

// Pas 1: Initializare ORB<br />

ORB orb = ORB.init(args, null);<br />

// Pas 2: Rezolvarea persistentei<br />

// Serviciul NameService ruleaza pe host cu portul port<br />

// Numele serviciului cerut lui NameService este<br />

// "PersistentCmmdcServer"<br />

org.omg.CORBA.Object obj = orb.string_to_object(<br />

"corbaname::"+host+":"+port+"#PersistentCmmdcServer");<br />

Cmmdc cmmdc=CmmdcHelper.narrow(obj);<br />

// Pas 3: Utilizarea serviciului<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println( "Calling Persistent Server.." );<br />

int m,n,r;<br />

System.out.println("m=");<br />

m=scanner.nextInt();<br />

System.out.println("n=");<br />

n=scanner.nextInt();<br />

System.out.println(cmmdc.cmmdc(m,n));<br />

}<br />

catch ( Exception e ) {<br />

System.err.println( "Exception in PersistentClient.java..." + e );<br />

e.printStackTrace( );<br />

}<br />

}<br />

}<br />

Serverul trebuie să fie pe acela¸si calculator pe care rulează orbd. Executarea<br />

aplicat¸iei presupune:<br />

1. Pornirea serviciului <strong>de</strong> intregistrare a numelor cu programul orbd.exe <strong>din</strong><br />

distribut¸ia jdk.<br />

start orbd -ORBInitialPort 1050 -serverPollingTime 200<br />

2. Activarea serverului:<br />

(a) Se lansează utilitarul servertool<br />

servertool -ORBInitialPort 1050<br />

(b) Se înregistrează serverul împreună cu numele serviciului pe care îl<br />

în<strong>de</strong>pline¸ste:<br />

servertool > register -server PersistentServer<br />

-applicationName PersistentCmmdcServer<br />

-classpath cale_catre_fisierele_server<br />

3. Executarea clientului<br />

java PersistentClient [hostORB [portORB]]


72 CAPITOLUL 4. PROGRAMARE DISTRIBUITĂ PRIN CORBA


Capitolul 5<br />

Mesaje în Java<br />

Comunicat¸ia prin apelul la distant¸ă - inclusiv RMI - este sincron: programul<br />

apelant se blochează ¸si a¸steaptă ca metoda apelată să se termine ¸si să furnizeze<br />

rezultatul cerut. Cu alte cuvinte apelul <strong>de</strong> procedură la distant¸ă cere atât clientului<br />

cât ¸si serverului să fie simultan disponibile.<br />

Comunicat¸iile asincrone între programe permit realizarea unor sisteme <strong>de</strong> programe<br />

cu un grad mult mai scăzut <strong>de</strong> cuplare.<br />

5.1 Java Message Service (JMS)<br />

JMS <strong>de</strong>fine¸ste un cadru <strong>de</strong> programare Java (API) pentru realizarea aplicat¸iilor<br />

bazate pe comunicat¸ii asincrone. Există mai multe implementări JMS, <strong>din</strong>tre care<br />

semnalăm:<br />

• Sun Java System Message Queue a firmei Sun. Versiunea Platform Edition<br />

este gratuită.<br />

• ActiveMQ realizată <strong>de</strong> fundat¸ia apache.<br />

O aplicat¸ie JMS este alcătuită <strong>din</strong><br />

• un furnizor JMS (provi<strong>de</strong>r JMS) : un sistem <strong>de</strong> mesagerie ce implementează<br />

specificat¸iile JMS;<br />

• client JMS : aplicat¸ie Java care trimite ¸si recept¸ionează mesaje;<br />

• mesaje : obiecte utilizate în schimbul <strong>de</strong> informat¸ii <strong>de</strong> client¸i JMS;<br />

• obiecte administrator : obiecte (resurse) create <strong>de</strong> administrator pentru a fi<br />

utilizate <strong>de</strong> client¸ii JMS, precum fabrica <strong>de</strong> conexiuni, obiectele <strong>de</strong>stinat¸ie<br />

împreună cu resursele lor.<br />

73


74 CAPITOLUL 5. MESAJE ÎN JAVA<br />

Mo<strong>de</strong>le <strong>de</strong> comunicat¸ie:<br />

• Comunicat¸ii punctuale : Un mesaj este generat <strong>de</strong> un producător (expeditor)<br />

¸si la care va avea acces un singur consumator (<strong>de</strong>stinatar). Mesajul<br />

este <strong>de</strong>pus într-o coadă, <strong>de</strong> un<strong>de</strong> este preluat <strong>de</strong> către consumatorul care<br />

s-a legat <strong>de</strong> coadă. Dacă <strong>de</strong> coadă nu se leagă nici un consumator, atunci<br />

mesajul este păstrat în coadă.<br />

• Comunicat¸ii axate pe subiect (topic) : Mesajele sunt <strong>de</strong>puse (publicate) în<br />

<strong>de</strong>stinat¸ii specifice subiectului. Consumatorii ce au subscris la acel subiect<br />

au acces la mesajele respective. Mai multi producători pot genera mesaje<br />

specifice unui subiect, mesaje care pot fi accesate <strong>de</strong> consumatorii care au<br />

subscris subiectului.<br />

Structura unui mesaj Un mesaj este alcătuit <strong>din</strong><br />

• Antet (hea<strong>de</strong>r) : cont¸ine informat¸ii pentru i<strong>de</strong>ntificarea <strong>de</strong>stinat¸iei cât ¸si<br />

pentru i<strong>de</strong>ntificarea mesajului.<br />

• Proprietăt¸i : au caracter opt¸ional ¸si sunt sub forma (nume, valoare). Proprietăt¸ile<br />

ajută consumatorii să selecteze mesajele.<br />

• Corpul mesajului : opt¸ional. Potrivit specificat¸iilor JMS există 6 tipuri <strong>de</strong><br />

mesaje.<br />

– Message : mesaj fără corp;<br />

– StreamMessage : corpul mesajului cont¸ine un flux Java <strong>de</strong> date <strong>de</strong> tip<br />

pre<strong>de</strong>finit;<br />

– ByteMessage :<br />

– MapMessage : corpul mesajului cont¸ine o familie <strong>de</strong> perechi (nume,<br />

valoare);<br />

– TextMessage : corpul mesajului cont¸ine un string;<br />

– ObjectMessage : corpul mesajului cont¸ine un obiect serializat.<br />

5.2 Sun Java System Message Queue<br />

Instalarea. Funct¸ie <strong>de</strong> resursa <strong>de</strong>scărcată, în mediul Windows, instalarea<br />

constă <strong>din</strong><br />

• Se <strong>de</strong>zarhivează fi¸sierul mq* *-installer-WINNT.zip ¸si se lansează în execut¸ie<br />

programul <strong>de</strong> instalare.<br />

• Se <strong>de</strong>zarhivează fi¸sierul mq* *-binary-WINNT*.jar ¸si se fixează atributele<br />

fi¸sierului mq\etc\imqenv.conf.


5.3. APACHE ACTIVEMQ 75<br />

Lansarea serviciului JMS. Orice aplicat¸ie JMS necesită funct¸ionarea serviciului<br />

JMS. Serviciul JMS se instalează prin<br />

imqbrokerd -tty<br />

Opt¸iunea -tty are ca efect afi¸sarea mesajelor pe ecran. Funct¸ionarea corectă este<br />

indicată prin mesajul<br />

imqbroker@hostname:7676 ready<br />

Dacă se dore¸ste schimbarea portului atunci se folose¸ste opt¸iunea -port port.<br />

Pe un calculator pot coexista mai multe servicii JMS doar dacă folosesc porturi<br />

distincte ¸si au nume diferite. În acest caz, lansarea unui nou serviciu se face<br />

prin<br />

imqbrokerd -tty -port port -name name<br />

Cu utilitarul imqsvcadmin putem<br />

• <strong>de</strong>zinstala : imqsvcadmin remove<br />

• verifica : imqsvcadmin query<br />

• instala : imqsvcadmin install<br />

serviciul JMS ca serviciu Windows. Dezinstalarea ¸si instalarea are efect odată cu<br />

repornirea calculatorului.<br />

Compilarea ¸si executarea unui program necesită completarea variabilei<br />

sistem classpath cu fi¸sierele<br />

• JMS HOME\lib\jms.jar<br />

• JMS HOME\lib\imq.jar<br />

5.3 Apache ActiveMQ<br />

Instalarea se face <strong>de</strong>zarhivând fi¸sierul <strong>de</strong>scărcat într-un catalog ACTIVEMQ HOME.<br />

Acest fi¸sier este specific sistemului <strong>de</strong> operare utilizat, Windows sau Linux.<br />

Lansarea serverului JMS se obt¸ine prin<br />

set JAVA_HOME=. . .<br />

set ACTIVEMQ_HOME=. . .<br />

set PATH=%ACTIVEMQ_HOME%\bin;%PATH%<br />

activemq<br />

În cazul unui calculator izolat este nevoie <strong>de</strong> instalarea driver-ului Microsoft loopback<br />

Adaptor care sinulează existent¸a funct¸onării unei plăci <strong>de</strong> ret¸ea active.<br />

Distribut¸ia apache-activemq-5.0.0 cont¸ine, ca exemplu, clasa Embed<strong>de</strong>dBroker.java<br />

care lansează serverul JMS în lucru.<br />

Compilarea unui program necesită prezent¸a în variabila <strong>de</strong> sistem classpath<br />

a referint¸ei către fi¸sierul ACTIVEMQ HOME\activemq-all-*.*.*.jar. Pentru execut¸ie,<br />

variabila <strong>de</strong> sistem classpath nevoie să cont¸ină referint¸ele către fi¸sierele jar <strong>din</strong><br />

catalogul ACTIVEMQ HOME\lib.


76 CAPITOLUL 5. MESAJE ÎN JAVA<br />

5.4 Elemente <strong>de</strong> programare - JMS<br />

5.4.1 Trimiterea unui mesaj<br />

Trimiterea unui mesaj necesită:<br />

1. Generarea unei fabrici <strong>de</strong> conexiuni. Fabrica <strong>de</strong> conexiuni este un obiect<br />

administrator. Această operat¸ie este specifică distribut¸iei JMS.<br />

•<br />

În cazul <strong>de</strong> fat¸a folosim obiectele create prin MessageQueue.<br />

Se poate obt¸ine prin<br />

ConnectionFactory cf=<br />

new com.sun.messaging.ConnectionFactory();<br />

Clasa com.sun.messaging.ConnectionFactory cont¸ine metoda<br />

setProperty( String name, String value) prin intermediul căreia<br />

se precizează calculatorul ¸si portul furnizorului <strong>de</strong> servicii JMS, fixând<br />

atributele "imqBrokerHostName" ¸si respectiv "imqBrokerHostPort".<br />

• Utilizând apache-activemq, fabrica <strong>de</strong> conexiuni se obt¸ine prin<br />

org.apache.activemq.ActiveMQConnectionFactory cf=<br />

new org.apache.activemq.ActiveMQConnectionFactory<br />

("tcp://host:61616");<br />

2. Generarea conexiunii.<br />

Se realizează prin<br />

Connection conn=cf.createConnection();<br />

Pentru realizarea acestui obiectiv se utilizează metoda createConnection,<br />

după caz, <strong>din</strong>tr-una <strong>din</strong> clasele<br />

class ConnectionFactory{<br />

Connection createConnection() throws JMSException;<br />

Connection createConnection(String userName,String password)<br />

throws JMSException;<br />

}<br />

class QueueConnectionFactory{<br />

QueueConnection createQueueConnection() throws JMSException;<br />

QueueConnection createQueueConnection(String userName,<br />

String password) throws JMSException;<br />

}<br />

class TopicConnectionFactory{


5.4. ELEMENTE DE PROGRAMARE - JMS 77<br />

}<br />

TopicConnection createTopicConnection() throws JMSException;<br />

TopicConnection createTopicConnection(String userName,<br />

String password) throws JMSException;<br />

un<strong>de</strong> Connection, QueueConnection, TopicConnection sunt interfet¸e.<br />

Amintim următoarele meto<strong>de</strong> ale unei interfet¸e Connection<br />

interface Connection{<br />

Session createSession(boolean transacted,<br />

int acknowledgeMo<strong>de</strong>) throws JMSException;<br />

void start() throws JMSException;<br />

void close() throws JMSException;<br />

}<br />

interface QueueConnection{<br />

QueueSession createQueueSession(boolean transacted,<br />

int acknowledgeMo<strong>de</strong>) throws JMSException;<br />

void start() throws JMSException;<br />

void close() throws JMSException;<br />

}<br />

interface TopicConnection{<br />

TopicSession createTopicSession(boolean transacted,<br />

int acknowledgeMo<strong>de</strong>) throws JMSException;<br />

void start() throws JMSException;<br />

void close() throws JMSException;<br />

}<br />

Un obiect ce implementează interfat¸a Connection asigură legătura clientului<br />

cu furnizorul JMS. Acest obiect este creat <strong>de</strong> fabrica <strong>de</strong> conexiuni.<br />

Un client JMS trebuie să închidă conexiunile create.<br />

Metoda start() asigură pornirea sau repornirea conexiunii în ve<strong>de</strong>rea<br />

recept¸ionării mesajelor sosite.<br />

3. Crearea unei sesiuni <strong>de</strong> lucru se face cu o metodă createSession().<br />

Session session=conn.createSession(false,<br />

Session.AUTO_ACKNOWLEDGE);<br />

Primul argument asigură (true) sau nu (false) caracterul indivizibil al<br />

unităt¸ii <strong>de</strong> lucru, adică al unei sesiuni.<br />

Al doilea argument indică modul <strong>de</strong> confirmare al receptării mesajului.


78 CAPITOLUL 5. MESAJE ÎN JAVA<br />

Un obiect <strong>de</strong> tip Session <strong>de</strong>fine¸ste un context format <strong>din</strong>tr-un singur fir <strong>de</strong><br />

execut¸ie în care are loc producerea ¸si consumul <strong>de</strong> mesaje.<br />

Sunt <strong>de</strong>finite<br />

interface Session{<br />

| MessageProducer createProducer(Destination <strong>de</strong>stination);<br />

| MessageConsumer createConsumer(Destination <strong>de</strong>stination);<br />

| Message createMessage();<br />

| TextMessage createTextMessage();<br />

| TextMessage createTextMessage(String s);<br />

| StreamMessage createStreamMessage();<br />

| MapMessage createMapMessage();<br />

| ObjectMessage createObjectMessage();<br />

| ObjectMessage createObjectMessage(Serializable object);<br />

| BytesMessage createBytesMessage();<br />

| }<br />

|->interface QueueSession{<br />

| QueueSen<strong>de</strong>r createQueueSen<strong>de</strong>r(Queue queue);<br />

| QueueReceiver createQueueReceiver(Queue queue);<br />

| }<br />

|->interface TopicSession{<br />

TopicPublisher createPublisher(Topic topic);<br />

TopicSubscriber createSubscriber(Topic topic);<br />

TopicSubscriber createDurableSubscriber(Topic topic,<br />

String name);<br />

}<br />

4. Generarea obiectului <strong>de</strong>stinat¸ie.<br />

În cazul comunicat¸iilor punctuale obiectul <strong>de</strong>stinat¸ie este <strong>de</strong> tip Queue, iar<br />

crearea se face prin<br />

Destination numeDestinatie=sesssion.createQueue(String numeCoada)<br />

iar pentru comunicat¸ii axate pe subiect obiectul <strong>de</strong>stinat¸ie, <strong>de</strong> tip Topic se<br />

instant¸iază prin<br />

Destination numeDestinatie=sesssion.createTopic(String numeSubiect)<br />

Sunt <strong>de</strong>finite arborescent¸ele:<br />

interface Destination


5.4. ELEMENTE DE PROGRAMARE - JMS 79<br />

|<br />

|->interface Queue<br />

|<br />

|->interface Topic<br />

class Destination implements Destination<br />

|<br />

|->class Queue implements Destination, Queue, Serializable<br />

|<br />

|->class Topic implements Destination, Topic, Serializable<br />

Utilizând Sun Java System Message Queue obiecte <strong>de</strong> tip Queue sau Topic<br />

se pot crea ¸si prin<br />

Queue q=new com.sun.messaging.Queue(String numeCoada);<br />

Topic t=new com.sun.messaging.Topic(String numeSubiect);<br />

5. Generarea producătorului <strong>de</strong> mesaje. Se realizează prin<br />

MessageProducer producer=session.createProducer(obiectDestinatie);<br />

Sunt <strong>de</strong>finite interfet¸ele<br />

interface MessageProducer{<br />

void send(Message mesaj);<br />

}<br />

interface QueueSen<strong>de</strong>r{<br />

void send(Message mesaj);<br />

}<br />

interface TopicPublisher{<br />

void publish(Message mesaj);<br />

}<br />

6. Generarea mesajelor. Un mesaj <strong>de</strong> tip TextMessage se poate crea prin<br />

TextMessage m=session.createTextMessage();<br />

m.setText(string);<br />

7. Expedierea mesajelor se face cu metoda send(...) a producătorului <strong>de</strong><br />

mesaje.


80 CAPITOLUL 5. MESAJE ÎN JAVA<br />

Exemplul 5.4.1 Clasa următoare generează într-un fir <strong>de</strong> execut¸ie, un număr<br />

<strong>de</strong> mesaje <strong>de</strong> tip TextMessage într-o comunicat¸ie punctuală. Sfâr¸situl expedierii<br />

mesajelor se indică prin generarea unui mesaj <strong>de</strong> tip Message. Numărul<br />

mesajelor este indicat <strong>de</strong> un parametru al constructorului.<br />

import javax.jms.*;<br />

public class MsgSen<strong>de</strong>rT extends Thread{<br />

int n;<br />

String queueName;<br />

MsgSen<strong>de</strong>rT(String queueName,int n){<br />

this.queueName=queueName;<br />

this.n=n;<br />

}<br />

public void run(){<br />

try{<br />

// Varianta Sun Message Queue<br />

com.sun.messaging.QueueConnectionFactory cf=<br />

new com.sun.messaging.QueueConnectionFactory();<br />

// setProperty este metoda a clasei com.sun.messaging.QueueConnnectionFactory<br />

// ce implementeaza interfata QueueConnectionFactory<br />

// dar nu este a interfetei QueueConnectionFactory.<br />

//cf.setProperty("imqBrokerHostName","host");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

// Varianta Apache-MessageQueue<br />

// org.apache.activemq.ActiveMQConnectionFactory cf=<br />

// new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");<br />

Connection conn=cf.createConnection();<br />

Session session=conn.createSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination q=session.createQueue(queueName);<br />

MessageProducer producer=session.createProducer(q);<br />

TextMessage m=session.createTextMessage();<br />

for(int i=0;i


5.4. ELEMENTE DE PROGRAMARE - JMS 81<br />

5.4.2 Recept¸ia sincronă a unui mesaj<br />

Primele patru act¸iuni sunt i<strong>de</strong>ntice cu cele <strong>de</strong> la trimiterea unui mesaj, adică<br />

1. Generarea unei fabrici <strong>de</strong> conexiuni.<br />

2. Generarea conexiunii.<br />

3. Crearea unei sesiuni <strong>de</strong> lucru.<br />

4. Generarea obiectului <strong>de</strong>stinat¸ie.<br />

5. Generarea consumatorului <strong>de</strong> mesaje. Se realizează prin<br />

MessageConsumer consumer=session.createConsumer(q);<br />

Sunt <strong>de</strong>finite interfet¸ele<br />

interface MessageConsumer{<br />

| Message receive();<br />

| Message receive(long timeout);<br />

| Message receiveNoWait();<br />

| }<br />

|-> interface QueueReceiver<br />

|<br />

|-> interface TopicSubscriber<br />

6. Recept¸ia mesajelor se face cu una <strong>din</strong> meto<strong>de</strong>le consumatorului <strong>de</strong> mesaje:<br />

• Message receive()<br />

• Message receive(long timeout)<br />

• Message receiveNoWait()<br />

Exemplul 5.4.2 Recept¸ia <strong>de</strong> tip sincron a mesajelor într-un fir <strong>de</strong> execut¸ie este<br />

efectuat <strong>de</strong> clasa următoare:<br />

import javax.jms.*;<br />

public class SyncMsgReceiverT extends Thread{<br />

String queueName;<br />

SyncMsgReceiverT(String queueName){<br />

this.queueName=queueName;<br />

}<br />

public void run(){<br />

try{<br />

// Varianta Sun Message Queue


82 CAPITOLUL 5. MESAJE ÎN JAVA<br />

com.sun.messaging.QueueConnectionFactory cf=<br />

new com.sun.messaging.QueueConnectionFactory();<br />

// setProperty este metoda a clasei QueueConnnectionFactory<br />

// ce implementeaza interfata QueueConnectionFactory<br />

// dar nu este a interfetei.<br />

//cf.setProperty("imqBrokerHostName","host");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

// Varianta Apache-MessageQueue<br />

//org.apache.activemq.ActiveMQConnectionFactory cf=<br />

// new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");<br />

Connection conn=cf.createConnection();<br />

Session session=conn.createSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination q=session.createQueue(queueName);<br />

MessageConsumer consumer=session.createConsumer(q);<br />

conn.start();<br />

Message msg=null;<br />

while((msg=consumer.receive())!=null){<br />

if(msg instanceof TextMessage){<br />

TextMessage m=(TextMessage)msg;<br />

System.out.println(m.getText());<br />

}<br />

else<br />

break;<br />

}<br />

session.close();<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("JMSException : "+e.getMessage());<br />

}<br />

System.out.println("Consumer finished");<br />

}<br />

}<br />

Exemplul 5.4.3 Trimiterea ¸si recept¸ia mesajelor se face prin aplicat¸ia<br />

class MsgHelloT{<br />

public static void main(String[] args){<br />

int n=3;<br />

String queueName="MyQueue";<br />

if(args.length>0)<br />

queueName=args[0];<br />

if(args.length>1)<br />

n=Integer.parseInt(args[1]);<br />

MsgSen<strong>de</strong>rT sen<strong>de</strong>r=new MsgSen<strong>de</strong>rT(queueName,n);<br />

SyncMsgReceiverT receiver =new SyncMsgReceiverT(queueName);<br />

receiver.start();<br />

sen<strong>de</strong>r.start();<br />

}<br />

}<br />

5.4.3 Recept¸ia asincronă a unui mesaj<br />

Recept¸ia asincronă a mesajelor presupune implementarea interfet¸ei<br />

MessageListener ce cont¸ine o singură metodă


5.4. ELEMENTE DE PROGRAMARE - JMS 83<br />

public void onMessage(Message mesaj);<br />

care fixează prelucrarea mesajului.<br />

Metoda MessageConsumer.setMessageListener(MessageListener obj ) fixează<br />

obiectul ce implementează interfat¸a Messagelistener.<br />

Exemplul 5.4.4 În i<strong>de</strong>ea exemplelor anterioare, un consumator <strong>de</strong> tip asincron<br />

al mesajelor este dat în clasa următoare:<br />

import javax.jms.*;<br />

public class AsyncMsgReceiverT extends Thread{<br />

String queueName;<br />

AsyncMsgReceiverT(String queueName){<br />

this.queueName=queueName;<br />

}<br />

public void run(){<br />

try{<br />

// Varianta Sun Message Queue<br />

com.sun.messaging.QueueConnectionFactory cf=<br />

new com.sun.messaging.QueueConnectionFactory();<br />

// setProperty este metoda a clasei QueueConnnectionFactory<br />

// ce implementeaza interfata QueueConnectionFactory<br />

// dar nu este a interfetei.<br />

//cf.setProperty("imqBrokerHostName","host");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

// Varianta Apache-MessageQueue<br />

//org.apache.activemq.ActiveMQConnectionFactory cf=<br />

// new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");<br />

Connection conn=cf.createConnection();<br />

Session session=conn.createSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination q==session.createQueue(queueName);<br />

MessageConsumer consumer=session.createConsumer(q);<br />

TextListener textListener=new TextListener();<br />

consumer.setMessageListener(textListener);<br />

conn.start();<br />

textListener.run();<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

}<br />

System.out.println("Consumer finished");<br />

}<br />

}<br />

import javax.jms.*;<br />

public class TextListener implements MessageListener{<br />

boolean sfarsit=false;<br />

public void onMessage(Message message){<br />

if(message instanceof TextMessage){<br />

TextMessage m=(TextMessage)message;<br />

try{<br />

System.out.println(m.getText());


84 CAPITOLUL 5. MESAJE ÎN JAVA<br />

}<br />

catch(JMSException e){<br />

System.out.println(e.getMessage());<br />

}<br />

}<br />

else<br />

sfarsit=true;<br />

}<br />

public void run(){<br />

while(!sfarsit);<br />

}<br />

}<br />

5.4.4 Publicarea mesajelor<br />

Publicarea mesajelor corespunzătoare unui subiect se face asemănător cu<br />

transmiterea mesajelor în comunicat¸ia punctuală, dar folosind instant¸e ale claselor<br />

<strong>de</strong>dicate acestui tip <strong>de</strong> comunicat¸ie.<br />

Exemplul 5.4.5<br />

import javax.jms.*;<br />

public class MsgPublisherT extends Thread{<br />

int n;<br />

String subiect;<br />

MsgPublisherT(String subiect,int n){<br />

this.n=n;<br />

this.subiect=subiect;<br />

}<br />

public void run(){<br />

try{<br />

// Varianta Sun Message Queue<br />

com.sun.messaging.TopicConnectionFactory cf=<br />

new com.sun.messaging.TopicConnectionFactory();<br />

//cf.setProperty("imqBrokerHostName","host");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

// Varianta Apache-MessageQueue<br />

// org.apache.activemq.ActiveMQConnectionFactory cf=<br />

// new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");<br />

TopicConnection conn=cf.createTopicConnection();<br />

TopicSession session=conn.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination t = session.createTopic(subiect);<br />

MessageProducer producer = session.createProducer(t);<br />

//Topic t=new com.sun.messaging.Topic(subiect);<br />

//TopicPublisher publisher=session.createPublisher(t);<br />

TextMessage m=session.createTextMessage();<br />

for(int i=0;i


5.4. ELEMENTE DE PROGRAMARE - JMS 85<br />

//publisher.publish(m);<br />

}<br />

producer.send(session.createMessage());<br />

//publisher.publish(session.createMessage());<br />

session.close();<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("JMSException : "+e.getMessage());<br />

}<br />

System.out.println("Publisher finished");<br />

}<br />

}<br />

Varianta comentată este o solut¸ie specifică implementării Sun Java System<br />

Message Queue.<br />

5.4.5 Subscrierea ¸si recept¸ia mesajelor<br />

Dacă t este obiectul <strong>de</strong> tip Destination, client¸ii se abonează - subscriu -<br />

unui subiect prin<br />

TopicSubscriber consumer=session.createSubscriber((Topic)t);<br />

Subscrierea este este valabilă atâta timp cât clientul este activ. Pentru a primi<br />

toate mesajele specifice subiectului, chiar ¸si când clientul este inactiv, acesta<br />

trebuie să fie durabil, adică crearea consumatorului să se facă prin<br />

conn.setClientID("myID");<br />

TopicSubscriber consumer=session.createDurableSubscriber((Topic)t,"nameClient");<br />

În ambele cazuri, clientul prime¸ste doar mesajele publicate <strong>din</strong> momentul subscrierii.<br />

Exemplul 5.4.6<br />

import javax.jms.*;<br />

public class MsgSubscriberT extends Thread{<br />

String subiect;<br />

String clientID;<br />

String clientName;<br />

MsgSubscriberT(String subiect,String clientID, String clientName){<br />

this.subiect=subiect;<br />

this.clientID=clientID;<br />

this.clientName=clientName;<br />

}<br />

public void run(){<br />

try{<br />

// Varianta Sun Message Queue<br />

com.sun.messaging.TopicConnectionFactory cf=


86 CAPITOLUL 5. MESAJE ÎN JAVA<br />

new com.sun.messaging.TopicConnectionFactory();<br />

//cf.setProperty("imqBrokerHostName","host");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

// Varianta Apache-MessageQueue<br />

//org.apache.activemq.ActiveMQConnectionFactory cf=<br />

// new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");<br />

TopicConnection conn=cf.createTopicConnection();<br />

conn.setClientID(clientID);<br />

TopicSession session=conn.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination t = session.createTopic(subiect);<br />

TopicSubscriber consumer=session.createDurableSubscriber((Topic)t,clientName);<br />

conn.start();<br />

Message msg=null;<br />

while((msg=consumer.receive())!=null){<br />

if(msg instanceof TextMessage){<br />

TextMessage m=(TextMessage)msg;<br />

System.out.println(clientName+" received : "+m.getText());<br />

}<br />

else<br />

break;<br />

}<br />

session.close();<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("JMSException : "+e.getMessage());<br />

}<br />

}<br />

}<br />

Apelarea celor două activităt¸i se face prin<br />

Exemplul 5.4.7<br />

class MsgPS{<br />

public static void main(String[] args){<br />

String subiect="JMS";<br />

int n=3,noAbonati=3;<br />

if(args.length>0)<br />

subiect=args[0];<br />

if(args.length>1)<br />

n=Integer.parseInt(args[1]);<br />

MsgPublisherT publisher=new MsgPublisherT(subiect,n);<br />

MsgSubscriberT[] abonat=new MsgSubscriberT[noAbonati];<br />

publisher.start();<br />

for(int i=0;i


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 87<br />

5.5 Mesaje SOAP prin Java Message Service<br />

Rezultatele acestei sect¸iuni sunt valabile doar în cazul pachetului Sun Java<br />

System Message Queue.<br />

5.5.1 SOAP<br />

SOAP - Simple Object Access Protocol - este un protocol <strong>de</strong> comunicat¸ii<br />

între aplicat¸ii. În prezent SOAP este protocolul standard pentru servicii Web<br />

prin Internet. SOAP este in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> platforma <strong>de</strong> calcul ¸si <strong>de</strong> limbajul <strong>de</strong><br />

programare.<br />

SOAP se bazează pe XML (eXten<strong>de</strong>d Markup Language) ¸si este un standard<br />

W3C (World Wi<strong>de</strong> Web Consortium).<br />

5.5.2 Mesaje SOAP<br />

Un mesaj SOAP este un document XML constând <strong>din</strong><br />

• o învelitoare (envelope) care poate cont¸ine<br />

• un număr arbitrar <strong>de</strong> antete (hea<strong>de</strong>r);<br />

• un corp (body);<br />

• un număr variabil <strong>de</strong> obiecte ata¸sate (attachments) MIME (Multipurpose<br />

Internet Mail Exchange).<br />

Astfel un mesaj SOAP apare sub forma documentului XML<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Facilităt¸ile Java <strong>de</strong> manipulare a mesajelor SOAP sunt cont¸inute în pachetul<br />

javax.xml.soap.<br />

În acestă sect¸iune vom crea mesaje SOAP, le transformăm în mesaje JMS pe<br />

care le trimitem furnizorului JMS, <strong>de</strong> un<strong>de</strong> un client le recept¸ionează, după care<br />

transformă mesajul JMS în mesaj SOAP ¸si regăse¸ste datele expediate. Solut¸ia<br />

este specifică implementării Sun Java System Message Queue. Pachetul javax.xml.soap<br />

aflat în distribut¸ia jdk cont¸ine resursele necesare programării mesajelor SOAP.


88 CAPITOLUL 5. MESAJE ÎN JAVA<br />

Crearea unui mesaj SOAP<br />

MessageFactory mf=MessageFactory.newInstance();<br />

SOAPMessage soapMsg=mf.createMessage();<br />

Mesajul creat are <strong>de</strong>finită structura <strong>de</strong> bază a mesajului SOAP: invelitoarea,<br />

un antetul ¸si corpul. Aceste elemente pot fi accesate prin<br />

SOAPPart part=soapMsg.getSOAPPart();<br />

SOAPEnvelope envelope=part.getEnvelope();<br />

SOAPHea<strong>de</strong>r hea<strong>de</strong>r=envelope.getHea<strong>de</strong>r();<br />

SOAPBody body=envelope.getBody();<br />

Completarea corpului unui mesaj SOAP<br />

Generăm numele elementului, ”e1” în cazul exemplului,<br />

Name n1=envelope.createName("e1");<br />

În body un element se poate inclu<strong>de</strong>, pe baza numelui creat prin<br />

SOAPElement e1=body.addBodyElement(n1);<br />

În general, un element se inclu<strong>de</strong> în elementul părinte, care pote fi chiar ¸si body,<br />

prin metoda clasei SOAPElement<br />

SOAPElement addChildElement(Name name)<br />

Completăm elementul e1 cu un text: ”primul”, prin<br />

e1.addTextNo<strong>de</strong>("primul");<br />

Exemplul 5.5.1 Mesajul SOAP<br />

<br />

<br />

<br />

<br />

primul<br />

<br />

al treilea<br />

<br />

<br />

<br />

al doilea<br />

<br />

<br />

<br />

se obt¸ine cu programul


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 89<br />

import javax.xml.soap.*;<br />

import java.io.*;<br />

public class MsgSOAP{<br />

public static void main(String[] args){<br />

Name name=null;<br />

try{<br />

MessageFactory mf=MessageFactory.newInstance();<br />

SOAPMessage soapMsg=mf.createMessage();<br />

SOAPPart part=soapMsg.getSOAPPart();<br />

SOAPEnvelope envelope=part.getEnvelope();<br />

SOAPBody body=envelope.getBody();<br />

Name n1=envelope.createName("e1");<br />

SOAPElement e1=body.addBodyElement(n1);<br />

e1.addTextNo<strong>de</strong>("primul");<br />

Name n2=envelope.createName("e2");<br />

SOAPElement e2=body.addBodyElement(n2);<br />

e2.addTextNo<strong>de</strong>("al doilea");<br />

Name n11 =envelope.createName("e11");<br />

SOAPElement e11=e1.addChildElement(n11);<br />

e11.addTextNo<strong>de</strong>("al treilea");<br />

FileOutputStream f=new FileOutputStream("MySOAPMessage.xml");<br />

soapMsg.writeTo(f);<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

}<br />

}<br />

Un mesaj SOAP se poate salva într-un fi¸sier text cu<br />

FileOutputStream f=new FileOutputStream(. . .);<br />

soapMsg.writeTo(f);<br />

Transformarea unui mesaj SOAP în mesaj JMS<br />

SOAPMessage soapMsg=. . .<br />

Message msg=<br />

MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);<br />

Transformarea unui mesaj JMS în mesaj SOAP<br />

MessageFactory mf=. . .<br />

Message msg=. . .<br />

SOAPMessage soapMsg =<br />

MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);<br />

Preluarea elementelor <strong>din</strong> corpul unui mesaj SOAP<br />

SOAPBody body=. . .<br />

SOAPBodyElement element=null;


90 CAPITOLUL 5. MESAJE ÎN JAVA<br />

Iterator iterator=body.getChildElements();<br />

while(iterator.hasNext()){<br />

element=(SOAPBodyElement)iterator.next();<br />

String name=element.getElementName();<br />

if(name.getLocalName().equals("numeCamp")){<br />

String s=element.getValue();<br />

. . .<br />

}<br />

}<br />

Exemplul 5.5.2 Un client introduce într-un mesaj SOAP două numere întregi,<br />

transmite mesajul altui program care calculează cel mai mare divizor comun al<br />

celor două numere ¸si transmite clientului rezultatul tot sub forma unui mesaj<br />

SOAP.<br />

Activitatea clientului este se compune <strong>din</strong><br />

• Transmiterea către server a cererii. Mesajul este alcătuit <strong>din</strong> cele două<br />

numere ¸si un topic, în care va găsi răspunsul.<br />

import javax.jms.*;<br />

import javax.xml.soap.*;<br />

import com.sun.messaging.xml.MessageTransformer;<br />

import java.util.*;<br />

public class MsgSOAPClientSen<strong>de</strong>r{<br />

long a,b;<br />

String topicResult;<br />

String clientID,clientName;<br />

MsgSOAPClientSen<strong>de</strong>r(String clientID,String clientName){<br />

this.clientID=clientID;<br />

this.clientName=clientName;<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("Introduceti m :");<br />

a=scanner.nextLong();<br />

System.out.println("Introduceti n :");<br />

b=scanner.nextLong();<br />

System.out.println("Introduceti ’Topic’-ul raspunsului");<br />

topicResult=scanner.next();<br />

}<br />

public void service(){<br />

MessageFactory mf=null;<br />

SOAPMessage soapMsg=null;<br />

SOAPPart part=null;<br />

SOAPEnvelope envelope=null;<br />

SOAPBody body=null;<br />

SOAPElement elem=null;<br />

Name name=null;<br />

try{<br />

com.sun.messaging.TopicConnectionFactory cf=


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 91<br />

new com.sun.messaging.TopicConnectionFactory();<br />

//cf.setProperty("imqBrokerHostName","atlantis");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

TopicConnection conn=cf.createTopicConnection();<br />

conn.setClientID(clientID);<br />

TopicSession session=conn.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination tDate=session.createTopic("Cmmdc");<br />

MessageProducer producer=session.createProducer(tDate);<br />

mf=MessageFactory.newInstance();<br />

soapMsg=mf.createMessage();<br />

part=soapMsg.getSOAPPart();<br />

envelope=part.getEnvelope();<br />

body=envelope.getBody();<br />

name=envelope.createName("n1");<br />

elem=body.addChildElement(name);<br />

elem.addTextNo<strong>de</strong>((new Long(a)).toString());<br />

name=envelope.createName("n2");<br />

elem=body.addChildElement(name);<br />

elem.addTextNo<strong>de</strong>((new Long(b)).toString());<br />

name=envelope.createName("topic");<br />

elem=body.addChildElement(name);<br />

elem.addTextNo<strong>de</strong>(topicResult);<br />

Destination tResult=session.createTopic(topicResult);<br />

TopicSubscriber consumer=<br />

session.createDurableSubscriber((Topic)tResult,clientName);<br />

Message m=<br />

MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);<br />

producer.send(m);<br />

FileOutputStream f=new FileOutputStream("MySOAPMessage.xml");<br />

soapMsg.writeTo(f);<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

System.out.println("Sen<strong>de</strong>r finished");<br />

}<br />

public static void main(String[] args){<br />

if(args.length


92 CAPITOLUL 5. MESAJE ÎN JAVA<br />

String clientID,clientName;<br />

MsgSOAPClientReceiver(String clientID,String clientName){<br />

this.clientID=clientID;<br />

this.clientName=clientName;<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("Introduceti ’Topic’-ul raspunsului");<br />

topicResult=scanner.next();<br />

}<br />

public void service(){<br />

MessageFactory mf=null;<br />

SOAPMessage soapMsg=null;<br />

SOAPPart part=null;<br />

SOAPEnvelope envelope=null;<br />

SOAPBody body=null;<br />

SOAPBodyElement element=null;<br />

Name name=null;<br />

try{<br />

com.sun.messaging.TopicConnectionFactory cf=<br />

new com.sun.messaging.TopicConnectionFactory();<br />

//cf.setProperty("imqBrokerHostName","atlantis");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

TopicConnection conn=cf.createTopicConnection();<br />

conn.setClientID(clientID);<br />

TopicSession session=conn.createTopicSession(false,<br />

Session.AUTO_ACKNOWLEDGE);<br />

Destination tResult=session.createTopic(topicResult);<br />

TopicSubscriber consumer=<br />

session.createDurableSubscriber((Topic)tResult,clientName);<br />

mf=MessageFactory.newInstance();<br />

conn.start();<br />

Message msg=consumer.receive();<br />

soapMsg=MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);<br />

System.out.println("Client Mesaj SOAP receptionat");<br />

part=soapMsg.getSOAPPart();<br />

envelope=part.getEnvelope();<br />

body=envelope.getBody();<br />

Iterator iterator=body.getChildElements();<br />

String s="";<br />

while(iterator.hasNext()){<br />

element=(SOAPBodyElement)iterator.next();<br />

name=element.getElementName();<br />

if(name.getLocalName().equals("cmmdc"))<br />

s=element.getValue();<br />

}<br />

System.out.println("Cmmdc: "+s);<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

System.out.println("Receiver finished");<br />

}<br />

public static void main(String[] args){<br />

if(args.length


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 93<br />

System.exit(0);<br />

}<br />

MsgSOAPClientReceiver client=new MsgSOAPClientReceiver(args[0],args[1]);<br />

client.service();<br />

}<br />

}<br />

Programul server este<br />

import javax.jms.*;<br />

import javax.xml.soap.*;<br />

import com.sun.messaging.xml.MessageTransformer;<br />

import java.util.Iterator;<br />

public class MsgSOAPCmmdcServer{<br />

long cmmdc(long m,long n){. . .}<br />

public void service(){<br />

MessageFactory mf=null;<br />

SOAPMessage soapMsg=null;<br />

SOAPPart part=null;<br />

SOAPEnvelope envelope=null;<br />

SOAPBody body=null;<br />

SOAPBodyElement element=null;<br />

SOAPElement elem=null;<br />

Name name=null;<br />

try{<br />

com.sun.messaging.TopicConnectionFactory<br />

cf=new com.sun.messaging.TopicConnectionFactory();<br />

//cf.setProperty("imqBrokerHostName","atlantis");<br />

//cf.setProperty("imqBrokerHostPort","7676");<br />

TopicConnection conn=cf.createTopicConnection();<br />

TopicSession session=conn.createTopicSession(false,<br />

Session.AUTO_ACKNOWLEDGE);<br />

Destination tDate=session.createTopic("Cmmdc");<br />

TopicSubscriber consumer=session.createSubscriber((Topic)tDate);<br />

conn.start();<br />

Message msg=null;<br />

mf=MessageFactory.newInstance();<br />

while(true){<br />

msg=consumer.receive();<br />

soapMsg=MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);<br />

System.out.println("Server Mesaj SOAP receptionat");<br />

part=soapMsg.getSOAPPart();<br />

envelope=part.getEnvelope();<br />

body=envelope.getBody();<br />

Iterator iterator=body.getChildElements();<br />

String sn1="",sn2="",topicResult="";<br />

while(iterator.hasNext()){<br />

element=(SOAPBodyElement)iterator.next();<br />

name=element.getElementName();<br />

if(name.getLocalName().equals("n1"))<br />

sn1=element.getValue();<br />

if(name.getLocalName().equals("n2"))<br />

sn2=element.getValue();<br />

if(name.getLocalName().equals("topic"))<br />

topicResult=element.getValue();<br />

}


94 CAPITOLUL 5. MESAJE ÎN JAVA<br />

System.out.println(sn1+":"+sn2+":"+topicResult);<br />

long a=Long.parseLong(sn1);<br />

long b=Long.parseLong(sn2);<br />

long c=cmmdc(a,b);<br />

soapMsg=mf.createMessage();<br />

part=soapMsg.getSOAPPart();<br />

envelope=part.getEnvelope();<br />

body=envelope.getBody();<br />

name=envelope.createName("cmmdc");<br />

elem=body.addChildElement(name);<br />

elem.addTextNo<strong>de</strong>((new Long(c)).toString());<br />

Message m=<br />

MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);<br />

Destination tResult=session.createTopic(topicResult);<br />

MessageProducer producer=session.createProducer(tResult);<br />

producer.send(m);<br />

}<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

System.out.println("Server finished");<br />

}<br />

public static void main(String[] args){<br />

MsgSOAPCmmdcServer server=new MsgSOAPCmmdcServer();<br />

server.service();<br />

}<br />

}<br />

Mesajul SOAP utilizat <strong>de</strong> client, pentru n1 = 45, n2 = 35 ¸si topic = nume<br />

este<br />

<br />

<br />

<br />

45<br />

35<br />

nume<br />

<br />

<br />

5.5.3 Ata¸samente SOAP<br />

Crearea ata¸samentelor<br />

1. Crearea mesajului SOAP<br />

MessageFactory mf=MessageFactory.newInstance();<br />

SOAPMessage soapMsg=mf.createMessage();


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 95<br />

2. • Ata¸sament text<br />

(a) Crearea unui obiect <strong>de</strong> tip AttachmentPart<br />

AttachmentPart attachment=soapMsg.createAttachmentPart();<br />

(b) Completarea cont¸inutului<br />

String stringContent=. . .<br />

attachment.setContent(stringContent, "text/plain");<br />

Cont¸inutului i se poate ata¸sa un cod <strong>de</strong> i<strong>de</strong>ntificare<br />

attachment.setContentId("Text1");<br />

• Ata¸sament imagine jpeg/png<br />

(a) Crearea unui obiect <strong>de</strong> tip AttachmentPart cu încărcarea imaginii.<br />

URL url=new URL("file://localhost/c:\\. . .\\***.jpg");<br />

DataHandler dataHandler = new DataHandler(url);<br />

AttachmentPart attachment =<br />

soapMsg.createAttachmentPart(dataHandler);<br />

attachment.setContentId("Imagine1");<br />

• Ata¸sament cu sunet în format mp3.<br />

(a) Crearea unui obiect <strong>de</strong> tip AttachmentPart cu încărcarea fi¸sierului<br />

mp3.<br />

URL url=new URL("file://localhost:c:\\. . .\\***.mp3");<br />

DataHandler dataHandler=new DataHandler(url);<br />

AttachmentPart attachment =<br />

soapMsg.createAttachmentPart(dataHandler);<br />

attachment.setContentId("attached_mp3");<br />

3. Inclu<strong>de</strong>rea ata¸samentului în mesajul SOAP<br />

soapMsg.addAttachmentPart(attachment);<br />

Extragerea ata¸samentelor<br />

Tipul unui ata¸sament se poate <strong>de</strong>duce <strong>din</strong> rezultatul meto<strong>de</strong>i getContentId<br />

sau getContentType a clasei AttachmentPart.<br />

Iterator iterator = soapMsg.getAttachments();<br />

while (iterator.hasNext()) {<br />

AttachmentPart attached =<br />

(AttachmentPart)iterator.next();<br />

// Codul <strong>de</strong> i<strong>de</strong>ntificare<br />

String id = attached.getContentId();<br />

// Tipul atasamentului<br />

String type = attached.getContentType();


96 CAPITOLUL 5. MESAJE ÎN JAVA<br />

// Preluarea unui string<br />

if (type.equals("text/plain")) {<br />

Object content = attached.getContent();<br />

. . .<br />

}<br />

// Preluarea unei imagini<br />

if (type.equals("image/jpeg")){<br />

Image image=(Image)attached.getContent();<br />

. . .<br />

}<br />

// Preluarea unei inregistrari mp3<br />

if(type.equals("audio/x-wav")){<br />

System.out.println("Play MP3");<br />

MP3Player mp3Player=new MP3Player(attached.getRawContent());<br />

mp3Player.play();<br />

}<br />

}<br />

Exemplul 5.5.3 Crearea unui mesaj SOAP cu ata¸samente text, imagine ¸si muzică<br />

mp3. Textul, imaginea ¸si muzica mp3 sunt cont¸inute în fi¸siere. Căile către aceste<br />

fi¸siere se vor da ca proprietăt¸i.<br />

import javax.jms.*;<br />

import javax.xml.soap.*;<br />

import com.sun.messaging.xml.MessageTransformer;<br />

import java.io.*;<br />

import javax.activation.DataHandler;<br />

import java.net.URL;<br />

public class MsgSOAPPublisher extends Thread{<br />

String file_location, image_location, mp3_location;<br />

MsgSOAPPublisher(String file_location,String image_location,String mp3_location){<br />

this.file_location=file_location;<br />

this.image_location=image_location;<br />

this.mp3_location=mp3_location;<br />

}<br />

public void run(){<br />

try{<br />

com.sun.messaging.TopicConnectionFactory cf=<br />

new com.sun.messaging.TopicConnectionFactory();<br />

TopicConnection conn=cf.createTopicConnection();<br />

TopicSession session=conn.createTopicSession(false,<br />

Session.AUTO_ACKNOWLEDGE);<br />

Destination t=session.createTopic("Date");<br />

MessageProducer producer=session.createProducer(t);<br />

MessageFactory mf=MessageFactory.newInstance();


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 97<br />

SOAPMessage soapMsg=mf.createMessage();<br />

SOAPPart part=soapMsg.getSOAPPart();<br />

SOAPEnvelope envelope=part.getEnvelope();<br />

SOAPBody body=envelope.getBody();<br />

Name bodyName=envelope.createName("verif");<br />

SOAPElement element=body.addBodyElement(bodyName);<br />

element.addTextNo<strong>de</strong>("Atasamente");<br />

// Crearea unui atasament text<br />

AttachmentPart attachment1 =<br />

soapMsg.createAttachmentPart();<br />

// Se completeaza calea la fisierul myText.txt<br />

FileRea<strong>de</strong>r fr = new FileRea<strong>de</strong>r(file_location));<br />

BufferedRea<strong>de</strong>r br = new BufferedRea<strong>de</strong>r(fr);<br />

String stringContent = "";<br />

String line = br.readLine();<br />

while (line != null) {<br />

stringContent = stringContent.concat(line);<br />

stringContent = stringContent.concat("\n");<br />

line = br.readLine();<br />

}<br />

attachment1.setContent(stringContent, "text/plain");<br />

attachment1.setContentId("attached_text");<br />

soapMsg.addAttachmentPart(attachment1);<br />

// Crearea unui atasament imagine<br />

// Se completeazu calea la fisierul xml-pic.jpg<br />

URL url = new URL("file://"+image_location);<br />

DataHandler dataHandler = new DataHandler(url);<br />

AttachmentPart attachment2 =<br />

soapMsg.createAttachmentPart(dataHandler);<br />

attachment2.setContentId("attached_image");<br />

soapMsg.addAttachmentPart(attachment2);<br />

// Crearea unui atasament <strong>de</strong> tip mp3<br />

url=new URL("file://"+mp3_location);<br />

dataHandler= new DataHandler(url);<br />

AttachmentPart attachment3 =<br />

soapMsg.createAttachmentPart(dataHandler);<br />

attachment3.setContentId("attached_mp3");<br />

soapMsg.addAttachmentPart(attachment3);<br />

Message m=MessageTransformer.SOAPMessageIntoJMSMessage(soapMsg,session);<br />

producer.send(m);<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

System.out.println("Publisher finised");<br />

}<br />

}<br />

Exemplul 5.5.4 Consumarea unui mesaj SOAP cu ata¸samente<br />

import javax.jms.*;<br />

import javax.xml.soap.*;


98 CAPITOLUL 5. MESAJE ÎN JAVA<br />

import com.sun.messaging.xml.MessageTransformer;<br />

import java.util.Iterator;<br />

import java.io.*;<br />

import java.awt.*;<br />

public class MsgSOAPSubscriber extends Thread{<br />

public void run(){<br />

try{<br />

com.sun.messaging.TopicConnectionFactory cf=<br />

new com.sun.messaging.TopicConnectionFactory();<br />

TopicConnection conn=cf.createTopicConnection();<br />

TopicSession session=conn.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);<br />

Destination t=session.createTopic("Date");<br />

TopicSubscriber consumer=session.createSubscriber((Topic)t);<br />

conn.start();<br />

Message msg=null;<br />

MessageFactory mf=MessageFactory.newInstance();<br />

while((msg=consumer.receive())!=null){<br />

SOAPMessage soapMsg=<br />

MessageTransformer.SOAPMessageFromJMSMessage(msg,mf);<br />

// Extragerea atasamentelor<br />

Iterator iterator = soapMsg.getAttachments();<br />

while (iterator.hasNext()) {<br />

AttachmentPart attached=(AttachmentPart)iterator.next();<br />

String id = attached.getContentId();<br />

String type = attached.getContentType();<br />

System.out.println("Attachment " + id +<br />

" has content type " + type);<br />

if (type.equals("text/plain")) {<br />

Object content = attached.getContent();<br />

System.out.println("Attachment contains:\n" + content);<br />

}<br />

if (type.equals("image/jpeg")){<br />

Image image=(Image)attached.getContent();<br />

ShowImage s=new ShowImage(image);<br />

s.show();<br />

}<br />

if (type.equals("audio/x-wav")){<br />

MP3Player mp3Player=new MP3Player(attached.getRawContent());<br />

mp3Player.start();<br />

}<br />

}<br />

}<br />

conn.close();<br />

}<br />

catch(Exception e){<br />

System.out.println("Exception : "+e.getMessage());<br />

}<br />

System.out.println("Subscriber finished");<br />

}<br />

}<br />

Apelarea celor două fire <strong>de</strong> execut¸ie se face prin<br />

class MsgAttach{<br />

public static void main(String[] args){<br />

String file_location=System.getProperty("file_location");<br />

String image_location=System.getProperty("image_location");


5.5. MESAJE SOAP PRIN JAVA MESSAGE SERVICE 99<br />

String mp3_location=System.getProperty("mp3_location");<br />

MsgSOAPPublisher publisher=<br />

new MsgSOAPPublisher(file_location,image_location,mp3_location);<br />

MsgSOAPSubscriber subscriber=new MsgSOAPSubscriber();<br />

publisher.start();<br />

subscriber.start();<br />

}<br />

}<br />

Acest program se execută cu comanda<br />

java -Dfile location=... -Dimage location=... -Dmp3 location=... MsgAttach<br />

Programul <strong>de</strong> afi¸sare a imaginii<br />

import java.awt.*;<br />

import java.awt.image.*;<br />

import javax.swing.*;<br />

import java.io.*;<br />

import javax.imageio.ImageIO;<br />

import java.net.*;<br />

class MyCanvas extends Canvas{<br />

Image image=null;<br />

MyCanvas(Image image){<br />

this.image=image;<br />

}<br />

public void paint(Graphics g){<br />

g.drawImage(image,0,0,this);<br />

}<br />

}<br />

public class ShowImage{<br />

Image image=null;<br />

MyCanvas mc=null;<br />

ShowImage(Image image){<br />

this.image=image;<br />

mc=new MyCanvas(image);<br />

}<br />

public void show(){<br />

// Interfata swing<br />

JFrame jframe = new JFrame("The received image");<br />

jframe.addNotify();<br />

jframe.getContentPane().setLayout(new Bor<strong>de</strong>rLayout());<br />

jframe.getContentPane().add(mc,Bor<strong>de</strong>rLayout.CENTER);<br />

jframe.setDefaultCloseOperation(jframe.EXIT_ON_CLOSE);<br />

jframe.setSize(200,200);<br />

jframe.setVisible(true);<br />

}<br />

}<br />

Programul pentru redarea cont¸inutului unui fi¸sier mp3 necesită prezent¸a resursei<br />

jl1.0.jar <strong>din</strong> pachetul JLayer1.0, <strong>de</strong>scărcabil <strong>din</strong> internet. Un program <strong>de</strong><br />

redare este


100 CAPITOLUL 5. MESAJE ÎN JAVA<br />

public class MP3Player extends Thread{<br />

private Player player;<br />

public MP3Player(InputStream is) {<br />

try {<br />

BufferedInputStream bis=new BufferedInputStream(is);<br />

player=new Player(bis);<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

System.exit(1);<br />

}<br />

}<br />

public void run(){<br />

try{<br />

player.play();<br />

}<br />

catch(Exception e){<br />

System.out.println(e.getMessage());<br />

}<br />

if (player != null) player.close();<br />

}<br />

}


Capitolul 6<br />

Servlet<br />

Printre aplicat¸iile distribuite <strong>de</strong> tip client-server, în care comunicat¸iile se<br />

bazează pe protocolul http, se disting<br />

• Aplicat¸ii Web (site): Cererea adresată serverului este lansată <strong>de</strong> o persoană<br />

prin intermediul unui site, utilizând un program navigator: Mozilla Firefox,<br />

Opera, Microsoft InternetExplorer, Apple Safari, etc.<br />

• Servicii Web: Cererea către server se face <strong>de</strong> un program.<br />

Un servlet este un program Java care se excută pe un server Web, compatibil,<br />

¸si este capabil să răpundă cererilor formulate <strong>de</strong> client¸i.<br />

Scrierea ¸si utilizarea unui servlet necesită<br />

• Cunoa¸sterea marcajului html pentru realizarea formularelor <strong>de</strong><br />

introducere a datelor;<br />

• Utilizarea unui server Web, container <strong>de</strong> servlet¸i.<br />

6.1 Marcajul <br />

Într-un document html introducerea datelor se poate obt¸ine utilizând marcajul<br />

... .<br />

Atribute ale marcajului . Reamintim că atributele se prezintă<br />

ca perechi (nume, valoare) ¸si se scriu în antetul marcajului sub forma nume =<br />

valoare.<br />

101


102 CAPITOLUL 6. SERVLET<br />

Nume Valoare Semnificat¸ia valorii<br />

action adresa tip URL Resursa care prelucrează formularul.<br />

method GET Mesajul trimis serverului Web cont¸ine după<br />

adresa URL numele ¸si valorile parametrilor<br />

introdu¸si. Adăugarea se face potrivit sintaxei<br />

?numeParam1=valoare&numeParam2=valoare. . .<br />

Lungimea mesajului nu poate <strong>de</strong>pă¸si 255 caractere.<br />

POST Transmisia datelor se face în fluxuri <strong>de</strong> date.<br />

Permite transferul unor fi¸siere <strong>de</strong> pe ma¸sina<br />

clientului pe ma¸sina serverului.<br />

Datele sunt transmise prin fluxuri <strong>de</strong> date.<br />

id Parametru <strong>de</strong> i<strong>de</strong>ntificare a formularului (opt¸ional).<br />

name Nume atribuit formularului (opt¸ional).<br />

onSubmit Metodă JavaScript executată înaintea apelării<br />

serverului Web (opt¸ional).<br />

În cont¸inutul marcajului putem inclu<strong>de</strong> elemente <strong>de</strong> control prin<br />

marcajele<br />

• <br />

• <br />

• <br />

• <br />

Atributele marcajului < input> sunt:<br />

Nume Valoare Semnificat¸ie<br />

type text Se a¸steaptă introducerea unui text<br />

number Se a¸steaptă introducerea unui număr<br />

password Se a¸steaptă introducerea unei parole<br />

submit Se marchează sfâr¸situl completării formularului<br />

reset Se reinit¸ializează formularul<br />

file Permite selectarea unui fi¸sier<br />

hid<strong>de</strong>n Transmite mai <strong>de</strong>parte un atribut fără vizualizarea lui<br />

name numele controlului<br />

value valoarea (init¸ială) a controlului<br />

size numărul caracterelor ata¸sat controlului<br />

În cazul marcajului < select> utilizarea este<br />


6.2. SERVER WEB - CONTAINER DE SERVLET 103<br />

Valoare<br />

. . . . . . . . . . . . . . . .<br />

<br />

Valoarea atributului nume este dată <strong>de</strong> valoarea selectată.<br />

6.2 Server Web - container <strong>de</strong> servlet<br />

În prezent sunt disponibile mai multe servere Web în care poate fi instalat un<br />

servlet ¸si un fi¸sier JSP. Se spune că serverul Web este container <strong>de</strong> servlet ¸si JSP.<br />

Dintre produsele gratuite amintim<br />

• apache-tomcat<br />

• jetty<br />

• Sun Java System Application Server<br />

Acest server Web este utilizat în Glassfish - o implementare JEE (Java<br />

Enterprise Edition).<br />

Geronimo, o alta implementare JEE <strong>de</strong>zvoltată <strong>de</strong> apache, poate utiliza containerul<br />

apache-tomcat sau jetty.<br />

Serverul Web apache-tomcat<br />

În continuare se va folosi serverul Web apache-tomcat, pe scurt tomcat.<br />

Serverul Web tomcat este distribuit gratuit, putând fi <strong>de</strong>scărcat <strong>de</strong> la adresa<br />

www.apache.org.<br />

Instalarea serverului în mediul Windows revine la <strong>de</strong>zarhivarea fi¸sierului<br />

<strong>de</strong>scărcat apache-tomcat-***, într-un catalog TOMCAT HOME. Utilizarea serverului<br />

necesită fixarea a doi parametri sistem:<br />

• CATALINA HOME= calea la catalogul în care s-a instalat produsul - TOMCAT HOME;<br />

• JAVA HOME=calea la distribut¸ia Java utilizată.<br />

Pachetul cont¸ine cataloagele 1 : bin, common, conf, logs, server, shared,<br />

temp, webapps, work.<br />

Serverul se lansează prin comanda<br />

¸si se opre¸ste cu comanda<br />

TOMCAT HOME\bin\startup<br />

1 Numele ¸si numărul cataloagelor este <strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> distribut¸ia apache-tomcat.


104 CAPITOLUL 6. SERVLET<br />

TOMCAT HOME\bin\shutdown<br />

Din catalogul TOMCAT HOME, lansarea se poate obt¸ine cu ajutorul fi¸sierului <strong>de</strong><br />

comenzi (*.bat)<br />

set CATALINA_HOME=. . .<br />

set JAVA_HOME=. . .<br />

bin\startup<br />

Opt¸ional se poate instala / activa managerul / administatorul serverului Web<br />

tomcat.<br />

Verificarea funct¸ionării serverului Web tomcat se face apelând <strong>din</strong>tr-un navigator<br />

pagina http://host:port un<strong>de</strong><br />

• host este numele calculatorului pe care rulează tomcat;<br />

• Portul implicit este 8080.<br />

Reu¸sita este ilustrată <strong>de</strong> imaginea motanului<br />

6.3 Realizarea unui servlet<br />

6.3.1 Instalarea unui servlet<br />

Pentru un servlet, în catalogul webapps, se crează un subcatalog, <strong>de</strong> exemplu<br />

apphello cont¸inând<br />

apphello<br />

| |---> WEB-INF<br />

| | |---> classes<br />

| | | web.xml<br />

Catalogul classes cont¸ine fi¸sierele .class ale servletului iar fi¸sierul web.xml<br />

furnizează serverului web informat¸ii <strong>de</strong> acces la servlet. Astfel<br />

1.<br />

2.<br />

În elementul se leagă numele servlet-ului <strong>de</strong>finit în elementul<br />

<strong>de</strong> clasa servlet-ului dat în elementul<br />

.<br />

În elementul se <strong>de</strong>fine¸ste numele sub care servlet-ul<br />

i<strong>de</strong>ntificat prin nume servlet< /servlet> se invocă <strong>din</strong><br />

programul navigator. Acest i<strong>de</strong>ntificator - numeApel - se fixează în elementul<br />

. I<strong>de</strong>ntificatorul are ca prefix caracterul / (slash).


6.3. REALIZAREA UNUI SERVLET 105<br />

Structura unui fi¸sier web.xml este<br />

<br />

<br />

nume_servlet_1<br />

Nume_clasa<br />

<br />

<br />

nume_servlet_2<br />

Nume_clasa<br />

<br />

. . .<br />

<br />

nume_servlet_1<br />

/numeApel_1<br />

<br />

<br />

nume_servlet_2<br />

/numeApel_2<br />

<br />

. . .<br />

<br />

Opt¸ional web.xml poate cont¸ine elementul<br />

<br />

<br />

fisier.html sau jsp<br />

<br />

<br />

cu precizarea fi¸sierelor html sau jsp care lansează servletul. Declarat¸ia fi¸sierului<br />

in<strong>de</strong>x.html este implicită.<br />

Dacă servlet-ul necesă alte resurse - fi¸siere jar, atunci acestea se <strong>de</strong>pun într-un<br />

subcatalog lib în WEB-INF.<br />

O altă variantă <strong>de</strong> instalare a unui servlet, <strong>de</strong> exemplu reprezentat prin clasa<br />

HelloServlet.class, în serverul Web tomcat constă <strong>din</strong>:<br />

1. Se crează oriun<strong>de</strong> structura <strong>de</strong> cataloage ¸si fi¸siere<br />

apphello<br />

| |---> WEB-INF<br />

| | |---> classes<br />

| | | | HelloServlet.class<br />

| | | web.xml<br />

2. Din catalogul apphello se realizează arhiva apphello.war<br />

jar cfv apphello.war WEB-INF\∗<br />

care se copiază în catalogul TOMCAT HOME\webapps.


106 CAPITOLUL 6. SERVLET<br />

3. Se porne¸ste serverul tomcat, operat¸ie în urma căreie arhiva este <strong>de</strong>zarhivată.<br />

Astfel servlet-ul este instalat.<br />

Dacă serverul tomcat este pornit atunci arhiva se <strong>de</strong>zarhivează automat<br />

¸si servlet-ul este gata <strong>de</strong> utilizare. Această instalare se nume¸ste instalare<br />

<strong>din</strong>amică - hot <strong>de</strong>ployment.<br />

Dacă fi¸sierul war este creat, atunci în locul copierii, instalarea se poate face<br />

prin componenta manager a lui tomcat.<br />

O altă posibilitate <strong>de</strong> instalare a unui servlet în serverul web tomcat este prin<br />

intermediul produsului apache-tomcat-<strong>de</strong>ployer. apache-tomcat-<strong>de</strong>ployer permite<br />

instalarea unui servlet <strong>de</strong> la distant¸ă cât ¸si instalarea comandată <strong>din</strong>tr-un program.<br />

apache-tomcat-*.*.*-<strong>de</strong>ployer se instalează prin <strong>de</strong>zarhivarea fi¸sierului apache-tomcat-*.*.*-<strong>de</strong>ployer.<br />

Posibilităt¸ile oferite <strong>de</strong> apache-tomcat-*.*.*-<strong>de</strong>ployer se obt¸in rulând ant cu un fi¸sierul build.xml<br />

<strong>din</strong> distribut¸ia produsului. Obiectivele care pot fi atinse sunt<br />

• compilarea unui servlet - compile<br />

• instalarea unui servlet - <strong>de</strong>ploy<br />

• <strong>de</strong>zinstalarea unui servlet - un<strong>de</strong>ploy<br />

În prealabil trebuie completat fi¸sierul <strong>de</strong> proprietăt¸i <strong>de</strong>ployer.properties cu<br />

• build=catalogul care va cont¸ine rezultatul compilării ¸si al arhivării.<br />

• webapp=catalogul cu sursa servlet-ului.<br />

• path=/catalog-ul servlet-ului.<br />

• url=url-ul aplicat¸iei manager <strong>din</strong> Tomcat<br />

http://host:8080/manager<br />

• username=numele <strong>de</strong> acces în manager-ul <strong>din</strong> Tomcat.<br />

• password=parola pentru manager-ul <strong>din</strong> Tomcat.<br />

Sursa servlet-ului are structura obi¸snuită, precizată anterior.<br />

6.3.2 Compilarea ¸si apelarea unui servlet<br />

Compilarea unui program necesită completarea variabilei <strong>de</strong> mediu classpath<br />

cu fi¸sierul TOMCAT HOME\. . .\servlet-api.jar <strong>din</strong> distribut¸ia tomcat. Pozit¸ia<br />

fi¸sierului <strong>de</strong>pin<strong>de</strong> <strong>de</strong> versiunea apache-tomcat utilizată.<br />

Un servlet se lansează în execut¸ie (se apelează) <strong>din</strong><br />

• meniul File/Open a unui program navigator (ex. Mozilla Firefox, Internet<br />

Explorer) prin


6.3. REALIZAREA UNUI SERVLET 107<br />

un<strong>de</strong><br />

http://host:port/catalog/numeApel<br />

– catalog este numele catalogului ce cont¸ine servlet-ul - apphello.<br />

– Portul implicit este 8080.<br />

– numeApel este i<strong>de</strong>ntificatorul fixat în marcajul url-pattern <strong>din</strong> fi¸sierul<br />

web.xml.<br />

• ca o referint¸ă <strong>din</strong>tr-un document html<br />

...<br />

• ca valoare a atributului action într-un marcaj form<br />


108 CAPITOLUL 6. SERVLET<br />

• public String getServletInfo()<br />

• public ServletConfig getServletConfig()<br />

În cele ce urmează un servlet va fi o clasă care extin<strong>de</strong> clasa HttpServlet.<br />

În locul meto<strong>de</strong>i service(...), programatorul suprascrie meto<strong>de</strong>le doGet(...)<br />

sau doPost(...), în funct¸ie <strong>de</strong> metoda utilizată <strong>de</strong> client la lansarea cererii.<br />

Practic, un servlet constă <strong>din</strong> scrierea meto<strong>de</strong>lor<br />

• void init(ServletConfig config)<br />

Această metodă este opt¸ională.<br />

public void init(ServletConfig config) throws ServletException{<br />

super.init(config);<br />

// cod <strong>de</strong> initializare<br />

}<br />

Obiectul config are o metodă String getInitParameter(String numeParam)<br />

cu ajutorul căreia se pot recupera parametri <strong>de</strong> initializare asociat¸i servletului<br />

¸si care se dau în fi¸sierul web.xml prin marcajele<br />

<br />

NumeleParametrului <br />

Valoare <br />

<br />

cuprinse în marcajul .<br />

• protected void doGet(HttpServletRequest req, HttpServletResponse<br />

res) throws IOException, ServletException<br />

Tratează o cerere trimisă cu metoda GET (vezi marcajul ).<br />

• protected void doPost(HttpServletRequest req, HttpServletResponse<br />

res) throws IOException, ServletException<br />

Tratează o cerere trimisă cu metoda POST (vezi marcajul ).<br />

Activităt¸ile <strong>de</strong> întreprins într-o metodă doGet() sau doPost() sunt<br />

1. Stabilirea naturii răspunsului:<br />

res.setContentType(String tip)<br />

un<strong>de</strong> tip specifică tipul MIME - Multipurpose Internet Mail Extensions al<br />

răspunsului:


6.3. REALIZAREA UNUI SERVLET 109<br />

• "text/html" - pagină html;<br />

• "text/xml" - document xml;<br />

• "text/plain" - text;<br />

• "image/jpg" - imagine gif;<br />

• "image/gif" - imagine jpg.<br />

2. Se obt¸ine o referint¸a către un obiect care realizeaza transmisia datelor către<br />

navigatorul clientului:<br />

ServletOutputStream out = res.getOutputStream();<br />

sau<br />

PrintWriter out=res.getWriter();<br />

3. Se preiau datele cererii cu una <strong>din</strong> meto<strong>de</strong>le:<br />

String getParameter(String numeParapetru)<br />

java.util.Enumeration getParameterNames()<br />

4. Rezolvă cererea clientului;<br />

5. Formează ¸si scrie răspunsul;<br />

6.<br />

Închi<strong>de</strong> conexiunea obiectului prin care s-a realizat transmisia datelor către<br />

navigatorul clientului prin out.close().<br />

Un utilizator lansează o cerere către servlet. De obicei acest lucru se realizează<br />

prin completarea unui formular al unui document html. Programul navigator<br />

trimite cererea serverului Web prin intermediul căruia este lansat servlet-ul în<br />

act¸iune.<br />

Ciclul <strong>de</strong> viat¸ă al unui servlet. Când un servlet este apelat prima dată<br />

<strong>de</strong> către serverul Web se execută metoda init. După aceasta, fiecărei cereri<br />

lansate <strong>de</strong> un utilizator i se asociază un fir <strong>de</strong> execut¸ie în care se apelează metoda<br />

service. Metoda service apelează apoi meto<strong>de</strong>le doGet(), doPost() sau o<br />

altă metodă <strong>de</strong> forma doXXX() <strong>de</strong>pinzând <strong>de</strong> tipul <strong>de</strong> cerere primit.<br />

Exemplul 6.3.1 Servletul Hello: Clientul transmite numele servet-ului care îi<br />

răspun<strong>de</strong> cu mesajul <strong>de</strong> salut ”Hi nume!”.<br />

Formularul html prin care clientul introduce numele este (in<strong>de</strong>x.html)<br />

<br />

<br />

Servlet-ul Hello <br />

<br />

<br />

<br />

Pagina <strong>de</strong> apelare a servletului HelloServlet <br />


110 CAPITOLUL 6. SERVLET<br />

action="http://localhost:8080/apphello/hello"><br />

Introduceti numele:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Codul servlet-ului este<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

public class HelloServlet extends HttpServlet {<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

res.setContentType("text/html");<br />

ServletOutputStream out=res.getOutputStream();<br />

String nume=req.getParameter("name");<br />

out.println("");<br />

out.println("HelloServlet");<br />

out.println("");<br />

out.println("HelloServlet");<br />

out.println("");<br />

out.println( "Hi "+ nume+" !");<br />

out.println("");<br />

out.println("");<br />

out.println("");<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

Fi¸sierul web.xml pentru acest exemplu este<br />

<br />

<br />

<br />

<br />

hello<br />

HelloServlet<br />

<br />

<br />

hello<br />

/hello<br />

<br />

<br />

in<strong>de</strong>x.html<br />

<br />


6.3. REALIZAREA UNUI SERVLET 111<br />

Compilarea ¸si arhivarea servlet-ului o vom realiza prin intermediul lui apacheant.<br />

În acest scop se crează structura:<br />

hello<br />

| |---> src<br />

| | | HelloServlet.java<br />

| |---> lib<br />

| |---> web<br />

| | | web.xml<br />

| |---> web-files<br />

| | | in<strong>de</strong>x.html<br />

| build.xml<br />

cu fi¸sierul build.xml<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


112 CAPITOLUL 6. SERVLET<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Observat¸ie. Valoarea parametrului dist.name trebuie să coincidă cu numele<br />

catalogului în atributul action a elementului form, <strong>din</strong> documentul in<strong>de</strong>x.html.<br />

În cazul exemplului <strong>de</strong> fat¸ă, catalogul lib este gol. Dacă aplicat¸ia solicită<br />

resurse externe, cont¸inute în fi¸sierele jar, atunci aceste fi¸siere se <strong>de</strong>pun în catalogul<br />

lib.<br />

Se lansează în execut¸ie serverul Web tomcat, se încarcă servlet-ul în serverul<br />

Web ¸si <strong>din</strong>tr-un navigator se <strong>de</strong>schi<strong>de</strong> pagina http://localhost:8080/apphello<br />

Exemplul 6.3.2 Servlet pentru calculul celui mai mare divizor comun a două<br />

numere.<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

public class CmmdcServlet extends HttpServlet{<br />

public long cmmdc(long m, long n){. . .}<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

String sm=req.getParameter("m"),sn=req.getParameter("n");<br />

String tip=req.getParameter("tip");<br />

long m=Long.parseLong(sm),n=Long.parseLong(sn);<br />

long x=cmmdc(m,n);<br />

PrintWriter out=res.getWriter();<br />

String title="CmmdcServlet";<br />

if(tip.equals("text/html")){<br />

res.setContentType("text/html");<br />

out.println("");<br />

out.println(title);<br />

out.println("");<br />

out.println(""+title+"");<br />

out.println("Cmmdc is "+x);<br />

out.println("");<br />

}<br />

else{<br />

res.setContentType("text/plain");<br />

out.println(x);<br />

}<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 113<br />

}<br />

}<br />

apelabil prin documentul html (in<strong>de</strong>x.html)<br />

<br />

<br />

<br />

Primul numar este <br />

Al doilea numar este <br />

<br />

<br />

<br />

<br />

<br />

Pentru fixarea naturii răspunsului text/html sau text/plain s-a introdus variabila<br />

tip, care în fi¸sierul <strong>de</strong> invocare in<strong>de</strong>x.html prime¸ste pe ascuns valoarea<br />

text/html. În cazul în care vom apela servlet-ul <strong>din</strong>tr-un program, va fi avantajos<br />

să primim răspunsul ca text/plain.<br />

6.4 Facilităt¸i <strong>de</strong> programare cu servlet<br />

6.4.1 Program client al unui servlet<br />

Apelarea unui servlet <strong>din</strong>tr-un program Java – adică lansarea unei cereri<br />

¸si recept¸ionarea răspunsului furnizat <strong>de</strong> servlet – se poate realiza cu produsul<br />

commons-httpclient <strong>de</strong>zvoltat în cadrul proiectului jakarta al fundat¸iei apache.<br />

Într-un asemenea caz, <strong>din</strong> punctul <strong>de</strong> ve<strong>de</strong>re al clientului este mai avantajos<br />

ca răspunsul servlet-ului fie text/plain, în loc <strong>de</strong> text/html.<br />

Pe lângă commons-httpclient este nevoie <strong>de</strong> următoarele produse soft:<br />

• commons-co<strong>de</strong>c <strong>de</strong> la apache;<br />

• commons-logging <strong>de</strong> la apache;<br />

Pentru compilare trebuie <strong>de</strong>clarată în variabila <strong>de</strong> sistem classpath referint¸a<br />

către commons-httpclient, dar pentru execut¸ie este nevoie ¸si <strong>de</strong> referintele către<br />

celelalte două produse.<br />

Dezvoltarea unui client presupune:<br />

1. Resursele utilizate se <strong>de</strong>clară prin<br />

import org.apache.commons.httpclient.*;<br />

import org.apache.commons.httpclient.methods.*;<br />

import org.apache.commons.httpclient.params.HttpMethodParams;


114 CAPITOLUL 6. SERVLET<br />

2. Crearea unui obiect <strong>de</strong> tip HttpClient:<br />

HttpClient client=new HttpClient();<br />

3. Declararea meto<strong>de</strong>i <strong>de</strong> transmitere a datelor get, post.<br />

• GetMethod method = new GetMethod(url);<br />

un<strong>de</strong> url este String-ul <strong>de</strong> apelare a servlet-ului, <strong>de</strong> forma<br />

http://host:port/catalog/numeApel?numeCâmp=*&numeCâmp=*,<br />

* t¸inând locul valorilor introduse <strong>de</strong> client;<br />

• PostMethod method = new PostMethod(url);<br />

cu url=”http://host:port/catalog/numeApel”.<br />

Datele se adaugă cu metoda<br />

method.addParameter(String paramName, String paramValue);<br />

Dacă se transmit atât parametri cât ¸si fi¸siere atunci datele se adaugă<br />

prin ¸sablonul<br />

Part[] parts = {<br />

new StringPart(paramName, paramValue),<br />

. . .<br />

new FilePart(file.getName(), file)<br />

. . .<br />

};<br />

method.setRequestEntity(<br />

new MultipartRequestEntity(parts, method.getParams())<br />

);<br />

un<strong>de</strong> o variabilă file corespun<strong>de</strong> unui fi¸sier care este încărcat.<br />

4. Specificarea modului <strong>de</strong> reluare a cererii.<br />

DefaultHttpMethodRetryHandler retryhandler=<br />

new DefaultHttpMethodRetryHandler(int numarReluari,<br />

boolean seFacReluari);<br />

method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,<br />

retryhandler);<br />

5. Lansarea cererii.<br />

int statusCo<strong>de</strong> = client.executeMethod(method);<br />

6. Preluarea răspunsului. Există trei căi <strong>de</strong> realizare a acestui obiectiv:


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 115<br />

7.<br />

• Ca ¸sir <strong>de</strong> octet¸i:<br />

byte[] method.getResponseBody();<br />

• Ca String:<br />

String method.getResponseBodyAsString();<br />

• Prin intermediul unui flux:<br />

InputStream method.getResponseBodyAsStream();<br />

Închi<strong>de</strong>rea conexiunii cu servlet-ul.<br />

method.releaseConnection();<br />

Exemplul 6.4.1 Dezvoltăm un program client pentru servlet-ul CmmdcServlet.<br />

import java.util.*;<br />

import org.apache.commons.httpclient.*;<br />

import org.apache.commons.httpclient.methods.*;<br />

import org.apache.commons.httpclient.params.HttpMethodParams;<br />

import java.io.*;<br />

public class ClientCmmdcServlet{<br />

private static String url = "http://localhost:8080/myservlet/cmmdc";<br />

public static void main(String[] args) {<br />

Scanner scanner=new Scanner(System.in);<br />

System.out.println("m=");<br />

String m=scanner.nextLine().trim();<br />

System.out.println("n=");<br />

String n=scanner.nextLine().trim();<br />

HttpClient client = new HttpClient();<br />

PostMethod method = new PostMethod(url);<br />

method.addParameter("m",m);<br />

method.addParameter("n",n);<br />

method.addParameter("tip","text/plain");<br />

DefaultHttpMethodRetryHandler retryhandler=new DefaultHttpMethodRetryHandler(3,true);<br />

method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,retryhandler);<br />

try {<br />

int statusCo<strong>de</strong> = client.executeMethod(method);<br />

if (statusCo<strong>de</strong> != HttpStatus.SC_OK) {<br />

System.err.println("Method failed: " + method.getStatusLine());<br />

}<br />

byte[] responseBody = method.getResponseBody();<br />

System.out.println("Cmmdc = "+(new String(responseBody)));<br />

}<br />

catch (HttpException e) {<br />

System.err.println("Http error: " + e.getMessage());<br />

}<br />

catch (IOException e) {


116 CAPITOLUL 6. SERVLET<br />

System.err.println("I/O error: " + e.getMessage());<br />

}<br />

finally {<br />

method.releaseConnection();<br />

}<br />

}<br />

}<br />

6.4.2 Servlete înlănt¸uite<br />

Un servlet apelează la un moment dat alt servlet. S¸ablonul <strong>de</strong> lucru este<br />

RequestDispatcher dispatcher=<br />

getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat");<br />

if(dispatcher!=null)<br />

dispatcher.inclu<strong>de</strong>(request,response);<br />

Exemplul 6.4.2 Un servlet VerifServlet verifică parametri cererii. Pentru problema<br />

calculului celui mai mare divizor comun a două numere, dacă cei doi parametri<br />

sunt numere întregi, atunci se apelează servletul ComputeServlet, altfel se formează<br />

un mesaj <strong>de</strong> eroare.<br />

Codurile celor două servlete sunt:<br />

VerifServlet.java<br />

package cmmdc;<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

public class VerifServlet extends HttpServlet{<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

PrintWriter out=res.getWriter();<br />

res.setContentType("text/html");<br />

String sm=req.getParameter("m"),sn=req.getParameter("n");<br />

String message="";<br />

long m,n;<br />

if((sm==null)||(sm.equals(""))){<br />

message="Numar absent";<br />

}<br />

else{<br />

try{<br />

m=Long.parseLong(sm);<br />

}<br />

catch(NumberFormatException e){<br />

message="Nu este numar";<br />

}<br />

}<br />

if((sn==null)||(sn.equals(""))){<br />

message="Numar absent";<br />

}<br />

else{


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 117<br />

try{<br />

n=Long.parseLong(sn);<br />

}<br />

catch(NumberFormatException e){<br />

message="Nu este numar";<br />

}<br />

}<br />

out.println("");<br />

if(message.equals("")){<br />

out.println(" Rezultatul ob&#355;inut ");<br />

RequestDispatcher dispatcher=getServletContext().getRequestDispatcher("/calcul");<br />

if(dispatcher!=null)<br />

dispatcher.inclu<strong>de</strong>(req,res);<br />

}<br />

else{<br />

out.println(" Date eronate ");<br />

out.println(message);<br />

}<br />

out.println("");<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

ComputeServlet.java<br />

package cmmdc;<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

public class ComputeServlet extends HttpServlet{<br />

public long cmmdc(long m, long n){. . .}<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

long m=Long.parseLong(req.getParameter("m"));<br />

long n=Long.parseLong(req.getParameter("n"));<br />

PrintWriter out=res.getWriter();<br />

out.println(" Cmmdc = "+cmmdc(m,n)+"");<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

6.4.3 Sesiune <strong>de</strong> lucru<br />

În cazul protocolului HTTP, <strong>de</strong> fiecare dată când un client <strong>de</strong>schi<strong>de</strong> sau revine<br />

la o pagină Web se <strong>de</strong>schi<strong>de</strong> o nouă conexiune cu serverul Web iar acesta nu ret¸ine


118 CAPITOLUL 6. SERVLET<br />

informat¸iile referitoare la client pe perioada conexiunii respective. Perioada <strong>de</strong><br />

timp cât un client este în conexiune cu o pagină Web se nume¸ste sesiune.<br />

Există posibilitatea păstrării unor informat¸ii pe durata unei sesiuni (mecanismul<br />

Session Tracking).<br />

Înaintea satisfacerii unei cereri, servletul verifică existent¸a unui obiect HttpSession.<br />

Acest obiect se crează la prima apelare <strong>de</strong> către un client a servletului prin<br />

HttpSession sesiune=request.getSession(true);<br />

Un obiect HttpSession poate ret¸ine atribute, adică perechi <strong>de</strong> forma (nume,<br />

valoare). Introducerea unui atribut se realizează prin<br />

void setAttribute(String nume, Object valoare)<br />

iar extragerea valorii unui atribut se obt¸ine prin<br />

Object getAttribute(String nume)<br />

Metoda String nume[ ] getValueNames() returnează numele tuturor<br />

atributelor <strong>de</strong>finite.<br />

Un atribut se elimină cu metoda void removeAttribute(String nume).<br />

Exemplul 6.4.3 Exemplul următor numără <strong>de</strong> câte ori se apelează servlet-ul<br />

într-o sesiune. Se <strong>de</strong>fine¸ste un atribut noAcces, care la prima apelare este init¸ializat<br />

iar apoi este mărit cu câte o unitate la fiecare nouă apelare a servlet-ului.<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

public class Sesiune extends HttpServlet{<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

res.setContentType("text/html");<br />

String mesaj;<br />

PrintWriter out=res.getWriter();<br />

HttpSession session=req.getSession(true);<br />

Integer contor=(Integer)session.getAttribute("noAcces");<br />

if(contor==null){<br />

contor=new Integer(1);<br />

mesaj="Salut !";<br />

}<br />

else{<br />

contor=new Integer(contor.intValue()+1);<br />

mesaj="Bine ati revenit !";<br />

}<br />

session.setAttribute("noAcces",contor);<br />

out.println("");<br />

out.println(""+mesaj+"");<br />

out.println("Numarul <strong>de</strong> accesari al aceastei pagini este "+contor.intValue());<br />

out.println("");


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 119<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

Apelarea servletului se face <strong>din</strong><br />

<br />

<br />

Sesiune <br />

<br />

<br />

Formular <strong>de</strong> acces <br />

<br />

<br />

<br />

<br />

<br />

<br />

6.4.4 Cookie<br />

Un Cookie este un fi¸sier <strong>de</strong> mică dimensiune trimisă <strong>de</strong> către programul server<br />

clientului ca parte a hea<strong>de</strong>r-ului Http.<br />

Acesta cont¸ine informat¸ii <strong>de</strong>spre sesiunea curentă care salvate pe disc vor<br />

putea fi accesate în sesiuni ulterioare. Când un navigator emite o cerere către un<br />

server, cookie-urile anterioare primite <strong>de</strong> către client <strong>de</strong> la serverul respectiv sunt<br />

trimise <strong>din</strong> nou serverului ca parte a cererii formulată <strong>de</strong> client.<br />

Cookie-urile sunt sterse automat în momentul expirării.<br />

Unii client¸i nu permit memorarea cookie-urilor.<br />

În acest caz, clientul este<br />

informat că acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale<br />

/ accesării paginii Web. Implicit, durata <strong>de</strong> viat¸ă a unui cookie este sesiunea<br />

curentă a navigatorului (până se închi<strong>de</strong> navigatorul).<br />

Constructorul clasei Cookie<br />

Cookie(String nume, String valoare)<br />

Meto<strong>de</strong><br />

• void setDomain(String mo<strong>de</strong>l)<br />

Domeniul este o adresă URL ce restrict¸ionează accesul cookie-urilor la acel<br />

domeniu. mo<strong>de</strong>l trebuie să cont¸ină cel put¸in două caractere ”.”.<br />

• void setMaxAge(int durată) Fixează durata <strong>de</strong> existent¸ă a cookie-ului - în<br />

secun<strong>de</strong>. Valoarea implicită este -1, adică cookie-ul există până la închi<strong>de</strong>rea<br />

programului navigator.


120 CAPITOLUL 6. SERVLET<br />

• void setComment(String comentariu)<br />

• void setSecure(boolean flag)<br />

Valoarea implicită este false.<br />

Trimiterea unui cookie clientului:<br />

public void HttpServletResponse.addCookie(Cookie cookie)<br />

Recunoa¸sterea cookie-urilor <strong>de</strong> către servlet:<br />

Cookie [ ] cookies=request.getCookies();<br />

if(cookies!=null){<br />

for(int i=0;i


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 121<br />

out.println(""+mesaj+"");<br />

out.println("Numarul <strong>de</strong> accesari al aceastei pagini este "+contor);<br />

out.println("");<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

6.4.5 Autorizarea accesului prin parola<br />

Parolele celor îndreptăt¸it¸i să acceseze servletul sunt cuprin¸si într-un fi¸sier. În<br />

servlet accesul la fi¸sier se realizează prin preluarea unui parametru a cărei valoare<br />

este numele fi¸sierului.<br />

Servlet-ul solicită afi¸sarea pe ma¸sina clientului a unei căsut¸e <strong>de</strong> dialog prin<br />

care clientul introduce numele ¸si parola. Dacă datele coincid cu cele înregistrate<br />

în fi¸sier atunci se autorizează accesul la servlet.<br />

Date transmise <strong>de</strong> client sunt codificate. Decodificarea se poate realiza cu<br />

clasa Base64Co<strong>de</strong>r : www.source-co<strong>de</strong>.biz, Christian d’Heureuse, Inventec Informatik<br />

AG, Switzerland.<br />

Exemplul 6.4.5<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import java.util.Properties;<br />

public class ProtectedPage extends HttpServlet{<br />

private Properties passwords;<br />

private String passwordFile;<br />

// Parolele sunt intr-un fisier "parole"<br />

// sub forma nume=parola.<br />

public void init(ServletConfig config)throws ServletException {<br />

super.init(config);<br />

try {<br />

passwordFile = config.getInitParameter("passwordFile");<br />

passwords = new Properties();<br />

passwords.load(new FileInputStream(passwordFile));<br />

}<br />

catch(IOException ioe) {}<br />

}<br />

public void doGet(HttpServletRequest request,HttpServletResponse response)<br />

throws ServletException, IOException {<br />

response.setContentType("text/html");<br />

PrintWriter out = response.getWriter();<br />

String authorization = request.getHea<strong>de</strong>r("Authorization");<br />

if (authorization == null) {<br />

cerParola(response);


122 CAPITOLUL 6. SERVLET<br />

}<br />

else{<br />

String userInfo = authorization.substring(6).trim();<br />

String nameAndPassword = Base64Co<strong>de</strong>r.<strong>de</strong>co<strong>de</strong>String(userInfo);<br />

System.out.println(nameAndPassword);<br />

int in<strong>de</strong>x = nameAndPassword.in<strong>de</strong>xOf(":");<br />

String user = nameAndPassword.substring(0, in<strong>de</strong>x);<br />

String password = nameAndPassword.substring(in<strong>de</strong>x+1).trim();<br />

passwords.list(System.out);<br />

String realPassword = passwords.getProperty(user);<br />

System.out.println(user+" "+password+" "+realPassword);<br />

if ((realPassword != null)&&(realPassword.equals(password))){<br />

String title = "Welcome to the Protected Page";<br />

out.println(""+title+"" +<br />

"\n"+"" + title + "\n" +<br />

"Aveti acces la pagina"+"");<br />

}<br />

else {<br />

cerParola(response);<br />

}<br />

}<br />

}<br />

// Cererea a fost fara autorizare<br />

private void cerParola(HttpServletResponse response) {<br />

response.setStatus(response.SC_UNAUTHORIZED); // Ie 401<br />

response.setHea<strong>de</strong>r("WWW-Authenticate",<br />

"BASIC realm=\"privileged-few\"");<br />

}<br />

public void doPost(HttpServletRequest request,HttpServletResponse response)<br />

throws ServletException, IOException {<br />

doGet(request, response);<br />

}<br />

}<br />

Parolele se ret¸in într-un fi¸sier <strong>de</strong>numit parole.properties alcătuit <strong>din</strong> înregistrări<br />

<strong>de</strong> forma nume=parolă, câte o înregistrare pe linie. Localizarea fi¸sierului se obt¸ine<br />

prin intermediul datelor <strong>din</strong> elementul<br />

<br />

passwordFile<br />

d:\\apache-tomcat-*.*.*\\. . .\\parole.properties<br />

<br />

Acest element apare în corpul elementului ata¸sat servlet-ului. Servletul<br />

se apelează prin http://host:port/context/numeApel.<br />

6.4.6 Servlet cu conexiune la o bază <strong>de</strong> date<br />

Folosind Anexa C consi<strong>de</strong>răm<br />

Exemplul 6.4.6 Consultarea unei agen<strong>de</strong> telefonice. Se utilizează o bază <strong>de</strong> date<br />

AgendaTelefonica alcătuită <strong>din</strong>tr-un singur tabel telef (nume varchar(20), numar<br />

varchar(20)).


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 123<br />

Utilizând SGBD <strong>de</strong>rby servletul este<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import java.sql.*;<br />

public class Telef extends HttpServlet{<br />

Statement instructiune=null;<br />

public void init(ServletConfig config) throws ServletException{<br />

super.init(config);<br />

String jdbcDriver="org.apache.<strong>de</strong>rby.jdbc.ClientDriver";<br />

String URLBazaDate="jdbc:<strong>de</strong>rby://localhost:1527/AgendaTelefonica";<br />

/*<br />

//Cazul SGBD Access<br />

String jdbcDriver="sun.jdbc.odbc.JdbcOdbcDriver";<br />

String URLBazaDate="jdbc:odbc:AgendaTelefonica";<br />

//Cazul SGBD Mysql<br />

String jdbcDriver="com.mysql.jdbc.Driver";<br />

String URLBazaDate="jdbc:mysql://localhost:3306/AgendaT?user=root";<br />

*/<br />

Connection con=null;<br />

try{<br />

Class.forName(jdbcDriver).newInstance();<br />

con=DriverManager.getConnection(URLBazaDate);<br />

instructiune=con.createStatement();<br />

}<br />

catch(ClassNotFoundException e){<br />

System.out.println("N-am gasit driverul JDBC: "+jdbcDriver);<br />

}<br />

catch(SQLException e){<br />

System.out.println("Eroare cautare date <strong>din</strong> "+URLBazaDate);<br />

}<br />

catch(Exception e){<br />

System.out.println("Eroare : "+e.getMessage());<br />

}<br />

}<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

String myAtribut,myVal;<br />

res.setContentType("text/html");<br />

ServletOutputStream out = res.getOutputStream();<br />

// Preluarea valorii unui parametru<br />

myAtribut=req.getParameter("criteriu");<br />

myVal=req.getParameter("termen");<br />

myVal=’\’’+myVal+’\’’;<br />

try{<br />

String sql="select * from telef where "+ myAtribut+" = "<br />

+myVal;<br />

ResultSet rs=instructiune.executeQuery(sql);<br />

out.println("");<br />

out.println("AgendaTelefonica");<br />

out.println("");<br />

out.println("Agenda Telefonica");


124 CAPITOLUL 6. SERVLET<br />

while(rs.next()){<br />

out.print(rs.getString("nume")+" are numarul <strong>de</strong> telefon:"+<br />

rs.getString("numar"));<br />

}<br />

out.println("");<br />

out.println("");<br />

out.close();<br />

}<br />

catch(SQLException e){<br />

System.out.println("SQLException: "+e.getMessage());<br />

}<br />

catch(Exception e){<br />

System.out.println("Eroare : "+e.getMessage());<br />

}<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

Utilizarea servlet-ului se face <strong>din</strong><br />

<br />

<br />

<br />

Cautare in baza <strong>de</strong> date telefica<br />

<br />

<br />

<br />

<br />

Cautare in baza <strong>de</strong> date a Societatii <strong>de</strong> telefoane<br />

<br />

<br />

Criteriu <strong>de</strong> cautare:<br />

<br />

dupa Nume<br />

dupa Numar<br />

<br />

<br />

Entitatea cautata<br />

<br />

<br />

<br />

<br />

<br />

<br />

Testarea aplicat¸iei presupune:<br />

1. Realizarea bazei <strong>de</strong> date:<br />

2. Testarea servlet-ului:<br />

(a) Pornirea serverului bazei <strong>de</strong> date.


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 125<br />

(b) Se verifică prezent¸a în catalogul servlet-ului ...\WEB-INF\lib a fi¸sierului<br />

<strong>de</strong>rbyclient.jar sau mysql-connector-java-*.*.*-bin.jar.<br />

(c) Pornirea serverului tomcat sau reîncărcarea servlet-ului.<br />

(d) Apelarea servlet-ului <strong>din</strong> pagina Web.<br />

6.4.7 Imagini furnizate <strong>de</strong> servlet<br />

Indicăm două modalităt¸i prin care un client obt¸ine o imagine furnizată <strong>de</strong><br />

un servlet. Imaginea poate proveni <strong>din</strong>tr-un fi¸sier extern sau poate fi creată <strong>de</strong><br />

servlet.<br />

• Imaginea este transmisă direct clientului<br />

response.setContentType("image/gif");<br />

În cazul unui fi¸sier extern imaginea este refăcută în memorie ¸si în fluxul <strong>de</strong><br />

ie¸sire <strong>de</strong> tip ServletOutputStream se transmite recodarea imaginii în format<br />

gif. Această recodare se poate face cu pachetul Acme.JPM.Enco<strong>de</strong>rs,<br />

disponibil gratuit la adresa web http://www.acme.com.<br />

Preluarea imaginii <strong>din</strong>tr-un fi¸sier se programează<br />

Image image=Toolkit.getDefaultToolkit().getImage(String<br />

referint¸ăFi¸sier);<br />

Textul sursă al servlet-ului este:<br />

import java.io.*;<br />

import java.awt.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import Acme.JPM.Enco<strong>de</strong>rs.GifEnco<strong>de</strong>r;<br />

public class MyGraphG extends HttpServlet{<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException, IOException{<br />

res.setContentType("image/gif");<br />

// iesire prin flux <strong>de</strong> octeti<br />

ServletOutputStream out = res.getOutputStream();<br />

// Referinta la fisierul grafic<br />

String f="d:\\apache-tomcat-*.*.*\\webapps\\myservlet\\<br />

WEB-INF\\classes\\walking_santa.gif";<br />

// Preluarea imaginii grafice<br />

Image image=Toolkit.getDefaultToolkit().getImage(f);<br />

// Transmiterea imaginii utilizand pachetul<br />

GifEnco<strong>de</strong>r enco<strong>de</strong>r = new GifEnco<strong>de</strong>r(image, out);<br />

enco<strong>de</strong>r.enco<strong>de</strong>();<br />

}<br />

}


126 CAPITOLUL 6. SERVLET<br />

• Pe server imaginea se salvează într-un fi¸sier jpg sau png, după care servletul<br />

scrie în fluxul <strong>de</strong> ie¸sire un document html ce apelează fi¸sierul cu imaginea<br />

creată anterior. Navigatorul clientului va <strong>de</strong>scărca ¸si vizualiza imaginea.<br />

Textul sursă al servlet-ului este:<br />

import java.io.*;<br />

import java.awt.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import javax.imageio.*;<br />

import java.awt.image.*;<br />

import javax.imageio.stream.*;<br />

import java.util.*;<br />

public class MyGraphP extends HttpServlet {<br />

public void doGet(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException, IOException {<br />

res.setContentType("text/html");<br />

PrintWriter out=res.getWriter();<br />

String numeFis="<strong>de</strong>sen";<br />

String ext="jpg"; // sau "png"<br />

// Formarea imaginii<br />

Frame frame = null;<br />

Graphics g = null;<br />

BufferedImage image=null;<br />

try{<br />

frame = new Frame();<br />

// addNotify : Cadrul Frame <strong>de</strong>vine afisabil prin<br />

// legarea lui la o resursa nativa a ecranului.<br />

// Proprietatea se mosteneste <strong>de</strong> toti <strong>de</strong>scen<strong>de</strong>ntii<br />

// cadrului<br />

frame.addNotify();<br />

image = (BufferedImage)frame.createImage(800, 60);<br />

g = image.getGraphics();<br />

// Fixarea fontului<br />

g.setFont(new Font("Serif", Font.ITALIC, 48));<br />

// Editarea unui text<br />

g.drawString(" Tehnologii distribuite in Java", 10, 50);<br />

// Salvarea imaginii intr-un fisier jpg sau png<br />

File f=new File(numeFis+"."+ext);<br />

ImageIO.write(image,"jpg",f);<br />

// Raspunsul catre client<br />

out.println("");<br />

out.println("Imagine preluata <strong>de</strong> pe server ");<br />

out.println("");<br />

out.println("Vizualizarea imaginii ");<br />

out.println("");<br />

out.close();<br />

}<br />

finally{


6.4. FACILITĂT¸ I DE PROGRAMARE CU SERVLET 127<br />

// Eliberarea resurselor<br />

if (g != null) g.dispose();<br />

if (frame != null) frame.removeNotify();<br />

}<br />

}<br />

}<br />

6.4.8 Servlet cu RMI<br />

Un servlet poate fi client al unei aplicat¸ii RMI. Interfat¸a la diatant¸ă se <strong>de</strong>pune<br />

în catalogul WEB-INF\lib al servletului. Apelarea programului server RMI se face<br />

prin<br />

InterfataDistanta obj=(InterfataDistanta)<br />

Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");<br />

Exemplul 6.4.7 Client servlet pentru aplicat¸ia RMI <strong>de</strong> calcul al celui mai mare<br />

divizor comun a două numere naturale.<br />

import java.io.*;<br />

import java.rmi.*;<br />

import java.rmi.registry.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import cmmdc.*;<br />

public class ServletRMI extends HttpServlet {<br />

public void doGet(HttpServletRequest req, HttpServletResponse res)<br />

throws ServletException, IOException {<br />

res.setContentType("text/html");<br />

PrintWriter out = res.getWriter();<br />

String sm=req.getParameter("m"),sn=req.getParameter("n");<br />

long m=(new Long(sm)).longValue(),n=(new Long(sn)).longValue();<br />

long x=0;<br />

String host=req.getParameter("host").trim();<br />

String sPort=req.getParameter("port");<br />

int port=Integer.parseInt(sPort);<br />

try{<br />

ICmmdc obj=(ICmmdc)Naming.lookup("//"+host+":"+port+"/CmmdcServer");<br />

x=obj.cmmdc(m,n);<br />

}<br />

catch (Exception e) {<br />

System.out.println("CmmdcClient exception: "+e.getMessage());<br />

}<br />

String title="CmmdcServlet";<br />

res.setContentType("text/html");<br />

out.println("");<br />

out.println(title);<br />

out.println("");<br />

out.println(""+title+"");<br />

out.println("Cmmdc : "+x);


128 CAPITOLUL 6. SERVLET<br />

out.println("");<br />

out.close();<br />

}<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException{<br />

doGet(req,res);<br />

}<br />

}<br />

6.5 FileUpload<br />

Deseori clientul trebuie să furnizeze unui servlet un volum mare <strong>de</strong> date,<br />

<strong>de</strong>pozitate într-un fi¸sier. Un produs care ne ajută să în<strong>de</strong>plinim acest obiectiv<br />

este commons-fileupload - <strong>de</strong>zvoltat <strong>de</strong> apache.<br />

Commons-FileUpload - <strong>de</strong>zvoltat în cadrul apache - este un produs care simplifică<br />

transferul unui fi¸sier <strong>de</strong> la un client la programul server (file upload).<br />

Interfat¸a <strong>de</strong> programare a produsului se referă la partea <strong>de</strong> server - în cazul <strong>de</strong><br />

fat¸ă reprezentat prin servlet.<br />

Instalarea produsului constă <strong>din</strong> <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scărcat <strong>din</strong> Internet.<br />

În plus este nevoie <strong>de</strong><br />

• commons-io<br />

Fi¸sierele<br />

• commons-fileupload-*.*.jar<br />

• commons-io-*.*.jar<br />

se <strong>de</strong>pun în catalogul lib al servlet-ului.<br />

Transferarea unui fi¸sier, <strong>din</strong> partea clientului nu ridică nici o problemă. În<br />

fi¸sierul html <strong>de</strong> apelare, se <strong>de</strong>fine¸ste un formular<br />

<br />

iar un fi¸sier <strong>de</strong> încărcat se fixează prin intermediul marcajului<br />

<br />

Programul navigator afi¸sează o fereastră <strong>de</strong> căutare, prin care clientul selectează<br />

fi¸sierul pe care dore¸ste să-l încarce.<br />

Dacă partea <strong>de</strong> client este un program, atunci se utilizează commons-httpclient.<br />

6.4.1<br />

De partea serverului, programarea încărcării revine la


6.5. FILEUPLOAD 129<br />

1. Crearea unei fabrici pentru manipularea fi¸sierelor pe disc<br />

FileItemFactory factory = new DiskFileItemFactory();<br />

2. Crearea unei unelte <strong>de</strong> încărcare<br />

ServletFileUpload upload = new ServletFileUpload(factory);<br />

3. Analiza (parsarea) mesajului furnizat <strong>de</strong> client<br />

List fileItems = upload.parseRequest(req);<br />

Fiecare element al listei implementează interfat¸a FileItem.<br />

Se pot fixa parametrii<br />

• dimensiunea zonei <strong>de</strong> pe disc <strong>de</strong>stinată datelor <strong>de</strong> încărcat<br />

DiskFileItemFactory factory = new DiskFileItemFactory();<br />

factory.setSizeThreshold(maxMemorySize);<br />

• catalogul temporar <strong>de</strong> ret¸inere a datelor <strong>de</strong> încărcat<br />

factory.setRepositoryPath(tempDirectory);<br />

sau direct<br />

DiskFileItemFactory factory = new DiskFileItemFactory(<br />

maxMemorySize, tempDirectory);<br />

• dimensiunea maximă a unui fi¸sier<br />

upload.setSizeMax(maxRequestSize);<br />

4. Prelucrarea elementelor încărcate<br />

Iterator iter=fileItems.iterator();<br />

while (iter.hasNext()) {<br />

FileItem item = (FileItem) iter.next();<br />

if (item.isFormField()) {<br />

// Prelucrarea elementului item care corespun<strong>de</strong> unei<br />

// date <strong>din</strong> formularul html care nu este <strong>de</strong> tip fisier<br />

}<br />

else{<br />

// Prelucrarea elementului item <strong>de</strong> tip fisier<br />

}<br />

}


130 CAPITOLUL 6. SERVLET<br />

5.<br />

6.<br />

În cazul unui element care nu este <strong>de</strong> tip fi¸sier putem obt¸ine numele ¸si<br />

valoarea atributului furnizat <strong>de</strong> client<br />

String name = item.getFieldName();<br />

String value = item.getString();<br />

În cazul unui fi¸sier putem afla numele câmpului input, numele fi¸sierului,<br />

dimensiunea fi¸sierului<br />

String fieldName = item.getFieldName();<br />

String fileName = item.getName();<br />

long sizeInBytes = item.getSize();<br />

7. Dacă dorim să salvăm fi¸sierul pe calculatorul server atunci prelucrarea este<br />

File uploa<strong>de</strong>dFile = new File(...);<br />

item.write(uploa<strong>de</strong>dFile);<br />

8. Dacă datele fi¸sierului se încarcă în memoria calculatorului atunci prelucrarea<br />

este<br />

InputStream in = item.getInputStream();<br />

//preluarea datelor <strong>din</strong> fluxul in<br />

. . .<br />

in.close();<br />

Alternativ, datele se pot ret¸ine ca un ¸sir <strong>de</strong> octet¸i prin<br />

byte[] data = item.get();<br />

Exemplul 6.5.1 Să se obt¸ină în memoria serverului matricea cont¸inută într-un<br />

fi¸sier text. În fi¸sierul text, fiecare linie cont¸ine o linie a matricei, iar elementele<br />

sunt separate prin spat¸ii.<br />

Metoda getMatrix utilizată reface matricea <strong>din</strong> datele fi¸sierului.<br />

package upload;<br />

import java.io.*;<br />

import javax.servlet.*;<br />

import javax.servlet.http.*;<br />

import java.util.*;<br />

import org.apache.commons.fileupload.disk.*;<br />

import org.apache.commons.fileupload.servlet.*;<br />

import org.apache.commons.fileupload.*;<br />

public class FileUploadServlet extends HttpServlet{


6.5. FILEUPLOAD 131<br />

public void doPost(HttpServletRequest req,HttpServletResponse res)<br />

throws ServletException,IOException {<br />

res.setContentType("text/plain");<br />

ServletOutputStream out = res.getOutputStream();<br />

try{<br />

boolean isMultipart = ServletFileUpload.isMultipartContent(req);<br />

FileItemFactory factory = new DiskFileItemFactory();<br />

ServletFileUpload upload = new ServletFileUpload(factory);<br />

List items = upload.parseRequest(req);<br />

upload.setSizeMax(1000000);<br />

Iterator iter=items.iterator();<br />

while (iter.hasNext()) {<br />

FileItem item = (FileItem) iter.next();<br />

if (!item.isFormField()) {<br />

String fileName = item.getName();<br />

out.println(fileName);<br />

long sizeInBytes = item.getSize();<br />

out.println(sizeInBytes);<br />

InputStream in=item.getInputStream();<br />

InputStreamRea<strong>de</strong>r isr=new InputStreamRea<strong>de</strong>r(in);<br />

BufferedRea<strong>de</strong>r br=new BufferedRea<strong>de</strong>r(isr);<br />

double[][] matrix=getMatrix(br);<br />

int m=matrix.length;<br />

int n=matrix[0].length;<br />

for(int i=0;i


132 CAPITOLUL 6. SERVLET<br />

while(line!=null);<br />

if(v.size()>0){<br />

mn=v.size();<br />

n=mn/m;<br />

matrix=new double[m][n];<br />

for(int i=0;i<br />

<br />

Inc&#259;rcarea unui fi&#351;ier <br />

<br />

<br />

Selecta&#355;i fi&#351;ierul<br />

<br />

<br />

<br />

<br />

<br />

<br />


Capitolul 7<br />

Java Server Page – JSP<br />

7.1 Tehnologia JSP<br />

JSP permite inclu<strong>de</strong>rea codului Java într-un document html. Un asemenea<br />

document se <strong>de</strong>pozitează pe un server Web, container <strong>de</strong> servlet¸i, cu extensia<br />

jsp, eventual jspx.<br />

Apelarea documentului JSP se realizează prin<br />

• meniul File/Open a unui navigator, cu<br />

http://host:port/contex/doc.jsp<br />

• referint¸ă html<br />

<br />

• valoare a atributului action într-un marcaj form<br />

<br />

Prin context se înt¸elege calea <strong>de</strong> la catalogul webapps până la catalogul ce<br />

cont¸ine fi¸sierul jsp.<br />

În cazul serverului Web tomcat vom <strong>de</strong>pozita fi¸sierele JSP într-un catalog jsp<br />

<strong>din</strong> arborele<br />

webapps<br />

|--> JSPApp<br />

|--> WEB-INF<br />

|--> classes<br />

|--> web.xml<br />

|--> jsp<br />

|--> doc.jsp<br />

caz în care contextul va fi JSPApp/jsp.<br />

Astfel, schimbând numele fi¸sierului Hello.html<br />

133


134 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

<br />

<br />

Hello<br />

<br />

<br />

în Hello.jsp ¸si plasându-l în catalogul jsp se obt¸ine acela¸si efect, dar prelucrarea<br />

paginilor / documentelor este diferită. Fi¸sierul html este prelucrat doar <strong>de</strong> programul<br />

navigator ¸si poate fi <strong>de</strong>schis ca fi¸sier, în timp ce fi¸sierul JSP este prelucrat <strong>de</strong><br />

serverul Web cu afi¸sarea prin intermediul navigatorului. Prelucrarea efectuată<br />

<strong>de</strong> serverul Web constă <strong>din</strong> transformarea paginii / documentului JSP într-un<br />

servlet, care este compilat ¸si lansat în execut¸ie. Din aceastră cauză prima invocare<br />

a paginii / documentului JSP durează mai mult <strong>de</strong>cât apelările ulterioare.<br />

Apelarea paginii / documentului JSP se face prin<br />

http://localhost:8080/JSPApp/jsp/Hello.jsp<br />

Există două moduri <strong>de</strong> a inclu<strong>de</strong> elemente JSP într-un text html:<br />

• prin elemente specifice JSP.<br />

Fi¸sierul are extensia jsp ¸si se nume¸ste pagină JSP.<br />

• prin marcaje xml apart¸inând spat¸iului <strong>de</strong> nume<br />

http://java.sun.com/JSP/Page<br />

Fi¸sierul poate avea extensia jsp sau jspx ¸si se nume¸ste document JSP.<br />

Comentariile JSP se scriu <strong>de</strong> forma<br />

<br />

Consi<strong>de</strong>răm următoarul exemplu introductiv:<br />

Exemplul 7.1.1 Putem afi¸sa valoarea unei variabile Java (<strong>de</strong> exemplu data calendaristică)<br />

prin<br />

• Varianta paginii JSP<br />

<br />

<br />

<br />

Data calendaristica 1:<br />

<br />

<br />

<br />

Data calendaristica 2:<br />

<br />


7.1. TEHNOLOGIA JSP 135<br />

<br />

Data calendaristica 3:<br />

<br />

<br />

<br />

Dacă se utilizează operatorul <strong>de</strong> afi¸sare = atunci după expresia <strong>de</strong> afi¸sat nu<br />

se pune ;.<br />

Variabila pre<strong>de</strong>finită out este <strong>de</strong> tip javax.servlet.jsp.JspWriter.<br />

• Varianta documentului JSP<br />

<br />

<br />

<br />

<br />

java.util.Date d=new java.util.Date();<br />

<br />

d <br />

<br />

<br />

Codul Java inglobat într-un text html se nume¸ste scriptlet. Sintaxa utilizată<br />

este<br />

• Varianta paginii JSP<br />

• Varianta documentului JSP<br />

<br />

codJava <br />

Domeniul <strong>de</strong> valabilitate. Domeniul <strong>de</strong> valabilitate <strong>de</strong>fine¸ste intervalul <strong>de</strong><br />

timp, <strong>de</strong> existent¸ă al unui obiect. În cadrul unei pagini / document JSP sunt<br />

<strong>de</strong>finite domeniile <strong>de</strong> valabilitate prin valorile:<br />

Valoare Domeniu <strong>de</strong> vizibilitate<br />

page pagina curentă<br />

request în pagina curentă,<br />

în paginile incluse ¸si<br />

în paginile către care se face o redirectare<br />

session în sesiunea curentă<br />

application pe durata rulării aplicat¸iei<br />

În orice pagină / document JSP sunt pre<strong>de</strong>finite variabilele:


136 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

Variabila Tip/Clasa<br />

out javax.servlet.jsp.JspWriter<br />

request javax.servlet.ServletRequest<br />

response javax.servlet.ServletResponse<br />

session javax.servlet.http.HttpSession<br />

page java.lang.Object, this<br />

pageContext javax.servlet.jsp.PageContext<br />

application javax.servlet.ServletContext<br />

ServletContext.getServletConfig().getContext()<br />

exception java.lang.Throwable<br />

Astfel<br />

String request.getParameter(String numeParametru)<br />

furnizează valoarea parametrului numeParametru <strong>din</strong>tr-un formular html.<br />

Exemplul 7.1.2 Pagina JSP Hello: Clientul transmite numele paginii care îi<br />

răspun<strong>de</strong> cu mesajul <strong>de</strong> salut ”Hi nume!”.<br />

Codul paginii JPS (hello.jsp) este<br />

<br />

<br />

jsphello <br />

<br />

<br />

<br />

Pagina <strong>de</strong> r&#259;spuns <br />

<br />

<br />

<br />

<br />

<br />

apelat <strong>din</strong> (in<strong>de</strong>x.html)<br />

<br />

<br />

JSP Hello <br />

<br />

<br />

<br />

Pagina <strong>de</strong> apelare JSP <br />

<br />

Numele:<br />

<br />

<br />


7.1. TEHNOLOGIA JSP 137<br />

<br />

<br />

<br />

<br />

Compilarea ¸si arhivarea servlet-ului o vom realiza prin intermediul lui apacheant.<br />

În acest scop se crează structura:<br />

jsphello<br />

| |---> jsp<br />

| | | hello.jsp<br />

| |---> lib<br />

| |---> src<br />

| |---> web<br />

| | | web.xml<br />

| |---> web-files<br />

| | | in<strong>de</strong>x.html<br />

| build.xml<br />

Fi¸sierul web.xml este simplu<br />

<br />

<br />

<br />

<br />

in<strong>de</strong>x.html<br />

in<strong>de</strong>x.jsp<br />

<br />

<br />

Fi¸sierul build.xml prelucrat <strong>de</strong> apache-ant folosit este<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


138 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

7.1.1 Declarat¸ii JSP<br />

Într-un scriplet, printr-o <strong>de</strong>clarat¸ie JSP, putem <strong>de</strong>fini câmpuri(variabile) ¸si<br />

meto<strong>de</strong> Java ce pot fi apoi folosite, respectiv apelate în documentul respectiv. O<br />

<strong>de</strong>clarat¸ie JSP se <strong>de</strong>fine¸ste printr-un marcaj<br />

sau, în format XML<br />

<br />

. . . <br />

Există două meto<strong>de</strong> jspInit() - utilizată pentru init¸ializarea datelor -, ¸si<br />

jspDestroy() - utilizată pentru eliberarea resurselor -, care dacă sunt <strong>de</strong>clarate<br />

<strong>de</strong> programator atunci sunt executate la începutul ¸si la sfâr¸situl ciclului <strong>de</strong> execut¸ie<br />

a paginii / documentului JSP.


7.1. TEHNOLOGIA JSP 139<br />

7.1.2 Directive JSP<br />

Directivele JSP fixează informat¸ii pentru tot documentul jsp. O directivă jsp<br />

se indică prin marcajul<br />

sau în format XML<br />

<br />

<br />

un<strong>de</strong> fiecare atribut are sintaxa nume=valoare.<br />

Directivele pot fi: page, inclu<strong>de</strong>, taglib.<br />

• Directiva page are atributele<br />

extends= ”numeClasă” Servlet-ul corespunzător paginii jsp extin<strong>de</strong><br />

clasa numeClasă.<br />

import= ”listă <strong>de</strong> pachete separate prin ,”<br />

session= "true | false"<br />

info= ”text” Informat¸ia se poate regăsi apelând metoda<br />

Servlet.getServletInfo()<br />

errorPage= ”adresa url a paginii ce tratează except¸ia”<br />

isErrorPage= "true | false"<br />

• Directiva inclu<strong>de</strong> permite inclu<strong>de</strong>rea unor fi¸siere .html sau .jsp în document<br />

<br />

• Directiva taglib indică bibliotecile <strong>de</strong> marcaje utilizate în documentul jsp,<br />

având atributele<br />

uri= ”uri - Universal Resource I<strong>de</strong>ntifier - a bibliotecii <strong>de</strong> marcaje”<br />

prefix= ”prefixul marcajului”<br />

7.1.3 Marcaje JSP pre<strong>de</strong>finite<br />

Un marcaj JSP <strong>de</strong>fine¸ste o act¸iune care se execută în timpul procesării paginii<br />

jsp. Sintaxa marcajelor JSP seamănă cu cea a marcajelor html sau xml<br />

<br />

Dintre marcajele JSP pre<strong>de</strong>finite – adică cu prefixul JSP – amintim:<br />


140 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

• <br />

În cazul marcajelor , se pot transmite<br />

parametri prin marcajele incluse<br />

<br />

. . . . . .<br />

<br />

• <br />

un<strong>de</strong> domeniu precizează domeniul <strong>de</strong> vizibilitate al componentei Java,<br />

adică page, request, session, application.<br />

• <br />

Acest marcaj este echivalent cu codul Java<br />

numeComponentăJava.setNumeProp(valoare).<br />

• <br />

Daca numeProp=* atunci toate proprietăt¸ile componentei sunt accesibile.<br />

7.1.4 Componentă Java (Java Bean)<br />

O componentă Java este o clasă care poate interact¸iona cu alte componente<br />

Java, cu un document jsp, etc.<br />

O componenta Java cont¸ine cel put¸in<br />

• Un constructor fără nici un argument;<br />

• O mult¸ime <strong>de</strong> câmpuri <strong>de</strong>clarate private;<br />

• Pentru fiecare asemenea câmp<br />

private Tip xyz;<br />

trebuie <strong>de</strong>finite meto<strong>de</strong>le


7.1. TEHNOLOGIA JSP 141<br />

public void setXyz(Tip xyz){<br />

this.xyz=xyz;<br />

}<br />

public Tip getXyz(){<br />

return xyz;<br />

}<br />

7.1.5 Pagini JSP cu componente Java<br />

Numele parametrilor <strong>din</strong> formularelele <strong>de</strong> introducere a datelor trebuie să<br />

coincidă cu i<strong>de</strong>ntificatorii câmpurilor <strong>din</strong> componenta Java corespunzătoare.<br />

Reluăm exemplul 7.1.2 cu o componentă Java corespunzătoare numelui <strong>din</strong><br />

formularul in<strong>de</strong>x.html.<br />

Exemplul 7.1.3<br />

package jsp;<br />

public class HelloBean {<br />

private String name="";<br />

public String getName() {<br />

return name;<br />

}<br />

public void setName(String name) {<br />

this.name=name;<br />

}<br />

}<br />

În acest caz, pagina JSP este<br />

<br />

<br />

<br />

<br />

jsphello <br />

<br />

<br />

Pagina <strong>de</strong> r&#259;spuns <br />

<br />

<br />

<br />

<br />

<br />

Mai mult, se poate inclu<strong>de</strong> formularul în pagina JSP, bineînt¸eles ¸stergându-l<br />

<strong>din</strong> fi¸sierul html:<br />

jsp:useBean id="obj" class="jsp.HelloBean" scope="request"/><br />


142 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

<br />

<br />

jsphello <br />

<br />

<br />

<br />

Pagina JSP - aplica&#355;ia Hello <br />

<br />

Introduceti numele: <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Desfă¸surarea aplicat¸iei în ve<strong>de</strong>rea generării arhivei war va fi<br />

jsphello<br />

| |---> jsp<br />

| | | hello.jsp<br />

| |---> lib<br />

| |---> src<br />

| | |---> jsp<br />

| | | | HelloBean.java<br />

| |---> web<br />

| | | web.xml<br />

| |---> web-files<br />

| | | in<strong>de</strong>x.html<br />

| build.xml<br />

Exemplul 7.1.4 Pagină JSP pentru calculul celui mai mare divizor comun.<br />

Documentului html<br />

<br />

<br />

Calculul Cmmdc <br />

<br />

<br />

Primul numar este<br />

<br />

<br />

Al doilea numar este<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

îi corespun<strong>de</strong> componenta Java


7.1. TEHNOLOGIA JSP 143<br />

package cmmdc;<br />

public class CmmdcBean{<br />

private String m="";<br />

private String n="";<br />

public void setM(String m){<br />

this.m=m;<br />

}<br />

public void setN(String n){<br />

this.n=n;<br />

}<br />

public String getM(){<br />

return m;<br />

}<br />

public String getN(){<br />

return n;<br />

}<br />

}<br />

Instant¸iem o componenta Java ¸si îi fixăm proprietăt¸ile (adică îi transmitem<br />

parametri problemei) după care apelăm metoda ce calculează rezultatul dorit:<br />

<br />

<br />

<br />

<br />

<br />

Cel mai mare divizor comun al numerelor<br />

<br />

si <br />

<br />

este<br />

<br />

<br />

<br />

Exemplul 7.1.5 Generarea unei except¸ii (errhandler.jsp):<br />

<br />

<br />

<br />


144 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

%><br />

<br />

<br />

cu pagina <strong>de</strong> tratare a except¸iei (errorpage.jsp)<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

apelate prin<br />

<br />

<br />

<br />

Care este materia preferata <strong>din</strong> anii <strong>de</strong> studiu universitar ?<br />

<br />

Algoritmica si programare<br />

<br />

<br />

Analiza numerica<br />

<br />

<br />

Inteligenta artificiala<br />

<br />

<br />

<br />

<br />

<br />

<br />

7.2 JSP Standard Tag Library JSTL<br />

JSTL este o familie <strong>de</strong> biblioteci <strong>de</strong> marcaje ce oferă o serie <strong>de</strong> facilităt¸i<br />

activităt¸ii <strong>de</strong> realizare a paginilor Web. JSTL ajută la separarea activităt¸ii <strong>de</strong><br />

programare <strong>de</strong> aceea a proiectare (<strong>de</strong>sign) a paginii Web.


7.2. JSP STANDARD TAG LIBRARY JSTL 145<br />

JSTL este alcătuită <strong>din</strong> 5 biblioteci:<br />

URI Descriere<br />

http://java.sun.com/jsp/jstl/core Biblioteca <strong>de</strong> bază<br />

http://java.sun.com/jsp/jstl/xml Biblioteca <strong>de</strong> prelucrare<br />

a documentelor xml<br />

http://java.sun.com/jsp/jstl/fmt Biblioteca <strong>de</strong> formatare a datelor<br />

http://java.sun.com/jsp/jstl/sql Biblioteca <strong>de</strong> lucru cu baze <strong>de</strong> date<br />

http://java.sun.com/jsp/jstl/functions Biblioteca <strong>de</strong> funct¸ii ajutătoare<br />

Instalarea bibliotecilor. Bibliotecile sunt livrate împreună cu apachetomcat-*<br />

în catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prin<br />

fi¸sierele jstl.jar ¸si standard.jar.<br />

Utilizarea bibliotecilor. În ve<strong>de</strong>rea utilizării, cele două fi¸siere trebuie copiate<br />

în catalogul apache-tomcat-*.*\shared\lib<br />

În pagina / documentul JSP, o bibliotecă utilizată trebuie <strong>de</strong>clarată printr-o<br />

directivă taglib.<br />

7.2.1 Biblioteca <strong>de</strong> bază<br />

<br />

Marcaje <strong>din</strong> biblioteca <strong>de</strong> bază:<br />

• c:set Fixează o valoare într-o variabilă.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

var obligatoriu Numele variabilei ce va stoca valoarea<br />

expresiei.<br />

value opt¸ional Expresia care va fi evaluată ¸si atribuită<br />

variabilei<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei.<br />

Unul <strong>din</strong> valorile:<br />

page, request, session, application.<br />

Referirea la o variabilă se face prin sintaxa ${numeVariabilă}<br />

Referirea la valoarea unui câmp <strong>din</strong>tr-un formular se face prin sintaxa<br />

${param.numeCâmp}<br />

Alături <strong>de</strong> obiectul param, alte obiecte pre<strong>de</strong>finite sunt cookie, hea<strong>de</strong>r,<br />

initParam, pageContext.<br />

Se pot <strong>de</strong>fini variabile cu acela¸si nume dar având domenii <strong>de</strong> vizibilitate<br />

diferită. Referirea se face prin ${pageScope.numeVariabilă},


146 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

${requestScope.numeVariabilă}, ${sessionScope.numeVariabilă},<br />

${applicationScope.numeVariabilă}.<br />

Plasând clauza empty înaintea unei variabile, ${empty numeVariabilă}, se<br />

obt¸ine false sau true după cum variabila are sau nu atribuită o valoare.<br />

• c:remove S¸terge o variabilă.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

var obligatoriu Numele variabilei ce se ¸sterge.<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei.<br />

Unul <strong>din</strong> valorile:<br />

page, request, session, application.<br />

• c:out Afi¸sează o valoare.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

value obligatoriu Valoarea ce se evaluează ¸si se afi¸sează.<br />

<strong>de</strong>fault opt¸ional Cea ce se afi¸sează în cazul în care<br />

expresia nu poate fi evaluată.<br />

escapeXml opt¸ional true / false. Valoarea implicită este true.<br />

Pe false interpretează caracterele <strong>din</strong> value<br />

ca ¸si cod html.<br />

• c:if Test, verificarea unei condit¸ii.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

test obligatoriu Condit¸ia <strong>de</strong> test.<br />

var opt¸ional Numele variabilei ce va stoca valoarea<br />

testului.<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei<br />

<strong>de</strong>finită anterior.<br />

În cazul în care condit¸ia are valoarea true se prelucrează corpul marcajului,<br />

în caz contrar, acesta este ignorat.<br />

Exemplul 7.2.1 Preluarea datelor unui formular cu câmpurile <strong>de</strong> intrare<br />

nume, prenume ¸si email se face prin pagina JSP<br />

<br />


7.2. JSP STANDARD TAG LIBRARY JSTL 147<br />

<br />

<br />

<br />

<br />

<br />

<br />

Nume:<br />

<br />

<br />

<br />

<br />

<br />

<br />

Prenume:<br />

<br />

<br />

<br />

<br />

<br />

<br />

E-mail:<br />

<br />

<br />

<br />

• c:choose Marcajul <strong>de</strong> select¸ie poate cont¸ine oricâte marcaje c:when ¸si cel<br />

mult un marcaj c:otherwise. Fiecare marcaj c:when cont¸ine obligatoriu<br />

atributul test. Dacă într-un marcaj c:when condit¸ia are valoarea true,<br />

atunci se prelucrează corrpul acelui marcaj.<br />

În cazul în care toate mar-<br />

cajele c:when au fost evaluate cu false atunci se va prelucra marcajul<br />

c:otherwise (marcaj fără atribute).<br />

• c:forEach Ciclu.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

items opt¸ional Colect¸ia care se parcurge.<br />

var opt¸ional Numele variabilei în care se stochează<br />

valoarea elementului curent.<br />

begin opt¸ional Valoarea init¸ială a variabilei var.<br />

end opt¸ional Valoarea finală a variabilei var.<br />

step opt¸ional Valoarea pasului <strong>de</strong> iterare. Implicit este 1.<br />

varStatus opt¸ional Informat¸ii <strong>de</strong>spre elementul curent.<br />

Variabila varStatus are câmpurile:<br />

– in<strong>de</strong>x valoarea curentă a elementului după care se realizează ciclarea;<br />

– count numărul iterat¸iei curente;<br />

– first are valoarea true dacă este primul element al ciclului;


148 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

– last are valoarea true dacă este ultimul element al ciclului;<br />

Exemplul 7.2.2 Lista parametrilor formularului <strong>de</strong> apelare a exemplului<br />

anterior se afi¸sează prin:<br />

Lista parametrilor <strong>din</strong> formular <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Exemplul 7.2.3 Lista parametrilor unui hea<strong>de</strong>r se afi¸sează prin:<br />

Lista campurilor <strong>din</strong> antet <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Exemplul 7.2.4 Verificarea fontului cu care se scriu titlurile într-un document<br />

html:<br />

<br />

<br />

<br />

• c:forTokens Asigură acea¸si funct¸ionalitate ca ¸si clasei java.util.String<br />

Tokenizer.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

value obligatoriu Valoarea ce se evaluează ¸si se afi¸sează.<br />

expresiei.<br />

<strong>de</strong>fault opt¸ional Cea ce se afi¸sează în cazul în care<br />

expresia nu poate fi evaluată.<br />

escapeXml opt¸ional true / false. Valoarea implicită este true.<br />

Pe false interpretează caracterele <strong>din</strong> value<br />

ca ¸si cod html.


7.2. JSP STANDARD TAG LIBRARY JSTL 149<br />

• c:import Permite inclu<strong>de</strong>rea altor pagini JSP în pagina curentă.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

url obligatoriu Adresa documentului importat.<br />

context opt¸ional Context-ul paginii / documentului importat.<br />

Simbolul /, urmat <strong>de</strong> numele unei aplicat¸ii<br />

<strong>de</strong> pe acela¸si server.<br />

var opt¸ional Numele variabilei în care va fi stocat<br />

documentul importat.<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei var.<br />

Unul <strong>din</strong> valorile:<br />

page, request, session, application.<br />

Cu marcajul c:param se pot fixa parametri pentru pagina importată. Acest<br />

marcaj are două atribute name ¸si value. Acesti parametri se transmit cu<br />

metoda get.<br />

• c:redirect Redirectarea activitatea către o altă pagină.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

url obligatoriu Adresa paginii către care se face redirectarea.<br />

context opt¸ional Context-ul paginii către care se face redirectarea.<br />

Simbolul /, urmat <strong>de</strong> numele unei aplicat¸ii<br />

<strong>de</strong> pe acela¸si server.<br />

Prin redirectare, parametrii nu sunt retransmi¸si automat mai <strong>de</strong>parte.<br />

• c:url Ret¸ine adrese URL.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

value obligatoriu Adresa documentului <strong>de</strong> ret¸inut.<br />

context opt¸ional Context-ul documentului.<br />

Simbolul /, urmat <strong>de</strong> numele unei aplicat¸ii<br />

<strong>de</strong> pe acela¸si server.<br />

var opt¸ional Numele variabilei în care va fi stocată<br />

adresa documentului.<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei var.<br />

Unul <strong>din</strong> valorile:<br />

page, request, session, application.


150 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

7.2.2 Biblioteca <strong>de</strong> lucru cu baze <strong>de</strong> date<br />

<br />

Marcaje <strong>din</strong> biblioteca <strong>de</strong> bază:<br />

• sql:setDataSource Fixează referint¸a la baza <strong>de</strong> date.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

dataSource opt¸ional Referint¸a la baza <strong>de</strong> date<br />

driver opt¸ional Driver-ul bazei <strong>de</strong> date<br />

url opt¸ional url-ul bazei <strong>de</strong> date<br />

username opt¸ional nume utilizatorului bazei <strong>de</strong> date<br />

password opt¸ional parola <strong>de</strong> acces la baza <strong>de</strong> date<br />

var opt¸ional variabila cu referint¸a la baza <strong>de</strong> date<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei var.<br />

• sql:query O interogare a bazei <strong>de</strong> date.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

sql obligatoriu Fraza sql<br />

dataSource opt¸ional Referint¸a la baza <strong>de</strong> date<br />

startRow opt¸ional Linia <strong>de</strong> la care se începe interogarea<br />

maxRows opt¸ional Numărul maxim <strong>de</strong> rezultate acceptate<br />

var obligatoriu Variabila cu rezultatele interogării<br />

bazei <strong>de</strong> date<br />

scope opt¸ional Domeniul <strong>de</strong> vizibilitate al variabilei var.<br />

• sql:update Actualizarea a bazei <strong>de</strong> date.<br />

Atribute ale marcajului:<br />

Atribut Fel Descriere<br />

sql obligatoriu Fraza sql<br />

dataSource opt¸ional Referint¸a la baza <strong>de</strong> date<br />

Exemplul 7.2.5 Să se afi¸seze lista <strong>din</strong> agenda telefonică creată în exemplul <strong>din</strong><br />

Cap. Servlet.<br />

<br />

<br />

<br />

<br />


7.3. MARCAJE JSP PERSONALE 151<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

7.3 Marcaje JSP personale<br />

Programatorul poate crea marcaje JSP proprii care se grupează în colect¸ii<br />

numite biblioteci <strong>de</strong> marcaje.<br />

7.3.1 Marcaje fără atribute ¸si fără corp.<br />

Pentru a crea unui asemenea marcaj JSP propriu este necesară <strong>de</strong>finirea a<br />

patru componente:<br />

1. O clasă <strong>de</strong> <strong>de</strong>finit¸ie a comportamentului marcajului JSP (tag handler class).<br />

2. Descriptorul <strong>de</strong> bibliotecă <strong>de</strong> marcaje JSP, care leagă clasa <strong>de</strong> <strong>de</strong>finit¸ie a<br />

marcajului cu numele simbolic <strong>de</strong> utilizare.<br />

3. Marcajul taglib a fi¸sierului web.xml a lui tomcat, care permite serverului<br />

Web să găsească <strong>de</strong>scriptorul <strong>de</strong> bibliotecă <strong>de</strong> marcaje ¸si clasele <strong>de</strong> <strong>de</strong>finit¸ie<br />

a comportamentului marcajelor JPS.<br />

4. Fi¸sierul JSP ce utilizează marcajul JSP (clientul).<br />

Exemplificăm acestă tehnologie prin


152 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

Exemplul 7.3.1 Să se realizeze un marcaj dateTag, a cărui efect să fie afi¸sarea<br />

datei calendaristice.<br />

1. Clasa <strong>de</strong> <strong>de</strong>finit¸ie a comportamentului marcajului. Programul constă <strong>din</strong>:<br />

(a) Importul pachetelor<br />

import javax.servlet.jsp.*;<br />

import javax.servlet.jsp.tagext.*;<br />

Aceste pachete se găsesc în fi¸sierul jsp-api.jar.<br />

(b) Un marcaj fără atribute ¸si fără corp trebuie să extindă clasa TagSupport<br />

¸si să suprascrie metoda doStartTag, care <strong>de</strong>fine¸ste activitatea intreprinsă<br />

când este întâlnit marcajul într-un document jsp. Metoda<br />

trebuie să returneze constanta SKIP BODY.<br />

public class NumeClasa extends TagSupport{<br />

public int doStartTag(){<br />

. . .<br />

return SKIP_BODY;<br />

}<br />

}<br />

(c) Scrierea în fluxul <strong>de</strong> ie¸sire se face cu un obiect JspWriter, care se<br />

obt¸ine cu pageContext.getOut(). Metoda print a clasei JspWriter<br />

poate genera o except¸ie IOException.<br />

Textul sursă al clasei <strong>de</strong> <strong>de</strong>finit¸ie a comportamentului marcajului dateTag<br />

este:<br />

package jsp;<br />

import javax.servlet.jsp.*;<br />

import javax.servlet.jsp.tagext.*;<br />

import java.io.*;<br />

import java.util.*;<br />

public class DateTag extends TagSupport{<br />

public int doStartTag(){<br />

try{<br />

JspWriter out=pageContext.getOut();<br />

out.println(new Date());<br />

}<br />

catch(IOException e){<br />

System.out.println("DateTagException "+e.getMessage());<br />

}<br />

return SKIP_BODY;<br />

}<br />

}


7.3. MARCAJE JSP PERSONALE 153<br />

2. Descriptorul <strong>de</strong> bibliotecă <strong>de</strong> marcaje JSP este <strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> versiunea tomcat<br />

folosită. Acest fi¸sier trebuie să aibă extensia tld (Taglib Language<br />

Definition). Localizarea acestui fi¸sier este <strong>de</strong>finită în elementul taglib <strong>din</strong><br />

web.xml. În cazul unei distribut¸ii ≥ apache-tomcat-5.*, acest fi¸sier este<br />

(mylibtag.tld):<br />

<br />

<br />

<br />

<br />

1.0 <br />

1.2 <br />

mytags <br />

http://java.apache.org/tomcat/mytaglib<br />

Librarie <strong>de</strong> marcaje <br />

<br />

dateTag <br />

jsp.DateTag <br />

EMPTY <br />

furnizeaza data curenta <br />

<br />

<br />

Pentru fiecare marcaj propriu se completează un marcaj tag. Pentru un<br />

marcaj propriu fără atribute elementele acestui marcaj sunt<br />

(a) name Numele simbolic al marcajului.<br />

(b) tag-class Referint¸a la fi¸sierul class al clasei <strong>de</strong> <strong>de</strong>finit¸ie a comportamentului<br />

marcajului propriu. Referint¸a se face relativ la catalogul<br />

...\WEB-INF\classes<br />

(c) <strong>de</strong>scription Descrierea marcajului propriu.<br />

(d) body-content În cazul nostru are valoarea EMPTY. În cazul unui marcaj<br />

cu corp se dă valoarea JSP.<br />

3. Marcajul taglib <strong>din</strong> fi¸sierul web.xml<br />

<br />

<br />

http://java.apache.org/tomcat/mytaglib<br />

<br />

<br />

/WEB-INF/jsp/mylibtag.tld<br />

<br />

<br />

Elementele marcajului taglib sunt:


154 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

(a) taglib-uri Referint¸ă a subcatalogului <strong>din</strong> catalogul webapps în care<br />

se găse¸ste <strong>de</strong>scriptorul <strong>de</strong> bibliotecă <strong>de</strong> marcaje.<br />

(b) taglib-location Numele complet al fi¸sierului <strong>de</strong>scriptor <strong>de</strong> bibliotecă<br />

<strong>de</strong> marcaje.<br />

Astfel elementele constitutive se vor găsi în:<br />

webapps<br />

|--> mytag<br />

| |--> WEB-INF<br />

| | |--> classes<br />

| | | |--> jsp<br />

| | | | |--> DateTag.class<br />

| | | web.xml<br />

| | |--> jsp<br />

| | | |--> mylibtag.tld<br />

| |--> jsp<br />

| | | dateTag.jsp<br />

4. Marcajele proprii se utilizează cu sintaxa<br />

<br />

Referint¸a la catalogul cu toate componentele necesare marcajului ¸si prefixul<br />

se fixează în directiva taglib.<br />

Un fi¸sier jsp care utilizează marcajul realizat este (dateTag.jsp):<br />

<br />

<br />

<br />

Tag pentru data calendaristica curenta<br />

<br />

<br />

<br />

<br />

<br />

Data curenta este:<br />

<br />

<br />

<br />

7.3.2 Marcaje cu atribute ¸si fără corp.<br />

Realizăm un marcaj ziuaTag cu un atribut ziua care va fi afi¸sat în momentul<br />

prelucrării marcajului.


7.3. MARCAJE JSP PERSONALE 155<br />

1. Pentru fiecare atribut clasa ce <strong>de</strong>fine¸ste act¸iunea marcajului trebuie să<br />

cont¸ină o metodă<br />

2.<br />

public void setNumeAtribut(String value){...}<br />

care preia valoarea atributului dată <strong>de</strong> parametrul value.<br />

Exemplul 7.3.2<br />

Pentru exemplul enunt¸at această clasă este<br />

package jsp;<br />

import javax.servlet.jsp.*;<br />

import javax.servlet.jsp.tagext.*;<br />

import java.io.*;<br />

public class ZiuaTag extends TagSupport{<br />

String ziua;<br />

public void setZiua(String value){<br />

ziua=value;<br />

}<br />

public int doStartTag(){<br />

try{<br />

JspWriter out=pageContext.getOut();<br />

out.println(ziua);<br />

}<br />

catch(IOException e){<br />

System.out.println("ZiuaTagException "+e.getMessage());<br />

}<br />

return SKIP_BODY;<br />

}<br />

}<br />

În <strong>de</strong>scriptorul bibliotecii <strong>de</strong> marcaje pentru fiecare atribut se <strong>de</strong>fine¸ste un<br />

marcaj ...< /attribute> având incluse marcajele<br />

Nume marcaj Semnificat¸ie Fel<br />

name numele atributului obligatoriu<br />

required true | false după cum atributul e obligatoriu<br />

obligatoriu sau nu<br />

rtexprvalue true | false după cum atributul opt¸ional<br />

se poate utiliza într-o expresie<br />

< %= numeAtribut % ><br />

Marcajul <strong>din</strong> <strong>de</strong>scriptorul bibliotecii <strong>de</strong> marcaje <strong>de</strong>vine


156 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

<br />

ziuaTag <br />

jsp.ZiuaTag <br />

EMPTY <br />

furnizeaza argumentul ziua curenta <br />

<br />

ziua <br />

true <br />

true <br />

<br />

<br />

3. Utilizarea acestui marcaj este exemplificat în<br />

<br />

<br />

<br />

Astazi,este<br />

<br />

Luni<br />

Marti<br />

Miercuri<br />

Joi<br />

Vineri<br />

Simbata<br />

Duminica<br />

<br />

<br />

<br />

<br />

<br />

un<strong>de</strong> ziuaTag.jsp este<br />

<br />

<br />

Tag cu marcaj <br />

<br />

<br />

<br />

<br />

<br />

Ziua este:<br />

<br />

<br />

<br />

7.3.3 Marcaje cu corp.<br />

În metoda doStartTag valoarea returnată trebuie să fie EVAL BODY INCLUDE,<br />

în loc <strong>de</strong> SKIP BODY.<br />

În <strong>de</strong>scriptorul bibliotecii <strong>de</strong> marcaje apare


7.3. MARCAJE JSP PERSONALE 157<br />

JSP <br />

în loc <strong>de</strong> EMPTY.<br />

Dacă se dore¸ste ca marcajul să execute act¸iuni după interpretarea corpului,<br />

atunci acele activităt¸i sunt <strong>de</strong>finite în metoda doEndTag. Această metodă<br />

returnează valoarea EVAL PAGE sau SKIP PAGE după cum se dore¸ste sau nu continuarea<br />

procesării paginii jsp.<br />

Exemplul 7.3.3 Fie marcajul modTag care modifica un text în caractere mari<br />

sau mici după valoarea atributului trans. Acest marcaj poate inclu<strong>de</strong> ale elemente.<br />

Codul clasei ce prelucrează marcajul este<br />

package jsp;<br />

import javax.servlet.jsp.*;<br />

import javax.servlet.jsp.tagext.*;<br />

import java.io.*;<br />

public class ModTag extends TagSupport{<br />

String text;<br />

boolean toUpperCase;<br />

public void setText(String value){<br />

text=value;<br />

}<br />

public void setTrans(String value){<br />

toUpperCase=(new Boolean(value)).booleanValue();<br />

}<br />

public int doStartTag(){<br />

try{<br />

JspWriter out=pageContext.getOut();<br />

if(toUpperCase)<br />

out.println(text.toUpperCase());<br />

else<br />

out.println(text.toLowerCase());<br />

}<br />

catch(IOException e){<br />

System.out.println("ModTagException "+e.getMessage());<br />

}<br />

return EVAL_BODY_INCLUDE;<br />

}<br />

}<br />

Descriptorul bibliotecii <strong>de</strong> marcaje se completează cu<br />

<br />

modTag <br />

jsp.ModTag <br />

JSP <br />

modifica caracterele <br />

<br />

text <br />

true


158 CAPITOLUL 7. JAVA SERVER PAGE – JSP<br />

true <br />

<br />

<br />

trans <br />

true <br />

true <br />

<br />

<br />

O pagină <strong>de</strong> utilizare a marcajului modTag cu un corp nevid este<br />

<br />

<br />

<br />

Introduce o fraz&#259;<br />

<br />

<br />

Se transform&#259; &#238;n litere<br />

<br />

mari<br />

mici<br />

<br />

<br />

<br />

<br />

<br />

împreună cu modtextTag.jsp<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


Capitolul 8<br />

Portlet<br />

Prezentarea termenului <strong>de</strong> portlet se face împreună cu cea <strong>de</strong> portal. Portalul<br />

ca ¸si portletul sunt aplicat¸ii Web. Practic un portal accesat afi¸sează portleturi în<br />

ferestre distincte, portleturile fiind aplicat¸ii pe care clientul le poate folosi (Fig.<br />

1, Fig. 2).<br />

Fig. 1. Portal - Portlet.<br />

Această prezentare se raportează la JSR (Java Specification Request) 168.<br />

JSR 286 este următorul standard pe care trebuie să le în<strong>de</strong>plinească un portlet.<br />

Portalul este o aplicat¸ie Web cu funct¸ionalităt¸ile:<br />

• Container <strong>de</strong> portlet¸i. Containerul este responsabil <strong>de</strong> init¸ializarea ¸si distrugerea<br />

portlet¸ilor, <strong>de</strong> transmiterea cererilor către portlet¸i ¸si <strong>de</strong> colectarea<br />

răspunsurilor.<br />

• Agregarea cont¸inuturilor (Content aggregator). Permite afi¸sarea ¸si gestionarea<br />

mai multor portleturi.<br />

• Asigură servicii <strong>din</strong>tre care amintim:<br />

159


160 CAPITOLUL 8. PORTLET<br />

Fig. 2. Aparit¸ia portlet-etelor într-o pagină a unui portal.<br />

– acces la portal pe bază <strong>de</strong> autentificare ¸si autorizare. Odată autorizat,<br />

un client are acces la orice portlet.<br />

– posibilitatea personalizării portleturilor <strong>de</strong> către client¸i.<br />

Varietatea serviciilor variază <strong>de</strong> la un portal la altul.<br />

Portletul este o aplicat¸ie Web care se aseamănă cu servletul prin:<br />

• Se instalează într-un container.<br />

• Generează cont¸inut <strong>din</strong>amic.<br />

• Ciclul <strong>de</strong> viat¸ă este gestionat <strong>de</strong> container.<br />

• Interact¸ionează cu clientul prin mo<strong>de</strong>lul request/reply.<br />

Deosebirile unui portlet fat¸ă <strong>de</strong> un server sunt:<br />

• Portletul posedă mai multe variante <strong>de</strong> tratare a cererilor.<br />

• Prin conceptul <strong>de</strong> mod (mo<strong>de</strong>) se specifică variante distincte prin care<br />

portletul react¸ionează. Sunt <strong>de</strong>finite modurile VIEW, EDIT, HELP. Act¸iunile<br />

corespunzătoare sunt <strong>de</strong>finite în meto<strong>de</strong>le doView, doEdit, doHelp.


8.1. APACHE-PLUTO 161<br />

• Prin WindowState se fixează spat¸iul utilizat <strong>de</strong> portlet. Valorile variabilei<br />

WindowState sunt NORMAL, MAXIMIZED, MINIMIZED. În varianta MAXI-<br />

MIZED portletul ocupă întreaga fereastră, în timp ce în varianta MINI-<br />

MIZED portletul apare într-o bară <strong>de</strong> titluri.<br />

8.1 Apache-pluto<br />

Pentru <strong>de</strong>zvoltarea portleturilor vom folosi produsul Apache-pluto care generează<br />

un portal în care se pot instala / <strong>de</strong>zinstala u¸sor portleturi.<br />

Instalarea produsului. În funct¸ie <strong>de</strong> natura distribut¸iei <strong>de</strong>scărcate:<br />

• pluto-1.1.*-bundle.*<br />

Cont¸ine pluto integrat într-o versiune apache-tomcat-5.5.*. Instalarea revine<br />

la <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scăcat.<br />

• pluto-1.1.*-bin.*<br />

După <strong>de</strong>zarhivarea fi¸serului pluto-1.1.*-bin.*, <strong>de</strong>scărcat <strong>din</strong> internet, în catalogul<br />

PLUTO HOME, instalarea se face în apache-tomcat-5.5.* prin:<br />

1. Fi¸sierele jar <strong>din</strong> catalogul PLUTO HOME\lib se copiază în catalogul<br />

TOMCAT HOME\shared\lib.<br />

2.<br />

În acest catalog mai trebuie introduse fi¸sierele:<br />

– castor-1.1.1.jar<br />

– portlet-api.jar<br />

Aceste fi¸siere sunt incluse în distribut¸ia pluto-1.1.*-bundle.*.<br />

3. Se crează în TOMCAT HOME catalogul PlutoDomain<br />

4. Se copiază fi¸sierele war <strong>din</strong> catalogul PLUTO HOME\webapps în catalogul<br />

TOMCAT HOME\PlutoDomain<br />

5. Se crează în catalogul TOMCAT HOME\conf\Catalina\localhost fi¸sierul<br />

pluto.xml având cont¸inutul<br />

<br />

<br />

6. Se completează fi¸sierul tomcat-users.xml <strong>din</strong> catalogul TOMCAT HOME\conf<br />

cu<br />

<br />

<br />

<br />

<br />

Utilizarea produsului. Dintr-un navigator, portalul se apelează prin<br />

http://host:8080/pluto/portal


162 CAPITOLUL 8. PORTLET<br />

Accesul se face cu User name = password = pluto.<br />

Instalarea unui portlet se face în 2 pa¸si:<br />

1. Desfă¸surarea portlet-ului: Fi¸sierul arhivat al portletului, având estensia<br />

war, se <strong>de</strong>pune în catalogul PlutoDomain. Apelând managerul lui apachetomcat<br />

<strong>din</strong> componenta Pluto admin se obt¸ine instalarea portletului.<br />

Alternativ, <strong>de</strong>sfă¸surarea portlet-lui se va obt¸ine cu apache-ant cu utilizarea<br />

unui fi¸sier build.xml <strong>de</strong>dicat.<br />

2. Publicarea portlet-ului se face prin componenta Pluto admin.<br />

8.2 Portlet container JSR 286<br />

portlet-container-configurator(.jar) instalează un container <strong>de</strong> portlete în apachetomcat-5.5.*<br />

/ glassfish v2, container care suportă portlete potrivit specificat¸iei<br />

JSR 286. Containerului îi este ata¸sat un portal simplu.<br />

Instalarea containerului <strong>de</strong> portlete JSR 286. Presupunem că serverul<br />

Web apache-tomcat-5.5.* este instalat împreună cu componenta manager. Containerul<br />

<strong>de</strong> portlete se instalează prin<br />

java -jar portlet-container-configurator.jar<br />

În interfat¸a grafică, se fixează serverul Web (Glassfish / Tomcat), locat¸ia apacheant<br />

(Ant-Home) ¸si locat¸ia serverului Web Select Install Directory).<br />

Utilizarea portalului. Portalul se apelează prin<br />

http://host:port/portletdriver<br />

Prin administratorul portalului (Admin) se pot încărca / sterge portlete. Acestea<br />

sunt vizibile pe pagina Portlets.<br />

8.3 Dezvoltarea unui portlet<br />

Compilarea ¸si arhivarea unui portlet în ve<strong>de</strong>rea <strong>de</strong>sfă¸surării se va face rulând<br />

ant cu fi¸sierul build.xml:<br />

<br />

<br />

<br />

<br />

<br />


8.3. DEZVOLTAREA UNUI PORTLET 163<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


164 CAPITOLUL 8. PORTLET<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Fi¸sierul <strong>de</strong> proprietăt¸i build.properties este<br />

#build.properties<br />

#Standard properties for Ant build of a Pluto 1.1 portlet<br />

#module name<br />

app.name=NumePortlet<br />

#Directory that holds source co<strong>de</strong><br />

src.dir = src/main<br />

java.src.dir = ${src.dir}/java<br />

#Directory that holds documentation


8.3. DEZVOLTAREA UNUI PORTLET 165<br />

doc.dir = docs<br />

#Directory that holds files to be built into a jar, war or ear<br />

build.dir = build<br />

webbuild.dir = ${build.dir}/webapp<br />

classbuild.dir = ${webbuild.dir}/WEB-INF/classes<br />

#Directory that holds configuration files<br />

conf.dir = ${src.dir}/resource<br />

#Directory that holds libraries required to build and run the classes<br />

lib.dir = lib<br />

#Directory that holds webapp files<br />

web.dir = ${src.dir}/webapp<br />

#WEB-INF directory<br />

web-inf.dir = ${web.dir}/WEB-INF<br />

#Directory that holds files to build distribution<br />

dist.dir = ${build.dir}/dist<br />

Pentru utilizarea acestui build.xml este nevoie <strong>de</strong> structura următoare <strong>de</strong> cataloage<br />

NumePortlet<br />

|--> lib<br />

| | castor-1.1.1.jar<br />

| | commons-logging-*.jar<br />

| | pluto-ant-tasks-*.jar<br />

| | pluto-<strong>de</strong>scriptor-api-*-<strong>de</strong>v.jar<br />

| | pluto-<strong>de</strong>scriptor-impl-*-<strong>de</strong>v.jar<br />

| | pluto-util-*-<strong>de</strong>v.jar<br />

| | portlet-api-*.jar<br />

| | servlet-api-*.jar<br />

|--> src<br />

| |--> main<br />

| | |--> java<br />

| | | |--> pachetul portletului<br />

| | |--> resource<br />

| | | | NumePortlet.xml<br />

| | |--> webapp<br />

| | | |--> jsp<br />

| | | | | fisierele jsp ale portletului<br />

| | | |--> WEB-INF<br />

| | | | | portlet.xml<br />

| | | | | web.xml


166 CAPITOLUL 8. PORTLET<br />

Fi¸sierele castor.1.1.1.jar, pluto-<strong>de</strong>scriptor-api-*.jar, pluto-<strong>de</strong>scriptor-impl-*.jar,<br />

portlet-api.jar se copiază <strong>din</strong> catalogul PLUTO HOME\shared\lib, iar fi¸sierul servletapi-*.jar<br />

se ia <strong>din</strong> PLUTO HOME\common\lib.<br />

Fi¸sierul web.xml <strong>de</strong> mai sus este<br />

<br />

<br />

<br />

Cont¸inutul final al acestui fi¸sier rezultă în urma obiectivului ant assemple,<br />

în care se preiau date <strong>din</strong> fi¸sierul <strong>de</strong> configurare al portletului portlet.xml.<br />

Editarea fi¸sierului portlet.xml este sarcina programatorului.<br />

Fi¸sierul NumePortlet.xml este utilizat la <strong>de</strong>sfă¸surarea aplicat¸ie, fiind copiat<br />

în catalogul conf\Catalina\localhost al lui apache-tomcat sau Apache-pluto.<br />

Acest fi¸sier are cont¸inutul:<br />

<br />

8.4 Elemente <strong>de</strong> programare<br />

Orice portlet implementează interfat¸a Portlet. Interfat¸a Portlet <strong>de</strong>clară 4<br />

meto<strong>de</strong><br />

public interface Portlet{<br />

public void init(PortletConfig config) throws PortletException;<br />

}<br />

public void processAction(ActionRequest request, ActionResponse<br />

response) throws PortletException, java.io.IOException;<br />

public void ren<strong>de</strong>r(Ren<strong>de</strong>rRequest request, Ren<strong>de</strong>rResponse<br />

response) throws PortletException, java.io.IOException;<br />

public void <strong>de</strong>stroy();<br />

Metoda processAction prelucrează cererea emisă <strong>de</strong> containerul <strong>de</strong> portlete.<br />

La solicitarea containerului, metoda ren<strong>de</strong>r regenerează cont¸inutul unui portlet.<br />

Clasa GenericPortlet este implementarea init¸ială a interfet¸ei Portlet. Extinzând<br />

clasa GenericPortlet, sarcina programatorului este să suprascrie meto<strong>de</strong>le


8.4. ELEMENTE DE PROGRAMARE 167<br />

• doView pentru tratarea modului VIEW;<br />

protected void doView(Ren<strong>de</strong>rRequest req,Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException<br />

• doEdit pentru tratarea modului EDIT;<br />

protected void doEdit(Ren<strong>de</strong>rRequest req,Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException<br />

• doHelp pentru tratarea modului HELP;<br />

protected void doHelp(Ren<strong>de</strong>rRequest req,Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException<br />

• init, <strong>de</strong>stroy pentru init¸ializarea, respectiv oprirea portletului.<br />

void init() throws PortletException<br />

void init(PortletConfig config) throws PortletException<br />

void <strong>de</strong>stroy()<br />

¸si eventual, să <strong>de</strong>finească cont¸inutul meto<strong>de</strong>i<br />

public void processAction(ActionRequest request,ActionResponse<br />

response) throws PortletException, java.io.IOException;<br />

Exemplul 8.4.1 Portletul HelloWorld.<br />

package hello;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

public class HelloWorldPortlet extends GenericPortlet{<br />

protected void doView(Ren<strong>de</strong>rRequest request, Ren<strong>de</strong>rResponse response)<br />

throws PortletException, IOException{<br />

response.setContentType("text/html");<br />

response.getWriter().println("Hello World!");<br />

}<br />

//Alta varianta <strong>de</strong> programare<br />

/*<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

PrintWriter out=res.getWriter();<br />

out.println("");<br />

out.println("Hello World! ");<br />

out.println("");<br />

}<br />

*/<br />

}<br />

Fi¸sierul portlet.xml este


168 CAPITOLUL 8. PORTLET<br />

<br />

<br />

<br />

Hello World as a portlet app<br />

HelloWorld1Portlet<br />

Hello World Portlet<br />

hello.HelloWorld1Portlet<br />

<br />

text/html<br />

VIEW<br />

<br />

<br />

Hello World Portlet<br />

<br />

<br />

<br />

Exemplul 8.4.2 Evi<strong>de</strong>nt¸ierea modurilor VIEW, EDIT ¸si HELP.<br />

package hellopluto;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

public class HelloPlutoPortlet extends GenericPortlet{<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

Writer out=res.getWriter();<br />

out.write("Hello Pluto in view mo<strong>de</strong>");<br />

}<br />

public void doEdit(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

Writer out=res.getWriter();<br />

out.write("Hello Pluto in edit mo<strong>de</strong>");<br />

}<br />

public void doHelp(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

Writer out=res.getWriter();<br />

out.write("Hello Pluto in help mo<strong>de</strong>");<br />

}<br />

}<br />

Fi¸sierul portlet.xml este<br />

<br />


8.4. ELEMENTE DE PROGRAMARE 169<br />

<br />

Hello Pluto as a portlet app<br />

HelloPlutoPortlet<br />

Hello Pluto<br />

hellopluto.HelloPlutoPortlet<br />

<br />

text/html<br />

VIEW<br />

EDIT<br />

HELP<br />

<br />

<br />

Hello Pluto Portlet<br />

<br />

<br />

<br />

Exemplul 8.4.3 Portletul Hello. Portletul afi¸sează o zonă text <strong>de</strong> introducere a<br />

unui nume ¸si un buton. Odată introdus numele, la apăsarea butonului se afi¸saeză<br />

textul Hello nume ¸si un buton <strong>de</strong> reluare.<br />

package helloname;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

import java.util.Enumeration;<br />

public class HelloNamePortlet extends GenericPortlet{<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

String nume=(String)req.getParameter("name");<br />

PortletRequestDispatcher prd=null;<br />

if(nume==null){<br />

prd=getPortletContext().getRequestDispatcher("/jsp/input.jsp");<br />

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

else{<br />

// Varianta cu afisare prin View<br />

/*<br />

Writer out=res.getWriter();<br />

out.write("Hello "+ nume);<br />

PortletURL ren<strong>de</strong>rURL=res.createRen<strong>de</strong>rURL();<br />

ren<strong>de</strong>rURL.setPortletMo<strong>de</strong>(PortletMo<strong>de</strong>.VIEW);<br />

ren<strong>de</strong>rURL.setWindowState(WindowState.NORMAL);<br />

out.write(" Reluare ");<br />

*/<br />

// Varianta cu afisare printr-un fisier jsp<br />

prd=getPortletContext().getRequestDispatcher("/jsp/output.jsp");<br />

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

}<br />

public void processAction(ActionRequest req, ActionResponse res)<br />

throws IOException,PortletException{<br />

// Preia parametrii si le trimite celui care a emis cererea


170 CAPITOLUL 8. PORTLET<br />

Enumeration params=req.getParameterNames();<br />

while(params.hasMoreElements()){<br />

String parameterName = (String)params.nextElement();<br />

String parameterValue=req.getParameter(parameterName);<br />

res.setRen<strong>de</strong>rParameter(parameterName,parameterValue);<br />

}<br />

}<br />

}<br />

Fi¸sierele input.jsp ¸si putput.jsp au codurile<br />

<br />

<br />

<br />

Introduce&#355;i numele:<br />

<br />

<br />

<br />

<br />

<br />

<br />

Reluare<br />

.<br />

Exemplul 8.4.4 Cel mai mare divizor comun a două numere naturale într-un<br />

portlet.<br />

Variantă în care calculul este programat în portlet.<br />

package cmmdc;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

import java.util.Enumeration;<br />

public class CmmdcPortlet extends GenericPortlet{<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

PortletRequestDispatcher prd=null;<br />

String rez=req.getParameter("rez");<br />

if(rez==null){


8.4. ELEMENTE DE PROGRAMARE 171<br />

}<br />

prd=getPortletContext().getRequestDispatcher("/jsp/input.jsp");<br />

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

else{<br />

prd=getPortletContext().getRequestDispatcher("/jsp/output.jsp");<br />

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

}<br />

public void processAction(ActionRequest req, ActionResponse res)<br />

throws IOException,PortletException{<br />

// Preia parametrii si le trimite celui care a emis cererea<br />

String sm=req.getParameter("m");<br />

String sn=req.getParameter("n");<br />

long m=Long.parseLong(sm);<br />

long n=Long.parseLong(sn);<br />

long c=cmmdc(m,n);<br />

res.setRen<strong>de</strong>rParameter("rez",(new Long(c)).toString());<br />

}<br />

private long cmmdc(long m,long n){. . .}<br />

Fi¸sierele inputCmmdc.jsp ¸si outputCmmdc.jsp au codurile<br />

<br />

<br />

<br />

<br />

<br />

<br />

Primul num&#259;r <br />

<br />

<br />

<br />

Al doilea num&#259;r <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

¸si respectiv<br />

<br />

<br />

<br />

<br />


172 CAPITOLUL 8. PORTLET<br />

%><br />

<br />

<br />

Reluare<br />

<br />

Variantă în care calculul este programat într-o componentă Java (bean)<br />

¸si care este apelat în pagina jsp <strong>de</strong> afi¸sare a rezutlatului.<br />

package cmmdc;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

import java.util.Enumeration;<br />

public class CmmdcPortlet extends GenericPortlet{<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

res.setContentType("text/html");<br />

PortletRequestDispatcher prd=null;<br />

String sb=req.getParameter("submitButton");<br />

if(sb==null){<br />

prd=getPortletContext().getRequestDispatcher("/jsp/inputCmmdc.jsp");<br />

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

else{<br />

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

prd.inclu<strong>de</strong>(req,res);<br />

}<br />

}<br />

public void processAction(ActionRequest req, ActionResponse res)<br />

throws IOException,PortletException{<br />

// Preia parametrii si le trimite celui care a emis cererea<br />

Enumeration params=req.getParameterNames();<br />

while(params.hasMoreElements() ) {<br />

String parameterName = (String)params.nextElement();<br />

String parameterValue=req.getParameter(parameterName);<br />

System.out.println(" >> parameterName = " + parameterName +<br />

" parameterValue = " + parameterValue);<br />

res.setRen<strong>de</strong>rParameter(parameterName,parameterValue);<br />

}<br />

}<br />

}<br />

Codul componentei Java<br />

public class CmmdcBean{<br />

private String m="";<br />

private String n="";<br />

public void setM(String m){<br />

this.m=m;<br />

}<br />

public void setN(String n){<br />

this.n=n;<br />

}


8.4. ELEMENTE DE PROGRAMARE 173<br />

public String getM(){<br />

return m;<br />

}<br />

public String getN(){<br />

return n;<br />

}<br />

public String cmmdc(){<br />

long m0=Long.parseLong(m);<br />

long n0=Long.parseLong(n);<br />

long c,r;<br />

do{<br />

c=n0;<br />

r=m0%n0;<br />

m0=n0;<br />

n0=r;<br />

}<br />

while(r!=0);<br />

return (new Long(c)).toString();<br />

}<br />

}<br />

Pagina outputCmmdc.jsp<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Reluare<br />

<br />

Variantă în care care calculul este programat într-un servlet. Servletul<br />

utilizat este cel prezentat în capitolul Servlet, (6.3.2), dar inclus în pachetul<br />

portlet-ului. Fi¸sierul inputCmmdc.jsp are în plus linia<br />

<br />

iar în codul clasei CmmdcPortlet, în locul liniei<br />

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

apare<br />

prd=getPortletContext().getRequestDispatcher("/cmmdc");<br />

adică în locul invocării paginii JSP, dispecerul apelează servletul. În servlet este<br />

esent¸ială furnizarea rezultatului în format html. Pagina html generată se încarcă<br />

în fereastra portlet-ului.<br />

Fi¸sierul web.xml, înaintea completării prin ant, este


174 CAPITOLUL 8. PORTLET<br />

<br />

<br />

<br />

CmmdcServlet<br />

cmmdc.CmmdcServlet<br />

<br />

<br />

CmmdcServlet<br />

/cmmdc<br />

<br />

<br />

Interfat¸a PortletPreferences<br />

Atribute, adică perechi <strong>de</strong> tip String (nume,valoare) <strong>de</strong>finite în fi¸sierul portlet.xml<br />

prin<br />

<br />

<br />

nume_atribut<br />

valoare_atribut<br />

true|false<br />

<br />

. . .<br />

<br />

Atributele se transmit meto<strong>de</strong>lor doView, doEdit ¸si doHelp. Suportul este<br />

oferit prin interfat¸a PortletPreferences.<br />

Meto<strong>de</strong><br />

• String getValue(String key, String <strong>de</strong>f )<br />

Returnează valoarea primului atribut având numele key. În lipsa atributului<br />

sau a valurii returnează valoarea <strong>de</strong>f.<br />

• String[] getValues(String key, String[] <strong>de</strong>f )<br />

Returnează toate valorile atributului key.<br />

• Enumeration getNames()<br />

Suport pentru acces la numele atributelor care au valoare.


8.5. PRODUSE PORTAL 175<br />

• Map getMap()<br />

Suport pentru acces la atribute.<br />

Un obiect care implementează interfat¸a PortletPreferences se obt¸ine prin<br />

metoda getPreferences() a clasei Ren<strong>de</strong>rRequest.<br />

Exemplul 8.4.5 Portlet în care se preiau ¸si se afi¸sează valori ale atributelor.<br />

Codul portletului este<br />

package pref;<br />

import java.io.*;<br />

import javax.portlet.*;<br />

public class PrefPortlet extends GenericPortlet{<br />

public void doView(Ren<strong>de</strong>rRequest req, Ren<strong>de</strong>rResponse res)<br />

throws PortletException, IOException {<br />

PortletPreferences prefs = req.getPreferences();<br />

String attr1 = prefs.getValue("ATTR1", "attr1");<br />

String attr2 = prefs.getValue("ATTR2", "attr2");<br />

res.setContentType("text/html");<br />

Writer out=res.getWriter();<br />

out.write(""+attr1+" "+attr2+"");<br />

}<br />

}<br />

iar atributele <strong>din</strong> fi¸sierul portlet.xml sunt<br />

<br />

<br />

ATTR1<br />

Programare distribuita<br />

true<br />

<br />

<br />

ATTR2<br />

<br />

true<br />

<br />

<br />

Al doilea atribut nu are valoare.Portletul afi¸sează textul Programare distribuita<br />

attr2.<br />

8.5 Produse Portal<br />

Termenul portal va <strong>de</strong>semna atât aplicat¸ia informatică prin care o institut¸ie<br />

comunică cu lumea exterioară cât ¸si produsul informatic care realizează acest<br />

lucru.<br />

Dezvoltarea unui portal al unei organizat¸ii se face pe produse specializate<br />

acestui scop. Dintre asemenea produsele gratuite amintim:


176 CAPITOLUL 8. PORTLET<br />

• uPortal;<br />

• jetspeed-2;<br />

care vor fi prezentate în continuare. apache-pluto este i<strong>de</strong>al pentru testarea<br />

portlet-elor.<br />

8.5.1 uPortal<br />

uPortal este un portal cadru, <strong>de</strong>zvoltat <strong>de</strong> JA-SIG (Java Architecture Special<br />

Interest Group) ¸si a fost utilizat <strong>de</strong> mai multe universităt¸i ca suport în construct¸ia<br />

portalului specific.<br />

Instalarea produsului. Distribut¸ia produsului se face în două variante<br />

• uPortal-*.*.* - uPortal-only;<br />

• uPortal-*.*.*-quick-start care înglobează toate resursele necesare funct¸ionării<br />

(apache-ant, apache-tomcat, apache-maven, HypersonicSQLDB).<br />

În cele ce urmează utilizăm varianta uPortal-quick-start. Instalarea produsului<br />

revine la <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scărcat.<br />

Lansarea portalului. În urma <strong>de</strong>zarhivării, în catalogul uPortal HOME se<br />

găse¸ste un fi¸sier build.xml, ale cărei obiective asigură lansarea portalului1 .<br />

Se completează fi¸sierul ant.bat cu referint¸a set JAVA HOME=...<br />

Lansarea portalului constă în executarea comenzii<br />

ant start<br />

De fapt se porne¸ste SGBD HypersonicSQLDB ¸si serverul Web apache-tomcat.<br />

Oprirea portalului se face prin executarea comenzii<br />

ant stop<br />

Dintr-un navigator, portalul se accesează prin<br />

http://host:8080/uPortal<br />

Accesarea portalului se poate face doar <strong>de</strong> <strong>de</strong>t¸inătorii unui cont (UserName,<br />

Password). Administratorul (UserName=Password=admin) poate crea conturi<br />

noi.<br />

Instalarea unui portlet constă în <strong>de</strong>sfă¸surarea ¸si publicarea lui.<br />

Compilarea ¸si arhivarea portletului se poate face cu apache-ant În acest scop<br />

se crează structura<br />

1 La prima executare a unei operat¸ii asupra portalului, calculatorul trebuie să fie conectat<br />

la internet, <strong>de</strong>oarece mai multe resurse sunt <strong>de</strong>scărcate prin apache-maven. Aceste resurse se<br />

<strong>de</strong>pun în c:\Documents and Settings\adminName\.m2\repository.


8.5. PRODUSE PORTAL 177<br />

|--> lib<br />

| | portlet-api-1.0.jar<br />

|--> pachetul portlet-ului<br />

| |--> jsp<br />

| | | *.jsp<br />

| |--> WEB-INF<br />

| | |--> classes<br />

| | | | *.java<br />

| | | web.xml<br />

| | | portlet.xml<br />

| build.xml<br />

cu fi¸sierele *.java, *.jsp ¸si portlet.xml corespunzătoare portletului iar web.xml<br />

este generic<br />

<br />

<br />

<br />

<br />

Fi¸sierul build.xml, compilare ¸si arhivare este<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


178 CAPITOLUL 8. PORTLET<br />

webxml="${package}/WEB-INF/web.xml"/><br />

<br />

<br />

<br />

<br />

<br />

<br />

Desfă¸surarea portlet-ului se face cu apache-ant utilizând fi¸sierul build.xml<br />

<strong>din</strong> uPortal HOME\uPortal-*.*.* prin<br />

ant <strong>de</strong>ployPortletApp -DportletApp=arhiva portlet-ului.war<br />

În urma acestei operat¸ii, portlet-ul se <strong>de</strong>zarhivează în uPortal HOME\apachetomcat-*.*.*\webapps<br />

iar fi¸sierul web.xml este actualizat.<br />

Publicarea portlet-ului se face cu rolul <strong>de</strong> administrator. După conectare la<br />

uPortal<br />

1. AdminTools → Portlet Manager → Publish a new channel<br />

2. Se parcurg meniurile Channel Manager<br />

(a) Din meniul Channel Type se selectează opt¸iunea Portlet. Clic Next.<br />

(b)<br />

(c)<br />

(d)<br />

(e)<br />

(f)<br />

(g)<br />

(h)<br />

În meniul General Settings se fixează tot¸i parametrii indicat¸i. Clic<br />

Next.<br />

În meniul Portlet Descriptor se fixează<br />

• Contextul portlet-ului, adică catalogul <strong>din</strong> webapps care cont¸ine<br />

portlet-ul. În mod obligatoriu primul caracter este \;<br />

• Numele portlet-ului a¸sa cum este <strong>de</strong>finit în fi¸sierul portlet.xml.<br />

Clic Next.<br />

În meniul Portlet Preferences, clic Next.<br />

În meniul Channel Controls, clic Next.<br />

În meniul Categories se fixează categoria canalului ¸si cel putin un<br />

membru.<br />

Select Marked → Next.<br />

În meniul Groups se fixează grupul ¸si cel putin un membru.<br />

Select Marked → Next<br />

Grupul <strong>de</strong>semnează client¸ii care pot publica portlet-ul.<br />

În meniul Review, clic Finish.<br />

Canalul portlet-ului apare în lista afi¸sată.


8.5. PRODUSE PORTAL 179<br />

3. Fiecare client care poate utiliza portlet-ul, îl publică prin componenta Customize.<br />

Pentru administrator: AdminTools → Customize urmat <strong>de</strong><br />

(a) Clic pe un buton Add Channel corespunzător locului un<strong>de</strong> vrem să fie<br />

pozit¸ionat portlet-ul.<br />

(b) În User Preferences,<br />

i. se alege categoria portlet-ului, clic go;<br />

ii. se alege numele portlet-ului, clic Add Channel.<br />

(c) Clic pe numele canalului corespunzător portlet-ului. Canalul este<br />

afi¸sat în meniul Welcome.<br />

(d) Clic pe numele canalului <strong>din</strong> meniul Welcome lansează portlet-ul.<br />

Un client elimină un portlet stergând canalul corespunzător în componenta<br />

Costumize (clic pe butonul <strong>de</strong> închi<strong>de</strong>re).<br />

Administratorul portalului ¸sterge un portlet prin clic pe butonul <strong>de</strong> închi<strong>de</strong>re<br />

în lista portlet-elor publicate <strong>din</strong> AdminTools → Portlet Manager → Modify<br />

a currently published channel.<br />

Asemănător, se pot publica în uPortal aplicat¸ii Web. Deosebirea esent¸ială<br />

este că tipul canalului (Channel Type) este WebProxy sau Inline Frame.<br />

8.5.2 Jetspeed-2<br />

Jetspeed-2 este un portal cadru <strong>de</strong>zvoltat <strong>de</strong> apache.<br />

Instalarea se execută rulând distribut¸ia jetspeed-2.*.*-installer.jar.<br />

Portalul se accesează, <strong>din</strong>tr-un navigator, prin<br />

http://localhost:8080/jetspeed<br />

Desfă¸surarea unui portlet constă în copierea arhivei war corespunzătoare,<br />

realizat în 8.5.1, în catalogul<br />

Jetspeed HOME\webapps\jetspeed\WEB-INF\<strong>de</strong>ploy<br />

Pe rol <strong>de</strong> admin, publicarea portlet-ului presupune<br />

1. Clic pe icon-ul butonului Edit - aflat în dreapta butonului logout.<br />

2. Clic pe un buton Add Portlet, stabilind astfel ¸si pozit¸ia în care va fi afi¸sată<br />

fereastra portlet-ului.<br />

3. Clic pe butonul Add al portlet-ului care se dore¸ste publicat.<br />

4. Clic pe săgeata <strong>de</strong> reîntoarcere, urmat <strong>de</strong> clic pe iconul butonului View -<br />

aflat pe pozit¸ia butonului Edit.<br />

Pentru a ¸sterge un portlet, după primul pas anterior, se apasă butonul <strong>de</strong><br />

închi<strong>de</strong>re <strong>din</strong> zona portlet-ului.


180 CAPITOLUL 8. PORTLET


Capitolul 9<br />

Teme <strong>de</strong> laborator<br />

9.1 Probleme propuse<br />

1. Să se realizeze conversia temperaturii exprimată în gra<strong>de</strong> Celsius în gra<strong>de</strong><br />

Fahrenheit ¸si invers. Formula <strong>de</strong> transformare este<br />

tF = 1.8tC + 32 o F<br />

Eventual, programul server implementează interfat¸a (la distant¸ă)<br />

package conversie;<br />

public interface Gra<strong>de</strong> extends java.rmi.Remote{<br />

public double celsiusToFahrenheit(double celsius)<br />

// throws java.rmi.RemoteException;<br />

public double fahrenheitToCelsius(double fahrenheit)<br />

// throws java.rmi.RemoteException;<br />

}<br />

2. Să se realizeze conversia a unei sume <strong>de</strong> bani între USD, EURO ¸si RON.<br />

Ratele <strong>de</strong> schimb sunt fixate <strong>de</strong> un obiect ce implementează interfat¸a<br />

public interface IRataSchimb{<br />

double OneEuroIsRon();<br />

double OneUsdIsRon();<br />

}<br />

accesibil programului server.<br />

Programul server implementează interfat¸a<br />

181


182 CAPITOLUL 9. TEME DE LABORATOR<br />

package exchange;<br />

public interface IConversie extends java.rmi.Remote{<br />

public double usdToEuro(double usd)<br />

// throws java.rmi.RemoteException;<br />

public double usdToRol(double usd)<br />

// throws java.rmi.RemoteException;<br />

public double euroToUsd(double euro)<br />

// throws java.rmi.RemoteException;<br />

public double euroToRol(double euro)<br />

// throws java.rmi.RemoteException;<br />

public double rolToEuro(double rol)<br />

// throws java.rmi.RemoteException;<br />

public double rolToUsd(double rol)<br />

// throws java.rmi.RemoteException;<br />

}<br />

Rata zilnică <strong>de</strong> schimb se poate prelua <strong>din</strong>amic sub forma unui fi¸sier xml,<br />

apelând http://www.bnr.ro/nbrfxrates.xml.<br />

3. Să se realizeze conversia unui număr natural, cuprins între 1 ¸si 3999, <strong>din</strong><br />

cifre arabe în cifre romane ¸si invers.<br />

4. Să se realizeze conversia unui număr <strong>din</strong>tr-o bază în alta.<br />

5. Unui client îi corespun<strong>de</strong> un număr întreg, valoarea init¸ială fiind 0. La<br />

o apelare a serverului, clientul transmite un număr care este adunat la<br />

numărul care îi corespun<strong>de</strong> clientului. Serverul retransmite clientului valoarea<br />

actualizată a numărului. Să se implementeze serviciul <strong>de</strong>scris.<br />

6. Aplicat¸ia producător – consumator.<br />

Fie un sistem format <strong>din</strong> două procese P1 ¸si P2, primul producând ni¸ste<br />

date care apoi vor fi preluate <strong>de</strong> cel <strong>de</strong> al doilea. Comunicarea între cele<br />

două procese se realizează prin intermediul unei zone <strong>de</strong> memorie – tampon,<br />

– <strong>de</strong> o anumită dimensiune, în care procesul P1 introduce informat¸ii (sub<br />

forma unor înregistrări), pe care apoi P2 le extrage.<br />

Procesul P2 nu este nevoit să a¸stepte pentru fiecare înregistrare în parte, iar<br />

P1 nu a¸steptă până ce P2 este gata să recept¸ioneze înregistrarea produsă.<br />

Procesele evoluează in<strong>de</strong>pen<strong>de</strong>nt unul <strong>de</strong> celălat, P1 introducând în tampon<br />

înregistrarea produsă, <strong>de</strong> un<strong>de</strong> P2 o va extrage la nevoie.<br />

Se impun următoarele restrict¸ii:<br />

• Procesul P1 încearcă să introducă o înregistrare în tampon ¸si constată<br />

că acesta s-a umplut. În acest caz, el va trebui să a¸stepte până ce se<br />

ive¸ste un loc în tampon (ceea ce se va întâmpla ca urmare a extrageri<br />

unei înregistrări <strong>de</strong> către P2).


9.1. PROBLEME PROPUSE 183<br />

• Procesul P2 încearcă să extragă o înregistrare ¸si constată că tamponul<br />

este gol. În acest caz el va trebui să a¸stepte până ce apare o înregistrare<br />

ca urmare a introduceri unei înregistrări în tampon <strong>de</strong> câtre P1.<br />

Se <strong>de</strong>fine¸ste interfat¸a<br />

package iprodcons;<br />

public interface IBoun<strong>de</strong>dBuffer extends java.rmi.Remote{<br />

public void put(Object obj) throws java.rmi.RemoteException;<br />

public Object get() throws java.rmi.RemoteException;<br />

}<br />

Se cere:<br />

(a) Implementarea interfet¸ei IBoun<strong>de</strong>dBuffer.<br />

(b) Realizarea a două programe client Producator, care introduce obiecte<br />

în tampon ¸si Consumator pentru extragerea lor.<br />

7. Aplicat¸ie <strong>de</strong> e-mail.<br />

Un e-mail este <strong>de</strong>finit printr-un ansamblu <strong>de</strong> 4 variabile <strong>de</strong> tip String<br />

(<strong>de</strong> la (from), catre (to), subiect (subject), mesaj (body)).<br />

package iemail;<br />

import java.io.Serializable;<br />

public class Email implements Serializable {<br />

public String from = "";<br />

public String subject = "";<br />

public String to = "";<br />

public String body = "";<br />

public Email() {}<br />

public Email(String from, String to, String subject, String body) {<br />

this.from =from;<br />

this.subject =subject;<br />

this.to =to;<br />

this.body =body;<br />

}<br />

}<br />

Interfat¸a aplicat¸iei IEmailServer este<br />

package iemail;<br />

import java.rmi.*;<br />

public interface IEmailServer extends Remote {<br />

public boolean login(String name, String password)<br />

throws RemoteException;<br />

public void createUser(String name, String password)


184 CAPITOLUL 9. TEME DE LABORATOR<br />

throws RemoteException;<br />

public void writeEmail(String from, String to,<br />

String subject, String body) throws RemoteException,<br />

UnknownUserException;<br />

public void readEmail(String userName,ICallbackEmail ce)<br />

throws RemoteException;<br />

}<br />

Un client / utilizator al serviciului sau serverului <strong>de</strong> e-mail este o instant¸ă<br />

a clasei User.<br />

package email;<br />

import java.util.*;<br />

import iemail.*;<br />

public class User implements java.io.Serializable{<br />

String name, password;<br />

Vector emails = new Vector();<br />

public User(String name, String password) {<br />

this.name = name;<br />

this.password = password;<br />

}<br />

public void addEmail(Email email) {<br />

emails.addElement(email);<br />

}<br />

}<br />

Pentru a putea folosi serverul <strong>de</strong> e-mail, un client trebuie în prealabil să se<br />

înregistreze (createUser).<br />

Un client înregistrat se poate conecta la serverul <strong>de</strong> e-mail (login) după<br />

care poate scrie (trimite) sau citi (recept¸iona) mesaje.<br />

Se cere ca la adăgarea unui mesaj (<strong>de</strong>ci înaintea apelării meto<strong>de</strong>i User.addEmail)<br />

să se verifice dacă emitentul este conectat ¸si dacă <strong>de</strong>stinatarul este înregistrat.<br />

în caz contrar se generează except¸ia UnknownUserException<br />

package iemail;<br />

public class UnknownUserException extends Exception {<br />

public UnknownUserException() {<br />

super();<br />

}<br />

public UnknownUserException(String exception) {<br />

super(exception);<br />

}<br />

}<br />

Citirea mesajelor este lăsată la latitu<strong>din</strong>ea client¸ilor în sensul că clientul<br />

implementează metoda printEmail al interfet¸ei ICallbackEmail.


9.1. PROBLEME PROPUSE 185<br />

package iemail;<br />

import java.rmi.*;<br />

import java.rmi.server.*;<br />

public interface ICallbackEmail extends Remote {<br />

public void printEmail(Email email) throws RemoteException;<br />

}<br />

Solicitarea recept¸ionării mesajelor se realizează <strong>de</strong> către server prin apelarea<br />

meto<strong>de</strong>i printEmail pentru fiecare mesaj primit <strong>de</strong> client.<br />

Se cere:<br />

(a) Implementarea interfet¸ei IEmailServer.<br />

(b) Realizarea a două programe client AddClient pentru înregistrarea utilizatorilor<br />

¸si ClientEmail pentru exploatarea serviciului <strong>de</strong> e-mail.<br />

Fiecare <strong>din</strong> cele două programe are ca parametri numele (i<strong>de</strong>ntificatorul)<br />

clientului, parola ¸si referint¸a serverului.<br />

8. Integrare numerică.<br />

Scopul aplicat¸iei este calculul unei integrale <strong>de</strong> un program server cu funct¸ia<br />

<strong>de</strong> integrat <strong>de</strong>t¸inută <strong>de</strong> către client. Evaluările funct¸iei cerute <strong>de</strong> formula<br />

<strong>de</strong> integrare numerică se vor realiza prin apel invers. Integrarea numerică<br />

va fi executat <strong>de</strong> un server disponibil client¸ilor prin mecanismul <strong>de</strong> fabrică<br />

<strong>de</strong> obiecte.<br />

Interfat¸a fabricii <strong>de</strong> obiecte este<br />

package integ;<br />

import java.rmi.*;<br />

public interface IFabIntegrator extends Remote{<br />

IIntegrator getIntegrator() throws RemoteException;<br />

}<br />

iar interfat¸a IIntegrator este<br />

package integ;<br />

import java.rmi.*;<br />

public interface IIntegrator extends Remote{<br />

double adaptiveSimpson(double leftEnd, double rightEnd,<br />

double epsilon, int initParam) throws RemoteException;<br />

}<br />

<strong>de</strong>clară o metodă ce calculează un ¸sir (Imk )k până în momentul |Imk −<br />

| < ε.<br />

Imk−1<br />

Propunem utilizarea formulei lui Simpson<br />

b<br />

f(x)dx ≈ Im =<br />

a<br />

m−1<br />

b − a <br />

m−1 <br />

[f(a) + 2 f(a2i) + 4 f(a2i+1) + f(b)]<br />

6m<br />

i=1<br />

i=0


186 CAPITOLUL 9. TEME DE LABORATOR<br />

un<strong>de</strong> ai = a + i b−a<br />

2m .<br />

S¸irul (mk)k este <strong>de</strong>finit prin mk = 2 k m0.<br />

Semnificat¸ia parametrilor meto<strong>de</strong>i adaptiveSimpson este<br />

Interfat¸a apelului invers este<br />

leftEnd a<br />

rightEnd b<br />

epsilon ε<br />

initParam m0<br />

package integ;<br />

import java.rmi.*;<br />

double function(double x)throws RemoteException;<br />

}<br />

Se cere implementarea aplicat¸iei cu minimizarea numărului <strong>de</strong> apelări a<br />

meto<strong>de</strong>i function.<br />

9. Agendă telefonică.<br />

Pentru crearea ¸si întret¸inerea unei agen<strong>de</strong> telefonice consi<strong>de</strong>răm:<br />

Un ServerCarteTelefon realizează următoarele operat¸ii:<br />

• adaugă o înregisrare în agenda telefonică;<br />

O înregistrare este alcătuită <strong>din</strong>tr-o pereche (nume, număr).<br />

package itelef;<br />

import java.io.Serializable;<br />

public class Entry implements Serializable{<br />

public String nume,numar;<br />

}<br />

}<br />

public Entry(String nume,String numar){<br />

this.nume=nume;<br />

this.numar=numar;<br />

• sterge înregistrarea corespunzătoare unui nume <strong>din</strong> agenda telefonică.<br />

• interogarea agen<strong>de</strong>i: furnizează numărul <strong>de</strong> telefon al unui nume;<br />

• modificarea numărului <strong>de</strong> telefon corespunzător unui nume;<br />

• afi¸sarea înregistrărilor;<br />

• salvarea înregistrărilor într-un fi¸sier;<br />

• restaurarea înregistrărilor <strong>din</strong>tr-un fi¸sier.<br />

Interfat¸a corespunzătoare ICarteTelefon este


9.1. PROBLEME PROPUSE 187<br />

package itelef;<br />

import java.rmi.*;<br />

public interface ICarteTelefon extends Remote{<br />

void addEntry(Entry e)throws RemoteException;<br />

String lookupNumber(String p)throws RemoteException;<br />

void <strong>de</strong>leteEntry(Entry e)throws RemoteException;<br />

Entry[] list() throws RemoteException;<br />

void save(String file)throws RemoteException;<br />

void restore(String file)throws RemoteException,ClassNotFoundException;<br />

void modifyEntry(Entry e)throws RemoteException;<br />

}<br />

Interfat¸a fabricii <strong>de</strong> obiecte IFabCarteTelefon este<br />

package itelef;<br />

import java.rmi.*;<br />

public interface IFabCarteTelefon extends Remote{<br />

ICarteTelefon getCarteTelefon() throws RemoteException;<br />

}<br />

Se cere implementarea aplicat¸iei <strong>de</strong> creare ¸si întret¸inere a agen<strong>de</strong>i telefonice.<br />

Se extin<strong>de</strong> aplicat¸ia anterioară cu funct¸iunea suplimentară a serverului <strong>de</strong><br />

a ret¸ine toate modificările efectuate <strong>de</strong> către un client ¸si care la solicitare<br />

pot fi afi¸sate.<br />

Modificările se ret¸in într-o variabilă mod <strong>de</strong> tip Vector. La solicitarea<br />

clientului, pentru fiecare modificare memorată, programul server apelează<br />

metoda schimbStare <strong>de</strong>clarată în interfat¸a<br />

package itelef;<br />

import java.rmi.*;<br />

public interface IApelInvers extends Remote{<br />

void schimbStare(Entry e) throws RemoteException;<br />

}<br />

Metoda schimbStare(Entry e) nu face altceva <strong>de</strong>cât afi¸sează câmpurile<br />

variabilei e.<br />

Interfat¸a ICarteTelefon <strong>de</strong>clară în plus metoda<br />

void apelInvers(IApelInvers obj)throws RemoteException;<br />

Această metodă va fi implementată în programul ServerCarteTelefon.java.<br />

Elementelor ret¸inute în vectorul mod li se aplică metoda schimbStare().<br />

Să se implementeze acestă funct¸iune utilizând tehnica apelului invers.<br />

Se poate utiliza baza <strong>de</strong> date AGENDATELEFONICA formată <strong>din</strong> tabelul


188 CAPITOLUL 9. TEME DE LABORATOR<br />

TELEF<br />

ID<br />

NUME<br />

NUMAR<br />

10. Să se realizeze programe client având o interfat¸ă grafică. Recomandăm<br />

utilizarea produsului NetBeans.<br />

R. Exemplu <strong>de</strong> client pentru problema calculului celui mai mare divizor<br />

comun a două numere cu soclu TCP.<br />

import java.net.*;<br />

import java.io.*;<br />

public class VisualCmmdcClient extends javax.swing.JFrame {<br />

public VisualCmmdcClient() {<br />

initComponents();<br />

}<br />

private void initComponents(){<br />

// cod generat <strong>de</strong> Netbeans<br />

}<br />

private void jButton1MouseClicked(java.awt.event.MouseEvent evt){<br />

long m=(new Long(jTextField1.getText())).longValue();<br />

long n=(new Long(jTextField2.getText())).longValue();<br />

String host=jTextField4.getText();<br />

int port=(new Integer(jTextField5.getText())).intValue();<br />

Socket cmmdcSocket = null;<br />

DataInputStream in=null;<br />

DataOutputStream out=null;<br />

try {<br />

cmmdcSocket = new Socket(host, port);<br />

out=new DataOutputStream(cmmdcSocket.getOutputStream());<br />

in=new DataInputStream(cmmdcSocket.getInputStream());<br />

}<br />

catch(UnknownHostException e) {<br />

System.err.println("Server necunoscut: "+host);<br />

System.exit(1);<br />

}<br />

catch (IOException e) {<br />

System.err.println("Eroare I/O : "+host+" la portul "+port);<br />

System.exit(1);<br />

}<br />

try{<br />

out.writeLong(m);<br />

out.writeLong(n);<br />

long r=in.readLong();<br />

jTextField3.setText(new Long(r).toString());<br />

out.close();<br />

in.close();<br />

cmmdcSocket.close();<br />

}<br />

catch(IOException e){<br />

System.err.println("Imposibilitate <strong>de</strong> comunicare");


9.1. PROBLEME PROPUSE 189<br />

}<br />

}<br />

private void exitForm(java.awt.event.WindowEvent evt) {<br />

System.exit(0);<br />

}<br />

public static void main(String args[]) {<br />

new VisualCmmdcClient().setVisible(true);<br />

}<br />

private javax.swing.JButton jButton1;<br />

private javax.swing.JLabel jLabel1;<br />

private javax.swing.JLabel jLabel2;<br />

private javax.swing.JLabel jLabel3;<br />

private javax.swing.JLabel jLabel4;<br />

private javax.swing.JTextField jTextField1;<br />

private javax.swing.JTextField jTextField2;<br />

private javax.swing.JTextField jTextField3;<br />

private javax.swing.JTextField jTextField4;<br />

private javax.swing.JTextField jTextField5;<br />

}<br />

11. Să se <strong>de</strong>termine zodia (chinezească) corespunzătoare unei date calendaristice.<br />

12. Să se convertească unităt¸ile <strong>de</strong> masură pentru masă ¸si lungime între sistemul<br />

internat¸ional ¸si sistemul anglo-saxon.<br />

13. Se consi<strong>de</strong>ră baza <strong>de</strong> date NORME-DIDACTICE formată <strong>din</strong> tabelele<br />

CADRU-DIDACTIC MATERIA CURSURI<br />

COD-CADRU-DIDACTIC COD-MATERIE COD-CURS<br />

NUME DENUMIRE COD-CADRU-DIDACTIC<br />

COD-MATERIE<br />

Să se elaboreze programe <strong>de</strong> întret¸inere ¸si interogare a bazei <strong>de</strong> date.<br />

14. Se consi<strong>de</strong>ră baza <strong>de</strong> date APROVIZIONARE formată <strong>din</strong> tabelele<br />

RESURSA FURNIZOR CONTRACT<br />

COD-RESURSA COD-FURNIZOR COD-CONTRACT<br />

DENUMIRE NUME COD-FURNIZOR<br />

CANTITATE COD-RESURSA<br />

CANTITATE<br />

Să se elaboreze programe <strong>de</strong> întret¸inere ¸si interogare a bazei <strong>de</strong> date.<br />

15. Se consi<strong>de</strong>ră baza <strong>de</strong> date DESFACERE formată <strong>din</strong> tabelele


190 CAPITOLUL 9. TEME DE LABORATOR<br />

PRODUSE BENEFICIAR CONTRACT<br />

COD-PRODUS COD-BENEFICIAR COD-CONTRACT<br />

DENUMIRE NUME COD-BENEFICIAR<br />

CANTITATE COD-PRODUS<br />

CANTITATE<br />

Să se elaboreze programe <strong>de</strong> întret¸inere ¸si interogare a bazei <strong>de</strong> date.


Appendix A<br />

XML<br />

Exten<strong>de</strong>d Markup Language (XML) reprezintă un limbaj pentru <strong>de</strong>finirea<br />

marcajelor <strong>de</strong> semantică care împart un document în părt¸i ¸si permit i<strong>de</strong>ntificarea<br />

lor în document.<br />

Totodată XML este un meta-limbaj pentru <strong>de</strong>finirea sintaxei <strong>de</strong> utilizat în<br />

alte domenii.<br />

XML <strong>de</strong>scrie structura ¸si semantica ¸si nu formatarea.<br />

Structura unui document xml este<br />

<br />

corpul documentului alcatuit <strong>din</strong> elemente<br />

Prima linie reprezintă <strong>de</strong>clarat¸ia <strong>de</strong> document XML.<br />

Corpul documentului este alcătuit <strong>din</strong> elemente. Începutul unui element este<br />

indicat printr-un marcaj. Textul marcajului constituie <strong>de</strong>numirea elementului.<br />

Elementele pot fi cu corp, alcătuit <strong>din</strong> alte elemente, având sintaxa<br />

<br />

corpul elementului<br />

<br />

sau fără corp, caz în care sintaxa este<br />

<br />

Un marcaj poate avea atribute date prin sintaxa<br />

numeAtribut="valoareAtribut"<br />

Valoarea unui atribut este cuprinsă între ghilimele (””).<br />

Există un singur element rădăcină. Elementele unui document XML formează<br />

un arbore. Fiecărui marcaj <strong>de</strong> început unui element trebuie să-i corespundă un<br />

191


192 APPENDIX A. XML<br />

marcaj <strong>de</strong> sfâr¸sit. Caracterele mari ¸si mici <strong>din</strong> <strong>de</strong>numirea unui element sunt<br />

distincte (case sensitive).<br />

Elementele încuibărite (nested)- incluse într-un alt element - nu se pot amesteca.<br />

Un comentariu se indică prin<br />

<br />

Exemplul A.0.1<br />

<br />

<br />

<br />

Analiza numerica <br />

<br />

2 <br />

1 <br />

1 <br />

<br />

<br />

<br />

Programare distribuita <br />

<br />

2 <br />

0 <br />

2 <br />

<br />

<br />

<br />

Soft matematic <br />

<br />

2 <br />

0 <br />

1 <br />

<br />

<br />


Appendix B<br />

Apache-ant<br />

Utilitarul Apache-ant asigură executarea unui ¸sir <strong>de</strong> comenzi <strong>de</strong> operare.<br />

Aceste comenzi se înregistrează într-un fi¸sier <strong>de</strong> tip xml, cu <strong>de</strong>numirea build.xml.<br />

Astfel Apache-ant se substituie unui fi¸sier <strong>de</strong> comenzi bat. Avantajul obt¸inut<br />

constă în in<strong>de</strong>pen<strong>de</strong>nt¸a fat¸ă <strong>de</strong> platforma <strong>de</strong> calcul (Windows, Linux).<br />

Instalarea constă în <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scărcat <strong>de</strong> pe pagina Web<br />

www.apache.org.<br />

Lansarea în execut¸ie necesită fixarea parametrului JAVA HOME, ce cont¸ine<br />

calea la distribut¸ia Java. Lansarea se poate face prin următorul fi¸sier <strong>de</strong> comenzi<br />

set ANT_HOME=. . .<br />

set JAVA_HOME=. . .<br />

set PATH=%ANT_HOME%\bin;%PATH%<br />

ant.bat %1<br />

Parametrul acestui fi¸sier <strong>de</strong> comenzi reprezintă obiectivul care se dore¸ste a fi<br />

atins.<br />

Fi¸sierul build.xml. Un fi¸sier build.xml corespun<strong>de</strong> unui proiect (project),<br />

alcătuit <strong>din</strong> una sau mai multe obiective (target). Atingerea fiecarărui obiectiv<br />

constă <strong>din</strong> in<strong>de</strong>plinirea uneia sau mai multor sarcini (task). Apache-ant cont¸ine o<br />

familie <strong>de</strong> sarcini. Programatorul are datoria fixării atributelor sarcinilor. Manualul<br />

<strong>din</strong> documentat¸ia produsului cont¸ine <strong>de</strong>scrierea atributelor cât ¸si exemple.<br />

În general, o sarcină reprezintă o operat¸ie executată uzual în linia <strong>de</strong> comandă.<br />

Atributele se dau, respectând sintaxa xml<br />

Astfel, un proiect apare sub forma<br />


194 APPENDIX B. APACHE-ANT<br />

<strong>de</strong>fault="obiectiv"<br />

basedir="catalogDeReferinta"><br />

<br />

sarcini<br />

<br />

. . . . . . .<br />

<br />

Dacă la apelarea lui Apache-ant lipse¸ste parametrul opt¸ional atunci se va<br />

executa obiectivul <strong>de</strong>fault.<br />

Într-un proiect se pot <strong>de</strong>fini variabile prin marcajul<br />

<br />

O variabilă se utilizează prin sintaxa ${numeVariabila}<br />

Exemplul B.0.2 Fi¸sierul build pentru execut¸ia programelor <strong>din</strong> §1.2.<br />

<br />

Socluri TCP <br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


Appendix C<br />

Utilizarea SGBD în Java<br />

Scopul acestei anexe este prezentarea bazelor utilizării unui sistem <strong>de</strong> gestiune<br />

a bazelor <strong>de</strong> date (SGBD) <strong>din</strong> Java. Exemplificăm modul <strong>de</strong> operare ¸si utilizare<br />

pentru crearea ¸si exploatarea unei baze <strong>de</strong> date corespunzătoare unei agen<strong>de</strong><br />

telefonice.<br />

C.1 Derby<br />

Instalarea produsului constă în <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scărcat în catalogul<br />

jdk*.*.*\db.<br />

Utilizarea produsului. Va fi utilizată varianta <strong>de</strong> ret¸ea bazată pe un server<br />

al SGBD care utilizează implicit portul 1527.<br />

Se întreprind următoarele operat¸ii:<br />

1. Lansarea serverului Derby:<br />

set JAVA_HOME=. . .<br />

set DERBY_HOME=. . .<br />

set PATH=%DERBY_HOME%\bin;%PATH%<br />

startNetworkServer.bat<br />

2. Crearea bazei <strong>de</strong> date se va face utilizând utilitarul ij <strong>din</strong> distribut¸ia Derby.<br />

Acesta se lansează prin:<br />

set JAVA_HOME=. . .<br />

set DERBY_HOME=. . .<br />

set PATH=%DERBY_HOME%\bin;%PATH%<br />

ij.bat<br />

Exemplul C.1.1<br />

Baza <strong>de</strong> date AgendaTelefonica se crează executând<br />

195


196 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

run ’CreateAgendaT.sql’;<br />

un<strong>de</strong> fi¸sierul CreateAgendaT.sql este<br />

connect ’jdbc:<strong>de</strong>rby:AgendaTelefonica;create=true’;<br />

create table telef(<br />

id int generated always as i<strong>de</strong>ntity(start with 1, increment by 1) primary key,<br />

nume char(20) not null,<br />

numar char(13) not null<br />

);<br />

¸si încărcarea cu date<br />

run ’ValuesAgendaT.sql’;<br />

cu fi¸sierul ValuesAgendaT.sql<br />

insert into telef values(’aaa’,’111111’),(’bbb’,’222222’),(’ccc’,’333333’);<br />

C.2 mysql<br />

Instalarea produsului. Pentru instalare s-a <strong>de</strong>scărcat varianta fără instalare<br />

automată mysql-noinstall-*.*.*-win32.zip. Acest fi¸sier se <strong>de</strong>zarhivează<br />

într-un catalog MYSQL HOME.<br />

Implicit, serverul mysql utilizează portul 3306, iar fi¸sierele bazelor <strong>de</strong> date vor<br />

fi găzduite în catalogul MYSQL HOME\data.<br />

Pentru utilizarea în aplicat¸ii Java trebuie <strong>de</strong>scărcat un conector mysql-connectorjava-*.*.*.tar.gz,<br />

cont¸inând fi¸sierul mysql-connector-java-<br />

*.*.*-bin.jar.<br />

Utilizarea produsului.<br />

Se întreprind următoarele operat¸ii:<br />

1. Lansarea serverului mysql:<br />

set MYSQL_HOME=. . .<br />

set PATH=%MYSQL_HOME%\bin;%PATH%<br />

mysqld<br />

2. Exemplul C.2.1<br />

Crearea bazei <strong>de</strong> date AgendaTelefonica se va face prin intermediul fi¸sierului<br />

<strong>de</strong> comenzi<br />

set MYSQL_HOME=d:\mysql-5.0.45-win32\bin<br />

set path=%MYSQL_HOME%;%PATH%<br />

mysql -u root < CreateAgendaT.sql<br />

mysql -u root < ValuesAgendaT.sql


C.3. POSTGRSQL 197<br />

un<strong>de</strong> scriptul CreateAgendaT.sql este<br />

create database AgendaTelefonica;<br />

use AgendaTelefonica;<br />

create table telef(<br />

nume char(20) not null primary key,<br />

numar char(13) not null<br />

);<br />

iar scriptul <strong>de</strong> populare cu date (ValuesAgendaT.sql) este<br />

use AgendaTelefonica;<br />

insert telef values("aaa","111111");<br />

insert telef values("bbb","222222");<br />

insert telef values("ccc","333333");<br />

3. Serverul mysql se opre¸ste prin<br />

set MYSQL_HOME=d:\mysql-5.0.45-win32<br />

set PATH=%MYSQL_HOME%\bin;%PATH%<br />

mysqladmin -u root shutdown<br />

C.3 PostgrSQL<br />

Instalarea produsului. PostgreSQL este distribuit gratuit. Pentru sistemul<br />

<strong>de</strong> operare Windows se <strong>de</strong>scarcă o distribut¸ie cu instalare. Cu drepturi <strong>de</strong> administrator<br />

al sistemului gazdă, se execută instalarea cu serverul PostgreSQL drept<br />

serviciu Windows. Comunicat¸ia cu acest server se face prin portul 5432.<br />

Pentru utilizarea în aplicat¸ii Java trebuie <strong>de</strong>scărcat un conector postgresql-<br />

*.*-*.jdbc4.jar.<br />

Utilizarea produsului.<br />

Exemplul C.3.1<br />

Crearea aceleia¸si baze <strong>de</strong> date AgendaTelefonică se face cu fi¸sierul <strong>de</strong> comenzi<br />

set PGHOME=d:\PostgreSQL<br />

set PATH=%PGHOME%\8.3\bin;%PATH%<br />

psql -U postgres -f createdb.sql<br />

psql -U user -d AgendaTelefonica -f createtable.sql<br />

psql -U user -d AgendaTelefonica -f insertvalues.sql<br />

user este numele unui cont PostgreSQL care se poate crea cu componenta <strong>de</strong><br />

administrare pgAdmin III, prin meniul Login Role / New Login Role.<br />

Script-urile sql sunt<br />

createdb.sql<br />

create database "AgendaTelefonica" enco<strong>din</strong>g ’utf8’ owner user;


198 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

createtable.sql<br />

create table telef(id int4 primary key,<br />

nume varchar(20) not null, numar varchar(15) not null);<br />

insertvalues.sql<br />

insert into telef values(1,’aaa’,’111111’);<br />

insert into telef values(2,’bbb’,’222222’);<br />

insert into telef values(3,’ccc’,’333333’);<br />

C.4 S¸ablonul <strong>de</strong> utilizare a unei baze <strong>de</strong> date într-un<br />

program Java<br />

Pentru a avea acces la o bază <strong>de</strong> date trebuie stabilită o conexiune la acea<br />

bază <strong>de</strong> date. În acest sens este necesar cunoa¸sterea:<br />

• driver-ului <strong>de</strong> acces la sistemul <strong>de</strong> gestiune a bazei <strong>de</strong> date (SGBD) (String<br />

jdbcDriver)<br />

Tip SGBD Driver Fi¸sierul<br />

driver-ului<br />

access sun.jdbc.odbc.JdbcOdbcDriver<br />

mysql com.mysql.jdbc.Driver mysql-connector-java-*.*.*-bin.jar<br />

(www.mysql.com)<br />

<strong>de</strong>rby org.apache.<strong>de</strong>rby.jdbc.ClientDriver <strong>de</strong>rbyclient.jar<br />

(distribut¸ia <strong>de</strong>rby)<br />

postgrsql org.postgresql.Driver postgresql-*.*-*.jdbc4.jar<br />

Dacă într-un servlet se realizează o conexiune la o bază <strong>de</strong> date atunci<br />

fi¸sierul driver-ului trebuie copiat în catalogul<br />

%TOMCAT HOME%\common\endorsed.<br />

• adresa URL a bazei <strong>de</strong> date (String URLBazaDate), sub forma<br />

un<strong>de</strong> protocol este<br />

Tip SGBD Protocol<br />

access odbc<br />

mysql mysql<br />

<strong>de</strong>rby <strong>de</strong>rby<br />

postgresql postgresql<br />

S¸ablonul <strong>de</strong> prelucrare este<br />

jdbc:protocol://host:port/numeBazaDate


C.4. S¸ABLONUL DE UTILIZARE ÎNTR-UN PROGRAM JAVA 199<br />

String jdbcDriver=. . .<br />

String URLBazaDate=. . .<br />

Connection con=null;<br />

try{<br />

Class.forName(jdbcDriver).newInstance();<br />

con=DriverManager.getConnection(URLBazaDate);<br />

...<br />

}<br />

catch(ClassNotFoundException e){. . .}<br />

catch(SQLException e){. . .}<br />

Odată conexiunea cu baza <strong>de</strong> date stabilită se generează un obiect <strong>de</strong> tip<br />

Statement prin intermediul căruia se execută interogarea SQL.<br />

Statement instructiune=con.createStatement();<br />

String sql=. . . //fraza select;<br />

Rezultatele interogării bazei <strong>de</strong> date se obt¸ine prin<br />

try{<br />

ResultSet rs=instructiune.executeQuery(sql);<br />

while(rs.next()){<br />

prelucrarea rezultatului<br />

}<br />

}<br />

catch(SQLException e){...}<br />

Exemplul C.4.1<br />

O interogare simplă a bazei <strong>de</strong> date AgendaTelefonica se realizează cu programul<br />

import java.io.*;<br />

import java.sql.*;<br />

import java.net.*;<br />

import java.util.*;<br />

public class AgendaT {<br />

Statement instructiune=null;<br />

public void init(){<br />

// SGBD Derby<br />

/*<br />

String jdbcDriver="org.apache.<strong>de</strong>rby.jdbc.ClientDriver";<br />

String URLBazaDate="jdbc:<strong>de</strong>rby://localhost:1527/AgendaTelefonica";<br />

*/<br />

// SGBD mysql<br />

String jdbcDriver="com.mysql.jdbc.Driver";<br />

String URLBazaDate="jdbc:mysql://localhost:3306/AgendaTelefonica?user=root";


200 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

// PostgreSQL<br />

/*<br />

String jdbcDriver="org.postgresql.Driver";<br />

String URLBazaDate="jdbc:postgresql://localhost:5432/AgendaTelefonica";<br />

String username=". . .";<br />

String password=". . .";<br />

*/<br />

Connection con=null;<br />

try{<br />

Class.forName(jdbcDriver).newInstance();<br />

con=DriverManager.getConnection(URLBazaDate);<br />

instructiune=con.createStatement();<br />

}<br />

catch(ClassNotFoundException e){<br />

System.out.println("Driver inexistent JDBC: "+jdbcDriver);<br />

}<br />

catch(SQLException e){<br />

System.out.println("Baza <strong>de</strong> date inexistenta "+URLBazaDate);<br />

}<br />

catch(Exception e){<br />

System.out.println("Eroare : "+e.getMessage());<br />

}<br />

}<br />

public static void main(String[] args) {<br />

AgendaT agenda=new AgendaT();<br />

agenda.init();<br />

Scanner scanner=new Scanner(System.in);<br />

int prel,no;<br />

String ch="Y",nume="",numar="",sql="";<br />

ResultSet rs=null;<br />

try{<br />

while(ch.startsWith("Y")){<br />

do{<br />

System.out.println("Continue ? (Y/N)");<br />

ch=scanner.next().toUpperCase();<br />

}<br />

while((!ch.startsWith("Y"))&&(!ch.startsWith("N")));<br />

if(ch.startsWith("Y")){<br />

System.out.println("Natura interogarii ?");<br />

System.out.println("(Dupa nume:1,Dupa numar:2)");<br />

do{<br />

prel=0;<br />

try{<br />

prel=scanner.nextInt();<br />

}<br />

catch(InputMismatchException e){}<br />

}<br />

while((prel2));<br />

switch(prel){<br />

case 1 :<br />

System.out.println("Numele");<br />

nume=’\’’+scanner.next().trim()+’\’’;<br />

sql="select * from telef where nume="+nume;<br />

rs=agenda.instructiune.executeQuery(sql);<br />

if(rs!=null){<br />

System.out.println("S-au gasit numerele <strong>de</strong> telefon:");<br />

while(rs.next()){


C.4. S¸ABLONUL DE UTILIZARE ÎNTR-UN PROGRAM JAVA 201<br />

System.out.println(rs.getString("numar"));<br />

}<br />

}<br />

else{<br />

System.out.println("Fara telefon !");<br />

}<br />

break;<br />

case 2 :<br />

System.out.println("Numar");<br />

numar=’\’’+scanner.next().trim()+’\’’;<br />

sql="select * from telef where numar="+numar;<br />

rs=agenda.instructiune.executeQuery(sql);<br />

if(rs!=null){<br />

System.out.println("S-a gasit numeley" +<br />

"y:");<br />

while(rs.next()){<br />

System.out.println(rs.getString("nume"));<br />

}<br />

}<br />

else{<br />

System.out.println("Numar inexistent !");<br />

}<br />

break;<br />

<strong>de</strong>fault: System.out.println("Comanda eronata");<br />

}<br />

}<br />

}<br />

}<br />

catch(Exception e){<br />

System.out.println("ClientException: "+e.getMessage());<br />

}<br />

}<br />

}<br />

Fraza select ¸si interogarea se mai putea programa prin<br />

String sql="select * from telef where nume =?";<br />

PreparedStatement prepStmt=con.prepareStatement(sql);<br />

prepStmt.setString(1,nume);<br />

RezultSet rs=prepStmt.executeQuery();<br />

. . .<br />

prepStmt.close();<br />

În acest caz, valoarea variabilei nume este fără apostroafe.<br />

Compilarea ¸si execut¸ia programului necesită <strong>de</strong>clararea în variabila classpath<br />

a fi¸sierelor<br />

• Varianta Derby<br />

<strong>de</strong>rby.jar, <strong>de</strong>rbytools.jar, <strong>de</strong>rbyclient.jar, <strong>de</strong>rbynet.jar <strong>din</strong> catalogul<br />

%DERBY INSTALL%\lib.<br />

• Varianta mysql<br />

%MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar


202 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

Execut¸ia programului presupune serverul SGBD activ.<br />

C.5 Java Persistence API - JPA<br />

Interfat¸a JPA este standardizarea accesului <strong>din</strong> Java la un SGBD relat¸ional.<br />

JPA este un strat care se interpune între programul Java ¸si SGBD. Avantajul<br />

oferit <strong>de</strong> JPA constă în in<strong>de</strong>pen<strong>de</strong>nt¸a programelor Java <strong>de</strong> SGBD utilizat.<br />

Din punct <strong>de</strong> ve<strong>de</strong>re al programării, rezultatul interogării unei baze <strong>de</strong> date<br />

este un obiect.<br />

JPA cont¸ine:<br />

• Persistence: Clasa javax.persistence.Persistence cont¸ine meto<strong>de</strong> statice<br />

pentru obt¸inerea unei instant¸e a clasei EntityManagerFactory, într-o<br />

manieră in<strong>de</strong>pen<strong>de</strong>ntă <strong>de</strong> producătorul JPA.<br />

• EntityManagerFactory: Clasa javax.persistence.EntityManagerFactory<br />

este producătorul obiectelor EntityManager.<br />

• EntityManager: javax.persistence.EntityManager este actorul JPA principal<br />

într-o aplicat¸ie. Un obiect EntityManager mijloce¸ste întret¸inerea ¸si<br />

interogarea unei baze <strong>de</strong> date. Fiecărui obiect <strong>de</strong> tip EntityManager i se<br />

asociază un obiect <strong>de</strong> tip javax.persistence.EntityTransaction.<br />

• Entity: Obiectele Entity corespund înregistrărilor în tabelele bazei <strong>de</strong> date.<br />

• EntityTransaction: asigură integritatea bazei <strong>de</strong> date. Operat¸iile care privesc<br />

persistent¸a datelor sunt grupate în unităt¸i <strong>de</strong> lucru care sunt executate cu<br />

succes sau <strong>de</strong>loc.<br />

• Query: Interfat¸a javax.persistence.Query este specifică implementării.<br />

Prin obiecte <strong>de</strong> tip Query se asigură accesul la baza <strong>de</strong> date. Portivit<br />

standardului JPA este suportat atât limbajul Structured Query Language<br />

(SQL) cât ¸si Java Persistence Query Language (JPQL). Un obiect Query<br />

este instant¸iat prin obiecte EntityManager.<br />

Există mai multe implementări a interfet¸ei JPA.<br />

C.5.1 apache-openjpa<br />

A¸sa cum sugerează numele produsului, openjpa este implementarea oferită <strong>de</strong><br />

apache.<br />

Instalarea revine la <strong>de</strong>zarhivarea fi¸sierului <strong>de</strong>scărcat.<br />

Utilizarea. Compilarea ¸si execut¸ia unei aplicat¸ii o vom face prin intermediul<br />

lui apache-ant. Construim structura <strong>de</strong> cataloage ¸si fi¸siere:


C.5. JAVA PERSISTENCE API - JPA 203<br />

|--> catalogul_aplicatiei<br />

|--> META-INF<br />

| | persistence.xml<br />

| build.xml<br />

Fi¸sierul persistence.xml specifică unităt¸ile <strong>de</strong> persistent¸ă. Fiecare unitate <strong>de</strong><br />

persistent¸ă corespun<strong>de</strong> unui tabel al bazei <strong>de</strong> date ¸si i se asociază o clasă Entity,<br />

<strong>de</strong> fapt o componentă Java. Clasa ¸si tabelul au acela¸si nume. Doar tabelele cărora<br />

li s-a <strong>de</strong>clarat o unitate <strong>de</strong> persistent¸ă pot fi accesate prin apache-openjpa.<br />

Principial fi¸sierul persistence.xml este<br />

<br />

<br />

<br />

<br />

Entity_class_name<br />

<br />

<br />

<br />

<br />

<br />

<br />

appagenda.Telef<br />

<br />

<br />


204 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

<br />

<br />

--><br />

<br />

<br />

<br />

Atributele ce apar în comentarii, pot fi specificate ¸si prin proprietăt¸i System.<br />

S¸ablonul <strong>de</strong> prelucrare este<br />

EntityManagerFactory factory=<br />

Persistence.createEntityManagerFactory("nume_unitate_<strong>de</strong>_persistenta",<br />

System.getProperties());<br />

EntityManager em=factory.createEntityManager();<br />

em.getTransaction().begin();<br />

String sql=fraza SQL sau JPQL<br />

Query query=em.createQuery(sql);<br />

// introducerea unei inregistrari<br />

em.persist(obiect_Entity)<br />

// actualizarea sau stergerea unei inregistrari<br />

query.executeUpdate();<br />

// interogare bazei <strong>de</strong> date<br />

List result=query.getResultList();<br />

em.getTransaction().commit();<br />

em.close();<br />

factory.close();<br />

Dacă fraza SQL este specifică unui SGBD atunci obiectul <strong>de</strong> tip Query se instant¸iază<br />

prin<br />

Query query=em.createNativeQuery(sql,clasa_Entity_utilizata.class);<br />

Exemplul C.5.1 Aplicat¸ie pentru întret¸inerea ¸si interogarea bazei <strong>de</strong> date AgendaTelefonica.<br />

Tabelei telef a bazei <strong>de</strong> date îi corespun<strong>de</strong> clasa Entity<br />

package appagenda;<br />

import javax.persistence.*;<br />

@Entity<br />

public class Telef implements java.io.Serializable{


C.5. JAVA PERSISTENCE API - JPA 205<br />

private int id;<br />

private String nume;<br />

private String numar;<br />

Telef() {}<br />

public int getId(){<br />

return id;<br />

}<br />

public void setId(int id){<br />

this.id=id;<br />

}<br />

public String getNume() {<br />

return nume;<br />

}<br />

public void setNume(String nume) {<br />

this.nume = nume;<br />

}<br />

public String getNumar() {<br />

return numar;<br />

}<br />

public void setNumar(String numar) {<br />

this.numar = numar;<br />

}<br />

}<br />

Accessarea bazei <strong>de</strong> date se face prin clasa AgendaTDAO<br />

package appagenda;<br />

import javax.persistence.*;<br />

import java.util.*;<br />

@SuppressWarnings("unchecked")<br />

public class AgendaTDAO{<br />

EntityManagerFactory factory=null;<br />

EntityManager em;<br />

public AgendaTDAO(EntityManagerFactory factory){<br />

this.factory=factory;<br />

}<br />

public void addAgendaT(Telef a){<br />

em=factory.createEntityManager();<br />

em.getTransaction().begin();<br />

//em.persist(a);<br />

String sql="insert into telef(nume,numar) values(\’"+a.getNume()+"\’,\’"+a.getNumar()+"\’)";<br />

Query query=em.createNativeQuery(sql);<br />

query.executeUpdate();<br />

em.getTransaction().commit();<br />

em.close();<br />

}<br />

public void <strong>de</strong>leteAgendaT(String nume){<br />

em=factory.createEntityManager();<br />

em.getTransaction().begin();<br />

String sql="<strong>de</strong>lete from Telef a where a.nume=\’"+nume+"\’";<br />

Query query=em.createQuery(sql);<br />

query.executeUpdate();


206 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

em.getTransaction().commit();<br />

em.close();<br />

}<br />

public List interogareAgendaT(String nume){<br />

em=factory.createEntityManager();<br />

em.getTransaction().begin();<br />

String sql="select a from Telef a where a.nume=\’"+nume+"\’";<br />

Query query=em.createQuery(sql);<br />

//String sql="select * from telef where nume=\’"+nume+"\’";<br />

//Query query=em.createNativeQuery(sql,appagenda.Telef.class);<br />

List result=query.getResultList();<br />

em.getTransaction().commit();<br />

em.close();<br />

return result;<br />

}<br />

public List listAgendaT() {<br />

em=factory.createEntityManager();<br />

em.getTransaction().begin();<br />

String sql="select a from Telef a";<br />

Query query=em.createQuery(sql);<br />

//String sql="select * from telef";<br />

//Query query=em.createNativeQuery(sql,appagenda.Telef.class);<br />

List result=query.getResultList();<br />

em.getTransaction().commit();<br />

em.close();<br />

return result;<br />

}<br />

}<br />

iar clientul este AgendaTClient<br />

package appagenda;<br />

import java.util.*;<br />

import javax.persistence.*;<br />

public class AgendaTClient{<br />

public static void main(String[] args) {<br />

EntityManagerFactory factory=<br />

Persistence.createEntityManagerFactory("appagenda",System.getProperties());<br />

AgendaTDAO dao=new AgendaTDAO(factory);<br />

String ch="Y";<br />

int prel;<br />

Scanner scanner=new Scanner(System.in);<br />

Telef a=null;<br />

while(ch.startsWith("Y")){<br />

do{<br />

System.out.println("Continue ? (Y/N)");<br />

ch=scanner.next().toUpperCase();<br />

}<br />

while((!ch.startsWith("Y"))&&(!ch.startsWith("N")));<br />

if(ch.startsWith("Y")){<br />

System.out.println("Natura prelucrarii ?");<br />

System.out.println("(Adaug:1,Sterg:2,Inter:3,List:4)");<br />

prel=scanner.nextInt();<br />

String nume,numar;<br />

switch(prel){<br />

case 1 :


C.5. JAVA PERSISTENCE API - JPA 207<br />

System.out.println("ADAUG");<br />

System.out.println("Numele:");<br />

nume=scanner.next().trim();<br />

System.out.println("Numar telefon:");<br />

numar=scanner.next().trim();<br />

a=new Telef();<br />

a.setNume(nume);<br />

a.setNumar(numar);<br />

dao.addAgendaT(a);<br />

break;<br />

case 2 :<br />

System.out.println("STERG");<br />

System.out.println("Numele:");<br />

nume=scanner.next().trim();<br />

dao.<strong>de</strong>leteAgendaT(nume);<br />

break;<br />

case 3 :<br />

System.out.println("INTEROGARE");<br />

System.out.println("Numele:");<br />

nume=scanner.next().trim();<br />

List listInter=dao.interogareAgendaT(nume);<br />

for(Telef t: (List)listInter){<br />

System.out.println("Numele: "+t.getNume()+" Numar: "+t.getNumar());<br />

}<br />

break;<br />

case 4 :<br />

List datas=dao.listAgendaT();<br />

for(Telef t: (List)datas){<br />

System.out.println("Numele: "+t.getNume()+" Numar: "+t.getNumar());<br />

}<br />

break;<br />

<strong>de</strong>fault: System.out.println("Comanda eronata");<br />

}<br />

}<br />

else<br />

System.exit(0);<br />

}<br />

factory.close();<br />

}<br />

}<br />

Fi¸sierul persistence.xml pentru exemplul <strong>de</strong> mai sus este<br />

<br />

<br />

<br />

appagenda.Telef<br />

<br />

<br />

appagenda.Telef<br />

<br />

<br />

Fi¸sierul build.xml are codul<br />


208 APPENDIX C. UTILIZAREA SGBD ÎN JAVA<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


C.5. JAVA PERSISTENCE API - JPA 209<br />

is passed "System.getProperties()".<br />

--><br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


210 APPENDIX C. UTILIZAREA SGBD ÎN JAVA


Bibliografie<br />

[1] ATHANASIU I., COSTINESCU B., DRĂGOI O.A., POPOVICI F.I., 1998,<br />

Limbajul Java. O perspectivă pragmatică. Ed. Computer Libris Agora, Cluj-<br />

Napoca.<br />

[2] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentru<br />

aplicat¸ii Web. Ed. Albastră, Cluj-Napoca.<br />

[3] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucure¸sti.<br />

[4] BURAGA S. (ed), 2007, Programarea în Web 2.0., Ed. Polirom, Ia¸si.<br />

[5] JURCĂ I.,<br />

Timi¸soara.<br />

2000, Programarea ret¸elelor <strong>de</strong> calculatoare. Ed. <strong>de</strong> Vest,<br />

[6] HUNTER J., CRAWFORD W., 1998, Java Servlet Programming. O’Reilly.<br />

[7] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Ia¸si.<br />

[8] SCHEIBER E., 2007, Programare concurentă ¸si paralel distribuită în Java.<br />

Ed. Albastră, Cluj-Napoca.<br />

[9] TANASĂ S¸., OLARU C., 2005, Dezvoltarea aplicat¸iilor Web folosind Java.<br />

Ed. Polirom, Bucure¸sti.<br />

[10] * * * , Java 2 SDK /docs/, Sun Microsystems.<br />

[11] * * * , JavaWS Tutorial 1.*, Sun Microsystems.<br />

[12] * * * , J2EE Tutorial, Sun Microsystems.<br />

[13] * * * , Java 2 Tutorial, Sun Microsystems.<br />

211

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!