programare distribuita

371
Universitatea Transilvania din Bra¸ sov Facultatea de Matematic˘a–Informatic˘ a ERNEST SCHEIBER PROGRAMARE DISTRIBUIT ˘ A ˆ IN JAVA Bra¸ sov

description

programare distribuita

Transcript of programare distribuita

Page 1: programare distribuita

Universitatea Transilvania din BrasovFacultatea de Matematica–Informatica

ERNEST SCHEIBER

PROGRAMAREDISTRIBUITA IN JAVA

Brasov

Page 2: programare distribuita

2

Page 3: programare distribuita

Prefata

Scopul acestui curs este prezentarea tehnologiilor de programare Java carepermit programarea aplicatiilor client - server:

• socluri Java;

• apelarea metodelor de la distanta (Remote Method Invocation - RMI );

• CORBA - Common Object Request Brocker Arhitecture;

• mesageria Java;

• servlet;

• Java Server Pages - JSP;

• Enterprise Java Bean.

Accentul cade pe detaliile tehnice de realizare a comunicatiilor si pe arhi-tectura programelor / aplicatiilor care le utilizeaza. Trebuie semnalat faptulca exemplele date nu incorporeaza aspecte indispensabile unei aplicatii infor-matice la standardele zilei:

• securitate, autentificare si autorizare;

• interfata grafica pentru componenta client;

• utilizarea bazelor de date relationale / orientate obiect / NoSQL.

Metodele si instrumentele de programare vor fi exemplificate pe problemafoarte simpla de calcul a celui mai mare divizor comun a doua numere naturale.Codul acestei metode de calcul poate fi

Varianta imperativa ca metoda

3

Page 4: programare distribuita

4

1 public long cmmdc( long m, long n){2 long r , c ;3 do{4 c=n ;5 r=m%n ;6 m=n ;7 n=r ;8 }9 while ( r !=0) ;

10 return c ;11 }

care se poate transforma ıntr-o lambda expresie

1 interface CmmdcService {2 long cmmdc( long m, long n ) ;3 }

5 stat ic CmmdcService cmmdcService=(long m, long n) −> {6 long r , c ;7 do{8 c=n ;9 r=m%n ;

10 m=n ;11 n=r ;12 }13 while ( r !=0) ;14 return c ;15 } ;

Varianta declarativa / recursiva

1 public long cmmdc( long m, long n){2 i f (m==n)3 return m;4 else5 i f (m>n)6 return cmmdc(m−n , n ) ;7 else8 return cmmdc(m, n−m) ;9 }

Guava: Google Core Libraries for Java poseda o metoda de calcul a celui maimare divizor a doua numere naturale com.google.common.math.LongMath.

gcd(...).

Pentru aplicatiile care utilizeaza o baza de date, sistemul de gestiune abazei de date (SGBD) va fi una dintre sistemele Derby/Javadb sau mysql.

Tiparul de ınvatare propus este

1. Se instaleaza toate resursele necesare (Se exemplifica la laborator).

2. Se executa aplicatia / aplicatiile din curs (Se exemplifica la laborator).

Page 5: programare distribuita

5

3. Pentru fiecare tehnologie, pe suportul oferit de curs, se programeaza oalta aplicatie.

Propunem urmatoarele teme:

• Conversia dintre grade Celsius si grade Fahrenheit (F = 1.8C+32).

• Crearea, ıntretinerea si utilizarea unei agende de adrese de e-mail.Agenda este o baza de date.

4. In final, se rezolva tema pentru examen.

Nu de putine ori metodele / tehnologiile utilizate presupun utilizarea unuisablon de programare specific. Din acest punct de vedere, acest curs se dorestea fi un suport metodic.

Page 6: programare distribuita

6

Page 7: programare distribuita

Produsele informatice utilizate

Pe durata existentei, produsele informatice evolueaza prin versiunile pe careproducatorii ni le pun la dispozitie. Nu de putine ori o versiune noua nu estecompatibila cu versiunea anterioara, fapt care necesita adaptarea programelorclient.

Lista urmatoare precizeaza versiunile produselor utilizate ın curs, indicateın majoritatea cazurilor prin resursa de instalare.

Versiunile produselor informatice utilizate ın lucrare

No. Produsul informatic Resursa/versiunea

1 apache-ant apache.ant-1.8.1-bin.tar.gz2 apache-commons-fileupload commons-fileupload-1.3-bin.tar.gz3 apache-ftpserver ftpserver-1.0.6.tar.gz4 apache-maven apache-maven-3.1.0-bin.tar.gz5 apache-tomcat apache-tomcat-7.0.42.tar.gz6 apacheds apacheds-2.0.0-M15.tar.gz7 glassfish glassfish-4.0.zip8 google appengine appengine-java-sdk-1.8.0.zip9 db-derby db-derby-10.10.1.1-bin.tar.gz10 httpcomponents-client httpcomponents-client-4.3-bin.tar.gz11 httpcomponents-asyncclient httpcomponents-asyncclient-4.0-beta4-bin.tar.gz12 Java (jdk) jdk-7u40-windows-{i586;x64}.exe13 junit junit4.11.zip14 mysql mysql-5.6.10-win{32;x64}.zip15 mysql-connector mysql-connector-java-5.1.24.tar.gz16 OpenDS OpenDS-2.3.0-build003.zip17 openmq openmq5.0-binary-WINNT.zip

7

Page 8: programare distribuita

8

Page 9: programare distribuita

Cuprins

1 Introducere 15

I TEHNOLOGII PENTRU RETELE LOCALE 21

2 Programare cu socluri Java 23

2.1 TCP vs. UDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

2.2 Soclu TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.2.1 Aplicatie client – server cu socluri . . . . . . . . . . . . . 25

2.2.2 Streaming . . . . . . . . . . . . . . . . . . . . . . . . . . 30

2.3 Datagrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.3.1 Aplicatii client – server cu datagrame. . . . . . . . . . . 38

2.3.2 Multicast vs. Broadcast . . . . . . . . . . . . . . . . . . 43

2.4 Canale de comunicatie . . . . . . . . . . . . . . . . . . . . . . . 44

2.5 Receptie cu Selector . . . . . . . . . . . . . . . . . . . . . . . 58

2.6 Comunicatii asincrone prin canale . . . . . . . . . . . . . . . . . 61

3 Regasirea obiectelor prin servicii de nume 67

3.1 Java Naming and Directory Interface . . . . . . . . . . . . . . . 67

3.1.1 LDAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4 Invocarea procedurilor la distanta 77

4.1 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . 77

4.1.1 Crearea unei aplicatii RMI . . . . . . . . . . . . . . . . . 81

4.1.2 Tipare de programare . . . . . . . . . . . . . . . . . . . . 87

4.1.3 Obiect activabil la distanta . . . . . . . . . . . . . . . . 93

4.2 CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

4.2.1 Conexiunea RMI - CORBA . . . . . . . . . . . . . . . . 98

4.2.2 Aplicatie Java prin CORBA . . . . . . . . . . . . . . . . 103

9

Page 10: programare distribuita

10 CUPRINS

5 Mesaje ın Java 1135.1 Java Message Service (JMS) . . . . . . . . . . . . . . . . . . . . 1135.2 Open Message Queue 5 . . . . . . . . . . . . . . . . . . . . . . . 1155.3 Elemente de programare - JMS-2 . . . . . . . . . . . . . . . . . 116

5.3.1 Modul programat: Trimiterea unui mesaj . . . . . . . . . 1165.3.2 Receptia sincrona a unui mesaj . . . . . . . . . . . . . . 1185.3.3 Receptia asincrona a unui mesaj . . . . . . . . . . . . . . 1205.3.4 Publicarea mesajelor . . . . . . . . . . . . . . . . . . . . 1225.3.5 Abonare si receptia mesajelor . . . . . . . . . . . . . . . 1235.3.6 Cazul abonatului partajat . . . . . . . . . . . . . . . . . 1245.3.7 Obiecte administrator prin JNDI . . . . . . . . . . . . . 1275.3.8 Comunicatia prin coada - queue . . . . . . . . . . . . . . 1285.3.9 Comunicatia pe baza de subiect - topic . . . . . . . . . . 1315.3.10 Aplicatie JMS slab cuplata . . . . . . . . . . . . . . . . . 1335.3.11 Programare JMS prin glassfish . . . . . . . . . . . . . . . 136

II COMUNICATII PRIN INTERNET 139

6 HyperText Transfer Protocol 1416.1 Transactie http . . . . . . . . . . . . . . . . . . . . . . . . . . . 1416.2 Server Web - container de servlet . . . . . . . . . . . . . . . . . 1476.3 Serverul Web apache-tomcat . . . . . . . . . . . . . . . . . . . . 1486.4 Glassfish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

7 Applet - Miniaplicatie Java 1537.1 Clasa Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1547.2 Desfasurarea unui applet . . . . . . . . . . . . . . . . . . . . . . 1557.3 Comunicare Java - JavaScript ıntr-un applet . . . . . . . . . . . 161

8 Conexiune simpla prin clase din java.net 1638.1 Clasa java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . 163

9 Servlet 1659.1 Marcajul <form> . . . . . . . . . . . . . . . . . . . . . . . . . . 1669.2 Realizarea unui servlet . . . . . . . . . . . . . . . . . . . . . . . 167

9.2.1 Codul unui servlet . . . . . . . . . . . . . . . . . . . . . 1709.3 Procesare asincrona ın Java Servlet 3.0 . . . . . . . . . . . . . . 1779.4 Dezvoltari ın servlet-api 3.1 . . . . . . . . . . . . . . . . . . . . 180

9.4.1 Procesare asincrona neblocanta . . . . . . . . . . . . . . 180

Page 11: programare distribuita

CUPRINS 11

9.4.2 Modificarea protocolului http: upgrade . . . . . . . . . . 1829.5 Facilitati de programare cu servlet . . . . . . . . . . . . . . . . . 188

9.5.1 Program client al unui servlet . . . . . . . . . . . . . . . 1889.5.2 Servlete ınlantuite . . . . . . . . . . . . . . . . . . . . . 1949.5.3 Sesiune de lucru . . . . . . . . . . . . . . . . . . . . . . . 1969.5.4 Cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1989.5.5 Autentificare . . . . . . . . . . . . . . . . . . . . . . . . 2009.5.6 Servlet cu conexiune la o baza de date . . . . . . . . . . 2019.5.7 Imagini furnizate de servlet . . . . . . . . . . . . . . . . 2049.5.8 Servlet cu RMI . . . . . . . . . . . . . . . . . . . . . . . 2069.5.9 Servlet cu JMS . . . . . . . . . . . . . . . . . . . . . . . 2079.5.10 Servlet cu jurnalizare . . . . . . . . . . . . . . . . . . . . 211

9.6 FileUpload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2129.7 Descarcarea unui fisier . . . . . . . . . . . . . . . . . . . . . . . 2199.8 Filtru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2209.9 Eveniment si auditor . . . . . . . . . . . . . . . . . . . . . . . . 2239.10 Server apache-tomcat ıncorporat . . . . . . . . . . . . . . . . . . 224

10 Java Server Page – JSP 22710.1 Tehnologia JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

10.1.1 Declaratii JSP . . . . . . . . . . . . . . . . . . . . . . . . 23210.1.2 Directive JSP . . . . . . . . . . . . . . . . . . . . . . . . 23410.1.3 Marcaje JSP predefinite . . . . . . . . . . . . . . . . . . 23410.1.4 Pagini JSP cu componente Java . . . . . . . . . . . . . . 236

10.2 JSP Standard Tag Library JSTL . . . . . . . . . . . . . . . . . 23910.2.1 Biblioteca de baza . . . . . . . . . . . . . . . . . . . . . 24010.2.2 Biblioteca de lucru cu baze de date . . . . . . . . . . . . 245

10.3 Marcaje JSP personale . . . . . . . . . . . . . . . . . . . . . . . 24610.3.1 Marcaje fara atribute si fara corp. . . . . . . . . . . . . . 24610.3.2 Marcaje cu atribute si fara corp. . . . . . . . . . . . . . . 25010.3.3 Marcaje cu corp. . . . . . . . . . . . . . . . . . . . . . . 252

10.4 Servlet si JSP ın Google App Engine . . . . . . . . . . . . . . . 254

11 Enterprise Java Beans 25911.1 Session EJB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260

11.1.1 Componenta EJB sesiune stateless . . . . . . . . . . . . 26111.1.2 Aplicatie JEE cu module EJB, Web si client RMI-IIOP . 26411.1.3 Componenta EJB sesiune singleton . . . . . . . . . . . . 26611.1.4 Componenta EJB sesiune stateful . . . . . . . . . . . . . 268

Page 12: programare distribuita

12 CUPRINS

11.1.5 Componenta EJB MessageDriven . . . . . . . . . . . . . 271

11.1.6 Componenta EJB Entity . . . . . . . . . . . . . . . . . . 274

12 Java Web Start 279

12.1 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . 279

13 Java Management Extensions 285

13.1 Standard MBean . . . . . . . . . . . . . . . . . . . . . . . . . . 286

13.1.1 Crearea unui Standard MBean . . . . . . . . . . . . . . . 286

13.1.2 Crearea unui MBeanServer . . . . . . . . . . . . . . . . . 288

13.1.3 Notificari . . . . . . . . . . . . . . . . . . . . . . . . . . 292

13.1.4 Agent MBean . . . . . . . . . . . . . . . . . . . . . . . . 295

13.1.5 Invocarea la distanta . . . . . . . . . . . . . . . . . . . . 296

III ANEXE 311

A Unelte de dezvoltare 313

A.1 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313

A.2 apache-ant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316

A.3 apache-maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318

B Testare cu junit 333

C Jurnalizare 337

D Componenta Java 341

E Adnotari 343

E.1 Definirea unei adnotari . . . . . . . . . . . . . . . . . . . . . . . 343

E.2 Declararea unei adnotari . . . . . . . . . . . . . . . . . . . . . . 344

E.3 Procesarea unei adnotari . . . . . . . . . . . . . . . . . . . . . . 345

F Utilizarea SGBD ın Java 349

F.1 Derby / Javadb . . . . . . . . . . . . . . . . . . . . . . . . . . . 349

F.2 mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350

F.3 Sablonul de utilizare a unei baze de date . . . . . . . . . . . . . 352

Page 13: programare distribuita

CUPRINS 13

IV TEME DE LABORATOR 357

G Teme de aplicatii 359G.1 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . 359

Bibliografie 371

Page 14: programare distribuita

14 CUPRINS

Page 15: programare distribuita

Capitolul 1

Introducere

Retelele locale, internetul, raspandirea pe o arie geografica a resurselor si alocatiilor ın care se petrec actiuni ce tin de o activitate bine definita sau sunturmarite, gestionate din alte locuri au drept consecinta existenta aplicatiilordistribuite. Termenul distribuit se refera tocmai la faptul ca componente aleaplicatiei se afla pe calculatoare diferite dar ıntre care au loc schimburi dedate. Daca partile unei aplicatii sau resursele utilizate se gasesc pe calculatoaredistincte atunci aplicatia se numeste distribuita.

Intre partile sau resursele unei aplicatii distribuite au loc schimburi dedate, ceea ce se face utilizand diferite mecanisme la realizarea carora concurasistemul de calcul, sistemul de operare si limbajul de programare.

Astfel se vorbeste de programare distribuita ca mijloc de realizare a aplicatiilordistribuite. Pe langa algoritm, structuri de date, limbaj de programare, larealizarea unei aplicatii distribuite intervin comunicatiile: schimbul de datedintre doua componente aflate pe calculatoare diferite.

Punem ın evidenta doua modele de aplicatii distribuite:

• client-server: Programul server executa cererile clientilor.

O aplicatie client – server se compune din:

– componenta server - alcatuita din programe / clase ce asigura unasau mai multe functiuni (servicii), care pot fi apelate de catre clienti.

– componenta client - alcatuita din programe / clase care permit ac-cesul la server si apelarea serviciilor acestuia.

Serverul si clientul (clientii) ruleaza, de obicei, pe calculatoare distincte.Un server trebuie sa satisfaca cererile mai multor clienti.

15

Page 16: programare distribuita

16 CAPITOLUL 1. INTRODUCERE

Durata de viata a unei aplicatii client – server este data de duratafunctionarii serverului. Aceasta durata poate fi alcatuita din intervaledisjuncte de timp, ıntre acele intervale, din diverse motive, serverul esteinactiv.

Intervalul de timp determinat de conectarea unui client la server si panala deconectare poarta numele de sesiune. In aceasta perioada, clientulpoate invoca mai multe servicii ale serverului. Un client poate initia maimulte sesiuni.

Un client trebuie sa-si regaseasca datele ın cadrul unei sesiuni, ıntre se-siuni, pe toata durata de viata a aplicatiei. Astfel se pune problemaretinerii / persistentei datelor pentru fiecare client ın parte.

Amintim urmatoarele tehnologii Java pentru realizarea aplicatiilor client-server:

– Tehnologii destinate retelelor locale, nebazate pe protocolul http.

∗ Socluri

∗ RMI (Remote Method Invocation)

∗ CORBA (Common Object Request Brocker Arhitecture)

∗ JMS (Java Message Service)

Comunicatiile utilizeaza porturi care nu trebuie sa fie ınchise deeventuale aplicatii de tip firewall.

– Tehnologii cu comunicatii prin Internet, bazate pe protocolul http.

∗ Servlet si JSP (Java Server Pages)

∗ Java Web Start

∗ WebSocket

• dispecer-lucrator: Programul dispecer distribuie sarcinile de execu-tat lucratorilor si le coordoneaza activitatea. Exista multe abordari deprogramere a aplicatiilor dispecer-lucrator.

Exista diferente mari ıntre o aplicatie care ruleaza pe un calculator si oaplicatie distribuita1

• latenta (latency) - exista mai multe definitii:

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

Page 17: programare distribuita

17

– diferenta ın timp ıntre o operatie executata pe un calculator ladistanta de executia ei pe calculatorul local.

– diferenta ın timp ıntre momentul receptionarii raspunsului la ocerere si momentul lansarii ei.

– diferenta ın timp ıntre momentul receptionarii unei cereri si mo-mentul transmiterii raspunsului.

Receptia rezultatului unei operatii executate pe un calculator la distantase poate programa

– sincron – de obicei receptia blocheaza firul de executie al apeluluipana la sosirea rezultatului;

– asincron – receptia se obtine ıntr-un obiect dedicat care se executaın afara firului de executie al apelului.

O preocupare continua este dezvoltarea de tehnologii hard si soft pentrumicsorarea latentei.

• accesul la memorie (memory access) Aplicatiile distribuite pot rula peplatforme diferite (de exemplu Java si .NET) iar componentele ei pot firealizate ın limbaje de programare diferite. Instrumente de programare -cadre de lucru (framework) care mijlocesc realizarea aplicatiilor asiguraaccesul la resursele aflate ın memoria calculatoarelor.

Exista o preocupare pentru produse care asigura interoperabilitatea din-tre platformele de calcul.

• prabusirea partiala (partial failure) consta ın ıncetarea functionarii uneiparti a aplicatiei distribuite, dar care continua sa fie accesibila. Tratareaacestei probleme pare a fi cea mai dificila tema a programarii distribuite.Teorema CAP (Eric Brewer, 2000) trateaza legatura dintre prabusireapartiala, disponibilitatea aplicatiei si consistenta datelor.

Precizam sensul unor notiuni utilizate ın lucrare:

• protocol - pachet de reguli, sablon utilizat ın comunicatii, ın accesareaunor resurse. Exemple de protocoale utilizate sunt:

– http - HyperText Transfer Protocol este principalul protocol utilizatın comunicatiile prin Internet;

– https protocol http securizat;

Page 18: programare distribuita

18 CAPITOLUL 1. INTRODUCERE

– file - protocol pentru specificarea fisierelor aflate pe calculatorullocal;

– ftp - File Transfer Protocol - protocol pentru transferul fisierelorıntre doua calculatoare;

– smtp - Simple Message Transfer Protocol utilizat de posta elecronica.

• host - calculatorul gazda, cel pe care se lucreaza. Acest calculator sespecifica printr-o adresa IP (Internet Protocol) sau printr-un nume.

• port - o adresa de memorie cuprinsa ıntre 0 si 65535. Porturile cuprinseıntre 0 si 1023 sunt rezervate sistemului de operare. Dintre acestea amin-tim:

Port Utilizat de

80 http443 https25 smtp

Referintele resurselor se indica folosind Uniform Resource Identifiers - (URI)si mai precis Uniform Resource Locator - (URL). URI identifica o resursa ıntimp ce URL desemneaza locatia resursei. URL se considera ca un caz partic-ular de URI. Sintaxa folosita pentru URI este

protocol://host[:port][cale][?cerere]

Un rol important ın dezvoltarea tehnologiilor legate de limbajul Java revineorganizatiilor de standardizare:

• Java Community Process JCP;

• Advancing open standards for the information society OASIS;

• The Internet Engineering Task Force IETF.

Intrebari recapitulative

1. Explicati notiunea de latenta.

2. Explicati termenul de protocol si dati exemple de protocoale de comunicatie.

3. Explicati notiunea de prabusire partiala.

Page 19: programare distribuita

19

4. Ce desemneaza denumirea Java Community Process?

5. Precizati sintaxa unui URI.

Page 20: programare distribuita

20 CAPITOLUL 1. INTRODUCERE

Page 21: programare distribuita

Partea I

TEHNOLOGII PENTRURETELE LOCALE

21

Page 22: programare distribuita
Page 23: programare distribuita

Capitolul 2

Programare cu socluri Java

Comunicatia bazata pe socluri Java constituie modalitatea de nivelul infe-rior pentru realizarea aplicatiilor distribuite.

2.1 TCP vs. UDP

Calculatoarele ce ruleaza ın retea comunica ıntre ele folosind protocolulTCP (Transmission Control Protocol) sau UDP (User Datagram Protocol).

Intr-un program Java se utilizeaza clasele pachetului java.net prin inter-mediul carora se acceseaza nivelele deservite de protocoalele TCP sau UDP.In felul acesta se pot realiza comunicatii independente de platforma de calcul.Pentru a alege clasa Java care sa fie utilizata trebuie cunoscuta diferenta dintreTCP si UDP.

TCP Cand doua aplicatii comunica ıntre ele se stabileste o conexiune prinintermediul careia se schimba date. Folosind protocolul TCP, comunicatiagaranteaza ca datele trimise dintr-un capat ajung ın celalalt capat cu pastrareaordinii ın care au fost trimise. Acest tip de comunicatie seamana cu o convor-bire telefonica. TCP furnizeaza un canal sigur de comunicatie ıntre aplicatii.

UDP Utilizarea protocolului UDP presupune trimiterea unor pachete dedate – numite datagrame – de la o aplicatie la alta fara sa se asigure faptulca datagramele ajung la destinatie si nici ordinea lor de sosire. Acest tip decomunicatie seamana cu trimiterea scrisorilor prin posta.

23

Page 24: programare distribuita

24 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2.2 Soclu TCP

Pentru a comunica utilizand TCP programul client si programul serverstabilesc o conexiune sigura. Fiecare program se leaga la conexiune printr-unsoclu (socket). Un soclu este capatul unei cai de comunicatie bidirectionalıntre doua programe ce ruleaza ın retea. Un soclu este legat de un port – princare nivelul TCP poate identifica aplicatia careia ıi sunt transmise datele.

Pentru a comunica atat clientul cat si serverul citesc date de la si scriu datela soclul legat la conexiunea dintre ele.

In pachetul java.net clasele Socket si ServerSocket implementeaza unsoclu din partea clientului si respectiv din partea serverului.

Clientul cunoaste numele calculatorului pe care ruleaza serverul cat si por-tul la care acesta este conectat. Pentru stabilirea conexiunii, clientul ıncearcaun rendez-vous cu serverul de pe masina serverului si la portul serverului. Dacatotul decurge bine, serverul accepta conexiunea. Dupa acceptare, serverulcreaza pentru client un nou soclu legat la un alt port ın asa fel ıncat as-cultarea cererilor la soclul initial sa poata continua ın timp ce sunt satisfacutecererile clientului conectat. Din partea clientului, dupa acceptarea conexiuniisoclul este creat si este utilizat pentru comunicatia cu serverul.

Clasa java.net.Socket

Resursele clasei Socket sunt destinate clientului.

Constructori

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

IOException

Creaza un soclu conectat la calculatorul cu portul specificat.

• public Socket(InetAddress host, int port) throws IOException

Creaza un soclu conectat la calculatorul cu portul specificat.

Metode

• public InputStream getInputStream() throws IOException

Returneaza un flux de intrare atasat soclului, pentru citirea (preluarea)informatiilor de la soclu.

Page 25: programare distribuita

2.2. SOCLU TCP 25

• public OutputStream getOutputStream() throws IOException

Returneaza un flux de iesire atasat soclului, pentru scrierea (transmiterea)informatiilor la soclu.

• public synchronized void close() throws IOException

ınchide soclul de referinta.

Clasa java.net.ServerSocket

Resursele clasei ServerSocket sunt destinate serverului.Constructori

• public ServerSocket(int port) throws IOException

Creaza un soclu la portul specificat. Daca port=0, atunci va fi utilizatorice port disponibil. Capacitatea sirului (tamponului) de asteptare pen-tru cererile de conectare se fixeaza la valoarea implicita 50. Cererile ınexces vor fi refuzate.

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

In plus fixeaza lungimea sirului (tamponului) de asteptare.

Metode

• public Socket accept() throws IOException

Metoda blocheaza procesul (firul de executie) apelant pana la sosireaunei cereri de conectare si creaza un soclu client prin care se va desfasuracomunicarea cu solicitantul acceptat.

• public synchronized void close() throws IOException

ınchide soclul de referinta.

2.2.1 Aplicatie client – server cu socluri

Serverul trebuie sa satisfaca simultan solicitarile mai multor clienti. Fiecareclient apeleaza programul server la acelasi port si ın consecinta cererile deconectare sunt receptionate de acelasi ServerSocket. Serverul receptioneazaapelurile secvential. La un apel, se creaza de partea severului un soclu princare se va face schimbul de date cu clientul. Cererile clientilor pot fi satisfaceconcurent/paralel, utilizand fire de executie ce implementeaza serviciul oferitsau secvential - ın cazul unor servicii de durata scurta.

Page 26: programare distribuita

26 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.2.1 Sistem client - server pentru calculul celui mai mare divizorcomun a doua numere naturale. Portul obiectului de tip ServerSocket este7999.

Programul client CmmdcClient se conecteaza la server, transmite serveru-lui cele doua numere naturale si receptioneaza rezultatul pe care apoi ıl afiseaza.

In esenta orice program client trebuie sa execute:

1. Deschide/creaza un soclu.

2. Deschide/creaza fluxuri de date pentru comunicatia cu serverul.

3. Transmite si receptioneaza date potrivit specificului aplicatiei (proto-colului serverului). Acest pas variaza de la un program client la altul.

4. Inchiderea fluxurilor de date.

5. Inchiderea soclului.

1 import java . i o . DataInputStream ;2 import java . i o . DataOutputStream ;3 import java . net . Socket ;4 import java . u t i l . Scanner ;

6 public class CmmdcClient {7 public stat ic void main ( St r ing [ ] a rgs ) {8 St r ing host=” l o c a l h o s t ” ;9 int port =7999;

10 i f ( args . length >0)11 host=args [ 0 ] ;12 i f ( args . length >1)13 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;14 Scanner scanner=new Scanner ( System . in ) ;15 long m, n , r ;16 System . out . p r i n t l n ( ”m=” ) ;17 m=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ”n=” ) ;19 n=scanner . nextLong ( ) ;20 try ( Socket cmmdcSocket = new Socket ( host , port ) ;21 DataInputStream in=new DataInputStream ( cmmdcSocket . getInputStream ( ) ) ;22 DataOutputStream out=23 new DataOutputStream ( cmmdcSocket . getOutputStream ( ) ) ) {24 out . writeLong (m) ;25 out . writeLong (n ) ;26 r=in . readLong ( ) ;27 System . out . p r i n t l n ( ” Required r e s u l t : ”+r ) ;28 }29 catch ( Exception e ){30 System . e r r . p r i n t l n ( ” C l i en t comunication e r r o r : ”+e . getMessage ( ) ) ;31 }32 }33 }

Page 27: programare distribuita

2.2. SOCLU TCP 27

Se presupune ca programul server ruleaza pe calculatorul local si utilizeazaportul 7999. Daca acesti parametri se modifica - de exemplu serverul ruleazaın retea pe calculatorul atlantis la portul 8200 - atunci la apelare transmitemacesti parametri prin java CmmdcClient atlantis 8200

Partea server este alcatuita din mai multe clase:

• Clasa MyMServer, independenta de un serviciu anume, preia apelurileclientilor si lanseaza satisfacerea cererii.

1 import java . net . ServerSocket ;2 import java . net . Socket ;3 import java . i o . IOException ;4 import java . u t i l . concurrent . ExecutorServ ice ;5 import java . u t i l . concurrent . Executors ;

7 public class MyMServer {8 stat ic f ina l int NTHREADS=100;9 stat ic ExecutorServ i ce exec=Executors . newFixedThreadPool (NTHREADS) ;

11 public stat ic void main ( St r ing [ ] a rgs ) throws IOException {

13 int port =7999;14 boolean l i s t e n i n g=true ;15 try ( ServerSocket s e rve rSocke t=new ServerSocket ( port ) ) {16 System . out . p r i n t l n ( ”The s e r v e r i s l i s t e n i n g on port 7999” ) ;17 while ( l i s t e n i n g ){18 AppThread obj=new AppThread ( s e rve rSocke t . accept ( ) ) ;19 exec . execute ( obj ) ;20 // var ian ta21 // new AppThread ( s e r v e r S o c k e t . accept ( ) ) . s t a r t ( ) ;22 }23 }catch ( IOException e ) {24 System . e r r . p r i n t l n ( ”Could not l i s t e n on port : ”+port ) ;25 System . e r r . p r i n t l n ( e . getMessage ( ) ) ;26 System . e x i t ( 1 ) ;27 }28 }29 }

In ciclul while, la receptia unei solicitari de conexiune se creaza sise lanseaza un fir de executie a carei metoda run contine actiunile ceraspund solicitarii.

• Clasa AppTread - fir de executie responsabil de preluarea datelor si detransmitere a rezultatului.

1 import java . net . Socket ;2 import java . i o . DataInputStream ;3 import java . i o . DataOutputStream ;4 import java . i o . IOException ;

6 public class AppThread extends Thread{7 Socket socke t=null ;

Page 28: programare distribuita

28 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

9 public AppThread ( Socket socke t ){10 this . s ocke t=socket ;11 }

13 public void run ( ){14 try ( DataOutputStream out =15 new DataOutputStream ( socke t . getOutputStream ( ) ) ;16 DataInputStream in =17 new DataInputStream ( socke t . getInputStream ( ) ) ) {18 long m=0,n=0, r ;19 App app=new App ( ) ;20 m=in . readLong ( ) ;21 n=in . readLong ( ) ;22 r=app . cmmdc(m, n ) ;23 out . writeLong ( r ) ;24 socke t . c l o s e ( ) ;25 }26 catch ( IOException e ){27 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+e . getMessage ( ) ) ;28 }29 }30 }

• Clasa App corespunzatoare calcului celui mai mare divizor comul a douanumere naturale.

1 public class App{2 public long cmmdc( long m, long n ) { . . .}3 }

Rularea programelor. Se porneste la ınceput programul server MyMServeriar apoi clientul CmmdcClient. Clientul se poate rula de pe orice calculatoral retelei. Daca programul client se executa pe alt calculator decat cel pe careruleaza programul server, atunci la apelarea clientului trebuie precizat numelecalculatorului server si eventual portul utilizat.

O alta arhitectura a aplicatiei este dezvoltata ın continuare. Aceasta arhi-tectura este mai buna ın sensul ca poate fi utilizata ın alte cadre de lucru / dedezvoltare (de exemplu OSGi, Junit).

Aplicatia se va compune din:

• Aplicatia server alcatuita din:

– Interfata

1 package i s e r v e r ;2 import java . net . ServerSocket ;3 public interface IMyMServer{4 public ServerSocket ge tSe rve rSocket ( int port ) ;5 public void myAction ( ServerSocket s e rve rSocke t ) ;6 }

Page 29: programare distribuita

2.2. SOCLU TCP 29

– Implementarea interfetei

1 package s e r v e r . impl ;2 import s e r v e r . AppThread ;3 import i s e r v e r . IMyMServer ;4 import java . net . ServerSocket ;5 import java . net . Socket ;6 import java . i o . IOException ;7 import java . u t i l . concurrent . ExecutorServ ice ;8 import java . u t i l . concurrent . Executors ;

10 public class MyMServer implements IMyMServer{

12 public ServerSocket ge tSe rve rSocket ( int port ){13 ServerSocket s e rve rSocke t = null ;14 try{15 s e rve rSocke t = new ServerSocket ( port ) ;16 }17 catch ( IOException e ) {18 System . e r r . p r i n t l n ( ”Could not l i s t e n on port : ”+port ) ;19 System . e r r . p r i n t l n ( e . getMessage ( ) ) ;20 System . e x i t ( 1 ) ;21 }22 System . out . p r i n t l n ( ” ServerSocket i s ready . . . ” ) ;23 return s e rve rSocke t ;24 }

26 public void myAction ( ServerSocket s e rve rSocke t ){27 int NTHREADS=100;28 ExecutorServ i ce exec=Executors . newFixedThreadPool (NTHREADS) ;29 while ( true ){30 try{31 AppThread obj=new AppThread ( s e rve rSocke t . accept ( ) ) ;32 exec . execute ( obj ) ;33 }34 catch ( IOException e ){35 System . e r r . p r i n t l n ( ”MyActionException : ”+e . getMessage ( ) ) ;36 }37 }38 }39 }

Clasele AppThread, App sunt cele utilizate anterior.

– Clasa de lansare a serverului

1 package s e r v e r ;2 import java . net . ServerSocket ;3 import s e r v e r . impl . MyMServer ;4 import i s e r v e r . IMyMServer ;

6 public class AppServer{7 public stat ic void main ( St r ing [ ] a rgs ){8 int port =7999;9 i f ( args . length >0)

10 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;11 IMyMServer myMServer=new MyMServer ( ) ;12 ServerSocket s e rve rSocke t=myMServer . ge tSe rve rSocket ( port ) ;13 myMServer . myAction ( s e rve rSocke t ) ;14 }

Page 30: programare distribuita

30 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

15 }

• Aplicatia client este nemodificata.

2.2.2 Streaming

Prin socluri se pot transmite fluxuri de date (streaming). Modul de pro-gramare depinde de natura datelor ce trebuie vehiculate (text, sunet, grafica).

Exemplul 2.2.2 Clientul solicita serverului transmisia unui fisier text, cererecare va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe care le poatetrimite serverul.

Structura aplicatiei este:Client StreamClient.javaServer MyMServer.java

AppThread.javaClasa StreamClient

1 import java . i o . DataInputStream ;2 import java . i o . DataOutputStream ;3 import java . net . Socket ;4 import java . i o . IOException ;5 import java . i o . EOFException ;6 import java . i o . UTFDataFormatException ;7 import java . u t i l . Scanner ;

9 public class StreamClient {10 public stat ic void main ( St r ing [ ] a rgs ){11 St r ing host=” l o c a l h o s t ” ;12 int port =7999;13 System . out . p r i n t l n ( ” A l e g e t i f i s i e r u l : ” ) ;14 System . out . p r i n t l n ( ”1 : c a p i t o l . txt ” ) ;15 System . out . p r i n t l n ( ”2 : j u n i t . tex ” ) ;16 Scanner scanner=new Scanner ( System . in ) ;17 int noFi l e=scanner . next Int ( ) ;18 try ( Socket c l i e n t S o c k e t = new Socket ( host , port ) ;19 DataInputStream in =20 new DataInputStream ( c l i e n t S o c k e t . getInputStream ( ) ) ;21 DataOutputStream out =22 new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) {23 out . w r i t e I n t ( noF i l e ) ;24 System . out . p r i n t l n ( ” Received : ” ) ;25 St r ing s ;26 while ( ! ( s=in . readUTF ( ) ) . equa l s ( ” endOFfi le ” ) ) System . out . p r i n t l n ( s ) ;27 }28 catch ( IOException e ){29 System . e r r . p r i n t l n ( ” C l i en t comunication e r r o r : ”+e . getMessage ( ) ) ;30 }31 }32 }

Page 31: programare distribuita

2.2. SOCLU TCP 31

Clasa MyThread.java

1 import java . net . Socket ;2 import java . i o . DataInputStream ;3 import java . i o . DataOutputStream ;4 import java . i o . F i l e ;5 import java . i o . F i l eReader ;6 import java . i o . BufferedReader ;7 import java . i o . IOException ;

9 public class AppThread extends Thread{10 Socket socke t=null ;

12 public AppThread ( Socket socke t ){13 this . s ocke t=socket ;14 }

16 public void run ( ){17 try ( DataInputStream in = new DataInputStream ( socke t . getInputStream ( ) ) ;18 DataOutputStream out =19 new DataOutputStream ( socke t . getOutputStream ( ) ) ) {20 int noFi l e=in . r eadInt ( ) ;21 System . out . p r i n t l n ( noF i l e ) ;22 St r ing f i leName=”” ;23 i f ( noF i l e==1)24 f i leName=” c a p i t o l . txt ” ;25 else26 f i leName=” j u n i t . tex ” ;27 F i l e i n p u t F i l e=new F i l e ( f i leName ) ;28 Fi leReader f r=new Fi leReader ( i n p u t F i l e ) ;29 BufferedReader br= new BufferedReader ( f r ) ;

31 St r ing s ;32 while ( ( s=br . readLine ( ) ) != null ) out . writeUTF ( s ) ;33 out . writeUTF ( ” endOFfi le ” ) ;34 out . f l u s h ( ) ;35 br . c l o s e ( ) ;36 f r . c l o s e ( ) ;37 System . out . p r i n t l n ( ” Act i v i ty Fin i shed ! ” ) ;38 socke t . c l o s e ( ) ;39 }40 catch ( IOException e ){41 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+e . getMessage ( ) ) ;42 }43 }44 }

Exemplul 2.2.3 Clientul solicita serverului transmisia unui fisier grafic, cererecare va fi satisfacuta de server. Clientul cunoaste lista fisierelor pe care le poatetrimite serverul.

Pe aceasi structura codurile claselor suntClasa StreamClient

1 import java . i o . DataOutputStream ;2 import java . i o . InputStream ;

Page 32: programare distribuita

32 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

3 import java . awt . image . BufferedImage ;4 import java . net . Socket ;5 import java . i o . IOException ;6 import javax . imageio . ImageIO ;7 import java . awt . Image ;8 import java . u t i l . Scanner ;

10 public class StreamClient {11 public stat ic void main ( St r ing [ ] a rgs ){12 St r ing host=” l o c a l h o s t ” ;13 int port =7999;14 System . out . p r i n t l n ( ” A l e g e t i f i s i e r u l : ” ) ;15 System . out . p r i n t l n ( ”1 : xml−p i c . jpg ” ) ;16 System . out . p r i n t l n ( ”2 : brasov . jpg ” ) ;17 Scanner scanner=new Scanner ( System . in ) ;18 int noFi l e=scanner . next Int ( ) ;19 try ( Socket c l i e n t S o c k e t = new Socket ( host , port ) ;20 InputStream in=c l i e n t S o c k e t . getInputStream ( ) ;21 DataOutputStream out =22 new DataOutputStream ( c l i e n t S o c k e t . getOutputStream ( ) ) ) {23 out . w r i t e I n t ( noF i l e ) ;24 BufferedImage b i=ImageIO . read ( in ) ;25 Image image=(Image ) b i ;26 ShowImage s=new ShowImage ( image ) ;27 s . show ( ) ;28 }29 catch ( Exception e ){30 System . e r r . p r i n t l n ( ” C l i en t comunication e r r o r : ”+e . getMessage ( ) ) ;31 }32 }33 }

Clasa MyThread.java

1 import java . net . Socket ;2 import java . i o . InputStream ;3 import java . i o . OutputStream ;4 import javax . imageio . stream . FileImageOutputStream ;5 import java . i o . DataInputStream ;6 import javax . imageio . ImageIO ;7 import java . i o . IOException ;8 import java . i o . F i l e ;9 import java . awt . image . BufferedImage ;

10 import java . awt . Image ;

12 public class AppThread extends Thread{13 Socket socke t=null ;

15 public AppThread ( Socket socke t ){16 this . s ocke t=socket ;17 }

19 public void run ( ){20 try ( OutputStream out=socket . getOutputStream ( ) ;21 DataInputStream in=new DataInputStream ( socke t . getInputStream ( ) ) ) {22 int noFi l e=in . r eadInt ( ) ;23 System . out . p r i n t l n ( noF i l e ) ;

25 St r ing f i leName=”” ;

Page 33: programare distribuita

2.3. DATAGRAME 33

26 i f ( noF i l e==1)27 f i leName=”xml−p i c . jpg ” ;28 else29 f i leName=” brasov . jpg ” ;30 F i l e f i l e=new F i l e ( f i leName ) ;31 BufferedImage b i=ImageIO . read ( f i l e ) ;32 ImageIO . wr i t e ( bi , ” jpg ” , out ) ;33 out . f l u s h ( ) ;34 socke t . c l o s e ( ) ;35 }36 catch ( Exception e ){37 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+e . getMessage ( ) ) ;38 }39 }40 }

2.3 Datagrame

Pentru utilizarea datagramelor pachetul java.net pune la dispozitie clasele

• DatagramSocket

• DatagramPacket

• MulticastSocket

O aplicatie trimite si receptioneaza pachete DatagramPacket prin inter-mediul unui DatagramSocket. Un pachet DatagramPacket poate fi trimis lamai multi destinatari prin intermediul unui MulticastSocket.

Reamintim ca o datagrama este un mesaj trimis prin retea a carei sosirenu este garantata iar momentul de sosire este neprecizat.

Clasa java.net.DatagramPacket.

Trimiterea unui pachet UDP necesita crearea unui obiectDatagramPacket care contine corpul mesajului si adresa destinatiei. Apoiacest obiect DatagramPacket poate fi pus ın retea ın vederea trimiterii sale.Primirea unui pachet UDP necesita crearea unui obiect DatagramPacket siapoi acceptarea unui pachet UDP din retea. Dupa primire, se poate extragedin obiectul DatagramPacket adresa sursa si continutul mesajului.

ConstructoriExista doi constructori pentru datagrame UDP. Primul constructor este

folosit pentru primirea de pachete si necesita doar furnizarea unei memoriitampon, iar celalalt este folosit pentru trimiterea de pachete si necesita speci-ficarea adresei destinatarului.

Page 34: programare distribuita

34 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• DatagramPacket(byte[ ] buffer,int lung)

Acest contructor este folosit pentru primirea pachetelor. Un pachet sememoreaza ın tamponul buffer avand lung octeti. Daca lungimea pa-chetului depaseste aceasta lungime, atunci pachetul este trunchiat iaroctetii ın plus se pierd.

• DatagramPacket(byte[ ] buffer,int lung ,InetAddress adresa ,int

port)

Acest constructor este folosit pentru crearea unui pachet ın vederea ex-pedierii. Corpul pachetului este continut ın tamponul buffer avand lungocteti. Pachetul va fi trimis catre adresa si portul specificat. Trebuie saexiste un server UDP care asculta la portul specificat pentru trimitereapachetelor. Un server UDP poate coexista cu un server TCP care ascultaacelasi port.

Metode

• InetAddress getAddress()

returneaza adresa IP a expeditorului.

• int getPort()

returneaza portul expeditorului.

• byte[] getData()

returneaza continutul pachetului.

• int getLength()

returneaza lungimea pachetului.

• void setAddress(InetAddress adresa)

fixeaza adresa IP a pachetului.

• void setPort(int port)

fixeaza portul.

• void setData(byte[] buffer)

fixeaza continutul pachetului.

• void setLength(int lung)

fixeaza lungimea pachetului.

Page 35: programare distribuita

2.3. DATAGRAME 35

Clasa java.net.DatagramSocket

Aceasta clasa se foloseste atat pentru trimiterea, cat si pentru primireaobiectelor DatagramPacket. Un obiect DatagramSocket asculta la un portcuprins ıntre 1 si 65535 (porturile cuprinse ıntre 1 si 1023 sunt rezervate pentruaplicatiile sistem). Deoarece UDP nu este orientat pe conexiune, se va creaun singur obiect DatagramSocket pentru trimiterea pachetelor catre diferitedestinatii si primirea pachetelor de la diferite surse.

Constructori

• DatagramSocket() throws SocketException

Creaza un obiect DatagramSocket cu un numar de port aleator;

• DatagramSocket(int port) throws SocketException

Creaza un obiect DatagramSocket cu numarul de port specificat;

MetodeClasa DatagramSocket contine metode pentru trimiterea si primirea de

obiecte DatagramPacket, ınchiderea soclului, determinarea informatiilor adre-sei locale si setarea timpului de primire.

• void send(DatagramPacket pachet) throws IOException

Trimite pachetul prin retea. Daca se trimit pachete la o destinatie ne-cunoscuta sau care nu asculta, ın cele din urma se genereaza o exceptieIOException.

• void receive(DatagramPacket pachet) throws IOException

Metoda primeste un singur pachet UDP ın obiectul pachet specificat.Apoi, pachetul poate fi inspectat pentru determinarea adresei IP sursa,portul sursa si lungimea mesajului. Executia metodei este blocata panacand se primeste cu succes un pachet sau se scurge timpul de asteptare.

• InetAddress getLocalAddress()

Returneaza adresa locala catre care este legat acest DatagramSocket;

• int getLocalPort()

Returneaza numarul de port unde asculta DatagramSocket.

• void close()

Inchide DatagramSocket.

Page 36: programare distribuita

36 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• void setSoTimeout(int timpDeAsteptere) throws SocketException

Metoda fixeaza timpul de asteptare (ın milisecunde) a soclului. Metodareceive() se va bloca pentru timpul de asteptare specificat pentru prim-irea unui pachet UDP, dupa care va arunca o exceptie Interrupted

Exception. Daca valoarea parametrului este 0, atunci soclul este blo-cat.

• int getSoTimeout() throws SocketException

Returneaza timpul de asteptare.

• void setSendBufferSize(int lungime) throws SocketException

Fixeaza lungimea tamponului de trimitere a soclului la valoarea speci-ficata. Nu poate fi trimis mesaj UDP de lungime mai mare de aceastavaloare.

• int getSendBufferSize() throws SocketException

Returneaza lungimea tamponului de trimitere a soclului.

• void setReceiveBufferSize(int lungime) throws SocketException

Fixeaza lungimea tamponului de primire a soclului la valoarea specifi-cata. Nu poate fi primit un mesaj UDP de lungime mai mare de aceastavaloare.

• int getReceiveBufferSize() throws SocketException

Returneaza lungimea tamponului de primire a soclului.

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

Conecteaza soclul la adresa si portul specificat. Aceasta metoda nu esteceruta pentru operatiile uzuale UDP.

• void disconnect()

Deconecteaza soclul conectat.

• InetAddress getInetAddress()

Returneaza obiectul InetAddress catre care este conectat soclul saunull daca acesta nu este conectat.

• int getPort()

Returneaza portul la care este conectat soclul sau -1 daca acesta nu esteconectat.

Page 37: programare distribuita

2.3. DATAGRAME 37

Clasa java.net.InetAddress

Datele pot fi trimise prin retea indicand adresa IP corespunzatoare masiniidestinatie. Clasa InetAddress furnizeaza acces la adresele IP.

Nu exista constructori pentru aceasta clasa. Instantele trebuie create folosindmetodele statice:

• InetAddress getLocalHost() throws UnknownHostException

Returneaza un obiect InetAddress corespunzator masinii locale.

• InetAddress getByName(String host) throws UnknownHostException

Returneaza un obiect InetAddress corespunzator masinii host, parametrucare poate fi specificat prin nume (de exemplu ”atlantis”) sau prin adresaIP (”168.192.0.1”).

• InetAddress [ ]getAllByName(String host)throws UnknownHostException

Returneaza un sir de obiecte InetAddress corespunzator fiecarei adreseIP a masinii host.

Metodele clasei InetAddress

• byte [ ] getAddress()

Returneaza sirul de octeti corespunzator obiectului InetAddress de referinta.

• String getHostName()

Returneaza numele masinii gazda.

• String getHostAddress()

Returneaza adresa IP a masinii gazda.

• boolean isMulticastAddress()

Returneaza true daca obiectul InetAddress reprezinta o adresa IP mul-ticast (cuprins ıntre 224.0.0.0 si 239.255.255.255).

Exemplul urmator afiseaza numele si adresa calculatorului gazda cat siacela al calculatoarelor ale caror nume este transmis programului ca parametru.

Exemplul 2.3.1

Page 38: programare distribuita

38 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 import java . net . InetAddress ;2 import java . net . UnknownHostException ;

4 public class AdreseIP{5 public stat ic void main ( St r ing arg [ ] ) {6 InetAddress adresa=null ;7 try{8 adresa=InetAddress . getLocalHost ( ) ;9 System . out . p r i n t l n ( ” C a l c u l a t o r u l gazda are : ” ) ;

10 System . out . p r i n t l n ( ”numele : ”+adresa . getHostName ( ) ) ;11 System . out . p r i n t l n ( ” adresa IP : ”+adresa . getHostAddress ( ) ) ;12 }13 catch ( UnknownHostException e ){14 System . out . p r i n t l n ( ”UnknownHostException : ”+e . getMessage ( ) ) ;15 }16 i f ( arg . length >0){17 for ( int i =0; i<arg . l ength ; i ++){18 try{19 adresa=InetAddress . getByName( arg [ i ] ) ;20 System . out . p r i n t l n ( ” C a l c u l a t o r u l ”+arg [ i ]+” are : ” ) ;21 System . out . p r i n t l n ( ” adresa IP \”getByName\” : ”+adresa ) ;22 byte [ ] b=adresa . getAddress ( ) ;23 for ( int j =0; j<b . l ength ; j++)24 i f (b [ j ]<0)25 System . out . p r i n t (256+b [ j ]+” . ” ) ;26 else27 System . out . p r i n t (b [ j ]+” . ” ) ;28 System . out . p r i n t l n ( ) ;29 }30 catch ( UnknownHostException e ){31 System . out . p r i n t l n ( ”UnknownHostException : ”+32 e . getMessage ( ) ) ;33 }34 }35 }36 }37 }

2.3.1 Aplicatii client – server cu datagrame.

Un pachet de tip DatagramPacket este alcatuit dintr-un sir de octeti. Estedatoria programatorului sa transforme datele (mesajul) ın siruri de octeti laexpediere si la receptie.

Transformarea unui obiect serializabil ıntr-un sir de octeti si invers se poaterealiza cu schema

Page 39: programare distribuita

2.3. DATAGRAME 39

Object Object

ObjectOutputStream ObjectInputStream

ByteArrayOutputStream ByteArrayInputStream

output - DatagramPacket input - DatagramPacket

? 6

? 6

? 6

? 6

Fie socket un obiect de tip DatagramSocket prin intermediul caruia seexecuta expedierea / receptionarea pachetelor de tip DatagramPacket.

In principiu expedierea si transformarea obiectului obj ıntr-un sir de octetise poate realiza cu secventa de cod

ByteArrayOutputStream baos=new ByteArrayOutputStream(256);

ObjectOutputStream out=new ObjectOutputStream(baos);

out.writeObject(obj);

byte[] bout=baos.toByteArray();

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

address,port);

socket.send(packet);

unde address si port sunt adresa si portul destinatarului. Daca packet este unobiect DatagramPacket receptionat atunci metodele getAddress() si getPort()furnizeaza adresa si portul expeditorului

Receptionarea si transformarea inversa este

byte[] bin=new byte[256];

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

socket.receive(packet);

ByteArrayInputStream bais=new ByteArrayInputStream(bin);

ObjectInputStream in=new ObjectInputStream(bais);

obj=in.readObject();

Daca mesajul este un obiect String atunci el se transforma ıntr-un sir deocteti cu metoda byte[] String.getByte() si invers, el se obtine prin new

String(bin) sau new String(packet.getData()).

Exemplul 2.3.2 Programam aplicatia de calculul a celui mai mare divizorcomun a doua numere naturale.

Page 40: programare distribuita

40 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

In vederea transportului definim clasa

1 package s e r v e r ;2 import java . i o . S e r i a l i z a b l e ;

4 public class Protoco l implements S e r i a l i z a b l e {5 long x , y ;6 Protoco l ( long x , long y ){7 this . x=x ;8 this . y=y ;9 }

10 }

Clientul va trimite un obiect Protocol, care va contine datele problemei si vareceptiona un obiect de acelasi tip cu rezultatul (cel mai mare divizor comun)ın primul camp al obiectului. Aceasta clasa este disponibila atat serverului catsi clientului.

Se va utiliza arhitectura de aplicatie dezvoltata ın finalul sectiunii ante-rioare. Aplicatia se va compune din:

• Aplicatia server alcatuita din:

– Interfata

1 package i s e r v e r ;2 import java . net . DatagramSocket ;3 public interface IMyMServer{4 public DatagramSocket getDatagramSocket ( int port ) ;5 public void myAction ( DatagramSocket datagramSocket ) ;6 }

– Implementarea interfetei

1 package s e r v e r . impl ;2 import s e r v e r . App ;3 import s e r v e r . Protoco l ;4 import i s e r v e r . IMyMServer ;5 import java . net . DatagramSocket ;6 import java . net . DatagramPacket ;7 import java . net . InetAddress ;8 import java . i o . IOException ;9 import java . i o . ByteArrayInputStream ;

10 import java . i o . ByteArrayOutputStream ;11 import java . i o . ObjectInputStream ;12 import java . i o . ObjectOutputStream ;

14 public class MyMServer implements IMyMServer{

16 public DatagramSocket getDatagramSocket ( int port ){17 DatagramSocket datagramSocket = null ;18 try{19 datagramSocket = new DatagramSocket ( port ) ;20 }21 catch ( IOException e ) {22 System . e r r . p r i n t l n ( ”Could not l i s t e n on port : ”+port ) ;

Page 41: programare distribuita

2.3. DATAGRAME 41

23 System . e r r . p r i n t l n ( e . getMessage ( ) ) ;24 System . e x i t ( 1 ) ;25 }26 System . out . p r i n t l n ( ”DatagramSocket i s ready . . . ” ) ;27 return datagramSocket ;28 }

30 public void myAction ( DatagramSocket datagramSocket ){31 DatagramPacket packet=null ;32 App app=new App ( ) ;33 Protoco l p=null ;34 while ( true ){35 try{36 byte [ ] bin=new byte [ 4 0 4 8 ] ;37 packet=new DatagramPacket ( bin , bin . l ength ) ;38 datagramSocket . r e c e i v e ( packet ) ;39 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;40 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;41 p=(Protoco l ) in . readObject ( ) ;42 p . x=app . cmmdc(p . x , p . y ) ;43 p . y=0;44 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;45 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;46 out . wr i teObject (p ) ;47 byte [ ] bout=baos . toByteArray ( ) ;48 InetAddress address=packet . getAddress ( ) ;49 int port=packet . getPort ( ) ;50 packet=new DatagramPacket ( bout , bout . length , address , port ) ;51 datagramSocket . send ( packet ) ;52 }53 catch ( Exception e ){54 System . out . p r i n t l n ( e . getMessage ( ) ) ;55 }56 }57 }

59 }

– Clasa de lansare a serverului

1 package s e r v e r ;2 import java . net . DatagramSocket ;3 import s e r v e r . impl . MyMServer ;4 import i s e r v e r . IMyMServer ;

6 public class AppServer{7 public stat ic void main ( St r ing [ ] a rgs ){8 int port =7999;9 i f ( args . length >0)

10 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;11 IMyMServer myMServer=new MyMServer ( ) ;12 DatagramSocket datagramSocket=myMServer . getDatagramSocket ( port ) ;13 myMServer . myAction ( datagramSocket ) ;14 }15 }

• Aplicatia client

Page 42: programare distribuita

42 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 package c l i e n t ;2 import java . net . DatagramSocket ;3 import java . net . DatagramPacket ;4 import java . net . InetAddress ;5 import java . i o . ByteArrayInputStream ;6 import java . i o . ByteArrayOutputStream ;7 import java . i o . ObjectInputStream ;8 import java . i o . ObjectOutputStream ;9 import s e r v e r . Protoco l ;

10 import java . u t i l . Scanner ;

12 public class CmmdcClient{13 public stat ic void main ( St r ing [ ] a rgs ){14 St r ing hos tServe r=” l o c a l h o s t ” ;15 int por tSe rve r =7999;16 i f ( args . length >0)17 hos tServe r=args [ 0 ] ;18 i f ( args . length >1)19 por tSe rve r=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;20 try{21 DatagramSocket socke t=new DatagramSocket ( ) ;22 Protoco l p=new Protoco l ( 0 , 0 ) ;23 Scanner scanner=new Scanner ( System . in ) ;24 System . out . p r i n t l n ( ” I n t r o d u c e t i primul numar : ” ) ;25 p . x=scanner . nextLong ( ) ;26 System . out . p r i n t l n ( ” I n t r o d u c e t i a l d o i l e a numar : ” ) ;27 p . y=scanner . nextLong ( ) ;28 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;29 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;30 out . wr i teObject (p ) ;31 byte [ ] bout=baos . toByteArray ( ) ;32 InetAddress address=InetAddress . getByName( hos tServe r ) ;33 DatagramPacket packet =34 new DatagramPacket ( bout , bout . length , address , por tServe r ) ;35 socke t . send ( packet ) ;36 byte [ ] bin=new byte [ 4 0 4 8 ] ;37 packet=new DatagramPacket ( bin , bin . l ength ) ;38 socke t . r e c e i v e ( packet ) ;39 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;40 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;41 p=(Protoco l ) in . readObject ( ) ;42 System . out . p r i n t l n ( ”Cmmdc = ”+p . x ) ;43 socke t . c l o s e ( ) ;44 }45 catch ( Exception e ){46 System . out . p r i n t l n ( e . getMessage ( ) ) ;47 }48 }49 }

Page 43: programare distribuita

2.3. DATAGRAME 43

2.3.2 Multicast vs. Broadcast

Clasa java.net.MulticastSocket

Prin intermediul unui soclu de tip MulticastSocket se pot receptionadatagrame expediate de un server catre toti clientii cu un asemenea soclu.

Constructori

• MulticastSocket(int port) throws SocketException

Metode

• void joinGroup(InetAddress adresa) throws SocketException

Soclul se ”conecteaza” la grupul definit de adresa IP (de tip D, adicacuprins ıntre 224.0.0.0 si 239.255.255.255).

• void leaveGroup(InetAddress adresa) throws SocketException

Soclul se ”deconecteaza” la grupul definit de adresa IP.

• void close()

Pregatirea clientului ın vederea receptionarii datagramelor printr-un soclude tip MulticastSocket consta din

MulticastSocket socket= new MulticastSocket(port);

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

socket.joinGroup(adresa);

In final, clientul se deconecteaza si ınchide soclul.

socket.leaveGroup(adresa);

socket.close();

Pachetele trimise de programul server trebuie sa se adreseze grupului, iden-tificat prin adresa IP de tip D.

Astfel prin multicast serverul trimite pachete la o adresa de grup si la unport fixat. Pachetele emise de server sunt receptionate de orice client ce creazaun soclu de tip MulticastSocket pentru portul la care emite serverul si carese alatura grupului.

Prin broadcast serverul emite datagrame catre orice calculator al reteleilocale la un anumit port. Faptul ca emiterea datagramelor este de tip broadcastse indica prin

Page 44: programare distribuita

44 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

DatagramSocket.setBroadcast(true)

Orice client care ısi creaza un soclu la portul la care emite serverul receptioneazadatagramele trimise de server. Adresa utilizata de server la crearea data-gramelor trebuie sa identifice reteaua.

Observatie. In cazul unui calculator ”izolat” este nevoie de instalareadriverului Microsoft Loopback Adapter, care simuleaza existenta unei placi deretea active.

Exemplul 2.3.3 Multicast si Broadcast: programele server emit din cinciın cinci secunde ora exacta. Un client va receptiona cate cinci datagrame.

Codurile sunt date ın Fig. 2.1 si Fig. 2.2, respectiv pentru partea de serversi cea de client.

2.4 Canale de comunicatie

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

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

DatagramChannel. Informatia transportata ın aceste canale de comunicatietrebuie ınglobata ın obiecte container de tip Buffer.

Clasa java.nio.Buffer

Ierarhia claselor Buffer

abstract Buffer

ByteBuffer

ShortBuffer

IntBuffer

LongBuffer

FloatBuffer

DoubleBuffer

CharBuffer

Un obiect de tip typeBuffer este un tampon (container) care contine datede tipul specificat de denumirea clasei.

Un obiect de tip Buffer este caracterizat de

Page 45: programare distribuita

2.4. CANALE DE COMUNICATIE 45

MulticastServer BroadcastServer

import java.io.*; import java.io.*;

import java.net.*; import java.net.*;

import java.util.*; import java.util.*;

import java.text.DateFormat; import java.text.DateFormat;

public class MulticastServer{ public class BroadcastServer{

public static void main(String[] args){ public static void main(String[] args){

long FIVE_SECONDS = 5000; long FIVE_SECONDS = 5000;

boolean sfarsit=false; boolean sfarsit=false;

int serverPort=7000; int serverPort=7000;

int clientPort=7001; int clientPort=7001;

byte[] buf = new byte[256]; byte[] buf = new byte[256];

Date data=null; Date data = null;

DatagramPacket packet = null; DatagramPacket packet = null;

try(DatagramSocket socket= try(DatagramSocket socket=

=new DatagramSocket(serverPort)){ new DatagramSocket(serverPort)){

while (! sfarsit){ while (! sfarsit) {

data=new Date(); data=new Date();

String df=DateFormat. String df=DateFormat.

getTimeInstance().format(data); getTimeInstance().format(data);

buf = df.getBytes(); buf = df.getBytes();

// send it

InetAddress group = InetAddress group =

InetAddress.getByName("230.0.0.1"); InetAddress.getByName("192.168.0.255");

packet=new DatagramPacket(buf, packet=new DatagramPacket(buf,

buf.length,group,clientPort); buf.length,group,clientPort);

socket.setBroadcast(true);

socket.send(packet); socket.send(packet);

// sleep for a while

Thread.sleep(FIVE_SECONDS); Thread.sleep(FIVE_SECONDS);

} }

} }

catch (Exception e) { catch (Exception e) {

System.out.println(e.getMessage()); System.out.println(e.getMessage());

} }

} }

} }

Table 2.1: Clasele server.

Page 46: programare distribuita

46 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

MulticastClient BroadcastClient

import java.io.*; import java.io.*;

import java.net.*; import java.net.*;

public class MulticastClient { public class BroadcastClient {

public static void main(String[] args) public static void main(String[] args)

throws IOException { throws IOException {

DatagramPacket packet; DatagramPacket packet;

byte[] buf = new byte[256]; byte[] buf = new byte[256];

int clientPort=7001; int clientPort=7001;

MulticastSocket socket= DatagramSocket socket=

new MulticastSocket(clientPort); new DatagramSocket(clientPort);

InetAddress address=

InetAddress.getByName("230.0.0.1");

socket.joinGroup(address);

int i=-1; int i=-1;

do{ do{

i++; i++;

packet=new DatagramPacket(buf, buf.length); packet=new DatagramPacket(buf, buf.length);

socket.receive(packet); socket.receive(packet);

String received=new String(packet.getData()); String received=new String(packet.getData());

System.out.println("Am primit: "+received); System.out.println("Am primit: "+received);

} }

while(i<5); while(i<5);

socket.leaveGroup(address);

socket.close(); socket.close();

} }

} }

Table 2.2: Clasele client.

Page 47: programare distribuita

2.4. CANALE DE COMUNICATIE 47

• capacitate (capacity) numarul elementelor care pot fi ınmagazitate ıntampon;

• limita (limit) marginea superiora a indicelui;

• indice (position) valoarea curenta a indicelui, ce corespunde unui cursorce indica ınceputul zonei unde se introduc sau de unde se extrag datedin tampon.

Metode generale

• clear() permite unui obiect de tip Buffer sa fie reıncarcat. Fixeazalimita = capacitate si indice = 0.

• flip() pregateste obiectul de tip Buffer pentru consultare (citire). Fix-eaza limita =numarul elementelor din tampon si indice = 0.

• rewind() pregateste obiectul de tip Buffer pentru re-citire.

• remaining() returneaza numaul octetilor cuprinsi ıntre valoarea indiceluisi limita.

Clasa java.nio.ByteBuffer

Instantierea unui obiect se obtine prin metoda statica

static ByteBuffer allocate(capacitate)

Introducerea si extragerea datelor din tampon se poate face ın mod

• relativ - implica modificarea indicelui tamponului;

• absolut - fara modificarea indicelui.

MetodeIntroducerea datelor ın mod relativ:

• ByteBuffer put(byte b)

• ByteBuffer putTip(tip x)

Extragerea datelor ın mod relativ:

• byte get()

Page 48: programare distribuita

48 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

• tip getTip()

Introducerea datelor ın mod absolut:

• ByteBuffer put(int index,byte b)

• ByteBuffer putTip(int index,tip x)

Extragerea datelor ın mod absolut:

• byte get(int index)

• tip getTip(int index)

unde tip poate fi char, short, int, long, float, double.

Alte metode

• public final boolean hasRemaining()

Daca indicele nu este egal cu limita atunci returneaza true, semnalandexistenta ın tampon a unor octeti.

• static ByteBuffer wrap(byte[] array)

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

Converteste sirul de octeti ıntr-un obiect ByteBuffer.

• public final byte[] array()

Transformarea inversa, obiectul ByteBuffer este convertit ıntr-un sir deocteti.

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

DoubleBuffer, etc prin

ByteBuffer bb=ByteBuffer.allocate(10);

LongBuffer lb=bb.asLongBuffer();

DoubleBuffer db=bb.asDoubleBuffer();

Page 49: programare distribuita

2.4. CANALE DE COMUNICATIE 49

Clasa java.net.InetSocketAddress

Clasa InetSocketAddress extinde clasa SocketAddress si ıncapsuleazaadresa unui calculator din Internet ımpreuna cu un port ın vederea legarii laun ServerSocket.

Constructori:

• InetSocketAddress(InetAddress addr,int port)

• InetSocketAddress(String numeCalculator,int port)

• InetSocketAddress(int port)

Clasa java.nio.channels.ServerSocketChannel

Crearea unui obiect de tip ServerSocketChannel se realizeaza prin

static ServerSocketChannel open() throws IOException

Unui asemenea obiect i se asociaza un ServerSocket prin metoda

ServerSocket socket() throws IOException.

Obiectul de tip ServerSocket trebuie leagat la un port de comunicatie prinmetoda

void bind(InetSocketAddress endpoint) throws IOException.

Sablonul de utilizare este

try{

ServerSocketChannel ssc=ServerSocketChannel.open();

ServerSocket ss=ssc.socket();

InetSocketAddress isa=new InetSocketAddress(addr,port);

ss.bind(isa);

}

catch(Exception e){. . .}

La apelul unui client, serverul trebuie sa genereze un obiect de tip Socket

Channel prin care se vor derula comunicatiile cu clientul. Acest canal decomunicatie se obtine cu metoda accept().

Page 50: programare distribuita

50 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa java.nio.channels.SocketChannel

Crearea unui obiect de tip SocketChannel se realizeaza prin

static SocketChannel open() throws IOException

Acest obiect trebuie conectat la obiectul ServerSocketChannel al serveruluicu metoda connect(InetSocketAddress addr).

Datele vehiculate printr-un SocketChannel sunt de tip ByteBuffer. Datelese transmit prin metoda

int write(ByteBuffer sursa)

si se receptioneaza prin metoda

int read(ByteBuffer destinatie)

Valoarea returnata de cele doua metode reprezinta numarul octetilor trimisi/ receptionati.

Doar octetii unui obiect de tip ByteBuffer cuprinsi ıntre indice si limitasunt transmisi prin canal. Astfel, dupa ıncarcarea unui obiectului ByteBuffercu metode relative trebuie apelata metoda flip().

Canalul se ınchide cu metoda close().

Exemplul 2.4.1 Calculul celui mai mare divizor comun a doua numere nat-urale.

Aplicatie client-server bazat pe canale de comunicatie prin socluri se com-pune din:

• Aplicatia server alcatuita din:

– Interfata

1 package i s e r v e r ;2 import java . n io . channe l s . ServerSocketChannel ;3 public interface IMyMServer{4 public ServerSocketChannel getServerSocketChannel ( int port ) ;5 public void myAction ( ServerSocketChannel serverSocketChanne l ) ;6 }

– Implementarea interfetei

Page 51: programare distribuita

2.4. CANALE DE COMUNICATIE 51

1 package s e r v e r . impl ;2 import s e r v e r . AppThread ;3 import i s e r v e r . IMyMServer ;4 import java . net . InetSocketAddress ;5 import java . net . ServerSocket ;6 import java . n io . channe l s . ServerSocketChannel ;7 import java . u t i l . concurrent . ExecutorServ ice ;8 import java . u t i l . concurrent . Executors ;9 import java . i o . IOException ;

11 public class MyMServer implements IMyMServer{

13 public ServerSocketChannel getServerSocketChannel ( int port ){14 ServerSocketChannel serverSocketChanne l=null ;15 try{16 serverSocketChanne l = ServerSocketChannel . open ( ) ;17 InetSocketAddress i s a=new InetSocketAddress ( port ) ;18 ServerSocket s s=serverSocketChanne l . socke t ( ) ;19 s s . bind ( i s a ) ;20 }21 catch ( IOException e ){22 System . out . p r i n t l n ( ” ServerSocketChannelError : ”+23 e . getMessage ( ) ) ;24 System . e x i t ( 0 ) ;25 }26 System . out . p r i n t l n ( ” Server ready . . . ” ) ;27 return serverSocketChanne l ;28 }

30 public void myAction ( ServerSocketChannel serverSocketChanne l ){31 int NTHREADS=100;32 ExecutorServ i ce exec=Executors . newFixedThreadPool (NTHREADS) ;33 while ( true ){34 try{35 AppThread obj=new AppThread ( serverSocketChanne l . accept ( ) ) ;36 exec . execute ( obj ) ;37 }38 catch ( IOException e ){39 System . e r r . p r i n t l n ( ”MyActionException : ”+e . getMessage ( ) ) ;40 }41 }42 }43 }

– Clasa AppThread

1 package s e r v e r ;2 import java . i o . IOException ;3 import java . n io . channe l s . SocketChannel ;4 import java . n io . ByteBuffer ;

6 public class AppThread extends Thread{7 SocketChannel socketChannel=null ;

9 public AppThread ( SocketChannel socketChannel ){10 this . socketChannel=socketChannel ;11 }

Page 52: programare distribuita

52 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

13 public void run ( ){14 try{15 ByteBuf fer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;16 // LongBuffer l b = bb . asLongBuffer ( ) ;17 socketChannel . read (bb ) ;18 // Varianta 119 long m=bb . getLong ( 0 ) ;20 long n=bb . getLong ( 8 ) ;21 // Varianta 222 // long m=l b . g e t ( 0 ) ;23 // long n=l b . g e t ( 1 ) ;24 App app=new App ( ) ;25 long r=app . cmmdc(m, n ) ;26 bb . c l e a r ( ) ;27 // Varianta 128 bb . putLong (0 , r ) ;29 // Varianta 230 // l b . put ( r ) ;31 socketChannel . wr i t e (bb ) ;32 socketChannel . c l o s e ( ) ;33 }34 catch ( IOException e ){35 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+36 e . getMessage ( ) ) ;37 }38 }39 }

– Clasa de lansare a serverului

1 package s e r v e r ;2 import java . n io . channe l s . ServerSocketChannel ;3 import s e r v e r . impl . MyMServer ;4 import i s e r v e r . IMyMServer ;

6 public class AppServer{7 public stat ic void main ( St r ing [ ] a rgs ){8 int port =7999;9 i f ( args . length >0)

10 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;11 IMyMServer myMServer=new MyMServer ( ) ;12 ServerSocketChannel serverSocketChanne l =13 myMServer . getServerSocketChannel ( port ) ;14 myMServer . myAction ( serverSocketChanne l ) ;15 }16 }

• Aplicatia client

1 package c l i e n t ;2 import java . net . UnknownHostException ;3 import java . net . InetSocketAddress ;4 import java . n io . channe l s . SocketChannel ;5 import java . n io . ByteBuffer ;6 import java . u t i l . Scanner ;7 import java . i o . IOException ;

9 public class CmmdcClient {

Page 53: programare distribuita

2.4. CANALE DE COMUNICATIE 53

10 public stat ic void main ( St r ing [ ] a rgs ) {11 St r ing host=” l o c a l h o s t ” ;12 int port =7999;13 i f ( args . length >0)14 host=args [ 0 ] ;15 i f ( args . length >1)16 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;17 SocketChannel sc=null ;18 try{19 InetSocketAddress i s a=new InetSocketAddress ( host , port ) ;20 sc=SocketChannel . open ( ) ;21 sc . connect ( i s a ) ;22 }23 catch ( UnknownHostException e ) {24 System . e r r . p r i n t l n ( ” Server necunoscut : ”+host+” ”+e . getMessage ( ) ) ;25 System . e x i t ( 1 ) ;26 }27 catch ( IOException e ) {28 System . e r r . p r i n t l n ( ” Conectare i m p o s i b i l a l a : ”+29 host+” pe por tu l ”+port+” ”+e . getMessage ( ) ) ;30 System . e x i t ( 1 ) ;31 }32 Scanner scanner=new Scanner ( System . in ) ;33 long m, n , r ;34 System . out . p r i n t l n ( ”m=” ) ;35 m=scanner . nextLong ( ) ;36 System . out . p r i n t l n ( ”n=” ) ;37 n=scanner . nextLong ( ) ;

39 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;40 // Varianta 141 bb . putLong (0 ,m) . putLong (8 , n ) ;42 // Varianta 243 // LongBuffer l b=bb . asLongBuffer ( ) ;44 // l b . put (0 ,m) . put (1 ,n ) ;45 try{46 sc . wr i t e (bb ) ;47 bb . c l e a r ( ) ;48 sc . read (bb ) ;49 // Varianta 150 r=bb . getLong ( 0 ) ;51 // Varianta 252 // r=l b . g e t ( 0 ) ;53 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;54 sc . c l o s e ( ) ;55 }56 catch ( Exception e ){57 System . e r r . p r i n t l n ( ” Eroare de comunicat ie ”+e . getMessage ( ) ) ;58 }59 }60 }

Varianta comentata corespunde cazului ın care se utilizeara clasa acoperitoareLongBuffer.

Alternativ, se poate lucra cu obiecte. Pentru exemplul dat, utilizand clasaProtocol, introdusa ın sectiunea dedicata datagramelor, codul privind trim-iterea ti receptia datelor din clasele AppThread si CmmdcClient va fi

Page 54: programare distribuita

54 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

1 . . .2 ByteBuffer bb = ByteBuffer . a l l o c a t e ( 1 0 2 4 ) ;3 socketChannel . read (bb ) ;4 byte [ ] bin=bb . array ( ) ;5 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;6 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;7 Protoco l p=(Protoco l ) in . readObject ( ) ;8 App app=new App ( ) ;9 p . x=app . cmmdc(p . x , p . y ) ;

10 p . y=0;11 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;12 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;13 out . wr i teObject (p ) ;14 byte [ ] bout=baos . toByteArray ( ) ;15 bb=ByteBuffer . wrap ( bout ) ;16 socketChannel . wr i t e (bb ) ;17 socketChannel . c l o s e ( ) ;18 . . .

si, respectiv,

1 . . .2 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 2 0 4 8 ) ;3 Protoco l p=new Protoco l (m, n ) ;4 try{5 ByteArrayOutputStream baos=new ByteArrayOutputStream ( 2 5 6 ) ;6 ObjectOutputStream out=new ObjectOutputStream ( baos ) ;7 out . wr i teObject (p ) ;8 byte [ ] bout=baos . toByteArray ( ) ;9 bb=ByteBuffer . wrap ( bout ) ;

10 sc . wr i t e (bb ) ;11 bb . c l e a r ( ) ;12 sc . read (bb ) ;13 byte [ ] bin=bb . array ( ) ;14 ByteArrayInputStream ba i s=new ByteArrayInputStream ( bin ) ;15 ObjectInputStream in=new ObjectInputStream ( ba i s ) ;16 p=(Protoco l ) in . readObject ( ) ;17 System . out . p r i n t l n ( ”Cmmdc : ”+p . x ) ;18 sc . c l o s e ( ) ;19 . . .

Clasa java.nio.channels.DatagramChannel

Sablonul de programare pentru instantierea unui obiect de tip DatagramChannel

este

DatagramChannel dc=null;

InetSocketAddress isa=new InetSocketAddress(port);

try{

dc=DatagramChannel.open();

DatagramSocket datagramSocket=dc.socket();

datagramSocket.bind(isa);

Page 55: programare distribuita

2.4. CANALE DE COMUNICATIE 55

}

catch(Exception e){. . .}

unde port este portul folosit de DatagramChannel. Daca port=0 atunci sealege aleator un port disponibil.

Transmiterea unui obiect ByteBuffer se face cu metoda

public int send(ByteBuffer src, SocketAddress target) throws

IOException

Metoda returneaza numarul de octeti expediati. Receptia unui ByteBuffer seobtine cu metoda

public SocketAddress receive(ByteBuffer dst) throws IOException

Obiectul returnat reprezinta adresa expeditorului.

Exemplul 2.4.2 Calculul celui mai mare divizor comun a doua numere nat-urale.

• Aplicatia server este alcatuita din:

– Interfata

1 package i s e r v e r ;2 import java . n io . channe l s . DatagramChannel ;3 public interface IMyMServer{4 public DatagramChannel getDatagramChannel ( int port ) ;5 public void myAction ( DatagramChannel datagramChannel ) ;6 }

– Implementarea interfetei

1 package s e r v e r . impl ;2 import s e r v e r . App ;3 import i s e r v e r . IMyMServer ;4 import java . net . DatagramSocket ;5 import java . net . InetSocketAddress ;6 import java . net . SocketAddress ;7 import java . n io . channe l s . DatagramChannel ;8 import java . n io . ByteBuffer ;9 import java . i o . IOException ;

11 public class MyMServer implements IMyMServer{

13 public DatagramChannel getDatagramChannel ( int port ){14 DatagramChannel datagramChannel=null ;15 InetSocketAddress i s a=new InetSocketAddress ( port ) ;16 try{17 datagramChannel = DatagramChannel . open ( ) ;18 DatagramSocket datagramSocket=datagramChannel . socke t ( ) ;19 datagramSocket . bind ( i s a ) ;

Page 56: programare distribuita

56 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

20 }21 catch ( IOException e ){22 System . out . p r i n t l n ( ”DatagramChannelError : ”+e . getMessage ( ) ) ;23 System . e x i t ( 0 ) ;24 }25 System . out . p r i n t l n ( ” Server ready . . . ” ) ;26 return datagramChannel ;27 }

29 public void myAction ( DatagramChannel datagramChannel ){30 int NTHREADS=100;31 while ( true ){32 App app=new App ( ) ;33 try{34 ByteBuf fer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;35 // LongBuffer l b = bb . asLongBuffer ( ) ;36 SocketAddress sa=datagramChannel . r e c e i v e (bb ) ;37 // Varianta 138 long m=bb . getLong ( 0 ) ;39 long n=bb . getLong ( 8 ) ;40 // Varianta 241 // long m=l b . g e t ( 0 ) ;42 // long n=l b . g e t ( 1 ) ;43 long r=app . cmmdc(m, n ) ;44 bb . c l e a r ( ) ;45 // Varianta 146 bb . putLong (0 , r ) ;47 // Varianta 248 // l b . put ( r ) ;49 datagramChannel . send (bb , sa ) ;50 }51 catch ( IOException e ){52 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+53 e . getMessage ( ) ) ;54 }55 }56 }57 }

– Clasa de lansare a serverului

1 package s e r v e r ;2 import java . n io . channe l s . DatagramChannel ;3 import s e r v e r . impl . MyMServer ;4 import i s e r v e r . IMyMServer ;

6 public class AppServer{7 public stat ic void main ( St r ing [ ] a rgs ){8 int port =7999;9 i f ( args . length >0)

10 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;11 IMyMServer myMServer=new MyMServer ( ) ;12 DatagramChannel datagramChannel =13 myMServer . getDatagramChannel ( port ) ;14 myMServer . myAction ( datagramChannel ) ;15 }16 }

Page 57: programare distribuita

2.4. CANALE DE COMUNICATIE 57

• Aplicatia client

1 package c l i e n t ;2 import java . net . UnknownHostException ;3 import java . net . InetSocketAddress ;4 import java . net . InetAddress ;5 import java . net . DatagramSocket ;6 import java . n io . channe l s . DatagramChannel ;7 import java . n io . ByteBuffer ;8 import java . u t i l . Scanner ;9 import java . i o . IOException ;

11 public class CmmdcClient {12 public stat ic void main ( St r ing [ ] a rgs ) throws IOException {13 St r ing se rverHost=” l o c a l h o s t ” ;14 int port =7999;15 i f ( args . length >0)16 se rverHost=args [ 0 ] ;17 i f ( args . length >1)18 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;19 InetSocketAddress s e r v e r=null , i s a=null ;20 try{21 s e r v e r=22 new InetSocketAddress ( InetAddress . getByName( se rverHost ) , port ) ;23 }24 catch ( UnknownHostException e ){25 System . out . p r i n t l n ( ”Unknown host : ”+e . getMessage ( ) ) ;26 System . e x i t ( 1 ) ;27 }28 i s a=new InetSocketAddress ( 0 ) ;29 DatagramChannel dc=null ;30 try {31 dc=DatagramChannel . open ( ) ;32 DatagramSocket socke t = dc . socket ( ) ;33 socke t . bind ( i s a ) ;34 }35 catch ( IOException e ) {36 System . e r r . p r i n t l n ( ”Couldn ’ t open the DatagramChannel ”+37 e . getMessage ( ) ) ;38 System . e x i t ( 1 ) ;39 }40 long m, n , r ;41 Scanner scanner=new Scanner ( System . in ) ;42 System . out . p r i n t l n ( ”m=” ) ;43 m=scanner . nextLong ( ) ;44 System . out . p r i n t l n ( ”n=” ) ;45 n=scanner . nextLong ( ) ;46 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;47 // Varianta 148 bb . putLong (0 ,m) . putLong (8 , n ) ;49 // Varianta 250 // LongBuffer l b=bb . asLongBuffer ( ) ;51 // l b . put (0 ,m) . put (1 ,n ) ;52 try{53 dc . send (bb , s e r v e r ) ;54 bb . c l e a r ( ) ;55 dc . r e c e i v e (bb ) ;56 // Varianta 157 r=bb . getLong ( 0 ) ;58 // Varianta 2

Page 58: programare distribuita

58 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

59 // r=l b . g e t ( 0 ) ;60 System . out . p r i n t l n ( ”Cmmdc = ”+r ) ;61 }62 catch ( Exception e ){63 System . e r r . p r i n t l n ( ” C l i en t e r r o r : ”+e . getMessage ( ) ) ;64 }65 f ina l ly {66 i f ( dc !=null ) dc . d i s connec t ( ) ;67 }68 }69 }

2.5 Receptie cu Selector

Programarea receptiei cererilor clientilor fara utilizarea firelor de executiese poate face utilizand clasele

• java.nio.channel.Selector

Gestioneaza obiectele SocketChannel ınregistrate si transmite cererilecare trebuie satisfacute.

• java.nio.channel.SelectionKey

Obiect utilizat de selector pentru sortarea cererilor. O cheie identificaun client si tipul cererii.

Figura 2.1 prezinta structura unei aplicatii. 1

Clasa java.nio.channel.Selector

Metode

• public static Selector open() throws IOException

Instatiaza un obiect de tip Selector.

• public Set<SelectionKey> selectedKeys()

Returneaza cheile inregistrate de selector.

• public int select() throws IOException

Metoda blocanta pana la selectarea unui canal.

1Imaginea este preluata din Naccarato G., Introducing Nonblocking Sockets,http://www.onjava.com, 2002.

Page 59: programare distribuita

2.5. RECEPTIE CU SELECTOR 59

Figure 2.1: Structura unei aplicatii.

Inregistrarea selectorului se face de catre obiectiul SocketChannel sauServerSocketChannel prin metodapublic final SelectionKey register(Selector selector, int ops) throws

ClosedChannelException

Operatiile pot fiSelectionKey.OP CONNECT

SelectionKey.OP ACCEPT

SelectionKey.OP READ

SelectionKey.OP WRITE

Canalul se configureaza pe modul ne-blocant princonfigureBlocking(false) throws IOException

Clasa java.nio.channel.SelectionKey

Metode

• public final boolean isConnectable()

• public final boolean isReadable()

• public final boolean isWritable()

• public final boolean isAcceptable()

• public void cancel()

Page 60: programare distribuita

60 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Exemplul 2.5.1 Aplicatia server pentru aplicatia de calcul a celui mai maredivizor comun.

Aplicatia server va fi formata de clasele AppServer si App, cea utilizata ınacest capitol.

1 package s e r v e r ;2 import java . n io . channe l s . ServerSocketChannel ;3 import java . n io . channe l s . SocketChannel ;4 import java . n io . channe l s . Se lect ionKey ;5 import java . n io . channe l s . S e l e c t o r ;6 import java . net . InetSocketAddress ;7 import java . net . ServerSocket ;8 import java . n io . ByteBuffer ;9 import java . u t i l . I t e r a t o r ;

10 import java . u t i l . Set ;11 import java . i o . IOException ;

13 public class AppServer{14 public stat ic void main ( St r ing [ ] a rgs ){15 int port =7999;16 i f ( args . length >0)17 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;

19 ServerSocketChannel serverSocketChanne l=null ;20 try{21 serverSocketChanne l = ServerSocketChannel . open ( ) ;22 InetSocketAddress i s a=new InetSocketAddress ( port ) ;23 ServerSocket s s=serverSocketChanne l . socke t ( ) ;24 s s . bind ( i s a ) ;25 serverSocketChanne l . c on f i gu r eB lock ing ( fa l se ) ;26 System . out . p r i n t l n ( ” Server ready . . . ” ) ;

28 S e l e c t o r s e l e c t o r = S e l e c t o r . open ( ) ;29 Se lect ionKey se rve rkey =30 serverSocketChanne l . r e g i s t e r ( s e l e c t o r , Se lect ionKey .OP ACCEPT) ;31 ByteBuffer b u f f e r = ByteBuffer . a l l o c a t e ( 1 6 ) ;32 while ( true ){33 s e l e c t o r . s e l e c t ( ) ;34 Set< Select ionKey> keys = s e l e c t o r . s e l e c t edKeys ( ) ;35 for ( I t e r a t o r i = keys . i t e r a t o r ( ) ; i . hasNext ( ) ; ) {36 Se lect ionKey key = ( Se lect ionKey ) i . next ( ) ;37 i . remove ( ) ;38 i f ( key == serve rkey ) {39 i f ( key . i sAcceptab l e ( ) ){40 SocketChannel c l i e n t = serverSocketChanne l . accept ( ) ;41 c l i e n t . c on f i gu r eB lock ing ( fa l se ) ;42 Se lect ionKey c l i e n t k e y = c l i e n t . r e g i s t e r ( s e l e c t o r ,43 Se lect ionKey .OP READ) ;44 }45 }46 else {47 i f ( key . i sReadable ( ) ){48 SocketChannel c l i e n t = ( SocketChannel ) key . channel ( ) ;49 int bytesread = c l i e n t . read ( b u f f e r ) ;50 long m=b u f f e r . getLong ( 0 ) ;51 long n=b u f f e r . getLong ( 8 ) ;52 App app=new App ( ) ;

Page 61: programare distribuita

2.6. COMUNICATII ASINCRONE PRIN CANALE 61

53 long r=app . cmmdc(m, n ) ;54 b u f f e r . c l e a r ( ) ;55 b u f f e r . putLong (0 , r ) ;56 c l i e n t . wr i t e ( b u f f e r ) ;57 b u f f e r . c l e a r ( ) ;58 c l i e n t . c l o s e ( ) ;59 key . cance l ( ) ;60 }61 }62 }63 }64 }65 catch ( Exception e ){66 System . e r r . p r i n t l n ( ” BufferOpException : ”+e . getMessage ( ) ) ;67 }68 }69 }

Aplicatia client nu sufera nici o modificare.

2.6 Comunicatii asincrone prin canale

Utilizarea canalelor asincrone, introduse ın Java 7, face apel la metodeneblocante.

Astfel sunt introduse clasele:

• java.nio.channels.AsynchronousServerSocketChannel sijava.nio.channels.AsynchronousSocketChannel.

Tehnicile de programare utilizate se bazeaza pe utilizarea claselor:

• java.util.concurrent.Future

Interfata Future<V>

Metode

• V get()

• boolean isDone()

Valoarea true rezulta daca s-a obtinut / generat obiectul de tip V.

Un obiect de tip V care rezulta ın urma apelarii metodei cu semnaturaFuture<V> metoda(. . . )

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

Page 62: programare distribuita

62 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

Clasa AsynchronousServerSocketChannel

Un obiect de tip AsynchronousServerSocketChannel se obtine cu metodastatica open().Metode

• static AsynchronousServerSocketChannel open() throws IOException

• AsynchronousServerSocketChannel bind(SocketAddress addr)

Se precizeaza portul la care se leaga canalul asincron. Clasa InetSocketAddresseste extinde clasa SocketAddress.

• public Future<AsynchronousSocketChannel> accept()

Metoda neblocanta genereaza un soclu prin care se realizeaza conexiuneadin partea serverului cu un client.

Clasa AsynchronousSocketChannel

Metodei

• public static AsynchronousSocketChannel open() throws IOException

• public abstract Future<Void> connect(SocketAddress remote)

• public Future<Integer> read(ByteBuffer dst)

Metoda returneaza numarul octetilor ıncarcati ın dst.

• public Future<Integer> write(ByteBuffer src)

Metoda returneaza numarul octetilor expediati din src.

Exemplul 2.6.1

Utilizam modelul aplicatiei dezvoltata pe baza clasei ServerSocketChannel:

1. IMyMServer.java

1 package i s e r v e r ;2 import java . n io . channe l s . AsynchronousServerSocketChannel ;3 public interface IMyMServer{4 public AsynchronousServerSocketChannel5 getAsynchronousServerSocketChannel ( int port ) ;6 public void myAction ( AsynchronousServerSocketChannel7 asynchronousServerSocketChannel ) ;8 }

Page 63: programare distribuita

2.6. COMUNICATII ASINCRONE PRIN CANALE 63

2. MyMServer.java

1 package s e r v e r . impl ;2 import s e r v e r . AppThread ;3 import i s e r v e r . IMyMServer ;4 import java . net . InetSocketAddress ;5 import java . n io . channe l s . AsynchronousServerSocketChannel ;6 import java . n io . channe l s . AsynchronousSocketChannel ;7 import java . u t i l . concurrent . ExecutorServ ice ;8 import java . u t i l . concurrent . Executors ;9 import java . i o . IOException ;

10 import java . u t i l . concurrent . Future ;

12 public class MyMServer implements IMyMServer{

14 public AsynchronousServerSocketChannel15 getAsynchronousServerSocketChannel ( int port ){16 AsynchronousServerSocketChannel asynchronousServerSocketChannel=null ;17 try{18 asynchronousServerSocketChannel =19 AsynchronousServerSocketChannel . open ( ) ;20 InetSocketAddress i s a=new InetSocketAddress ( port ) ;21 asynchronousServerSocketChannel . bind ( i s a ) ;22 }23 catch ( IOException e ){24 System . out . p r i n t l n ( ” AsynchronousServerSocketChannelError : ”+25 e . getMessage ( ) ) ;26 System . e x i t ( 0 ) ;27 }28 System . out . p r i n t l n ( ” Server ready . . . ” ) ;29 return asynchronousServerSocketChannel ;30 }

32 public void myAction ( AsynchronousServerSocketChannel33 asynchronousServerSocketChannel ){34 int NTHREADS=100;35 ExecutorServ i ce exec=Executors . newFixedThreadPool (NTHREADS) ;36 while ( true ){37 try{38 Future<AsynchronousSocketChannel> f u tu r e =39 asynchronousServerSocketChannel . accept ( ) ;40 while ( ! f u tu r e . isDone ( ) ) ;41 AppThread obj=new AppThread ( fu tu r e . get ( ) ) ;42 exec . execute ( obj ) ;43 }44 catch ( Exception e ){45 System . e r r . p r i n t l n ( ”MyActionException : ”+e . getMessage ( ) ) ;46 }47 }48 }49 }

3. AppThread.java

1 package s e r v e r ;2 import java . n io . channe l s . AsynchronousSocketChannel ;3 import java . n io . ByteBuffer ;4 import java . u t i l . concurrent . Future ;

Page 64: programare distribuita

64 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

6 public class AppThread extends Thread{7 private AsynchronousSocketChannel asc=null ;

9 public AppThread ( AsynchronousSocketChannel asc ){10 this . asc=asc ;11 }

13 public void run ( ){14 try{15 ByteBuffer bb = ByteBuffer . a l l o c a t e ( 1 6 ) ;16 Future<Integer> f r=asc . read (bb ) ;17 while ( ! f r . isDone ( ) ) ;18 long m=bb . getLong ( 0 ) ;19 long n=bb . getLong ( 8 ) ;20 App app=new App ( ) ;21 System . out . p r i n t l n (m+” <−> ”+n ) ;22 long r=app . cmmdc(m, n ) ;23 bb . c l e a r ( ) ;24 bb . putLong (0 , r ) ;25 Future<Integer> fw=asc . wr i t e (bb ) ;26 while ( ! fw . isDone ( ) ) ;27 asc . c l o s e ( ) ;28 }29 catch ( Exception e ){30 System . e r r . p r i n t l n ( ” Server comunication e r r o r : ”+e . getMessage ( ) ) ;31 }32 }33 }

4. AppServer.java

1 package s e r v e r ;2 import java . n io . channe l s . AsynchronousServerSocketChannel ;3 import s e r v e r . impl . MyMServer ;4 import i s e r v e r . IMyMServer ;

6 public class AppServer{7 public stat ic void main ( St r ing [ ] a rgs ){8 int port =7999;9 i f ( args . length >0)

10 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;11 IMyMServer myMServer=new MyMServer ( ) ;12 AsynchronousServerSocketChannel asynchronousServerSocketChannel =13 myMServer . getAsynchronousServerSocketChannel ( port ) ;14 myMServer . myAction ( asynchronousServerSocketChannel ) ;15 }16 }

5. CmmdcClient.java

1 package c l i e n t ;2 import java . net . UnknownHostException ;3 import java . net . InetSocketAddress ;4 import java . n io . channe l s . AsynchronousSocketChannel ;5 import java . n io . ByteBuffer ;6 import java . u t i l . Scanner ;7 import java . i o . IOException ;

Page 65: programare distribuita

2.6. COMUNICATII ASINCRONE PRIN CANALE 65

8 import java . u t i l . concurrent . Future ;

10 public class CmmdcClient {11 public stat ic void main ( St r ing [ ] a rgs ) {12 St r ing host=” l o c a l h o s t ” ;13 int port =7999;14 i f ( args . length >0)15 host=args [ 0 ] ;16 i f ( args . length >1)17 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;18 AsynchronousSocketChannel asc=null ;19 try{20 InetSocketAddress i s a=new InetSocketAddress ( host , port ) ;21 asc=AsynchronousSocketChannel . open ( ) ;22 asc . connect ( i s a ) ;23 }24 catch ( UnknownHostException e ) {25 System . e r r . p r i n t l n ( ” Server necunoscut : ”+host+” ”+e . getMessage ( ) ) ;26 System . e x i t ( 1 ) ;27 }28 catch ( IOException e ) {29 System . e r r . p r i n t l n ( ” Conectare i m p o s i b i l a l a : ”+30 host+” pe por tu l ”+port+” ”+e . getMessage ( ) ) ;31 System . e x i t ( 1 ) ;32 }

34 Scanner scanner=new Scanner ( System . in ) ;35 long m, n , r ;36 System . out . p r i n t l n ( ”m=” ) ;37 m=scanner . nextLong ( ) ;38 System . out . p r i n t l n ( ”n=” ) ;39 n=scanner . nextLong ( ) ;

41 ByteBuffer bb=ByteBuffer . a l l o c a t e ( 1 6 ) ;42 bb . putLong (0 ,m) . putLong (8 , n ) ;43 try{44 Future<Integer> fw=asc . wr i t e (bb ) ;45 while ( ! fw . isDone ( ) ) ;46 bb . c l e a r ( ) ;47 Future<Integer> f r=asc . read (bb ) ;48 while ( ! f r . isDone ( ) ) ;49 r=bb . getLong ( 0 ) ;50 System . out . p r i n t l n ( ”Cmmdc : ”+r ) ;51 asc . c l o s e ( ) ;52 }53 catch ( Exception e ){54 System . e r r . p r i n t l n ( ” Eroare de comunicat ie ”+e . getMessage ( ) ) ;55 }56 }57 }

Intrebari recapitulative

1. Precizati termenul socket (soclu).

Page 66: programare distribuita

66 CAPITOLUL 2. PROGRAMARE CU SOCLURI JAVA

2. Precizati clasele Java necesare unei aplicatii client-server cu socluri (socket).

3. Precizati diferenta de simetrie privind instantierea dintre un obiect detip Socket si unul de tip ServerSocket.

4. Care este rolul unui obiect de tip ServerSocket si cum se utilizeaza?

5. Precizati metodele unui obiect Socket, necesare ın transmiterea si receptiadatelor.

6. Precizati termenul multicast.

7. In ce consta participarea serverului la transmisie multicast ?

8. In ce consta participarea unui client la receptia multicast ?

9. Precizati termenul broadcast.

10. In ce consta participarea serverului la transmisie broadcast ?

11. In ce consta participarea unui client la receptia broadcast ?

12. Care este rolul unui obiect de tip DatagramPacket ?

13. Precizati metodele clasei DatagramSocket utilizate la expedierea si lareceptia unui datagram.

14. Ce parametri caracterizeaza un obiect de tip Buffer ?

15. Ce asemanare exista ıntre comunicatia bazata de datagrame si cea prinintermediul canalelor ?

Page 67: programare distribuita

Capitolul 3

Regasirea obiectelor prinservicii de nume

Oricarui obiect ıi sunt asociate un nume si o referinta. Regasirea / cautareaobiectului se face pornind de la numele obiectului, prin referinta se ajunge laobiect.

Exemple date prin sablonul (Nume ⇒ Referinta ⇒ Obiect)

1. Accesul la o carte ıntr-o biblioteca:

Titlul cartii ⇒ Referinta cartii din biblioteca ⇒ Carte

2. Contactul telefonic cu o persoana:

Nume persoana ⇒ Numar telefon ⇒ Persoana

Un serviciu de nume contine asocieri dintre nume de obiecte si obiecte sipoate oferi facilitati de regasire a obiectelor.

3.1 Java Naming and Directory Interface

Java Naming and Directory Interface - JNDI este o interfata de programare(Application Programming Interface - API ) care descrie functionalitatea unuiserviciu de nume.

Cuvantul servici este utilizat ın sens comun, entitate care pune la dispozitiefacilitati de folosire.

Alaturi de interfata JNDI, arhitectura JNDI mai contine interfata ServiceProvider Interface - SPI. Implementarea interfetei SPI de un furnizor de ser-vicii JNDI are ca efect independenta programului Java de furnizorul de serviciiJNDI.

67

Page 68: programare distribuita

68 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

JNDI este implementat de serviciile de nume:

• Filesystem are ca obiect asocierea dintre numele de fisier sau catalog cuobiectul corespunzator.

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

• RMI registry utilizat ın aplicatii RMI, din Java. Are ca obiect asociereaıntre un nume de serviciu de invocare ale obiectelor la distanta cu undelegat al serviciului (stub).

• COS - Common Object Service Naming utilizat ın aplicatii CORBA. Areca obiect asocierea ıntre numele unui serviciu de invocare ale obiectelorla distanta cu referinta la serviciu.

• LDAP - Lightweight Directory Access Protocol defineste un protocol pen-tru accesarea datelor retinute ıntr-un catalog LDAP (LDAP directory,information directory). Un catalog LDAP permite retinerea si regasireareferintelor obiectelor definite pe un calculator.

Interfata javax.naming.Context

Printr-un context se va ıntelege o multime de asocieri nume - obiect. Core-spunzator unui context, JNDI defineste interfata Context, cu metodele

• void bind(String nume,Object object)

• void rebind(String nume,Object object)

• void unbind(String nume)

• Object lookup(String nume)

• NamingEnumeration list(String nume)

Returneaza lista cu nume obiectelor ımpreuna cu tipul lor.

• NamingEnumeration listBindings(String nume)

Returneaza lista cu nume obiectelor ımpreuna cu tipul si locatia acestora.

Specificatiile JNDI prevad definirea unui context initial, implementat princlasa javax.naming.InitialContext, clasa ce implementeaza interfata Context.

Constructori.

Page 69: programare distribuita

3.1. JAVA NAMING AND DIRECTORY INTERFACE 69

• public InitialContext() throws NamingException

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

Pentru crearea contextului initial trebuie specificata clasa care creaza con-textul initial prin parametrul java.naming.factory.initial sau constantaContext.INITIAL CONTEXT FACTORY.

Acest parametru se poate da ın mai multe moduri:

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

Hashtable env=new Hashtable()

env.put("java.naming.factory.initial",...);

Context ctx=InitialContext(env);

sau

Hashtable env=new Hashtable()

env.put(Context.INITIAL_CONTEXT_FACTORY,...);

Context ctx=new InitialContext(env);

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

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

Parametrul se poate da ın interiorul programului prin

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

sau

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

• Atribut ın fisierul de proprietati jndi.properties.

In aceste ultime doua cazuri, contextul initial se creaza prin

Context ctx=new InitialContext();

Page 70: programare distribuita

70 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Functie de serviciul de nume, clasa care creaza contextul initial este dat ıntabelul

Serviciul de nume Clasa

Filesystem com.sun.jndi.fscontext.RefFSContextFactoryCOS com.sun.jndi.cosnaming.CNCtxFactoryRMI com.sun.jndi.rmi.registry.RegistryContextFactoryDNS com.sun.jndi.dns.DnsContextFactoryLDAP com.sun.jndi.ldap.LdapCtxFactory

Exemplul 3.1.1 Utilizand serviciul JNDI Filesystem se creaza un contextprin intermediul careia se afiseaza continutul unui catalog indicat de client.

1 import javax . naming . Context ;2 import javax . naming . I n i t i a l C o n t e x t ;3 import javax . naming . Binding ;4 import javax . naming . NamingEnumeration ;5 import javax . naming . NamingException ;6 import javax . naming . NameClassPair ;7 import java . i o . F i l e ;8 import java . u t i l . Hashtable ;9 import java . u t i l . Scanner ;

11 class Lookup{12 public stat ic void main ( St r ing [ ] a rgs ) {13 Context ctx=null ;14 /∗15 // Varianta 116 Hashtab le env = new Hashtab le ( 1 1 ) ;17 env . put ( Context .INITIAL CONTEXT FACTORY,18 ”com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ” ) ;19 t r y {20 c t x = new I n i t i a l C o n t e x t ( env ) ;21 }22 catch ( NamingException e ) {23 System . out . p r i n t l n (” I n i t i a l C o n t e x t E r r o r : ”+e . getMessage ( ) ) ;24 }25 ∗/26 /∗27 // Varianta 228 System . se tProper ty (” java . naming . f a c t o r y . i n i t i a l ” ,29 ”com . sun . j n d i . f s c o n t e x t . RefFSContextFactory ” ) ;30 t r y {31 c t x = new I n i t i a l C o n t e x t ( ) ;32 }33 catch ( NamingException e ) {34 System . out . p r i n t l n (” I n i t i a l C o n t e x t E r r o r : ”+e . getMessage ( ) ) ;35 }36 ∗/

38 // Varianta 339 try{40 ctx = new I n i t i a l C o n t e x t ( ) ;

Page 71: programare distribuita

3.1. JAVA NAMING AND DIRECTORY INTERFACE 71

41 }42 catch ( NamingException e ) {43 System . out . p r i n t l n ( ” I n i t i a l C o n t e x t E r r o r : ”+e . getMessage ( ) ) ;44 }

46 Scanner scanner=new Scanner ( System . in ) ;47 System . out . p r i n t l n ( ” I n t r o d u c e t i r e f e r i n t a abso luta a unui ca ta l og : ” ) ;48 St r ing myName=scanner . next ( ) ;49 try{50 System . out . p r i n t l n ( ”\n ctx . lookup ( ”+myName+” ) produce ” ) ;51 System . out . p r i n t l n ( ctx . lookup (myName ) ) ;

53 System . out . p r i n t l n ( ”\nContinutul c a t a l o g u l u i ”+myName+” e s t e :\n” ) ;54 NamingEnumeration l s t=ctx . l i s t (myName) ;55 while ( l s t . hasMore ( ) ){56 NameClassPair nc = ( NameClassPair ) l s t . next ( ) ;57 System . out . p r i n t l n ( nc ) ;58 }

60 System . out . p r i n t l n ( ”\nContinutul c a t a l o g u l u i ”+myName+” e s t e :\n” ) ;61 NamingEnumeration l s t 1 = ctx . l i s t B i n d i n g s (myName) ;62 while ( l s t 1 . hasMore ( ) ) {63 Binding bd = ( Binding ) l s t 1 . next ( ) ;64 System . out . p r i n t l n (bd ) ;65 }66 ctx . c l o s e ( ) ;67 }68 catch ( NamingException e ) {69 System . out . p r i n t l n ( ”Lookup f a i l e d : ” + e . getMessage ( ) ) ;70 }71 }72 }

Apelarea clasei, ın varianta data, consta din

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

sau

java Lookup

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

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

Serviciul de nume Filesystem este dat de fisierele: fscontext.jar siproviderutil.jar.

3.1.1 LDAP

LDAP poate fi privit ca un sistem de gestiune a unei baze de date (nerelational). Baza de date este alcatuita din atribute ale caror nume este pre-cizat de protocolul LDAP.

Punctele de intrare (radacinile) sunt date de DN (Distinguished Name).Uzual DN se defineste printr-una din variantele

Page 72: programare distribuita

72 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

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

2. o=”organization”

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

De exemplu, dc=example,dc=com

4. uid=user id,ou=”organization unit”

De exemplu, uid=admin,ou=system

Un utilizator este caracterizat prin atributul cn - common name si areacces la LDAP prin precizarea simultana a atributelor DN si cn.

Implementari gratuite LDAP sunt:

• OpenDS (Open Directory Service);

• ApacheDS (Apache Directory Service). Apache Directory Studio incor-poreaza si ofera interfata grafica de administrare pentru ApacheDS.

Vom utiliza produsul OpenDS.

Instalarea consta din:

1. dezarhivarea distributiei;

2. se completeaza sursa fisierului OpenDS-*\setup.bat cuset OPENDS JAVA HOME=... ca prima linie;

3. se executa OpenDS-*\setup.bat. Prin intermediul unei interfete graficese fixeaza

• o parola pentru cn=Directory Manager. Fie 1q2w3e aceasta parola.

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

Implicit, serverul OpenDS utilizeaza portul 389.Operatiile de configurare se fac utilizand interfata grafica a componentei

OpenDS Directory Server Control Panel, lansat prin

set OPENDS_JAVA_HOME=. . .

set OpenDS_HOME=. . .\OpenDS-*

%OpenDS_HOME%\bat\control-panel.bat

Page 73: programare distribuita

3.1. JAVA NAMING AND DIRECTORY INTERFACE 73

Declararea unui punct de intrare (utilizator) se face prin Manage Entries→ Entries → New User, urmat de completarea datelor cerute.

Schimbarea parolei unui utilizator se face tot din Manage Entries urmatde clic-dreapta pe DN si Reset User Password.

Prin aceasta componenta se poate porni si opri serverul OpenDS, ambeleoperatii putand fi executate si apeland start-ds, stop-ds din catalogulOpenDS HOME\bat.

Actiunile care pot fi ıntreprinse de un client care interactioneaza cu serverulconstau ın

• autentificare: datele necesare sunt DN si parola;

• conectare (bind) / deconectare (unbind) la un punct de intrare. Conectareaimplica crearea unui punct de intrare precizat prin cn;

• cautarea / localizarea (lookup) unui punct de intrare precizat prin cn.

Exemplul 3.1.2 Program pentru ınregistrarea si stergerea referintei unui obiectde tip Cmmdc.

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

8 public class LDAPServerCmmdc {9 public stat ic void main ( St r ing [ ] a rgs ) {

10 Scanner scanner=new Scanner ( System . in ) ;11 System . out . p r i n t l n ( ” A l e g e t i f u r n i z o r u l LDAP: ” ) ;12 System . out . p r i n t l n ( ” 1 : OpenDS” ) ;13 System . out . p r i n t l n ( ” 2 : Apache Di rec to ry S e r v i c e ” ) ;14 int prov ide r=scanner . next Int ( ) ;

16 Hashtable env = new Hashtable ( ) ;17 env . put ( Context . INITIAL CONTEXT FACTORY,18 ”com . sun . j n d i . ldap . LdapCtxFactory” ) ;19 i f ( prov ide r==1){20 env . put ( Context .PROVIDER URL,21 ” ldap :// l o c a l h o s t :389/ dc=example , dc=com” ) ;22 env . put ( Context .SECURITY PRINCIPAL, ”cn=Direc tory Manager” ) ;23 env . put ( Context .SECURITY CREDENTIALS, ”1q2w3e” ) ;24 }25 else {26 env . put ( Context .PROVIDER URL,27 ” ldap :// l o c a l h o s t :10389/ uid=admin , ou=system” ) ;28 env . put ( Context .SECURITY PRINCIPAL, ” uid=admin , ou=system” ) ;29 env . put ( Context .SECURITY CREDENTIALS, ” s e c r e t ” ) ;30 }31 DirContext ctx = null ;

Page 74: programare distribuita

74 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

32 System . out . p r i n t l n ( ” A l e g e t i ope ra t i a : 1− bind ; 2− unbind” ) ;33 int oper=scanner . next Int ( ) ;34 System . out . p r i n t l n ( ” I n t r o d u c e t i va loa rea a t r i b u t u l u i \”cn\” ”+35 +”a o b i e c t u l u i Cmmdc” ) ;36 System . out . p r i n t l n ( ”cn=” ) ;37 St r ing cmmdcObj=scanner . next ( ) . tr im ( ) ;

39 try {40 ctx = new I n i t i a l D i r C o n t e x t ( env ) ;41 i f ( oper==1){42 Cmmdc obj=new Cmmdc( ) ;43 St r ing s t r=”cn=”+cmmdcObj ;44 ctx . bind ( s t r , obj ) ;45 }46 else {47 ctx . unbind ( ”cn=”+cmmdcObj ) ;48 }49 ctx . c l o s e ( ) ;50 }51 catch ( NamingException e ) {52 System . out . p r i n t l n ( ”LDAPserverCmmdc : ”+e . getMessage ( ) ) ;53 }54 }55 }

Codul clasei Cmmdc este

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

10 }

Exemplul 3.1.3 Utilizarea unui obiect de tip Cmmdc regasit pe baza referinteidin serverul LDAP.

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

8 public class LDAPClientCmmdc {9 public stat ic void main ( St r ing [ ] a rgs ){

10 Scanner scanner=new Scanner ( System . in ) ;11 System . out . p r i n t l n ( ” A l e g e t i f u r n i z o r u l LDAP: ” ) ;12 System . out . p r i n t l n ( ” 1 : OpenDS” ) ;13 System . out . p r i n t l n ( ” 2 : Apache Di rec to ry S e r v i c e ” ) ;14 int prov ide r=scanner . next Int ( ) ;15 Hashtable env = new Hashtable ( ) ;

Page 75: programare distribuita

3.1. JAVA NAMING AND DIRECTORY INTERFACE 75

16 env . put ( Context . INITIAL CONTEXT FACTORY,17 ”com . sun . j n d i . ldap . LdapCtxFactory” ) ;18 i f ( prov ide r==1){19 env . put ( Context .PROVIDER URL,20 ” ldap :// l o c a l h o s t :389/ dc=example , dc=com” ) ;21 env . put ( Context .SECURITY PRINCIPAL, ”cn=Direc tory Manager” ) ;22 env . put ( Context .SECURITY CREDENTIALS, ”1q2w3e” ) ;23 }24 else {25 env . put ( Context .PROVIDER URL,26 ” ldap :// l o c a l h o s t :10389/ uid=admin , ou=system” ) ;27 env . put ( Context .SECURITY PRINCIPAL, ” uid=admin , ou=system” ) ;28 env . put ( Context .SECURITY CREDENTIALS, ” s e c r e t ” ) ;29 }30 DirContext ctx = null ;31 try {32 ctx=new I n i t i a l D i r C o n t e x t ( env ) ;33 i f ( ctx != null ) {34 System . out . p r i n t l n ( ” I n t r o d u c e t i va loa rea a t r i b u t u l u i \”cn\” ”+35 ”a o b i e c t u l u i Cmmdc” ) ;36 System . out . p r i n t l n ( ”cn=” ) ;37 St r ing cmmdcObj=scanner . next ( ) . tr im ( ) ;38 Object ob j e c t = ctx . lookup ( ”cn=”+cmmdcObj ) ;39 System . out . p r i n t l n ( ”Primul numar” ) ;40 long a=scanner . next Int ( ) ;41 System . out . p r i n t l n ( ”Al d o i l e a numar” ) ;42 long b=scanner . next Int ( ) ;43 Cmmdc obj=(Cmmdc) ob j e c t ;44 System . out . p r i n t l n ( ” Rezu l ta tu l cmmdc e s t e : ”+obj . cmmdc( a , b ) ) ;45 ctx . c l o s e ( ) ;46 }47 }48 catch ( NamingException e ) {49 System . out . p r i n t l n ( ”LDAPClientCmmdc : ”+e . getMessage ( ) ) ;50 }51 }52 }

Page 76: programare distribuita

76 CAPITOLUL 3. REGASIREA OBIECTELOR PRIN SERVICII DE NUME

Page 77: programare distribuita

Capitolul 4

Invocarea procedurilor ladistanta

Invocarea procedurilor la distanta (Remote Procedure Call – RPC ) ınseamnaapelarea unei metode a unui obiect aflat pe un alt calculator ca si cum acestas-ar afla pe calculatorul local.

Se vor prezenta doua cazuri:

• Invocarea procedurilor la distanta ın cazul mediului omogen Java. Denu-mirea tehnologiei ın acest caz este Invocarea metodei la distanta – RemoteMethod Invocation (RMI). Prin mediu omogen se ıntelege faptul ca atatcompontenta server cat si componenta client sunt programate ın acelasilimbaj de programare, Java ın cazul de fata.

• Invocarea procedurilor la distanta ın cazul medii neomogene. Solutiaın acest caz este dat de Common Object Request Broker Arhitecture(CORBA).

4.1 Remote Method Invocation

Regasirea obiectelor la distanta. Ideea gasirii unui obiect la distantaeste ca serverul ınscrie un reprezentant al sau – numit stub (ciot) – ıntr-unobiect registry - registru. Acest obiect se creaza cu programul rmiregistry.exedin distributia java si se lanseaza ın executie prin

start rmiregistry [port ]

unde valoarea implicita a portului este 1099. Comanda start apartine sis-temului de operare. rmiregistry este un serviciu de nume JNDI.

77

Page 78: programare distribuita

78 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Un client obtine din registry stub-ul serverului, prin intermediul caruiarealizeaza comunicatia cu programul server.

Cand un obiect al clientului apeleaza o metoda a unui obiect aflat ladistanta, se va face, de fapt, un apel de metoda a unui obiect care reprezintaserverul. Acesta este stub-ul, aflat pe aceasi masina cu clientul.

Rolul acestui obiect este sa ımpacheteze (marshalling) parametrii de apelai metodei ıntr-un mesaj ce va fi transferat prin retea. Impachetarea se faceıntr-o maniera independenta de calculator, mai precis sirurile de caractere siobiecte sunt transmise ıntr-un format care nu se bazeaza pe referinte. Pentruobiecte se utilizeaza serializarea obiectelor Java.

Serializarea datelor reprezinta transformarea acestora din tipuri de datediferite ıntr-un sir de octeti care va fi transportat prin retea fara interpretare,dar care pastreaza informatiile despre structura initiala a datelor.

Deserializarea este procesul invers de refacere a structurilor trimise prinretea.

Mesajul asamblat este transmis catre server, care stie sa desfaca mesajulreceptionat invocand ın mod corespunzator metoda referita de client.

Atunci cand clientul face apel la o metoda aflata pe o alta masina, esteinvocat stub-ul client, care ıncepe conversatia cu serverul. Acest lucru estecomplet transparent utilizatorului, care are impresia ca invoca o metoda locala.

Metodele apelate la distanta trebuie declarate ca apartinand unei interfetece extinde interfata java.rmi.Remote. Fiecare asemenea metoda trebuie saarunce o exceptie java.rmi.RemoteException. Obiectele care circula prinretea trebuie sa implementeze interfata java.io.Serializable.

Structura unei aplicatii RMI. O aplicatie RMI este alcatuita din treicomponente:

1. O interfata la distanta (remote) ın care se declara serviciile puse ladispozitie de server;

2. Aplicatia server care poate implementa serviciile interfetei la distanta siınscrie ın registry stub-ul corespunzator;

3. Aplicatia client ce apeleaza unul sau mai multe servicii ale serverului.

Aplicatia server trebuie sa aiba acces la clasele interfetei si a celor careo implementeaza. Locatia acestor clase se fixeaza prin atributul de numejava.rmi.server.codebase. Valoarea atributului trebuie indicat printr-unuldin protocoalele http, ftp, file.

Utilizand protocoalele http sau ftp arhiva interfetei si a claselor care oimplementeaza se depun ıntr-un server Web (Microsoft Internet Interchange

Page 79: programare distribuita

4.1. REMOTE METHOD INVOCATION 79

Server (IIS), apache-tomcat, respectiv ıntr-un server ftp (apache-ftp). In mo-mentul lansarii aplicatiei server, serverul http / ftp trebuie sa fie activ.

Daca se indica prin protocolul file calea catre cataloagele care continclasele interfetei si ale implementarii lor atunci ultimul caracter al caii este /.

Din punctul de vedere al executiei sunt implicate componentele:

• Serviciul de nume rmiregistry;

• Aplicatia server;

• Aplicatia client.

Aplicatia server si rmiregistry trebuie sa ruleze pe acelasi calculator.Registrul rmiregistry implementeaza interfata java.rmi.registry.Registry1.

Metodele oferite sunt:

• void bind(String numeServiciu, Remote obj)throwsRemoteException, AlreadyBoundException, AccessException

Inregistreaza ın registry obiectul obj ce implementeaza interfata Remote

sub numele numeServiciu.

• void rebind(String numeServiciu, Remote obj)throwsRemoteException, AccessException

Reınregistreaza ın registry obiectul obj ce implementeaza interfata Remotesub numele numeServiciu.

Aceasta metoda poate fi apelata doar daca programul care face ınregistrarease afla pe aceasi masina ca registrul registry.

• String[] list()throws RemoteException, AccessException

Returneaza o lista a tuturor serviciilor ınregistrate ın registry.

• Remote lookup(String numeServiciu)throwsRemoteException, NotBoundException, AccessException

Returneaza stub-ul serviciului ınregistrat sub numele numeServiciu.

• void unbind(String numeServiciu)throwsRemoteException, NotBoundException, AccessException

Sterge din registru serviciul.

1Varianta directa, fara a folosi facilitatile JNDI pentru rmiregistry.

Page 80: programare distribuita

80 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Localizarea registrului se obtine utilizand metoda statica getRegistry aclasei java.rmi.registry.LocateRegistry.

• public static Registry getRegistry() throws RemoteException

• public static Registry getRegistry(String host)throws RemoteException

• public static Registry getRegistry(int port)throws RemoteException

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

Metoda public static Registry createRegistry(int port)throws RemoteException creaza un registru la portul specificat pe calcula-torul local.

Ansamblul (rmiregistry, port) determina ın mod univoc o aplicatie / servi-ciu.

Interfata Remote serveste la marcarea interfetelor ale caror metode urmeazaa fi apelate de pe alta masina virtuala Java.

Un obiect de tip java.rmi.server.UnicastRemoteObject mijloceste trans-miterea obiectelor si serveste la generarea unui stub unui serviciu. Generareastub-ului unui serviciu se obtine prin intermediul metodei statice

static Remote UnicastRemoteObject.exportObject(Remote obj,intport)

Inregistrarea stub-ului unui serviciu descris de interfata IService si im-plementat de clasa ServiceImpl ın registry se face prin

ServiceImpl obj=new ServiceImpl();

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

// Varianta cu apel rmiregistry direct

/*

Registry registry=LocateRegistry.getRegistry(host,port);

registry.bind("MyServiceName",stub);

*/

// Varianta JNDI

String sPort=(new Integer(port)).toString();

System.setProperty(Context.INITIAL_CONTEXT_FACTORY,

Page 81: programare distribuita

4.1. REMOTE METHOD INVOCATION 81

"com.sun.jndi.rmi.registry.RegistryContextFactory");

System.setProperty(Context.PROVIDER_URL,"rmi://"+host+":"+sPort);

Context ctx=new InitialContext();

ctx.bind("MyServiceName",stub);

Un client care doreste sa foloseasca trebuie sa cunoasca :

• calculatorul pe care se gaseste obiectul registry si portul la care ascultaserviciul;

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

• metodele puse la dispozitie de serviciu.

4.1.1 Crearea unei aplicatii RMI

Exemplificam construirea unei aplicatii RMI ın care serviciul asigurat deserver este calculul celui mai mare divizor comun a doua numere naturale.

Pentru exemplele2 care urmeaza, presupunem ca textele sursa se retinın subcataloage ale unui catalog src, la care are acces doar programatorul,iar clasele obtinute prin compilare se depun ın subcataloagele unui catalogpublic\classes, accesibil prin retea.

Dezvoltarea unei aplicatii se va face pe un calculator. In acest sens, celor3 componente li se asociaza cataloagele \i - pentru interfata la distanta, \s -pentru componenta server si \c - pentru componenta client. Pasi necesari com-pilarii si desfasurarii componentelor aplicatiei se vor realiza prin intermediullui ant.

Pentru fiecare componenta se vor executa succesiv obiectivele:

1. Install - creaza o structura de cataloage src si public\classes.

2. Init - creaza structura de cataloage specifica aplicatiei.

3. Compile - compileaza programele sursa.

Dezvoltarea unei aplicatii RMI consta din parcurgerea urmatorilor pasi:

1. Definitea interfetei la distanta.

2Sistemul de operare utilizat este Windows

Page 82: programare distribuita

82 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

1 package cmmdc ;2 public interface ICmmdc extends java . rmi . Remote{3 long cmmdc( long a , long b) throws java . rmi . RemoteException ;4 }

Presupunem ca programatorul interfetei retine textul sursaICmmdc.java ın catalogul \i\src\cmmdc.

2. Compilarea si arhivarea interfetei se poate realiza fisierul ant-build

1 <project name=” I n t e r f a c e ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description> I n t e r f a c e a c t i o n s </description>3 < !−− s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d −−>

5 <property name=” package ” value=”cmmdc”/>

7 <target name=” I n s t a l l ”>8 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>9 <delete d i r=” s r c ”/>

10 <mkdir d i r=” s r c ”/>11 <delete d i r=” pub l i c ”/>12 <mkdir d i r=” pub l i c ”/>13 <delete d i r=” pub l i c / c l a s s e s ”/>14 <mkdir d i r=” pub l i c / c l a s s e s ”/>15 </target>

17 <target name=” I n i t ”>18 < !−− Create the time stamp −−>19 <tstamp/>20 <mkdir d i r=” s r c /${package}”/>21 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>22 </target>

24 <target name=”Compile” depends=” I n i t ”25 description=” compile the source ” >26 <javac s r c d i r=” s r c ” i n c l u d e s=”${package }/∗∗”27 d e s t d i r=” pub l i c / c l a s s e s ” inc ludeantrunt ime=” f a l s e ”/>28 <jar based i r=” pub l i c / c l a s s e s ”29 d e s t f i l e=” pub l i c / c l a s s e s /${package }/${ package } . j a r ”30 i n c l u d e s=”${package }/∗ . c l a s s ” />31 </target>32 </project>

3. Implementarea interfetei remote prin construirea aplicatiei server.

1 package s e r v e r ;2 import cmmdc . ICmmdc ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;4 // Varianta cu ape l r m i r e g i s t r y d i r e c t5 import java . rmi . r e g i s t r y . Reg i s t ry ;6 import java . rmi . r e g i s t r y . LocateReg i s t ry ;7 // Varianta JNDI8 import javax . naming . Context ;

Page 83: programare distribuita

4.1. REMOTE METHOD INVOCATION 83

9 import javax . naming . I n i t i a l C o n t e x t ;

11 public class CmmdcImpl implements ICmmdc{

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

15 public stat ic void main ( St r ing args [ ] ) {16 St r ing host=” l o c a l h o s t ” ;17 int port =1099;18 i f ( args . length >0)19 port=I n t e g e r . pa r s e In t ( args [ 0 ] ) ;20 try {21 CmmdcImpl obj=new CmmdcImpl ( ) ;22 ICmmdc stub=(ICmmdc) UnicastRemoteObject . exportObject ( obj , 0 ) ;

24 // Varianta d i r e c t a25 /∗26 Reg i s t ry r e g i s t r y=LocateReg is t ry . g e t R e g i s t r y ( host , por t ) ;27 r e g i s t r y . bind (”CmmdcServer” , s tub ) ;28 ∗/

30 // Varianta JNDI31 St r ing sPort=(new I n t e g e r ( port ) ) . t oS t r i ng ( ) ;32 System . se tProper ty ( Context . INITIAL CONTEXT FACTORY,33 ”com . sun . j n d i . rmi . r e g i s t r y . RegistryContextFactory ” ) ;34 System . se tProper ty ( Context .PROVIDER URL, ”rmi : // ”+host+” : ”+sPort ) ;35 Context ctx=new I n i t i a l C o n t e x t ( ) ;36 ctx . bind ( ”CmmdcServer” , stub ) ;

38 System . out . p r i n t l n ( ”CmmdcServer ready ” ) ;39 }40 catch ( Exception e ) {41 System . out . p r i n t l n ( ”CmmdcImpl e r r : ” + e . getMessage ( ) ) ;42 }43 }44 }

Textul sursa al programului server CmmdcImpl.java se retine ın catalogul\s\src\server

4. (a) Compilarea programului server;

(b) Crearea obiectului registry ;

(c) Lansarea serverului ın lucru

se obtin cu ant cu

1 <project name=” Server ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>Server a c t i o n s </description>

4 <property name=”path” location=” . . . ”/>

6 <property name=” package ” value=” s e r v e r ”/>7 <property name=” i n t e r f a c e−j a r ”8 location=”${path}/ i / pub l i c / c l a s s e s /cmmdc” />9 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />

10 <property name=” s e r v i c e−c l a s s ” value=”CmmdcImpl” />

Page 84: programare distribuita

84 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

11 <property name=” port ” value=”1099”/>12 <property name=” host ” value=” l o c a l h o s t ”/>

14 <target name=” I n s t a l l ”>15 < !−− Create the time stamp −−>16 <tstamp/>17 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>18 <delete d i r=” s r c ”/>19 <mkdir d i r=” s r c ”/>20 <delete d i r=” pub l i c ”/>21 <mkdir d i r=” pub l i c ”/>22 <delete d i r=” pub l i c / c l a s s e s ”/>23 <mkdir d i r=” pub l i c / c l a s s e s ”/>24 </target>

26 <target name=” I n i t ”>27 <mkdir d i r=” s r c /${package}”/>28 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>29 <copy f i l e=”${ i n t e r f a c e−j a r }/${ ja r− f i l e }” t o d i r=” pub l i c / c l a s s e s ” />30 </target>

32 <target name=”Compile” depends=” I n i t ”33 description=” compile the source ” >34 <javac s r c d i r=” s r c ”35 i n c l u d e s=”${package }/∗∗” d e s t d i r=” pub l i c / c l a s s e s ”36 classpath=” pub l i c / c l a s s e s /${ ja r− f i l e }”37 inc ludeantrunt ime=” f a l s e ”/>38 <unjar src=” pub l i c / c l a s s e s /${ ja r− f i l e }” dest=” pub l i c / c l a s s e s ” />39 </target>

41 <target name=”Rmi”>42 <exec executab l e=” r m i r e g i s t r y ”>43 <arg value=”${ port }” />44 </exec>45 </target>

47 <target name=” Archive ”>48 <jar d e s t f i l e=”cmmdc . j a r ” ba s ed i r=” pub l i c / c l a s s e s ”>49 <include name=”${package }/∗”/>50 <include name=”cmmdc/∗”/>51 </ jar>52 </target>

54 <target name=” Server ”>55 <java classname=”${package } . ${ s e r v i c e−c l a s s }”56 classpath=”${path}/ s / pub l i c / c l a s s e s ” f o rk=” true ”>

58 <jvmarg value=59 ”−Djava . rmi . s e r v e r . codebase= f i l e : ${path}/ s / pub l i c / c l a s s e s /”/>

61 < !−−62 <jvmarg value=63 ”−Djava . rmi . s e r v e r . codebase=ht tp : //${ host } : 8080 /rmi/cmmdc . j a r ”/>64 −−>65 < !−−66 <jvmarg value=67 ”−Djava . rmi . s e r v e r . codebase=f t p : //${ host } : 2121 /rmi/cmmdc . j a r ”/>68 −−>69 <arg l i n e=”${ port }”/>

Page 85: programare distribuita

4.1. REMOTE METHOD INVOCATION 85

70 </ java>71 </target>72 </project>

Obiectivele Rmi si Server se lanseaza ın ferestre dos distincte care ramanactive pe durata de viata a aplicatiei server.

Obiectivul Archive creaza arhiva jar necesara desfasurarii interfetei sia claselor care o implementeaza ıntr-un server http / ftp. Asa cums-a amintit mai sus, acesta arhiva este preluata de aplicatia server, lalansare, prin atributul java.rmi.server.codebase.

Server ftp

Utilizam serverul ftp apache-ftpserver. Instalarea consta din dezarhivareaarhivei descarcate. Lansarea serverului se obtine prin

set FTP_SERVER_HOME=. . .

set JAVA_HOME=. . .

%FTP_SERVER_HOME%\bin\ftpd.bat res/conf/ftpd-typical.xml

Resursele / fisierele puse la dispozitie de serverul ftp sunt puse ın cata-logul FTP SERVER HOME\res\home.Serverul RMI cu server ftp. Se creaza arhiva cmmdc.jar cu continutul

cmmdc

| ICmmdc.class

server

| CmmdcImpl.class

care se depune ın serverul ftp, ın catalogul rmi.

5. Realizarea programului client

1 package c l i e n t ;2 import cmmdc . ICmmdc ;3 import java . u t i l . Scanner ;4 // Varianta cu ape l r m i r e g i s t r y d i r e c t5 import java . rmi . r e g i s t r y . Reg i s t ry ;6 import java . rmi . r e g i s t r y . LocateReg i s t ry ; ;7 // Varianta JNDI8 import javax . naming . Context ;9 import javax . naming . I n i t i a l C o n t e x t ;

11 public class CmmdcClient {

Page 86: programare distribuita

86 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

12 public stat ic void main ( St r ing args [ ] ) {13 St r ing host=” l o c a l h o s t ” ;14 int port =1099;15 i f ( args . length >0)16 host=args [ 0 ] ;17 i f ( args . length >1)18 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;19 Scanner scanner=new Scanner ( System . in ) ;20 System . out . p r i n t l n ( ”Primul numar : ” ) ;21 long m=Long . parseLong ( scanner . next ( ) ) ;22 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;23 long n=Long . parseLong ( scanner . next ( ) ) ;24 long x=0;25 try {26 // Varianta d i r e c t a27 /∗28 Reg i s t ry r e g i s t r y=LocateReg is t ry . g e t R e g i s t r y ( host , por t ) ;29 ICmmdc ob j =(ICmmdc) r e g i s t r y . lookup (”CmmdcServer ” ) ;30 ∗/31 // Varianta JNDI32 St r ing sPort=(new I n t e g e r ( port ) ) . t oS t r i ng ( ) ;33 System . se tProper ty ( Context . INITIAL CONTEXT FACTORY,34 ”com . sun . j n d i . rmi . r e g i s t r y . RegistryContextFactory ” ) ;35 System . se tProper ty ( Context .PROVIDER URL, ”rmi : // ”+host+” : ”+sPort ) ;36 Context ctx=new I n i t i a l C o n t e x t ( ) ;37 ICmmdc obj=(ICmmdc) ctx . lookup ( ”CmmdcServer” ) ;

39 x=obj . cmmdc(m, n ) ;40 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;41 }42 catch ( Exception e ) {43 System . out . p r i n t l n ( ”CmmdcClient except ion : ”+e . getMessage ( ) ) ;44 }45 }46 }

Sursa programului client CmmdcClient.java apartine catalogului\c\src\client

6. Compilarea programului client si lansarea acestuia ın executie.

1 <project name=” Cl i en t ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description> Cl i en t a c t i o n s </description>

4 <property name=”path” location=” . . . ”/>

6 <property name=” package ” value=” c l i e n t ”/>7 <property name=” i n t e r f a c e−j a r ”8 location=”${path}/ i / pub l i c / c l a s s e s /cmmdc”/>9 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />

10 <property name=” host ” value=” l o c a l h o s t ” />11 <property name=” port ” value=”1099” />12 <property name=” c l i e n t−c l a s s ” value=”CmmdcClient” />

14 <target name=” I n s t a l l ”>15 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>16 <delete d i r=” s r c ”/>17 <mkdir d i r=” s r c ”/>

Page 87: programare distribuita

4.1. REMOTE METHOD INVOCATION 87

18 <delete d i r=” c l a s s e s ”/>19 <mkdir d i r=” c l a s s e s ”/>20 </target>

22 <target name=” I n i t ”>23 < !−− Create the time stamp −−>24 <tstamp/>25 <mkdir d i r=” s r c /${package}”/>26 <mkdir d i r=” c l a s s e s /${package}”/>27 <copy f i l e=”${ i n t e r f a c e−j a r }\${ ja r− f i l e }” t o d i r=” c l a s s e s ” />28 </target>

30 <target name=”Compile” depends=” I n i t ”31 description=” compile the source ”>32 <javac s r c d i r=” s r c ”33 i n c l u d e s=”${package }/∗ . java ” d e s t d i r=” c l a s s e s ”34 classpath=” c l a s s e s \${ j a r− f i l e }” inc ludeantrunt ime=” f a l s e ”/>35 </target>

37 <target name=”Run” depends=”Compile”38 description=” Star t thr c l i e n t ”>39 <java classname=”${package } . ${ c l i e n t−c l a s s }” f o rk=” true ”>40 <classpath>41 <pathelement location=” c l a s s e s /${ j a r− f i l e }” />42 <pathelement path=” c l a s s e s ” />43 </classpath>44 <arg l i n e=”${ host } ${ port }” />45 </ java>46 </target>47 </project>

4.1.2 Tipare de programare

Fabrica de obiecte

Tiparul fabrica de obiecte va permite crearea dinamica a unui server. Prinaceea schema, se va crea o clasa - fabrica de obiecte - care implementeaza cateo metoda get, ce returneaza o instanta de server. Aceste metode sunt declarateıntr-o interfata la distanta.

Un client, apeland o asemenea metoda, va instantia serverul dorit si vaobtine stub-ul corespunzator.

In felul acesta se vor putea utiliza o multime de aplicatii distincte prinintermediul unui singur rmiregistry. Fiecarei aplicatii ıi corespunde un server,instantiat la apelul clientului de metoda get corespunzatoare.

Programarea unui server care poate fi lansat dinamic trebuie sa satisfacarestrictiile:

• Clasa serverului extinde clasa UnicastRemoteObject.

Page 88: programare distribuita

88 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

• Exista un constructor fara argumente ce arunca exceptia java.rmi.RemoteException.

Pentru exemplificarea tehnicii de lucru reluam aplicatia pentru calcululcelui mai mare divizor comun a doua numere naturale, considerand interfata

1 package cmmdc0 ;2 pub l i c i n t e r f a c e ICmmdc0 extends java . rmi . Remote{3 pub l i c long compute ( long m, long n) throws java . rmi . RemoteException ;4 }

Aceasa interfata va fi implementata de clasa ServerCmmdc. Metoda com-pute este o metoda de calcul a celui mai mare divizor comun a doua numere.

Obiecte de tip ServerCmmdc se creaza, de la distanta prin fabrica de obiecteFabObiecte, o clasa ce implementeaza interfata

1 package cmmdc0 ;2 pub l i c i n t e r f a c e IFabObiecte extends java . rmi . Remote{3 pub l i c ICmmdc0 getCmmdc ( ) throws java . rmi . RemoteException ;4 }

Codurile claselor ServerCmmdc si FabObiecte sunt

1 package cmmdc0 ;2 import java . rmi . RemoteException ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;

5 pub l i c c l a s s ServerCmmdc extends UnicastRemoteObject implements ICmmdc0{

7 pub l i c ServerCmmdc ( ) throws RemoteException{}

9 pub l i c long compute ( long m, long n) throws RemoteException{10 . . .11 }12 }

respectiv

1 package cmmdc0 ;2 import java . rmi . RemoteException ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;4 import java . rmi . r e g i s t r y . Reg i s t ry ;5 import java . rmi . r e g i s t r y . LocateReg i s t ry ;

7 pub l i c c l a s s FabObiecte implements IFabObiecte {

9 pub l i c ICmmdc0 getCmmdc ( ) throws RemoteException{10 ServerCmmdc cmmdc=new ServerCmmdc ( ) ;11 r e turn cmmdc ;12 }

14 pub l i c s t a t i c void main ( S t r ing args [ ] ) {15 St r ing host=” l o c a l h o s t ” ;16 i n t port =1099;17 i f ( a rgs . length >0)18 host=args [ 0 ] ;

Page 89: programare distribuita

4.1. REMOTE METHOD INVOCATION 89

19 t ry {20 FabObiecte obj=new FabObiecte ( ) ;21 IFabObiecte stub=(IFabObiecte ) UnicastRemoteObject . exportObject ( obj , 0 ) ;22 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;23 r e g i s t r y . bind ( ” ObjectFactory ” , stub ) ;24 System . out . p r i n t l n ( ” ObjectFactory ready ” ) ;25 }26 catch ( Exception e ){27 System . out . p r i n t l n ( ” Factory e r r ”+e . getMessage ( ) ) ;28 }29 }30 }

Aplicatia client se compune din doua clase

1. RemoteClient

Clientul obtine stub-ul serviciului, prin intermediul caruia apeleaza metadagetCmmdc() a fabricii de obiecte, obtinand un obiect remote de tipServerCmmdc, ce implementeaza interfata la distanta ICmmdc0.

1 package cmmdc0 ;2 import java . rmi . RemoteException ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;4 import java . rmi . r e g i s t r y . Reg i s t ry ;5 import java . rmi . r e g i s t r y . LocateReg i s t ry ;

7 pub l i c c l a s s RemoteClient extends UnicastRemoteObject{

9 ICmmdc0 remote=n u l l ;

11 pub l i c RemoteClient ( ) throws RemoteException{}

13 pub l i c RemoteClient ( S t r ing host , i n t port ) throws RemoteException{14 IFabObiecte f a b r i c a=n u l l ;15 t ry {16 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;17 IFabObiecte obj=(IFabObiecte ) r e g i s t r y . lookup ( ” ObjectFactory ” ) ;18 remote=obj . getCmmdc ( ) ;19 }20 catch ( Exception e ){21 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;22 }23 }24 }

2. ClientCmmdc0Apeleaza metoda compute a obiectului remote.

1 package cmmdc0 ;2 import java . u t i l . Scanner ;

4 pub l i c c l a s s ClientCmmdc0{

6 pub l i c s t a t i c void main ( S t r ing args [ ] ) {7 St r ing host=” l o c a l h o s t ” ;

Page 90: programare distribuita

90 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

8 i n t port =1099;9 i f ( a rgs . length >0)

10 host=args [ 0 ] ;11 i f ( a rgs . length >1)12 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;13 Scanner scanner=new Scanner ( System . in ) ;14 t ry {15 RemoteClient ct=new RemoteClient ( host , port ) ;16 System . out . p r i n t l n ( ”m=” ) ;17 long m=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ”n=” ) ;19 long n=scanner . nextLong ( ) ;20 long x=ct . remote . compute (m, n ) ;21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;22 }23 catch ( Exception e ){24 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;25 }26 System . e x i t ( 0 ) ;27 }28 }

Apelul invers – Callback

Se numeste apel invers apelarea de catre programul server a unei metodea clientului.

In RMI realizarea unui apel invers presupune:

1. definirea unei interfete la distanta ce va fi implementat de programulclient;

2. programul client ce implementeaza interfata extinde clasa UnicastRemoteObject si are un constructor ce arunca o exceptie java.rmi.RemoteException.

Extindem aplicatia anterioara cu posibilitatea suplimentara a serverului(ServerCmmdc) de a alege metoda de calcul a celui mai mare divizor comundintre varianta imperativa si cea recursiva.

Extindem interfata ICmmdc0 cu metoda

public void setMethod(ICallbackCmmdc obj)throws RemoteException;

1 package cmmdc0 ;2 pub l i c i n t e r f a c e ICmmdc0 extends java . rmi . Remote{3 pub l i c long compute ( long m, long n) throws java . rmi . RemoteException ;4 pub l i c void setMethod ( ICallbackCmmdc obj ) throws java . rmi . RemoteException ;5 }

unde ICallbackCmmdc este interfata

Page 91: programare distribuita

4.1. REMOTE METHOD INVOCATION 91

1 package cmmdc0 ;2 pub l i c i n t e r f a c e ICallbackCmmdc extends java . rmi . Remote{3 pub l i c S t r ing getMethod ( ) throws java . rmi . RemoteException ;4 }

ce va fi implementata ın clasa RemoteClient.Programul ServerCmmdc devine

1 package cmmdc0 ;2 import java . rmi . RemoteException ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;

5 pub l i c c l a s s ServerCmmdc extends UnicastRemoteObject6 implements ICmmdc0{7 p r i v a t e S t r ing method=n u l l ;

9 pub l i c ServerCmmdc ( ) throws RemoteException{}

11 pub l i c long compute ( long m, long n){12 long x=0;13 i f ( method . equa l s ( ”NERECURSIV” ) )14 x=n e r e c u r s i v (m, n ) ;15 i f ( method . equa l s ( ”RECURSIV” ) )16 x=r e c u r s i v (m, n ) ;17 r e turn x ;18 }

20 pub l i c void setMethod ( ICallbackCmmdc obj ) throws RemoteException{21 method=obj . getMethod ( ) ;22 }

24 p r i v a t e long r e c u r s i v ( long a , long b){25 i f ( a==b)26 r e turn a ;27 e l s e28 i f ( a<b)29 r e turn r e c u r s i v ( a , b−a ) ;30 e l s e31 r e turn r e c u r s i v ( a−b , b ) ;32 }

34 p r i v a t e long n e r e c u r s i v ( long m, long n){35 long r , c ;36 do{37 c=n ;38 r=m%n ;39 m=n ;40 n=r ;41 }42 whi le ( r !=0) ;43 r e turn c ;44 }45 }

Dupa obtinerea stub-ului, clientul apeleaza metoda setMethod a serveruluiremote, care, prin apel invers, apeleaza metoda getMethod din RemoteClient.Clientul stabileste metoda de calcul si apeleaza metoda compute a lui remote.

Page 92: programare distribuita

92 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Programele client devin

1 package cmmdc0 ;2 import java . rmi . RemoteException ;3 import java . rmi . s e r v e r . UnicastRemoteObject ;4 import java . rmi . r e g i s t r y . Reg i s t ry ;5 import java . rmi . r e g i s t r y . LocateReg i s t ry ;6 import java . u t i l . Scanner ;

8 pub l i c c l a s s RemoteClient extends UnicastRemoteObject9 implements ICallbackCmmdc{

10 ICmmdc0 remote=n u l l ;

12 pub l i c RemoteClient ( ) throws RemoteException{}

14 pub l i c S t r ing getMethod ( ){15 Scanner scanner=new Scanner ( System . in ) ;16 System . out . p r i n t l n ( ” A l e g e t i va r i anta a l g o r i t m u l u i l u i Eucl id ” ) ;17 System . out . p r i n t l n ( ”1 − a l go r i tmu l ne−r e c u r s i v ” ) ;18 System . out . p r i n t l n ( ”2 − a l go r i tmu l r e c u r s i v ” ) ;19 i n t x=scanner . next Int ( ) ;20 St r ing method=n u l l ;21 i f ( x==1)22 method=”NERECURSIV” ;23 e l s e24 method=”RECURSIV” ;25 r e turn method ;26 }

28 pub l i c RemoteClient ( S t r ing host , i n t port ) throws RemoteException{29 IFabObiecte f a b r i c a=n u l l ;30 t ry {31 Reg i s t ry r e g i s t r y=LocateReg i s t ry . g e tReg i s t ry ( host , port ) ;32 IFabObiecte obj=(IFabObiecte ) r e g i s t r y . lookup ( ” ObjectFactory ” ) ;33 remote=obj . getCmmdc ( ) ;34 }35 catch ( Exception e ){36 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;37 }38 }39 }

si

1 package cmmdc0 ;2 import java . u t i l . Scanner ;

4 pub l i c c l a s s ClientCmmdc0{5 pub l i c s t a t i c void main ( S t r ing args [ ] ) {6 St r ing host=” l o c a l h o s t ” ;7 i n t port =1099;8 i f ( a rgs . length >0)9 host=args [ 0 ] ;

10 i f ( a rgs . length >1)11 port=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;12 Scanner scanner=new Scanner ( System . in ) ;13 t ry {14 RemoteClient ct=new RemoteClient ( host , port ) ;15 ct . remote . setMethod ( ct ) ;16 System . out . p r i n t l n ( ”m=” ) ;

Page 93: programare distribuita

4.1. REMOTE METHOD INVOCATION 93

17 long m=scanner . nextLong ( ) ;18 System . out . p r i n t l n ( ”n=” ) ;19 long n=scanner . nextLong ( ) ;20 long x=ct . remote . compute (m, n ) ;21 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;22 }23 catch ( Exception e ){24 System . out . p r i n t l n ( ” C l i en tExcept i on : ”+e . getMessage ( ) ) ;25 }26 System . e x i t ( 0 ) ;27 }28 }

4.1.3 Obiect activabil la distanta

O instanta a clasei UnicastRemoteObject reprezinta un obiect la distantacare ruleaza ın permanenta, folosind resursele masinii server.

Incepand cu versiunea JDK 1.2, prin ıntroducerea clasei java.rmi.activa-tion.Activatable si a programului rmid (...\jdk...\bin\rmid.exe) se pot creaprograme care ınregistreaza informatii despre obiecte la distanta ce vor fi createsi executate la cerere.

Invocarea de la distanta a unei metode apartinand unui asemenea obiectare ca efect activarea obiectului.

Pe fiecare masina virtuala Java exista un grup de activare (activationgroup), care realizeaza activarea. Activarea este facuta de un activator. Unactivator contine o tabela care face legatura dintre clasa obiectului cu URL-ulacestuia si eventual, cu date necesare initializarii obiectului. Atunci cand acti-vatorul constata ca nu exista un obiect referit, face apel la grupul de activarecare va produce activarea obiectului.

Din punctul de vedere al clientului utilizarea mecanismului de activare ladistanta nu implica modificari. Modificarile intervin numai din punctul devedere al serverului si al ınregistrarii sale.

Reluam aplicatia dezvoltata la ınceputul capitolului, privind calculul celuimai mare divizor comun a doua numere naturale.

Aplicatia server este compusa din doua clase

1. o clasa ce implementeaza interfata ICmmdc : CmmdcActivabil;

2. clasa Setup, cu metoda main, care face posibila mecanismul de activaresi ınscrie serviciul ın registry. Aceasta clasa este preluata din tutorialuldedicat activarii a documentatiei ce ınsoteste distributia Java.

Clasa ce implementeaza interfata la distanta trebuie

Page 94: programare distribuita

94 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

1. sa extinda clasa Activatable;

2. sa aiba un constructor ce are doi parametrii

(a) un identificator al grupului de activare, de tip ActivationID, utilizatde demonul de activare rmid;

(b) un obiect de tip MarshalledObject cu date de initializare a obiec-tului activabil. In cazul nostru, acest parametru nu va fi folosit.

Codul sursa al clasei CmmdcActivabil este

1 package acmmdc ;2 import java . rmi . RemoteException ;3 import java . rmi . Marshal ledObject ;4 import java . rmi . a c t i v a t i o n . Act ivatab l e ;5 import java . rmi . a c t i v a t i o n . Act ivat ionID ;6 import cmmdc . ICmmdc ;

8 pub l i c c l a s s CmmdcActivabil extends Act ivatab l e9 implements ICmmdc{

11 pub l i c CmmdcActivabil ( Act ivat ionID id , Marshal ledObject data )12 throws RemoteException{13 super ( id , 0 ) ;14 }

16 pub l i c long cmmdc( long m, long n ) { . . .}17 }

Clasa Setup necesita o serie de date furnizare ca proprietati:

1. drepturile de securitate ale grupului de activare

myactivation.policy=group.policy;

cu continutul

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

// permission to read and write object’s file

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

// permission to listen on an anonymous port

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

};

2. java.class.path=no.classpath

ceea ce previne grupul de activare sa ıncarce o clasa din classpath-ullocal;

3. localizarea (URL) clasei ce implementeaza interfata

myactivation.impl.codebase;

Page 95: programare distribuita

4.1. REMOTE METHOD INVOCATION 95

4. localizarea unui fisier cu date de initializare a obiectului activabil

myactivation.file;

5. numele sub care ınregistreaza serviciul ın registry

myactivation.name.

Programul Setup realizeaza:

1. Construirea unui descriptor al grupului de activare. Grupul de activareeste un container ce gestioneaza obiectele activabile continute.

2. Inregistrarea descriptorului grupului de activare si obtinerea unui iden-tificator al grupului de activare.

3. Construirea descriptorului de activare. Trebuie cunoscute

• idendificatorul grupului de activare;

• numele clasei ce implementeaza interfata la distanta;

• localizarea (URL) clasei ce implementeaza interfata la distanta;

• obiectul de tip MarshalledObject, cu datele de initializare a obiec-tului activabil.

4. Inregistrarea descriptorului de activare, ın urma careia se obtine stub-ulobiectului activabil.

5. Inregistrarea stub-ului ımpreuna cu numele serviciului ın registry.

Codul clasei setup este

1 package acmmdc ;

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

8 pub l i c c l a s s Setup{

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

12 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) throws Exception {

14 // Argumentul l i n i e i de comanda15 St r ing implClass = ”” ;16 i f ( a rgs . l ength < 1) {17 System . out . p r i n t l n ( ” usage : ” ) ;18 System . out . p r i n t l n ( ” java [ opt ions ] examples . a c t i v a t i o n . Setup <implClass>” ) ;

Page 96: programare distribuita

96 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

19 System . e x i t ( 1 ) ;20 }21 e l s e {22 implClass = args [ 0 ] ;23 }

25 // Const ru i rea d e s c r i p t o r u l u i g rupu lu i de a c t i v a r e26 St r ing p o l i c y=System . getProperty ( ” myact ivat ion . p o l i c y ” , ”group . p o l i c y ” ) ;27 St r ing implCodbase=System . getProperty ( ” myact ivat ion . impl . codebase ” ) ;28 St r ing filename=System . getProperty ( ” myact ivat ion . f i l e ” , ”” ) ;29 P r o p e r t i e s props = new P r o p e r t i e s ( ) ;30 props . put ( ” java . s e c u r i t y . p o l i c y ” , p o l i c y ) ;31 props . put ( ” java . c l a s s . path” , ” no c l a s spa th ” ) ;32 props . put ( ” myact ivat ion . impl . codebase ” , implCodebase ) ;33 i f ( filename != n u l l && ! filename . equals ( ”” ) ) {34 props . put ( ” myact ivat ion . f i l e ” , filename ) ;35 }36 ActivationGroupDesc groupDesc = new ActivationGroupDesc ( props , n u l l ) ;

38 // I n r e g i s t r a r e a grupu lu i de a c t i v a r e pentr ob t ine r ea39 // i d e n t i f i c a t o r u l u i de a c t i v a r e40 ActivationGroupID groupID=41 ActivationGroup . getSystem ( ) . r eg i s t e rGroup ( groupDesc ) ;42 System . e r r . p r i n t l n ( ” Act ivat ion group d e s c r i p t o r r e g i s t e r e d . ” ) ;

44 // Const ru i rea d e s c r i p t o r u l u i de a c t i v a r e45 Marshal ledObject data = n u l l ;46 i f ( filename != n u l l && ! filename . equals ( ”” ) ) {47 data = new Marshal ledObject ( filename ) ;48 }

50 Act ivat ionDesc desc=51 new Act ivat ionDesc ( groupID , implClass , implCodebase , data ) ;

53 // I n r e g i s t r a r e a d e s c r i p t o r u l u i de a c t i v a r e54 Remote stub = Act ivatab l e . r e g i s t e r ( desc ) ;55 System . e r r . p r i n t l n ( ” Act ivat ion d e s c r i p t o r r e g i s t e r e d . ” ) ;

57 // I n r e g i s t r a r e a s e r v i c i u l u i in r e g i s t r y58 St r ing name = System . getProperty ( ” myact ivat ion . name” ) ;59 LocateReg i s t ry . g e tReg i s t ry ( ) . reb ind (name , stub ) ;60 System . e r r . p r i n t l n ( ”Stub bound in r e g i s t r y . ” ) ;61 }62 }

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

sunt ın catalogul \c\src\acmmdc.Lansarea serverului ın executie consta din

1. Pornirea demon-ului rmid

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

-J-Dmyactivation.policy=group.policy

unde rmid.policy este

Page 97: programare distribuita

4.2. CORBA 97

grant {

// allow activation groups to use certain system properties

permission com.sun.rmi.rmid.ExecOptionPermission

"-Djava.security.policy=${myactivation.policy}";

permission com.sun.rmi.rmid.ExecOptionPermission

"-Djava.class.path=no_classpath";

permission com.sun.rmi.rmid.ExecOptionPermission

"-Dmyactivation.impl.codebase=*";

permission com.sun.rmi.rmid.ExecOptionPermission

"-Dmyactivation.file=*";};

iar group.policy are codul

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

// permission to read and write object’s file

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

// permission to listen on an anonymous port

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

};

2. Pornirea registry-ului

start rmiregistry

3. Lansarea programului Setup

set classpath=\s\public\classes\cmmdc.jar;\s\public\classes

java -Djava.rmi.server.codebase=file:/s/public/classes/

-Dmyactivation.impl.codebase=file:/s/public/classes/

-Dmyactivation.name=CmmdcServer

-Dmyactivation.file=""

-Dmyactivation.policy=group.policy

acmmdc.Setup acmmdc.CmmdcActivabil

Localizarea (URL) interfetei la distanta se precizeaza prinjava.rmi.server.codebase;

Drept client se utilizeaza programul realizat ın sectiunea 4.1.

4.2 CORBA

Retelele de calculatoare sunt eterogene ın timp ce majoritatea interfetelorde programare a aplicatiilor sunt orientate spre platforme omogene.

Pentru a facilita integrarea unor sisteme dezvoltate separat, ıntr-un sin-gur mediu distribuit eterogen, OMG (Object Management Group – consortiu

Page 98: programare distribuita

98 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

cuprinzand peste 800 de firme) a elaborat standardul CORBA (Common Ob-ject Request Broker Arhitecture): un cadru de dezvoltare a aplicatiilor dis-tribuite ın medii eterogene.

La CORBA au aderat toate marile firme de software - cu exceptia Microsoft,firma care a dezvoltat propriul sau model DCOM (Distributed ComponentObject Model), incompatibil CORBA.

Aplicatia server se ınregistreaza ıntr-un Object Request Broker (ORB)

sub un nume simbolic - nume servici. Pe baza acestui nume de servici, unclient accesand ORB va avea acces la functiile oferite de aplicatia server.

ORB este un pachet de servicii, independent de aplicatii, dar care permitaplicatiilor sa interactioneze prin retea. ORB face parte din middleware – unintermediar ıntre softul de retea si cel de aplicatie.

Un ORB se poate executa local pe un singur calculator sau poate fi conectatcu oricare alt ORB din Internet, folosind protocolul IIOP -- Internet Inter

ORB Protocol, definit de CORBA 2.Distributia jdk ofera un ORB utilizabil ın Java sub forma unui servici

JNDI.CORBA face o separare ıntre interfata unui obiect si implementarea sa si

foloseste un limbaj neutru pentru definirea interfetelor: IDL -- Interface

Definition Language.

IDL permite realizarea descrierii de interfete independent de limbajul deprogramare si de sistemul de operare folosit. O interfata IDL defineste legaturadintre client si server.

4.2.1 Conexiunea RMI - CORBA

Firma Oracle - Sun Microsystems a dezvoltat o solutie prin care interfeteleRMI pot fi implementate pentru a putea fi accesate ca obiecte CORBA. Aceastaeste cunoscuta sub numele de solutia RMI-IIOP, concretizata printr-o serie depachete din distributia jdk. In acest fel nu mai este necesar utilizarea limba-jului IDL pentru descrierea interfetelor la distanta.

Instrumente necesare utilizarii solutiei RMI-IIOP:

• compilatorul rmic

Optiunea -iiop genereaza stub-ul si legatura (tie) din partea serverului.

Cu optiunea -d se specifica catalogul ın care aceste fisiere sunt scrise.

• serviciul ORB care asigura regasirea resurselor CORBA. Acest server selanseaza ın executie prin

Page 99: programare distribuita

4.2. CORBA 99

start orbd -ORBInitialPort [port ]

Programele orbd, rmic sunt ın distributia jdk.

Dezvoltarea unei aplicatii RMI-IIOP

Exemplificam prin aplicatia care implementeaza un serviciu de calcul a celuimai mare divizor comun a doua numere naturale. Etapele realizarii aplicatieisunt:

1. Elaborarea interfetei este identica cu cea a aplicatiei RMI.

2. Implementarea interfetei

1 package cmmdciiop ;2 import javax . rmi . PortableRemoteObject ;3 import cmmdc . ICmmdc ;4 import java . rmi . RemoteException ;

6 // Se ext inde c l a s a PortableRemoteObject7 // s i nu UnicastRemoteObject

9 pub l i c c l a s s CmmdcImpl extends PortableRemoteObject implements ICmmdc{10 // Const ructoru l c l a s e i11 pub l i c CmmdcImpl ( ) throws RemoteException {}

13 pub l i c long cmmdc( long a , long b ) { . . .}14 }

3. Realizarea programului server.

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

5 pub l i c c l a s s CmmdcServer {6 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ) {7 St r ing host=” l o c a l h o s t ” ;8 St r ing port=”1050” ;9 i f ( a rgs . length >0)

10 host=args [ 0 ] ;11 i f ( a rgs . length >1)12 port=args [ 1 ] ;13 t ry {14 // 1 : Crearea unei i n s t a n t e CmmdcImpl15 CmmdcImpl cmmdcRef = new CmmdcImpl ( ) ;

17 // 2 : I n r e g i s t r a r e a unei r e f e r i n t e a s e r v i c i u l u i18 // u t i l i z a n d JNDI API19 System . se tProper ty ( ” java . naming . f a c t o r y . i n i t i a l ” ,20 ”com . sun . j n d i . cosnaming . CNCtxFactory” ) ;

Page 100: programare distribuita

100 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

21 System . se tProper ty ( ” java . naming . prov ide r . u r l ” ,22 ” i i o p : //”+host+” : ”+port ) ;23 Context ctx = new I n i t i a l C o n t e x t ( ) ;24 ctx . reb ind ( ”CmmdcService” , cmmdcRef ) ;25 System . out . p r i n t l n ( ”Cmmdc S e r v e r : Ready . . . ” ) ;26 }27 catch ( Exception e ) {28 System . out . p r i n t l n ( ”CmmdcServer: ” + e . getMessage ( ) ) ;29 }30 }31 }

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

5. Generarea stub-ului cmmdc. ICmmdc Stub.class corespunzator interfeteiICmmdc si a fisierului Tie cmmdciiop. CmmdcImpl Tie.class corespunzatorclasei CmmdcImpl. Acestea se obtin ruland utilitarul rmic - din distrubutiaJava – cu optiunea -iiop

rmic -iiop cmmdciiop.CmmdcImpl

6. Pornirea serverului CORBA de regasire a serviciilor

start orbd -ORBInitialPort 1050

7. Lansarea serverului ın executie.

Activitatile legate de server se obtin prin ant cu fisierul build

1 <project name=” Server ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>Server a c t i o n s</description>

4 <property name=”path” location=” . . . ”/>

6 <property name=” package ” value=”cmmdciiop”/>7 <property name=” i n t e r f a c e−package ” value=”cmmdc” />8 <property name=” i n t e r f a c e−j a r ”9 location=”${path}/ i / pub l i c / c l a s s e s /cmmdc” />

10 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />11 <property name=” s e r v i c e−c l a s s ” value=”CmmdcServer” />12 <property name=” implementation−c l a s s ” value=”CmmdcImpl” />13 <property name=” host ” value=” l o c a l h o s t ” />14 <property name=” port ” value=”1050” />

16 <target name=” I n s t a l l ”>17 < !−− Create the time stamp −−>18 <tstamp/>19 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>20 <delete d i r=” s r c ”/>21 <mkdir d i r=” s r c ”/>22 <delete d i r=” pub l i c ”/>

Page 101: programare distribuita

4.2. CORBA 101

23 <mkdir d i r=” pub l i c ”/>24 <delete d i r=” pub l i c / c l a s s e s ”/>25 <mkdir d i r=” pub l i c / c l a s s e s ”/>26 </target>

28 <target name=” I n i t ”>29 <mkdir d i r=” s r c /${package}”/>30 <mkdir d i r=” pub l i c / c l a s s e s /${package}”/>31 <copy f i l e=”${ i n t e r f a c e−j a r }/${ ja r− f i l e }” t o d i r=” pub l i c / c l a s s e s ” />32 <unjar src=” pub l i c / c l a s s e s /${ ja r− f i l e }” dest=” pub l i c / c l a s s e s ” />33 <delete d i r=” pub l i c / c l a s s e s /META−INF” />34 </target>

36 <target name=”Compile” depends=” I n i t ”37 description=” compile the source ” >38 <javac s r c d i r=” s r c ” d e s t d i r=” pub l i c / c l a s s e s ”39 i n c l u d e s=”${package }\∗∗”40 classpath=” pub l i c \ c l a s s e s \${ ja r− f i l e }”41 inc ludeantrunt ime=” f a l s e ”/>42 <rmic classname=”${package } . ${ implementation−c l a s s }”43 sourcebase=” s r c ”44 i i o p=” yes ”45 base=” pub l i c / c l a s s e s ”46 classpath=” pub l i c / c l a s s e s ” />47 </target>

49 <target name=”Orb”>50 <exec executab l e=”orbd”>51 <arg l i n e=”−ORBInit ia lPort ${ port } −ORBInitialHost ${ host }” />52 </exec>53 </target>

55 <target name=” Server ” description=” Star t thr s e r v e r ” >56 <java classname=”${package } . ${ s e r v i c e−c l a s s }” f o rk=” true ”>57 <classpath>58 <pathelement location=” pub l i c / c l a s s e s /${ ja r− f i l e }” />59 <pathelement path=” pub l i c / c l a s s e s ” />60 </classpath>61 <arg l i n e=”${ host } ${ port }” />62 </ java>63 </target>64 </project>

orbd si aplicatia server se pot afla pe calculatoare distincte.

8. Editarea programului client.

1 package cmmdciiop ;2 import javax . rmi . PortableRemoteObject ;3 import javax . naming . Context ;4 import javax . naming . I n i t i a l C o n t e x t ;5 import java . u t i l . Scanner ;6 import cmmdc . ICmmdc ;

8 public class CmmdcClient {9 public stat ic void main ( St r ing args [ ] ) {

Page 102: programare distribuita

102 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

10 St r ing host=” l o c a l h o s t ” ;11 St r ing port=”1050” ;12 i f ( args . length >0)13 host=args [ 0 ] ;14 i f ( args . length >1)15 port=args [ 1 ] ;

17 Scanner scanner=new Scanner ( System . in ) ;18 System . out . p r i n t l n ( ”Primul numar : ” ) ;19 long m=Long . parseLong ( scanner . next ( ) ) ;20 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;21 long n=Long . parseLong ( scanner . next ( ) ) ;22 try {23 System . se tProper ty ( ” java . naming . f a c t o r y . i n i t i a l ” ,24 ”com . sun . j n d i . cosnaming . CNCtxFactory” ) ;25 System . se tProper ty ( ” java . naming . prov ide r . u r l ” ,26 ” i i o p :// ”+host+” : ”+port ) ;27 Context ctx = new I n i t i a l C o n t e x t ( ) ;

29 // STEP 1: Get the Object r e f e r e n c e from the Name Servc txe30 // using JNDI c a l l .31 Object o b j r e f = ctx . lookup ( ”CmmdcService” ) ;32 System . out . p r i n t l n ( ” C l i en t : Obtained a r e f . to Cmmdc s e r v e r . ” ) ;

34 // STEP 2: Narrow the o b j e c t r e f e r e n c e to the concre te type and35 // invoke the method .36 ICmmdc obj=(ICmmdc) PortableRemoteObject . narrow ( ob j r e f , ICmmdc . class ) ;37 long x=obj . cmmdc(m, n ) ;38 System . out . p r i n t l n ( ”Cmmdc=”+x ) ;39 }40 catch ( Exception e ) {41 System . out . p r i n t l n ( ” Exception ” + e . getMessage ( ) ) ;42 }43 }44 }

9. Compilarea si lansarea clientului ın executie. Clientul trebuie sa dispunade fisierul stub (cmmdc. ICmmdc Stub.class) si bineınteles de interfataICmmdc.jar.

Fisierul buildfile pentru executarea clientului:

1 <project name=” Cl i en t ” d e f a u l t=” I n s t a l l ” ba s ed i r=” . ”>2 <description>Cl i en t a c t i o n s</description>

4 <property name=”path” location=” . . . ”/>

6 <property name=” package ” value=”cmmdciiop”/>7 <property name=” i n t e r f a c e−j a r ”8 location=”${path}/ i / pub l i c / c l a s s e s /cmmdc” />9 <property name=” jar− f i l e ” va lue=”cmmdc . j a r ” />

10 <property name=” server−package ” value=”cmmdciiop” />11 <property name=” i n t e r f a c e−package ” value=”cmmdc” />12 <property name=” i n t e r f a c e−stub−l o c a t i o n ”13 location=”${path}/ s / pub l i c / c l a s s e s /${ i n t e r f a c e−package}” />14 <property name=”stub−c l a s s ” value=”∗ Stub . c l a s s ” />15 <property name=” host ” value=” l o c a l h o s t ” />

Page 103: programare distribuita

4.2. CORBA 103

16 <property name=” port ” value=”1050” />17 <property name=” c l i e n t−c l a s s ” value=”CmmdcClient” />

19 <target name=” I n s t a l l ”>20 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>21 <delete d i r=” s r c ”/>22 <mkdir d i r=” s r c ”/>23 <delete d i r=” c l a s s e s ”/>24 <mkdir d i r=” c l a s s e s ”/>25 </target>

27 <target name=” I n i t ”>28 < !−− Create the time stamp −−>29 <tstamp/>30 <mkdir d i r=” s r c /${package}”/>31 <mkdir d i r=” c l a s s e s /${package}”/>32 <delete d i r=” c l a s s e s /${ s e rver−package}” />33 <mkdir d i r=” c l a s s e s /${ s e rver−package}”/>34 <delete d i r=” c l a s s e s /${ i n t e r f a c e−package}” />35 <mkdir d i r=” c l a s s e s /${ i n t e r f a c e−package} ”/>36 <copy f i l e=”${ i n t e r f a c e−j a r }\${ ja r− f i l e }” t o d i r=” c l a s s e s ” />37 <copy t o d i r=” c l a s s e s /${ i n t e r f a c e−package}” >38 <f i l e s e t d i r=”${ i n t e r f a c e−stub−l o c a t i o n }”39 i n c l u d e s=”${ stub−c l a s s }” />40 </copy>41 <unjar src=” c l a s s e s /${ j a r− f i l e }” dest=” c l a s s e s ” />42 <delete d i r=” c l a s s e s /META−INF” />43 </target>

45 <target name=”Compile” depends=” I n i t ”46 description=” compile the source ” >47 <javac s r c d i r=” s r c ” d e s t d i r=” c l a s s e s ”48 i n c l u d e s=”${package }\∗ . java ” classpath=” c l a s s e s ”49 inc ludeantrunt ime=” f a l s e ” />50 </target>

52 <target name=”Run” depends=”Compile” description=”Run the c l i e n t ” >53 <java classname=”${package } . ${ c l i e n t−c l a s s }” f o rk=” true ”>54 <classpath>55 <pathelement location=” c l a s s e s /${ ja r− f i l e }” />56 <pathelement path=” c l a s s e s ” />57 </classpath>58 <arg l i n e=”${ host } ${ port }”/>59 </ java>60 </target>61 </project>

4.2.2 Aplicatie Java prin CORBA

Scopul acestei sectiuni este prezentarea dezvoltarii unei aplicatii pe bazaunei interfete bazat pe IDL.

Pentru dezvoltarea aplicatiilor ın limbajul de programare Java, translatareainterfetei IDL ın Java se realizeaza cu utilitarul idlj din distributia jdk.

Corespondenta ıntre entitatile IDL si Java este data ın Tabelul 4.1

Page 104: programare distribuita

104 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Tip IDL Tip Java

module packageboolean booleanchar, wchar charoctet bytestring, wstring java.lang.Stringshort, unsigned short shortlong, unsigned long intlong long, unsigned long long longfloat floatdouble doublefixed java.math.BigDecimalenum, struct, union classsequence, array arrayinterface (non-abstract) signature interface,

operations interface,helper class, holder class

Any org.omg.CORBA.Any

Table 4.1: Entitati IDL si Java

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

Model cu server temporal

Exemplificam dezvoltarea unei aplicatii distribuite CORBA ın cazul ın careserviciul pus la dispozitie de server este calculul celui mai mare divizor comuna doua numere naturale.

Dezvoltarea unei aplicatii distribuite CORBA cu mediul nativ Java pre-supune parcurgerea urmatoarelor pasi:

1. Realizarea interfetei IDL care ınseamna

(a) Editarea programului de interfata:

1 module CmmdcApp{2 interface Cmmdc{3 long long cmmdc( in long long a , in long long b ) ;4 } ;5 } ;

Page 105: programare distribuita

4.2. CORBA 105

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

Cmmdc va fi numele interfetei utilizat de un client si implementatde server. Serviciul contine o singura metoda cmmdc.

(b) Translatarea interfetei ın Java

idlj -fall Cmmdc.idl

Programul idlj creaza un subcatalog CmmdcApp cu un pachet Java CmmdcAppcontinand fisierele:

• Cmmdc.java

• CmmdcPOA.java ;

• CmmdcOperations.java;

• CmmdcStub.java;

• CmmdcHelper.java;

• CmmdcHolder.java.

2. Realizarea programelor server. Punem ın evidenta programul servantCmmdcImpl.java ce implementeaza interfata Cmmdc.

1 import CmmdcApp . ∗ ;2 import org . omg .CORBA.ORB;

4 pub l i c c l a s s CmmdcImpl extends CmmdcPOA {5 p r i v a t e ORB orb ;

7 pub l i c CmmdcImpl(ORB orb ){8 t h i s . orb = orb ;9 }

11 pub l i c long cmmdc( long a , long b ) { . . .}12 }

si programul CmmdcServer.java, care ınscrie ın registrul ORB referinteleservantului. Activitatile ce trebuie ıntreprinse sunt declarate prin comen-tarii ın textul sursa al programului

1 import CmmdcApp . ∗ ;2 import org . omg . CosNaming . NameComponent ;3 import org . omg . CosNaming . NamingContextExtHelper ;4 import org . omg . CosNaming . NamingContextExt ;5 import org . omg .CORBA.ORB;6 import org . omg . Por tab l eServer .POA;7 import org . omg . Por tab l eServer . POAHelper ;

Page 106: programare distribuita

106 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

9 pub l i c c l a s s CmmdcServer {10 pub l i c s t a t i c void main ( S t r ing args [ ] ) {11 t ry {12 // Crease s i i n i t i a l i z a r e ORB13 ORB orb = ORB. i n i t ( args , n u l l ) ;

15 // Obtinerea unei r e f e r i n t e POA s i16 // a c t i v a r e a g e s t i o n a r u l u i POAManager17 POA rootPOA =18 POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”RootPOA” ) ) ;19 rootPOA . the POAManager ( ) . a c t i v a t e ( ) ;

21 // Crearea unui se rvant22 CmmdcImpl cmmdcImpl = new CmmdcImpl( orb ) ;

24 // Obtinerea unei r e f e r i n t e pentru se rvant25 org . omg .CORBA. Object r e f=rootPOA . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ;26 Cmmdc h r e f = CmmdcHelper . narrow ( r e f ) ;

28 // Obtinerea s e r v i c i u l u i NameService29 org . omg .CORBA. Object objRef =30 orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;31 NamingContextExt ncRef=NamingContextExtHelper . narrow ( objRef ) ;

33 // Legarea s e r v a n t u l u i in NameService34 St r ing name = ”CmmdcService” ;35 NameComponent path [ ] = ncRef . to name (name ) ;36 ncRef . reb ind ( path , h r e f ) ;

38 System . out . p r i n t l n ( ”CmmdcServer ready and wai t ing . . . ” ) ;

40 // Gata pentru s a t i s f a c e r e a c l i e n t i l o r41 orb . run ( ) ;42 }43 catch ( Exception e ) {44 System . e r r . p r i n t l n ( ”ERROR: ” + e . getMessage ( ) ) ;45 }46 System . out . p r i n t l n ( ”CmmdcServer Ex i t ing . . . ” ) ;47 }48 }

Aceasta clasa corespunde unui sablon de programare adaptat exempluluitratat. In acest caz numele serviciului inregistrat ın ORB va fi Cmmdc-Service. Evidenta numelor serviciilor CORBA ınregistrate ın ORB estefacuta de serviciul NameService.

3. Realizarea programului client CmmdcClient.java:

1 import CmmdcApp . ∗ ;2 import org . omg . CosNaming . NamingContextExtHelper ;3 import org . omg . CosNaming . NamingContextExt ;4 import org . omg .CORBA.ORB;5 import java . u t i l . Scanner ;

7 pub l i c c l a s s CmmdcClient{8 s t a t i c Cmmdc cmmdc ;

Page 107: programare distribuita

4.2. CORBA 107

10 pub l i c s t a t i c void main ( S t r ing args [ ] ) {11 t ry {12 // c r ea r ea s i i n i t i a l i z a r e a unui r eprezentant ORB13 ORB orb = ORB. i n i t ( args , n u l l ) ;

15 // obt ine r ea unei r e f e r i n t e pentru s e r v i c i u l denumir i l o r16 // s e r v i c i i l o r i n r e g i s t r a t e17 org . omg .CORBA. Object objRef =18 orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;19 NamingContextExt ncRef = NamingContextExtHelper . narrow ( objRef ) ;

21 // obt ine r ea unei r e f e r i n t e l a s e r v i c i u l d o r i t22 St r ing name = ”CmmdcService” ;23 cmmdc = CmmdcHelper . narrow ( ncRef . r e s o l v e s t r (name ) ) ;

25 System . out . p r i n t l n ( ”Obtained a handle on s e r v e r o b j e c t : ” +26 cmmdc ) ;27 Scanner scanner=new Scanner ( System . in ) ;28 long m, n ;29 System . out . p r i n t l n ( ”m=” ) ;30 m=scanner . nextLong ( ) ;31 System . out . p r i n t l n ( ”n=” ) ;32 n=scanner . nextLong ( ) ;33 System . out . p r i n t l n ( ”Cmmdc=”+cmmdc . cmmdc(m, n ) ) ;34 }35 catch ( Exception e ) {36 System . out . p r i n t l n ( ”ERROR : ” + e ) ;37 e . pr intStackTrace ( System . out ) ;38 }39 }40 }

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

Programele se compileaza

javac CmmdcApp\*.java

4. Pornirea serviciului de intregistrare a numelor cu programul orbd.exedin distributia jdk.

start orbd -ORBInitialHost localhost -ORBInitialPort 1050

5. Pornirea programului server prin

start java CmmdcServer -ORBInitialHost localhost -ORBInitialPort 1050

6. Lansarea programului client prin

Page 108: programare distribuita

108 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

java CmmdcClient -ORBInitialHost localhost -ORBInitialPort 1050

Model cu server persistent

Se considera aceasi interfata Cmmdc.idl.Partea de server este alcatuita din clasa servant CmmdcImpl.java care im-

plementeaza interfata Cmmdc -prezentat ın sectiunea anterioara si clasa Per-sistentServer care asigura

• legatura cu serviciile ORB;

• accesul la clasa servantului.

1 import java . u t i l . P r o p e r t i e s ;2 import org . omg .CORBA.ORB;3 import org . omg .CORBA. Po l i cy ;4 import org . omg . CosNaming . NamingContextExtHelper ;5 import org . omg . CosNaming . NamingContextExt ;6 import org . omg . CosNaming . NameComponent ;7 import org . omg . Por tab l eServer .POA;8 import org . omg . Por tab l eServer . POAHelper ;9 import org . omg . Por tab l eServer . L i f e spanPo l i cyVa lue ;

11 pub l i c c l a s s P e r s i s t e n t S e r v e r {12 pub l i c s t a t i c void main ( St r ing args [ ] ) {13 P r o p e r t i e s p r o p e r t i e s = System . g e t P r o p e r t i e s ( ) ;14 p r o p e r t i e s . put ( ” org . omg .CORBA. ORBInitialHost ” , ” l o c a l h o s t ” ) ;15 p r o p e r t i e s . put ( ” org . omg .CORBA. ORBInit ia lPort ” , ”1050” ) ;16 t ry {17 // Pas 1 : Crease s i i n i t i a l i z a r e ORB18 ORB orb = ORB. i n i t ( args , p r o p e r t i e s ) ;

20 // Pas 2 : Crearea unui se rvant21 CmmdcImpl cmmdcImpl = new CmmdcImpl( orb ) ;

23 // Pas 3 : Obtinerea unei r e f e r i n t e POA s i24 // a c t i v a r e a g e s t i o n a r u l u i POAManager25 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗26 // Pas 3−1 : Obtinerea r a d a c i n i i rootPOA27 POA rootPOA =28 POAHelper . narrow ( orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”RootPOA” ) ) ;29 // Pas 3−2 : Create s e c u r i t a t i i P e r s i s t e n t Po l i cy30 Pol i cy [ ] p e r s i s t e n t P o l i c y = new Po l i cy [ 1 ] ;31 p e r s i s t e n t P o l i c y [ 0 ] = rootPOA . c r e a t e l i f e s p a n p o l i c y (32 Li f e spanPo l i cyVa lue .PERSISTENT) ;33 // Pas 3−3 : Crearea o b i e c t u l u i POA cu s e c u r i t a t e a the P e r s i s t e n t Po l i cy34 POA persistentPOA=rootPOA . create POA ( ”childPOA” , nu l l , p e r s i s t e n t P o l i c y ) ;35 // Pas 3−4 : Act ivarea managerului PersistentPOA POAManager ,36 persistentPOA . the POAManager ( ) . a c t i v a t e ( ) ;37 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

39 // Pas 4 : Asoc i e rea s e r v a n t u l u i cu PersistentPOA

Page 109: programare distribuita

4.2. CORBA 109

40 persistentPOA . a c t i v a t e o b j e c t ( cmmdcImpl ) ;

42 // Pas 5 : Fixarea c o n t e x t u l u i RootNaming s i43 // l e g a r e a de numele s e r v a n t u l u i44 // Numele s e r v i c i u l u i de nume : ’ NameService ’45 // Numele s e r v a n t u l u i ’ PersistentCmmdcServer ’

47 org . omg .CORBA. Object objRef=48 orb . r e s o l v e i n i t i a l r e f e r e n c e s ( ”NameService” ) ;49 NamingContextExt rootContext=NamingContextExtHelper . narrow ( objRef ) ;50 NameComponent [ ] nc = rootContext . to name ( ” PersistentCmmdcServer ” ) ;51 rootContext . reb ind ( nc , persistentPOA . s e r v a n t t o r e f e r e n c e ( cmmdcImpl ) ) ;

53 // Pas 6 : Gata pentru s a t i s f a c e r e a c l i e n t i l o r54 orb . run ( ) ;55 }56 catch ( Exception e ) {57 System . e r r . p r i n t l n ( ” Exception in P e r s i s t e n t Server Startup ”+58 e . getMessage ( ) ) ;59 }60 }61 }

Programul client

1 import CmmdcApp . ∗ ;2 import org . omg .CORBA.ORB;3 import java . u t i l . Scanner ;

5 pub l i c c l a s s P e r s i s t e n t C l i e n t {6 pub l i c s t a t i c void main ( S t r ing args [ ] ) {7 St r ing host=” l o c a l h o s t ” ;8 St r ing port=”1050” ;9 i f ( a rgs . length >0)

10 host=args [ 0 ] ;11 i f ( a rgs . length >1)12 port=args [ 1 ] ;13 t ry {14 // Pas 1 : I n i t i a l i z a r e ORB15 ORB orb = ORB. i n i t ( args , n u l l ) ;

17 // Pas 2 : Rezolvarea p e r s i s t e n t e i18 // S e r v i c i u l NameService ru l ea za pe host cu por tu l port19 // Numele s e r v i c i u l u i c e rut l u i NameService e s t e20 // ” PersistentCmmdcServer ”21 org . omg .CORBA. Object obj = orb . s t r i n g t o o b j e c t (22 ” corbaname: : ”+host+” : ”+port+”#PersistentCmmdcServer ” ) ;23 Cmmdc cmmdc=CmmdcHelper . narrow ( obj ) ;

25 // Pas 3 : U t i l i z a r e a s e r v i c i u l u i26 Scanner scanner=new Scanner ( System . in ) ;27 System . out . p r i n t l n ( ” Ca l l i ng P e r s i s t e n t Server . . ” ) ;28 i n t m, n , r ;29 System . out . p r i n t l n ( ”m=” ) ;30 m=scanner . next Int ( ) ;31 System . out . p r i n t l n ( ”n=” ) ;32 n=scanner . next Int ( ) ;33 System . out . p r i n t l n (cmmdc . cmmdc(m, n ) ) ;34 }

Page 110: programare distribuita

110 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

35 catch ( Exception e ) {36 System . e r r . p r i n t l n ( ” Exception in P e r s i s t e n t C l i e n t . java . . . ” +37 e . getrMessage ( ) ) ;38 }39 }40 }

Serverul trebuie sa fie pe acelasi calculator pe care ruleaza orbd. Exe-cutarea aplicatiei presupune:

1. Pornirea serviciului de intregistrare a numelor cu programul orbd.exedin distributia jdk.

orbd -ORBInitialPort 1050 -serverPollingTime 200

2. Activarea serverului:

(a) Se lanseaza utilitarul servertoolservertool -ORBInitialPort 1050

(b) Se ınregistreaza serverul ımpreuna cu numele serviciului pe care ılındeplineste:

servertool > register -server PersistentServer

-applicationName PersistentCmmdcServer

-classpath cale_catre_fisierele_server\

Indeplinirea actiunii de ınregistrare a serverului este indicat printr-unmesaj de forma server registered (serverid=257).

Alte comenzi servertool

Comanda Semnificatie

servertool> shutdown -serverid 257 Oprirea serviciuluiservertool> unregister -serverid 257 Stergerea serviciului

servertool> quit Inchiderea utilitaruluiservertool> help

Observatie 4.2.1 Daca se utilizeaza referinta

c:\Program Files\Java\jdk1.7.0 *\bin

Page 111: programare distribuita

4.2. CORBA 111

ın variabila de sistem PATH (ın loc de c:\Progra 1\Java\jdk1.7.0 *\bin)atunci apelarea serviciilor orbd si servertool se va face prin

c:\Progra~1\Java\jdk1.7.0_*\bin\orbd -ORBInitialPort 1050 -serverPollingTime 200

c:\Progra~1\Java\jdk1.7.0_*\bin\servertool -ORBInitialPort 1050

3. Executarea clientului

java PersistentClient [hostORB [portORB]]

Intrebari recapitulative

1. Precizati abrevierea RMI.

2. Care sunt componentele unei aplicatii client-server bazat pe RMI?

3. Cate si care sunt entitatile care participa la executia unei aplicatii client-server bazat pe RMI?

4. Care este rolul ındeplinit de (rmi)registry?

5. Ce asigura sablonul de programare Fabrica de obiecte ın RMI?

6. Ce asigura sablonul de programare Callback ın RMI?

7. Explicati caracterul sincron al comunicarii ın RMI.

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

9. Care sunt componentele unei aplicatii client server bazat pe CORBA?

10. Cate si care sunt entitatile care participa la executia unei aplicatii client-server bazat pe CORBA?

11. Care este ideea solutiei CORBA pentru asigurarea interoperabilitatiiıntre client si server realizate ın limbaje de programare diferite.

12. Explicati caracterul sincron al comunicarii ın CORBA.

13. Ce ofera RMI-IIOP ?

14. Precizati modelele de aplicatii CORBA prezentate ın curs si diferentadintre ele din punctul de vedere al executiei.

Page 112: programare distribuita

112 CAPITOLUL 4. INVOCAREA PROCEDURILOR LA DISTANTA

Page 113: programare distribuita

Capitolul 5

Mesaje ın Java

Comunicatia prin apelul la distanta - inclusiv RMI - este sincron: pro-gramul apelant se blocheaza si asteapta ca metoda apelata sa se termine si safurnizeze rezultatul cerut. Cu alte cuvinte apelul de procedura la distanta cereatat clientului cat si serverului sa fie simultan disponibile.

Comunicatiile asincrone1 ıntre programe permit realizarea unor sisteme deprograme cu un grad mult mai scazut de cuplare, ın sensul ca lansarea uneicereri si receptionarea rezultatului se pot executa ın momente diferite de timp.Asemenea aplicatii se pot realiza prin comunicatii de mesaje, mesaje care suntretinute de un intermediar (serviciu de mesagerie, server, broker, messagingmiddleware).

5.1 Java Message Service (JMS)

JMS defineste un cadru de programare Java (API) pentru realizarea aplicatiilorbazate pe comunicatii asincrone.

Prezentarea se bazeaza pe interfata de programare (API) JMS-2, pentrucare exista implementarea de referinta Open Message Queue 5.* de la Oracle.

Pentru interfata de programare (API) JMS-1, exista mai multe imple-mentari JMS, dintre care semnalam:

• Open Message Queue *

• apache ActiveMQ

• apache qpid

1In acceptiunea din acest capitol.

113

Page 114: programare distribuita

114 CAPITOLUL 5. MESAJE IN JAVA

Apache-qpid implementeaza protocolul Advanced Message Queue Protocol(AMQP) referitor la modul de reprezentare a datelor ıntr-un mesaj. Scopulprotocolului este asigurarea interoperabilitatii ıntre aplicatii de mesagerie re-alizate ın diferite limbaje de programare. Versiunea Java a lui apache-qpid areın vedere interfata de programare JMS 1.

O aplicatie JMS este alcatuita din

• un furnizor JMS (provider JMS) : un sistem de mesagerie ce imple-menteaza specificatiile JMS;

• client JMS : aplicatie Java care trimite si receptioneaza mesaje;

• mesaje : obiecte utilizate ın schimbul de informatii de clienti JMS;

• obiecte administrator - obiecte (resurse) create de administrator pentrua fi utilizate de clientii JMS, precum

– fabrica de conexiuni,

– obiectele destinatie pentru retinerea mesajelor.

Aplicatiile dezvoltate pe baza JMS 1 functioneaza si ın cazul utilizarii unuifurnizor de servicii realizat pentru JMS-2. In esenta, JMS-2 simplifica progra-marea fata de JMS-1.

Modele de comunicatie:

• Comunicatii punctuale : Un mesaj este generat de un producator (exped-itor) si la care va avea acces un singur consumator (destinatar). Mesajuleste depus ıntr-o coada, de unde este preluat de catre consumatorul cares-a legat de coada. Daca de coada nu se leaga nici un consumator, atuncimesajul este pastrat ın coada.

• Comunicatii axate pe subiect (topic) : Mesajele sunt depuse (publicate)ın destinatii specifice subiectului. Consumatorii ce au subscris la acelsubiect au acces la mesajele respective. Mai multi producatori pot generamesaje specifice unui subiect, mesaje care pot fi accesate de consumatoriicare au subscris subiectului.

Consumatorii abonati pe un subiect pot fi

– abonat simplu - valabi, adica are acces la mesajele emise dupa mo-mentul abonarii, pe durata conexiunii la furnizorul de servicii JMS;

– abonat permanent - valabil si dupa o ıntrerupere a conexiunii lafurnizorul de servicii JMS;

Page 115: programare distribuita

5.2. OPEN MESSAGE QUEUE 5 115

– abonat partajat - mai multi abonati utilizeaza aceasi conexiune;

– abonat partajat si permanent.

Structura unui mesaj Un mesaj este alcatuit din

• Antet (header) : contine informatii pentru identificarea destinatiei cat sipentru identificarea mesajului.

• Proprietati : au caracter optional si sunt sub forma (nume, valoare).Proprietatile ajuta consumatorii sa selecteze mesajele.

• Corpul mesajului : optional. Potrivit specificatiilor JMS exista 6 tipuride mesaje.

– javax.jms.Message : mesaj fara corp;

– javax.jms.StreamMessage : corpul mesajului contine un flux Javade date de tip predefinit;

– javax.jms.ByteMessage :

– javax.jms.MapMessage : corpul mesajului contine o familie deperechi (nume, valoare);

– javax.jms.TextMessage : corpul mesajului contine un string;

– javax.jms.ObjectMessage : corpul mesajului contine un obiectserializat.

• Atasament (optional).

5.2 Open Message Queue 5

Instalarea variantei de sine statatoare. In mediul Windows, ın functiede resursa descarcata instalarea consta din:

• Se dezarhiveaza fisierul openmq*-binary-Windows.zip

• Se fixeaza atributele fisierului etc\mq\imqenv.conf.

Lansarea serviciului JMS. Orice aplicatie JMS necesita functionareaserviciului JMS. Serviciul JMS se instaleaza prin

imqbrokerd

Functionarea corecta este indicata prin mesajul

Page 116: programare distribuita

116 CAPITOLUL 5. MESAJE IN JAVA

imqbroker@hostname:7676 ready

Daca se doreste schimbarea portului atunci se foloseste optiunea -port

port.Pe un calculator pot coexista mai multe servicii JMS doar daca folosesc

porturi distincte si au nume diferite. In acest caz, lansarea unui nou serviciuse face prin

imqbrokerd -port port -name nameCu utilitarul imqsvcadmin putem

• dezinstala : imqsvcadmin remove

• verifica : imqsvcadmin query

• instala : imqsvcadmin install

serviciul JMS ca serviciu Windows. Dezinstalarea si instalarea are efect odatacu repornirea calculatorului.

Compilarea si executarea unui program necesita completarea variabileisistem classpath cu fisierele

• JMS HOME\lib\jms.jar

• JMS HOME\lib\imq.jar

5.3 Elemente de programare - JMS-2

Semnalam doua modalitati de programare / generare / regasire a obiecteloradministrator:

• Programat: obiectele administrator se instantiaza prin API-ul oferit deprodusul informatic;

• Prin JNDI. Codul sursa al programelor este independent de furnizorulde servicii de mesagerie. Elementele specifice se declara ın fisiere deproprietati.

5.3.1 Modul programat: Trimiterea unui mesaj

Trimiterea unui mesaj necesita:

1. Generarea obiectelor administrator

Page 117: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 117

(a) Fabrici de conexiuni.

com.sun.messaging.ConnectionFactory cf=

new com.sun.messaging.ConnectionFactory();

Clasa com.sun.messaging.ConnectionFactory are descendentii QueueConnectionFactory,TopicConnectionFactory.

(b) Obiectul destinatie. In cazul comunicatiilor punctuale obiectul destinatieeste de tip javax.jms.Queue, iar crearea se face prin

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

Pentru comunicatii axate pe subiect, obiectul destinatie, de tipjavax.jms.Topic se instantiaza prin

Topic t=new com.sun.messaging.Topic(subiect);

2. Instantierea unui obiect de tip javax.jms.JMSContext

JMSContext ctx=cf.createContext();

In final, contextul se ınchide

ctx.close();

Prin intermediul unui obiect de tip JMSContext se obtin producatorii demesaje, de tip javax.jms.JMSProducer, dar si consumatorii de mesaje,de tip javax.jms.JMSConsumer.

3. Instantierea unui producator de mesaje

JMSProducer producer=ctx.createProducer();

Crearea si expedierea mesajelor se realizeaza cu metodele claseiJMSProducer

• JMSProducer send(Destination destination, byte[] body)

• JMSProducer send(Destination destination, Serializable body)

• JMSProducer send(Destination destination, Map<String,Object>body)

• JMSProducer send(Destination destination, String body)

Page 118: programare distribuita

118 CAPITOLUL 5. MESAJE IN JAVA

• JMSProducer send(Destination destination, Message message)

Un obiect care implementeaza interfata javax.jms.Message se obtineprin ctx.createMessage().

Exemplul 5.3.1 Clasa urmatoare genereaza ıntr-un fir de executie, un numarde mesaje de tip TextMessage ıntr-o comunicatie punctuala. Sfarsitul expe-dierii mesajelor se indica prin generarea unui mesaj de tip Message. Numarulmesajelor este indicat de un parametru al constructorului.

1 import javax . jms . Queue ;2 import javax . jms . JMSContext ;3 import javax . jms . JMSProducer ;

5 public class MsgSenderT extends Thread{6 int n ;7 St r ing queueName ;

9 MsgSenderT ( St r ing queueName , int n){10 this . queueName=queueName ;11 this . n=n ;12 }

14 public void run ( ){15 try{16 com . sun . messaging . QueueConnectionFactory c f=17 new com . sun . messaging . QueueConnectionFactory ( ) ;18 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;19 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);20 Queue q=new com . sun . messaging . Queue ( queueName ) ;21 JMSContext ctx=c f . c reateContext ( ) ;22 JMSProducer producer=ctx . c reateProducer ( ) ;

24 for ( int i =0; i<n ; i ++){25 producer . send (q , ” He l lo ”+i ) ;26 }27 producer . send (q , ctx . createMessage ( ) ) ;28 ctx . c l o s e ( ) ;29 }30 catch ( Exception e ){31 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;32 }33 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;34 }35 }

5.3.2 Receptia sincrona a unui mesaj

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

1. Generarea obiectelor administrator.

Page 119: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 119

2. Instantierea unui obiect de tip javax.jms.JMSContext.

3. Instantierea unui consumator de mesaje

JMSConsumer consumer = ctx.createConsumer(q);

Receptia unui mesaj se obtine cu una din metode

• Message receive()

Receptie blocanta.

• Message receive(long timeout)

Receptie ıntr-un interval de timp.

• Message receiveNoWait()

Receptie neblocanta.

Exemplul 5.3.2 Receptia de tip sincron a mesajelor ıntr-un fir de executieeste efectuat de clasa urmatoare:

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Queue ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;

7 public class SyncMsgReceiverT extends Thread{8 St r ing queueName ;

10 SyncMsgReceiverT ( St r ing queueName){11 this . queueName=queueName ;12 }

14 public void run ( ){15 try{16 com . sun . messaging . QueueConnectionFactory c f=17 new com . sun . messaging . QueueConnectionFactory ( ) ;18 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;19 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);20 Queue q=new com . sun . messaging . Queue ( queueName ) ;21 JMSContext ctx=c f . c reateContext ( ) ;22 JMSConsumer consumer = ctx . createConsumer ( q ) ;23 Message msg=null ;24 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){25 i f (msg instanceof TextMessage ){26 TextMessage m=(TextMessage )msg ;27 System . out . p r i n t l n (m. getText ( ) ) ;28 }29 else30 break ;31 }

Page 120: programare distribuita

120 CAPITOLUL 5. MESAJE IN JAVA

32 ctx . c l o s e ( ) ;33 }34 catch ( Exception e ){35 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;36 }37 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;38 }39 }

Exemplul 5.3.3 Trimiterea si receptia mesajelor se face prin aplicatia

1 class MsgHelloT{2 public stat ic void main ( St r ing [ ] a rgs ){3 int n=3;4 St r ing queueName=”MyQueue” ;5 i f ( args . length >0)6 queueName=args [ 0 ] ;7 i f ( args . length >1)8 n=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;9 MsgSenderT sender=new MsgSenderT (queueName , n ) ;

10 SyncMsgReceiverT r e c e i v e r =new SyncMsgReceiverT ( queueName ) ;11 r e c e i v e r . s t a r t ( ) ;12 sender . s t a r t ( ) ;13 }14 }

5.3.3 Receptia asincrona a unui mesaj

Receptia asincrona a mesajelor presupune implementarea interfeteiMessageListener ce contine o singura metoda

public void onMessage(Message mesaj);

care fixeaza prelucrarea mesajului.

Metoda setMessageListener(MessageListener obj) a claseiJMSConsumer fixeaza obiectul ce implementeaza interfata Messagelistener.

Astfel, caracterul asincron consta din faptul ca mesajele sunt preluate deascultator - adica obiectul ce implementeaza interfata MessageListener si nude clientul JMS.

Exemplul 5.3.4 In ideea exemplelor anterioare, un consumator de tip asin-cron al mesajelor este dat ın clasa urmatoare:

Page 121: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 121

1 import javax . jms . MessageConsumer ;2 import javax . jms . Queue ;3 import javax . jms . JMSContext ;4 import javax . jms . JMSConsumer ;

6 public class AsyncMsgReceiverT extends Thread{7 St r ing queueName ;

9 AsyncMsgReceiverT ( St r ing queueName){10 this . queueName=queueName ;11 }

13 public void run ( ){14 try{15 com . sun . messaging . QueueConnectionFactory c f=16 new com . sun . messaging . QueueConnectionFactory ( ) ;17 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;18 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);19 Queue q=new com . sun . messaging . Queue ( queueName ) ;20 JMSContext ctx=c f . c reateContext ( ) ;21 JMSConsumer consumer = ctx . createConsumer ( q ) ;

23 TextLi s tener t e x t L i s t e n e r=new TextLi s tener ( ) ;24 consumer . s e tMessageL i s t ene r ( t e x t L i s t e n e r ) ;25 t e x t L i s t e n e r . run ( ) ;26 ctx . c l o s e ( ) ;27 }28 catch ( Exception e ){29 System . out . p r i n t l n ( e . getMessage ( ) ) ;30 }31 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;32 }33 }

ımpreuna cu ascultatorul

1 import javax . jms . MessageListener ;2 import javax . jms . JMSException ;3 import javax . jms . TextMessage ;4 import javax . jms . Message ;

6 public class TextLi s tener implements MessageListener {7 boolean s f a r s i t=fa l se ;8 public void onMessage ( Message message ){9 i f ( message instanceof TextMessage ){

10 TextMessage m=(TextMessage ) message ;11 try{12 St r ing s=m. getText ( ) ;13 System . out . p r i n t l n ( s ) ;14 }15 catch ( JMSException e ){16 System . out . p r i n t l n ( e . getMessage ( ) ) ;17 }18 }19 else20 s f a r s i t=true ;21 }

23 public void run ( ){

Page 122: programare distribuita

122 CAPITOLUL 5. MESAJE IN JAVA

24 while ( ! s f a r s i t ){25 try{26 Thread . s l e e p ( 1 ) ;27 }28 catch ( Inter ruptedExcept ion e ){}29 } ;30 }31 }

5.3.4 Publicarea mesajelor

Publicarea mesajelor corespunzatoare unui subiect se face asemanator cutransmiterea mesajelor ın comunicatia punctuala, dar folosind instante aleclaselor dedicate acestui tip de comunicatie.

Exemplul 5.3.5

1 import javax . jms . Topic ;2 import javax . jms . JMSContext ;3 import javax . jms . JMSProducer ;

5 public class MsgPublisherT extends Thread{6 int n ;7 St r ing s u b i e c t ;

9 MsgPublisherT ( St r ing sub i ec t , int n){10 super ( ) ;11 this . n=n ;12 this . s u b i e c t=s u b i e c t ;13 }

15 public void run ( ){16 try{17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);21 Topic t=new com . sun . messaging . Topic ( s u b i e c t ) ;22 JMSContext ctx=c f . c reateContext ( ) ;23 JMSProducer producer=ctx . c reateProducer ( ) ;24 for ( int i =0; i<n ; i ++){25 producer . send ( t , ” He l lo ”+i ) ;26 }27 producer . send ( t , ctx . createMessage ( ) ) ;28 ctx . c l o s e ( ) ;29 }30 catch ( Exception e ){31 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;32 }33 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;34 }35 }

Page 123: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 123

5.3.5 Abonare si receptia mesajelor

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

JMSConsumer consumer = ctx.createConsumer(t);

Subscrierea este valabila atata timp cat clientul este activ. Pentru a primitoate mesajele specifice subiectului, chiar si cand clientul este inactiv, acestatrebuie sa fie durabil, adica crearea consumatorului sa se faca prin

ctx.setClientID(clientID);

JMSConsumer consumer = ctx.createDurableConsumer(t,clientName);

In ambele cazuri, clientul primeste doar mesajele publicate din momentul sub-scrierii.

Exemplul 5.3.6

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Topic ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;

7 public class MsgSubscriberT extends Thread{8 St r ing s u b i e c t ;9 St r ing c l i e n t I D ;

10 St r ing cl ientName ;

12 MsgSubscriberT ( St r ing sub iec t , S t r ing c l i en t ID , S t r ing cl ientName ){13 this . s u b i e c t=s u b i e c t ;14 this . c l i e n t I D=c l i e n t I D ;15 this . c l ientName=clientName ;16 }

18 public void run ( ){19 try{20 com . sun . messaging . TopicConnectionFactory c f=21 new com . sun . messaging . TopicConnectionFactory ( ) ;22 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;23 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);24 Topic t=new com . sun . messaging . Topic ( s u b i e c t ) ;25 JMSContext ctx=c f . c reateContext ( ) ;26 ctx . s e tC l i en t ID ( c l i e n t I D ) ;27 JMSConsumer consumer = ctx . createDurableConsumer ( t , cl ientName ) ;

29 Message msg=null ;30 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){31 i f (msg instanceof TextMessage ){32 TextMessage m=(TextMessage )msg ;33 System . out . p r i n t l n ( cl ientName+” r e c e i v e d : ”+m. getText ( ) ) ;34 }

Page 124: programare distribuita

124 CAPITOLUL 5. MESAJE IN JAVA

35 else36 break ;37 }38 ctx . c l o s e ( ) ;39 }40 catch ( Exception e ){41 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;42 }43 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;44 }45 }

Apelarea celor doua activitati se face prin

Exemplul 5.3.7

1 class MsgPS{2 public stat ic void main ( St r ing [ ] a rgs ){3 St r ing s u b i e c t=”JMS” ;4 int n=3,noAbonati =3;5 i f ( args . length >0)6 s u b i e c t=args [ 0 ] ;7 i f ( args . length >1)8 n=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;9 MsgPublisherT p u b l i s h e r=new MsgPublisherT ( sub iec t , n ) ;

10 MsgSubscriberT [ ] abonat=new MsgSubscriberT [ noAbonati ] ;11 p u b l i s h e r . s t a r t ( ) ;12 for ( int i =0; i<noAbonati ; i ++){13 abonat [ i ]=new MsgSubscriberT ( sub i ec t , ”ID”+i , ” id ”+i ) ;14 abonat [ i ] . s t a r t ( ) ;15 }16 }17 }

5.3.6 Cazul abonatului partajat

Mai multi client JMS folosesc aceasi conexiune iar abonamentul se identificaprintr-un nume (String). Dintre acesi clienti doar unul receptioneaza mesajelecare sunt emise dupa momentul abonarii.

Exemplul 5.3.8

Fata de exemplul anterior se vor expedia mai multe mesaje de tip Message.

1 import javax . jms . Topic ;2 import javax . jms . JMSContext ;3 import javax . jms . JMSProducer ;

5 public class MsgPublisherT extends Thread{6 int n ;7 St r ing s u b i e c t ;

Page 125: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 125

9 MsgPublisherT ( St r ing sub i ec t , int n){10 super ( ) ;11 this . n=n ;12 this . s u b i e c t=s u b i e c t ;13 }

15 public void run ( ){16 try{17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);21 Topic t=new com . sun . messaging . Topic ( s u b i e c t ) ;22 JMSContext ctx=c f . c reateContext ( ) ;23 JMSProducer producer=ctx . c reateProducer ( ) ;24 for ( int i =0; i<n ; i ++){25 producer . send ( t , ” He l lo ”+i ) ;26 }27 for ( int i =0; i<n ; i++)producer . send ( t , ctx . createMessage ( ) ) ;28 ctx . c l o s e ( ) ;29 }30 catch ( Exception e ){31 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;32 }33 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;34 }35 }

Pentru a folosi aceasi conexiune receptia mesajelor este programata ın douaclase :

• Se instantiaza o fabrica de conexiuni si un numar de clienti care vorutiliza aceasi conexiune. Fiecare client este un fir de executie care estegestionat de o cuva (pool) de fire de executie.

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Topic ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;6 import java . u t i l . concurrent . ExecutorServ ice ;7 import java . u t i l . concurrent . Executors ;

9 public class ReceiversT extends Thread{10 St r ing s u b i e c t ;11 St r ing sharedSubscriptionName ;12 int noAbonati ;13 com . sun . messaging . TopicConnectionFactory c f ;

15 ReceiversT ( int noAbonati , S t r ing sub iec t ,16 St r ing sharedSubscriptionName ){17 this . s u b i e c t=s u b i e c t ;18 this . noAbonati=noAbonati ;19 this . sharedSubscriptionName=sharedSubscriptionName ;20 }

22 public void run ( ){23 ExecutorServ i ce exec=Executors . newFixedThreadPool ( noAbonati ) ;

Page 126: programare distribuita

126 CAPITOLUL 5. MESAJE IN JAVA

25 try{26 c f=new com . sun . messaging . TopicConnectionFactory ( ) ;27 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;28 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);

30 for ( int i =0; i<noAbonati ; i ++){31 St r ing cl ientName=” Cl i en t ”+i ;32 MsgSubscriberT t=new MsgSubscriberT ( cf , sub i ec t ,33 sharedSubscriptionName , cl ientName ) ;34 exec . execute ( t ) ;35 }36 exec . shutdownNow ( ) ;37 }38 catch ( Exception e ){39 System . out . p r i n t l n ( ” Rece ive r s : ”+e . getMessage ( ) ) ;

41 }42 System . out . p r i n t l n ( ” Rece ive r s f i n i s h e d ” ) ;43 }44 }

• Clientii JMS propriu-zisi

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Topic ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;

7 public class MsgSubscriberT extends Thread{8 St r ing s u b i e c t ;9 St r ing c l i e n t I D ;

10 St r ing cl ientName ;11 St r ing sharedSubscriptionName ;12 com . sun . messaging . TopicConnectionFactory c f ;

14 MsgSubscriberT (com . sun . messaging . TopicConnectionFactory cf ,15 St r ing sub iec t , S t r ing sharedSubscriptionName ,16 St r ing cl ientName ){17 this . c f=c f ;18 this . s u b i e c t=s u b i e c t ;19 this . sharedSubscriptionName=sharedSubscriptionName ;20 this . c l ientName=clientName ;21 }

23 public void run ( ){24 try{25 Topic t=new com . sun . messaging . Topic ( s u b i e c t ) ;26 JMSContext ctx=c f . c reateContext ( ) ;27 JMSConsumer consumer = ctx . createSharedConsumer ( t ,28 sharedSubscriptionName ) ;

30 Message msg=null ;31 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){32 i f (msg instanceof TextMessage ){33 TextMessage m=(TextMessage )msg ;34 System . out . p r i n t l n ( cl ientName+” r e c e i v e d : ”+m. getText ( ) ) ;

Page 127: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 127

35 }36 else37 break ;38 }39 ctx . c l o s e ( ) ;40 }41 catch ( Exception e ){42 System . out . p r i n t l n ( ” MsgSubscriber : ”+e . getMessage ( ) ) ;43 }44 System . out . p r i n t l n ( ” Subsc r ibe r ”+clientName+” f i n i s h e d ” ) ;45 }46 }

Aplicatia este condusa de clasa

1 public class MsgPS{2 public stat ic void main ( St r ing [ ] a rgs ){3 St r ing s u b i e c t=”JMS” ;4 St r ing sharedSubscriptionName=” ourSubsc r ip t i on ” ;5 int n=3,noAbonati =3;6 i f ( args . length >0)7 s u b i e c t=args [ 0 ] ;8 i f ( args . length >1)9 n=I n t e g e r . pa r s e In t ( args [ 1 ] ) ;

10 MsgPublisherT p u b l i s h e r=new MsgPublisherT ( sub iec t , n ) ;11 ReceiversT abonat i=new ReceiversT ( noAbonati , sub i ec t ,12 sharedSubscriptionName ) ;13 abonat i . s t a r t ( ) ;14 p u b l i s h e r . s t a r t ( ) ;15 }16 }

5.3.7 Obiecte administrator prin JNDI

Obiectele administrator coada sau topic, care retin mesajele se precizeazaın fisiere de proprietati - jndi.properties.

Pentru Open Message Queue acest fisier esteVarianta Oracle-Open Message Queue

1 java . naming . f a c t o r y . i n i t i a l =2 com . sun . j n d i . f s c o n t e x t . RefFSContextFactory3 java . naming . prov ide r . u r l= f i l e : /// d : /Temp

5 # use the f o l l o w i n g property to c o n f i g u r e the d e f a u l t connector

7 # r e g i s t e r some queues in JNDI us ing the form8 # queue . [ jndiName ] = [ physicalName ]9 queue . queue = myqueue

11 # r e g i s t e r some t o p i c s in JNDI us ing the form12 # t op i c . [ jndiName ] = [ physicalName ]13 t op i c . t o p i c = mytopic

Page 128: programare distribuita

128 CAPITOLUL 5. MESAJE IN JAVA

In acest caz este nevoie de crearea ın prealabil a obiectelor corespunzatoareconexiunii, a cozii (queue) si a subiectului (topic). Aceaste obiecte se creazacu utilitarul imqobjmgr din distributia Oracle-Open Message Queue.

Obiectele se pot crea cu fisierul de comenzi:

1 s e t PATH=d: \mq\bin ;%PATH%2 imqobjmgr add −t q f − l ” ConnectionFactory ”3 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp4 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory5 rem imqobjmgr add −t t f − l ” ConnectionFactory ”6 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp7 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory8 imqobjmgr add −t q − l ”queue”9 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp

10 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory11 rem imqobjmgr add −t t − l ” t o p i c ”12 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp13 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory

Obiectele se pot sterge cu fisierul de comenzi:

1 s e t PATH=d: \mq\bin ;%PATH%2 imqobjmgr d e l e t e −t q f − l ” ConnectionFactory ”3 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp4 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory5 imqobjmgr d e l e t e −t t f − l ” ConnectionFactory ”6 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp7 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory8 imqobjmgr d e l e t e −t q − l ”queue”9 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp

10 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory11 imqobjmgr d e l e t e −t t − l ” t o p i c ”12 −j java . naming . prov ide r . u r l= f i l e : /// d : /Temp13 −j java . naming . f a c t o r y . i n i t i a l=com . sun . j n d i . f s c o n t e x t . RefFSContextFactory

Reluam aplicatiile anterioare privind transmiterea / receptia unui mesajprin comunicatie punctuala utilizand o coada si publicarea si receptionareaunui mesaj prin comunicatie bazata pe subiect ıntr-o varianta independententade suportul middleware de serviciu de mesagerie folosit. Regasirea resurselorgestionate de serviciul de mesagerie se va face utilizand JNDI.

5.3.8 Comunicatia prin coada - queue

Aplicatia este alcatuita din clasele MsgHelloT, MsgSenderT, SyncMsgRe-ceiverT, AsyncMsgReceiverT, TextListener. Fata de versiunea prezentata an-terior se modifica doar clasele MsgSenderT, SyncMsgReceiverT, AsyncMsgRe-ceiverT.

In clasa MsgHelloT campul queueName reprezinta numele JNDI al cozii.Clasa MsgSenderT

1 import javax . jms . QueueConnectionFactory ;2 import javax . jms . Queue ;

Page 129: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 129

3 import javax . jms . JMSContext ;4 import javax . jms . JMSProducer ;5 import javax . naming . I n i t i a l C o n t e x t ;6 import javax . naming . NamingException ;7 import java . u t i l . P r o p e r t i e s ;8 import java . i o . IOException ;

10 public class MsgSenderT extends Thread{11 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;12 St r ing QUEUE JNDI NAME = ”queue” ;13 private I n i t i a l C o n t e x t ctx ;14 private int n ;

16 MsgSenderT ( St r ing queueName , int n){17 QUEUE JNDI NAME=queueName ;18 this . n=n ;19 }

21 public void run ( ){22 try{23 setupJNDI ( ) ;24 QueueConnectionFactory c f=25 ( QueueConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;26 Queue q=(Queue ) ctx . lookup (QUEUE JNDI NAME) ;27 closeJNDI ( ) ;

29 JMSContext jmsctx=c f . c reateContext ( ) ;30 JMSProducer producer=jmsctx . c reateProducer ( ) ;31 for ( int i =0; i<n ; i ++){32 producer . send (q , ” He l lo ”+i ) ;33 }34 producer . send (q , jmsctx . createMessage ( ) ) ;35 jmsctx . c l o s e ( ) ;36 }37 catch ( Exception e ){38 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;39 }40 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;41 }

43 private void setupJNDI ( ){44 P r o p e r t i e s p r o p e r t i e s = new P r o p e r t i e s ( ) ;45 try{46 p r o p e r t i e s . load ( this . g e tC la s s ( ) . getResourceAsStream ( ” j n d i . p r o p e r t i e s ” ) ) ;47 }48 catch ( IOException e ){49 System . out . p r i n t l n ( ”JNDI−Prope r t i e sEr ro r : ”+e . getMessage ( ) ) ;50 }51 try{52 ctx = new I n i t i a l C o n t e x t ( p r o p e r t i e s ) ;53 }54 catch ( NamingException e ){55 System . e r r . p r i n t l n ( ” Error Se t t i ng up JNDI Context : ” + e ) ;56 }57 }

59 private void closeJNDI ( ){60 try{61 ctx . c l o s e ( ) ;

Page 130: programare distribuita

130 CAPITOLUL 5. MESAJE IN JAVA

62 }63 catch ( NamingException e ){64 System . e r r . p r i n t l n ( ”Unable to c l o s e JNDI Context : ” + e ) ;65 }66 }67 }

Clasa SyncMsgReceiverT

1 import javax . jms . QueueConnectionFactory ;2 import javax . jms . Queue ;3 import javax . jms . TextMessage ;4 import javax . jms . Message ;5 import javax . jms . JMSContext ;6 import javax . jms . JMSConsumer ;7 import javax . naming . I n i t i a l C o n t e x t ;8 import javax . naming . NamingException ;9 import java . u t i l . P r o p e r t i e s ;

10 import java . i o . IOException ;

12 public class SyncMsgReceiverT extends Thread{13 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;14 St r ing QUEUE JNDI NAME = ”queue” ;15 private I n i t i a l C o n t e x t ctx ;

17 SyncMsgReceiverT ( St r ing queueName){18 QUEUE JNDI NAME=queueName ;19 }

21 public void run ( ){22 try{23 setupJNDI ( ) ;24 QueueConnectionFactory c f=25 ( QueueConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;26 Queue q=(Queue ) ctx . lookup (QUEUE JNDI NAME) ;27 closeJNDI ( ) ;

29 JMSContext jmsctx=c f . c reateContext ( ) ;30 JMSConsumer consumer = jmsctx . createConsumer ( q ) ;31 Message msg=null ;32 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){33 i f (msg instanceof TextMessage ){34 TextMessage m=(TextMessage )msg ;35 System . out . p r i n t l n (m. getText ( ) ) ;36 }37 else38 break ;39 }40 jmsctx . c l o s e ( ) ;41 }42 catch ( Exception e ){43 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;44 }45 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;46 }

48 private void setupJNDI ( ) { . . .}

50 private void closeJNDI ( ) { . . .}

Page 131: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 131

51 }

5.3.9 Comunicatia pe baza de subiect - topic

Aplicatia este alcatuita din clasele MsgPS, MsgPublisherT, MsgSubscrib-erT. Fata de versiunea prezentata anterior se modifica doar clasele MsgPub-lisherT si MsgSubscriberT.

In clasa MsgPS campul subiect reprezinta numele JNDI atasat topic-ului.Clasa MsgPublisherT

1 import javax . jms . TopicConnectionFactory ;2 import javax . jms . Topic ;3 import javax . jms . JMSContext ;4 import javax . jms . JMSProducer ;5 import javax . naming . I n i t i a l C o n t e x t ;6 import javax . naming . NamingException ;7 import java . u t i l . P r o p e r t i e s ;8 import java . i o . IOException ;

10 public class MsgPublisherT extends Thread{11 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;12 St r ing TOPIC JNDI NAME = ” t op i c ” ;13 private I n i t i a l C o n t e x t ctx ;14 private int n ;

16 MsgPublisherT ( St r ing sub i ec t , int n){17 this . n=n ;18 TOPIC JNDI NAME=s u b i e c t ;19 }

21 public void run ( ){22 try{23 setupJNDI ( ) ;24 TopicConnectionFactory c f=25 ( TopicConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;26 Topic t=(Topic ) ctx . lookup (TOPIC JNDI NAME ) ;27 closeJNDI ( ) ;

29 JMSContext jmsctx=c f . c reateContext ( ) ;30 JMSProducer producer=jmsctx . c reateProducer ( ) ;31 for ( int i =0; i<n ; i ++){32 producer . send ( t , ”Despre JMS”+” ”+i ) ;33 }34 producer . send ( t , jmsctx . createMessage ( ) ) ;35 jmsctx . c l o s e ( ) ;36 }37 catch ( Exception e ){38 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;39 }40 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;41 }

43 private void setupJNDI ( ) { . . .}

45 private void closeJNDI ( ) { . . .}

Page 132: programare distribuita

132 CAPITOLUL 5. MESAJE IN JAVA

46 }

Clasa MsgSubscriberT

1 import javax . jms . TopicConnectionFactory ;2 import javax . jms . Topic ;3 import javax . jms . TextMessage ;4 import javax . jms . Message ;5 import javax . jms . JMSContext ;6 import javax . jms . JMSConsumer ;7 import javax . naming . I n i t i a l C o n t e x t ;8 import javax . naming . NamingException ;9 import java . u t i l . P r o p e r t i e s ;

10 import java . i o . IOException ;

12 public class MsgSubscriberT extends Thread{13 f ina l St r ing CONNECTION JNDI NAME = ” ConnectionFactory ” ;14 St r ing TOPIC JNDI NAME = ” t op i c ” ;15 private I n i t i a l C o n t e x t ctx ;16 private St r ing c l i e n t I D ;17 private St r ing cl ientName ;

19 MsgSubscriberT ( St r ing sub i ec t , S t r ing c l i en t ID , S t r ing cl ientName ){20 TOPIC JNDI NAME=s u b i e c t ;21 this . c l i e n t I D=c l i e n t I D ;22 this . c l ientName=clientName ;23 }

25 public void run ( ){26 try{27 setupJNDI ( ) ;28 TopicConnectionFactory c f=29 ( TopicConnectionFactory ) ctx . lookup (CONNECTION JNDI NAME) ;30 Topic t=(Topic ) ctx . lookup (TOPIC JNDI NAME ) ; ;31 JMSContext jmsctx=c f . c reateContext ( ) ;32 jmsctx . s e tC l i en t ID ( c l i e n t I D ) ;33 JMSConsumer consumer = jmsctx . createDurableConsumer ( t , cl ientName ) ;34 closeJNDI ( ) ;

36 Message msg=null ;37 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){38 i f (msg instanceof TextMessage ){39 TextMessage m=(TextMessage )msg ;40 System . out . p r i n t l n ( cl ientName+” r e c e i v e d : ”+m. getText ( ) ) ;41 }42 else43 break ;44 }45 jmsctx . c l o s e ( ) ;46 }47 catch ( Exception e ){48 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;49 }50 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;51 }

53 private void setupJNDI ( ) { . . .}

55 private void closeJNDI ( ) { . . .}

Page 133: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 133

56 }

5.3.10 Aplicatie JMS slab cuplata

Aplicatia va fi alcatuita din trei clienti:

• Client care preia si rezolva cererile iar raspunsurile sunt trimise solici-tantului ıntr-un mesaj pe un subiect indicat de acesta. Acest client preiamesajele corespunzatoare unui subiect public.

• Client care lanseaza cererea. Acest client va crea un abonat durabil pesubiectul pe care se va prelua raspunsul. Subiectul face parte din cerere.

• Client care preia raspunsul.

Exemplul 5.3.9 Calculul celui mai mare divizor comun a doua numere nat-urale.

Clasa MsgCmmdcServer

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Topic ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;6 import javax . jms . JMSProducer ;

8 public class MsgCmmdcServer{

10 public stat ic void main ( St r ing [ ] a rgs ){11 MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ;12 s e r v e r . s e r v i c e ( ) ;13 }

15 private void s e r v i c e ( ){16 try{17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);21 Topic t=new com . sun . messaging . Topic ( ”Cmmdc” ) ;22 JMSContext ctx=c f . c reateContext ( ) ;23 JMSConsumer consumer = ctx . createSharedConsumer ( t , ”Cmmdc” ) ;24 JMSProducer producer = ctx . c reateProducer ( ) ;25 while ( true ){26 Message msg=null ;27 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){28 i f (msg instanceof TextMessage ){29 TextMessage tm=(TextMessage )msg ;30 St r ing s=tm . getText ( ) ;31 St r ing [ ] s s=s . s p l i t ( ” ” ) ;32 long m=Long . parseLong ( s s [ 0 ] ) ;

Page 134: programare distribuita

134 CAPITOLUL 5. MESAJE IN JAVA

33 long n=Long . parseLong ( s s [ 1 ] ) ;34 St r ing t op i c=s s [ 2 ] ;35 long c=cmmdc(m, n ) ;36 Topic t1=new com . sun . messaging . Topic ( t o p i c ) ;37 producer . send ( t1 , (new Long ( c ) ) . t oS t r i ng ( ) ) ;38 System . out . p r i n t l n ( ” Server sent ”+c+” to ”+t op i c ) ;39 }40 }41 }

43 }44 catch ( Exception e ){45 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;46 }47 }

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

Clasa MsgClientSender

1 import javax . jms . Topic ;2 import javax . jms . JMSContext ;3 import javax . jms . JMSProducer ;4 import javax . jms . JMSConsumer ;5 import java . u t i l . Scanner ;

7 public class MsgClientSender{8 private St r ing msg , c l i en t ID , clientName , t op i cRe su l t ;

10 MsgClientSender ( S t r ing c l i en t ID , S t r ing cl ientName ){11 this . c l i e n t I D=c l i e n t I D ;12 this . c l ientName=clientName ;13 Scanner scanner=new Scanner ( System . in ) ;14 System . out . p r i n t l n ( ” I n t r o d u c e t i m : ” ) ;15 long m=scanner . nextLong ( ) ;16 St r ing sm=new Long (m) . t oS t r i ng ( ) ;17 System . out . p r i n t l n ( ” I n t r o d u c e t i n : ” ) ;18 long n=scanner . nextLong ( ) ;19 St r ing sn=new Long (n ) . t oS t r i ng ( ) ;20 System . out . p r i n t l n ( ” I n t r o d u c e t i ’ Topic ’−ul ra spunsu lu i ” ) ;21 t op i cResu l t=scanner . next ( ) ;22 msg=sm+” ”+sn+” ”+top i cRe su l t ;23 }

25 private void s e r v i c e ( ){26 try{27 com . sun . messaging . TopicConnectionFactory c f=28 new com . sun . messaging . TopicConnectionFactory ( ) ;29 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;30 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);31 Topic t=new com . sun . messaging . Topic ( ”Cmmdc” ) ;32 JMSContext ctx=c f . c reateContext ( ) ;

34 Topic t1=new com . sun . messaging . Topic ( t op i cRe su l t ) ;35 ctx . s e tC l i en t ID ( c l i e n t I D ) ;36 JMSConsumer consumer = ctx . createDurableConsumer ( t1 , cl ientName ) ;37 JMSProducer producer=ctx . c reateProducer ( ) ;38 producer . send ( t , msg ) ;

Page 135: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 135

39 ctx . c l o s e ( ) ;40 }41 catch ( Exception e ){42 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;43 }44 }

46 public stat ic void main ( St r ing [ ] a rgs ){47 i f ( args . length <2){48 System . out . p r i n t l n ( ”Usage : ” ) ;49 System . out . p r i n t l n ( ” java MsgClientSender c l i e n t I D clientName ” ) ;50 System . e x i t ( 0 ) ;51 }52 MsgClientSender c l i e n t=new MsgClientSender ( args [ 0 ] , a rgs [ 1 ] ) ;53 c l i e n t . s e r v i c e ( ) ;54 }55 }

Clasa MsgClientReceiver

1 import javax . jms . TextMessage ;2 import javax . jms . Message ;3 import javax . jms . Topic ;4 import javax . jms . JMSContext ;5 import javax . jms . JMSConsumer ;6 import java . u t i l . Scanner ;

8 public class MsgCl ientRece iver {9 private St r ing top i cResu l t , c l i en t ID , cl ientName ;

11 MsgCl ientRece iver ( S t r ing c l i ent ID , S t r ing cl ientName ){12 this . c l i e n t I D=c l i e n t I D ;13 this . c l ientName=clientName ;14 Scanner scanner=new Scanner ( System . in ) ;15 System . out . p r i n t l n ( ” I n t r o d u c e t i ’ Topic ’−ul ra spunsu lu i ” ) ;16 t op i cRe su l t=scanner . next ( ) ;17 }

19 public void s e r v i c e ( ){20 try{21 com . sun . messaging . TopicConnectionFactory c f=22 new com . sun . messaging . TopicConnectionFactory ( ) ;23 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;24 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);25 Topic t=new com . sun . messaging . Topic ( t op i cRe su l t ) ;26 JMSContext ctx=c f . c reateContext ( ) ;27 ctx . s e tC l i en t ID ( c l i e n t I D ) ;28 JMSConsumer consumer = ctx . createDurableConsumer ( t , cl ientName ) ;29 Message msg=null ;30 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){31 i f (msg instanceof TextMessage ){32 TextMessage m=(TextMessage )msg ;33 System . out . p r i n t l n ( ”Cmmdc : ”+m. getText ( ) ) ;34 break ;35 }36 }37 ctx . c l o s e ( ) ;38 }39 catch ( Exception e ){

Page 136: programare distribuita

136 CAPITOLUL 5. MESAJE IN JAVA

40 System . out . p r i n t l n ( ”JMSException : ”+e . getMessage ( ) ) ;41 }42 }

44 public stat ic void main ( St r ing [ ] a rgs ){45 i f ( args . length <2){46 System . out . p r i n t l n ( ”Usage : ” ) ;47 System . out . p r i n t l n ( ” java MsgSOAPClientReceiver c l i e n t I D clientName ” ) ;48 System . e x i t ( 0 ) ;49 }50 MsgCl ientRece iver c l i e n t=new MsgCl ientRece iver ( args [ 0 ] , a rgs [ 1 ] ) ;51 c l i e n t . s e r v i c e ( ) ;52 }53 }

5.3.11 Programare JMS prin glassfish

Diferenta fata de versiunile amintite mai sus constau ın

• obiectele administrator,

– fabrica de conexiuni,

– obiectul / sursa destinatie

care se creaza de administratorul glassfish.

1. Se lanseaza serverul de aplicatii glassfish

set GLASSFISH_HOME=. . .\glassfish3

set PATH=%GLASSFISH_HOME%\bin;%PATH%

asadmin start-domain domain1

Lansarea serverului de aplicatie implica pornirea serverului JMS.

2. Dintr-un navigator se apeleaza administratorul http://localhost:4848.

3. – Resources → JMS Resources → Destination ResourcesSe creaza cate un obiect destinatie cu datele:JNDI Name myQueue myTopicPhysical Name myQueue myTopicResource Type javax.jms.Queue javax.jms.Topic

– Resources → JMS Resources → Connection FactoriesSe creaza cate o fabrica de conexiuni cu datele:Pool Name myQueueConnectionFactory, respectiv

myTopicConnectionFactoryResource Type javax.jms.QueueConnectionFactory, respectiv

javax.jms.TopicConnectionFactory

• Aceste obiecte se injecteaza ıntr-o clasa utilizınd adnotarea javax.annotation.Resource

Page 137: programare distribuita

5.3. ELEMENTE DE PROGRAMARE - JMS-2 137

import javax.annotation.Resource;

. . .

public class . . .

@Resource(lookup="myQueueConnectionFactory")

private static QueueConnectionFactory cf;

@Resource(lookup="myQueue")

private static Queue q;

• O aplicatie se arhiveaza cu jar cu indicarea clasei cu metoda main sise lanseaza prin intermediul procedurii acoperitoare glassfish\bin\appclient.bat

appclient -client numeArhiva.jar [-targetserver host:3700]

Exemplul 5.3.10 Aplicatie cu comunicatie punctuala.

Clasa expeditorului

1 import javax . jms . QueueConnectionFactory ;2 import javax . jms . Queue ;3 import javax . jms . JMSContext ;4 import javax . jms . JMSProducer ;5 import javax . annotat ion . Resource ;

7 public class MsgSender{8 @Resource ( lookup=”myQueueConnectionFactory” )9 private stat ic QueueConnectionFactory c f ;

10 @Resource ( lookup=”myQueue” )11 private stat ic Queue q ;12 private stat ic int n=3;

14 public stat ic void main ( St r ing [ ] a rgs ){15 try{16 JMSContext jmsctx=c f . c reateContext ( ) ;17 JMSProducer producer=jmsctx . c reateProducer ( ) ;18 for ( int i =0; i<n ; i ++){19 producer . send (q , ” He l lo ”+i ) ;20 }21 producer . send (q , jmsctx . createMessage ( ) ) ;22 jmsctx . c l o s e ( ) ;23 }24 catch ( Exception e ){25 //System . out . p r i n t l n (” JMSException : ”+e . getMessage ( ) ) ;26 e . pr intStackTrace ( ) ;27 }28 System . out . p r i n t l n ( ” Sender f i n i s h e d ” ) ;29 }30 }

Clasa unui client sincron

Page 138: programare distribuita

138 CAPITOLUL 5. MESAJE IN JAVA

1 import javax . jms . QueueConnectionFactory ;2 import javax . jms . Queue ;3 import javax . jms . JMSContext ;4 import javax . jms . JMSConsumer ;5 import javax . jms . Message ;6 import javax . jms . TextMessage ;7 import javax . annotat ion . Resource ;

9 public class SyncMsgReceiver{10 @Resource ( lookup=”myQueueConnectionFactory” )11 private stat ic QueueConnectionFactory c f ;12 @Resource ( lookup=”myQueue” )13 private stat ic Queue q ;

15 public stat ic void main ( St r ing [ ] a rgs ){16 try{17 JMSContext jmsctx=c f . c reateContext ( ) ;18 JMSConsumer consumer = jmsctx . createConsumer ( q ) ;19 Message msg=null ;20 while ( ( msg=consumer . r e c e i v e ( ) ) != null ){21 i f (msg instanceof TextMessage ){22 TextMessage m=(TextMessage )msg ;23 System . out . p r i n t l n (m. getText ( ) ) ;24 }25 else26 break ;27 }28 jmsctx . c l o s e ( ) ;29 }30 catch ( Exception e ){31 //System . out . p r i n t l n (” JMSException : ”+e . getMessage ( ) ) ;32 e . pr intStackTrace ( ) ;33 }34 System . out . p r i n t l n ( ”Consumer f i n i s h e d ” ) ;35 }36 }

Intrebari recapitulative

1. Explicati caracterul de cuplare slaba al unei aplicatii bazat pe JMS.

2. Care este rolul furnizorului (provider) JMS?

3. Precizati si explicati modelele de comunicatii cu mesaje ın JMS.

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

Probleme:

• StreamMessage

Page 139: programare distribuita

Partea II

TEHNOLOGII CUCOMUNICATII PRIN

INTERNET

139

Page 140: programare distribuita
Page 141: programare distribuita

Capitolul 6

HyperText Transfer Protocol

Protocolul http- HyperText Transfer Protocol (http) este destinat schim-burilor de informatii ın Internet.

In vederea schimburilor dintre calculatoare prin Internet, reprezentareadatelor se face utilizand ın principal:

• eXtensible Markup Language (XML) - subset al limbajului StandardGeneralized Markup Language (SGML);

• JavaScript Object Notation (JSON).

HyperText Markup Language (HTML), XHTML, HTML 5 sunt principalelelimbaje pentru publicarea informatiilor pe Web. Aceste limbaje deriva deasemenea din SGML.

6.1 Transactie http

Protocolul http este de tip client-server:

• Navigatoarele Google Chrome, Mozilla Firefox, Microsoft Internet Ex-plorer, Opera, Apple Safari sunt aplicatii client uzuale.

• Informatiile sunt gazduite / generate de servere Web de catre site-urisi servicii Web. Exemple de servere Web sunt apache HTTP Server,

Microsoft Internet Interchange Server. O categorie aparte - esentialapentru platforma Java - este data de servere Web container de servlet siJava Server Pages (JSP).

Protocolul http este unidirectional. Transmiterea unui mesaj conform pro-tocolului http consta din

141

Page 142: programare distribuita

142 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

1. stabilirea unei conexiuni catre un destinatar;

2. expedierea mesajului;

3. ınchiderea conexiunii.

Acest ciclu de actiuni se numeste tranzactie http. Practic, ıntr-o aplicatieWeb, expedierea unei cereri de un client catre un server Web si receptionarearaspunsului furnizat de server presupun doua tranzactii http. Un mesaj detip cerere difera de un mesaj de tip raspuns prin structura unor elementeconstitutive.

Serverul nu retine informatii ıntre doua tranzactii http. Acest comporta-ment se exprima prin terminologia: protocolul http este fara stare - stateless.

Transmisia datelor se realizeaza utilizand de obicei protocolul TCP.

Referintele resurselor se indica folosind URI / URL.

Cererile si raspunsurile sunt reprezentate ca linii de text separate de carac-terul <CR><LF>, avand structura

1. preambul - format dintr-o linie;

2. antete (header) - 0 sau mai multe atribute (nume:valoare);

3. o linie goala;

4. corpul mesajului - optional.

Preambulul unei cereri contine:

1. numele metodei {GET, POST, PUT, DELETE, HEAD, CONNECT, TRACE,

OPTIONS};

2. referinta resursei (URL);

3. Versiunea protocolului http.

Preambulul unui raspuns contine:

1. Versiunea protocolului http;

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

Page 143: programare distribuita

6.1. TRANSACTIE HTTP 143

Categoria Indica

1** mesaj de informare2** mesaj de succes3** redirectare catre alt URL4** eroare in mesajul clientului5** eroare din partea serverului

Categoria este data de prima cifra.

3. String explicitand codul raspunsului.

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

Antet SemnificatieExemplu

host Gazda si portul serverului Weblocalhost:8080

user-agent Navigatorul care a lansat cerereaMozilla/5.0 (Windows NT 6.1; WOW64)AppleWebKit/535.2 (KHTML, like Gecko)Chrome/15.0.874.106 Safari/535.2

referer URL-ul cereriihttp://localhost:8080/apphello/

accept-encoding Tipuri de arhive acceptategzip,deflate,sdch

accept-charset Tipuri de codificare acceptateISO-8859-1,utf-8;q=0.7,*;q=0.3

accept-language Cea mai potrivita limba pentru ıntelegereacontinutuluien-US,en;q=0.8

content-type Tipul MIME al corpului mesajuluihttp://application/x-www-form-urlencoded

content-length Lungimea corpului mesajului22

Corpul mesajului este reprezentat printr-un text. Daca continutul esteimagine, cod binar, etc., atunci acesta este codificat ın text.

Codul Multipurpose Internet Mail Exchange (MIME) precizeaza naturacontinutului unei resurse:

Page 144: programare distribuita

144 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

text/plaintext/htmltext/xmlimage/pngimage/jpgapplication/octet-streamapplication/x-www-form-urlencoded

Ne propunem sa punem ın evidenta mesajele http.

Mesaj cerere http

Dintr-un navigator se va lansa prin intermediul unui document html ocerere catre un ipotetic servlet dintr-un server Web. Cererea este interceptatade o clasa Java cu un soclu TCP, ServerSocket, care preia mesajele pe portulserverului Web.

Codul clasei Java este

1 import java . net . ServerSocket ;2 import java . net . Socket ;3 import java . i o . InputStream ;4 import java . i o . InputStreamReader ;5 import java . i o . BufferedReader ;6 import java . i o . IOException ;7 import java . i o . Buf feredWriter ;8 import java . i o . F i l eWr i t e r ;

10 public class RequestHTTPMsg{11 public stat ic void main ( St r ing [ ] a rgs ){12 Socket socke t=null ;13 try{14 ServerSocket s e rve rSocke t=new ServerSocket ( 8 0 8 0 ) ;15 socke t=se rve rSocke t . accept ( ) ;16 }17 catch ( Exception e ){18 System . out . p r i n t l n ( e . getMessage ( ) ) ;19 }20 try (21 InputStream i s=socket . getInputStream ( ) ;22 InputStreamReader i s r=new InputStreamReader ( i s ) ;23 BufferedReader br=new BufferedReader ( i s r ) ;24 Fi l eWr i t e r fw=new Fi l eWr i t e r ( ” output . txt ” , true ) ;25 Buf feredWriter bw=new Buf feredWriter ( fw ) ){26 for ( ; ; ) {27 St r ing s=br . readLine ( ) ;28 i f ( s==null )break ;29 System . out . p r i n t l n ( s ) ;30 bw. wr i t e ( s ) ;31 bw. newLine ( ) ;32 }33 }34 catch ( IOException e ){35 System . out . p r i n t l n ( ” Input Exception : ”+e . getMessage ( ) ) ;

Page 145: programare distribuita

6.1. TRANSACTIE HTTP 145

36 }37 }38 }

Rezultatul cererii depinde de metoda GET sau POST utilizata ın formula-rul html folosit.

Pentru metoda GET cererea http este

GET /apphello/hello?name=mk&tip=text%2Fhtml HTTP/1.1

Host: localhost:8080

Connection: keep-alive

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)

AppleWebKit/535.2 (KHTML, like Gecko)

Chrome/15.0.874.106 Safari/535.2

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Encoding: gzip,deflate,sdch

Accept-Language: en-US,en;q=0.8

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

iar pentru metoda POST cererea http este

POST /apphello/hello HTTP/1.1

Host: localhost:8080

Connection: keep-alive

Content-Length: 23

Cache-Control: max-age=0

Origin: null

User-Agent: Mozilla/5.0 (Windows NT 6.1;

WOW64) AppleWebKit/535.2 (KHTML, like Gecko)

Chrome/15.0.874.106 Safari/535.2

Content-Type: application/x-www-form-urlencoded

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Encoding: gzip,deflate,sdch

Accept-Language: en-US,en;q=0.8

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

name=mk&tip=text%2Fhtml

Formularul html utilizat are codul

1 <html>2 <head><t i t l e> Serv l e t−ul He l lo</ t i t l e></head>3 <body>4 <center>5 <h1> Pagina de ape l a r e a s e r v l e t u l u i H e l l o S e r v l e t </h1>6 <form method=” post ”7 action=” http :// l o c a l h o s t :8080/ apphe l l o / h e l l o ”>8 <p>I n t r o d u c e t i numele :9 <input type=” text ” name=”name” s ize=20>

10 <p>11 <input type=”submit” value=” Apeleaza ”>12 <input type=” hidden ” name=” t i p ” value=” text /html” >13 </form>14 </center>15 </body>16 </htm

Page 146: programare distribuita

146 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Mesaj raspuns http

Un servlet (apphello) este activ ıntr-un server Web. O clasa Java lanseazao cerere http catre acel servlet - chiar unul din mesajele obtinute mai sus -dupa care receptioneaza raspunsul dat de servlet.

Codul clasei Java

1 import java . net . Socket ;2 import java . i o . InputStreamReader ;3 import java . i o . BufferedReader ;4 import java . i o . IOException ;5 import java . i o . Buf feredWriter ;6 import java . i o . F i l eWr i t e r ;7 import java . i o . Pr intWriter ;8 import java . u t i l . Scanner ;

10 public class ResponseHTTPMsg{11 public stat ic void main ( St r ing [ ] a rgs ){12 St r ing reqGET=”GET / apphe l l o / h e l l o ?name=mk&t i p=text%2Fhtml HTTP/1.1\ r \n”+13 ”Host : l o c a l h o s t :8080\ r \n”+14 ” Connection : keep−a l i v e \ r \n”+15 ”User−Agent : Moz i l l a /5 .0 (Windows NT 6 . 1 ; WOW64) ”+16 ”AppleWebKit /535 .2 (KHTML, l i k e Gecko ) ”+17 ” Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i /535.2\ r \n”+18 ”Accept : t ex t /html , a p p l i c a t i o n /xhtml+xml , a p p l i c a t i o n /xml ; ”+19 ”q =0.9 ,∗/∗ ; q=0.8\ r \n”+20 ”Accept−Encoding : gzip , d e f l a t e , sdch\ r \n”+21 ”Accept−Language : en−US, en ; q=0.8\ r \n”+22 ”Accept−Charset : ISO−8859−1, utf −8;q =0.7 ,∗ ; q=0.3\ r \n” ;

24 St r ing reqPOST=”POST / apphe l l o / h e l l o HTTP/1.1\ r \n”+25 ”Host : l o c a l h o s t :8080\ r \n”+26 ” Connection : keep−a l i v e \ r \n”+27 ”Content−Length : 23\ r \n”+28 ”Cache−Control : max−age=0\r \n”+29 ” Orig in : n u l l \ r \n”+30 ”User−Agent : Moz i l l a /5 .0 (Windows NT 6 . 1 ; WOW64) ”+31 ”AppleWebKit /535 .2 (KHTML, l i k e Gecko ) ”+32 ”Chrome / 1 5 . 0 . 8 7 4 . 1 0 6 S a f a r i /535 .2\ r \n”+33 ”Content−Type : a p p l i c a t i o n /x−www−form−ur lencoded \ r \n”+34 ”Accept : t ex t /html , a p p l i c a t i o n /xhtml+xml , a p p l i c a t i o n /xml ; ”+35 ”q =0.9 ,∗/∗ ; q=0.8\ r \n”+36 ”Accept−Encoding : gzip , d e f l a t e , sdch\ r \n”+37 ”Accept−Language : en−US, en ; q=0.8\ r \n”+38 ”Accept−Charset : ISO−8859−1, utf −8;q =0.7 ,∗ ; q=0.3\ r \n”+39 ”\ r \n”+40 ”name=mk&t i p=text%2Fhtml” ;

42 Scanner scanner=new Scanner ( System . in ) ;43 System . out . p r i n t l n ( ” P r e c i z a t i metoda HTTP : ” ) ;44 System . out . p r i n t l n ( ”1 : GET; 2 : POST” ) ;45 int metoda ;46 do{47 metoda=scanner . next Int ( ) ;48 }49 while ( ( metoda!=1)&&(metoda ! = 2 ) ) ;50 try (51 Socket socke t=new Socket ( ” l o c a l h o s t ” , 8 0 8 0 ) ;

Page 147: programare distribuita

6.2. SERVER WEB - CONTAINER DE SERVLET 147

52 InputStreamReader i s r=new InputStreamReader ( socket . getInputStream ( ) ) ;53 BufferedReader br=new BufferedReader ( i s r ) ;54 Fi l eWr i t e r fw=new Fi l eWr i t e r ( ” output . txt ” , true ) ;55 Buf feredWriter bw=new Buf feredWriter ( fw ) ;56 PrintWriter pw=new PrintWriter ( socket . getOutputStream ( ) , true )57 ){58 switch ( metoda ){59 case 1 :60 // Lansarea unei c e r e r i GET61 pw. p r i n t l n (reqGET ) ;62 break ;63 case 2 :64 // Lansarea unei c e r e r i POST65 pw. p r i n t l n (reqPOST ) ;66 }67 for ( ; ; ) {68 St r ing s=br . readLine ( ) ;69 i f ( s==null )break ;70 System . out . p r i n t l n ( s ) ;71 bw. wr i t e ( s ) ;72 bw. newLine ( ) ;73 }74 }75 catch ( Exception e ){76 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;77 }78 }79 }

Indiferent de metoda cererii, mesajul http de raspuns este

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Content-Type: text/html

Content-Length: 119

Date: Sun, 30 Oct 2011 16:35:47 GMT

<html>

<head><title>HelloServlet</title></head>

<body>

<h1>HelloServlet</h1>

<p>

Hi mk !

</p>

</body>

</html>

6.2 Server Web - container de servlet

In prezent sunt disponibile mai multe servere Web ın care poate fi instalatun servlet si un fisier JSP Java Server Pages. Despre un asemenea server Webse spune ca este container de servlet si JSP. Dintre produsele gratuite amintim

• apache-tomcat

Page 148: programare distribuita

148 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

• jetty

• glassfish

Acest server Web este utilizat ın Glassfish - o implementare JEE (JavaEnterprise Edition) sprijinit de Oracle.

• jboss application server

Geronimo, o alta implementare JEE dezvoltata de fundatia apache, poateutiliza containerul apache-tomcat sau jetty.

Serverul Apache HTTP Server si Windows Internet Information Server nusunt servere Web containere de servlet si JSP.

6.3 Serverul Web apache-tomcat

Serverul Web apache-tomcat, (pe scurt tomcat) este distribuit gratuit sipoate fi descarcat pornind de la adresa www.apache.org.

Instalarea serverului ın mediul Windows revine la dezarhivarea fisieruluidescarcat apache-tomcat-***, ıntr-un catalog TOMCAT HOME. Utilizarea serveru-lui necesita fixarea a doi parametri sistem:

• CATALINA HOME= calea la catalogul ın care s-a instalat produsul - TOMCAT HOME;

• JAVA HOME=calea la distributia Java utilizata.

Pachetul contine cataloagele1: bin, common, conf, logs, server, shared,

temp, webapps, work.

Serverul se lanseaza prin comanda

TOMCAT HOME\bin\startup

si se opreste cu comanda

TOMCAT HOME\bin\shutdown

Din catalogul TOMCAT HOME, lansarea se poate obtine cu ajutorul fisieruluide comenzi (*.bat)

set CATALINA_HOME=. . .

set JAVA_HOME=. . .

bin\startup

1Numele si numarul cataloagelor este dependent de distributia apache-tomcat.

Page 149: programare distribuita

6.3. SERVERUL WEB APACHE-TOMCAT 149

Optional se poate instala / activa managerul / administatorul serverului Webtomcat.

Verificarea functionarii serverului Web tomcat se face apeland dintr-un nav-igator pagina http://host:port unde

• host este numele calculatorului pe care ruleaza tomcat;

• Portul implicit este 8080.

Reusita este ilustrata de imaginea motanului

Toate aplicatiile se depun ın catalogul TOMCAT HOME\webapps.

Asemanator se procedeaza si ın cazul serverului Web jetty. Nu este nevoiede nici o configurare suplimentara, lansarea facandu-se prin

cd . . .\jetty-hightide-*

java -jar start.jar

Din nou aplicatiile se depun ın catalogul \jetty-hightide-8.0.*\webapps.

Secure Socket Layer ın tomcat

Transmisia utilizand Secure Socket Layer - SSL (mai nou Transport LayerSecurity - TLS) ınseamna criptarea datelor care circula ıntre client si server.

Realizarea presupune

1. Generarea unui certificat de securitate cu utilitarul keytool din distributiaJava, de exemplu

keytool -genkey -alias tomcat -keyalg RSA

-keystore {cale}/tomcatKeystore

-dname "cn=SE, ou=cs, o=unitbv, l=brasov, c=RO"

-keypass 1q2w3e -storepass 1q2w3e

Parametrul keystore fixeaza locatia si denumirea fisierului certificatuluide securitate.

Se definesc doua parole

• keypass parola certificatului de securitate;

Page 150: programare distribuita

150 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

• storepass parola de protectie a locatiei certificatului de securitate.

Parametrul cale desemneaza calea catre catalogul unde ın care se creazafisierul tomcatKeystore - certificatul de securitate. Uzual, certificatul desecuritate se muta ın catalogul TOMCAT HOME\conf.

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

• Se decomenteaza elementul

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"

maxThreads="150" scheme="https" secure="true"

clientAuth="false" sslProtocol="TLS" />

• Acest element Connector se completeaza cu atributele

keystoreFile="conf\tomcatKeystore"

keystorePass="1q2w3e"

3. Serverul Web se apeleaza prin

https://localhost:8443

6.4 Glassfish

Instalarea si lansarea serverului. Instalarea consta din dezarhivareaarhivei descarcate.

Este recomandat includerea ın fisierul GLASSFISH HOME\grassfish\config\asenv.bat a liniei

set AS_JAVA=c:\Progra~1\Java\jdk1.*

Utilizarea paginilor JSP necesita aceasta setare.Prin intermediul paginii de administrare se poate schimba parola adminis-

tratorului (admin).Containerele ın care se depun aplicatiile se afla ıntr-un domeniu. Implicit,

ın catalogul glassfish\domain se creaza domeniul cu numele domain1:GLASSFISH HOME\glassfish\domains\domain1.

Lansarea serverului se poate face prin:

• Din GLASSFISH HOME\glassfish\bin se comanda

asadmin start-domain domain1

Oprirea serverului se poate face prin:

Page 151: programare distribuita

6.4. GLASSFISH 151

asadmin stop-domain domain1

Administrarea serverului se face prin

• pagina Web http://localhost:4848

• utilitarul GLASSFISH HOME\bin\asadmin.bat

Administratorul serverului are posibilitatea sa creeze domenii noi: Astfel creareaunui domeniu nou, avand numele numeDomeniu, situat ın catalogul dirDome-niu se obtine prinasadmin create-domain --adminport 4848 --domaindir dirDomeniu nume-Domeniu

Stergerea domeniului se obtine prinasadmin delete-domain --domaindir dirDomeniu numeDomeniu

Lansarea si oprirea serverului glassfish se comanda prinasadmin start-domain --domaindir dirDomeniu numeDomeniuasadmin stop-domain --domaindir dirDomeniu numeDomeniu

Page 152: programare distribuita

152 CAPITOLUL 6. HYPERTEXT TRANSFER PROTOCOL

Page 153: programare distribuita

Capitolul 7

Applet - Miniaplicatie Java

O categorie deosebita de programe Java ıl reprezinta miniaplicatiile (ap-plet-uri), care se executa prin intermediul unui program de navigare ın WWW(World Wide Web) – browser (Mozilla Firefox, Google Chrome, Microsoft In-ternetExplorer, Opera, Apple Safari. La aparitia limbajului de programareJava, acest tip de aplicatie a reprezentat unul din factorii de impact prin nou-tatea si simplitatea solutiei oferite.

Applet-ul este o resursa program, depusa ıntr-o zona publica, accesibilaprin Internet (server Web.) Un program de navigare preia codul applet-ului siıl executa. Apelarea unui applet se face dintr-un fisier html.

O aplicatie applet nu este o aplicatie de tip client server dar este prin modulde utilizare este o aplicatie distribuita.

Datorita acestui mod de folosire, applet-urile au o structura speciala sisunt supuse la reguli stricte de securitate, printre care acela de a nu puteascrie informatii pe calculatorul pe care se executa - calculatorul clientului.

Metoda actuala de apelare a unui applet se face prin intermediul uneiresurse Deployment Toolkit(DT) - o biblioteca de functii javascript. ResursaDT este apelabila la adresa http://java.com/js/deployJava.js sauhttp://www.java.com/js/deployJava.js

DT utilizeaza protocolul Java Network Launching Protocol (jnlp) si evitaproblemele de compatibilitate cu programul navigator. Aceasta resursa re-alizeaza descarcarea applet-ului cat si lansarea ın executie. Pe calculatorulclient, adica pe care ruleaza applet-ul, trebuie sa fie instalat jre - Java Run-time Environment - versiunea pe 32 biti.

Programarea unui applet se face prin extinderea clasei java.applet.Appletsau javax.swing.JApplet. Clasa Applet extinde clasa java.awt.Panel iarclasa JApplet extinde clasa Applet.

153

Page 154: programare distribuita

154 CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

Interfata grafica, ın cazul extinderii clasei Applet, va utiliza controlurileapartinand interfetei de programare AWT (Abstract Window Toolkit), iar ıncazul extinderii clasei JApplet se vor utiliza controluri JavaFX / Swing.

7.1 Clasa Applet

Structura unui applet este

import java.applet.*;

import java.awt.*;

public classNumeClasa extends Applet{public void init(){

Actiuni efectuate la instantierea clasei applet-ului.}public void start(){

Actiuni efectuate la lansarea applet-ului ın executie saula reıntoarcerea ın pagina applet-ului.

}public void paint(Graphics g){

Actiuni efectuate ori de cate ori este necesara re-desenarea ferestrei applet-ului.

}public void stop(){

Actiuni efectuate la oprirea applet-ului, ca urmare aınchiderii ferestrei corespunzatoare applet-ului.

}public void destroy(){

Actiuni efectuate la distrugerea applet-ului, ce au loccand navigatorul paraseste documentul html din care s-aapelat applet-ul.

}}

Executarea applet-ului este controlat de programul navigator si revine laapelarea metodelor init, start, stop. Acest fenomen se numeste inver-sarea controlului.

Page 155: programare distribuita

7.2. DESFASURAREA UNUI APPLET 155

7.2 Desfasurarea unui applet

Prin desfasurarea (deployment) unei aplicatii se ıntelege realizarea struc-turilor de cataloage si fisiere dar si a operatiilor care trebuie ıntreprinse ınvederea functionarii unei aplicatii distribuite.

Desfasurarea unui applet se poate face ın mai multe feluri:

Varianta 1

1. Arhivarea fisierelor class ale applet-ului.

2. Certificarea arhivei jar se realizeaza ruland succesiv

(a) keytool -genkey -keystore myKeystore -alias myself

-dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO"

-keypass abc123 -storepass 123abc

(b) keytool -selfcert -alias myself -keystore myKeystore

-keypass abc123 -storepass 123abc

(c) jarsigner -keystore myKeystore -keypass abc123 -storepass 123abc

resursa.jar myself

keytool.exe si jarsigner.exe se gasesc ın distributia jdk.

Primele doua actiuni au ca rezultat obtinerea certificatului myKeystoreiar ultima actiune reprezinta ınglobarea certificarii ın arhiva resursa.jar.

3. Editarea fisierului html de apelare a applet-ului. Sablonul specific apelariiapplet-ului este

<BODY>

. . .

<script src="http://java.com/js/deployJava.js"></script>

<script>

var attributes={ code:’numele_clasei_Applet’,

archive:’numele_arhivei_jar’,width:...,height:...};

var parameters={. . .};

var minimumVersion=’1.6’;

deployJava.runApplet(attributes, parameters, minimumVersion);

</script>

. . .

</BODY>

4. Cele doua fisiere (arhiva jar, fisierul html) se depun ıntr-un catalog alunui server Web, asigurand vizibilitatea aplicatiei ın Internet.

Page 156: programare distribuita

156 CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

Verificarea aplicatiei se poate face, dintr-un program navigator, prin sim-pla apelare a fisierului html. In acest caz, calculatorul trebuie sa fieconectat la internet.

Daca dispunem de deployJava.js atunci acest fisier se alatura celorlaltedoua resurse, iar atributul src al elementului script va fi src="deployJava.js".

Exemplul 7.2.1 ”Hello ”+nume. Numele se transmite miniaplicatiei caparametru.

Codul applet-ului este:

1 import java . awt . ∗ ;2 import java . app le t . ∗ ;

4 public class Inceput extends Applet{5 public void i n i t ( ){}

7 public void paint ( Graphics g ){8 St r ing name=getParameter ( ”nume” ) ;9 g . drawString ( ” He l lo ”+name+” ! ! ” , 50 , 60 ) ;

10 }11 }

Fisierul html de apelare (inceput.html)

1 < ! doctype html>2 <head>3 <meta charset=” utf−8”>4 </head>5 <body>6 <script src=” http :// java . com/ j s / deployJava . j s ”></ script>7 <script>8 var a t t r i b u t e s = { code : ’ Inceput . c l a s s ’ , a r ch ive : ’ inceput . ja r ’ ,9 width : 300 , he ight : 3 0 0} ;

10 var parameters={nume : ’XYZ’} ;11 var minimumVersion = ’ 1 . 6 . 0 ’ ;12 deployJava . runApplet ( a t t r i b u t e s , parameters , minimumVersion ) ;13 </ script>14 </body>15 </html>

Varianta 2

Pe aceasta cale se va edita un fisier de configurare cu extensia jnlp. Re-alizarea applet-ului consta din:

1. Arhivarea fisierelor class ale applet-ului.

2. Certificarea arhivei jar.

3. Editarea unui fisier de configurare jnlp. Structura acestui fisier este

Page 157: programare distribuita

7.2. DESFASURAREA UNUI APPLET 157

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

<jnlp spec="1.0+" codebase="http://host:port/cale_applet" href="">

<information>

<title>. . .</title>

<vendor>. . .</vendor>

</information>

<resources>

<!-- Application Resources -->

<j2se version="1.6+"

href="http://java.sun.com/products/autodl/j2se"

max-heap-size="128m" />

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

</resources>

<security>

<all-permissions/>

</security>

<applet-desc

name="numele_simbolic_al_applet-ului"

main-class="clasa_principala_a_applet-ului"

width="latimea_ferestrei_applet-ului"

height="inaltimea_ferestrei_applet-ului">

</applet-desc>

</jnlp>

4. Editarea fisierului html de apelare a applet-ului. Sablonul specific apelariiapplet-ului este

<BODY>

. . .

<script src="http://java.com/js/deployJava.js"></script>

<script>

var attributes={code:’numele_arhivei_jar’,width:...,height:...};

var parameters={jnlp_href: ’cmmdc.jnlp’};

var minimumVersion=’1.6’;

deployJava.runApplet(attributes, parameters, minimumVersion);

</script>

. . .

</BODY>

Page 158: programare distribuita

158 CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

5. Cele trei fisiere (eventual patru cu deployJava.js) se depun ıntr-un cata-log al unui server Web, asigurand vizibilitatea aplicatiei ın Internet.

Exemplul 7.2.2 Calculul celui mai mare divizor comun a doua naturale.

Introducerea datelor exterioare se face prin intermediul unei interfete grafice.Applet-ul extinzand clasa Applet are codul

1 import java . awt . ∗ ;2 import java . app le t . ∗ ;3 import java . awt . event . ∗ ;

5 public class VisualCmmdc extends Applet implements Act ionL i s t ene r {6 TextFie ld tm , tn , r e z ;

8 public void i n i t ( ){9 setBackground ( Color . ye l low ) ;

10 GridLayout g l=new GridLayout ( 3 , 2 , 3 0 , 2 0 ) ;11 setLayout ( g l ) ;12 Label lm=new Label ( ”Primul numar : ” ) ;13 add ( lm ) ;14 tm=new TextFie ld ( ”1” , 5 ) ;15 add (tm ) ;16 Label ln=new Label ( ”Al d o i l e a numar : ” ) ;17 add ( ln ) ;18 tn=new TextFie ld ( ”1” , 5 ) ;19 add ( tn ) ;20 Button compute=new Button ( ” Calcu leaza ” ) ;21 compute . addAct ionLis tener ( this ) ;22 add ( compute ) ;23 r e z=new TextFie ld ( ”1” , 5 ) ;24 r e z . s e t E d i t a b l e ( fa l se ) ;25 add ( r ez ) ;26 }

28 public void paint ( Graphics g ){29 St r ing sm=tm . getText ( ) ;30 long m=Long . parseLong (sm ) ;31 St r ing sn=tn . getText ( ) ;32 long n=Long . parseLong ( sn ) ;33 long c=cmmdc(m, n ) ;34 r e z . setText ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;35 }

37 public void act ionPerformed ( ActionEvent ae ){38 r epa in t ( ) ;39 }

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

iar ın cazul extinderii clasei JApplet (cu elemente grafice JavaFX)

1 import java . awt . Container ;2 import javax . swing . JApplet ;3 import j ava fx . embed . swing . JFXPanel ;4 import j ava fx . a p p l i c a t i o n . Platform ;5 import j ava fx . scene . c o n t r o l . Label ;

Page 159: programare distribuita

7.2. DESFASURAREA UNUI APPLET 159

6 import j ava fx . scene . c o n t r o l . TextFie ld ;7 import j ava fx . scene . c o n t r o l . Button ;8 import j ava fx . scene . pa int . Color ;9 import j ava fx . event . ActionEvent ;

10 import j ava fx . event . EventHandler ;11 import j ava fx . scene . Group ;12 import j ava fx . scene . Scene ;13 import j ava fx . scene . layout . GridPane ;

15 public class VisualCmmdc extends JApplet{16 stat ic private TextFie ld tm , tn , r e z ;

18 public void i n i t ( ) {19 Container content = getContentPane ( ) ;20 f ina l JFXPanel fxPanel = new JFXPanel ( ) ;21 content . add ( fxPanel ) ;22 content . s e t V i s i b l e ( true ) ;23 Platform . runLater (new Runnable ( ) {24 @Override25 public void run ( ) {26 initFX ( fxPanel ) ;27 }28 } ) ;29 }

31 private stat ic void initFX ( JFXPanel fxPanel ) {32 Group root = new Group ( ) ;33 Scene scene = new Scene ( root , 600 , 250 , Color .LIGHTGREEN) ;34 fxPanel . s e tScene ( scene ) ;35 GridPane gridPane = new GridPane ( ) ;

37 Label mLabel = new Label ( ”Primul numar” ) ;38 gridPane . add ( mLabel , 1 , 1 ) ; // column=1 row=139 tm=new TextFie ld ( ) ;40 gridPane . add (tm , 2 , 1 ) ;

42 Label nLabel = new Label ( ”Al d o i l e a numar” ) ;43 gridPane . add ( nLabel , 1 , 2 ) ; // column=1 row=144 tn=new TextFie ld ( ) ;45 gridPane . add ( tn , 2 , 2 ) ;

47 Button button = new Button ( ” Calcu leaza ” ) ;48 button . setOnAction (new EventHandler<ActionEvent >() {49 @Override50 public void handle ( ActionEvent e ) {51 St r ing sm = tm . getText ( ) ;52 St r ing sn = tn . getText ( ) ;53 long m=Long . parseLong (sm ) ;54 long n=Long . parseLong ( sn ) ;55 long r=cmmdc(m, n ) ;56 r e z . setText ( (new Long ( r ) ) . t oS t r i ng ( ) ) ;57 }58 } ) ;59 gridPane . add ( button , 1 , 3 ) ;

61 r e z = new TextFie ld ( ) ;62 gridPane . add ( rez , 2 , 3 ) ;63 root . ge tChi ldren ( ) . add ( gridPane ) ;64 fxPanel . s e tScene ( scene ) ;

Page 160: programare distribuita

160 CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

65 }

67 stat ic long cmmdc( long m, long n ) { . . .}68 }

Fisierul de configurare jnlp (cmmdc.jnlp) este

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <j n l p spec=”1.0+” codebase=”” h r e f=””>3 <i n fo rmat ion>4 < t i t l e>Visua l Cmmdc</ t i t l e>5 <vendor>Trans i l van ia Un ive r s i ty o f Brasov</ vendor>6 </ in fo rmat ion>7 <r e s o u r c e s>8 < !−− App l i ca t ion Resources −−>9 < j 2 s e version=”1.6+”

10 h r e f=” ht t p : // java . sun . com/ products / autodl / j 2 s e ”11 max−heap−s i z e=”128m” />12 < j a r h r e f=”cmmdc . j a r ” main=” true ” />13 </ r e s o u r c e s>14 <r e s o u r c e s os=”Windows”>15 < j f x : j a v a f x−runtime version=”2.0+”16 h r e f=” ht t p : // javad l . sun . com/webapps/download/ GetFi le /17 javafx−l a t e s t /windows−i 586 / java fx2 . j n l p ”/>18 </ r e s o u r c e s>19 <s e c u r i t y>20 <a l l−permi s s i ons />21 </ s e c u r i t y>22 <applet−desc23 name=”VisualCmmdc Applet ”24 main−c l a s s=”VisualCmmdc”25 width=”300”26 he ight=”300”>27 </ applet−desc>28 </ j n l p>

iar apelarea se face din (VisualCmmdc.html)

1 < ! doctype html>2 <head>3 <meta cha r s e t=” utf−8”>4 < l i n k r e l=” s t y l e s h e e t ” h r e f=”mycss . c s s ”>5 </head>6 <body>7 <c en te r>8 <h1> Cel mai mare d i v i z o r comun </h1>9 <s c r i p t s r c=” h t t p : // java . com/ j s / deployJava . j s ”></ s c r i p t>

10 <s c r i p t>11 var a t t r i b u t e s = { code : ’cmmdc ’ , width:300 , he i gh t : 300 } ;12 var parameters = { j n l p h r e f : ’cmmdc . j n l p ’ } ;13 var minimumVersion= ’ 1 .6 ’ ;14 deployJava . runApplet ( a t t r i b u t e s , parameters , minimumVersion ) ;15 </ s c r i p t>16 </ cente r>17 </body>18 </html>

Page 161: programare distribuita

7.3. COMUNICARE JAVA - JAVASCRIPT INTR-UN APPLET 161

7.3 Comunicare Java - JavaScript ıntr-un ap-

plet

Se pot apela functii JavaScript definite ın documentul html din care seapeleaza applet-ul.

Prin intermediul unui obiect de tip netscape.javascript.JSObject, creatprinstatic JSObject getWindow(java.applet.Applet applet)se apeleaza metodacall(String numeFunctieJavaScript, java.lang.Object[] args).

Sablonul de utilizare este

import netscape.javascript.*;

public void init(){

. . .

JSObject window=JSObject.getWindow(null);

window.call("numeFunctieJavaScript",args);

. . .

}

Pachetul netscape.javascript se afla ın distributia jdk ın catalogul JAVA HOME\jre\lib\plugin.jar. Pentru compilare, variabila de sistem classpath tre-buie sa contina aceasta referinta.

Page 162: programare distribuita

162 CAPITOLUL 7. APPLET - MINIAPLICATIE JAVA

Page 163: programare distribuita

Capitolul 8

Conexiune simpla prin clase dinjava.net

Pachetul java.net ofera, prin intermediul claselor URL, URLConnection,

HttpURLConnection, HttpsURLConnection, JarURLConnection o posibili-tate elementara de acces a unor resurse din Internet.

8.1 Clasa java.net.URL

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

potrivit protocolurilor http, https, ftp, file, jar.Constructori

• URL(String spec) throws MalformedURLException

Creaza un obiect URL legat de resursa specificata de spec, care trebuie safie o referinta URL valida.

Metode

• InputStream openStream() throws IOException

Returneaza fluxul de intrare pentru citirea resursei.

• URLConnection openConnection() throws IOException

Returneaza o instanta a conexiunii cu obiectul definit de URL.

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

163

Page 164: programare distribuita

164 CAPITOLUL 8. CONEXIUNE SIMPLA PRIN CLASE DIN JAVA.NET

Exemplul 8.1.1 Pe baza referintei catre un fisier html dintr-un catalog vizibilal unui server Web, sa se afiseze continutul fisierului.

In codul reprodus mai jos, fisierul Hello.html se afla pe serverul apache-tomcat, ın catalogul webapps\url.

1 import java . net .URL;2 import java . i o . InputStream ;3 import java . i o . InputStreamReader ;4 import java . i o . BufferedReader ;

6 pub l i c c l a s s ReadHTTP{7 pub l i c s t a t i c void main ( S t r ing [ ] a rgs ){8 St r ing adr=” ht tp : // l o c a l h o s t : 8 0 8 0 / u r l / He l lo . html” ;9 //System . se tProper ty ( ” http . proxyHost” , ” 1 0 . 3 . 5 . 1 3 3 ” ) ;

10 //System . se tProper ty ( ” http . proxyPort ” , ”3128” ) ;11 URL u r l=n u l l ;12 t ry {13 u r l=new URL( adr ) ;14 }15 catch ( Exception e ){16 System . out . p r i n t l n ( e . getMessage ( ) ) ;17 }18 t ry (19 InputStream in=u r l . openStream ( ) ;20 InputStreamReader i s r=new InputStreamReader ( in ) ;21 BufferedReader br=new BufferedReader ( i s r ) ;22 ){23 St r ing s ;24 do{25 s=br . readLine ( ) ;26 i f ( s != n u l l )27 System . out . p r i n t l n ( s ) ;28 }29 whi le ( s != n u l l ) ;30 }31 catch ( Exception e ){32 System . out . p r i n t l n ( e . getMessage ( ) ) ;33 }34 }35 }

In cazul ın care resursa - ın exemplul dat reprezentat de fisierul Hello.html- este accesibil doar ın urma autentificarii basic sau digest (Cap. Servlet,Autentificare, 9.5.5) atunci codul de mai sus trebuie completat cu

final String username = "digest";

final String password = "digest";

Authenticator.setDefault(new Authenticator(){

@Override

protected PasswordAuthentication getPasswordAuthentication(){

return new PasswordAuthentication(username,password.toCharArray());

}

});

Un exemplu privind utilizarea clasei java.net.HttpURLConnection estedat ın capitolul Servlet.

Page 165: programare distribuita

Capitolul 9

Servlet

Printre aplicatiile distribuite de tip client-server, ın care comunicatiile sebazeaza pe protocolul http, se disting:

• Aplicatii Web (site): Cererea adresata serverului este lansata uzual deo persoana utilizand un program navigator: Google Chrome, MozillaFirefox, Microsoft InternetExplorer, Opera, Apple Safari, etc.

• Servicii Web: Cererea catre server se face de un program. Aplicatiaserver si client se programeaza utilizand interfete de programare specifice.

Un servlet este

• un program Java care se excuta pe un server Web, compatibil;

• gestionat de serverul Web;

• capabil sa receptioneze si sa rapunda cererilor formulate de clienti.

De asemenea vom utiliza termenul servlet si pentru aplicatia Web corespunzatoare.Pe platforma de programare Java, servlet-ul este componenta care sta la

baza majoritatii cadrelor de dezvoltare (framework) pentru aplicatii si serviciiWeb.

Programarea si utilizarea unui servlet necesita:

• Cunoasterea marcajului html <form> pentru realizarea formularelor deintroducere a datelor;

• Utilizarea unui server Web, container de servleti.

165

Page 166: programare distribuita

166 CAPITOLUL 9. SERVLET

9.1 Marcajul <form>

Intr-un document html introducerea datelor se poate obtine utilizand mar-cajul <form> ...</form> .

Atribute ale marcajului <form> . Reamintim ca atributele se prezintaca perechi (nume, valoare) si se scriu ın antetul marcajului sub forma nume =valoare.

Nume Valoare Semnificatia valorii

action adresa tip URL Resursa care prelucreaza formularul.method GET Mesajul trimis serverului Web contine dupa

adresa URL numele si valorile parametrilorintrodusi. Adaugarea se face potrivit sintaxei

?numeParam1=valoare&numeParam2=valoare. . .Lungimea mesajului nu poate depasi 255 caractere.

POST Transmisia datelor se face ın fluxuri de date.Permite transferul unor fisiere de pe masina

clientului pe masina serverului.id Parametru de identificare a formularului (optional).name Nume atribuit formularului (optional).onSubmit Metoda JavaScript executata ınaintea apelarii

serverului Web (optional).

In continutul marcajului <form> putem include elemente de controlprin marcajele

• <input>

• <option>

• <select>

• <textarea>

Atributele marcajului < input> sunt:

Page 167: programare distribuita

9.2. REALIZAREA UNUI SERVLET 167

Nume Valoare Semnificatie

type text Se asteapta introducerea unui textpassword Se asteapta introducerea unei parolesubmit Se marcheaza sfarsitul completarii formularuluireset Se reinitializeaza formularulfile Permite selectarea unui fisierhidden Transmite mai departe un atribut fara vizualizarea lui

name numele controluluivalue valoarea (initiala) a controluluisize numarul caracterelor atasat controlului

In cazul marcajului < select> utilizarea este

<select name="nume">

<option value="valoare"> Valoare

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

</select>

Valoarea atributului nume este data de valoarea selectata.

9.2 Realizarea unui servlet

Interfata de programare (API) pentru servlet nu face parte din JDK, fiindimplementat de fiecare producator de server Web container de servlet.

Structura minimala a unui servlet este

catalogAppServlet

|--> WEB-INF

| |--> classes

| | | *.class

| |--> lib

| | | *.jar

| index.html

Catalogul classes contine fisierele class ale aplicatiei servlet.Catalogul lib este optional si va contine resursele jar suplimentare cerute

de clasele servlet-ului.Prin intermediul fisierului index.html se apeleaza aplicatia servlet. Adresa

de apelare (URL - Universal Resource Locator) a aplicatiei servlet este

http://host:port/catalogAppServlet

Page 168: programare distribuita

168 CAPITOLUL 9. SERVLET

Daca ın loc de index fisierul html de apelare are alt nume, de exemplu xyz.htmlatunci adresa de apelare va fi

http://host:port/catalogAppServlet/xyz.html

host este numele calculatorului pe care ruleaza serverul Web - gazda aplicatieiservlet. Portul implicit utilizat de un server Web container de servlet este8080.

Catalogul aplicatiei este denumit context-ul servlet-ului.Apelarea servlet-ului se poate face:

• din meniul File/Open al unui navigator;

• ca referinta ıntr-un document html

<a href="URL-servlet">...</a>

Din documentul html pomenit anterior, apelarea clasei servlet se face uzualprin intermediul atributului action a elementului form. Valoarea atributuluieste numele de apel al servlet-ului.

Prin Asynchronous JavaScript And Xml - AJAX un servlet se poate apeladintr-o functie Javascript.

Legatura cu clasa servlet-ului se poate realiza

• programat – prin adnotari ın codul servlet-ului;

• descriptiv – ın catalogul WEB-INF se editeaza fisierul web.xml.

In versiunile anterioare ale interfetei de programare servlet aceasta a fostunica optiune.

Trebuie demarcata diferenta dintre apelarea / lansarea ın executie a claseiservlet de apelarea aplicatiei Web.

Modul programat se bazeaza pe adnotarea javax.servlet.annotation.WebServlet cu elementele:

String nameString[ ] urlPatterns@WebInitParams[ ] initParamsboolean asyncSupportedlong asyncTimeout

Modul descriptiv In fisierul web.xml apar elementele

Page 169: programare distribuita

9.2. REALIZAREA UNUI SERVLET 169

1. <servlet> leaga numele servlet-ului definit ın elementul<servlet-name>de clasa servlet-ului dat ın elementul <servlet-class> .

2. <servlet-mapping> defineste numele sub care servlet-ul identificat prin<servlet-name>nume servlet< /servlet-name> se invoca din progra-mul navigator. Acest identificator - numeApel - se fixeaza ın elementul<url-pattern> . Identificatorul are ca prefix caracterul / (slash).

Structura unui fisier web.xml este

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <web−app version=” 3 .0 ” xmlns=” h t t p : // java . sun . com/xml/ns/ javaee ”3 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”>4 <s e r v l e t>5 <s e r v l e t−name>nume se rv l e t 1</ s e r v l e t−name>6 <s e r v l e t−c l a s s>Nume clasa</ s e r v l e t−c l a s s>7 </ s e r v l e t>8 <s e r v l e t>9 <s e r v l e t−name>nume se rv l e t 2</ s e r v l e t−name>

10 <s e r v l e t−c l a s s>Nume clasa</ s e r v l e t−c l a s s>11 </ s e r v l e t>12 . . .13 <s e r v l e t−mapping>14 <s e r v l e t−name>nume se rv l e t 1</ s e r v l e t−name>15 <ur l−pattern>/numeApel 1</ ur l−pattern>16 </ s e r v l e t−mapping>17 <s e r v l e t−mapping>18 <s e r v l e t−name>nume se rv l e t 2</ s e r v l e t−name>19 <ur l−pattern>/numeApel 2</ ur l−pattern>20 </ s e r v l e t−mapping>21 . . .22 </web−app>

Unui element<servlet> ıi pot corespunde mai multe elemente<servlet-mapping>,prin utilizarea de numeApel diferite.

Optional web.xml poate contine elementul

<welcome-file-list>

<welcome-file>

fisier.html sau jsp

</welcome-file>

</welcome-file-list>

cu precizarea fisierelor html sau jsp care apeleaza aplicatia Web. Declaratiafisierului index.html este implicita.

Compilarea clasei servlet necesita completarea variabilei de mediu classpath

cu fisierul TOMCAT HOME\lib\servlet-api.jar.Odata completata structura de cataloage si fisiere ale aplicatiei servlet

aceasta structura trebuie copiata ın catalogul TOMCAT HOME\webapps. Aceastaoperatie se numeste desfasurarea (deployment) sau instalarea servlet-ului.Copierea se poate executa si cu serverul Web pornit.

Pentru instalarea unui servlet exista mai multe alternative:

Page 170: programare distribuita

170 CAPITOLUL 9. SERVLET

• Din catalogul catalogAppServlet se realizeaza arhiva catalogAppServlet.war

jar cfv catAppServlet.war WEB-INF\∗ index.html

care se copiaza ın catalogul TOMCAT HOME\webapps.

Serverul Web tomcat va dezarhiveaza arhiva. Astfel servlet-ul este insta-lat.

Aceasta instalare se numeste instalare dinamica - hot deployment.

Daca fisierul war este creat, atunci ın locul copierii, instalarea se poateface prin componenta manager a lui tomcat.

• O aplicatie servlet arhivata war se poate instala de la distata prin pro-dusele:

– apache-tomcat-deployer

– cargo

9.2.1 Codul unui servlet

Un servlet implementeaza interfata Servlet sau extinde una din claseleGenericServlet sau HttpServlet. GenericServlet implementeaza interfataServlet, iar HttpServlet extinde clasa GenericServlet. Extinzand clasaGenericServlet nu este nevoie de rescrierea tuturor metodelor abstracte aleinterfetei Servlet.

Metodele interfetei Servlet sunt:

• abstract public void init(ServletConfig config)

Se apeleaza o singura data la lansarea servlet-ului.

• abstract public void service(ServletRequest req, ServletResponseres)throws ServletException,IOException

Metoda este apelata de serverul Web pentru rezolvarea cererii unui client.

• abstract public void destroy()

Se apeleaza o singura data la distrugerea servlet-ului.

• public String getServletInfo()

• public ServletConfig getServletConfig()

Page 171: programare distribuita

9.2. REALIZAREA UNUI SERVLET 171

In cele ce urmeaza o clasa servlet va fi o clasa care extinde clasa HttpServlet.In locul metodei service(...), programatorul suprascrie metodele doGet(...)sau doPost(...), ın functie de metoda utilizata de client la lansarea cererii.

Practic, un servlet consta din scrierea metodelor

• void init(ServletConfig config)

Aceasta metoda este optionala.

public void init(ServletConfig config) throws ServletException{

super.init(config);

// cod de initializare

}

Obiectul config are o metoda String getInitParameter(String nu-meParam) cu ajutorul careia se pot recupera parametri de initializareasociati servlet-ului si care se dau fie prin adnotarea WebInitParam prinsablonul

import javax.servlet.annotation.WebInitParam;

@WebServlet(urlPatterns = "/numeApel",

initParams = {

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

. . .

}

)

fie ın fisierul web.xml prin elementele

<init-param>

<param-name> NumeleParametrului </param-name>

<param-value> Valoare </param-value>

</init-param>

cuprinse ın elementul <servlet>.

• protected void doGet(HttpServletRequest req, HttpServletResponseres) throws IOException, ServletException

Trateaza o cerere trimisa cu metoda GET (vezi marcajul <form>).

Page 172: programare distribuita

172 CAPITOLUL 9. SERVLET

• protected void doPost(HttpServletRequest req, HttpServletResponseres) throws IOException, ServletException

Trateaza o cerere trimisa cu metoda POST (vezi marcajul <form>).

Activitatile de ıntreprins ıntr-o metoda doGet() sau doPost() sunt

1. Stabilirea naturii raspunsului:res.setContentType(String tip)

unde tip specifica tipul MIME - Multipurpose Internet Mail Extensionsal raspunsului:

• "text/html" - pagina html;

• "text/xml" - document xml;

• "text/plain" - text;

• "image/jpg" - imagine jpg;

• "image/gif" - imagine gif.

2. Se obtine o referinta catre un obiect care realizeaza transmisia datelorcatre navigatorul clientului:ServletOutputStream out = res.getOutputStream();

sauPrintWriter out=res.getWriter();

3. Se preiau datele cererii cu una din metodele interfetei HttpServletRequest:String getParameter(String numeParametru)java.util.Enumeration getParameterNames()

Aditional se pot afla

• calculatorul cu serverul web: getServerName();

• portul: getServerPort();

• catalogul servlet-ului: getContextPath().

4. Rezolva cererea clientului;

5. Formeaza si scrie raspunsul;

6. Inchide conexiunea obiectului prin care s-a realizat transmisia datelorcatre navigatorul clientului prin out.close().

Page 173: programare distribuita

9.2. REALIZAREA UNUI SERVLET 173

Un camp (global) declarat ın clasa servletului este comun fiecarei instantea servletului.

Un utilizator lanseaza o cerere catre servlet. De obicei acest lucru se re-alizeaza prin completarea unui formular al unui document html. Programulnavigator trimite cererea serverului Web prin intermediul caruia este lansatservlet-ul ın actiune.

Ciclul de viata al unui servlet. Cand un servlet este apelat primadata de catre serverul Web se executa metoda init. Dupa aceasta, fiecareicereri lansate de un utilizator i se asociaza un fir de executie ın care se ape-leaza metoda service. Metoda service apeleaza apoi metodele doGet(),

doPost().

Exemplul 9.2.1 Servlet-ul Hello: Clientul transmite numele servlet-ului careıi raspunde cu mesajul de salut ”Hi” + nume!.

Formularul html prin care clientul introduce numele este (index.html)

1 < ! doctype html>2 <head>3 <meta charset=” utf−8”>4 <l ink rel=” s t y l e s h e e t ” href=”mycss . c s s ”>5 </head>6 <body>7 <center>8 <h1> Pagina de ape l a r e a s e r v l e t u l u i H e l l o S e r v l e t </h1>9 <form method=” post ”

10 action=” h e l l o ”>11 <table>12 <tr>13 <td><label>I n t r o d u c e t i numele </ label></td>14 <td>15 <input type=” text ” name=”name” s ize=”20”>16 </td>17 </ tr>18 <tr>19 <td>20 <input type=”submit” value=” Calcu leaza ”>21 </td>22 </ tr>23 </table>24 <input type=” hidden ” name=” t i p ” value=” text /html” >25 </form>26 </center>27 </body>28 </html>

In modul programat servlet-ului are codul

1 import java . i o . IOException ;2 import javax . s e r v l e t . Se rv l e tExcept ion ;3 import javax . s e r v l e t . http . HttpServ l e t ;4 import javax . s e r v l e t . http . HttpServ letRequest ;

Page 174: programare distribuita

174 CAPITOLUL 9. SERVLET

5 import javax . s e r v l e t . http . HttpServletResponse ;6 import javax . s e r v l e t . ServletOutputStream ;7 import javax . s e r v l e t . annotat ion . WebServlet ;

9 @WebServlet ( u r lPa t t e rn s = ”/ h e l l o ” )10 public class H e l l o S e r v l e t extends HttpServ l e t {11 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )12 throws Serv le tExcept ion , IOException{13 r e s . setContentType ( ” text /html” ) ;14 ServletOutputStream out=r e s . getOutputStream ( ) ;15 St r ing nume=req . getParameter ( ”name” ) ;16 out . p r i n t l n ( ”<html>” ) ;17 out . p r i n t l n ( ”<head><t i t l e >He l l oSe rv l e t </ t i t l e ></head>” ) ;18 out . p r i n t l n ( ”<body>” ) ;19 out . p r i n t l n ( ”<h1>He l l oSe rv l e t </h1>” ) ;20 out . p r i n t l n ( ”<p>” ) ;21 out . p r i n t l n ( ”Hi ”+ nume+” ! ” ) ;22 out . p r i n t l n ( ”</p>” ) ;23 out . p r i n t l n ( ”</body>” ) ;24 out . p r i n t l n ( ”</html>” ) ;25 out . c l o s e ( ) ;26 }

28 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )29 throws Serv le tExcept ion , IOException{30 doGet ( req , r e s ) ;31 }32 }

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

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <web−app version=” 3 .0 ” xmlns=” h t t p : // java . sun . com/xml/ns/ javaee ”3 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”>4 <s e r v l e t>5 <s e r v l e t−name>h e l l o</ s e r v l e t−name>6 <s e r v l e t−c l a s s>H e l l o S e r v l e t</ s e r v l e t−c l a s s>7 </ s e r v l e t>

9 <s e r v l e t−mapping>10 <s e r v l e t−name>h e l l o</ s e r v l e t−name>11 <ur l−pattern>/ h e l l o</ ur l−pattern>12 </ s e r v l e t−mapping>13 </web−app>

Compilarea si arhivarea servlet-ului o vom realiza prin intermediul luiapache-ant. In acest scop se creaza structura:

hello

| |---> src

| | | HelloServlet.java

| |---> web

| | |---> WEB-INF

| | | |---> classes

| | | |---> lib

| | | | web.xml

| | | index.html

| build.xml

Page 175: programare distribuita

9.2. REALIZAREA UNUI SERVLET 175

si se utilizeaza fisierul build.xml

1 <p r o j e c t ba s ed i r=” . ” default=” generate . war”>2 <property name=”TOMCATHOME” value=” . . . ”/>3 <property name=” d i s t . name” value=” apphel loP ” />4 <property name=” d i s t . d i r ” va lue=” d i s t ” />

6 <path id=” myclasspath ”>7 < f i l e s e t d i r=”web/WEB−INF/ l i b ”>8 <i n c l ude name=” ∗ . j a r ”/>9 </ f i l e s e t>

10 <pathelement path=”${TOMCATHOME}/ l i b / s e r v l e t−api . j a r ” />11 </path>

13 <t a r g e t name=” i n i t ”>14 <d e l e t e d i r=”${ d i s t . d i r }”/>15 <d e l e t e d i r=”web/WEB−INF/ c l a s s e s ”/>16 <mkdir d i r=”web/WEB−INF/ c l a s s e s ”/>17 <mkdir d i r=”${ d i s t . d i r }” />18 </ t a r g e t>

20 <t a r g e t name=” compile ” depends=” i n i t ”>21 <javac c l a s s p a t h r e f=” myclasspath ”22 inc ludeantrunt ime=” f a l s e ”23 s r c d i r=”${ based i r }/ s r c ”24 d e s t d i r=”web/WEB−INF/ c l a s s e s ” />25 </ t a r g e t>

27 <t a r g e t name=” generate . war” depends=” compi le ”>28 < j a r d e s t f i l e=”${ d i s t . d i r }/${ d i s t . name } . war” bas ed i r=”web” />29 </ t a r g e t>30 </ p r o j e c t>

Observatie. Valoarea parametrului dist.name defineste parametrul catalo-gAppServlet.

Se lanseaza ın executie serverul Web tomcat, se ıncarca servlet-ul ın serverulWeb si dintr-un navigator se deschide pagina http://localhost:8080/apphello

Exemplul 9.2.2 Servlet pentru calculul celui mai mare divizor comun a douanumere.

1 import java . i o . IOException ;2 import java . i o . Pr intWriter ;3 import javax . s e r v l e t . Se rv l e tExcept ion ;4 import javax . s e r v l e t . http . HttpServ l e t ;5 import javax . s e r v l e t . http . HttpServ letRequest ;6 import javax . s e r v l e t . http . HttpServletResponse ;7 import javax . s e r v l e t . annotat ion . WebServlet ;

9 @WebServlet ( u r lPa t t e rn s = ”/cmmdc” )10 public class CmmdcServlet extends HttpServ l e t {

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

14 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )

Page 176: programare distribuita

176 CAPITOLUL 9. SERVLET

15 throws Serv le tExcept ion , IOException{16 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;17 St r ing t i p=req . getParameter ( ” t i p ” ) ;18 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;19 long x=cmmdc(m, n ) ;20 PrintWriter out=r e s . getWriter ( ) ;21 i f ( t i p . equa l s ( ” t ext /html” ) ){22 St r ing t i t l e=”CmmdcServlet” ;23 r e s . setContentType ( ” text /html” ) ;24 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;25 out . p r i n t l n ( t i t l e ) ;26 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;27 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;28 out . p r i n t l n ( ”<P>Cmmdc i s ”+x ) ;29 out . p r i n t l n ( ”</BODY></HTML>” ) ;30 }31 else {32 r e s . setContentType ( ” text / p l a i n ” ) ;33 out . p r i n t l n ( x ) ;34 }35 out . c l o s e ( ) ;36 }

38 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )39 throws Serv le tExcept ion , IOException{40 doGet ( req , r e s ) ;41 }42 }

apelabil prin documentul html (index.html)

1 < ! doctype html>2 <head>3 <meta charset=” utf−8”>4 <l ink rel=” s t y l e s h e e t ” href=”mycss . c s s ”>5 </head>6 <body>7 <center>8 <h1> Pagina de ape l a r e CmmdcServlet </h1>9 <form method=” get ”

10 action=”cmmdc”>11 <table>12 <tr>13 <td><label> Primul numar </ label></td>14 <td>15 <input type=” text ” name=”m” s ize=”5”16 r equ i r ed pattern=” [0−9]{1 ,} ”>17 </td>18 </ tr>19 <tr>20 <td><label> Al d o i l e a numar </ label></td>21 <td>22 <input type=” text ” name=”n” s ize=”5”23 r equ i r ed pattern=” [0−9]{1 ,} ”>24 </td>25 </ tr>26 <tr>27 <td>28 <p><input type=”submit” value=” Calcu leaza ”>

Page 177: programare distribuita

9.3. PROCESARE ASINCRONA IN JAVA SERVLET 3.0 177

29 </td>30 </ tr>31 </table>32 <input type=” hidden ” name=” t i p ” value=” text /html” >33 </form>34 <center>35 </body>36 </html>

Pentru fixarea naturii raspunsului text/html sau text/plain s-a introdusvariabila tip, care ın fisierul de invocare index.html primeste pe ascuns valoareatext/html. In cazul ın care vom apela servlet-ul dintr-un program, va fiavantajos sa primim raspunsul ca text/plain.

9.3 Procesare asincrona ın Java Servlet 3.0

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

doPost) se executa de catre serverul Web ıntr-un fir de executie. Aceastaexecutie este sincrona ın sensul ın care trecerea la instructiunea urmatoare areloc doar la ıncheierea executiei instructiunii curente. Firul de executie estecreat si lansat de serverul Web.

Interfata de programare Servlet 3.0 ofera posibilitatea unui executii asin-crone: satisfacerea cererii clientului se face ıntr-un fir de executie lansat declasa servlet-ului. Terminarea activitatii clasei servlet nu mai este legata derezolvarea cererii clientului si de trimiterea raspunsului.

Acest mod de executie se indica prin adnotarea@WebServlet(urlPaterns="/numeApel" ,asyncSupported=true)

Suportul asincron necesita un context, obiect de tip AsyncContext

AsyncContext asyncCtx=req.startAsync(req,res);

Activitatile ce trebuie ındeplinite pentru satisfacerea cererii clientului selanseaza ıntr-un fir de executie, obiect care este parte a unei familii gestionatede o clasa ce implementeaza interfata Executor:

• public ScheduledThreadPoolExecutor(int corePoolSize)

• public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

Interfata AsyncListener permite notificarea evenimentelor

• void onComplete(AsyncEvent ae)

• void onTimeout(AsyncEvent ae)

Page 178: programare distribuita

178 CAPITOLUL 9. SERVLET

• void onError(AsyncEvent ae)

• void onStartAsync(AsyncEvent ae)

Obiectul de tip AsyncEvent este creat ın momentul satisfacerii cererii clientu-lui, depasirii timpului alocat sau producerii unei erori.

Exemplul 9.3.1 Varianta asincrona a servlet-ului de calcul a celui mare di-vizor comun.

1 package myserv let ;2 import javax . s e r v l e t . Se rv l e tExcept ion ;3 import javax . s e r v l e t . AsyncContext ;4 import javax . s e r v l e t . http . HttpServ l e t ;5 import javax . s e r v l e t . http . HttpServ letRequest ;6 import javax . s e r v l e t . http . HttpServletResponse ;7 import javax . s e r v l e t . annotat ion . WebServlet ;8 import java . u t i l . concurrent . Executor ;9 import java . u t i l . concurrent . ScheduledThreadPoolExecutor ;

10 import java . i o . IOException ;11 import l i s t e n e r s . MyAsyncListener ;

13 @WebServlet ( u r lPa t t e rn s=”/cmmdc” , asyncSupported=true )14 public class AsyncServ let extends HttpServ l e t {15 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )16 throws Serv le tExcept ion , IOException{17 AsyncContext asyncCtx=req . startAsync ( req , r e s ) ;18 asyncCtx . addLis tener (new MyAsyncListener ( ) ) ;19 Executor executor=new ScheduledThreadPoolExecutor ( 1 0 ) ;20 executor . execute (new AsyncWebService ( asyncCtx ) ) ;21 }

23 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )24 throws Serv le tExcept ion , IOException{25 doGet ( req , r e s ) ;26 }27 }

Firul de executie responsabil cu ındeplinirea cererii clientului este

1 package myserv let ;2 import javax . s e r v l e t . Serv l e tReques t ;3 import javax . s e r v l e t . Serv le tResponse ;4 import javax . s e r v l e t . AsyncContext ;5 import java . i o . IOException ;6 import java . i o . Pr intWriter ;

8 public class AsyncWebService implements Runnable{9 AsyncContext asyncCtx ;

11 public AsyncWebService ( AsyncContext asyncCtx ){12 this . asyncCtx=asyncCtx ;13 }

15 public void run ( ){

Page 179: programare distribuita

9.3. PROCESARE ASINCRONA IN JAVA SERVLET 3.0 179

16 Serv l e tReques t req=asyncCtx . getRequest ( ) ;17 Serv le tResponse r e s=asyncCtx . getResponse ( ) ;18 St r ing sm=req . getParameter ( ”m” ) ;19 St r ing sn=req . getParameter ( ”n” ) ;20 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;21 long x=cmmdc(m, n ) ;22 St r ing r e s u l t=new Long ( x ) . t oS t r i ng ( ) ;23 try{24 PrintWriter out=r e s . getWriter ( ) ;25 St r ing t i t l e=”Cmmdc S e r v l e t ” ;26 r e s . setContentType ( ” text /html” ) ;27 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;28 out . p r i n t l n ( t i t l e ) ;29 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;30 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;31 out . p r i n t l n ( ”<P>Cmmdc i s ”+x ) ;32 out . p r i n t l n ( ”</BODY></HTML>” ) ;33 out . c l o s e ( ) ;34 }35 catch ( IOException e ){36 System . out . p r i n t l n ( e . getMessage ( ) ) ;37 }38 }

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

Clasa care implementeaza interfata AsyncListener

1 package l i s t e n e r s ;2 import javax . s e r v l e t . AsyncEvent ;3 import javax . s e r v l e t . AsyncListener ;4 import javax . s e r v l e t . Serv l e tReques t ;

6 public class MyAsyncListener implements AsyncListener {

8 public MyAsyncListener ( ){}

10 public void onComplete ( AsyncEvent ae ){11 Serv l e tReques t req=ae . getAsyncContext ( ) . getRequest ( ) ;12 St r ing r=req . getParameter ( ”m”)+” <−> ”+req . getParameter ( ”n” ) ;13 System . out . p r i n t l n ( ” AsyncListener : onComplete f o r r eque s t : ”+r ) ;14 }

16 public void onTimeout ( AsyncEvent ae ){17 Serv l e tReques t req=ae . getAsyncContext ( ) . getRequest ( ) ;18 St r ing r=req . getParameter ( ”m”)+” <−> ”+req . getParameter ( ”n” ) ;19 System . out . p r i n t l n ( ” AsyncListener : onTimeout f o r r eque s t : ”+r ) ;20 }

22 public void onError ( AsyncEvent ae ){23 Serv l e tReques t req=ae . getAsyncContext ( ) . getRequest ( ) ;24 St r ing r=req . getParameter ( ”m”)+” <−> ”+req . getParameter ( ”n” ) ;25 System . out . p r i n t l n ( ” AsyncListener : onError f o r r eque s t : ”+r ) ;26 }

28 public void onStartAsync ( AsyncEvent ae ){29 Serv l e tReques t req=ae . getAsyncContext ( ) . getRequest ( ) ;30 St r ing r=req . getParameter ( ”m”)+” <−> ”+req . getParameter ( ”n” ) ;

Page 180: programare distribuita

180 CAPITOLUL 9. SERVLET

31 System . out . p r i n t l n ( ” AsyncListener : onStartAsync f o r r eque s t : ”+r ) ;32 }33 }

9.4 Dezvoltari ın servlet-api 3.1

Servlet-api 3.1 este implemetat ın glassfish 4.0.

9.4.1 Procesare asincrona neblocanta

Diferenta majora consta ın faptul ca solicitarea clientului este trimisa ne-mijlocit si ındeplinita de o clasa tip listener.

Clasa javax.servlet.ServletInputStream

Metode

• public int readLine(byte[] b, int off, int len) throws IOException

• public void setReadListener(ReadListenerreadListener)

Interfata javax.servlet.ReadListener declara metodele

• void onDataAvailable() throws IOException

• void onAllDataRead() throws IOException)

• void onError(Throwable t)

Exemplul 9.4.1

1 import java . i o . IOException ;2 import java . i o . Pr intWriter ;3 import java . net .URL;4 import javax . s e r v l e t . AsyncContext ;5 import javax . s e r v l e t . Se rv l e tExcept ion ;6 import javax . s e r v l e t . Serv let InputStream ;7 import javax . s e r v l e t . annotat ion . WebServlet ;8 import javax . s e r v l e t . http . HttpServ l e t ;9 import javax . s e r v l e t . http . HttpServ letRequest ;

10 import javax . s e r v l e t . http . HttpServletResponse ;

12 @WebServlet ( u r lPa t t e rn s = {”/ nonblock ” } , asyncSupported=true )13 public class NonBlockingServ let extends HttpServ l e t {14 protected void doGet ( HttpServ letRequest req , HttpServletResponse r e s )15 throws Serv le tExcept ion , IOException {16 r e s . setContentType ( ” text /html ; cha r s e t=UTF−8” ) ;17 try ( Pr intWriter output = r e s . getWriter ( ) ) {18 output . p r i n t l n ( ”<html>” ) ;

Page 181: programare distribuita

9.4. DEZVOLTARI IN SERVLET-API 3.1 181

19 output . p r i n t l n ( ”<body>” ) ;20 output . p r i n t l n ( ”<h1>S e r v l e t NonBlockingServlet at ” +21 req . getContextPath ( ) + ”</h1>” ) ;

23 AsyncContext context = req . startAsync ( ) ;24 Serv let InputStream input = req . getInputStream ( ) ;25 input . s e tReadLi s tener (new CmmdcListener ( input , context , output ) ) ;26 output . p r i n t l n ( ”</body>” ) ;27 output . p r i n t l n ( ”</html>” ) ;28 }29 }

31 @Override32 protected void doPost ( HttpServ letRequest req , HttpServletResponse r e s )33 throws Serv le tExcept ion , IOException {34 doGet ( req , r e s ) ;35 }36 }

ımpreuna cu

1 import java . i o . IOException ;2 import javax . s e r v l e t . AsyncContext ;3 import javax . s e r v l e t . ReadListener ;4 import javax . s e r v l e t . Serv let InputStream ;5 import java . i o . Pr intWriter ;

7 public class CmmdcListener implements ReadListener {

9 private Serv let InputStream input = null ;10 private AsyncContext context = null ;11 private PrintWriter out = null ;

13 public CmmdcListener ( Serv let InputStream in , AsyncContext ac ,14 PrintWriter output ){15 input = in ;16 context = ac ;17 out = output ;18 }

20 @Override21 public void onDataAvai lable ( ) {22 try {23 St r i ngBu i l d e r sb = new St r i ngBu i l d e r ( ) ;24 int l en = −1;25 byte b [ ] = new byte [ 1 0 2 4 ] ;26 while ( input . isReady ( ) && ( l en = input . read (b ) ) != −1) {27 St r ing data = new St r ing (b , 0 , l en ) ;28 out . wr i t e ( data ) ;29 out . wr i t e ( ”<p>” ) ;30 St r ing rez=s o l v e r ( data ) ;31 out . wr i t e ( r e z ) ;32 }33 }34 catch ( IOException e ) {35 System . out . p r i n t l n ( ” onAvai lab leExcept ion : ”+e . getMessage ( ) ) ;36 }37 }

Page 182: programare distribuita

182 CAPITOLUL 9. SERVLET

39 @Override40 public void onAllDataRead ( ) {41 System . out . p r i n t l n ( ”onAllDataRead” ) ;42 context . complete ( ) ;43 }

45 @Override46 public void onError ( Throwable t ) {47 t . pr intStackTrace ( ) ;48 context . complete ( ) ;49 }

51 private St r ing s o l v e r ( S t r ing data ){52 St r ing [ ] s=data . s p l i t ( ”&” ) ;53 St r ing [ ] s0=s [ 0 ] . s p l i t ( ”=” ) ;54 long m=Long . parseLong ( s0 [ 1 ] ) ;55 St r ing [ ] s1=s [ 1 ] . s p l i t ( ”=” ) ;56 long n=Long . parseLong ( s1 [ 1 ] ) ;57 St r ing r=(new Long (cmmdc(m, n ) ) ) . t oS t r i ng ( ) ;58 return ”Cmmdc : ”+r ;59 }

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

9.4.2 Modificarea protocolului http: upgrade

Schema este utilizata deja pentru utilizarea protocolului websocket.In apelul http trebuie inserat antetul (header) Upgrade. Odata aceast

antet recunoscut, solicitarea clientului este rezolvata ıntr-o clasa care imple-menteaza interfata javax.servlet.http.HttpUpgradeHandler.

Interfata declara metodele

• void init(WebConnection wc)

• void destroy()

Interfata javax.servlet.http.WebConnection

Metode

• ServletInputStream getInputStream() throws IOException

• ServletOutputStream getOutputStream() throws IOException

Clasa care implementeaza interfata HttpUpgradeHandler se declara ınservlet prin metoda interfetei HttpServletRequest

<T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)throws IOException, ServletException

In principiu clasa servlet-ului este independenta de specificul aplicatiei.

Page 183: programare distribuita

9.4. DEZVOLTARI IN SERVLET-API 3.1 183

1 import javax . s e r v l e t . Se rv l e tExcept ion ;2 import javax . s e r v l e t . http . HttpServ l e t ;3 import javax . s e r v l e t . http . HttpServ letRequest ;4 import javax . s e r v l e t . http . HttpServletResponse ;5 import javax . s e r v l e t . annotat ion . WebServlet ;

7 @WebServlet ( u r lPa t t e rn s = {”/upgrade” })

9 public class UpgradeServlet extends HttpServ l e t {

11 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )12 throws Serv le tExcept ion , IOException{13 i f ( ”upgrade” . equa l s ( req . getHeader ( ”Upgrade” ) ) ){14 r e s . s e t S ta tu s ( 1 0 1 ) ;15 r e s . setHeader ( ”Upgrade” , ”upgrade” ) ;16 r e s . setHeader ( ” Connection ” , ”Upgrade” ) ;17 r e s . f l u s h B u f f e r ( ) ;18 System . out . p r i n t l n ( ”Upgrade OK ”+req . getHeader ( ”Upgrade” ) ) ;19 MyHttpUpgradeHandler handler = req . upgrade ( MyHttpUpgradeHandler . class ) ;20 }21 else {22 System . out . p r i n t l n ( ”No upgrade : ” ) ;23 }24 }

26 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )27 throws Serv le tExcept ion , IOException{28 doGet ( req , r e s ) ;29 }30 }

Problema care ramane de rezolvat este inserarea antetului Update. Re-zolvarea consta ın generarea unui mesaj http care se va transmite printr-unsoclu TCP. Mesajul http foloseste metoda post, iar datele din corpul mesaju-lui sunt preluate prin interfata HttpInputStream.

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

1 import javax . s e r v l e t . ServletOutputStream ;2 import javax . s e r v l e t . Serv let InputStream ;3 import javax . s e r v l e t . http . WebConnection ;4 import javax . s e r v l e t . http . HttpUpgradeHandler ;

6 public class MyHttpUpgradeHandler implements HttpUpgradeHandler {7 private WebConnection wc = null ;

9 @Override10 public void i n i t ( WebConnection wc) {11 this . wc=wc ;12 try{13 Serv let InputStream input = wc . getInputStream ( ) ;14 ServletOutputStream output=wc . getOutputStream ( ) ;15 St r ing CRLF = ”\ r \n” ;16 St r ing r e s S t r = ”update /1 .0 ” + CRLF;17 r e s S t r += ” Server : G l a s s f i s h / ServerTest ” + CRLF;18 r e s S t r += ”Content−Type : t ex t /html” + CRLF;19 r e s S t r += ” Connection : Upgrade” + CRLF;

Page 184: programare distribuita

184 CAPITOLUL 9. SERVLET

20 r e s S t r += CRLF;21 byte [ ] b=new byte [ 2 5 6 ] ;22 input . read (b ) ;23 St r ing data=new St r ing (b ) . tr im ( ) ;24 St r ing rez=s o l v e r ( data ) ;25 r e s S t r +=rez + CRLF;26 output . wr i t e ( r e s S t r . getBytes ( ) ) ;27 output . f l u s h ( ) ;28 }29 catch ( Exception ex ) {30 throw new RuntimeException ( ex ) ;31 }32 }

34 @Override35 public void dest roy ( ) {36 try{37 wc . c l o s e ( ) ;38 }39 catch ( Exception ex ) {40 System . out . p r i n t l n ( ” Destroy wc Exception : ”+ex . getMessage ( ) ) ;41 }42 }

44 private St r ing s o l v e r ( S t r ing data ){45 System . out . p r i n t l n ( ” So lve r : ”+data ) ;46 St r ing [ ] s=data . s p l i t ( ” ” ) ;47 St r ing r=”−1” ;48 try{49 long m=Long . parseLong ( s [ 0 ] ) ;50 long n=Long . parseLong ( s [ 1 ] ) ;51 r=(new Long (cmmdc(m, n ) ) ) . t oS t r i ng ( ) ;52 }53 catch ( NumberFormatException e ){54 System . out . p r i n t l n ( ”NumberFormatException : ”+e . getMessage ( ) ) ;55 }56 return ”Cmmdc : ”+r ;57 }

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

iar lansarea aplicatiei se face dintr-un program client, ın care se genereazamesajul http cu anterul Upgrade, mesaj expediat printr-un soclu TCP.

Client Java

1 import java . net . Socket ;2 import java . i o . InputStream ;3 import java . i o . OutputStream ;4 import java . i o . InputStreamReader ;5 import java . i o . BufferedReader ;6 import java . i o . IOException ;7 import java . u t i l . Scanner ;

9 public class JCl i ent {10 public stat ic void main ( St r ing [ ] a rgs ){11 Scanner scanner=new Scanner ( System . in ) ;12 System . out . p r i n t l n ( ”m=” ) ;

Page 185: programare distribuita

9.4. DEZVOLTARI IN SERVLET-API 3.1 185

13 long m=scanner . nextLong ( ) ;14 St r ing sm=new Long (m) . t oS t r i ng ( ) ;15 System . out . p r i n t l n ( ”n=” ) ;16 long n=scanner . nextLong ( ) ;17 St r ing sn=new Long (n ) . t oS t r i ng ( ) ;18 St r ing data=sm+” ”+sn ;19 St r ing host=” l o c a l h o s t ” ;20 St r ing port=”8080” ;21 St r ing contextRoot=”/upgrade” ;

23 St r ing CRLF = ”\ r \n” ;24 St r ing reqSt r = ”POST ” + contextRoot + ”/upgrade HTTP/1 .1 ” + CRLF;25 r eqSt r += ”User−Agent : Java /1 .7 ” + CRLF;26 r eqSt r += ”Host : ” + host + ” : ” + port + CRLF;27 r eqSt r += ”Accept : t ex t /html , image/ g i f , image/ jpeg , ∗ ; q=.2 , ∗/∗ ; q=.2” + CRLF;28 r eqSt r += ”Upgrade : upgrade” + CRLF;29 r eqSt r += ” Connection : Upgrade” + CRLF;30 r eqSt r += ”Content−type : a p p l i c a t i o n /x−www−form−ur lencoded ” + CRLF;31 r eqSt r += ” Transfer−Encoding : chunked” + CRLF;32 r eqSt r += CRLF;33 r eqSt r += data + CRLF;

35 Socket socke t=null ;36 try{37 socke t=new Socket ( host , I n t e g e r . pa r s e In t ( port ) ) ;38 }39 catch ( Exception e ){40 System . out . p r i n t l n ( e . getMessage ( ) ) ;41 }42 try (43 OutputStream out=socket . getOutputStream ( ) ;44 InputStream in=socket . getInputStream ( ) ;45 InputStreamReader i s r=new InputStreamReader ( in ) ;46 BufferedReader br=new BufferedReader ( i s r ) ;47 ){48 out . wr i t e ( r eqSt r . getBytes ( ) ) ;49 out . f l u s h ( ) ;50 St r ing s ;51 while ( ( s=br . readLine ( ) ) != null ){52 System . out . p r i n t l n ( s ) ;53 } ;54 socke t . c l o s e ( ) ;55 //System . e x i t ( 0 ) ;56 }57 catch ( IOException e ){58 System . out . p r i n t l n ( ” Input Exception : ”+e . getMessage ( ) ) ;59 }60 }61 }

Client servlet

1 import java . i o . BufferedReader ;2 import java . i o . IOException ;3 import java . i o . InputStream ;4 import java . i o . InputStreamReader ;5 import java . i o . OutputStream ;6 import java . i o . Pr intWriter ;7 import java . net . Socket ;

Page 186: programare distribuita

186 CAPITOLUL 9. SERVLET

9 import javax . s e r v l e t . Se rv l e tExcept ion ;10 import javax . s e r v l e t . annotat ion . WebServlet ;11 import javax . s e r v l e t . http . HttpServ l e t ;12 import javax . s e r v l e t . http . HttpServ letRequest ;13 import javax . s e r v l e t . http . HttpServletResponse ;

15 @WebServlet ( u r lPa t t e rn s = {”/ c l i e n t ” })16 public class C l i e n t S e r v l e t extends HttpServ l e t {

18 protected void doGet ( HttpServ letRequest req , HttpServletResponse r e s )19 throws Serv le tExcept ion , IOException {20 St r ing m=req . getParameter ( ”m” ) ;21 St r ing n=req . getParameter ( ”n” ) ;

23 r e s . setContentType ( ” text /html ; cha r s e t=UTF−8” ) ;24 PrintWriter out = r e s . getWriter ( ) ;

26 f ina l St r ing CRLF = ”\ r \n” ;27 f ina l St r ing host = req . getServerName ( ) ; // ” l o c a l h o s t ” ;28 f ina l int port = req . ge tServerPort ( ) ; // 8080;29 f ina l St r ing contextRoot = ”/upgrade” ;30 f ina l St r ing data = m+” ”+n ;31 InputStream input = null ;32 OutputStream output = null ;33 BufferedReader reader = null ;34 Socket s = null ;35 try{36 out . p r i n t l n ( ”<html>” ) ;37 out . p r i n t l n ( ”<head>” ) ;38 out . p r i n t l n ( ”<t i t l e >S e r v l e t Cl ientTest </ t i t l e >” ) ;39 out . p r i n t l n ( ”</head>” ) ;40 out . p r i n t l n ( ”<body>” ) ;41 out . p r i n t l n ( ”<h1>Http Upgrade Process</h1>” ) ;

43 // S e t t i n g the HTTP upgrade req header44 St r ing reqSt r = ”POST ” + contextRoot + ”/upgrade HTTP/1 .1 ” + CRLF;45 r eqSt r += ”User−Agent : Java /1 .7 ” + CRLF;46 r eqSt r += ”Host : ” + host + ” : ” + port + CRLF;47 r eqSt r += ”Accept :48 t ex t /html , image/ g i f , image/ jpeg , ∗ ; q=.2 , ∗/∗ ; q=.2” + CRLF;49 r eqSt r += ”Upgrade : upgrade” + CRLF;50 r eqSt r += ” Connection : Upgrade” + CRLF;51 r eqSt r += ”Content−type : a p p l i c a t i o n /x−www−form−ur lencoded ” + CRLF;52 r eqSt r += ” Transfer−Encoding : chunked” + CRLF;53 r eqSt r += CRLF;54 r eqSt r += data + CRLF;

56 s = new Socket ( host , port ) ;57 input = s . getInputStream ( ) ;58 output = s . getOutputStream ( ) ;59 output . wr i t e ( r eqSt r . getBytes ( ) ) ;60 output . f l u s h ( ) ;

62 out . p r i n t l n ( ”<h2>Sending upgrade req to s e r v e r . . . . . . < / h2>” ) ;63 out . p r i n t l n ( ”<h3>Request header with data :</h3>” ) ;64 out . p r i n t l n ( ) ;

66 St r ing reqSt rDi sp lay = reqSt r . r e p l a c e A l l ( ”\ r \n” , ”</br>” ) ;

Page 187: programare distribuita

9.4. DEZVOLTARI IN SERVLET-API 3.1 187

67 out . p r i n t l n ( r eqSt rDi sp lay ) ;68 out . p r i n t l n ( ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− </br></br>” ) ;69 out . f l u s h ( ) ;

71 r eader = new BufferedReader (new InputStreamReader ( input ) ) ;

73 out . p r i n t l n ( ”<h2>Server accept upgrade req , send back the r e s :</h2>” ) ;74 out . p r i n t l n ( ”<h3>Response header :</h3>” ) ;75 out . p r i n t l n ( ) ;

77 // Reading the res , and d i s p l a y i n g the header from s e r v e r78 pr intHeader ( reader , out ) ;79 out . p r i n t l n ( ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− </br></br>” ) ;80 out . f l u s h ( ) ;

82 out . p r i n t l n ( ”<h2>Server send back the r e s with new pro to co l and data :</h2>” ) ;83 out . p r i n t l n ( ”<h3>Response header with data :</h3>” ) ;

85 // Reading the res , and d i s p l a y i n g the header from s e r v e r86 pr intHeader ( reader , out ) ;

88 // Reading the echo data89 St r ing dataOutput ;90 i f ( ( dataOutput = reader . readLine ( ) ) != null ) {91 // Print out the data a f t e r header92 out . p r i n t l n ( ”</br>” + dataOutput + ”</br>” ) ;93 out . p r i n t l n ( ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− </br></br>” ) ;94 out . p r i n t l n ( ”<h2>Connection with new pro to co l e s t a b l i s h e d </h2>” ) ;95 }96 out . f l u s h ( ) ;97 out . p r i n t l n ( ”</body>” ) ;98 out . p r i n t l n ( ”</html>” ) ;99 }

100 catch ( IOException e ) {101 System . out . p r i n t l n ( ” C l i e n t S e r v l e t Exception : ”+e . getMessage ( ) ) ;102 }103 f ina l ly {104 i f ( r eader != null ) {105 r eader . c l o s e ( ) ;106 }107 i f ( output != null ) {108 output . c l o s e ( ) ;109 }110 i f ( input != null ) {111 input . c l o s e ( ) ;112 }113 i f ( s != null ) {114 s . c l o s e ( ) ;115 }116 }117 }

119 protected void pr intHeader ( BufferedReader reader , Pr intWriter out )120 throws IOException {121 for ( S t r ing l i n e ; ( l i n e = reader . readLine ( ) ) != null ; ) {122 i f ( l i n e . isEmpty ( ) ){123 break ;124 }125 out . p r i n t l n ( l i n e + ”</br>” ) ;

Page 188: programare distribuita

188 CAPITOLUL 9. SERVLET

126 }127 }

129 @Override130 protected void doPost ( HttpServ letRequest req , HttpServletResponse r e s )131 throws Serv le tExcept ion , IOException {132 doGet ( req , r e s ) ;133 }134 }

9.5 Facilitati de programare cu servlet

9.5.1 Program client al unui servlet

Apelarea unui servlet dintr-un program Java – adica lansarea unei cereri sireceptionarea raspunsului furnizat de servlet se poate obtine

• sincron cu produsul httpcomponents-client,

• asincron cu produsul httpcomponents-asyncclient.

Ambele produse sunt dezvoltate de apache.Caracterul sincron / asincron consta ın faptul ca receptia si prelucrarea

raspunsului oferit de servlet are loc ın metoda din care s-a lansat cererea,respectiv ıntr-un alt obiect.

Intr-un asemenea caz, din punctul de vedere al clientului este mai avantajosca raspunsul servlet-ului fie text/plain, ın loc de text/html.

Cazul sincron

Catalogul lib din httpcomponents-client contine, printre altele, fisierelehttpcore-*.jar, httpclient-*.jar, commons-logging-*.jar.

Pentru compilare trebuie declarata ın variabila de sistem classpath referintacatre httpclient-*.jar si httpcore-*.jar dar pentru executie este nevoie si dereferinta catre commons-logging-*.jar.

Dezvoltarea unui client presupune:

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

CloseableHttpClient httpclient = HttpClients.createDefault();

2. Declararea metodei de transmitere a datelor get, post cu inserarea datelordin cerere.

Page 189: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 189

• GET

HttpGet httpget = new HttpGet(uri);

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

http://host:port/catalog/numeApel?numeParam=valParam&. . . ,

O solutie mai eleganta este

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

qparams.add(new BasicNameValuePair("param_1", value_1));

qparams.add(new BasicNameValuePair("param_2", value_2));

. . .

try{

URI uri = URIUtils.createURI("http", "localhost", 8080,

"/catalog/numeApel",URLEncodedUtils.format(qparams,"UTF-8"),

null);

HttpGet httpget = new HttpGet(uri);

. . .

}

catch(. . .){. . .}

• POST

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

qparams.add(new BasicNameValuePair("param_1", value_1));

qparams.add(new BasicNameValuePair("param_2", value_2));

. . .

try{

UrlEncodedFormEntity params=new UrlEncodedFormEntity(qparams,

"UTF-8");

HttpPost httppost=new HttpPost(uri);

httppost.setEntity(params);

. . .

}

catch(. . .){. . .}

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

Clasele HttpGet, HttpPost apartin pachetului org.apache.http.client.methods.

3. Lansarea cererii.

Page 190: programare distribuita

190 CAPITOLUL 9. SERVLET

HttpResponse response=httpclient.execute(httpget);

respectiv

HttpResponse response=httpclient.execute(httppost);

4. Preluarea raspunsului.

HttpEntity entity=response.getEntity();

if(entity!=null){

InputStream is=entity.getContent();

int l;

byte[] tmp=new byte[2048];

while((l=is.read(tmp))!=-1){}

. . .

}

Exemplul 9.5.1 Dezvoltam un program client pentru servlet-ul CmmdcServlet(post).

1 import java . u t i l . Scanner ;2 import org . apache . http . HttpEntity ;

4 import org . apache . http . impl . c l i e n t . C loseab l eHttpCl i ent ;5 import org . apache . http . c l i e n t . methods . HttpPost ;6 import org . apache . http . c l i e n t . methods . CloseableHttpResponse ;7 import org . apache . http . impl . c l i e n t . HttpCl i ents ;8 import java . u t i l . L i s t ;9 import java . u t i l . ArrayList ;

10 import org . apache . http . NameValuePair ;11 import org . apache . http . message . BasicNameValuePair ;

13 import org . apache . http . c l i e n t . e n t i t y . UrlEncodedFormEntity ;14 import java . i o . ∗ ;

16 public class ClientCmmdcServlet{17 stat ic St r ing u r i=” http :// l o c a l h o s t :8080/ myserv let /cmmdc” ;

19 public stat ic void main ( St r ing [ ] a rgs ) {20 Scanner scanner=new Scanner ( System . in ) ;21 System . out . p r i n t l n ( ”m=” ) ;22 St r ing m=scanner . nextLine ( ) . tr im ( ) ;23 System . out . p r i n t l n ( ”n=” ) ;24 St r ing n=scanner . nextLine ( ) . tr im ( ) ;

26 Closeab l eHttpCl i ent h t t p c l i e n t = HttpCl i ents . c r e a t e D e f a u l t ( ) ;27 List<NameValuePair> qparams = new ArrayList<NameValuePair >() ;28 qparams . add (new BasicNameValuePair ( ”m” , m) ) ;29 qparams . add (new BasicNameValuePair ( ”n” , n ) ) ;

Page 191: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 191

30 qparams . add (new BasicNameValuePair ( ” t i p ” , ” t ext / p l a i n ” ) ) ;31 try{32 UrlEncodedFormEntity params=new UrlEncodedFormEntity ( qparams , ”UTF−8” ) ;33 HttpPost httppost=new HttpPost ( u r i ) ;34 httppost . s e tEnt i ty ( params ) ;35 CloseableHttpResponse re sponse=h t t p c l i e n t . execute ( httppost ) ;36 HttpEntity e n t i t y=response . ge tEnt i ty ( ) ;37 i f ( e n t i t y !=null ){38 InputStream i s=e n t i t y . getContent ( ) ;39 int l ;40 byte [ ] tmp=new byte [ 2 0 4 8 ] ;41 while ( ( l=i s . read (tmp))!=−1){}42 System . out . p r i n t l n ( ”Cmmdc = ”+(new St r ing (tmp ) . tr im ( ) ) ) ;43 }44 }45 catch ( Exception e ){46 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;47 }48 }49 }

O solutie elementara bazata pe clasa java.net.HttpURLConnection este

1 import java . net .URL;2 import java . net . HttpURLConnection ;3 import java . u t i l . Scanner ;4 import java . i o . InputStreamReader ;5 import java . i o . BufferedReader ;6 import java . i o . Pr intWriter ;

8 public class CmmdcClient{9 public stat ic void main ( St r ing [ ] a rgs ){

10 Scanner scanner=new Scanner ( System . in ) ;11 System . out . p r i n t l n ( ”m=” ) ;12 long m=scanner . nextLong ( ) ;13 System . out . p r i n t l n ( ”n=” ) ;14 long n=scanner . nextLong ( ) ;15 St r ing msg=”m=”+m+”&n=”+n+”&t i p=text / p l a i n ” ;16 try{17 St r ing urlGET=” http :// l o c a l h o s t :8080/ myserv let /cmmdc?”+msg ;18 URL u r l=new URL(urlGET ) ;19 HttpURLConnection conn=(HttpURLConnection ) u r l . openConnection ( ) ;20 conn . setRequestMethod ( ”GET” ) ;21 System . out . p r i n t l n ( conn . getResponseCode ( ) ) ;22 System . out . p r i n t l n ( conn . getResponseMessage ( ) ) ;23 BufferedReader br=24 new BufferedReader (new InputStreamReader ( conn . getInputStream ( ) ) ) ;25 St r ing s ;26 while ( ( s=br . readLine ( ) ) != null ){27 System . out . p r i n t l n ( s ) ;28 }29 br . c l o s e ( ) ;30 conn . d i s connec t ( ) ;31 }32 catch ( Exception e ){33 System . out . p r i n t l n ( e . getMessage ( ) ) ;34 }35 try{36 St r ing urlPOST=” http :// l o c a l h o s t :8080/ myserv let /cmmdc” ;

Page 192: programare distribuita

192 CAPITOLUL 9. SERVLET

37 URL u r l=new URL(urlPOST ) ;38 HttpURLConnection conn=(HttpURLConnection ) u r l . openConnection ( ) ;39 conn . setRequestMethod ( ”POST” ) ;40 conn . setUseCaches ( fa l se ) ;41 conn . setDoInput ( true ) ;42 conn . setDoOutput ( true ) ;43 conn . setRequestProperty ( ”Content−Type” , ” a p p l i c a t i o n /x−www−form−ur lencoded ” ) ;44 PrintWriter pw=new PrintWriter ( conn . getOutputStream ( ) ) ;

46 pw. p r i n t l n (msg ) ;47 pw. f l u s h ( ) ;48 System . out . p r i n t l n ( conn . getResponseCode ( ) ) ;49 System . out . p r i n t l n ( conn . getResponseMessage ( ) ) ;50 BufferedReader br=51 new BufferedReader (new InputStreamReader ( conn . getInputStream ( ) ) ) ;52 St r ing s ;53 while ( ( s=br . readLine ( ) ) != null ){54 System . out . p r i n t l n ( s ) ;55 }56 br . c l o s e ( ) ;57 pw. c l o s e ( ) ;58 conn . d i s connec t ( ) ;59 }60 catch ( Exception e ){61 System . out . p r i n t l n ( e . getMessage ( ) ) ;62 }63 }64 }

Cazul asincron

Variabila classpath contine referentele catre fiserele jar aflate ın catalogullib din httpcomponent-asyncclient.

Programarea consta din

1. Crearea unei instante a clasei org.apache.http.impl.nio.client.DefaultHttpAsyncClient

CloseableHttpAsyncClient httpclient = HttpAsyncClient.createDefault();

httpclient.start();

2. Lansarea unei cereri apeland o metoda execute:<T> Future<T> execute(

org.apache.http.nio.protocol.HttpAsyncRequestProducer

requestProducer,org.apache.http.nio.protocol.HttpAsyncResponseConsumer<T>

responseConsumer,org.apache.http.concurrent.FutureCallback<T> callback)

O instanta de tip HttpAsyncRequestProducer se obtine prin

Page 193: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 193

HttpAsyncMethods.createGet(uri)

Drept instanta a clasei HttpAsyncResponseConsumer poate fi o clasa ceextinde clasa org.apache.http.nio.client.methods.AsyncCharConsumer.

Exemplul 9.5.2

1 import java . u t i l . Scanner ;

3 import org . apache . http . HttpResponse ;4 import org . apache . http . impl . n io . c l i e n t . CloseableHttpAsyncCl ient ;5 import org . apache . http . n io . IOControl ;6 import org . apache . http . impl . n io . c l i e n t . HttpAsyncClients ;7 import org . apache . http . n io . c l i e n t . methods . AsyncCharConsumer ;8 import org . apache . http . n io . c l i e n t . methods . HttpAsyncMethods ;9 import org . apache . http . p ro to co l . HttpContext ;

11 import java . n io . CharBuffer ;12 import java . i o . IOException ;13 import java . u t i l . concurrent . Future ;

15 public class AsyncClientCmmdcServlet{16 stat ic St r ing u r i=” http :// l o c a l h o s t :8080/ myserv let /cmmdc” ;

18 public stat ic void main ( St r ing [ ] a rgs ) throws Exception {19 Scanner scanner=new Scanner ( System . in ) ;20 System . out . p r i n t l n ( ”m=” ) ;21 St r ing m=scanner . nextLine ( ) . tr im ( ) ;22 System . out . p r i n t l n ( ”n=” ) ;23 St r ing n=scanner . nextLine ( ) . tr im ( ) ;24 St r ing requestData=”?m=”+m+”&n=”+n+”&t i p=text / p l a i n ” ;25 System . out . p r i n t l n ( requestData ) ;

27 CloseableHttpAsyncCl ient h t t p c l i e n t = HttpAsyncClients . c r e a t e D e f a u l t ( ) ;28 h t t p c l i e n t . s t a r t ( ) ;29 try {30 Future<Boolean> f u tu r e = h t t p c l i e n t . execute (31 HttpAsyncMethods . createGet ( u r i+requestData ) ,32 new MyResponseConsumer ( ) , null ) ;33 Boolean r e s u l t = fu tu r e . get ( ) ;34 i f ( r e s u l t != null && r e s u l t . booleanValue ( ) ) {35 System . out . p r i n t l n ( ”Request s u c c e s s f u l l y executed ” ) ;36 }37 else {38 System . out . p r i n t l n ( ”Request f a i l e d ” ) ;39 }40 System . out . p r i n t l n ( ” Shutt ing down” ) ;41 }42 f ina l ly {43 h t t p c l i e n t . c l o s e ( ) ;44 }45 System . out . p r i n t l n ( ”Done” ) ;46 }

48 stat ic class MyResponseConsumer extends AsyncCharConsumer<Boolean>{49 @Override

Page 194: programare distribuita

194 CAPITOLUL 9. SERVLET

50 protected void onResponseReceived ( f ina l HttpResponse re sponse ) {}

52 @Override53 protected void onCharReceived ( f ina l CharBuffer buf ,54 f ina l IOControl i o c t r l ) throws IOException {55 System . out . p r i n t l n ( ”Cmmdc : ” ) ;56 while ( buf . hasRemaining ( ) ) {57 System . out . p r i n t ( buf . get ( ) ) ;58 }59 }

61 @Override62 protected void r e l e a s e R e s o u r c e s ( ) {}

64 @Override65 protected Boolean bu i ldResu l t ( f ina l HttpContext context ) {66 return Boolean .TRUE;67 }68 }69 }

9.5.2 Servlete ınlantuite

Un servlet apeleaza la un moment dat alt servlet. Sablonul de lucru este

RequestDispatcher dispatcher=

getServletContext().getRequestDispatcher("/url_pattern_servlet_apelat");

if(dispatcher!=null)

dispatcher.include(request,response);

Exemplul 9.5.3 Un servlet VerifServlet verifica parametri cererii. Pentruproblema calculului celui mai mare divizor comun a doua numere, daca cei doiparametri sunt numere ıntregi, atunci se apeleaza servlet-ul ComputeServlet,altfel se formeaza un mesaj de eroare.

Codurile celor doua servlete sunt:VerifServlet.java

1 package cmmdc ;2 import java . i o . IOException ;3 import java . i o . Pr intWriter ;4 import javax . s e r v l e t . Se rv l e tExcept ion ;5 import javax . s e r v l e t . http . HttpServ l e t ;6 import javax . s e r v l e t . http . HttpServ letRequest ;7 import javax . s e r v l e t . http . HttpServletResponse ;8 import javax . s e r v l e t . RequestDispatcher ;9 import javax . s e r v l e t . annotat ion . WebServlet ;

11 @WebServlet ( u r lPa t t e rn s = ”/ v e r i f ” )12 public class V e r i f S e r v l e t extends HttpServ l e t {13 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )

Page 195: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 195

14 throws Serv le tExcept ion , IOException{15 PrintWriter out=r e s . getWriter ( ) ;16 r e s . setContentType ( ” text /html” ) ;17 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;18 St r ing message=”” ;19 long m, n ;20 i f ( ( sm==null ) | | ( sm . equa l s ( ”” ) ) ){21 message=”Numar absent ” ;22 }23 else {24 try{25 m=Long . parseLong (sm ) ;26 }27 catch ( NumberFormatException e ){28 message=”Nu e s t e numar” ;29 }30 }31 i f ( ( sn==null ) | | ( sn . equa l s ( ”” ) ) ){32 message=”Numar absent ” ;33 }34 else {35 try{36 n=Long . parseLong ( sn ) ;37 }38 catch ( NumberFormatException e ){39 message=”Nu e s t e numar” ;40 }41 }42 out . p r i n t l n ( ”<html><body>” ) ;43 i f ( message . equa l s ( ”” ) ){44 out . p r i n t l n ( ”<h3> Rezu l ta tu l ob&#355; inut </h3>” ) ;45 RequestDispatcher d i spa t che r=46 getSe rv l e tContext ( ) . getRequestDispatcher ( ”/ c a l c u l ” ) ;47 i f ( d i spa t che r !=null )48 d i spa t che r . i n c lude ( req , r e s ) ;49 }50 else {51 out . p r i n t l n ( ”<h3> Date eronate </h3>” ) ;52 out . p r i n t l n ( message ) ;53 }54 out . p r i n t l n ( ”</body></html>” ) ;55 out . c l o s e ( ) ;56 }

58 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )59 throws Serv le tExcept ion , IOException{60 doGet ( req , r e s ) ;61 }62 }

ComputeServlet.java

1 package cmmdc ;2 import java . i o . IOException ;3 import java . i o . Pr intWriter ;4 import javax . s e r v l e t . Se rv l e tExcept ion ;5 import javax . s e r v l e t . http . HttpServ l e t ;6 import javax . s e r v l e t . http . HttpServ letRequest ;7 import javax . s e r v l e t . http . HttpServletResponse ;

Page 196: programare distribuita

196 CAPITOLUL 9. SERVLET

8 import javax . s e r v l e t . annotat ion . WebServlet ;

10 @WebServlet ( u r lPa t t e rn s = ”/ c a l c u l ” )11 public class ComputeServlet extends HttpServ l e t {

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

15 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )16 throws Serv le tExcept ion , IOException{17 long m=Long . parseLong ( req . getParameter ( ”m” ) ) ;18 long n=Long . parseLong ( req . getParameter ( ”n” ) ) ;19 PrintWriter out=r e s . getWriter ( ) ;20 out . p r i n t l n ( ”<H1> Cmmdc = ”+cmmdc(m, n)+”</H1>” ) ;21 }

23 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )24 throws Serv le tExcept ion , IOException{25 doGet ( req , r e s ) ;26 }27 }

9.5.3 Sesiune de lucru

In cazul protocolului HTTP, de fiecare data cand un client deschide saurevine la o pagina Web se deschide o noua conexiune cu serverul Web iar acestanu retine informatiile referitoare la client pe perioada conexiunii respective.Perioada de timp cat un client este ın conexiune cu o pagina Web se numestesesiune.

Exista posibilitatea pastrarii unor informatii pe durata unei sesiuni prinintermediul unui obiect de tip javax.servlet.http.HttpSession.

Inaintea satisfacerii unei cereri, servlet-ul verifica existenta unui obiectHttpSession. Acest obiect se creaza la prima apelare de catre un client aservlet-ului prin

HttpSession sesiune=request.getSession(true);

Un obiect HttpSession poate retine atribute, adica perechi de forma (nume,valoare). Introducerea unui atribut se realizeaza prin

void setAttribute(String nume, Object valoare)

iar extragerea valorii unui atribut se obtine prin

Object getAttribute(String nume)

Metoda String nume[ ] getValueNames() returneaza numele tuturoratributelor definite.

Un atribut se elimina cu metoda void removeAttribute(String nume).

Page 197: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 197

Exemplul 9.5.4 Exemplul urmator numara de cate ori se apeleaza servlet-ul ıntr-o sesiune. Se defineste un atribut noAcces, care la prima apelare esteinitializat iar apoi este marit cu cate o unitate la fiecare noua apelare a servlet-ului.

1 import java . i o . IOException ;2 import java . i o . Pr intWriter ;3 import javax . s e r v l e t . Se rv l e tExcept ion ;4 import javax . s e r v l e t . http . HttpServ l e t ;5 import javax . s e r v l e t . http . HttpServ letRequest ;6 import javax . s e r v l e t . http . HttpServletResponse ;7 import javax . s e r v l e t . http . HttpSess ion ;8 import javax . s e r v l e t . annotat ion . WebServlet ;

10 @WebServlet ( u r lPa t t e rn s = ”/ s e s i u n e ” )11 public class Ses iune extends HttpServ l e t {

13 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )14 throws Serv le tExcept ion , IOException{15 r e s . setContentType ( ” text /html” ) ;16 St r ing mesaj ;17 PrintWriter out=r e s . getWriter ( ) ;18 HttpSess ion s e s s i o n=req . g e t S e s s i o n ( true ) ;19 I n t e g e r contor=( I n t e g e r ) s e s s i o n . ge tAt t r ibut e ( ”noAcces” ) ;20 i f ( contor==null ){21 contor=new I n t e g e r ( 1 ) ;22 mesaj=” Salut ! ” ;23 }24 else {25 contor=new I n t e g e r ( contor . intValue ( )+1) ;26 mesaj=”Bine a t i r e v e n i t ! ” ;27 }28 s e s s i o n . s e t A t t r i b u t e ( ”noAcces” , contor ) ;29 out . p r i n t l n ( ”<html><body>” ) ;30 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;31 out . p r i n t l n ( ”Numarul de a c c e s a r i a l a c e a s t e i pag in i e s t e ” +32 contor . intValue ( ) ) ;33 out . p r i n t l n ( ”</body></html>” ) ;34 out . c l o s e ( ) ;35 }

37 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )38 throws Serv le tExcept ion , IOException{39 doGet ( req , r e s ) ;40 }41 }

Apelarea servlet-ului se face din

1 < ! doctype html>2 <head>3 <meta charset=” utf−8”>4 <l ink rel=” s t y l e s h e e t ” href=”mycss . c s s ”>5 </head>6 <body>7 <center>8 <h1> Formular de acce s </h1>

Page 198: programare distribuita

198 CAPITOLUL 9. SERVLET

9 <form method=” get ”10 action=” s e s i u n e ”>11 <p>12 <input type=”submit” value=” Acceseaza ”>13 </form>14 </center>15 </body>16 </html>

9.5.4 Cookie

Un Cookie este un fisier de dimensiune mica trimis de catre programulserver clientului ca parte a header-ului Http.

Acesta contine informatii despre sesiunea curenta care salvate pe disc vorputea fi accesate ın sesiuni ulterioare. Cand un navigator emite o cerere catreun server, cookie-urile anterioare primite de catre client de la serverul respectivsunt trimise din nou serverului ca parte a cererii formulata de client.

Cookie-urile sunt sterse automat ın momentul expirarii.Unii clienti nu permit memorarea cookie-urilor. In acest caz, clientul este

informat ca acest fapt ar putea duce la imposibilitatea satisfacerii cereri sale/ accesarii paginii Web. Implicit, durata de viata a unui cookie este sesiuneacurenta a navigatorului (pana se ınchide navigatorul).

Clasa Cookie

ContructorCookie(String nume, String valoare)Metode

• void setDomain(String model)

Domeniul este o adresa URL ce restrictioneaza accesul cookie-urilor laacel domeniu. model trebuie sa contina cel putin doua caractere ”.”.

• void setMaxAge(int durata) Fixeaza durata de existenta a cookie-ului- ın secunde. Valoarea implicita este -1, adica cookie-ul exista pana laınchiderea programului navigator.

• void setComment(String comentariu)

• void setSecure(boolean flag)

Valoarea implicita este false.

Page 199: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 199

Trimiterea unui cookie clientului:public void HttpServletResponse.addCookie(Cookie cookie)

Recunoasterea cookie-urilor de catre servlet:

Cookie [ ] cookies=request.getCookies();

if(cookies!=null){

for(int i=0;i<cookies.length;i++){

String name=cookies[i].getName();

String valoare=cookies[i].getValue();

. . .

}

Exemplul 9.5.5 In exemplul urmator se numara de cate ori se apeleaza servlet-ul pe durata de viata a cookie-ului.

1 package cook i e ;2 import java . i o . IOException ;3 import java . i o . Pr intWriter ;4 import javax . s e r v l e t . Se rv l e tExcept ion ;5 import javax . s e r v l e t . http . HttpServ l e t ;6 import javax . s e r v l e t . http . HttpServ letRequest ;7 import javax . s e r v l e t . http . HttpServletResponse ;8 import javax . s e r v l e t . http . Cookie ;9 import javax . s e r v l e t . annotat ion . WebServlet ;

11 @WebServlet ( u r lPa t t e rn s = ”/ cook i e ” )

13 public class Ape lar i extends HttpServ l e t {

15 public void doGet ( HttpServ letRequest req ,16 HttpServletResponse r e s )17 throws Serv le tExcept ion , IOException{18 r e s . setContentType ( ” text /html” ) ;19 St r ing mesaj=”” ;20 PrintWriter out=r e s . getWriter ( ) ;21 Cookie myCookie=null ;22 int contor =0;23 Cookie [ ] c oo k i e s=req . getCookies ( ) ;24 boolean sw=fa l se ;25 i f ( c o ok i e s !=null ){26 for ( int i =0; i<c oo k i e s . l ength ; i ++){27 St r ing name=c oo k i e s [ i ] . getName ( ) ;28 i f (name . equa l s ( ” urmar ire ” ) ){29 sw=true ;30 contor=I n t e g e r . pa r s e In t ( c oo k i e s [ i ] . getValue ( ) ) ;31 contor++;32 mesaj=”Bine a t i r e v e n i t ! ” ;33 System . out . p r i n t l n ( ” Gasit ”+contor ) ;34 }35 }

Page 200: programare distribuita

200 CAPITOLUL 9. SERVLET

36 }37 i f ( sw){38 myCookie=new Cookie ( ” urmar ire ” , (new I n t e g e r ( contor ) ) . t oS t r i ng ( ) ) ;39 }40 else {41 myCookie=new Cookie ( ” urmar ire ” , (new I n t e g e r ( 1 ) ) . t oS t r i ng ( ) ) ;42 contor =1;43 mesaj=” Salut ! ” ;44 }45 myCookie . setMaxAge (1000000) ;46 r e s . addCookie ( myCookie ) ;47 out . p r i n t l n ( ”<html><body>” ) ;48 out . p r i n t l n ( ”<h1>”+mesaj+”</h1>” ) ;49 out . p r i n t l n ( ”Numarul de a c c e s a r i a l a c e a s t e i pag in i e s t e ”+contor ) ;50 out . p r i n t l n ( ”</body></html>” ) ;51 out . c l o s e ( ) ;52 }

54 public void doPost ( HttpServ letRequest req ,55 HttpServletResponse r e s )56 throws Serv le tExcept ion , IOException{57 doGet ( req , r e s ) ;58 }59 }

9.5.5 AutentificareServerul Web apache-tomcat poate executa autentificarile basic si digest.

Autenticarea se face pe baza perechii (nume utilizator, parola) (username,password).Aceste informatii sunt retinute ın serverul Web, ın fisierul conf\tomcat-users.xmlfiind asociate unui element <role>, de exemplu

<role rolename="BASIC_ROLE"/>

<role rolename="DIGEST_ROLE"/>

. . .

<user username="basic" password="basic" roles="BASIC_ROLE"/>

<user username="digest" password="digest" roles="DIGEST_ROLE"/>

Codul servlet-ului nu este implicat, iar cerinta de autentificare solicitataunui client se precizeaza ın fisierul web.xml

<security-role>

<role-name>BASIC_ROLE</role-name>

</security-role>

<security-constraint>

<web-resource-collection>

<web-resource-name>Restricted Access - Members Only</web-resource-name>

<url-pattern>/cmmdc</url-pattern>

<http-method>GET</http-method>

<http-method>POST</http-method>

</web-resource-collection>

<auth-constraint>

<role-name>BASIC_ROLE</role-name>

</auth-constraint>

<user-data-constraint>

Page 201: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 201

<transport-guarantee>NONE</transport-guarantee>

</user-data-constraint>

</security-constraint>

<login-config>

<auth-method>BASIC</auth-method>

<!--

<realm-name>My realm name</realm-name>

-->

</login-config>

Optional poate fi definit un domeniu (realm).In cazul apelarii dintr-un program Java a unui servlet, la care accesul pre-

supune autentificare, aceasta se realizeaza prin intermediul claselor pachetuluihttpcomponents-client :

import org.apache.http.auth.AuthScope;

import org.apache.http.auth.UsernamePasswordCredentials;

import org.apache.http.impl.auth.BasicScheme;

import org.apache.http.protocol.BasicHttpContext;

. . .

DefaultHttpClient httpclient = new DefaultHttpClient();

// Activitati pentru autentificare

httpclient.getCredentialsProvider().setCredentials(

new AuthScope(host,Integer.parseInt(port)),

// new AuthScope(host,Integer.parseInt(port),realm),

new UsernamePasswordCredentials(username,password)

);

BasicHttpContext context=new BasicHttpContext();

BasicScheme schema = new BasicScheme();

// DigestScheme schema = new DigestScheme();

context.setAttribute("preemptive-auth", schema);

. . .

HttpResponse response=httpclient.execute(httppost,context);

. . .

In cazul autentificarii digest, datele de identificare sunt criptate iar in cazulautentificarii basic se utilizeaza codarea base64.

9.5.6 Servlet cu conexiune la o baza de date

Folosind Anexa C consideram

Exemplul 9.5.6 Consultarea unei agende de adrese e-mail. Se utilizeaza obaza de date AgendaEMail alcatuita dintr-un singur tabel adrese (id int, numevarchar(20), email varchar(30)).

Utilizand SGBD derby servlet-ul este

Page 202: programare distribuita

202 CAPITOLUL 9. SERVLET

1 import java . i o . IOException ;2 import javax . s e r v l e t . Se rv l e tExcept ion ;3 import javax . s e r v l e t . ServletOutputStream ;4 import javax . s e r v l e t . S e rv l e tCon f i g ;5 import javax . s e r v l e t . http . HttpServ l e t ;6 import javax . s e r v l e t . http . HttpServ letRequest ;7 import javax . s e r v l e t . http . HttpServletResponse ;8 import javax . s e r v l e t . annotat ion . WebServlet ;9 import java . s q l . Statement ;

10 import java . s q l . Connection ;11 import java . s q l . DriverManager ;12 import java . s q l . SQLException ;13 import java . s q l . Resu l tSet ;

15 @WebServlet ( u r lPa t t e rn s = ”/ adrese ” )16 public class AgendaEMailServlet extends HttpServ l e t {17 Statement i n s t r u c t i u n e=null ;18 Connection con=null ;

20 public void i n i t ( Se rv l e tCon f i g c o n f i g ) throws Serv l e tExcept ion {21 super . i n i t ( c o n f i g ) ;22 // SGBD Derby23 St r ing jdbcDr iver=” org . apache . derby . jdbc . C l i en tDr ive r ” ;24 St r ing URLBazaDate=” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail” ;25 // SGBD Mysql26 // S t r i n g jdbcDr iver=”com . mysql . j dbc . Driver ” ;27 // S t r i n g URLBazaDate=”jdbc : mysql :// l o c a l h o s t :3306/ AgendaEMail? user=root ” ;

29 try{30 Class . forName ( jdbcDr iver ) . newInstance ( ) ;31 con=DriverManager . getConnect ion (URLBazaDate ) ;32 i n s t r u c t i u n e=con . createStatement ( ) ;33 }34 catch ( ClassNotFoundException e ){35 System . out . p r i n t l n ( ” Driver i n e x i s t e n t JDBC: ”+jdbcDr iver ) ;36 }37 catch ( SQLException e ){38 System . out . p r i n t l n ( ”Baza de date i n e x i s t e n t a ”+URLBazaDate ) ;39 }40 catch ( Exception e ){41 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;42 }43 }

45 public void dest roy ( ){46 try{47 i f ( con !=null ) con . c l o s e ( ) ;48 }49 catch ( SQLException e ){50 System . out . p r i n t l n ( e . getMessage ( ) ) ;51 }52 }

54 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )55 throws Serv le tExcept ion , IOException{56 St r ing myAtribut , myVal ;57 r e s . setContentType ( ” text /html” ) ;58 ServletOutputStream out = r e s . getOutputStream ( ) ;

Page 203: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 203

60 myAtribut=req . getParameter ( ” c r i t e r i u ” ) ;61 myVal=req . getParameter ( ” termen” ) ;62 myVal=’ \ ’ ’+myVal+’ \ ’ ’ ;63 try{64 St r ing s q l=” s e l e c t ∗ from adrese where ”+ myAtribut+” = ”+myVal ;65 Resu l tSet r s=i n s t r u c t i u n e . executeQuery ( s q l ) ;66 out . p r i n t l n ( ”<html>” ) ;67 out . p r i n t l n ( ”<head><t i t l e >AgendaEMail</ t i t l e ></head>” ) ;68 out . p r i n t l n ( ”<body>” ) ;69 out . p r i n t l n ( ”<h1>Agenda de Adrese e−mail </h1>” ) ;70 out . p r i n t l n ( ”<p/>” ) ;71 out . p r i n t l n ( ”<b> Nume <−−> Adresa e−mail </b>” ) ;72 out . p r i n t l n ( ”<br/>” ) ;73 while ( r s . next ( ) ){74 out . p r i n t ( r s . g e t S t r i n g ( ”nume”)+” <−−> ”+r s . g e t S t r i n g ( ” emai l ” ) ) ;75 out . p r i n t l n ( ”<br/>” ) ;76 }77 out . p r i n t l n ( ”</body>” ) ;78 out . p r i n t l n ( ”</html>” ) ;79 out . c l o s e ( ) ;80 }81 catch ( SQLException e ){82 System . out . p r i n t l n ( ”SQLException : ”+e . getMessage ( ) ) ;83 }84 catch ( Exception e ){85 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;86 }87 }

89 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )90 throws Serv le tExcept ion , IOException{91 doGet ( req , r e s ) ;92 }93 }

Apelarea servlet-ului se face din

1 <html>2 <body>3 <h1> Cautare in baza de date AgendaEMail</h1>4 <form method=” get ”5 action=” adrese ”>6 <p>C r i t e r i u de cautare :7 <select name=” c r i t e r i u ” >8 <option value=”nume”>dupa Nume9 <option value=” emai l ”>dupa Email

10 </ select>11 <br>12 <p>Ent i ta tea cautata13 <input type=” text ” name=”termen” s ize=30>14 <p><input type=”submit” value=”Cauta”>15 </form>16 </body>17 </html>

Testarea aplicatiei presupune:

1. Realizarea bazei de date:

Page 204: programare distribuita

204 CAPITOLUL 9. SERVLET

2. Testarea servlet-ului:

(a) Pornirea serverului bazei de date.

(b) Se verifica prezenta ın catalogul servlet-ului ...\WEB-INF\lib afisierului derbyclient.jar sau mysql-connector-java-*.*.*-bin.jar.

(c) Pornirea serverului tomcat sau reıncarcarea servlet-ului.

(d) Apelarea servlet-ului din pagina Web.

9.5.7 Imagini furnizate de servlet

Indicam doua modalitati prin care un client obtine o imagine furnizata deun servlet. Imaginea poate proveni dintr-un fisier extern sau poate fi creatade servlet.

• Imaginea este transmisa direct clientului ın fluxul de iesire de tipServletOutputStream, tipul MIME al raspunsului fiind

response.setContentType("image/ext");

ext∈ {gif, jpg, png, . . .}.Textul sursa al servlet-ului este:

1 package g raphg i f ;2 import java . i o . IOException ;3 import javax . s e r v l e t . Se rv l e tExcept ion ;4 import javax . s e r v l e t . http . HttpServ l e t ;5 import javax . s e r v l e t . http . HttpServ letRequest ;6 import javax . s e r v l e t . http . HttpServletResponse ;7 import javax . s e r v l e t . ServletOutputStream ;8 import javax . s e r v l e t . annotat ion . WebServlet ;

10 import java . n io . f i l e . Path ;11 import java . n io . f i l e . Paths ;12 import java . n io . f i l e . F i l e s ;

14 @WebServlet ( u r lPa t t e rn s = ”/ graphg i f ” )

16 public class MyGraphG extends HttpServ l e t {17 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )18 throws Serv le tExcept ion , IOException {19 St r ing f s=System . getProperty ( ” f i l e . s epa ra to r ” ) ;20 ServletOutputStream out = r e s . getOutputStream ( ) ;21 St r ing pathTomcat = new java . i o . F i l e ( ” . ” ) . getCanonicalPath ( ) ;22 St r ing contextPath=req . getContextPath ( ) ;23 Path path=Paths . get ( pathTomcat+f s+”webapps”+f s+24 contextPath+f s+” walk ing santa . g i f ” ) ;

Page 205: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 205

25 try{26 r e s . setContentType ( ” image/ g i f ” ) ;27 F i l e s . copy ( path , out ) ;28 }29 catch ( Exception e ){30 r e s . setContentType ( ” text / p l a i n ” ) ;31 System . out . p r i n t l n ( e . getMessage ( ) ) ;32 out . p r i n t l n ( ” Cererea d−voast ra nu poate f i s a t i s f a c u t a ” ) ;33 }34 out . c l o s e ( ) ;35 }36 }

• Pe calculatorul serverului Web, imaginea se salveaza ıntr-un fisier grafic,dupa care servlet-ul scrie ın fluxul de iesire un document html cu olegatura (link) catre fisierul cu imaginea creata anterior. Navigatorulclientului va descarca si vizualiza imaginea.

Daca tipul fisierului grafic este jpg sau png atunci textul sursa al servlet-ului este:

1 package graphjpg ;2 import java . i o . IOException ;3 import java . i o . Pr intWriter ;4 import java . i o . F i l e ;5 import javax . s e r v l e t . Se rv l e tExcept ion ;6 import javax . s e r v l e t . http . HttpServ l e t ;7 import javax . s e r v l e t . http . HttpServ letRequest ;8 import javax . s e r v l e t . http . HttpServletResponse ;

10 import javax . s e r v l e t . annotat ion . WebServlet ;11 import javax . imageio . ImageIO ;12 import java . awt . Frame ;13 import java . awt . Font ;14 import java . awt . Graphics ;15 import java . awt . image . BufferedImage ;

17 @WebServlet ( u r lPa t t e rn s = ”/ graphjpg ” )

19 public class MyGraphP extends HttpServ l e t {

21 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )22 throws Serv le tExcept ion , IOException {23 St r ing f s=System . getProperty ( ” f i l e . s epa ra to r ” ) ;24 r e s . setContentType ( ” text /html” ) ;25 PrintWriter out=r e s . getWriter ( ) ;26 St r ing pathTomcat = new java . i o . F i l e ( ” . ” ) . getCanonicalPath ( ) ;27 St r ing contextPath=req . getContextPath ( ) ;

29 St r ing f i l e R e f=pathTomcat+f s+”webapps”+f s+contextPath+f s ;30 St r ing numeFis=” desen ” ;31 St r ing ext=” jpg ” ; // sau ”png”32 // Formarea i m a g i n i i33 Frame frame = null ;

Page 206: programare distribuita

206 CAPITOLUL 9. SERVLET

34 Graphics g = null ;35 BufferedImage image=null ;36 try{37 frame = new Frame ( ) ;38 frame . addNoti fy ( ) ;39 image = ( BufferedImage ) frame . createImage (800 , 6 0 ) ;40 g = image . getGraphics ( ) ;41 // Fixarea f o n t u l u i42 g . setFont (new Font ( ” S e r i f ” , Font . ITALIC , 4 8 ) ) ;43 // Editarea unui t e x t44 g . drawString ( ” Tehno log i i d i s t r i b u i t e in Java” , 10 , 5 0 ) ;

46 // Sa lvarea i m a g i n i i in t r−un f i s i e r jpg sau png

48 F i l e f=new F i l e ( f i l e R e f+numeFis+” . ”+ext ) ;49 ImageIO . wr i t e ( image , ” jpg ” , f ) ;

51 // Raspunsul c a t r e c l i e n t52 out . p r i n t l n ( ”<HTML><BODY>” ) ;53 out . p r i n t l n ( ”<h2>Imagine pre lua ta de pe s e r v e r </h2>” ) ;54 out . p r i n t l n ( ”<p><a h r e f =\”http :// l o c a l h o s t :8080/ myserv let /”+55 numeFis+” . ”+ext+”\”>” ) ;56 out . p r i n t l n ( ” V i z u a l i z a r e a i m a g i n i i </a>” ) ;57 out . p r i n t l n ( ”</BODY></HTML>” ) ;58 out . c l o s e ( ) ;59 }60 f ina l ly {61 // E l i b e r a r e a r e s u r s e l o r62 i f ( g != null ) g . d i spo s e ( ) ;63 i f ( frame != null ) frame . removeNotify ( ) ;64 }65 }66 }

Daca tipul fisierului grafic va fi gif atunci linia 34 se ınlocuieste cu

FileOutputStream fos=new FileOutputStream(f);

Acme.JPM.Encoders.GifEncoder encoder =

new Acme.JPM.Encoders.GifEncoder(image,fos);

encoder.encode();

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

9.5.8 Servlet cu RMI

Un servlet poate fi client al unei aplicatii RMI. Interfata la diatanta sedepune ın catalogul WEB-INF\lib al servlet-ului. Apelarea programului serverRMI se face prin

InterfataDistanta obj=(InterfataDistanta)

Naming.lookup("//"+host+":"+port+"/NumeServiciuRMI");

Page 207: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 207

Exemplul 9.5.7 Client servlet pentru aplicatia RMI de calcul al celui maimare divizor comun a doua numere naturale.

1 import java . i o . ∗ ;2 import java . rmi . ∗ ;3 import java . rmi . r e g i s t r y . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;6 import cmmdc . ∗ ;7 import javax . s e r v l e t . annotat ion . WebServlet ;

9 @WebServlet ( u r lPa t t e rn s = ”/ s e r v l e t r m i ” )10 public class ServletRMI extends HttpServ l e t {

12 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )13 throws Serv le tExcept ion , IOException {14 r e s . setContentType ( ” text /html” ) ;15 PrintWriter out = r e s . getWriter ( ) ;

17 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;18 long m=(new Long (sm ) ) . longValue ( ) , n=(new Long ( sn ) ) . longValue ( ) ;19 long x=0;

21 St r ing host=req . getParameter ( ” host ” ) . tr im ( ) ;22 St r ing sPort=req . getParameter ( ” port ” ) ;23 int port=I n t e g e r . pa r s e In t ( sPort ) ;

25 try{26 ICmmdc obj=(ICmmdc)Naming . lookup ( ”//”+host+” : ”+port+”/CmmdcServer” ) ;27 x=obj . cmmdc(m, n ) ;28 }29 catch ( Exception e ) {30 System . out . p r i n t l n ( ”CmmdcClient except ion : ”+e . getMessage ( ) ) ;31 }32 St r ing t i t l e=”CmmdcServlet” ;33 r e s . setContentType ( ” text /html” ) ;34 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;35 out . p r i n t l n ( t i t l e ) ;36 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;37 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;38 out . p r i n t l n ( ”<P>Cmmdc : ”+x ) ;39 out . p r i n t l n ( ”</BODY></HTML>” ) ;40 out . c l o s e ( ) ;41 }

43 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )44 throws Serv le tExcept ion , IOException{45 doGet ( req , r e s ) ;46 }47 }

9.5.9 Servlet cu JMS

De data aceasta cererea clientului se rezolva asincron:

Page 208: programare distribuita

208 CAPITOLUL 9. SERVLET

• In prima faza se apeleaza un servlet care apeleaza un server JMS. Solutiaeste retinuta de furnizorul serviciului de mesagerie pe o destinatie cu unsubiect furnizat de client. Pentru regasirea rezultatului, servlet-ul creazaclientului un abonament durabil, functie de numele subiectului.

• In faza a doua, clientul apeleaza un alt servlet, a carei functie este pre-luarea rezultatului. Clientul trebuie sa furnizeze subiectul destinatieirezultatului.

Exemplul 9.5.8

Codul serverului JMS

1 import javax . jms . ∗ ;2 import java . i o . ∗ ;3 import java . u t i l . S t r ingToken i ze r ;

5 public class MsgCmmdcServer{

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

9 public void s e r v i c e ( ){10 try{11 // Varianta Apache−MessageQueue12 // org . apache . act ivemq . ActiveMQConnectionFactory c f=13 // new org . apache . activemq . ActiveMQConnectionFactory (14 // ” tcp :// l o c a l h o s t :61616”) ;

16 // Varianta Oracle−Sun MessageQueue17 com . sun . messaging . TopicConnectionFactory c f=18 new com . sun . messaging . TopicConnectionFactory ( ) ;19 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;20 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);21 TopicConnection conn=c f . createTopicConnect ion ( ) ;22 TopicSess ion s e s s i o n=23 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;24 Dest inat i on tDate=s e s s i o n . c reateTop ic ( ”Cmmdc” ) ;25 TopicSubscr iber consumer=s e s s i o n . c r e a t e S u b s c r i b e r ( ( Topic ) tDate ) ;26 conn . s t a r t ( ) ;27 TextMessage txtMsg=null ;28 St r ing sm=”” , sn=”” , t o p i c=”” ;29 while ( true ){30 txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;31 St r ing msg=txtMsg . getText ( ) ;32 St r ing [ ] s t=msg . s p l i t ( ” ” ) ;33 sm=s t [ 0 ] ;34 sn=s t [ 1 ] ;35 t op i c=s t [ 2 ] ;36 System . out . p r i n t l n (sm+” : ”+sn+” : ”+to p i c ) ;37 long a=Long . parseLong (sm ) ;38 long b=Long . parseLong ( sn ) ;39 long c=cmmdc( a , b ) ;40 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i c ) ;41 MessageProducer producer=s e s s i o n . c reateProducer ( tResu l t ) ;42 txtMsg=s e s s i o n . createTextMessage ( (new Long ( c ) ) . t oS t r i ng ( ) ) ;

Page 209: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 209

43 producer . send ( txtMsg ) ;44 System . out . p r i n t l n ( ” Expediat raspuns ” ) ;45 }46 }47 catch ( Exception e ){48 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;49 }50 System . out . p r i n t l n ( ” Server f i n i s h e d ” ) ;51 }

53 public stat ic void main ( St r ing [ ] a rgs ){54 MsgCmmdcServer s e r v e r=new MsgCmmdcServer ( ) ;55 s e r v e r . s e r v i c e ( ) ;56 }57 }

Codul servlet-ului care transmite datele problemei serverului JMS

1 package jms ;2 import javax . jms . ∗ ;3 import java . i o . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;6 import javax . s e r v l e t . annotat ion . WebServlet ;

8 @WebServlet ( u r lPa t t e rn s = ”/ sender ” )9 public class JMSSenderServlet extends HttpServ l e t {

11 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )12 throws Serv le tExcept ion , IOException {13 r e s . setContentType ( ” text /html” ) ;14 ServletOutputStream out = r e s . getOutputStream ( ) ;15 St r ing m=req . getParameter ( ”m” ) ;16 St r ing n=req . getParameter ( ”n” ) ;17 St r ing t op i c=req . getParameter ( ” t op i c ” ) ;18 St r ing c l i e n t I D=req . getParameter ( ” c l i e n t I D ” ) ;19 St r ing cl ientName=req . getParameter ( ” cl ientName ” ) ;20 try{21 // Varianta Apache−MessageQueue22 // org . apache . act ivemq . ActiveMQConnectionFactory c f=23 // new org . apache . activemq . ActiveMQConnectionFactory (24 // ” tcp :// l o c a l h o s t :61616”) ;

26 // Varianta Oracle−Sun MessageQueue27 com . sun . messaging . TopicConnectionFactory c f=28 new com . sun . messaging . TopicConnectionFactory ( ) ;29 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;30 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);31 TopicConnection conn=c f . createTopicConnect ion ( ) ;32 conn . s e tC l i en t ID ( c l i e n t I D ) ;33 TopicSess ion s e s s i o n=34 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;35 Dest inat i on tResu l t=s e s s i o n . c reateTop ic ( t op i c ) ;36 TopicSubscr iber consumer=37 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;38 Dest inat i on t = s e s s i o n . c reateTopic ( ”Cmmdc” ) ;39 MessageProducer producer = s e s s i o n . c reateProducer ( t ) ;40 TextMessage txtMsg=s e s s i o n . createTextMessage ( ) ;41 St r ing mesaj=m+” ”+n+” ”+t op i c ;

Page 210: programare distribuita

210 CAPITOLUL 9. SERVLET

42 txtMsg . setText ( mesaj ) ;43 producer . send ( txtMsg ) ;44 s e s s i o n . c l o s e ( ) ;45 conn . c l o s e ( ) ;46 out . p r i n t l n ( ”<html><body bgco lo r=\”#ccbbcc\”><center>” ) ;47 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;48 out . p r i n t l n ( ”<p>” ) ;49 out . p r i n t l n ( ” Date le au f o s t exped ia te s e r v e r u l u i ” ) ;50 out . p r i n t l n ( ”</center></body></html>” ) ;51 }52 catch ( Exception e ){53 out . p r i n t l n ( e . getMessage ( ) ) ;54 }55 out . c l o s e ( ) ;56 System . out . p r i n t l n ( ” Pub l i she r f i n i s h e d ” ) ;57 }

59 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )60 throws Serv le tExcept ion , IOException {61 doGet ( req , r e s ) ;62 }63 }

Codul servlet-ului care preia rezultatul

1 package jms ;2 import javax . jms . ∗ ;3 import java . i o . ∗ ;4 import javax . s e r v l e t . ∗ ;5 import javax . s e r v l e t . http . ∗ ;6 import javax . s e r v l e t . annotat ion . WebServlet ;

8 @WebServlet ( u r lPa t t e rn s = ”/ r e c e i v e r ” )9 public class JMSReceiverServlet extends HttpServ l e t {

11 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )12 throws Serv le tExcept ion , IOException {13 r e s . setContentType ( ” text /html” ) ;14 ServletOutputStream out = r e s . getOutputStream ( ) ;15 St r ing t op i c=req . getParameter ( ” t op i c ” ) ;16 St r ing c l i e n t I D=req . getParameter ( ” c l i e n t I D ” ) ;17 St r ing cl ientName=req . getParameter ( ” cl ientName ” ) ;18 try{19 // Varianta Apache−MessageQueue20 // org . apache . act ivemq . ActiveMQConnectionFactory c f=21 // new org . apache . act ivemq . ActiveMQConnectionFactory (22 // ” tcp :// l o c a l h o s t :61616”) ;

24 // Varianta Oracle−Sun MessageQueue25 com . sun . messaging . TopicConnectionFactory c f=26 new com . sun . messaging . TopicConnectionFactory ( ) ;27 // c f . se tProper ty (” imqBrokerHostName ” ,” hos t ” ) ;28 // c f . se tProper ty (” imqBrokerHostPort ” ,”7676”);29 TopicConnection conn=c f . createTopicConnect ion ( ) ;30 conn . s e tC l i en t ID ( c l i e n t I D ) ;31 TopicSess ion s e s s i o n=32 conn . c r ea t eTop i cSe s s i on ( false , S e s s i on .AUTOACKNOWLEDGE) ;33 Dest inat i on tResu l t = s e s s i o n . c reateTop ic ( t op i c ) ;34 TopicSubscr iber consumer=

Page 211: programare distribuita

9.5. FACILITATI DE PROGRAMARE CU SERVLET 211

35 s e s s i o n . c r ea t eDurab l eSubsc r ibe r ( ( Topic ) tResult , cl ientName ) ;36 conn . s t a r t ( ) ;37 TextMessage txtMsg=(TextMessage ) consumer . r e c e i v e ( ) ;38 St r ing cmmdc=txtMsg . getText ( ) ;39 s e s s i o n . c l o s e ( ) ;40 conn . c l o s e ( ) ;41 out . p r i n t l n ( ”<html><body bgco lo r=\”#ccbbcc\”><center>” ) ;42 out . p r i n t l n ( ”<h1> JSP Cmmdc </h1>” ) ;43 out . p r i n t l n ( ”<p>” ) ;44 out . p r i n t l n ( ” Rezu l ta tu l obt inut : ”+cmmdc ) ;45 out . p r i n t l n ( ”</center></body></html>” ) ;46 }47 catch ( Exception e ){48 out . p r i n t l n ( e . getMessage ( ) ) ;49 }50 out . c l o s e ( ) ;51 System . out . p r i n t l n ( ” Subsc r ibe r f i n i s h e d ” ) ;52 }

54 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )55 throws Serv le tExcept ion , IOException {56 doGet ( req , r e s ) ;57 }58 }

In catalogul lib al servlet-ului trebuie incluse fisierele jar ale serviciului JMSfolosit.

9.5.10 Servlet cu jurnalizare

Exemplul 9.5.9 Servlet cu jurnalizare. Fisierul log se va afla ın catalogulaplicatiei si va fi oferit clientului spre consultare.

1 package l o g t e s t ;2 import java . i o . IOException ;3 import javax . s e r v l e t . Se rv l e tExcept ion ;4 import javax . s e r v l e t . Serv l e tContext ;5 import javax . s e r v l e t . http . HttpServ l e t ;6 import javax . s e r v l e t . http . HttpServ letRequest ;7 import javax . s e r v l e t . http . HttpServletResponse ;8 import javax . s e r v l e t . ServletOutputStream ;9 import java . u t i l . l o gg ing . Logger ;

10 import java . u t i l . l o gg ing . F i l eHandler ;11 import java . u t i l . l o gg ing . SimpleFormatter ;

13 import javax . s e r v l e t . annotat ion . WebServlet ;

15 @WebServlet ( u r lPa t t e rn s = ”/ l ogg ing ” )

17 public class LoggerSe rv l e t extends HttpServ l e t {18 private stat ic Logger l o g g e r=Logger . getLogger ( ” l o g t e s t . Logge rSe rv l e t ” ) ;

20 public void i n i t ( ){21 try{22 Fi l eHandle r l o g g i n g F i l e = new Fi l eHandle r ( ”webapps/ l o g g e r / r e s u l t s . l og ” ) ;

Page 212: programare distribuita

212 CAPITOLUL 9. SERVLET

23 l o g g i n g F i l e . setFormatter (new SimpleFormatter ( ) ) ;24 l o g g e r . addHandler ( l o g g i n g F i l e ) ;25 }26 catch ( IOException e ){27 System . out . p r i n t l n ( e . getMessage ( ) ) ;28 }29 }

31 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )32 throws Serv le tExcept ion , java . i o . IOException {33 St r ing f i l e S e p = System . getProperty ( ” f i l e . s epa ra to r ” ) ;

35 l o g g e r . i n f o ( ”INFO : He l lo ” ) ;36 l o g g e r . warning ( ”WARN : He l lo ” ) ;37 l o g g e r . s eve r e ( ”ERROR : He l lo ” ) ;

39 r e s . setContentType ( ” text /html” ) ;40 java . i o . Pr intWriter out = r e s . getWriter ( ) ;41 out . p r i n t l n ( ”<html><head><t i t l e >S e r v l e t logg ing </ t i t l e ></head><body>” ) ;42 out . p r i n t l n ( ”<h2>Hel lo from LoggerServ le t </h2>” ) ;43 out . p r i n t l n ( ”<br/>” ) ;44 out . p r i n t l n ( ”<a h r e f =\”http :// ”+45 req . getServerName ()+” : ”+46 req . getLoca lPort ()+ f i l e S e p+47 ” l o g g e r ”+f i l e S e p+” r e s u l t s . l og\”>V i z u a l i z a t i f i s i e r u l log</a>” ) ;48 out . p r i n t l n ( ”</body></html>” ) ;49 out . c l o s e ( ) ;50 }

52 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )53 throws Serv le tExcept ion , java . i o . IOException {54 doGet ( req , r e s ) ;55 }56 }

9.6 FileUpload

Deseori clientul trebuie sa furnizeze unui servlet un volum mare de date,depozitate ıntr-un fisier. Un produs care ne ajuta sa ındeplinim acest obiectiveste commons-fileupload - dezvoltat de apache.

Commons-FileUpload - dezvoltat ın cadrul apache - este un produs caresimplifica transferul unui fisier de la un client la programul server (file upload).Interfata de programare a produsului se refera la partea de server - ın cazul defata reprezentat prin servlet.

Instalarea produsului consta din dezarhivarea fisierului descarcat din In-ternet.

In plus este nevoie de

• commons-io

Page 213: programare distribuita

9.6. FILEUPLOAD 213

Fisierele

• commons-fileupload-*.*.jar

• commons-io-*.*.jar

se depun ın catalogul lib al servlet-ului.Transferarea unui fisier, din partea clientului nu ridica nici o problema. In

fisierul html de apelare, se defineste un formular

<form

action=. . .

enctype="multipart/form-data"

method="post">

iar un fisier de ıncarcat se fixeaza prin intermediul marcajului

<input type="file" name=. . . size=. . .>

Programul navigator afiseaza o fereastra de cautare, prin care clientul se-lecteaza fisierul pe care doreste sa-l ıncarce.

Daca partea de client este un program, atunci se utilizeaza commons-httpclient, 9.5.1

De partea de server punem ın evidenta doua sabloane de programare:

• Fisierele ıncarcate sunt retinute ınaintea utilizarii.

• Datele fisierelor se utilizeaza ın flux, ın momentul parvenirii lor.

In primul caz, programarea ıncarcarii revine la

1. Crearea unei fabrici pentru manipularea fisierelor pe disc

FileItemFactory factory = new DiskFileItemFactory();

2. Crearea unei unelte de ıncarcare

ServletFileUpload upload = new ServletFileUpload(factory);

3. Analiza (parsarea) mesajului furnizat de client

List fileItems = upload.parseRequest(req);

Page 214: programare distribuita

214 CAPITOLUL 9. SERVLET

Fiecare element al listei implementeaza interfata FileItem.

Se pot fixa parametrii

• dimensiunea zonei de pe disc destinata datelor de ıncarcat

DiskFileItemFactory factory = new DiskFileItemFactory();

factory.setSizeThreshold(maxMemorySize);

• catalogul temporar de retinere a datelor de ıncarcat

factory.setRepositoryPath(tempDirectory);

sau direct

DiskFileItemFactory factory = new DiskFileItemFactory(

maxMemorySize, tempDirectory);

• dimensiunea maxima a unui fisier

upload.setSizeMax(maxRequestSize);

4. Prelucrarea elementelor ıncarcate

Iterator iter=fileItems.iterator();

while (iter.hasNext()) {

FileItem item = (FileItem) iter.next();

if (item.isFormField()) {

// Prelucrarea elementului item care corespunde unei

// date din formularul html care nu este de tip fisier

}

else{

// Prelucrarea elementului item de tip fisier

}

}

5. In cazul unui element care nu este de tip fisier putem obtine numele sivaloarea atributului furnizat de client

String name = item.getFieldName();

String value = item.getString();

6. In cazul unui fisier putem afla numele campului input, numele fisierului,dimensiunea fisierului

Page 215: programare distribuita

9.6. FILEUPLOAD 215

String fieldName = item.getFieldName();

String fileName = item.getName();

long sizeInBytes = item.getSize();

7. Daca dorim sa salvam fisierul pe calculatorul server atunci prelucrareaeste

File uploadedFile = new File(...);

item.write(uploadedFile);

8. Daca datele fisierului se ıncarca ın memoria calculatorului atunci prelu-crarea este

InputStream in = item.getInputStream();

//preluarea datelor din fluxul in

. . .

in.close();

Alternativ, datele se pot retine ca un sir de octeti prin

byte[] data = item.get();

Exemplul 9.6.1 Sa se obtina ın memoria serverului matricea continuta ıntr-un fisier text. In fisierul text, fiecare linie contine o linie a matricei, iar ele-mentele sunt separate prin spatii.

Metoda getMatrix utilizata va reface matricea din datele fisierului.

1 package upload ;2 import java . i o . IOException ;3 import java . i o . InputStream ;4 import java . i o . InputStreamReader ;5 import java . i o . BufferedReader ;6 import javax . s e r v l e t . Se rv l e tExcept ion ;7 import javax . s e r v l e t . http . HttpServ l e t ;8 import javax . s e r v l e t . http . HttpServ letRequest ;9 import javax . s e r v l e t . http . HttpServletResponse ;

10 import javax . s e r v l e t . ServletOutputStream ;11 import javax . s e r v l e t . annotat ion . WebServlet ;12 import java . u t i l . L i s t ;13 import java . u t i l . I t e r a t o r ;14 import java . u t i l . Vector ;15 import org . apache . commons . f i l e u p l o a d . d i sk . DiskFi le I temFactory ;16 import org . apache . commons . f i l e u p l o a d . s e r v l e t . Se rv l e tF i l eUp load ;17 import org . apache . commons . f i l e u p l o a d . F i l e I temFactory ;18 import org . apache . commons . f i l e u p l o a d . F i l e I t em ;

Page 216: programare distribuita

216 CAPITOLUL 9. SERVLET

20 @WebServlet ( u r lPa t t e rn s = ”/ upload ” )21 public class Fi l eUp loadSe rv l e t extends HttpServ l e t {

23 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )24 throws Serv le tExcept ion , IOException {25 r e s . setContentType ( ” text / p l a i n ” ) ;26 ServletOutputStream out = r e s . getOutputStream ( ) ;27 try{28 Fi le I temFactory f a c t o r y = new DiskFi le I temFactory ( ) ;29 Serv l e tF i l eUp load upload = new Serv l e tF i l eUp load ( f a c t o r y ) ;30 L i s t i tems = upload . parseRequest ( req ) ;31 upload . setSizeMax (1000000) ;32 I t e r a t o r i t e r=items . i t e r a t o r ( ) ;33 while ( i t e r . hasNext ( ) ) {34 Fi l e I tem item = ( Fi l e I tem ) i t e r . next ( ) ;35 i f ( ! item . isFormFie ld ( ) ) {36 St r ing f i leName = item . getName ( ) ;37 out . p r i n t l n ( f i leName ) ;38 long s i z e InByt e s = item . g e t S i z e ( ) ;39 out . p r i n t l n ( s i z e InByt e s ) ;40 InputStream in=item . getInputStream ( ) ;41 InputStreamReader i s r=new InputStreamReader ( in ) ;42 BufferedReader br=new BufferedReader ( i s r ) ;43 double [ ] [ ] matrix=getMatrix ( br ) ;44 int m=matrix . l ength ;45 int n=matrix [ 0 ] . l ength ;46 for ( int i =0; i<m; i ++){47 for ( int j =0; j<n ; j++)48 out . p r i n t ( matrix [ i ] [ j ]+” ” ) ;49 out . p r i n t l n ( ) ;50 }51 br . c l o s e ( ) ;52 i s r . c l o s e ( ) ;53 in . c l o s e ( ) ;54 out . c l o s e ( ) ;55 }56 }57 }58 catch ( Exception e ){59 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;60 }61 }

63 private double [ ] [ ] getMatrix ( BufferedReader br ) throws Exception {64 Vector<Double> v=new Vector<Double >(10) ;65 double [ ] [ ] matrix=null ;66 try{67 St r ing l i n e , s ;68 int m=0,n ,mn;69 do{70 l i n e=br . readLine ( ) ;71 i f ( l i n e !=null ){72 m++;73 St r ing [ ] s t=l i n e . s p l i t ( ” ” ) ;74 for ( S t r ing s : s t ){75 v . addElement (new Double ( s ) ) ;76 }77 }78 }

Page 217: programare distribuita

9.6. FILEUPLOAD 217

79 while ( l i n e !=null ) ;80 i f ( v . s i z e ()>0){81 mn=v . s i z e ( ) ;82 n=mn/m;83 matrix=new double [m] [ n ] ;84 for ( int i =0; i<m; i ++){85 for ( int j =0; j<n ; j++){86 matrix [ i ] [ j ]=(( Double ) v . elementAt ( i ∗n+j ) ) . doubleValue ( ) ;87 System . out . p r i n t ( matrix [ i ] [ j ]+” ” ) ;88 }89 System . out . p r i n t l n ( ) ;90 }91 }92 }93 catch ( Exception e ){94 throw new Exception ( e . getMessage ( ) ) ;95 }96 return matrix ;97 }98 }

Pentru compilare se completeaza variabila de sistem classpath cu referintacatre fisierul commons-fileupload-*.*.jar.

Formularul clientului este

1 <html>2 <head>3 <script language=” j a v a s c r i p t ” >4 < !−−5 f u n c t i o n c h e c k I t (){6 var f i s=document . l i n e a r . m y f i l e . value ;7 i f ( f i s==”” ){8 a l e r t ( ” S e l e c t a t i f i s i e r u l core spunzator mat r i c e i ” ) ;9 re turn f a l s e ;

10 }11 re turn true ;12 }13 //−−>14 </ script>15 </head>16 <body>17 <h1> Inc &#259; r ca r ea unui f i &#351; i e r </h1>18 <form method=” post ” action=” upload ”19 enctype=” mult ipar t /form−data ”20 name=” l i n e a r ” onSubmit=” return check I t ( ) ”>21 <p>22 S e l e c t a &#355; i f i &#351; i e r u l23 <p>24 <input type=” f i l e ” name=” myf i l e ” s ize=30>25 <p>26 <input type=”submit” value=” Expediaza f i s i e r u l ”>27 </form>28 </body>29 </html>

In al doilea caz, codul pentru acelasi exemplu este

1 package upload ;

Page 218: programare distribuita

218 CAPITOLUL 9. SERVLET

2 import java . i o . IOException ;3 import java . i o . InputStream ;4 import java . i o . InputStreamReader ;5 import java . i o . BufferedReader ;6 import javax . s e r v l e t . Se rv l e tExcept ion ;7 import javax . s e r v l e t . http . HttpServ l e t ;8 import javax . s e r v l e t . http . HttpServ letRequest ;9 import javax . s e r v l e t . http . HttpServletResponse ;

10 import javax . s e r v l e t . ServletOutputStream ;11 import javax . s e r v l e t . annotat ion . WebServlet ;12 import java . u t i l . L i s t ;13 import java . u t i l . I t e r a t o r ;14 import java . u t i l . Vector ;15 import org . apache . commons . f i l e u p l o a d . s e r v l e t . Se rv l e tF i l eUp load ;16 import org . apache . commons . f i l e u p l o a d . F i l e I t e m I t e r a t o r ;17 import org . apache . commons . f i l e u p l o a d . Fi leItemStream ;

19 @WebServlet ( u r lPa t t e rn s = ”/ upload ” )

21 public class Fi l eUp loadSe rv l e t extends HttpServ l e t {

23 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )24 throws Serv le tExcept ion , IOException {25 r e s . setContentType ( ” text / p l a i n ” ) ;26 ServletOutputStream out = r e s . getOutputStream ( ) ;27 try{28 Serv l e tF i l eUp load upload = new Serv l e tF i l eUp load ( ) ;29 F i l e I t e m I t e r a t o r i t e r = upload . g e t I t e m I t e r a t o r ( req ) ;30 while ( i t e r . hasNext ( ) ) {31 FileItemStream item = i t e r . next ( ) ;32 St r ing name = item . getFieldName ( ) ;33 out . p r i n t l n (name ) ;34 i f ( ! item . isFormFie ld ( ) ) {35 St r ing f i leName = item . getName ( ) ;36 out . p r i n t l n ( f i leName ) ;37 InputStream in=item . openStream ( ) ;38 InputStreamReader i s r=new InputStreamReader ( in ) ;39 BufferedReader br=new BufferedReader ( i s r ) ;40 double [ ] [ ] matrix=getMatrix ( br ) ;41 int m=matrix . l ength ;42 int n=matrix [ 0 ] . l ength ;43 for ( int i =0; i<m; i ++){44 for ( int j =0; j<n ; j++)45 out . p r i n t ( matrix [ i ] [ j ]+” ” ) ;46 out . p r i n t l n ( ) ;47 }48 br . c l o s e ( ) ;49 i s r . c l o s e ( ) ;50 in . c l o s e ( ) ;51 out . c l o s e ( ) ;52 }53 }54 }55 catch ( Exception e ){56 System . out . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;57 }58 }

60 private double [ ] [ ] getMatrix ( BufferedReader br ) throws Exception { . . .}

Page 219: programare distribuita

9.7. DESCARCAREA UNUI FISIER 219

62 }

9.7 Descarcarea unui fisier

Consideram cazul:

Exemplul 9.7.1 Fisierul ales de client dintr-o lista disponibila este descarcatfiind transmis navigatorului.

1 import java . i o . IOException ;2 import javax . s e r v l e t . Se rv l e tExcept ion ;3 import javax . s e r v l e t . http . HttpServ l e t ;4 import javax . s e r v l e t . http . HttpServ letRequest ;5 import javax . s e r v l e t . http . HttpServletResponse ;6 import javax . s e r v l e t . ServletOutputStream ;7 import javax . s e r v l e t . annotat ion . WebServlet ;8 import java . n io . f i l e . Path ;9 import java . n io . f i l e . Paths ;

10 import java . n io . f i l e . F i l e s ;

12 @WebServlet ( u r lPa t t e rn s = ”/download” )

14 public class DownloadServlet extends HttpServ l e t {15 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )16 throws Serv le tExcept ion , IOException{17 ServletOutputStream out=r e s . getOutputStream ( ) ;18 St r ing f i l e=req . getParameter ( ” f i l e ” ) ;19 System . out . p r i n t l n ( f i l e ) ;20 Path c a l e=Paths . get ( ”webapps/download/ r e s o u r c e s /”+f i l e ) ;21 try{22 System . out . p r i n t l n ( c a l e+f i l e ) ;23 r e s . setContentType ( ” Appl i ca t ion /Octet−stream ” ) ;24 r e s . addHeader ( ”Content−D i s p o s i t i o n ” , ” attachment ; f i l ename=”+ f i l e ) ;25 F i l e s . copy ( ca le , out ) ;26 }27 catch ( Exception e ){28 r e s . setContentType ( ” text / p l a i n ” ) ;29 out . p r i n t l n ( ” Cererea d−voast ra nu poate f i s a t i s f a c u t a ” ) ;30 }31 out . c l o s e ( ) ;32 }

34 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )35 throws Serv le tExcept ion , IOException{36 doGet ( req , r e s ) ;37 }38 }

Randul 18 are ca efect pastrarea numelui si a extensiei pentru fisierul selectata se descarca.

Page 220: programare distribuita

220 CAPITOLUL 9. SERVLET

9.8 Filtru

Un filtru se asemeana unui servlet, dar activitatea ıntreprinsa vizeaza uzualcontextul, adica ansamblul servletilor care fac parte din aplicatia Web.

Un filtru se declara ın fisierul web.xml prin

<web-app>

. . .

<filter>

<filter-name>nume_filtru</filter-name>

<filter-class>clasa_filtrului</filter-class>

</filter>

<filter-mapping>

<filter-name>nume_filtru</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

. . .

</web-app>

Clasa filtrului implementeaza interfata Filter, adica metodele

• public void init(FilterConfig filterConfig) throws ServletException

• public void destroy()

• public void doFilter(ServletRequest request,ServletResponse response, FilterChain filterChain)throws IOException, ServletException

Exemplul 9.8.1 Contextul myservlet contine doi servleti HelloServlet si Cm-mdcServlet, apelabili respectiv din hello.html, cmmdc.html. Sa se programezeun filtru care

• Redirecteaza solicitarea “/myservlet/hello” catre “/cmmdc.html”.

• Daca se cere ca natura raspunsului sa fie “text/xml” atunci invalideazacererea.

Servletii HelloServlet si CmmdcServlet sunt cei dezvoltati la ınceputul aces-tui capitol. Filtrul are codul

Page 221: programare distribuita

9.8. FILTRU 221

1 import java . i o . IOException ;2 import javax . s e r v l e t . Serv l e tReques t ;3 import javax . s e r v l e t . Serv le tResponse ;4 import javax . s e r v l e t . RequestDispatcher ;5 import javax . s e r v l e t . F i l t e r ;6 import javax . s e r v l e t . F i l t e r C o n f i g ;7 import javax . s e r v l e t . F i l t e rCha in ;8 import javax . s e r v l e t . Se rv l e tExcept ion ;9 import javax . s e r v l e t . http . HttpServ letRequest ;

10 import javax . s e r v l e t . http . HttpServletResponse ;

12 public class MyFi l terDispatcher implements F i l t e r {13 private F i l t e r C o n f i g f i l t e r C o n f i g ;

15 public void i n i t ( F i l t e r C o n f i g f i l t e r C o n f i g ) throws Serv l e tExcept ion {16 this . f i l t e r C o n f i g = f i l t e r C o n f i g ;17 }

19 public void dest roy ( ) {20 this . f i l t e r C o n f i g = null ;21 }

23 public void d o F i l t e r ( Serv l e tReques t request , Serv le tResponse response ,24 Fi l t e rCha in f i l t e r C h a i n ) throws IOException , Se rv l e tExcept ion {25 HttpServ letRequest req = ( HttpServ letRequest ) r eque s t ;26 HttpServletResponse r e s = ( HttpServletResponse ) re sponse ;27 St r ing u r i = req . getRequestURI ( ) ;28 System . out . p r i n t l n ( ” F i l t e r URI= ”+u r i ) ;29 System . out . p r i n t l n ( u r i ) ;

31 i f ( u r i . equa l s ( ”/ myserv let ” ) | | u r i . equa l s ( ”/ myserv let /” ) )32 f i l t e r C h a i n . d o F i l t e r ( request , r e sponse ) ;33 else {34 i f ( u r i . equa l s ( ”/ myserv let / h e l l o ” ) ){35 St r ing d i spa t che rUr i=”/cmmdc . html” ;36 RequestDispatcher rd=reques t . getRequestDispatcher ( d i spa t che rUr i ) ;37 rd . forward ( request , r e sponse ) ;38 }39 else {40 i f ( u r i . equa l s ( ”/ myserv let /cmmdc” ) ){41 St r ing t i p=req . getParameter ( ” t i p ” ) ;42 i f ( t i p . equa l s ( ” t ext /xml” ) ){43 r e s . sendError ( HttpServletResponse .SC FORBIDDEN) ;44 }45 }46 f i l t e r C h a i n . d o F i l t e r ( request , r e sponse ) ;47 }48 }49 }50 }

Fisierul web.xml este

1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1”?>2 < !DOCTYPE web−app3 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”4 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>

6 <web−app>

Page 222: programare distribuita

222 CAPITOLUL 9. SERVLET

7 < f i l t e r>8 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>9 < f i l t e r −c l a s s>MyFi l terDispatcher</ f i l t e r −c l a s s>

10 </ f i l t e r>

12 < f i l t e r −mapping>13 < f i l t e r −name> f i l t e r D i s p a t c h e r</ f i l t e r −name>14 <ur l−pattern>/∗</ ur l−pattern>15 </ f i l t e r −mapping>16 </web−app>

Pentru ıntelegerea aplicatiei prezentam si codul fisierului cmmdc.html

1 <html>2 <head>3 <t i t l e>4 Cmmdc S e r v l e t5 </ t i t l e>6 </head>7 <body bgcolor=”#ccbbcc ”>8 <center>9 <h1> Cmmdc S e r v l e t </h1>

10 <form method=” get ”11 action=” http :// l o c a l h o s t :8080/ myserv let /cmmdc”>12 <table border=”1”>13 <tr>14 <td> Primul numar </td>15 <td> <input type=” text ” name=”m” s ize=10> </td>16 </ tr>17 <tr>18 <td> Al d o i l e a numar </td>19 <td> <input type=” text ” name=”n” s ize=10> </td>20 </ tr>21 <tr>22 <td> Natura ra spunsu lu i </td>23 <td> <select name=” t i p ” >24 <option value=” text /html”> t ex t /html25 <option value=” text / p l a i n ”> t ex t / p l a i n26 <option value=” text /xml”> t ex t /xml27 </ select> </td>28 </ tr>29 <tr>30 <td> <input type=”submit” value=” Calcu leaza ”> </td>31 <td></td>32 </ tr>33 </table>34 </form>35 </center>36 </body>37 </html>

Alternativ, fisierul web.xml se poate elimina prin utilizarea adnotarilor:

. . .

import javax.servlet.annotation.WebFilter;

@WebFilter(filterName="MyFilterDispatcher",urlPatterns={"/cmmdc","/html"})

public class MyFilterDispatcher implements Filter {. . .}

Page 223: programare distribuita

9.9. EVENIMENT SI AUDITOR 223

9.9 Eveniment si auditor

Tehnologia Servlet permite urmarirea si interventia de catre serverul Webın:

• ciclul de viata al unui servlet, prin interfata

javax.servlet.ServletContextListener

• evolutia obiectului javax.servlet.http.HttpSession prin interfata

javax.servlet.http.HttpSessionListener

Interfata ServletContextListener declara metodele

• void contextInitialized(ServletContextEvent sec)

• void contextDestroyed(ServletContextEvent sec)

Interfata HttpSessiontListener declara metodele

• void sessionCreated(HttpSessionEvent hse)

• void sessionDestroyed(HttpSessionEvent hse)

Clasa care implementeaza una din aceste interfete se declara ın fisierulweb.xml printr-un element <listener>>

<listener>

<listener-class> clasa_listener </listener-class>

</listener>

Exemplul 9.9.1 Auditor care sesizeaza ıncarcarea si disparitia unui servletafisand ın fereastra DOS a serverului Web un mesaj.

1 import javax . s e r v l e t . S e rv l e tContex tL i s t ene r ;2 import javax . s e r v l e t . ServletContextEvent ;3 import javax . s e r v l e t . Serv l e tContext ;

5 public class Fi r s tContex tL i s t ene r6 implements Se rv l e tContex tL i s t ene r {7 public void contextDestroyed ( ServletContextEvent event ) {8 System . out . p r i n t l n ( ”Web app was removed . ” ) ;9 }

10 public void c o n t e x t I n i t i a l i z e d ( ServletContextEvent event ) {11 System . out . p r i n t l n ( ”Web app i s ready . ” ) ;12 Serv le tContext sc=event . ge tServ l e tContext ( ) ;13 System . out . p r i n t l n ( sc . getContextPath ( ) ) ;14 System . out . p r i n t l n ( sc . g e tE f f e c t i v eMajo rVer s i on ( ) ) ;15 System . out . p r i n t l n ( sc . g e tE f f e c t i veMinorVer s i on ( ) ) ;16 }17 }

Page 224: programare distribuita

224 CAPITOLUL 9. SERVLET

Exemplul 9.9.2

1 import javax . s e r v l e t . http . Ht tpSe s s i onL i s t ene r ;2 import javax . s e r v l e t . http . HttpSess ionEvent ;

4 public class F i r s t S e s s i o n L i s t e n e r implements HttpSe s s i onL i s t ene r {5 stat ic int use r s = 0 ;

7 public void s e s s i onCrea t ed ( HttpSess ionEvent e ) {8 use r s++;9 }

10 public void s e s s i onDes t royed ( HttpSess ionEvent e ) {11 users−−;12 }13 public stat ic int getConcurrentUsers ( ) {14 return use r s ;15 }16 }

9.10 Server apache-tomcat ıncorporat

Intr-o clasa Java se poate ıncorpora un server tomcat ın care pot fi instalateuna sau mai multi serveti. Resursele necesare sunt continute ın apache-tomcat-*-embedded, iar fisierele jar continute trebuie declarate ın variabila de sistemclasspath.

Sablonul de programare este:

1 import org . apache . c a t a l i n a . s ta r tup . Tomcat ;2 import org . apache . c a t a l i n a . Context ;3 import java . i o . F i l e ;

5 public class EmbeddedTomcat{6 public stat ic void main ( St r ing [ ] a rgs ) {7 try {8 Tomcat tomcat = new Tomcat ( ) ;9 tomcat . setBaseDir ( ” . ” ) ;

10 tomcat . s e tPor t ( 9 0 9 0 ) ; // p o r t u l s e r v e r u l u i

12 F i l e docBase = new F i l e ( ” . ” ) ;13 Context c tx t = tomcat . addContext ( ”/” , docBase . getAbsolutePath ( ) ) ;

15 Tomcat . addServ le t ( ctxt , ” numeServlet ” , new Cla saSe rv l e t ( ) ) ;16 c tx t . addServletMapping ( ”/numeApel” , ” numeServlet ” ) ;

18 tomcat . s t a r t ( ) ;19 tomcat . g e tSe rve r ( ) . await ( ) ;20 }21 catch ( Exception e ) {22 e . pr intStackTrace ( ) ;23 }24 }25 }

Page 225: programare distribuita

9.10. SERVER APACHE-TOMCAT INCORPORAT 225

Intrebari recapitulative

1. Precizati sensurile si continutul cuvantului servlet.

2. Unde se instaleaza o aplicatie servlet ın serverul Web apache-tomcat?

3. Cum se poate apela aplicatia servlet si, dar servlet-ul propriu zis?

4. Extinzand clasa HttpServlet, ce trebuie sa faca programatorul?

5. Care sunt modurile de programare a unui servlet si precizati diferentadintre ele.

6. Care sunt sarcinile de indeplinit ın metoda doGet?

Page 226: programare distribuita

226 CAPITOLUL 9. SERVLET

Page 227: programare distribuita

Capitolul 10

Java Server Page – JSP

10.1 Tehnologia JSP

Tipul tehnologiei JSP este denumit procesare de sabloane (template en-gine). JSP este o tehnologie similara cu PHP, ASP.NET, apache-velocity, etc.JSP permite includerea de cod Java ıntr-un document html. Un asemeneadocument se depoziteaza ıntr-un server Web, container de servlet, cu extensiajsp, eventual jspx.

Apelarea documentului JSP se realizeaza prin

• meniul File/Open a unui navigator, cu

http://host:port/cale/doc.jsp

• referinta html

<a href="http://host:port/cale/doc.jsp">

• valoare a atributului action ıntr-un marcaj form

<form action="http://host:port/cale/doc.jsp" ... >

Prin cale se ıntelege calea de la catalogul webapps pana la catalogul cecontine fisierul jsp.

Vom depozita fisierele JSP ıntr-un catalog jsp din arborele

webapps

|--> JSPApp

| |--> WEB-INF

| | |--> classes

| | | web.xml

227

Page 228: programare distribuita

228 CAPITOLUL 10. JAVA SERVER PAGE – JSP

| |--> jsp

| | | doc.jsp

caz ın care cale=JSPApp/jsp.Astfel, schimband numele fisierului Hello.html

1 <html>2 <body>3 Hel lo4 </body>5 </html>

ın Hello.jsp si plasandu-l ın catalogul jsp se obtine acelasi efect, dar prelu-crarea paginilor / documentelor este diferita. Fisierul html este prelucrat doarde programul navigator si poate fi deschis ca fisier, ın timp ce fisierul JSP esteprelucrat de serverul Web cu afisarea prin intermediul navigatorului. Prelu-crarea efectuata de serverul Web consta din transformarea paginii / documen-tului JSP ıntr-un servlet, care este compilat si lansat ın executie. Din aceastracauza prima invocare a paginii / documentului JSP dureaza mai mult decatapelarile ulterioare.

Fisierul JSP poate fi construit pe un document xhtml, avand preambulul

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

sau document html 5. In acest caz preambulul este

<!doctype html>

Apelarea paginii / documentului JSP se face prin jsp/Hello.jsp

Exista doua moduri de a include elemente JSP ıntr-un text html:

• prin elemente specifice JSP.

Fisierul are extensia jsp si se numeste pagina JSP.

• prin elemente xml apartinand spatiului de nume

http://java.sun.com/JSP/Page

Fisierul poate avea extensia jsp sau jspx si se numeste document JSP.

Comentariile JSP se scriu de forma

<%-- Comentariu --%>

Page 229: programare distribuita

10.1. TEHNOLOGIA JSP 229

Consideram urmatorul exemplu introductiv:

Exemplul 10.1.1 Putem afisa valoarea unei variabile Java (de exemplu datacalendaristica) prin

• Varianta paginii JSP

1 <html>2 <body>3 <p>4 Data c a l e n d a r i s t i c a 1 :5 <%= new java . u t i l . Date ( ) %>

7 <p>8 <% java . u t i l . Date data1=new java . u t i l . Date ( ) ; %>9 Data c a l e n d a r i s t i c a 2 :

10 <%= data1 %>

12 <p>13 <% java . u t i l . Date data2=new java . u t i l . Date ( ) ; %>14 Data c a l e n d a r i s t i c a 3 :15 <% out . p r i n t ( data2 ) ; %>16 </body>17 </html>

Daca se utilizeaza operatorul de afisare = atunci dupa expresia de afisatnu se pune ;.

Variabila predefinita out este de tip javax.servlet.jsp.JspWriter.

• Varianta documentului JSP

1 <?xml v e r s i o n=” 1 .0 ” encoding=”UTF−8” ?>2 <html xmlns : j s p=” http :// java . sun . com/JSP/Page”>3 <body>4 <j sp : s c r i p t l e t>5 java . u t i l . Date d=new java . u t i l . Date ( ) ;6 </ j sp : s c r i p t l e t>7 <j sp : exp r e s s i on> d </ j sp : exp r e s s i on>8 </body>9 </html>

Codul Java ınglobat ıntr-un text html se numeste scriptlet. Sintaxa uti-lizata este

• Varianta paginii JSP

<% cod Java %>

Page 230: programare distribuita

230 CAPITOLUL 10. JAVA SERVER PAGE – JSP

• Varianta documentului JSP

<jsp:scriptlet> codJava </jsp:scriptlet>

Domeniul de valabilitate. Domeniul de valabilitate defineste intervalulde timp, de existenta al unui obiect, fiind definit prin valorile:

Valoare Domeniu de valabilitate

page pagina curentarequest ın pagina curenta,

ın paginile incluse siın paginile catre care se face o redirectare

session ın sesiunea curentaapplication pe durata rularii aplicatiei

In orice pagina / document JSP sunt predefinite obiectele:

Variabila Tip/Clasa

out javax.servlet.jsp.JspWriterrequest javax.servlet.ServletRequestresponse javax.servlet.ServletResponsesession javax.servlet.http.HttpSessionpage java.lang.Object, thispageContext javax.servlet.jsp.PageContextapplication javax.servlet.ServletContext

ServletContext.getServletConfig().getContext()exception java.lang.Throwable

Astfel

String request.getParameter(String numeParametru)

furnizeaza valoarea parametrului numeParametru dintr-un formular html.

Exemplul 10.1.2 Pagina JSP Hello: Clientul transmite numele paginii careıi raspunde cu mesajul de salut ”Hi ” + nume + ” !”.

Codul paginii JPS (hello.jsp) este

1 <html>2 <head>3 <t i t l e> j s p h e l l o </ t i t l e>4 </head>5 <body>

Page 231: programare distribuita

10.1. TEHNOLOGIA JSP 231

6 <center>7 <h1> Pagina de r&#259; spuns </h1>8 <p>9 <%

10 out . p r i n t l n ( ”Hi ”+reques t . getParameter ( ”name”)+” ! ” ) ;11 %>12 </center>13 </body>14 </html>

apelat din (index.html)

1 <html>2 <head>3 <t i t l e> JSP Hel lo </ t i t l e>4 </head>5 <body bgcolor=”#bbeebb”>6 <center>7 <h1> Pagina de ape l a r e JSP </h1>8 <form method=” post ”9 action=” j sp / h e l l o . j sp ”>

10 <p> Numele :11 <input type=” text ” name=”name” s ize=20>12 <p>13 <input type=”submit”>14 </form>15 </center>16 </body>17 </html>

Compilarea si arhivarea servlet-ului o vom realiza prin intermediul luiapache-ant. In acest scop se creaza structura:

jsphello

| |--> src

| |--> web

| | | |--> jsp

| | | | hello.jsp

| | |--> WEB-INF

| | | |--> classes

| | | |--> lib

| | | | web.xml

| | | index.html

Fisierul web.xml este simplu

1 <p r o j e c t ba s ed i r=” . ” default=” generate . war”>2 <property name=” d i s t . name” value=”JSPApp” />3 <property name=” d i s t . d i r ” va lue=” d i s t ” />

5 <path id=” myclasspath ”>6 < f i l e s e t d i r=”web/WEB−INF/ l i b ”>7 <i n c l ude name=” ∗ . j a r ”/>8 </ f i l e s e t>9 </path>

11 <t a r g e t name=” i n i t ”>12 <d e l e t e d i r=”${ d i s t . d i r }”/>

Page 232: programare distribuita

232 CAPITOLUL 10. JAVA SERVER PAGE – JSP

13 <d e l e t e d i r=”web/WEB−INF/ c l a s s e s ”/>14 <mkdir d i r=”web/WEB−INF/ c l a s s e s ”/>15 <mkdir d i r=”${ d i s t . d i r }” />16 </ t a r g e t>

18 <t a r g e t name=” compile ” depends=” i n i t ”>19 <javac c l a s s p a t h r e f=” myclasspath ”20 s r c d i r=” s r c ”21 d e s t d i r=”web/WEB−INF/ c l a s s e s ”22 inc ludeantrunt ime=” f a l s e ”/>23 </ t a r g e t>

25 <t a r g e t name=” generate . war” depends=” compile ”>26 < j a r d e s t f i l e=”${ d i s t . d i r }/${ d i s t . name } . war” bas ed i r=”web” />27 </ t a r g e t>28 </ p r o j e c t>

10.1.1 Declaratii JSP

Printr-o declaratie JSP, putem defini campuri(variabile) si metode Java cepot fi apoi folosite, respectiv apelate ın documentul respectiv. O declaratieJSP se defineste printr-un marcaj

<%! . . . %>

sau, ın format XML

<jsp:declaration> . . . </jsp:declaration>

Exemplul 10.1.3 Calculul celui mai mare divizor comun a doua numere nat-urale cu metoda de calcul este definita ıntr-o declaratie JSP.

Pagina JSP a aplicatiei cmmdc.jsp:

1 <html>2 <body>3 <H1> CMMDC </H1>4 <%!5 long cmmdc( long m, long n ) { . . .}6 %>7 Rezu l ta tu l e s t e8 <%9 String sm=reques t . getParameter ( ”m” ) ;

10 String sn=reques t . getParameter ( ”n” ) ;11 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;12 out . p r i n t l n (cmmdc(m, n ) ) ;13 %>14 </body>15 </html>

apelat din documentul cmmdc.html

Page 233: programare distribuita

10.1. TEHNOLOGIA JSP 233

1 <html>2 <body>3 <h1> Calcu lu l Cmmdc </h1>4 <form method=” post ”5 action=” j sp /cmmdc . j sp ”>6 <p>7 Primul numar e s t e8 <input type=” text ” name=”m” value=”” s ize=5>9 <p>

10 Al d o i l e a numar e s t e11 <input type=” text ” name=”n” value=”” s ize=5>12 <p>13 <input type=”submit” value=” Calcu leaza ”>14 <input type=” r e s e t ” value=”Abandon”>15 </form>16 </body>17 </html>

Exista doua metode jspInit() si jspDestroy() care daca sunt declaratede programator atunci sunt executate la ınceputul si la sfarsitul ciclului deviata a paginii / documentului JSP.

Exemplul 10.1.4 Metoda jspInit initializeaza un numar cu 0 iar metodajspDestroy afiseaza numarul pe calculatorul serverului. Un client introduceun numar care este adunat la cel retinut de pagina JSP.

Efectul metodei jspDestroy are loc ın urma opririi aplicatiei JSP.Codul paginii JSP este

1 <html>2 <head>3 <t i t l e> I n i t </ t i t l e>4 </head>5 <body>6 <%!7 i n t numar ;8 pub l i c void j s p I n i t ( ){9 numar=0;

10 }11 pub l i c void j spDestroy ( ){12 System . out . p r i n t l n (numar ) ;13 }14 %>15 <center>16 <h1> Pagina de r&#259; spuns </h1>17 <p>18 <%19 String sn=reques t . getParameter ( ”numar” ) ;20 i n t n=I n t e g e r . pa r s e In t ( sn ) ;21 numar+=n ;22 out . p r i n t l n ( ”Numarul e s t e : ”+numar ) ;23 %>24 </center>25 </body>26 </html>

Page 234: programare distribuita

234 CAPITOLUL 10. JAVA SERVER PAGE – JSP

10.1.2 Directive JSP

Directivele JSP fixeaza informatii pentru tot documentul jsp. O directivajsp se indica prin marcajul

<%@ directiva atribut1 atribut2 . . . %>

sau ın format XML

<jsp:directive.directiva atribut1 atribut2 . . . />

unde fiecare atribut are sintaxa nume=valoare.Directivele pot fi: page, include, taglib.

• Directiva page. Mentionam atributele

import= ”lista de pachete separate prin ,”info= ”text” Informatia se poate regasi apeland metoda

getServletInfo()errorPage= ”adresa url a paginii ce trateaza exceptia”isErrorPage= "true | false"

• Directiva include permite includerea unor fisiere .html sau .jsp ın docu-ment

<%@ include file=”fisier html, jsp” %>

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

Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSPinitiale (adica cea ın care apare directiva).

• Directiva taglib indica bibliotecile de marcaje utilizate ın documentuljsp, avand atributele

uri= ”uri - Universal Resource Identifier - a bibliotecii de marcaje”prefix= ”prefixul marcajului”

10.1.3 Marcaje JSP predefinite

Un marcaj JSP defineste o actiune care se executa ın timpul procesariipaginii jsp. Sintaxa marcajelor JSP seamana cu cea a marcajelor html sauxml

<prefix : marcaj atribute />

Page 235: programare distribuita

10.1. TEHNOLOGIA JSP 235

Dintre marcajele JSP predefinite – adica cu prefixul JSP – amintim:

• <jsp : include page=”numeFisier jsp sau html” />

• <jsp : forward page=”numeFisier jsp sau html” />

Prelucrarea care urmeaza va fi cea din fisierul mentional. Diferenta dintrecele doua elemente consta ın faptul ca include prevede revenirea ınpagina JSP initiala iar forward nu.

Referinta la fisierul html sau jsp se face relativ la catalogul paginii JSPinitiale.

In cazul marcajelor<jsp: include>, <jsp: forward> se pot trans-mite parametri prin marcajele incluse<jsp:param name="nume" value=valoare "/>

sau<jsp:params>

<jsp:param name="nume" value=valoare "/>. . . . . .

</jsp:params>

• <jsp : useBean id=”numeComponentaJava”class=”numeClasa”scope=”domeniu” />

unde domeniu precizeaza domeniul de valabilitate al componentei Java,adica page, request, session, application.

Creaza un obiect ”numeComponentaJava” de tip ”numeClasa” avanddomeniul de valabilitate data de ”domeniu”.

• <jsp : setProperty name=”numeComponentaJava”property=”numeProp”value=”valoare”/>

Acest marcaj este echivalent cu codul JavanumeComponentaJava.setNumeProp(valoare).

<jsp : setProperty name=”numeComponentaJava” property="*" />vizeaza toate proprietatile componentei Java, fixarea valorilor facandu-se cu datele unui formular. Numele parametrilor din formularele de in-troducere a datelor trebuie sa coincida cu identificatorii campurilor dincomponenta Java corespunzatoare.

Page 236: programare distribuita

236 CAPITOLUL 10. JAVA SERVER PAGE – JSP

• <jsp : getProperty name=”numeComponentaJava”property=”numeProp”/>

Preia si afiseaza valoarea campului numeComponentaJava.numeProp.

10.1.4 Pagini JSP cu componente Java

Clasa componentei Java care se va utiliza ıntr-o pagina JSP trebuie inclusaıntr-un pachet.

Reluam exemplul 10.1.2 cu o componenta Java corespunzatoare numeluidin formularul index.html.

Exemplul 10.1.5

1 package j sp ;2 public class HelloBean {3 private St r ing name=”” ;4 public St r ing getName ( ) {5 return name ;6 }7 public void setName ( St r ing name) {8 this . name=name ;9 }

10 }

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

1 <j sp : useBean id=” obj ” class=” j sp . HelloBean ” scope=” reques t ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <head>5 <t i t l e> j s p h e l l o </ t i t l e>6 </head>7 <body>8 <h1> Pagina de r&#259; spuns </h1>9 <center>

10 <%11 out . p r i n t l n ( ”Hi ”+obj . getName()+” ! ” ) ;12 %>13 </center>14 </body>15 </html>

Mai mult, se poate include formularul ın pagina JSP, bineınteles stergandu-ldin fisierul html:

1 <j sp : useBean id=” obj ” class=” j sp . HelloBean ” scope=” reques t ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <head>5 <t i t l e> j s p h e l l o </ t i t l e>6 </head>

Page 237: programare distribuita

10.1. TEHNOLOGIA JSP 237

7 <body>8 <center>9 <h1> Pagina JSP − a p l i c a &#355; i a He l lo </h1>

10 <form method=” post ”>11 <p> <h3> I n t r o d u c e t i numele : </h3>12 <input type=” text ” name=”name” s ize=20>13 <p>14 <input type=”submit”>15 </form>16 <p>17 <%18 out . p r i n t l n ( ”Hi ”+obj . getName()+” ! ” ) ;19 %>20 </center>21 </body>22 </html>

Exemplul 10.1.6 Pagina JSP pentru calculul celui mai mare divizor comuncu metoda de calcul definita ıntr-o componenta Java.

Utilizand documentului html din Exemplul 10.1.3 se defineste componentaJava

1 package cmmdc ;2 public class CmmdcBean{3 private St r ing m=”” ;4 private St r ing n=”” ;5 private St r ing cmmdc ;

7 public void setM ( St r ing m){8 this .m=m;9 }

10 public void setN ( St r ing n){11 this . n=n ;12 }13 public St r ing getM (){14 return m;15 }16 public St r ing getN (){17 return n ;18 }

20 public St r ing getCmmdc ( ){21 long a=Long . parseLong (m) ;22 long b=Long . parseLong (n ) ;23 return (new Long (cmmdc( a , b ) ) ) . t oS t r i ng ( ) ;24 }

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

28 }

Instantiem o componenta Java si ıi fixam proprietatile (adica ıi transmitemparametri problemei) dupa care apelam metoda ce calculeaza rezultatul doritın pagina JSP:

Page 238: programare distribuita

238 CAPITOLUL 10. JAVA SERVER PAGE – JSP

1 <j sp : useBean id=” obj ” class=”cmmdc . CmmdcBean” scope=” a p p l i c a t i o n ”/>2 <j sp : s e tProper ty name=” obj ” property=”∗”/>3 <html>4 <body>5 Cel mai mare d i v i z o r comun a l numerelor6 <p>7 <%=obj . getM ( ) %> s i <%=obj . getN ( ) %>8 e s t e <%=obj . getCmmdc ( ) %>9 </body>

10 </html>

Exemplul 10.1.7 Generarea unei exceptii (errhandler.jsp):

1 <%@ page errorPage=” er ro rpage . j sp ” %>2 <html>3 <body>4 <%5 String mater ia=reques t . getParameter ( ” mater ia ” ) . tr im ( ) ;6 i f ( mater ia . equa l s ( ”AN” ) ) {7 out . p r i n t l n ( ”<hr><f ont c o l o r=red>Alegere co r e c ta !</ font>” ) ;8 }9 e l s e {

10 throw new Exception ( ”N−a t i f a cu t a l e g e r e a co r e c ta ” ) ;11 }12 %>13 </body>14 </html>

cu pagina de tratare a exceptiei (errorpage.jsp)

1 < !−−2 Aceste comentar i i sunt f o a r t e importante in c a z u l u t i l i z a r i i3 n a v i g a t o r u l u i IE s i a l u i apache−tomcat −5 .∗ .∗ . / 6 .∗ .∗ . In l i p s a4 l o r nu se genereaza s a l t u l l a e x c e p t i e pr in pagina j s p .5 Rolu l c o m e n t a r i i l o r e s t e marirea l u n g i m i i f i s i e r u l u i de f a t a .

7 O a l t e r n a t i v a e s t e ca din IE6 . . . Options sa se d e z a c t i v e z e8 opt iunea ”Show f r i e n d l y HTTP e r r o r message”

10 Cu n a v i g a t o r u l F i r e f o x nu e x i s t a aceas ta problema .11 −−>

13 <%@ page i sErrorPage=” true ” %>14 <html>15 <body>16 <div align=” cente r ”>17 <%= except ion . getMessage ( ) %>18 </div>

20 </body>21 </html>

Page 239: programare distribuita

10.2. JSP STANDARD TAG LIBRARY JSTL 239

apelate prin

1 <html>2 <body>3 <form method=post4 action=” j sp / e r rhand l e r . j sp ”>5 Care e s t e mater ia p r e f e r a t a din a n i i de s tud iu u n i v e r s i t a r ?6 <p>7 Algor i tmica s i programare8 <input type=” rad io ” name=” mater ia ” value=”AP” checked>9 <p>

10 Anal iza numerica11 <input type=” rad io ” name=” mater ia ” value=”AN”>12 <p>13 I n t e l i g e n t a a r t i f i c i a l a14 <input type=” rad io ” name=” mater ia ” value=”IA”>15 <p>16 <input type=submit>17 </form>18 </body>19 </html>

10.2 JSP Standard Tag Library JSTL

JSTL este o familie de biblioteci de marcaje ce ofera o serie de facilitatiactivitatii de realizare a paginilor Web. JSTL ajuta la separarea activitatii deprogramare de aceea a proiectare (design) a paginii Web.

JSTL este alcatuita din 5 biblioteci:URI Descriere

http://java.sun.com/jsp/jstl/core Biblioteca de bazahttp://java.sun.com/jsp/jstl/xml Biblioteca de prelucrare

a documentelor xmlhttp://java.sun.com/jsp/jstl/fmt Biblioteca de formatare a datelorhttp://java.sun.com/jsp/jstl/sql Biblioteca de lucru cu baze de datehttp://java.sun.com/jsp/jstl/functions Biblioteca de functii ajutatoare

Instalarea bibliotecilor. Bibliotecile sunt livrate ımpreuna cu apache-tomcat-* ın catalogul apache-tomcat-*\webapps\examples\WEB-INF\lib prinfisierele jstl.jar si standard.jar.

Utilizarea bibliotecilor. In vederea utilizarii, cele doua fisiere trebuiecopiate ın catalogul lib al aplicatiei care utilizeaza bibliotecile.

In pagina / documentul JSP, o biblioteca utilizata trebuie declarata printr-o directiva taglib.

Page 240: programare distribuita

240 CAPITOLUL 10. JAVA SERVER PAGE – JSP

10.2.1 Biblioteca de baza

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

Marcaje din biblioteca de baza:

• c:set Fixeaza o valoare ıntr-o variabila.

Atribute ale marcajului:

Atribut Fel Descriere

var obligatoriu Numele variabilei ce va stoca valoareaexpresiei.

value optional Expresia care va fi evaluata si atribuitavariabilei

scope optional Domeniul de valabilitate al variabilei.Unul din valorile:page, request, session, application.

Referirea la o variabila se face prin sintaxa ${numeVariabila}Referirea la valoarea unui camp dintr-un formular se face prin${param.numeCamp}Alaturi de obiectul param, alte obiecte predefinite sunt cookie, header,

initParam, pageContext.

Se pot defini variabile cu acelasi nume dar avand domenii de valabilitatediferita. Referirea se face prin ${pageScope.numeVariabila},${requestScope.numeVariabila}, ${sessionScope.numeVariabila},${applicationScope.numeVariabila}.Plasand clauza empty ınaintea unei variabile, ${empty numeVariabila},se obtine false sau true dupa cum variabila are sau nu atribuita ovaloare.

• c:remove Sterge o variabila.

Atribute ale marcajului:

Atribut Fel Descriere

var obligatoriu Numele variabilei ce se sterge.scope optional Domeniul de valabilitate al variabilei.

Unul din valorile:page, request, session, application.

Page 241: programare distribuita

10.2. JSP STANDARD TAG LIBRARY JSTL 241

• c:out Afiseaza o valoare.

Atribute ale marcajului:

Atribut Fel Descriere

value obligatoriu Valoarea ce se evalueaza si se afiseaza.default optional Cea ce se afiseaza ın cazul ın care

expresia nu poate fi evaluata.escapeXml optional true / false. Valoarea implicita este true.

Pe false interpreteaza caracterele din value

ca si cod html.

• c:if Test, verificarea unei conditii.

Atribute ale marcajului:

Atribut Fel Descriere

test obligatoriu Conditia de test.var optional Numele variabilei ce va stoca valoarea

testului.scope optional Domeniul de valabilitate al variabilei

definita anterior.

In cazul ın care conditia are valoarea true se prelucreaza corpul marca-jului, ın caz contrar, acesta este ignorat.

Exemplul 10.2.1 Preluarea datelor unui formular cu campurile de in-trare nume, prenume si email se face prin pagina JSP

1 <HTML>2 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / core ” p r e f i x=”c” %>3 <BODY>4 <p>5 <c : i f t e s t=”${empty param . nume}” var=”testNume” >6 <c : out value=”Numele l i p s e s t e ! ” />7 </c : i f>8 <c : i f t e s t=”${not testNume}” >9 Nume:<c : out value=”${param . nume}” />

10 </c : i f>11 <p>12 <c : i f t e s t=”${empty param . prenume}” var=” testPrenume ” >13 <c : out value=”Prenumele l i p s e s t e ! ” />14 </c : i f>15 <c : i f t e s t=”${not testPrenume}” >16 Prenume :<c : out value=”${param . prenume}” />17 </c : i f>18 <p>19 <c : i f t e s t=”${empty param . emai l }” var=” testEmai l ”>

Page 242: programare distribuita

242 CAPITOLUL 10. JAVA SERVER PAGE – JSP

20 <c : out value=”Adresa E−Mail l i p s e s t e ! ” />21 </c : i f>22 <c : i f t e s t=”${not tes tEmai l }” >23 E−mail :<c : out value=”${param . emai l }” />24 </c : i f>25 </BODY>26 </HTML>

• c:choose Marcajul de selectie poate contine oricate marcaje c:when

si cel mult un marcaj c:otherwise. Fiecare marcaj c:when contineobligatoriu atributul test. Daca ıntr-un marcaj c:when conditia arevaloarea true, atunci se prelucreaza corpul acelui marcaj. In cazul ın caretoate marcajele c:when au fost evaluate cu false atunci se va prelucramarcajul c:otherwise (marcaj fara atribute).

• c:forEach Ciclu.

Atribute ale marcajului:

Atribut Fel Descriere

items optional Colectia care se parcurge.var optional Numele variabilei ın care se stocheaza

valoarea elementului curent.begin optional Valoarea initiala a variabilei var.end optional Valoarea finala a variabilei var.step optional Valoarea pasului de iterare. Implicit este 1.varStatus optional Informatii despre elementul curent.

Variabila varStatus are campurile:

– index valoarea curenta a elementului dupa care se realizeaza ci-clarea;

– count numarul iteratiei curente;

– first are valoarea true daca este primul element al ciclului;

– last are valoarea true daca este ultimul element al ciclului;

Exemplul 10.2.2 Lista parametrilor formularului de apelare a exem-plului anterior se afiseaza prin:

<h2> Lista parametrilor din formular </h2>

<ul>

<c:forEach items="${param}" var="p">

<li>

<c:out value="${p.key}"/> = <c:out value="${p.value}" />

Page 243: programare distribuita

10.2. JSP STANDARD TAG LIBRARY JSTL 243

</li>

</c:forEach>

</ul>

Exemplul 10.2.3 Lista parametrilor unui header se afiseaza prin:

<h2> Lista campurilor din antet </h2>

<ul>

<c:forEach items="${header}" var="h">

<li>

<c:out value="${h.key}"/> = <c:out value="${h.value}"/>

</li>

</c:forEach>

</ul>

Exemplul 10.2.4 Evidentierea fontului cu care se scriu titlurile ıntr-undocument html:

<c:forEach begin="1" end="6" var="i" >

<c:out value="<h${i}> Heading ${i} </h${i}>" escapeXml="false" />

</c:forEach>

• c:forTokens Asigura aceasi functionalitate ca si clasei java.util.StringTokenizer.

Atribute ale marcajului:

Atribut Fel Descriere

value obligatoriu Valoarea ce se evalueaza si se afiseaza.expresiei.

default optional Cea ce se afiseaza ın cazul ın careexpresia nu poate fi evaluata.

escapeXml optional true / false. Valoarea implicita este true.Pe false interpreteaza caracterele din value

ca si cod html.

• c:import Permite includerea altor pagini JSP ın pagina curenta.

Atribute ale marcajului:

Page 244: programare distribuita

244 CAPITOLUL 10. JAVA SERVER PAGE – JSP

Atribut Fel Descriere

url obligatoriu Adresa documentului importat.context optional Context-ul paginii / documentului importat.

Simbolul /, urmat de numele unei aplicatiide pe acelasi server.

var optional Numele variabilei ın care va fi stocatdocumentul importat.

scope optional Domeniul de valabilitate al variabilei var.Unul din valorile:page, request, session, application.

Cu marcajul c:param se pot fixa parametri pentru pagina importata.Acest marcaj are doua atribute name si value. Acesti parametri setransmit cu metoda get.

• c:redirect Redirectarea activitatea catre o alta pagina.

Atribute ale marcajului:

Atribut Fel Descriere

url obligatoriu Adresa paginii catre care se face redirectarea.context optional Context-ul paginii catre care se face redirectarea.

Simbolul /, urmat de numele unei aplicatiide pe acelasi server.

Prin redirectare, parametrii nu sunt retransmisi automat mai departe.

• c:url Retine adrese URL.

Atribute ale marcajului:

Atribut Fel Descriere

value obligatoriu Adresa documentului de retinut.context optional Context-ul documentului.

Simbolul /, urmat de numele unei aplicatiide pe acelasi server.

var optional Numele variabilei ın care va fi stocataadresa documentului.

scope optional Domeniul de valabilitate al variabilei var.Unul din valorile:page, request, session, application.

Page 245: programare distribuita

10.2. JSP STANDARD TAG LIBRARY JSTL 245

10.2.2 Biblioteca de lucru cu baze de date

<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>

Marcaje din biblioteca de baza:

• sql:setDataSource Fixeaza referinta la baza de date.

Atribute ale marcajului:

Atribut Fel Descriere

dataSource optional Referinta la baza de datedriver optional Driver-ul bazei de dateurl optional url-ul bazei de dateusername optional nume utilizatorului bazei de datepassword optional parola de acces la baza de datevar optional variabila cu referinta la baza de datescope optional Domeniul de valabilitate al variabilei var.

• sql:query O interogare a bazei de date.

Atribute ale marcajului:

Atribut Fel Descriere

sql obligatoriu Fraza sqldataSource optional Referinta la baza de datestartRow optional Linia de la care se ıncepe interogareamaxRows optional Numarul maxim de rezultate acceptatevar obligatoriu Variabila cu rezultatele interogarii

bazei de datescope optional Domeniul de valabilitate al variabilei var.

• sql:update Actualizarea bazei de date.

Atribute ale marcajului:

Atribut Fel Descriere

sql obligatoriu Fraza sqldataSource optional Referinta la baza de date

Exemplul 10.2.5 Sa se afiseze lista din agenda de adrese e-mail creata ınexemplul din Cap. Servlet.

Page 246: programare distribuita

246 CAPITOLUL 10. JAVA SERVER PAGE – JSP

1 <HTML>2 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / core ” p r e f i x=”c” %>3 <%@ t a g l i b u r i=” http :// java . sun . com/ j sp / j s t l / s q l ” p r e f i x=” s q l ” %>4 <BODY>5 <p>6 <s q l : setDataSource7 d r i v e r=” org . apache . derby . jdbc . C l i en tDr ive r ”8 u r l=” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail”9 var=”db” />

10 <s q l : query11 dataSource=”${db}”12 var=” r e z u l t ”13 s q l=” s e l e c t ∗ from adrese ” />14 <c : i f t e s t=”${ r e z u l t . rowCount gt 0}” >15 <table>16 <tr>17 <c : forEach items=”${ r e z u l t . columnNames}” var=” c o l ”>18 <th>19 <c : out value=”${ c o l }” />20 </th>21 </c : forEach>22 </ tr>23 <c : forEach items=”${ r e z u l t . rowsByIndex}” var=” l i n e ” >24 <tr>25 <c : forEach items=”${ l i n e }” var=”elem” >26 <td>27 <c : out value=”${elem}” />28 </td>29 </c : forEach>30 </ tr>31 </c : forEach>32 </table>33 </c : i f>34 </BODY>35 </HTML>

10.3 Marcaje JSP personale

Programatorul poate crea marcaje JSP proprii care se grupeaza ın colectiinumite biblioteci de marcaje. O biblioteca de marcaje este reprezentata de oidentificator dat sub forma unui URI (Universal Resource Identifier).

10.3.1 Marcaje fara atribute si fara corp.

Pentru a crea unui asemenea marcaj JSP propriu este necesara definirea apatru componente:

1. O clasa de definitie a comportamentului marcajului JSP (tag handlerclass).

Page 247: programare distribuita

10.3. MARCAJE JSP PERSONALE 247

2. Descriptorul de biblioteca de marcaje JSP, care leaga clasa de definitiea marcajului cu identificatorul bibliotecii de marcaje.

3. Marcajul taglib a fisierului web.xml, care permite serverului Web sagaseasca descriptorul bibliotecii de marcaje.

4. Fisierul JSP ce utilizeaza marcajul JSP (clientul).

Exemplificam acesta tehnologie prin

Exemplul 10.3.1 Sa se realizeze un marcaj dateTag, a carui efect sa fieafisarea datei calendaristice.

1. Clasa de definitie a comportamentului marcajului. Programul constadin:

(a) Importul pachetelor

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

Aceste pachete se gasesc ın fisierul jsp-api.jar.

(b) Un marcaj fara atribute si fara corp trebuie sa extinda clasa TagSupportsi sa suprascrie metoda doStartTag, care defineste activitatea in-treprinsa cand este ıntalnit marcajul ıntr-un document jsp. Metodatrebuie sa returneze constanta SKIP BODY.

public class NumeClasa extends TagSupport{

public int doStartTag(){

. . .

return SKIP_BODY;

}

}

(c) Scrierea ın fluxul de iesire se face cu un obiect JspWriter, care seobtine cu pageContext.getOut(). Metoda print a clasei JspWriterpoate genera o exceptie IOException.

Textul sursa al clasei de definitie a comportamentului marcajului dateTageste:

Page 248: programare distribuita

248 CAPITOLUL 10. JAVA SERVER PAGE – JSP

1 package j sp ;2 import javax . s e r v l e t . j sp . JspWriter ;3 import javax . s e r v l e t . j sp . tagext . TagSupport ;4 import java . i o . IOException ;5 import java . u t i l . Date ;

7 public class DateTag extends TagSupport{8 public int doStartTag ( ){9 try{

10 JspWriter out=pageContext . getOut ( ) ;11 out . p r i n t l n (new Date ( ) ) ;12 }13 catch ( IOException e ){14 System . out . p r i n t l n ( ”DateTagException ”+e . getMessage ( ) ) ;15 }16 return SKIP BODY;17 }18 }

2. Descriptorul de biblioteca de marcaje JSP este dependent de versiuneatomcat folosita. Acest fisier trebuie sa aiba extensia tld (Taglib Lan-guage Definition). Localizarea acestui fisier este definita ın elementultaglib din web.xml. In cazul unei distributii ≥ apache-tomcat-5.*,acest fisier este (mylibtag.tld):

1 <?xml version=” 1 .0 ” encoding=”ISO−8859−1” ?>2 < !DOCTYPE t a g l i b3 PUBLIC ”−//Sun Microsystems , Inc . //DTD JSP Tag Library 1 .2//EN”4 ” h t tp : // java . sun . com/ j 2 e e /dtd/web−j s p t a g l i b r a r y 1 2 . dtd”>

6 < !−− a tag l i b r a r y d e s c r i p t o r −−>7 <t a g l i b>8 <t l i b−version> 1 .0 </ t l i b−version>9 <j sp−version> 1 .2 </ jsp−version>

10 <short−name> mytags </ short−name>11 <u r i>h t t p : // cs . unitbv . ro / mytagl ib</ u r i>12 <d e s c r i p t i o n> L i b r a r i e de marcaje </ d e s c r i p t i o n>

14 <tag>15 <name> dateTag </name>16 <tag−c l a s s> j sp . DateTag </tag−c l a s s>17 <body−content> EMPTY </body−content>18 <d e s c r i p t i o n> f u r n i z e a z a data curenta </ d e s c r i p t i o n>19 </ tag>20 </ t a g l i b>

Elementul uri contine identificatorul bibliotecii de marcaje, cs.unitbv.ro/mytaglib.

Pentru fiecare marcaj propriu se completeaza un marcaj tag. Pentru unmarcaj propriu fara atribute elementele acestui marcaj sunt

(a) name Numele simbolic al marcajului.

Page 249: programare distribuita

10.3. MARCAJE JSP PERSONALE 249

(b) tag-class Referinta la fisierul class al clasei de definitie a compor-tamentului marcajului propriu. Referinta se face relativ la catalogul...\WEB-INF\classes

(c) description Descrierea marcajului propriu.

(d) body-content In cazul nostru are valoarea EMPTY. In cazul unuimarcaj cu corp se da valoarea JSP.

3. Marcajul taglib din fisierul web.xml

<taglib>

<taglib-uri>

http://cs.unitbv.ro/mytaglib

</taglib-uri>

<taglib-location>

/WEB-INF/mylibtag.tld

</taglib-location>

</taglib>

Elementele marcajului taglib sunt:

(a) taglib-uri Identificatorul bibliotecii de marcaje.

(b) taglib-location Locatia fisierului descriptor de biblioteca de mar-caje (numele calificat al fisierului, adica alcatuit din cale plus numelefisierului).

Astfel elementele constitutive se vor gasi ın:

webapps

|--> mytag

| |--> WEB-INF

| | |--> classes

| | | |--> jsp

| | | | |--> DateTag.class

| | | web.xml

| | | mylibtag.tld

| |--> jsp

| | | dateTag.jsp

4. Marcajele proprii se utilizeaza cu sintaxa

<prefix : NumeMarcaj />

Page 250: programare distribuita

250 CAPITOLUL 10. JAVA SERVER PAGE – JSP

Referinta la catalogul cu toate componentele necesare marcajului si pre-fixul se fixeaza ın directiva taglib.

Un fisier jsp care utilizeaza marcajul realizat este (dateTag.jsp):

1 <html>2 <head>3 <t i t l e>4 Tag pentru data c a l e n d a r i s t i c a curenta5 </ t i t l e>6 </head>7 <body>8 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ”9 p r e f i x=”mk” %>

10 <p>11 Data curenta e s t e :12 <mk: dateTag/>13 </body>14 </html>

apelat din

1 <html>2 <body>3 <form method=” get ”4 action=” j sp /dateTag . j sp ”>

6 Data c a l e n d a r i s t i c &#259;:7 <p><input type=”submit” value=” Af i s eaza ”>8 </form>9 </body>

10 </html>

10.3.2 Marcaje cu atribute si fara corp.

Realizam un marcaj ziuaTag cu un atribut ziua care va fi afisat ın momentulprelucrarii marcajului.

1. Pentru fiecare atribut clasa ce defineste actiunea marcajului trebuie sacontina o metoda

public void setNumeAtribut(String value){...}

care preia valoarea atributului data de parametrul value.

Exemplul 10.3.2

Page 251: programare distribuita

10.3. MARCAJE JSP PERSONALE 251

Pentru exemplul enuntat aceasta clasa este

1 package j sp ;2 import javax . s e r v l e t . j sp . JspWriter ;3 import javax . s e r v l e t . j sp . tagext . TagSupport ;4 import java . i o . IOException ;

6 public class ZiuaTag extends TagSupport{7 St r ing z iua ;

9 public void s e tZ iua ( S t r ing value ){10 z iua=value ;11 }

13 public int doStartTag ( ){14 try{15 JspWriter out=pageContext . getOut ( ) ;16 out . p r i n t l n ( z iua ) ;17 }18 catch ( IOException e ){19 System . out . p r i n t l n ( ” ZiuaTagException ”+e . getMessage ( ) ) ;20 }21 return SKIP BODY;22 }23 }

2. In descriptorul bibliotecii de marcaje pentru fiecare atribut se definesteun marcaj <attribute>...< /attribute> avand incluse marcajele

Nume marcaj Semnificatie Fel

name numele atributului obligatoriurequired true | false dupa cum atributul e obligatoriu

obligatoriu sau nurtexprvalue true | false dupa cum atributul optional

se poate utiliza ıntr-o expresie< %= numeAtribut % >

Marcajul <tag> din descriptorul bibliotecii de marcaje devine

<tag>

<name> ziuaTag </name>

<tag-class> jsp.ZiuaTag </tag-class>

<body-content> EMPTY </body-content>

<description> furnizeaza argumentul ziua curenta </description>

<attribute>

<name> ziua </name>

<required> true </required>

<rtexprvalue> true </rtexprvalue>

</attribute>

</tag>

Page 252: programare distribuita

252 CAPITOLUL 10. JAVA SERVER PAGE – JSP

3. Utilizarea acestui marcaj este exemplificat ın

1 <html>2 <body>3 <form method=” get ”4 action=” j sp /ziuaTag . j sp ”>5 <p>Astazi , e s t e6 <select name=” z iua ”>7 <option value=” l u n i ”> Luni8 <option value=” marti ”> Marti9 <option value=” mie r cur i ”> Miercur i

10 <option value=” j o i ”> Jo i11 <option value=” v i n e r i ”> Viner i12 <option value=” simbata ”> Simbata13 <option value=”duminica ”> Duminica14 </ select>15 <p><input type=”submit” value=” Af i s eaza ”>16 </form>17 </body>18 </html>

unde ziuaTag.jsp este

1 <html>2 <head>3 <t i t l e> Tag cu marcaj </ t i t l e>4 </head>5 <body>6 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ”7 p r e f i x=”mk” %>8 <p>9 <%

10 String z i=reques t . getParameter ( ” z iua ” ) ;11 %>12 Ziua e s t e :13 <mk: ziuaTag z iua=”<%= z i %>” />14 </body>15 </html>

10.3.3 Marcaje cu corp.

In metoda doStartTag valoarea returnata trebuie sa fie EVAL BODY INCLUDE,

ın loc de SKIP BODY.

In descriptorul bibliotecii de marcaje apare

<body-content> JSP </body-content>

ın loc de EMPTY.

Daca se doreste ca marcajul sa execute actiuni dupa interpretarea corpului,atunci acele activitati sunt definite ın metoda doEndTag. Aceasta metoda

Page 253: programare distribuita

10.3. MARCAJE JSP PERSONALE 253

returneaza valoarea EVAL PAGE sau SKIP PAGE dupa cum se doreste sau nucontinuarea procesarii paginii jsp.

Exemplul 10.3.3 Fie marcajul modTag care modifica un text ın caracteremari sau mici dupa valoarea atributului trans. Acest marcaj poate include aleelemente.

Codul clasei ce prelucreaza marcajul este

1 package j sp ;2 import javax . s e r v l e t . j sp . JspWriter ;3 import javax . s e r v l e t . j sp . tagext . TagSupport ;4 import java . i o . IOException ;

6 public class ModTag extends TagSupport{7 St r ing text ;8 boolean toUpperCase ;

10 public void setText ( S t r ing value ){11 t ex t=value ;12 }

14 public void setTrans ( S t r ing value ){15 toUpperCase=(new Boolean ( value ) ) . booleanValue ( ) ;16 }

18 public int doStartTag ( ){19 try{20 JspWriter out=pageContext . getOut ( ) ;21 i f ( toUpperCase )22 out . p r i n t l n ( t ex t . toUpperCase ( ) ) ;23 else24 out . p r i n t l n ( t ex t . toLowerCase ( ) ) ;25 }26 catch ( IOException e ){27 System . out . p r i n t l n ( ”ModTagException ”+e . getMessage ( ) ) ;28 }29 return EVAL BODY INCLUDE;30 }31 }

Descriptorul bibliotecii de marcaje se completeaza cu

<tag>

<name> modTag </name>

<tag-class> jsp.ModTag </tag-class>

<body-content> JSP </body-content>

<description> modifica caracterele </description>

<attribute>

<name> text </name>

<required> true </required>

<rtexprvalue> true </rtexprvalue>

</attribute>

<attribute>

Page 254: programare distribuita

254 CAPITOLUL 10. JAVA SERVER PAGE – JSP

<name> trans </name>

<required> true </required>

<rtexprvalue> true </rtexprvalue>

</attribute>

</tag>

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

1 <html>2 <body>3 <form method=” get ”4 action=” j sp /modtextTag . j sp ”>5 Introduce o f r a z &#259;6 <input type=” text ” name=” text ” s ize=”40” >7 <p>8 Se trans form &#259; &#238;n l i t e r e9 <select name=” trans ”>

10 <option value=”upperCase”> mari11 <option value=” lowerCase ”> mici12 </ select>13 <p><input type=”submit” value=” Af i s eaza ”>14 </form>15 </body>16 </html>

ımpreuna cu modtextTag.jsp

1 <html>2 <body>3 <%@ t a g l i b u r i=” http :// cs . unitbv . ro / mytagl ib ” p r e f i x=”mk” %>4 <%5 String text=reques t . getParameter ( ” t ext ” ) ;6 String t rans=reques t . getParameter ( ” t rans ” ) ;7 String t ;8 i f ( t rans . equa l s ( ”upperCase” ) )9 t=” true ” ;

10 e l s e11 t=” f a l s e ” ;12 %>13 <p>14 <mk: modTag text=”<%= text %>” t rans=”<%=t%>”>15 <mk: dateTag/>16 </mk: modTag>17 </body>18 </html>

10.4 Servlet si JSP ın Google App Engine

Prezentam desfasurarea unui servlet ıntr-un produs sau platforma de cloudcomputing.

Dintre produsele de cloud computing disponibile ın prezent amintim:

• Amazon’s Elastic Compute Cloud -(EC2) produs de referinta, dar com-ercial;

Page 255: programare distribuita

10.4. SERVLET SI JSP IN GOOGLE APP ENGINE 255

• Google App Engine (GAE);

• Microsoft Azure;

In cele urmeaza se va utiliza Google App Engine.1

GAE permite:

• ıncarcarea unei aplicatii Web pe un simulator local al platformei de CloudComputing;

• ıncarcarea unei aplicatii Web pe platforma Google de Cloud Computing.

In prezent, pe platforma GAE se pot ıncarca aplicatii realizate ın Java,Python si Go, alaturi de care care pot aparea fisiere http, css, js. Exista cateo distributie distincta pentru fiecare din aceste limbaje de programare.

Prezentam numai ıncarcarea pe simulatorul local al platformei GAE, ınversiunea Java construit peste serverul Web jetty.

Instalarea produsului consta din dezarhivarea fisierului appengine-java-sdk-*.

Utilizarea. In vederea ıncarcarii unui servlet pe simulatorul local se creazastructura de cataloage si fisiere

www

|--> WEB-INF

| |--> classes

| | | *.class

| |--> lib

| | | *.jar

| | web.xml

| | appengine-web.xml

| index.html

Singurul fisier specific GAE este appengine-web.xml. Codul acestui fiser este

1 <appengine−web−app xmlns=” ht t p : // appengine . goog l e . com/ns /1 .0 ”>2 < !−− Replace t h i s with your a p p l i c a t i o n id from3 h t t p : // appengine . g o o g l e . com −−>4 <a p p l i c a t i o n></ a p p l i c a t i o n>

6 <version>1</version>

8 </ appengine−web−app>

Datele fisierului web.xml corespund servlet-ului, iar prin fisierul index.html seapeleaza aplicatia Web. Parametrul action al elementului form are forma sim-plificata action=/numeApel, unde numeApel coincide cu valoarea atributuluiurlPattern.

1O alta alternativa gratuita este emulatorul oferit de Microsoft Azure.

Page 256: programare distribuita

256 CAPITOLUL 10. JAVA SERVER PAGE – JSP

Daca aplicatia se ıncarca pe platforma Google de Cloud Computing atuncitrebuie completat elementul <application>.

Lansarea simulatorului si ıncarcarea se poate face prin comenzile

set GAE\_HOME=. . .\appengine-java-sdk-*

%GAE\_HOME%\bin\dev_appserver www

lansate ıntr-o fereasta DOS, ın catalogul care-l contine pe www. Aplicatiase apeleaza prin http://localhost:8080. Daca ın loc de index.html se uti-lizeaza alt nume, atunci apelarea aplicatiei este http://localhost:8080/fisier.html.

O aplicatie JSP se trateaza asemanator.Distributia GAE pentru Java contine sablonul unei aplicatii ımpreuna cu

un fisier build.xml (appengine-java-sdk-*\demos\new project template)prin intermediul caruia, cu ajutorul lui ant, se construieste catalogul wwwdescris anterior.

Exemplul 10.4.1 Servlet-ul CmmdcServlet instalat ın platforma Google AppEngine de Cloud Computing.

Sablonul se copiaza ın zona de lucru sub numele appcmmdc si se com-pleteaza cu fisierele servlet-ului (CmmdcServlet.java, cmmdc.html) rezultand:

appcmmdc

|--> html

| | cmmdc.html

|--> src

| |--> WEB-INF

| | | appengine-web.xml

| | | web.xml

| | CmmdcServlet.java

| build.xml

Se executa cu ant obiectivul implicit din build.xml, urmat de lansarea simu-latorului din interiorul catalogului appcmmdc. Deoarece numele fisierului htmldifera de index, aplicatia se apeleaza prinhttp://localhost:8080/cmmdc.html.

Alternativ, aplicatia se poate construi cu Eclipse folosind o componenta(plug-in) specifica.

GAE contine ın plus un serviciu de autentificare si autorizare UserService,un sistem de persistenta a datelor Datastore, Task-Queue.

Intrebari recapitulative

1. Care este tipul tehnologiei JSP ?

Page 257: programare distribuita

10.4. SERVLET SI JSP IN GOOGLE APP ENGINE 257

2. Precizati diferenta dintre o pagina JSP si un document JSP.

3. Unde se instaleaza o pagina JSP?

4. Care este rolul unei declaratii JSP ?

5. Care este rolul unei directive JSP ?

6. Cum apeleaza o pagina JSP ?

7. Cum prelucreaza un server Web o pagina / document JSP ?

8. Care sunt trasaturile unei componente Java (bean) ?

9. Care este rolul unui element <jsp:useBean> ?

Page 258: programare distribuita

258 CAPITOLUL 10. JAVA SERVER PAGE – JSP

Page 259: programare distribuita

Capitolul 11

Enterprise Java Beans

In prezent se evidentiaza doua abordari privind realizarea aplicatiilor decomplexitate mai mare (aplicatiilor de ıntreprindere):

• Java Enterprise Edition - JEE este o extensie a interfetei de programare(API ) Java, pentru care exista mai multe implementari. Principalulpromotor este al modelului este Oracle , dar este sustinut si de RedHat- JBoss.;

• Spring a carei dezvoltare tine de firma VMware. Spring este alcatuit dinmai multe cadre de lucru. Acest model de dezvoltare este sustinut deGoogle.

Java Enterprise Edition este un cadru de lucru care ınglobeaza pe o serieimplementari ale interfetelor de programare (JDBC, JMS, JNDI, JSF, RMI-IIOP, JPA, JTA, JAAS, etc), resurse care sunt utilizate prin intermediul uneicomponente Enterprise Java Bean- EJB.

O componenta EJB este o clasa Java - de obicei de tip POJO - care faceparte din aplicatia server, contine metodele care rezolva o problema (businesslogic) si este continut ıntr-un server de aplicatii. Serverul de aplicatii asiguraunei componente EJB o serie de functionalitati, ca injectarea dependintelor,conexiunea cu bazele de date, gestiunea tranzactiilor, etc. Serverul de aplicatiipoate fi interpretat si ca un container de componente EJB.

Se spune ca serverul de aplicatie JEE asigura accesul la contextul ın careruleaza aplicatia, adica la resursele serverului, si la injectarea dependintelor(Context and Dependency Injection -CDI ).

Servere de aplicatii gratuite:

• glassfish - Oracle - parte a produsului glassfish v3.

259

Page 260: programare distribuita

260 CAPITOLUL 11. ENTERPRISE JAVA BEANS

• geronimo - apache, sprijinit de I.B.M.

• JOnAS.

Glassfish, geronimo sunt implementari ale extensiei Java Enterprise Edi-tion - JEE. In acelasi timp, aceste servere Web sunt containere EJB, de servletsi JSP. In cele ce urmeaza vom utiliza glassfish.

Tipuri de componente EJB:

• Session - sesiune EJB.

• Message Driven - preia mesaje de tipul Java Message Service (JMS).Vom folosi prescurtarea MDB - Message Driven Bean.

• Entity

11.1 Session EJB

Starea unui obiect Java este data de valorile campurilor sale. Din punctulde vedere al retinerii starii, exista urmatoarele tipuri de componente sesiuneEJB:

• stateless - fara retinerea starii;

• stateful - cu retinerea starii pe parcursul sesiunii serverului;

• singleton - exista o singura instanta a componentei EJB. Durata de viataa componentei coincide cu intervalul de timp ın care componenta EJBeste activa ın serverul de aplicatii.

Aplicatiile cu componenta EJB constau din:

• componenta EJB - desfasurata ın serverul de aplicatii. Aceasta compo-nenta poate fi totodata si un serviciu Web de tip JAX-WS;

• aplicatie client care poate fi

– client Web - servlet sau client al serviciului Web de tip JAX-WS;

– client RMI-IIOP (Internet Inter ORB Protocol).

Page 261: programare distribuita

11.1. SESSION EJB 261

In terminologia JEE componenta EJB, clientul Web si clientul RMI-IIOPformeaza cate un modul. Componenta EJB si clientul Web formeaza o aplicatieJEE care se instaleaza ın serverul de aplicatii JEE.

Modulele EJB si RMI-IIOP se arhiveaza cu extensia jar iar modulul Webse arhiveaza cu extensia war. Aplicatia JEE se arhiveaza cu extensia ear

-Enterprise ARchive- sau war.Un client RMI-IIOP apeleaza modulul EJB prin intermediul programului

glassfish\bin\appclient.exe

appclient -client modul-iiop.jar [-targetserver host:port] arg1 . . .

Portul implicit este 3700.

11.1.1 Componenta EJB sesiune stateless

Sablonul pentru crearea unei componente EJB de tip stateless session este

import javax.ejb.Stateless;

@Stateless

public class Componenta{

public tip metoda(. . .){. . .}

. . .

}

Exemplul 11.1.1 Cel mai mare divizor comun a doua numere naturale.

Componentei EJB are codul

1 package cmmdc . e jb ;2 import javax . e jb . S t a t e l e s s ;

4 @State l e s s5 public class CmmdcBean{6 public long cmmdc( long m, long n ) { . . .}7 }

Aplicatia client va fi un servlet gazduit de acelasi server de aplicatie. Ac-cesul la componenta EJB se poate programa:

• prin injectare, utilizand adnotari;

• prin JNDI.

In ambele cazuri serverul Web este responsabil de instantierea componenteiEJB.

Page 262: programare distribuita

262 CAPITOLUL 11. ENTERPRISE JAVA BEANS

Injectare cu adnotare

Serverul de aplicatie injecteaza ın servlet o instanta a componentei EJBsau altfel explicat

@EJB @EJB(name="xyz")

Type var; Type var;

injecteaza (realizeaza o referinta) pentru var catre un obiect de tipul Typespecificat. Actiunea este declansata de adnotarea EJB.

Codul servlet-ului este

1 package cmmdc . web ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import cmmdc . e jb . CmmdcBean ;6 import javax . e jb .EJB ;7 import javax . s e r v l e t . annotat ion . WebServlet ;

9 @WebServlet ( u r lPa t t e rn s = ”/cmmdc” )10 public class CmmdcServlet extends HttpServ l e t {11 @EJB12 CmmdcBean cb ;

14 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )15 throws Serv le tExcept ion , IOException{16 St r ing sm=req . getParameter ( ”m” ) , sn=req . getParameter ( ”n” ) ;17 long m=Long . parseLong (sm) , n=Long . parseLong ( sn ) ;18 long x=cb . cmmdc(m, n ) ;19 PrintWriter out=r e s . getWriter ( ) ;

21 St r ing t i t l e=”Cmmdc S e r v l e t ” ;22 r e s . setContentType ( ” text /html” ) ;23 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;24 out . p r i n t l n ( t i t l e ) ;25 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;26 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;27 out . p r i n t l n ( ”<P>Cmmdc : ”+x ) ;28 out . p r i n t l n ( ”</BODY></HTML>” ) ;

30 out . c l o s e ( ) ;31 }

33 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )34 throws Serv le tExcept ion , IOException{35 doGet ( req , r e s ) ;36 }37 }

Desfasurarea aplicatiei

ejbcmmdc

|--> WEB-INF

| |--> classes

| | |--> cmmdc

| | | |--> ejb

| | | | | CmmdcBean.class

| | | |--> web

Page 263: programare distribuita

11.1. SESSION EJB 263

| | | | | CmmdcServlet.class

| index.html

Aceasta structura se arhiveaza cu jar, dar cu extensia war.

Acces la componenta EJB prin JNDI

Referinta JNDI are structura

prefix/[nume app][/nume modul ]/nume EJB

unde prefix poate fi

Prefix Vizibilitatea rezultatului

java:global Componenta se poate utiliza de oriunde.Coincide cu numele arhivei ear.

java:app Componenta se poate utiliza ın aplicatieCoincide cu numele arhivei jar sau war.

java:module Componental se poate utiliza ın modul

In cazul exemplului codul servlet-ului va fi

1 package cmmdc . web ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import cmmdc . e jb . CmmdcBean ;6 import javax . naming . Context ;7 import javax . naming . I n i t i a l C o n t e x t ;8 import javax . s e r v l e t . annotat ion . WebServlet ;

10 @WebServlet ( u r lPa t t e rn s = ”/cmmdc” )11 public class CmmdcServlet extends HttpServ l e t {12 CmmdcBean cb ;

14 public void i n i t ( Se rv l e tCon f i g c o n f i g ) throws Serv l e tExcept ion {15 super . i n i t ( c o n f i g ) ;16 Context ctx=null ;17 try{18 ctx=new I n i t i a l C o n t e x t ( ) ;19 cb=(CmmdcBean) ctx . lookup ( ” java : module/CmmdcBean” ) ;20 }21 catch ( Exception e ){22 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;23 }24 }

26 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )27 throws Serv le tExcept ion , IOException { . . . }

29 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )30 throws Serv le tExcept ion , IOException { . . .}31 }32 }

Page 264: programare distribuita

264 CAPITOLUL 11. ENTERPRISE JAVA BEANS

11.1.2 Aplicatie JEE cu module EJB, Web si client RMI-IIOP

Modificam arhitectura aplicatiei anterioare definind

• un modul EJB pentru componta EJB.

modul-ejb

|--> numePachet

| | *.class

• un modul Web, a carei arhiva va avea extensia war.

modul-Web

|--> WEB-INF

| |--> classes

| | | *.class

| index.html

Desfasurarea aplicatiei va fi

|--> META-INF

| | application.xml

| modul-ejb.jar

| modul-Web.war

Instalarea aplicatie, adica a ansamblului alcatuit din cele 2 module se face prinintermediul administratorului.

Fisierul application.xml precizeaza structura aplicatiei

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

<application version="5" xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/application_5.xsd">

<display-name>nume-aplicatie</display-name>

<module>

<ejb>modul-ejb.jar</ejb>

</module>

<module>

<web>

<web-uri>modul-web.war</web-uri>

<context-root>/context</context-root>

</web>

</module>

</application>

Aceasta organizare necesita modificarea componentei EJB din sectiunea11.1.1 ın sensul definirii unei interfete cu adnotarea Remote. ComponentaEJB implementeaza interfata si ın plus, daca interfata are numele Xyz atuncicomponenta EJB va avea numele XyzBean.

Pentru exemplul discutat codurile sunt:

Page 265: programare distribuita

11.1. SESSION EJB 265

1 package cmmdc . e jb ;2 import javax . e jb . Remote ;

4 @Remote5 public interface Cmmdc{6 public long cmmdc( long m, long n ) ;7 }

si

1 package cmmdc . e jb ;2 import javax . e jb . S t a t e l e s s ;

4 @State l e s s5 public class CmmdcBean implements Cmmdc{6 public long cmmdc( long m, long n ) { . . .}7 }

Modulul / clientul Web este cel prezentat anterior ın sectiunea 11.1.1, cudiferenta ca referinta la componenta EJB se face prin interfata.

In cazul exemplului tratat, desfasurarea clientului RMI-IIOP va fi

cmmdc-iiop

|--> cmmdc

| |--> client

| | | CmmdcClient.class

| |--> ejb

| | | Cmmdc.class

Codul clientului prin injectare este

1 package cmmdc . c l i e n t ;2 import javax . e jb .EJB ;3 import cmmdc . e jb .Cmmdc;4 import java . u t i l . Scanner ;

6 public class CmmdcClient{7 @EJB8 private stat ic Cmmdc cb ;

10 public stat ic void main ( St r ing [ ] a rgs )throws Exception {11 Scanner scanner=new Scanner ( System . in ) ;12 System . out . p r i n t l n ( ”m=” ) ;13 long m=scanner . nextLong ( ) ;14 System . out . p r i n t l n ( ”n=” ) ;15 long n=scanner . nextLong ( ) ;16 long x=cb . cmmdc(m, n ) ;17 System . out . p r i n t l n ( ”Cmmdc : ”+x ) ;18 }19 }

Daca se utilizeaza referinta prin JNDI atunci adresarea componentei EJBva fi:

java:global/cmmdc-ear/cmmdc-ejb/CmmdcBeanDaca dist este catalogul cu arhiva clientului atunci apelarea acestuia este

Page 266: programare distribuita

266 CAPITOLUL 11. ENTERPRISE JAVA BEANS

set GLASSFISH_HOME=. . .\glassfish3

%GLASSFISH_HOME%\glassfish\bin\appclient -client

dist\cmmdc-iiop.jar -targetserver localhost:3700

Apelarea modulului Web se face ın mod obisnuit, prin:http://host:8080/context

unde context a fost definit ın fisierul application.xml.

11.1.3 Componenta EJB sesiune singleton

Serverul de aplicatie creaza o singura instantiaza a componentei EJB careeste utilizata de toti clientii. Diferenta consta ın utilizarea adnotarii @Singletonın loc de @Stateless.

Utilizam modelul din sectiunea 11.1.2. Consideram doar varianta bazatape adnotari.

Exemplul 11.1.2 Numararea solicitarilor de utilizare a componentei EJB.

Codul componentei EJB singleton

1 package s i n g l e . e jb ;2 import javax . e jb . Remote ;

4 @Remote5 public interface S i n g l e {6 public int getIndex ( ) ;7 }

1 package s i n g l e . e jb ;2 import javax . e jb . S ing l e ton ;

4 @Singleton5 public class SingleBean implements S i n g l e {6 private int index =0;7 public int getIndex ( ){8 return ++index ;9 }

10 }

Servlet-ul aplicatiei client are codul

1 package s i n g l e . web ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import s i n g l e . e jb . S i n g l e ;6 import javax . e jb .EJB ;7 import javax . s e r v l e t . annotat ion . WebServlet ;

9 @WebServlet ( u r lPa t t e rn s = ”/ s i n g l e ” )10 public class S i n g l e S e r v l e t extends HttpServ l e t {11 @EJB

Page 267: programare distribuita

11.1. SESSION EJB 267

12 S i n g l e sb ;

14 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )15 throws Serv le tExcept ion , IOException{16 int x=sb . getIndex ( ) ;17 PrintWriter out=r e s . getWriter ( ) ;18 r e s . setContentType ( ” text /html” ) ;19 St r ing t i t l e=” S i n g l e S e r v l e t ” ;20 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;21 out . p r i n t l n ( t i t l e ) ;22 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;23 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;24 out . p r i n t l n ( ”<p>Valoarea index : ”+x ) ;25 out . p r i n t l n ( ”</BODY></HTML>” ) ;26 out . c l o s e ( ) ;27 }

29 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )30 throws Serv le tExcept ion , IOException{31 doGet ( req , r e s ) ;32 }33 }

Apelarea servlet-ului se face din fisierul index.html

1 <html>2 <body bgcolor=”#ccbbcc ”>3 <center>4 <h1> EJB S i n g l e S e r v l e t </h1>5 <form method=” get ”6 action=” http :// l o c a l h o s t :8080/ e j b s i n g l e / s i n g l e ”>7 <p><input type=”submit” value=” Apeleaza ”>8 </form>9 </center>

10 </body>11 </html

Aplicatia client are codul

1 package s i n g l e . c l i e n t ;2 import javax . e jb .EJB ;3 import s i n g l e . e jb . S i n g l e ;4 import java . u t i l . Scanner ;

6 public class S i n g l e C l i e n t {7 @EJB8 private stat ic S i n g l e nb ;

10 public stat ic void main ( St r ing [ ] a rgs )throws Exception {11 Scanner scanner=new Scanner ( System . in ) ;12 St r ing ch=”Y” ;13 int index =0;

15 while ( ch . equa l s ( ”Y” ) ){16 index=nb . getIndex ( ) ;17 System . out . p r i n t l n ( ”Numarul de a p e l a r i : ”+index ) ;18 System . out . p r i n t l n ( ” Cont inuat i ? (Y/N) ” ) ;19 do{20 ch=scanner . next ( ) . tr im ( ) . toUpperCase ( ) ;

Page 268: programare distribuita

268 CAPITOLUL 11. ENTERPRISE JAVA BEANS

21 }22 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;23 }24 }25 }

11.1.4 Componenta EJB sesiune stateful

Diferenta formala fata de modelele Stateless si Singleton consta ın utilizareaadnotarii @Stateful.

Consideram un exemplu ce deriva din cel precedent.

Exemplul 11.1.3 Numararea solicitarilor de utilizare a componentei EJB.

Componenta EJB are interfata

1 package numara . e jb ;2 import javax . e jb . Remote ;

4 @Remote5 public interface Numara{6 public int getIndex ( ) ;7 public void remove ( ) ;8 }

si implementarea

1 package numara . e jb ;2 import javax . e jb . S t a t e f u l ;3 import javax . e jb . Remove ;

5 @State fu l6 public class NumaraBean implements Numara{7 private int index =0;8 public int getIndex ( ){9 return ++index ;

10 }

12 @Remove13 public void remove ( ) {}14 }

Metoda cu adnotarea Remove are ca efect stergerea instantei componentei EJBdin serverul de aplicatii. Din acest motiv, apelarea acestei metode ıntr-unmodul Web, are ca efect compromiterea servlet-ului.

Injectarea componentei EJB are loc ın momentul activarii servlet-ului. Ast-fel fiecare client Web va utiliza aceasi componenta EJB.

Modulul IIOP este mult mai util. La fiecare apelare a modulului IIOPare loc injectarea unei componente EJB. Serverul de aplicatii pastreaza stareacomponentei pe durata de utilizare a modulului IIOP.

Codul modulului Web

Page 269: programare distribuita

11.1. SESSION EJB 269

1 package numara . web ;2 import java . i o . ∗ ;3 import javax . s e r v l e t . ∗ ;4 import javax . s e r v l e t . http . ∗ ;5 import numara . e jb . Numara ;6 import javax . e jb .EJB ;

8 public class NumaraServlet extends HttpServ l e t {9 @EJB

10 Numara nb ;

12 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )13 throws Serv le tExcept ion , IOException{14 St r ing oper=req . getParameter ( ” oper ” ) ;15 PrintWriter out=r e s . getWriter ( ) ;16 r e s . setContentType ( ” text /html” ) ;17 St r ing t i t l e=”Numara S e r v l e t ” ;18 out . p r i n t l n ( ”<HTML><HEAD><TITLE>” ) ;19 out . p r i n t l n ( t i t l e ) ;20 out . p r i n t l n ( ”</TITLE></HEAD><BODY>” ) ;21 out . p r i n t l n ( ”<H1>”+t i t l e+”</H1>” ) ;22 switch ( oper ){23 case ” index ” :24 int x=nb . getIndex ( ) ;25 out . p r i n t l n ( ”<p>Valoarea index : ”+x ) ;26 break ;27 case ” e x i t ” :28 out . p r i n t l n ( ”<p>OK: Pe raspunderea d−voast ra ” ) ;29 nb . remove ( ) ;30 break ;31 }32 out . p r i n t l n ( ”</BODY></HTML>” ) ;33 out . c l o s e ( ) ;34 }

36 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )37 throws Serv le tExcept ion , IOException{38 doGet ( req , r e s ) ;39 }40 }

apelat din

1 <html>2 <body bgcolor=”#ccbbcc ”>3 <center>4 <h1> EJB Numar&#259; S e r v l e t </h1>5 <form method=” get ”6 action=” http :// l o c a l h o s t :8080/ ejbnumara/numara”>7 <table>8 <tr>9 <td>S e l e c t a &#355; i opera&#355; i a</td>

10 <td>11 <select name=” oper ”>12 <option value=” index ”> Num&#259; r de ape l &#259; r i13 <option value=” e x i t ”> Sterge componenta EJB14 </ select>15 </td>16 </ tr>

Page 270: programare distribuita

270 CAPITOLUL 11. ENTERPRISE JAVA BEANS

17 <tr>18 <td> <input type=”submit” value=” Apeleaza ”></td>19 <td/>20 </ tr>21 </table>22 </form>23 </center>24 </body>25 </html>

Codul modulului IIOP

1 package numara . c l i e n t ;2 import javax . e jb .EJB ;3 import numara . e jb . Numara ;4 import java . u t i l . Scanner ;

6 public class NumaraClient{7 @EJB8 private stat ic Numara nb ;

10 public stat ic void main ( St r ing [ ] a rgs )throws Exception {11 Scanner scanner=new Scanner ( System . in ) ;12 St r ing ch=”Y” ,msg=”” ;13 int op , index =0;

15 while ( ch . equa l s ( ”Y” ) ){16 System . out . p r i n t l n ( ” Opera t i i : 1 . Numara 2 . Ste rge componenta EJB” ) ;17 System . out . p r i n t l n ( ” Operat ia : ” ) ;18 op=scanner . next Int ( ) ;19 switch ( op ){20 case 1 :21 index=nb . getIndex ( ) ;22 msg=”Numarul de a p e l a r i : ”+(new I n t e g e r ( index ) ) . t oS t r i ng ( ) ;23 break ;24 case 2 :25 nb . remove ( ) ;26 msg=”S−a s t e r s componenta EJB” ;27 break ;28 default :29 msg=”Cod o p e r a t i e eronat ” ;30 break ;31 }32 System . out . p r i n t l n (msg ) ;

34 System . out . p r i n t l n ( ” Cont inuat i ? (Y/N) ” ) ;35 do{36 ch=scanner . next ( ) . tr im ( ) . toUpperCase ( ) ;37 }38 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;39 }40 }41 }

Ruland modulele IIOP ale aplicatiilor corespunzatoare adnotarilor Statefulsi Singleton observati diferenta rezultatelor furnizate.

Page 271: programare distribuita

11.1. SESSION EJB 271

11.1.5 Componenta EJB MessageDriven

O componenta EJB MessageDriven (MDB) preia mesaje care sunt trimisecatre un obiect destinatie predefinit de tip Queue sau Topic. ComponentaEJB este adnotata cu

@MessageDriven(mappedName=nume Destinatie)

Prelucrarea mesajelor primite se programeaza ın metoda onMessage a interfeteiMessageListener.

Afisarea unor mesaje se obtine prin intermediul unei jurnalizari java.util.logging.Logger. Textele apar ın fisierul server.log aflat ın catalogul logal domeniului.

Obiectele administrator - fabrica de conexiuni, obiectul destinatie - secreaza ınaintea desfasurarii componentei EJB.

Crearea obiectelor administrator

Dintr-un navigator, apeland http://localhost:4848 se acceseaza administratorul grafic (web). DinResources | JMS Resources se vor crea obiectele

1. Destination Resources

• myQueue

JNDI Name : myQueue

Physical Destination Name : javax.jms.Queue

• myTopic

JNDI Name : myTopic

Physical Destination Name : javax.jms.Topic

2. Connection Factories

• myQueueConnectionFactory

Pool Name : myQueueConnectionFactory

Resource Type : javax.jms.QueueConnectionFactory

• myTopicConnectionFactory

Pool Name : myTopicConnectionFactory

Resource Type : javax.jms.TopicConnectionFactory

Exemplul 11.1.4 O aplicatie client trimite un numar de mesaje catre o com-ponenta MDB.

Codul componentei EJB

Page 272: programare distribuita

272 CAPITOLUL 11. ENTERPRISE JAVA BEANS

1 package mdb;2 import javax . e jb . MessageDriven ;3 import javax . jms . Message ;4 import javax . jms . TextMessage ;5 import javax . jms . MessageListener ;6 import java . u t i l . l o gg ing . Logger ;

8 @MessageDriven (mappedName=”myQueue” )9 public class MessageBean implements MessageListener {

10 private stat ic f ina l Logger l o g g e r =11 Logger . getLogger ( MessageBean . class . getName ( ) ) ;

13 public void onMessage ( Message msg) {14 TextMessage txtMsg = null ;15 try {16 i f (msg instanceof TextMessage ){17 txtMsg = ( TextMessage ) msg ;18 l o g g e r . i n f o ( ”MESSAGE BEAN: ” + txtMsg . getText ( ) ) ;19 System . out . p r i n t l n ( txtMsg . getText ( ) ) ;20 }21 }22 catch ( Throwable th ) {23 th . pr intStackTrace ( ) ;24 }25 }26 }

Desfasurarea componentei MDB va fi

simple-mdb

|--> META-INF

| | application.xml

| simple-mdb.jar

Fisierul simple-mdb.jar nu contine decat clasa mdb.MessageBean, reprodusamai sus.

Codul clientului cu regasirea obiectilor prin adnotare

1 package mdb;2 import javax . jms . QueueConnection ;3 import javax . jms . QueueConnectionFactory ;4 import javax . jms . Des t inat i on ;5 import javax . jms . QueueSession ;6 import javax . jms . MessageProducer ;7 import javax . jms . Message ;8 import javax . jms . TextMessage ;9 import javax . annotat ion . Resource ;

11 public class MessageCl ient {12 @Resource ( lookup=”myQueueConnectionFactory” )13 private stat ic QueueConnectionFactory c f ;14 @Resource ( lookup=”myQueue” )15 private stat ic Dest inat i on q ;

17 public stat ic void main ( St r ing [ ] a rgs ){18 try {19 QueueConnection conn = c f . createQueueConnection ( ) ;20 QueueSession s e s s i o n =

Page 273: programare distribuita

11.1. SESSION EJB 273

21 conn . createQueueSess ion ( false , QueueSession .AUTOACKNOWLEDGE) ;22 MessageProducer sender = s e s s i o n . c reateProducer ( q ) ;23 TextMessage msg = s e s s i o n . createTextMessage ( ) ;24 for ( int i = 0 ; i < 5 ; i++) {25 msg . setText ( ”Mesaj t r i m i s ” + ( i + 1 ) ) ;26 sender . send (msg ) ;27 }

29 System . out . p r i n t l n ( ” Sender has f i n i s h e d ” ) ;30 s e s s i o n . c l o s e ( ) ;31 System . e x i t ( 0 ) ;32 }33 catch ( Exception e ) {34 e . pr intStackTrace ( ) ;35 }36 }37 }

si prin JNDI

1 package mdb;2 import javax . jms . QueueConnection ;3 import javax . jms . QueueConnectionFactory ;4 import javax . jms . Des t inat i on ;5 import javax . jms . QueueSession ;6 import javax . jms . MessageProducer ;7 import javax . jms . Message ;8 import javax . jms . TextMessage ;9 import javax . naming . Context ;

10 import javax . naming . I n i t i a l C o n t e x t ;

12 public class MessageCl ient {13 private stat ic QueueConnectionFactory c f ;14 private stat ic Dest inat i on q ;

16 public stat ic void main ( St r ing [ ] a rgs ){17 Context ctx=null ;18 try{19 ctx=new I n i t i a l C o n t e x t ( ) ;20 c f =(QueueConnectionFactory ) ctx . lookup ( ”myQueueConnectionFactory” ) ;21 q=( Des t inat i on ) ctx . lookup ( ”myQueue” ) ;22 }23 catch ( Exception e ){24 System . out . p r i n t l n ( ” Eroare : ”+e . getMessage ( ) ) ;25 System . e x i t ( 1 ) ;26 }27 try {28 QueueConnection conn = c f . createQueueConnection ( ) ;29 QueueSession s e s s i o n = conn . createQueueSess ion ( false ,30 QueueSession .AUTOACKNOWLEDGE) ;31 MessageProducer sender = s e s s i o n . c reateProducer ( q ) ;32 TextMessage msg = s e s s i o n . createTextMessage ( ) ;33 for ( int i = 0 ; i < 5 ; i++) {34 msg . setText ( ”Mesaj t r i m i s ” + ( i + 1 ) ) ;35 sender . send (msg ) ;36 }

38 System . out . p r i n t l n ( ” Sender has f i n i s h e d ” ) ;39 s e s s i o n . c l o s e ( ) ;40 System . e x i t ( 0 ) ;

Page 274: programare distribuita

274 CAPITOLUL 11. ENTERPRISE JAVA BEANS

41 }42 catch ( Exception e ) {43 e . pr intStackTrace ( ) ;44 }45 }46 }

Clientul se executa prin intermediul lui appclient.

11.1.6 Componenta EJB Entity

O componenta de tip entity simplifica accesul la o baza de date ıntr-oaplicatie JEE.

Crearea bazei de dateGlassfish contine SGBD JavaDB (derby). Vom lansa serverul glassfish si prin intermediul utilitarului

ij vom crea baza de date AgendaEMail. Crearea se face ın modul descris ın anexa dedicata utilizarii uneiSGBD ıntr-un program Java.

Definirea elementelor de conexiune dintre glassfish si baza de dateDintr-un navigator, apeland http://localhost:4848 se acceseaza administratorul grafic (web). Din

Resources | JDBC se vor crea

1. JDBC Connection Pool

cuva de conexiuni la baza de date;

2. JDBC Resources

legatura dintre numele JNDI asociat bazei de date cu cuva de conexiuni creata anterior.

JDBC Connection Pool

1. Pool Name adresePool un nume simbolic atasat cuvei

2. Resource Type Se selecteaza java.sql.Driver

3. Database Driver Vendor Se selecteaza Derby

4. Introspect Se bifeaza Enabled

5. Next

6. Driver Classname Se selecteaza org.apache.derby.jdbc.ClientDriver

7. Additional Properties Se bifeaza URL si se completeaza coloana Value cujdbc:derby:\. . . calea catre locatia bazei de date. . .\AgendaEMail

8. Finish

JDBC Resources

1. JNDI Name jdbc/Adrese un nume simbolic atasat resursei

2. Pool Name Se selecteaza adresePool, numele cuvei de conexiuni

3. OK

Page 275: programare distribuita

11.1. SESSION EJB 275

Aplicatie cu componenta Entity

O componenta Entity va fi adnotata @Entity si corespunde unui tabel albazei de date relationale.

Exemplul 11.1.5 Aplicatie de consultarea a bazei de date AgendaEMail.

Desfasurarea aplicatiei este

agendae-ear

|--> META-INF

| | persistence.xml

| agenda-ejb.jar

unde agenda-ejb.jar are structura

|--> ejb

| | AgendaEMail.class

| | AgendaEMailBean.class

|--> entity

| | Adrese.class

|--> META-INF

| | persistence.xml

Clasa Adrese.java este componenta Entity si corespunde tabelei adrese.

1 package e n t i t y ;2 import java . i o . S e r i a l i z a b l e ;3 import javax . p e r s i s t e n c e . Entity ;4 import javax . p e r s i s t e n c e . Id ;5 import javax . p e r s i s t e n c e . GeneratedValue ;6 import javax . p e r s i s t e n c e . GenerationType ;7 import java . i o . S e r i a l i z a b l e ;

9 @Entity10 public class Adrese implements S e r i a l i z a b l e {11 @Id12 @GeneratedValue ( s t r a t e g y=GenerationType . IDENTITY)13 private int id ;14 private St r ing nume ;15 private St r ing emai l ;

17 public St r ing getNume ( ) {18 return nume ;19 }20 public void setNume ( St r ing nume) {21 this . nume = nume ;22 }23 public St r ing getEmail ( ) {24 return emai l ;25 }26 public void setEmai l ( S t r ing emai l ) {27 this . emai l = emai l ;28 }29 public int get Id ( ) {30 return id ;31 }

Page 276: programare distribuita

276 CAPITOLUL 11. ENTERPRISE JAVA BEANS

32 public void s e t I d ( int id ) {33 this . id = id ;34 }35 }

Accesul la baza de date se realizeaza printr-o componenta EJB Sessionstateless Codul interfetei AgendaEMail.java este

1 package e jb ;2 import javax . e jb . Remote ;3 import e n t i t y . Adrese ;4 import java . u t i l . L i s t ;

6 @Remote7 public interface AgendaEMail{8 public List<Adrese> getEmail ( S t r ing nume ) ;9 public List<Adrese> getNume ( St r ing emai l ) ;

10 }

implementat de clasa AgendaEMailBean.java

1 package e jb ;2 import javax . e jb . S t a t e l e s s ;3 import javax . p e r s i s t e n c e . Per s i s t enceContext ;4 import javax . p e r s i s t e n c e . EntityManager ;5 import javax . p e r s i s t e n c e . Query ;6 import e n t i t y . Adrese ;7 import java . u t i l . L i s t ;

9 @State l e s s10 public class AgendaEMailBean implements AgendaEMail{11 @Pers istenceContext ( unitName=” a g e n d a e p e r s i s t e n c e c t x ” )12 EntityManager em;

14 public List<Adrese> getEmail ( S t r ing nume){15 St r ing nm=” \ ’ ”+nume+” \ ’ ” ;16 St r ing s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . nume=”+nm;17 System . out . p r i n t l n ( s q l ) ;18 Query query=em. createQuery ( s q l ) ;19 List<Adrese> l i s t =(Lis t<Adrese>)query . g e t R e s u l t L i s t ( ) ;20 return l i s t ;21 }

23 public List<Adrese> getNume ( St r ing emai l ){24 St r ing eml=” \ ’ ”+emai l+” \ ’ ” ;25 St r ing s q l=”SELECT e n t i t y FROM Adrese e n t i t y WHERE e n t i t y . emai l=”+eml ;26 System . out . p r i n t l n ( s q l ) ;27 Query query=em. createQuery ( s q l ) ;28 List<Adrese> l i s t =(Lis t<Adrese>)query . g e t R e s u l t L i s t ( ) ;29 return l i s t ;30 }31 }

Fisierul de configurare persistence.xml este

1 <p e r s i s t e n c e xmlns=” ht tp : // java . sun . com/xml/ns/ p e r s i s t e n c e ” version=” 1 .0 ”>2 <p e r s i s t e n c e−uni t name=” a g e n d a e p e r s i s t e n c e c t x ”>3 <j ta−data−source>jdbc / Adrese</ j ta−data−source>4 <p r o p e r t i e s>

Page 277: programare distribuita

11.1. SESSION EJB 277

5 < !−−Use the java2db f e a t u r e −−>6 <property name=” t o p l i n k . ddl−gene ra t i on ” value=”none”/>7 < !−− Generate the s q l s p e c i f i c to Derby database −−>8 <property name=” t o p l i n k . jdbc . d r i v e r ”9 value=” org . apache . derby . jdbc . C l i en tDr ive r ”/>

10 </ p r o p e r t i e s>11 </ p e r s i s t e n c e−uni t>12 </ p e r s i s t e n c e>

Se observa urmatoarele corelatii

• Valoarea agendae persistence ctx atributului name a elementului persistence-unit este utilizat ın clasa AgendaEMailBean ın adnotarea@PersistenceContext

• Elementul jta-data-surse contine numele JNDI a bazei de date definitın glassfish.

Aplicatia client

Desfasurarea aplicatiei client este

agendae-client

|--> ejb

| | AgendaEMail.class

|--> entity

| | Adrese.class

|--> META-INF

| | MANIFEST.MF

| Client.class

Fisierul MANIFEST.MF este completat cu

Main-Class: Client

Class-Path: agendae-ejb.jar

Clasa Client.java are codul

1 import e jb . AgendaEMail ;2 import javax . e jb .EJB ;3 import java . u t i l . L i s t ;4 import java . u t i l . I t e r a t o r ;5 import java . u t i l . Scanner ;6 import java . u t i l . InputMismatchException ;7 import e n t i t y . Adrese ;

9 public class Cl i en t {10 @EJB11 private stat ic AgendaEMail bean ;12 private stat ic List<Adrese> l i s t=null ;

14 public stat ic void main ( St r ing [ ] a rgs ) {15 int pre l , no ;16 St r ing ch=”Y” ,nume=”” , emai l=”” ;17 Scanner scanner=new Scanner ( System . in ) ;

Page 278: programare distribuita

278 CAPITOLUL 11. ENTERPRISE JAVA BEANS

18 I t e r a t o r <Adrese> i t e r=null ;19 Adrese i n r e g=null ;

21 try {22 while ( ch . s tartsWith ( ”Y” ) ){23 do{24 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;25 ch=scanner . next ( ) . toUpperCase ( ) ;26 }27 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;28 i f ( ch . s tartsWith ( ”Y” ) ){29 System . out . p r i n t l n ( ”Natura i n t e r o g a r i i ?” ) ;30 System . out . p r i n t l n ( ” (Dupa nume : 1 , Dupa emai l : 2 ) ” ) ;31 do{32 p r e l =0;33 try{34 p r e l=scanner . next Int ( ) ;35 }36 catch ( InputMismatchException e ){}37 }38 while ( ( pre l <1)&&(pre l >2)) ;39 switch ( p r e l ){40 case 1 :41 System . out . p r i n t l n ( ”Numele” ) ;42 nume=scanner . next ( ) . tr im ( ) ;43 l i s t=bean . getEmail (nume ) ;44 i t e r=l i s t . i t e r a t o r ( ) ;45 System . out . p r i n t l n ( ” Adrese l e de emai l pentru : ”+nume ) ;46 while ( i t e r . hasNext ( ) ){47 i n r e g =(Adrese ) i t e r . next ( ) ;48 System . out . p r i n t l n ( i n r eg . getEmail ( ) ) ;49 }50 break ;51 case 2 :52 System . out . p r i n t l n ( ”Email” ) ;53 emai l=scanner . next ( ) . tr im ( ) ;54 l i s t=bean . getNume ( emai l ) ;55 i t e r=l i s t . i t e r a t o r ( ) ;56 System . out . p r i n t l n ( ” I n r e g i s t r a r i l e pentru adresa : ”+emai l ) ;57 while ( i t e r . hasNext ( ) ){58 i n r e g =(Adrese ) i t e r . next ( ) ;59 System . out . p r i n t l n ( i n r eg . getNume ( ) ) ;60 }61 break ;62 default : System . out . p r i n t l n ( ”Comanda eronata ” ) ;63 }64 }65 }66 }67 catch ( Exception e ) {68 e . pr intStackTrace ( ) ;69 }70 }71 }

Page 279: programare distribuita

Capitolul 12

Java Web Start

12.1 Java Web Start

O aplicatie Java destinata a fi utilizata pe un calculator poate fi valorificatasi ıntr-o retea, pe baza protocolului Java Network Launching Protocol - JNLP.Tehnologia poarta numele de Java Web Start.

Aplicatia Java trebuie sa satisfaca o serie de restrictii:

• Aplicatia trebuie arhivata cu jar;

• Arhiva jar trebuie certificata. Certificarea se realizeaza cu utilitarelekeytool.exe si jarsigner.exe din distributia jdk;

• Eventualele date necesare aplicatiei se introduc prin intermediul uneiinterfete grafice (JavaFX, swing, SWT, apache-pivot);

• Acces limitat la proprietatile si resursele sistemului client.

Aplicatiei i se ataseaza un fisier xml, dar cu extensia jnlp, care se va apeladintr-un navigator. Pentru acest fisier folosim terminologia de fisier jnlp.

Fisierul jnlp fixeaza:

• referinta URL a aplicatie (prin atributul codebase);

• arhivele jar utilizate (prin atributul href);

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

Ansamblul de resurse formeaza o aplicatie Web care poate fi desfasurataıntr-un server Web (container de servlet) sau poate fi incorporat ıntr-un servlet.

Aratam activitatile care trebuie ıntreprinse ın cazul unui exemplu simpludat de clasa VisualCmmdc.java.

279

Page 280: programare distribuita

280 CAPITOLUL 12. JAVA WEB START

1 public class VisualCmmdc extends javax . swing . JFrame {2 public VisualCmmdc ( ){3 initComponents ( ) ;4 }

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

8 private void initComponents ( ) {9 // cod generat de Netbeans

10 }

12 private void cmmdcButtonMouseClicked ( java . awt . event . MouseEvent evt ){13 try{14 St r ing sm=mTextField . getText ( ) ;15 St r ing sn=nTextField . getText ( ) ;16 long m=Long . parseLong (sm ) ;17 long n=Long . parseLong ( sn ) ;18 long c=cmmdc(m, n ) ;19 St r ing s=(new Long ( c ) ) . t oS t r i ng ( ) ;20 cmmdcTextField . setText ( s ) ;21 }22 catch ( Exception e ){23 System . e r r . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;24 }25 }

27 private void exitForm ( java . awt . event . WindowEvent evt ){28 System . e x i t ( 0 ) ;29 }

31 public stat ic void main ( St r ing args [ ] ) {32 new VisualCmmdc ( ) . s e t V i s i b l e ( true ) ;33 }

35 private javax . swing . JButton cmmdcButton ;36 private javax . swing . JLabel mLabel ;37 private javax . swing . JLabel nLabel ;38 private javax . swing . JTextFie ld mTextField ;39 private javax . swing . JTextFie ld nTextField ;40 private javax . swing . JTextFie ld cmmdcTextField ;41 }

Interfata grafica a programului este ilustrata ın Fig. 12.1

Figure 12.1: Interfata grafica pentru rezolvarea ecuatiei algebrice.

Page 281: programare distribuita

12.1. JAVA WEB START 281

Instalare ıntr-un server Web

Pentru instalarea aplicatiei ıntr-un server Web, se parcurg pasii:

1. Se arhiveaza aplicatia

jar cfv cmmdc.jar *.class

2. Certificarea se obtine prin

(a) keytool -genkey -keystore myKeystore -alias myself

-dname "cn=XYZ, ou=cs, o=unitbv, l=brasov, c=RO"

-keypass abc123 -storepass 123abc

(b) keytool -selfcert -alias myself -keystore myKeystore

-keypass abc123 -storepass 123abc

(c) jarsigner -keystore myKeystore -keypass abc123 -storepass 123abc

resursa.jar myself

Primele doua actiuni au ca rezultat obtinerea certificatului myKeystoreiar ultima actiune reprezinta ınglobarea certificarii ın arhiva resursa.jar- ın cazul exemplului cmmdc.jar.

3. Se editeaza fisierul launch.jnlp

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <j n l p codebase=” h t t p : // hos t : 8080 /cmmdc”>3 <i n fo rmat ion>4 < t i t l e> . . . </ t i t l e>5 <vendor> . . . </ vendor>6 <d e s c r i p t i o n> . . . </ d e s c r i p t i o n>7 </ in fo rmat ion>8 <r e s o u r c e s>9 < j 2 s e version=”1.2+”/>

10 < j a r h r e f=”cmmdc . j a r ”/>11 </ r e s o u r c e s>12 <s e c u r i t y>13 <a l l−permi s s i ons />14 </ s e c u r i t y>15 <app l i c a t i on−desc main−c l a s s=”VisualCmmdc”/>16 </ j n l p>

host se ınlocuieste cu numele calculatorului care gazduieste serverul Web.

4. Se creaza fisier de apelare a aplicatiei (cmmdc.html)

1 <html>2 <body bgcolor=”#AAEEAA”>3 <center>4 <h3>Visua l Cmmdc Appl i ca t ion </h3>

Page 282: programare distribuita

282 CAPITOLUL 12. JAVA WEB START

5 <a href=” http :// host :8080/cmmdc/ launch . j n l p ”>6 Launch the a p p l i c a t i o n </a>7 </center>8 </body>9 </html>

5. Ansamblul

cmmdc

| cmmdc.jar

| cmmdc.html

| launch.jnlp

se copiaza ın serverul Web.

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

Fisierul jnlp se descarca pe calculatorul clientului si se proceseaza cubin\javaws.exe din Java.

Aplicatia Java ca servlet

Pentru includerea aplicatie Java ıntr-un servlet, primii trei pasi prezentatimai sus coincid. Singura diferenta consta ın continutul referintelor, dupa hostva apare portul utilizat de serverul Web container de servlet, uzual host:8080.

4. Intr-un catalog de lucru se creaza structura de cataloage si fisiere:

app

| cmmdc.jar

| launch.jnlp

WEB-INF

|--> lib

| | jnlp-servlet.jar

| web.xml

cmmdc.html

Fisierul jnlp-servlet.jar se preia din distributia JDK, din catalogulsample/jnlp/servlet.

Fisierul web.xml este

1 ?xml v e r s i o n=” 1 .0 ” encoding=” i so −8859−1”?>2 < !DOCTYPE web−app3 PUBLIC ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”4 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd”>5 <web−app>6 < !−− Standard Action S e r v l e t Conf igurat ion ( with debugging ) −−>

Page 283: programare distribuita

12.1. JAVA WEB START 283

7 <web−app>8 <s e r v l e t>9 <s e r v l e t−name>JnlpDownloadServlet</ s e r v l e t−name>

10 <s e r v l e t−c l a s s>11 j n l p . sample . s e r v l e t . JnlpDownloadServlet12 </ s e r v l e t−c l a s s>13 </ s e r v l e t>14 <s e r v l e t−mapping>15 <s e r v l e t−name>JnlpDownloadServlet</ s e r v l e t−name>16 <ur l−pattern>∗ . j n l p</ ur l−pattern>17 </ s e r v l e t−mapping>18 </web−app>19 </web−app>

5. Continutul catalogului de lucru se arhiveaza ıntr-un fisier war.

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

6. Utilizand apache-tomcat sau jetty, de exemplu, fisierul war se copiaza ıncatalogul webapps al serverului web.

Dintr-un navigator, apelarea aplicatiei se obtine prinhttp://host:8080/cmmdc/cmmdc.html.

• Daca aplicatia Java utilizeaza imagini grafice acestea trebuie arhivateımpreuna cu aplicatia, de exemplu ıntr-un catalog images.

Incarcarea si afisarea unei imagini programandu-se prin

ClassLoader cl=this.getClass().getClassLoader();

URL file=cl.getResource("images/pic1.jpg");

Image img=Toolkit.getDefaultToolkit().getImage(file);

graphics.drawImage(img,x,y,this);

• 1. Daca aplicatia Java utilizeaza alte resurse date prin fisiere jar

atunci toate fisierele jar trebuie sa poarte aceasi certificare.

2. Fisierele jar certificate se depun ın catalogul app\lib.

3. In fisierul jnlp, ın elementul resources, pentru fiecare fisier jar

utilizat se introduce declaratia

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

• Daca arhiva jar a aplicatiei Java este executabila atunci, ın fisierul jnlp,elementul application-desc poate lipsi.

Intr-o arhiva jar executabila, fisierul MANIFEST.MF indica clasa cu metodamain si eventualele resurse externe utilizate (fisiere jar) prin proprietatile

Page 284: programare distribuita

284 CAPITOLUL 12. JAVA WEB START

Main-class: numeClasa

Class-path: lib/resursa1.jar lib/resursa2.jar . . .

Pentru a obtine fisierul MANIFEST.MF cu aceste proprietati se editeaza unfisier text cu continutul de mai sus, denumit de exemplu myManifest.mf,si se arhiveaza prin

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

Intrebari recapitulative

1. Ce posibilitate ofera tehnologia Java Web Start ?

2. O aplicatie Java urmeaza sa fie valorificat pe Internet prin Java WebStart. Daca aplicatia necesita date ale clientului ce restrictie exista sicum se satisface restrictia ?

Page 285: programare distribuita

Capitolul 13

Java Management Extensions

Java Management Extensions (JMX) face posibila ca un obiect Java sapermita gestionarea metodelor si a anumitor campuri de catre alte obiecte.Obiectele Java care ısi expun astfel resursele se numesc MBean - uri si formeazatemelia cadrului de lucru JMX.

Exista mai multe tipuri de MBean-uri:

• Standard MBean;

• Dynamic MBean;

• Open MBean;

• Model MBean;

• MXBean;

Un obiect care gestioneaza resursele unui MBean se numeste agent sau serverMBean. Agentul dispune de mijloace care interactioneaza cu un MBean,permitandu-i:

• accesul la valorile unui camp si la modificarea lor;

• invocarea metodelor.

In general, un agent poate fi definit ca

• autorul unei actiuni;

• factor care provoaca actiuni;

• reprezentant al unei institutii ınsarcinat cu ındeplinirea unor actiuni.

285

Page 286: programare distribuita

286 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Terminologia server MBean se justifica prin faptul ca poate fi invocat de unprogram client. In aceasta ipostaza, serverul MBean are rolul unui containerde MBean-uri si de gestionare si executie a apelurilor clientilor.

Structura unei aplicatii JMX contine doua nivele:

• componentele MBean;

• agentul (serverul MBean).

13.1 Standard MBean

13.1.1 Crearea unui Standard MBean

O componenta MBean este alcatuita dintr-o interfata si o clasa care imple-menteaza interfata satisfacand urmatoarele restrictii:

1. interfata are numele clasei care o implementeaza avand ın plus sufixulMBean;

2. Interfata si clasa care o implementeaza apartin aceluiasi pachet;

3. constructorii si metodele expuse trebuie sa fie publice.

In continuare campurile si metodele destinate expunerii se vor denumiatribute, respectiv operatii. Fiecarui atribut xxx i se ataseaza cel putin unadin metodele

public void setXxx(tip xxx){

this.xxx=xxx;

}

si / sau

public tip getXxx(){

return xxx;

}

Un atribut se precizeaza doar prin aceste metode, fara definirea / declarareacampului corespunzator. Campul se defineste ın clasa ce implementeaza interfataMBean-ului.

Astfel, un MBean este caracterizat de

Page 287: programare distribuita

13.1. STANDARD MBEAN 287

• atribute

care pot fi consultate (citite), modificate (scrise) sau cu ambele optiuni.

• operatii

• notificari

cu evidenta modificarilor suferite de atribute.

Exemplul 13.1.1

Construim un MBean cu

• atributele

– label

ce poate fi numai citit;

– cursEuro

care poate fi consultat si modificat;

• operatiile

– public String sayHello()

afiseaza un mesaj;

– public long cmmdc(long m, long n);

de calcul a celui mai mare divizor comun a doua numere naturale.

Interfata IntroMBean este

1 package bas i c ;

3 public interface IntroMBean {4 // Opera t i i5 public St r ing sayHe l lo ( ) ;6 public long cmmdc( long m, long n ) ;

8 // A t r i b u t e9 // read−only

10 public St r ing getLabe l ( ) ;11 // read−w r i t e12 public double getCursEuro ( ) ;13 public void setCursEuro (double cursEuro ) ;14 }

fiind implementat de clasa Intro

Page 288: programare distribuita

288 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

1 package bas i c ;

3 public class In t ro implements IntroMBean {

5 // A t r i b u t e6 private f ina l St r ing label = ”Fac . Matematica s i In fo rmat i ca ” ;7 private double cursEuro = 4 . 5 0 ;

9 public St r ing getLabe l ( ) {10 return label ;11 }

13 public double getCursEuro ( ) {14 return cursEuro ;15 }

17 public synchronized void setCursEuro (double cursEuro ) {18 this . cursEuro = cursEuro ;19 }

21 // Opera t i i22 public St r ing sayHe l lo ( ) {23 St r ing message=” He l lo World ! ” ;24 System . out . p r i n t l n ( message ) ;25 return message ;26 }

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

In acest caz nu s-a implementat posibilitatea notificarilor atributului cursEuro.

13.1.2 Crearea unui MBeanServer

Un agent sau MBean server implementeaza interfata MBeanServer. Unasemenea obiect se obtine printr-una din metodele statice

• static MBeanServer ManagementFactory.getPlatformMBeanServer()

Utilitarul jconsole permite conectarea la serverul MBean.

• static MBeanServer MBeanServerFactory.createMBeanServer()

In agent se ınregistreaza componente MBean. Un obiect MBean este car-acterizat de un nume, un obiect de tip ObjectName. Inregistrarea si / saucrearea unei componente MBean necesita definirea ın prealabil a acestui nume.Structura unei nume este

domeniu : numeAtribut=valAtribut ,numeAtribut=valAtribut . . .

unde

Page 289: programare distribuita

13.1. STANDARD MBEAN 289

• domeniu

este un nume simbolic (String). Daca domeniul este stringul vid atuncise considera valoarea implicita DefaultDomain.

• atribute uzuale:

– type=numele MBean-ului

– index=numar de identificare a MBean-ului

Cel putin un atribut este obligatoriu.

Clasa ObjectName

Constructori

• ObjectName(String nume)

Parametrul nume are structura descrisa mai sus.

• ObjectName(String domeniu, Hashtable<String,String> tabel)

• ObjectName(String domeniu, String numeAtribut, String

valAtribut)

Metode

• static ObjectName getInstance(String nume)

Inregistrarea si utilizarea MBean-ului face apel la metodele interfetei MBeanServer.

ObjectInstance

Un obiect de tip ObjectInstance este folosit pentru reprezentarea ansam-blului alcatuit de un obiect ObjectName asociat unui MBean si numele claseicorespunzatoare.

Interfata MBeanServer

Metode

• ObjectInstance registerMBean(Object obj, ObjectName nume)

Inregistreaza pe platforma, instanta obj a unui MBean avand numelenume.

Page 290: programare distribuita

290 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

• void unregister(ObjectName nume)

• ObjectInstance createMBean(String numeClasa, ObjectName nume)

Creaza si ınregistreaza un MBean de clasa numeClasa si de nume nume.

• ObjectInstance createMBean(String numeClasa, ObjectName nume,Object[] param, String[] sign)

In plus, sirul param contine parametri constructorului, de tip, respectivsign.

• String getDefaultDomain()

• Object invoke(ObjectName mbeanName, String operationName, Object[]

param, String[] paramTip)

Se invoca operatia operationName a MBean-ului mbeanName. Parametrinecesari operatiei ımpreuna cu tipurile corespunzatoare sunt dati ın vari-abilele param si respectiv paramTip.

• Object getAttribute(ObjectName mbeanName,String atribut)

Returneaza valoarea atributului atribut a mbean-ului mbeanName.

• void setAttribute(ObjectName mbeanName,Attribute atribut)

Fixeaza valoarea atributului atribut a MBean-ului mbeanName. Retinemdoar constructorul clasei Attribute prin

Attribute(String nume, Object valoare)

• MBeanInfo getMBeanInfo(ObjectName mbeanName)

Returneaza un obiect de tip MBeanInfo util inspectarii resurselor unuiMBean.

Exista mai multe sabloane de programare a ınregistrarii unei componenteMBean.

Exemplul 13.1.2 Se creaza doua componente MBean de tip Intro care vor fiinspectate prin intermediul utilitarului jconsole1 - distributia jdk .

Utilitarul jconsole permite apelarea operatiilor, modificarea atributelor sisemnaleaza notificarile.

1In acest caz, este nevoie ca variabilele de tip clasa acoperitoare Double, Long sa fieınlocuite prin tipuri predefinite.

Page 291: programare distribuita

13.1. STANDARD MBEAN 291

1 package bas i c ;2 import java . lang . management . ManagementFactory ;3 import javax . management . ObjectName ;4 import javax . management . MBeanServer ;

6 public class Main{7 public stat ic void main ( St r ing [ ] a rgs ){8 St r ing domeniu=”” ;9 i f ( args . length >0) domeniu=args [ 0 ] ;

10 try{11 // S e r v e r u l p l a t f o r m e i12 MBeanServer mbs = ManagementFactory . getPlatformMBeanServer ( ) ;

14 // Varianta 115 // Construirea ObjectName corespunzator MBean−u l u i16 ObjectName mbeanObjectName =17 new ObjectName ( domeniu+” : type=Intro , index=1” ) ;

19 // Crearea MBean−u l u i20 In t ro mbean = new In t ro ( ) ;

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

25 // Varianta 226 mbeanObjectName=new ObjectName ( domeniu+” : type=Intro , index=2” ) ;27 mbs . createMBean ( ” ba s i c . In t ro ” , mbeanObjectName ) ;

29 // Asteptare n e d e f i n i t a30 System . out . p r i n t l n ( ”Waiting f o r e v e r . . . ” ) ;31 while ( true ) ;32 }33 catch ( Exception e ){34 System . e r r . p r i n t l n ( ” Exception : ”+e . getMessage ( ) ) ;35 }36 }37 }

Executarea aplicatiei revine la

1. Intr-o fereastra DOS se lanseaza agentul Main prinjava -Dcom.sun.manager.jmxremote basic.Main

2. Intr-o alta fereastra DOS se lanseazajconsole

pornind utilitarul jconsole.

3. In fereastra de dialog jconsole:Connect to Agent se da clic pe Connect.

4. In panoul Tree gasim domeniul dat. Prin clic pe domeniu apar MBean-urile de indice 1 si 2.

5. Prin clic pe unul din aceste MBean-uri, ın panoul central avem acces laatributele si la operatiile lor.

Page 292: programare distribuita

292 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Rezultatul unei operatii apare ıntr-o fereastra de informare (Fig. 13.1).

Figure 13.1: Rezultatele furnizate de jcluster.

13.1.3 Notificari

Pentru implementarea retinerii de catre un agent MBean a notificarilor,clasa ce implementeaza interfata MBean-ului trebuie sa extinda clasa Notification-BroadcasterSupport.

Modificarile unui atribut se retin ıntr-un obiect de tip Notification si estetransmis prin metoda

sendNotification(Notification notification)

Page 293: programare distribuita

13.1. STANDARD MBEAN 293

a clasei NotificationBroadcasterSupport.Suplimentar se defineste metoda

public MBeanNotificationInfo[] getNotificationInfo()

ın care se precizeaza

• tipul notificarii - (constanta definita de clasa AttributeChangeNotification);

• clasa ın care s-a generat notificarea

String name = AttributeChangeNotification.class.getName();

• o descriere a modificarii.

Astfel, introducerea notificarilor presupune familiarizarea cu clasele

• NotificationBroadcasterSupport

Constructori

– NotificationBroadcasterSupport()

Metode

– void sendNotification(Notification notificare)

• Notification

Constructori

– Notification(String type, Object source, long sequenceNum-ber)

– Notification(String type, Object source, long sequenceNum-ber, long timeStamp)

– Notification(String type, Object source, long sequenceNum-ber, long timeStamp, String mesaj)

– Notification(String type, Object source, long sequenceNum-ber, String mesaj)

Metode

– public void setUserData(Object userData)

– public Object getUserData()

Page 294: programare distribuita

294 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

• AttributeChangeNotification extends Notification

Constructori

– AttributeChangeNotification(Object source, long sequenceNum-ber, long timeStamp, String msg, String attributeName, String

attributeType, Object oldValue, Object newValuE)

Campuri

– static String ATTRIBUTE CHANGE

Semnaleaza schimbarea atributului

Exemplul 13.1.3 Extinderea MBean-ului Intro cu notificarea modificariloratributelor ın jconsole.

Implementarea notificarilor ın clasa Intro presupune modificarea metodeisetCursEuro. Totodata se adauga metoda getNotificationInfo, ce furnizeazainformatii referitoare la modificarea aparuta. Codul clasei care implementeazainterfata devine

1 package agentn ;2 import javax . management . N o t i f i c a t i o n ;3 import javax . management . Att r ibuteChangeNot i f i ca t i on ;4 import javax . management . Not i f i c a t i onBroadcas t e rSuppor t ;5 import javax . management . MBeanNot i f i cat ionInfo ;

7 public class IntroN extends Not i f i c a t i onBroadcas t e rSuppor t8 implements IntroNMBean{9 private long sequenceNumber=1;

11 // A t r i b u t e12 private f ina l St r ing label = ”Fac . Matematica s i In fo rmat i ca ” ;13 private double cursEuro = 4 . 5 0 ;

15 public St r ing getLabe l ( ) { . . .}

17 public double getCursEuro ( ) { . . .}

19 public synchronized void setCursEuro (double cursEuro ) {20 double oldCursEuro=this . cursEuro ;21 this . cursEuro = cursEuro ;22 //System . out . p r i n t l n (” Curs de schimb euro : ” + euro+” ron . ” ) ;23 N o t i f i c a t i o n n=new Attr ibuteChangeNot i f i ca t i on (24 this ,25 sequenceNumber++,26 System . cur r entT imeMi l l i s ( ) ,27 ”Schimbarea c u r s u l u i Euro” ,28 ” cursEuro ” ,29 ” double ” ,30 oldCursEuro ,31 cursEuro ) ;

Page 295: programare distribuita

13.1. STANDARD MBEAN 295

32 s e n d N o t i f i c a t i o n (n ) ;33 }

35 public MBeanNot i f i cat ionInfo [ ] g e t N o t i f i c a t i o n I n f o ( ) {36 St r ing [ ] types = new St r ing [ ] {37 Attr ibuteChangeNot i f i ca t i on .ATTRIBUTE CHANGE38 } ;39 St r ing name = Att r ibuteChangeNot i f i ca t i on . class . getName ( ) ;40 St r ing d e s c r i p t i o n = ”An a t t r i b u t e o f t h i s MBean has changed” ;41 MBeanNot i f i cat ionInfo i n f o =42 new MBeanNot i f i cat ionInfo ( types , name , d e s c r i p t i o n ) ;43 return new MBeanNot i f i cat ionInfo [ ] { i n f o } ;44 }

46 // Opera t i i47 public St r ing sayHe l lo ( ) { . . .}

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

In jconsole pentru notificare, ın prealabil este nevoie de subscriere.

13.1.4 Agent MBean

In exemplelele anterioare resursele unui MBean au fost utilizate prin jcon-sole. Valorificarea resurselor unui MBean Intro, dintr-un MBeanServer (agent)se programeaza prin

Exemplul 13.1.4

1 package agent ;2 import java . i o . IOException ;3 import javax . management . ObjectName ;4 import javax . management . MBeanServer ;5 import javax . management . MBeanServerFactory ;6 import javax . management . Att r ibute ;7 import java . u t i l . Scanner ;

9 public class Agent{10 public stat ic void main ( St r ing [ ] a rgs ) {11 try {12 // Crearea Agentu lu i − MBeanServer13 MBeanServer mbs = MBeanServerFactory . createMBeanServer ( ) ;

15 // Crearea unui MBean16 St r ing domain = mbs . getDefaultDomain ( ) ;17 St r ing className=” agent . In t ro ” ;18 St r ing sObjectName=domain+” : type=”+className ;19 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;20 mbs . createMBean ( className , mbeanObjectName ) ;

22 // U t i l i z a r e a MBean−u l u i23 // Apelarea o p e r a t i i l o r24 St r ing ope ra t i a=” sayHe l lo ” ;

Page 296: programare distribuita

296 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

25 mbs . invoke ( mbeanObjectName , operat ia , null , null ) ;

27 ope ra t i a=”cmmdc” ;28 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;29 Scanner scanner=new Scanner ( System . in ) ;30 System . out . p r i n t l n ( ”Primul numar : ” ) ;31 long m=scanner . nextLong ( ) ;32 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;33 long n=scanner . nextLong ( ) ;34 Object [ ] param={m, n } ;35 St r ing [ ] s i gn={” long ” , ” long ” } ;36 Long r=(Long )mbs . invoke ( mbeanObjectName , operat ia , param , s i gn ) ;37 System . out . p r i n t l n ( ”cmmdc=”+r . t oS t r i ng ( ) ) ;

39 // U t i l i z a r e a A t r i b u t e l o r40 St r ing label=( St r ing )mbs . ge tAt t r ibut e ( mbeanObjectName , ” Label ” ) ;41 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i l a b e l : ”+label ) ;

43 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;44 double cursEuro=scanner . nextDouble ( ) ;45 Attr ibute curs=new Attr ibute ( ”CursEuro” , cursEuro ) ;46 mbs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;47 Double euro=(Double )mbs . ge tAt t r ibut e ( mbeanObjectName , ”CursEuro” ) ;48 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i cursEuro : ”+euro ) ;49 }50 catch ( Exception e ){51 System . out . p r i n t l n ( e . getMessage ( ) ) ;52 }53 }54 }

13.1.5 Invocarea la distanta

Din punct de vedere al programarii distribuite, cazul interesant este celın care clasa ce implementeaza MBean-ul si clientul (agentul MBean) care outilizeaza se afla pe calculatoare diferite.

In acest caz:

• Este nevoie de o clasa server (agent) al carui rol este

– Instantierea unui MBeanServer

– Instantiarea unui server de conexiune, obiect de tip MBeanServerConnection.

Bazat pe tehnologia RMI sau RMI-IIOP, acest obiect gestioneazacomunicatia dintre un client si serverul MBeanServer. Serverul deconexiune si serverul MBeanServer apartin aceleiasi clase.

In cazul utilizarii tehnologiei RMI rmiregistry si serverul MBeanServertrebuie sa ruleze pe acelasi calculator.

Utilizand tehnologia RMI-IIOP, orbd si serverul MBeanServer potrula pe calculatoare distincte.

Page 297: programare distribuita

13.1. STANDARD MBEAN 297

– Lansarea ın executie a serverului de conexiune.

• Clientul dispune de interfata MBean-ului.

Interfata MBeanServerConnection este implementata de clasa MBeanServerSablonul de programare pentru instantierea obiectului de tip MBeanServerConnection

si lansarea sa ın executie poate fi:

String surl="service:jmx:rmi:///jndi/rmi://host:port/numeServer"

// String surl="service:jmx:iiop:///jndi/iiop://host:port/numeServer";

// Crearea unui server-conector

JMXServiceURL url = new JMXServiceURL(surl);

JMXConnectorServer cs =

JMXConnectorServerFactory.newJMXConnectorServer(url,null,MBeanServer);

//

// Pornirea server-conectorului

cs.start();

System.out.println("Press Enter to finish !");

System.in.read();

cs.stop();

Serverul de conexiune are un nume, numeServer care trebuie cunoscut de catreclient.

Lansarea ın executie a serverului este precedata de pornirea registruluirmiregistry, respectiv orbd.

Exemplul 13.1.5

1 package s e r v e r ;2 import javax . management . MBeanServer ;3 import javax . management . MBeanServerFactory ;4 import javax . management . remote . JMXServiceURL ;5 import javax . management . remote . JMXConnectorServer ;6 import javax . management . remote . JMXConnectorServerFactory ;

8 public class MBServer{9 public stat ic void main ( St r ing [ ] a rgs ) {

10 St r ing host=” l o c a l h o s t ” ;11 St r ing port=”1099” ;12 // S t r i n g por t =”1050”;13 i f ( args . l ength==0){14 System . out . p r i n t l n ( ”The name o f the s e r v e r i s r equ i r ed ” ) ;15 System . e x i t ( 0 ) ;16 }17 i f ( args . length >=2)18 host=args [ 1 ] ;19 i f ( args . length >=3)20 port=args [ 2 ] ;21 try {22 // Crearea MBeanServer23 MBeanServer mbs = MBeanServerFactory . createMBeanServer ( ) ;

Page 298: programare distribuita

298 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

25 // Crearea unui server−conector26 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+27 host+” : ”+port+”/”+args [ 0 ] ;28 // S t r i n g s u r l=”s e r v i c e : jmx : i i o p :/// j n d i / i i o p ://”+29 // hos t +”:”+ port+”/”+args [ 0 ] ;30 JMXServiceURL u r l=new JMXServiceURL( s u r l ) ;31 JMXConnectorServer cs=32 JMXConnectorServerFactory . newJMXConnectorServer ( ur l , null , mbs ) ;

34 // Pornirea server−c o n e c t o r u l u i35 cs . s t a r t ( ) ;36 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;37 System . in . read ( ) ;38 cs . stop ( ) ;39 }40 catch ( Exception e ){41 System . out . p r i n t l n ( e . getMessage ( ) ) ;42 e . pr intStackTrace ( ) ;43 }44 }45 }

Primul argument care trebuie furnizat programului anterior (args[0]) este nu-mele serverului.

Clientul, la randul lui, este nevoit sa creeze un conector catre server (agent),prin intermediul caruia obtine un obiect ce implementeaza interfata MBeanServerConnection.Prin acest obiect, clientul va putea crea MBean-uri - ın agent - si le va puteautiliza resursele.

Sablonul de programare pentru crearea obiectului MBeanServerConnectionpoate fi

JMXServiceURL url =

new JMXServiceURL("service:jmx:rmi:///jndi/rmi://host:port/numeServer");

JMXConnector jmxc = JMXConnectorFactory.connect(url,null);

// Obtinerea obiectului de tip MBeanServerConnection

MBeanServerConnection cs = jmxc.getMBeanServerConnection();

Resursele unui MBean se poate invoca prin

• metoda invoke(mbeanObjectName,operationName,param,sign) a interfeteiMBeanServerConnection.

• crearea unui reprezentant local al MBean-ului prin metoda statica

mbeanClass proxy =(mbeanClass)MBeanServerInvocationHandler.newProxyInstance(mbeanServerConnection,mbeanObjectName,mbeanClass.class,true);

In final, MBean-ul se sterge din serverul de conexiune, princs.unregisterMBean(mbeanObjectName).

Page 299: programare distribuita

13.1. STANDARD MBEAN 299

Exemplul 13.1.6 Client ce utilizeaza un MBean Intro, definit ın Exemplul13.1.1

1 package c l i e n t ;2 import java . u t i l . Scanner ;3 import javax . management . MBeanServerConnection ;4 import javax . management . ObjectName ;5 import javax . management . Att r ibute ;6 import javax . management . MBeanServerInvocationHandler ;7 import javax . management . remote . JMXServiceURL ;8 import javax . management . remote . JMXConnector ;9 import javax . management . remote . JMXConnectorFactory ;

11 public class Cl i en t {12 public stat ic void main ( St r ing [ ] a rgs ) {13 St r ing host=” l o c a l h o s t ” ;14 St r ing port=”1099” ;15 i f ( args . length <=1){16 System . out . p r i n t l n ( ”The s e r v e r and domain names are r equ i r ed ” ) ;17 System . e x i t ( 0 ) ;18 }19 St r ing serverName=args [ 0 ] ;20 St r ing domain=args [ 1 ] ;21 i f ( args . length >=3) host=args [ 2 ] ;22 i f ( args . length >=4) port=args [ 4 ] ;23 Scanner scanner=new Scanner ( System . in ) ;24 try {25 // Crearea unui conector s i a o b i e c t u l u i de t i p MBeanServercsection26 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+27 host+” : ”+port+”/”+args [ 0 ] ;28 // S t r i n g s u r l=”s e r v i c e : jmx : i i o p :/// j n d i / i i o p ://”+29 // hos t +”:”+ port+”/”+args [ 0 ] ;30 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;31 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;32 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;

34 // Domeniile a g e n t u l u i sunt35 System . out . p r i n t l n ( ”Domains : ” ) ;36 St r ing domains [ ] = cs . getDomains ( ) ;37 for ( int i = 0 ; i < domains . l ength ; i++) {38 System . out . p r i n t l n ( ”\tDomain [ ” + i + ” ] = ” + domains [ i ] ) ;39 }

41 // i a r domeniul i m p l i c i t42 System . out . p r i n t l n ( ”DefaultDomain : ” +cs . getDefaultDomain ( ) ) ;43 System . out . p r i n t l n ( ”Domain : ” +domain ) ;

45 // Crearea unui MBean Intro46 St r ing className=” bas i c . In t ro ” ;47 St r ing sObjectName=domain+” : type=”+className ;48 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;49 cs . createMBean ( className , mbeanObjectName , null , null ) ;

51 double cursEuro ;52 long m, n ;

54 // U t i l i z a r e a MBean−u l u i55 // Varianta 1 de invocare pr in proxy

Page 300: programare distribuita

300 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

56 System . out . p r i n t l n ( ” Varianta de invocare pr in prox i ” ) ;57 IntroMBean proxy=58 ( IntroMBean ) MBeanServerInvocationHandler . newProxyInstance (59 cs ,60 mbeanObjectName ,61 c l i e n t . IntroMBean . class ,62 true ) ;

64 // U t i l i z a r e a o p e r a t i i l o r65 // o p e r a t i a ” sayHe l lo ”66 proxy . sayHe l lo ( ) ;

68 // o p e r a t i a cmmdc69 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;70 System . out . p r i n t l n ( ”Primul numar : ” ) ;71 m=scanner . nextLong ( ) ;72 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;73 n=scanner . nextLong ( ) ;74 System . out . p r i n t l n ( ”Cmmdc=”+proxy . cmmdc(m, n ) ) ;

76 // U t i l i z a r e a a t r i b u t e l o r77 System . out . p r i n t l n ( ”Numele : ”+proxy . getLabe l ( ) ) ;78 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;79 cursEuro=scanner . nextDouble ( ) ;80 proxy . setCursEuro ( cursEuro ) ;81 System . out . p r i n t l n ( ”Euro : ”+proxy . getCursEuro ( ) ) ;

83 // Varianta 2 de invocare pr in conexiune84 System . out . p r i n t l n ( ” Varianta de invocare pr in conexiune ” ) ;85 // Apelarea o p e r a t i i l o r86 St r ing ope ra t i a=” sayHe l lo ” ;87 cs . invoke ( mbeanObjectName , operat ia , null , null ) ;88 ope ra t i a=”cmmdc” ;89 System . out . p r i n t l n ( ”Cmmdc a l numerelor : ” ) ;90 System . out . p r i n t l n ( ”Primul numar : ” ) ;91 m=scanner . nextLong ( ) ;92 System . out . p r i n t l n ( ”Al d o i l e a numar : ” ) ;93 n=scanner . nextLong ( ) ;94 Object [ ] param={m, n } ;95 St r ing [ ] s i gn={” long ” , ” long ” } ;96 Long r=(Long ) cs . invoke ( mbeanObjectName , operat ia , param , s i gn ) ;97 System . out . p r i n t l n ( ”Cmmdc=”+r . t oS t r i ng ( ) ) ;

99 // U t i l i z a r e a A t r i b u t e l o r100 St r ing label=( St r ing ) cs . g e tAt t r ibut e ( mbeanObjectName , ” Label ” ) ;101 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i l a b e l : ”+label ) ;

103 System . out . p r i n t l n ( ” I n t r o d u c e t i c u r s u l euro ” ) ;104 cursEuro=scanner . nextDouble ( ) ;105 Attr ibute curs=new Attr ibute ( ”CursEuro” , cursEuro ) ;106 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;107 Double newEuro=(Double ) cs . g e tAt t r ibute ( mbeanObjectName , ”CursEuro” ) ;108 System . out . p r i n t l n ( ” Valoarea a t r i b u t u l u i euro : ”+newEuro ) ;109 cs . unregisterMBean ( mbeanObjectName ) ;110 }111 catch ( Exception e ) {112 System . out . p r i n t l n ( e . getMessage ( ) ) ;113 }114 }

Page 301: programare distribuita

13.1. STANDARD MBEAN 301

115 }

Inspectarea si valorificarea resurselor unei componente MBean sepoate face si prin intermediul metodei

1 private stat ic void getMBeanResources ( MBeanInfo i n f o ){2 System . out . p r i n t l n ( ”CLASA: \ t ” + i n f o . getClassName ( ) ) ;3 System . out . p r i n t l n ( ”DESCR: \ t ” + i n f o . g e tDe s c r i p t i on ( ) ) ;4 System . out . p r i n t l n ( ”ATTRIBUTE” ) ;5 MBeanAttributeInfo [ ] a t t r I n f o = i n f o . g e tAt t r i bu t e s ( ) ;6 i f ( a t t r I n f o . l ength > 0) {7 for ( int i = 0 ; i < a t t r I n f o . l ength ; i++) {8 System . out . p r i n t l n ( ”\tNUME: \ t ” + a t t r I n f o [ i ] . getName ( ) ) ;9 System . out . p r i n t l n ( ”\tDESC : \ t ” + a t t r I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;

10 System . out . p r i n t l n ( ”\tTIP : \ t ” + a t t r I n f o [ i ] . getType ( ) +11 ” READ: ”+ a t t r I n f o [ i ] . i sReadable ( ) +12 ” WRITE: ”+ a t t r I n f o [ i ] . i sWr i tab l e ( ) ) ;13 }14 }15 else16 System . out . p r i n t l n ( ”\ tFara a t r i b u t e ! ” ) ;17 System . out . p r i n t l n ( ”CONSTRUCTORI” ) ;18 MBeanConstructorInfo [ ] c o n s t r I n f o = i n f o . ge tConst ruc tor s ( ) ;19 for ( int i =0; i<c o n s t r I n f o . l ength ; i++) {20 System . out . p r i n t l n ( ”\tNUME: \ t ” + c o n s t r I n f o [ i ] . getName ( ) ) ;21 System . out . p r i n t l n ( ”\tDESCR: \ t ” + c o n s t r I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;22 System . out . p r i n t l n ( ”\tPARAM: \ t ” +23 c o n s t r I n f o [ i ] . g e tS ignature ( ) . l ength +” parametr i ” ) ;24 }25 System . out . p r i n t l n ( ”OPERATII” ) ;26 MBeanOperationInfo [ ] opInfo = i n f o . getOperat ions ( ) ;27 i f ( opInfo . l ength > 0) {28 for ( int i = 0 ; i < opInfo . l ength ; i++) {29 System . out . p r i n t l n ( ”\tNUME: \ t ” + opInfo [ i ] . getName ( ) ) ;30 System . out . p r i n t l n ( ”\tDESCR: \ t ” + opInfo [ i ] . g e tDe s c r i p t i on ( ) ) ;31 System . out . p r i n t l n ( ”\tPARAM: \ t ” +32 opInfo [ i ] . g e tS ignature ( ) . l ength +” parametr i ” ) ;33 }34 }35 else36 System . out . p r i n t l n ( ”\ tFara o p e r a t i i ” ) ;37 System . out . p r i n t l n ( ”NOTIFICARI” ) ;38 MBeanNot i f i cat ionInfo [ ] n o t i f I n f o = i n f o . g e t N o t i f i c a t i o n s ( ) ;39 i f ( n o t i f I n f o . l ength > 0) {40 for ( int i = 0 ; i < n o t i f I n f o . l ength ; i++) {41 System . out . p r i n t l n ( ”\tNUME: ” + n o t i f I n f o [ i ] . getName ( ) ) ;42 System . out . p r i n t l n ( ”\tDESCR: ” + n o t i f I n f o [ i ] . g e tDe s c r i p t i on ( ) ) ;43 St r ing not i fTypes [ ] = n o t i f I n f o [ i ] . getNot i fTypes ( ) ;44 for ( int j = 0 ; j < not i fTypes . l ength ; j++) {45 System . out . p r i n t l n ( ”\tTIP : ” + not i fTypes [ j ] ) ;46 }47 }48 }49 else50 System . out . p r i n t l n ( ”\ tFara n o t i f i c a r i ” ) ;51 }

Aceasta metoda poate fi inserata ın oricare din programele agent sau client.

Page 302: programare distribuita

302 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Notificarea la distanta

Notificarea la distanta presupune utilizarea unui MBean posedand aceastafacilitate. Pe partea de client trebuie implementat interfata NotificationListenercare declara metoda

public void handleNotification(Notification notification, Object

handback)

Atasarea si disponibilizarea clasei ce implementeaza interfata NotificationListener se obtin prin metodele interfetei MBeanServerConnection:

• void addNotificationListener(ObjectName name, NotificationListener

listener, NotificationFilter filter, Object handback )throws Instance-

NotFoundException, IOException

• void removeNotificationListener(ObjectName name, ObjectName lis-tener )throws InstanceNotFoundException, ListenerNotFoundException,

IOException

Exemplul 13.1.7 Folosind exemplul 13.1.6 - dar cu MBean-ul creat pentru13.1.3 se creaza un client cu notificare, care sesiseaza modificarea valoariiatributului cursEuro a MBean-ului IntroN.

Implementarea interfetei NotificationListener este

1 package c l i e n t ;2 import javax . management . N o t i f i c a t i o n ;3 import javax . management . N o t i f i c a t i o n L i s t e n e r ;4 import javax . management . Att r ibuteChangeNot i f i ca t i on ;

6 public class C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r {7 public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n ,8 Object handback ) {9 System . out . p r i n t l n ( ”\nReceived n o t i f i c a t i o n : ” + n o t i f i c a t i o n ) ;

10 Attr ibuteChangeNot i f i ca t i on myNotif=11 ( Att r ibuteChangeNot i f i ca t i on ) n o t i f i c a t i o n ;12 System . out . p r i n t l n ( ”Curs i n i t i a l : ” +13 myNotif . getOldValue ( ) . t oS t r i ng ( ) ) ;14 System . out . p r i n t l n ( ”Curs curent : ” +15 myNotif . getNewValue ( ) . t oS t r i ng ( ) ) ;16 }17 }

Codul clasei client este

1 package c l i e n t ;2 import javax . management . ObjectName ;3 import javax . management . MBeanInfo ;4 import javax . management . MBeanAttributeInfo ;5 import javax . management . MBeanConstructorInfo ;

Page 303: programare distribuita

13.1. STANDARD MBEAN 303

6 import javax . management . MBeanOperationInfo ;7 import javax . management . MBeanNot i f i cat ionInfo ;8 import javax . management . MBeanServerConnection ;9 import javax . management . remote . JMXServiceURL ;

10 import javax . management . remote . JMXConnector ;11 import javax . management . remote . JMXConnectorFactory ;

13 public class C l i e n t N o t i f {14 public stat ic void main ( St r ing [ ] a rgs ) {15 St r ing host=” l o c a l h o s t ” ;16 St r ing port=”1099” ;17 i f ( args . length <=1){18 System . out . p r i n t l n ( ”The s e r v e r and domain names are r equ i r ed ” ) ;19 System . e x i t ( 0 ) ;20 }21 St r ing serverName=args [ 0 ] ;22 St r ing domain=args [ 1 ] ;23 i f ( args . length >=3) host=args [ 2 ] ;24 i f ( args . length >=4) port=args [ 3 ] ;25 C l i e n t N o t i f obj=new C l i e n t N o t i f ( ) ;26 try {27 // Crearea unui conector s i a o b i e c t u l u i28 // de t i p MBeanServerConnection29 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ” +30 host+” : ”+port+”/”+args [ 0 ] ;31 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;32 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;33 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;

35 // Crearea o b i e c t u l u i OBjectName a t a s a t MBean−u l u i IntroN36 St r ing className=” bas i cn . IntroN ” ;37 St r ing sObjectName=domain+” : type=”+className ;38 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

40 MBeanInfo i n f o=cs . getMBeanInfo ( mbeanObjectName ) ;41 getMBeanResources ( i n f o ) ;

43 // U t i l i z a r e a n o t i f i c a r i i44 // Crearea unui a s c u l t a t o r45 C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ;46 // Act ivarea n o t i f i c a t o r u l u i47 cs . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , obj ) ;

49 Thread . s l e e p ( 5 0 0 ) ;50 // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i51 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;52 try{53 System . in . read ( ) ;54 }55 catch ( java . i o . IOException e ){}56 cs . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ;57 // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName58 cs . unregisterMBean ( mbeanObjectName ) ;59 }60 catch ( Exception e ) {61 System . out . p r i n t l n ( e . getMessage ( ) ) ;62 e . pr intStackTrace ( ) ;63 }64 }

Page 304: programare distribuita

304 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

66 private stat ic void getMBeanResources ( MBeanInfo i n f o ) { . . .}

68 }

Clasa Client care creaza MBean-ul trebuie lansata ınaintea clasei ClientNotif.Aceste doua clase pot rula pe calculatoare distincte.

Exemplul 13.1.8 O aplicatie servlet ıntretine un cont. Actiunile ce pot fiıntreprinse sunt: depunerea unei sume, extragerea unei sume ın limita solduluisi consultarea contului. Contul este implementat ca un MBean standard. Secere urmarirea la distanta a modificarilor suferite de cont.

Interfata contului (a MBean-ului) este

1 public interface ContMBean {2 // A t r i b u t e3 // read−w r i t e4 public double getCont ( ) ;5 public void setCont (double cont ) ;6 }

implementat prin

1 import javax . management . N o t i f i c a t i o n ;2 import javax . management . Att r ibuteChangeNot i f i ca t i on ;3 import javax . management . Not i f i c a t i onBroadcas t e rSuppor t ;4 import javax . management . MBeanNot i f i cat ionInfo ;

6 public class Cont extends Not i f i c a t i onBroadcas t e rSuppor t7 implements ContMBean{8 private long sequenceNumber=1;9 private double cont ;

11 public synchronized double getCont ( ) {12 return cont ;13 }

15 public synchronized void setCont (double cont ) {16 double oldCont=this . cont ;17 this . cont=cont ;18 N o t i f i c a t i o n n=new Attr ibuteChangeNot i f i ca t i on (19 this ,20 sequenceNumber++,21 System . cur r entT imeMi l l i s ( ) ,22 ”Schimbarea Cont” ,23 ” cont ” ,24 ” double ” ,25 oldCont ,26 cont ) ;27 s e n d N o t i f i c a t i o n (n ) ;28 }

30 public MBeanNot i f i cat ionInfo [ ] g e t N o t i f i c a t i o n I n f o ( ) {31 St r ing [ ] types = new St r ing [ ] {32 Attr ibuteChangeNot i f i ca t i on .ATTRIBUTE CHANGE

Page 305: programare distribuita

13.1. STANDARD MBEAN 305

33 } ;34 St r ing name = Att r ibuteChangeNot i f i ca t i on . class . getName ( ) ;35 St r ing d e s c r i p t i o n = ”An a t t r i b u t e o f t h i s MBean has changed” ;36 MBeanNot i f i cat ionInfo i n f o =37 new MBeanNot i f i cat ionInfo ( types , name , d e s c r i p t i o n ) ;38 return new MBeanNot i f i cat ionInfo [ ] { i n f o } ;39 }40 }

Codul servlet-ului este

1 import java . i o . IOException ;2 import javax . s e r v l e t . Se rv l e tExcept ion ;3 import javax . s e r v l e t . http . HttpServ l e t ;4 import javax . s e r v l e t . http . HttpServ letRequest ;5 import javax . s e r v l e t . http . HttpServletResponse ;6 import javax . s e r v l e t . ServletOutputStream ;7 import javax . s e r v l e t . S e rv l e tCon f i g ;8 import javax . s e r v l e t . annotat ion . WebServlet ;9 import javax . s e r v l e t . annotat ion . WebInitParam ;

10 import javax . management . ObjectName ;11 import javax . management . Att r ibute ;12 import javax . management . MBeanServerConnection ;13 import javax . management . remote . JMXServiceURL ;14 import javax . management . remote . JMXConnector ;15 import javax . management . remote . JMXConnectorFactory ;

17 @WebServlet ( u r lPa t t e rn s = ”/ appdepozit ” ,18 in itParams = {19 @WebInitParam (name = ” jmxServerHost ” , va lue = ” l o c a l h o s t ” )20 }21 )22 public class Depoz i tSe rv l e t extends HttpServ l e t {23 MBeanServerConnection cs=null ;24 ObjectName mbeanObjectName=null ;25 St r ing host ;26 St r ing port=”1099” ;27 St r ing s e r v e r=” s e r v e r ” ;

29 public void i n i t ( Se rv l e tCon f i g c o n f i g ) {30 try {31 super . i n i t ( c o n f i g ) ;32 host=c o n f i g . ge t In i tParameter ( ” jmxServerHost ” ) ;33 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ”+host+” : ”+port+”/”+s e r v e r ;34 // S t r i n g s u r l=”s e r v i c e : jmx : i i o p :/// j n d i / i i o p ://”+ hos t +”:”+ port+”/”+s e r v e r ;35 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;36 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;37 cs = jmxc . getMBeanServerConnection ( ) ;38 St r ing domain = cs . getDefaultDomain ( ) ;39 St r ing className=”Cont” ;40 St r ing sObjectName=domain+” : type=”+className ;41 mbeanObjectName = new ObjectName ( sObjectName ) ;42 cs . createMBean ( className , mbeanObjectName , null , null ) ;43 }44 catch ( Exception e ){45 System . out . p r i n t l n ( e . getMessage ( ) ) ;46 System . e x i t ( 0 ) ;47 }48 }

Page 306: programare distribuita

306 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

50 public void doGet ( HttpServ letRequest req , HttpServletResponse r e s )51 throws Serv le tExcept ion , IOException{52 ServletOutputStream out=r e s . getOutputStream ( ) ;53 St r ing oper=req . getParameter ( ” oper ” ) ;54 St r ing message=”” ;55 double suma=0;56 i f ( ! oper . equa l s ( ”con” ) ){57 St r ing s=req . getParameter ( ”suma” ) ;58 suma=Double . parseDouble ( s ) ;59 }60 Double objValue=null ;61 try{62 objValue=(Double ) cs . g e tAt t r ibute ( mbeanObjectName , ”Cont” ) ;63 }64 catch ( Exception e ){65 message=”JMX−Error : ”+e . getMessage ( ) ;66 }67 double value=objValue . doubleValue ( ) ;68 double x ;69 Attr ibute curs=null ;70 switch ( oper ){71 case ”dep” :72 x=value+suma ;73 curs=new Attr ibute ( ”Cont” , x ) ;74 try{75 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;76 message=”S−a depus suma” ;77 }78 catch ( Exception e ){79 message=”JMX−Error : ”+e . getMessage ( ) ;80 }81 break ;82 case ” ext ” :83 i f ( value>=suma){84 x=value−suma ;85 curs=new Attr ibute ( ”Cont” , x ) ;86 try{87 cs . s e t A t t r i b u t e ( mbeanObjectName , curs ) ;88 message=”S−a ex t ra s suma” ;89 }90 catch ( Exception e ){91 message=”JMX−Error : ”+e . getMessage ( ) ;92 }93 }94 else {95 message=” Cererea nu poate f i i n d e p l i n i t a ” ;96 }97 break ;98 case ”con” :99 message=”Suma din cont e s t e ”+value+” un i t . ” ;

100 break ;101 }102 r e s . setContentType ( ” text /html” ) ;103 out . p r i n t l n ( ”<html>” ) ;104 out . p r i n t l n ( ”<head><t i t l e >Depozit</ t i t l e ></head>” ) ;105 out . p r i n t l n ( ”<body>” ) ;106 out . p r i n t l n ( ”<h1>Operat iuni Cont</h1>” ) ;107 out . p r i n t l n ( ”<p>” ) ;

Page 307: programare distribuita

13.1. STANDARD MBEAN 307

108 out . p r i n t l n ( message ) ;109 out . p r i n t l n ( ”</p>” ) ;110 out . p r i n t l n ( ”</body></html>” ) ;111 out . c l o s e ( ) ;112 }

114 public void doPost ( HttpServ letRequest req , HttpServletResponse r e s )115 throws Serv le tExcept ion , IOException{116 doGet ( req , r e s ) ;117 }118 }

Pagina de apelare a servlet-ului fiind (index.html)

1 <html>2 <head>3 <t i t l e> Serv l e t−ul He l lo </ t i t l e>4 </head>5 <body bgcolor=”#aaeeaa ”>6 <center>7 <h1> Pagina de &#238; nt re &#355; i n e r e a d e p o z i t u l u i </h1>8 <form method=” post ”9 action=” http :// l o c a l h o s t :8080/ appcont/ appdepozit ”>

10 <p>Introduce &#355; i :11 <p>Opera&#355; i a : <select name=” oper ” >12 <option value=”dep”>Depunere13 <option value=” ext ”>Extragere14 <option value=”con”>Consultare15 </ select>16 <p>17 <input type=” text ” name=”suma” value=”0”>18 <p>19 <input type=”submit” value=”Executa”>20 </form>21 </center>22 </body>23 </html>

Clientlul care urmareste de la distanta contul are codul

1 import javax . management . ObjectName ;2 import javax . management . MBeanInfo ;3 import javax . management . MBeanAttributeInfo ;4 import javax . management . MBeanConstructorInfo ;5 import javax . management . MBeanOperationInfo ;6 import javax . management . MBeanNot i f i cat ionInfo ;7 import javax . management . MBeanServerConnection ;8 import javax . management . N o t i f i c a t i o n ;9 import javax . management . N o t i f i c a t i o n L i s t e n e r ;

10 import javax . management . Att r ibuteChangeNot i f i ca t i on ;11 import javax . management . remote . JMXServiceURL ;12 import javax . management . remote . JMXConnector ;13 import javax . management . remote . JMXConnectorFactory ;

15 public class C l i e n t N o t i f {16 public stat ic void main ( St r ing [ ] a rgs ) {17 St r ing host=” l o c a l h o s t ” ;18 St r ing port=”1099” ;19 i f ( args . l ength==0){

Page 308: programare distribuita

308 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

20 System . out . p r i n t l n ( ”The Server name i s r equ i r ed ” ) ;21 System . e x i t ( 0 ) ;22 }23 i f ( args . length >=2) host=args [ 1 ] ;24 i f ( args . length >=3) port=args [ 2 ] ;25 C l i e n t N o t i f obj=new C l i e n t N o t i f ( ) ;26 try {27 // Crearea unui conector s i a o b i e c t u l u i de28 // t i p MBeanServerConnection29 St r ing s u r l=” s e r v i c e : jmx : rmi :/// j n d i /rmi : // ” +30 host+” : ”+port+”/”+args [ 0 ] ;31 JMXServiceURL u r l = new JMXServiceURL( s u r l ) ;32 JMXConnector jmxc = JMXConnectorFactory . connect ( ur l , null ) ;33 MBeanServerConnection cs = jmxc . getMBeanServerConnection ( ) ;

35 St r ing domain = cs . getDefaultDomain ( ) ;36 System . out . p r i n t l n ( ”DefaultDomain : ” +domain ) ;37 // Crearea o b i e c t u l u i OBjectName a t a s a t MBean−u l u i Cont38 St r ing className=”Cont” ;39 St r ing sObjectName=domain+” : type=”+className ;40 ObjectName mbeanObjectName = new ObjectName ( sObjectName ) ;

42 MBeanInfo i n f o=cs . getMBeanInfo ( mbeanObjectName ) ;43 getMBeanResources ( i n f o ) ;

45 // U t i l i z a r e a n o t i f i c a r i i46 // Crearea unui a s c u l t a t o r47 C l i e n t L i s t e n e r l i s t e n e r = new C l i e n t L i s t e n e r ( ) ;48 // Act ivarea n o t i f i c a t o r u l u i49 cs . a d d N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r , null , obj ) ;

51 Thread . s l e e p ( 5 0 0 ) ;52 // D i s p o n i b i l i z a r e a a s c u l t a t o r u l u i de n o t i f i c a r i53 System . out . p r i n t l n ( ” Press Enter to f i n i s h ! ” ) ;54 try{55 System . in . read ( ) ;56 }57 catch ( java . i o . IOException e ){}58 cs . r e m o v e N o t i f i c a t i o n L i s t e n e r ( mbeanObjectName , l i s t e n e r ) ;59 // D i s p o n i b i l i z a r e a o b i e c t u l u i MBeanObjectName60 cs . unregisterMBean ( mbeanObjectName ) ;61 }62 catch ( Exception e ) {63 System . out . p r i n t l n ( e . getMessage ( ) ) ;64 e . pr intStackTrace ( ) ;65 }66 }

68 private stat ic void getMBeanResources ( MBeanInfo i n f o ) { . . .}69 }

71 class C l i e n t L i s t e n e r implements N o t i f i c a t i o n L i s t e n e r {72 public void h a n d l e N o t i f i c a t i o n ( N o t i f i c a t i o n n o t i f i c a t i o n ,73 Object handback ){74 System . out . p r i n t l n ( ”\nReceived n o t i f i c a t i o n : ” + n o t i f i c a t i o n ) ;75 Attr ibuteChangeNot i f i ca t i on myNotif=76 ( Att r ibuteChangeNot i f i ca t i on ) n o t i f i c a t i o n ;77 System . out . p r i n t l n ( ” Sold i n i t i a l : ” +78 myNotif . getOldValue ( ) . t oS t r i ng ( ) ) ;

Page 309: programare distribuita

13.1. STANDARD MBEAN 309

79 System . out . p r i n t l n ( ” Sold curent : ” +80 myNotif . getNewValue ( ) . t oS t r i ng ( ) ) ;81 }82 }

Serverul MBean este cel prezentat ın Exemplul 13.1.5.Serverul MBean este plasat ın servlet (ın catalogul WEB-INF/classes al

aplicatiei) iar clientul care urmareste de la distanta se poate afla oriunde.Dupa instalarea servlet-ului se lanseaza pe masina acestuia server-ul MBean.

Deoarece notificarea presupune existenta MBean-ului, iar acesta se instanteazaprin metoda init a servlet-ului este nevoie de apelarea servlet-ului, depunand0 unitati. Dupa aceasta operatie se lanseaza ın executie programul ClientNotif.

Intrebari recapitulative

1. Ce posibilitate ofera Java Management Extensions (JMX) ?

2. Care este structute unui MBean standard ?

3. Precizati continutul unui server MBean cu agenti la distanta.

4. Precizati termenul de notificare ın legatura cu MBean.

Page 310: programare distribuita

310 CAPITOLUL 13. JAVA MANAGEMENT EXTENSIONS

Page 311: programare distribuita

Partea III

ANEXE

311

Page 312: programare distribuita
Page 313: programare distribuita

Anexa A

Unelte de dezvoltare

Incepem aceasta sectiune prin a introduce cateva elemente privind sintaxaunui document xml.

A.1 XML

EXtensible Markup Language (XML) reprezinta un limbaj pentru definireamarcajelor de semantica, care ımpart un document ın parti identificabile ındocument. Din 1998, XML este un standard World Wide Web Consortium(W3C).

Totodata XML este un meta-limbaj pentru definirea sintaxei de utilizat ınalte domenii.

XML descrie structura si semantica si nu formatarea.Structura unui document XML este

<?xml version="1.0" encoding="tip_codare" [standalone="yes"]?>

corpul documentului alcatuit din elemente

Prima linie - preambulul - reprezinta declaratia de document XML. Tipulcodarii poate fi utf-8, iso-8859-1.

Corpul documentului este alcatuit din elemente. Inceputul unui elementeste indicat printr-un marcaj. Textul marcajului constituie denumirea elemen-tului. Elementele pot fi cu corp, alcatuit din alte elemente, avand sintaxa

<marcaj>

corpul elementului

</marcaj>

313

Page 314: programare distribuita

314 ANEXA A. UNELTE DE DEZVOLTARE

sau fara corp, caz ın care sintaxa este

<marcaj/>

Un marcaj poate avea atribute date prin sintaxa

numeAtribut="valoareAtribut"

Valoarea unui atribut este cuprinsa ıntre ghilimele (””).

<marcaj numeAtribut="valoareAtribut" . . .>

corpul elementului

</marcaj>

Exista un singur element radacina. Elementele unui document XML formeazaun arbore. Fiecarui marcaj de ınceput al unui element trebuie sa-i corespundaun marcaj de sfarsit. Caracterele mari si mici din denumirea unui element suntdistincte (case sensitive).

Elementele ıncuibarite (nested)- incluse ıntr-un alt element - nu se potamesteca, adica un marcaj de sfarsit corespunde ultimului marcaj de ınceput.

Un comentariu se indica prin

<!--

Text comentariu

-->

Exemplul A.1.1 Fisier XML - denumirile elementelor si continutul lor permitıntelegerea simpla a semanticii introduse ın document.

1 <?xml version=” 1 .0 ” encoding=” utf−8”?>2 <c u r s u r i>3 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>4 <nume> Anal iza numerica </nume>5 <fond−de−timp>6 <curs> 2 </ curs>7 <seminar> 1 </ seminar>8 <l a b o r a t o r> 1 </ l a b o r a t o r>9 </ fond−de−timp>

10 </ d i s c i p l i n a>11 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>12 <nume> Programare d i s t r i b u i t a </nume>13 <fond−de−timp>14 <curs> 2 </ curs>15 <seminar> 0 </ seminar>16 <l a b o r a t o r> 2 </ l a b o r a t o r>17 </ fond−de−timp>18 </ d i s c i p l i n a>19 <d i s c i p l i n a f e l=” o b l i g a t o r i u ”>

Page 315: programare distribuita

A.1. XML 315

20 <nume> So f t matematic </nume>21 <fond−de−timp>22 <curs> 2 </ curs>23 <seminar> 0 </ seminar>24 <l a b o r a t o r> 1 </ l a b o r a t o r>25 </ fond−de−timp>26 </ d i s c i p l i n a>27 </ c u r s u r i>

Un document XML este bine formatat daca:

• exista preambul;

• fiecare element este ınchis sau ıi corespunde un marcaj de inchidere;

• marcajele ıncuibarite nu se amesteca.

Un document XML este valid daca

• este bine formatat;

• ın cazul ca exista o referinta catre XML Schema atunci documentul XMLeste conform schemei.

Un produs informatic accesibil gratuit, care permite verificarea bine for-matarii si a validitatii unui document xml, este XML Copy Editor.

Pentru validare, daca fisierul XML Schema se afla ın alt catalog decat cel alfiserului xml atunci acestuia i se asociaza XML Schema prin XML→ Associate→ XML Schema. . .

Prelucrarea unui document XML ın Java se poate face pe baza interfetelorde programare:

• Document Object Model - DOM;

• Simple API for XML - SAX;

• Stream API for XML - StAX;

• Java Architecture for XML Binding - JAXB.

Amintim faptul ca reprezentarea obiectelor matematice prin elemente XMLconstituie subiectul a doua proiecte MathML si OpenMath. Obiectivul limbaju-lui MathML este reprezentarea unui text matematic ıntr-un document HTML,ın timp ce obiectivul proiectului OpenMath este reprezentarea semantica adatelor matematice pentru realizarea de aplicatii cooperante ıntre sisteme decalcul simbolic - CAS (Computer Algebra System).

Page 316: programare distribuita

316 ANEXA A. UNELTE DE DEZVOLTARE

A.2 apache-ant

Utilitarul apache-ant asigura executarea unui sir de comenzi de operare.Aceste comenzi se ınregistreaza ıntr-un fisier de tip xml, cu denumirea build.xml.Astfel, apache-ant se substituie unui fisier de comenzi bat ın Windows sau unuiscript shell din Linux/Unix. Avantajul obtinut consta ın independenta fata deplatforma de calcul (Windows, Linux).

Instalarea consta ın dezarhivarea fisierului descarcat din Internet.Lansarea ın executie necesita fixarea variabilei de mediu JAVA HOME, ce

contine calea la distributia Java. Lansarea se poate face prin urmatorul fisierde comenzi

set JAVA_HOME=. . .

set ANT_HOME=. . .

%ANT_HOME%\bin\ant.bat %1

Parametrul %1 acestui fisier de comenzi reprezinta obiectivul care se dorestea fi atins. Daca se modifica denumirea sau locatia fisierului build.xml atuncifisierul de comenzi se invoca cu optiunea -buildfile.

Un fisier build.xml corespunde unui proiect (project), alcatuit din unulsau mai multe obiective (target). Atingerea fiecararui obiectiv consta dinındeplinirea uneia sau mai multor sarcini (task). Apache-ant contine o familiepredefinita de sarcini. Programatorul are datoria fixarii atributelor sarcinilor.Manualul din documentatia produsului contine descrierea atributelor cat siexemple. In general, o sarcina reprezinta o operatie executata uzual ın liniade comanda.

Atributele se dau, respectand sintaxa XML

numeAtribut = ”valoareAtribut”

Astfel, un proiect apare sub forma

<project name="numeProiect"

default="obiectiv"

basedir="catalogDeReferinta">

<target name="numeObiectiv">

sarcini

</target>

. . . . . . .

</project>

Page 317: programare distribuita

A.2. APACHE-ANT 317

Daca la apelarea lui Apache-ant lipseste parametrul optional atunci se vaexecuta obiectivul default.

Intr-un proiect se pot defini variabile prin marcajul

<property name=”numeVariabila” value=”valoareVariabila” />

O variabila definita se va utiliza cu sintaxa ${numeVariabila}.

Exemplul A.2.1 Fisierul build pentru executia programelor din §1.2.

1 <p r o j e c t name=” Socket ” default=” Server ” ba s ed i r=” . ”>2 <d e s c r i p t i o n> S o c l u r i TCP </ d e s c r i p t i o n>

4 < !−− s e t g l o b a l p r o p e r t i e s f o r t h i s b u i l d −−>5 <property name=” bu i ld ” l o c a t i o n=”work”/>6 <property name=” s r c ” l o c a t i o n=” . ” />

8 <t a r g e t name=” i n i t ”>9 < !−− Create the time stamp −−>

10 <tstamp/>11 < !−− Create the b u i l d d i r e c t o r y s t r u c t u r e used by compile −−>12 <d e l e t e d i r=”${ bu i ld }”/>13 <mkdir d i r=”${ bu i ld }”/>14 </ t a r g e t>

16 <t a r g e t name=”Compile” depends=” i n i t ” d e s c r i p t i o n=” compile the source ” >17 <javac s r c d i r=”${ s r c }” d e s t d i r=”${ bu i ld }” inc ludeantrunt ime=” f a l s e ”/>18 </ t a r g e t>

20 <t a r g e t name=” Server ” depends=”Compile”>21 <java classname=”MyMServer” c l a s s pa th=”${ bu i ld }” f o rk=” true ”/>22 </ t a r g e t>

24 <t a r g e t name=” Cl i en t ”>25 <java classname=”VisualCmmdcClient” c l a s sp a t h=”${ bu i ld }” f o rk=” true ”/>26 </ t a r g e t>27 </ p r o j e c t>

Utilizarea lui apache-ant presupune ca toate resursele utilizate, cuprinseuzual ın fisiere cu extensia jar (j ava arhive) sunt disponibile pe calculatorullocal. Daca calculatorul este conectat la Internet, atunci resursele publicepot fi descarcate ımpreuna cu toate dependintele si utilizate prin apache-ant,folosind suplimentar apache-ivy 1.

In vederea utilizarii lui apache-ivy se copiaza fisierul ivy-*.jar din distributiaapache-ivy ın ANT HOME\lib.

Fisierul build.xml contine ın plus

1Asemanator cu maven, un alt produs de dezvoltare.

Page 318: programare distribuita

318 ANEXA A. UNELTE DE DEZVOLTARE

<project name="Proiect" basedir="." default="obiectiv_final"

xmlns:ivy="antlib:org.apache.ivy.ant">

. . .

<!-- =================================

target: resolve

================================= -->

<target name="resolve" depends="init"

description="--> retreive dependencies with ivy">

<ivy:retrieve/>

</target>

<!-- =================================

target: report

================================= -->

<target name="report" depends="resolve"

description="--> generates a report of dependencies">

<ivy:report todir="${report.dir}"/>

</target>

. . .

</project>

la care se adauga un fisier ivy.xml, cu dependintele necesare aplicatiei careurmeaza a fi preluate dintr-unul din depozitele ivy - local, shared, public

<ivy-module version="2.0">

<info organisation="cs.unitbv.ro" module="Biblioteca-Ivy"/>

<dependencies>

<dependency org="commons-fileupload" name="commons-fileupload" rev="1.2"/>

. . .

</dependencies>

</ivy-module>

A.3 apache-maven

Apache-maven2 este un alt cadru de dezvoltare si gestiune a proiectelor(Project management framework). Calculatorul pe care se dezvolta proiectul/ aplicatia trebuie sa fie conectat la internet. Resursele necesare ındeplinitiidiferitelor sarcini (maven artifacts) sunt preluate din internet si depuse ıntr-un depozit local maven (local repository). In prezent sunt ıntretinute depozite

2Maven – acumulator de cunostiinte (Idis).

Page 319: programare distribuita

A.3. APACHE-MAVEN 319

publice de resurse soft necesare dezvoltarii de aplicatii cu maven3 iar dez-voltatorii de instrumente soft au posibilitatea de a-si promova produsele prindepunerea ıntr-un depozit maven. Dintr-un asemenea depozit public resurselenecesare sunt descarcate ın depozitul local.

Gestiunea proiectelor cu apache-maven

Instalarea produsului consta ın dezarhivarea fisierului descarcat din in-ternet ıntr-un catalog MAVEN HOME.

Utilizarea produsului necesita

• Completarea variabilei de sistem PATH cu calea MAVEN HOME\bin.

• Declararea variabilei JAVA HOME avand ca valoare calea catre distributiajdk folosita.

In mod obisnuit depozitul local maven este

C:\Documents and Settings\client\.m2\repositoryLocatia depozitului local se poate modifica, introducand elementul

<localRepository>volum:/cale/catalog_depozit</localRepository>

ın fisierul MAVEN HOME\conf\settings.xml.Potrivit principiului separarii preocuparilor (Separation of Conserns), un

proiect maven produce o singura iesire.Declararea unui proiect se face printr-un fisier pom.xml (Project Object

Model). Este sarcina programatorului sa completeze fisierul pom.xml, creatla generarea structurii de cataloage ale proiectului, cu specificarea resurselorsuplimentare sau a conditionarilor ın efectuarea unor operatii (de exemplu,prezenta adnotarilor necesita utilizarea versiunii Java ≥ 1.5).

Dezvoltarea unei aplicatii / proiect prin maven presupune generarea uneistructuri de cataloage (Standard directory layout for projects). Aceasta struc-tura de cataloage este specifica tipului / sablonului de aplicatie (archetype, ınlimbajul maven).

Sabloane uzuale de aplicatii:

Nume sablon Semnificatia

maven-archetype-quickstart aplicatie simpla(sablonul implicit)

maven-archetype-webapp aplicatie Webmaven-archetype-j2ee-simple aplicatie JEE

3De exemplu repo1.maven.org/maven2.

Page 320: programare distribuita

320 ANEXA A. UNELTE DE DEZVOLTARE

Sablonul se specifica ın parametrul -DarchetypeArtifactId al comenziimvn archetype:create.

Indeplinirea diferitelor obiective (generarea unui proiect, compilare, arhivare,testare, etc) se obtin prin comenzi maven.

Comenzile maven sunt de doua tipuri:

• Comenzi pentru gestiunea ciclului de viata al unui proiect (lifecycle com-mands):

Comanda maven Semnificatia

mvn -version afiseaza versiunea maven(utila pentru verificarea functionarii lui maven)

mvn clean sterge fisierele maven generatemvn compile compilarea sursele Javamvn test-compile compileaza sursele Java care

realizeaza testele junit

mvn test executa testul junitmvn package creaza o arhiva jar sau warmvn install depune arhiva jar sau war ın depozitul local

• Comenzi de operare inserate (plugin commands):

Page 321: programare distribuita

A.3. APACHE-MAVEN 321

Comanda maven Semnificatia

mvn archetype:create genereaza structura de cataloage a proiectuluimvn archetype:create \-DgroupId=numelePachetuluiAplicatiei \-DartifactId=numeleProiectului \-DarchetypeArtifactId=numeSablon

mvn archetype:generate genereaza structura de cataloage a proiectuluisablonul se alege dintr-o lista

mvn clean:clean sterge fisierele generate ın urma compilariimvn compiler:compile compilarea sursele Javamvn surefire:test executa testul junitmvn jar:jar creaza o arhiva jarmvn install:install-file depune o arhiva jar ın depozitul local

mvn install:install-file \-Dfile=numeFisier \-DgroupId=numePachet \-DartifactId=numeProiect \-Dversion=versiunea \-Dpackaging=tipArhiva

mvn exec:java executa metoda main a unei clasemvn exec:java -Dexec.mainClass=”clasaMetodeiMain”

Astfel comanda

mvn archetype:create -DgroupId=unitbv.cs.calcul -DartifactId=hello

-DarchetypeArtifactId=maven-archetype-quickstart

genereaza arborescenta

hello

|--> src

| |--> main

| | |--> java

| | | |--> unitbv

| | | | |--> cs

| | | | | |--> calcul

| | | | | | | App.java

| |--> test

| | |--> java

| | | |--> unitbv

| | | | |--> cs

| | | | | |--> calcul

| | | | | | | AppTest.java

| pom.xml

Descrierea proiectului este data ın fisierul pom.xml generat

Page 322: programare distribuita

322 ANEXA A. UNELTE DE DEZVOLTARE

1 <p r o j e c t xmlns=” h t t p : //maven . apache . org /POM/ 4 . 0 . 0 ”2 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”3 xs i : s chemaLocat ion=” h t t p : //maven . apache . org /POM/ 4 . 0 . 04 h t t p : //maven . apache . org /maven−v4 0 0 . xsd”>5 <modelVersion>4 . 0 . 0</ modelVersion>6 <groupId>unitbv . cs . c a l c u l</ groupId>7 <a r t i f a c t I d>h e l l o</ a r t i f a c t I d>8 <packaging> j a r</ packaging>9 <version>1.0−SNAPSHOT</version>

10 <name>h e l l o</name>11 <u r l>h t t p : //maven . apache . org</ u r l>12 <dependenc ies>13 <dependency>14 <groupId> j u n i t</ groupId>15 <a r t i f a c t I d> j u n i t</ a r t i f a c t I d>16 <version>3 . 8 . 1</version>17 <scope>t e s t</ scope>18 </dependency>19 </ dependenc ies>20 </ p r o j e c t>

App.java este programul Java HelloWorld iar AppTest.java este un pro-gram de verificare bazat pe junit.

Pentru testarea aplicatiei, din catalogul hello se executa comenzile

mvn compile

mvn test

Sarcina programatorul este acela de a ınlocui aceste programe cu cele carerezolva sarcinile proiectului. Pentru orice prelucrare toate dependintele trebuiesa se gaseasca ın depozitul local maven.

Exemplul A.3.1 Dezvoltarea aplicatiei de calcul al celui mai mare divizorcomun a doua numere naturale utilizand maven.

Generam proiectul maven

mvn archetype:create -DgroupId=simple.app.cmmdc -DartifactId=cmmdc

-DarchetypeArtifactId=maven-archetype-quickstart

Inlocuim clasa App cu

1 package s imple . app . cmmdc ;2 public class MyCmmdc{3 private long m, n ;4 MyCmmdc( long m, long n){5 this .m=m;6 this . n=n ;7 }

9 public long cmmdc ( ) { . . .}10 }

si

Page 323: programare distribuita

A.3. APACHE-MAVEN 323

1 package s imple . app . cmmdc ;2 import java . u t i l . Scanner ;

4 public class App{5 public stat ic void main ( St r ing [ ] a rgs ){6 Scanner scanner=new Scanner ( System . in ) ;7 System . out . p r i n t l n ( ”m=” ) ;8 long m=scanner . nextLong ( ) ;9 System . out . p r i n t l n ( ”n=” ) ;

10 long n=scanner . nextLong ( ) ;11 MyCmmdc obj=new MyCmmdc(m, n ) ;12 System . out . p r i n t l n ( ”cmmdc = ”+obj . cmmdc ( ) ) ;13 }14 }

iar programul de testare AppTest.java prin

1 package s imple . app . cmmdc ;2 import org . j u n i t . ∗ ;3 import stat ic org . j u n i t . Assert . ∗ ;

5 public class TestPro i ec t {6 MyCmmdc obj ;7 long r e z ;

9 @Before10 public void setUp ( ) {}

12 @Test13 public void testCmmdc1 ( ){14 obj=new MyCmmdc( 5 6 , 4 2 ) ;15 r e z=obj . cmmdc ( ) ;16 a s s e r tEqua l s (14 , r e z ) ;17 }

19 @Test20 public void testCmmdc2 ( ){21 obj=new MyCmmdc( 4 5 , 3 1 ) ;22 r e z=obj . cmmdc ( ) ;23 a s s e r tEqua l s (1 , r e z ) ;24 }

26 public stat ic void main ( St r ing args [ ] ) {27 org . j u n i t . runner . JUnitCore . main ( ” p r o i e c t . Tes tPro i ec t ” ) ;28 }29 }

Intrucat dorim sa folosim cea mai recenta versiune a produsului junitmodificam ın fisierul pom.xml precizand versiunea junit cat si versiunea distributieijdk utilizata, care trebuie sa fie cel putin 1.5 (restrictie impusa mai nou dejunit).

1 <p r o j e c t xmlns=” h t t p : //maven . apache . org /POM/ 4 . 0 . 0 ”2 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”3 xs i : s chemaLocat ion=” h t tp : //maven . apache . org /POM/ 4 . 0 . 04 h t t p : //maven . apache . org /maven−v4 0 0 . xsd”>5 <modelVersion>4 . 0 . 0</ modelVersion>

Page 324: programare distribuita

324 ANEXA A. UNELTE DE DEZVOLTARE

6 <groupId>unitbv . p r o i e c t .mycmmdc</ groupId>7 <a r t i f a c t I d>cmmdc</ a r t i f a c t I d>8 <packaging> j a r</ packaging>9 <version>1.0−SNAPSHOT</version>

10 <name>cmmdc</name>11 <u r l>h t t p : //maven . apache . org</ u r l>12 <dependenc ies>13 <dependency>14 <groupId> j u n i t</ groupId>15 <a r t i f a c t I d> j u n i t</ a r t i f a c t I d>16 <version>4 .11</version>17 <scope>t e s t</ scope>18 </dependency>19 </ dependenc ies>20 </ p r o j e c t>

Operarea poate fi

mvn archetype:create -DgroupId=simple.app.cmmdc -DartifactId=cmmdc

cd cmmdc

mvn compile

mvn test

mvn exec:java -Dexec.mainClass="simple.app.cmmdc.App"

maven cu ant

In maven se pot integra sarcini apache-ant pentru orice etapa al evolutieiunei aplicatii. Utilizarea consta ın completarea fisierului pom.xml cu

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-antrun-plugin</artifactId>

<executions>

<execution>

<phase>

<!-- etapa de viata : compile, package, install, test -->

</phase>

<configuration>

<tasks>

<!-- Exemplu

<property name="compile_classpath" refid="maven.compile.classpath"/>

<property name="runtime_classpath" refid="maven.runtime.classpath"/>

<property name="test_classpath" refid="maven.test.classpath"/>

<property name="plugin_classpath" refid="maven.plugin.classpath"/>

<echo message="compile classpath: ${compile_classpath}"/>

<echo message="runtime classpath: ${runtime_classpath}"/>

<echo message="test classpath: ${test_classpath}"/>

<echo message="plugin classpath: ${plugin_classpath}"/>

-->

</tasks>

</configuration>

<goals>

<goal>run</goal>

Page 325: programare distribuita

A.3. APACHE-MAVEN 325

</goals>

</execution>

</executions>

</plugin>

</plugins>

</build>

In elementul <tasks> se definesc sarcinile ant care se doresc executate lacomanda corespunzatoare prelucrarii etapei din evolutia proiectului maven -compile, package, install, test, etc.

Mai precis, elementele <echo> se ınlocuiesc cu sarcinile ant care se dorescefectuate.

Proprietatile se definesc ın elementul

<properties>

<nume.proprietate>valoare</nume.proprietate>

. . .

</properties>

RMI prin maven

Exemplul A.3.2 Aplicatia de calcul a celui mai mare divizor comun.

Corespunzator celor trei componente ale unei aplicatii RMI se genereazaıntr-un catalog comenzile maven

mvn archetype:create -DgroupId=i.cmmdc -DartifactId=i

mvn archetype:create -DgroupId=s.cmmdc -DartifactId=s

mvn archetype:create -DgroupId=c.cmmdc -DartifactId=c

Clasa App.java se ınlocuieste cu

Catalog Clase

i ICmmdc.javas CmmdcImpl.javac CmmdcClient.java

Fisierele pom.xml din s,c se completeaza cu

<dependency>

<groupId>i.cmmdc</groupId>

<artifactId>icmmdc</artifactId>

<version>1.0.0</version>

</dependency>

In catalogul aplicatiei se introduce fisierul pom.xml

Page 326: programare distribuita

326 ANEXA A. UNELTE DE DEZVOLTARE

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <p r o j e c t>3 <modelVersion>4 . 0 . 0</ modelVersion>4 <a r t i f a c t I d>cmmdc</ a r t i f a c t I d>5 <groupId>cmmdc</ groupId>6 <version>1 . 0 . 0</version>7 <name>RMI</name>8 <packaging>pom</ packaging>9 <modules>

10 <module> i</module>11 <module>s</module>12 <module>c</module>13 </modules>14 </ p r o j e c t>

Se executa:

1. mvn clean install

2. Din s

set Path=. . .\apache-maven-*\bin;%PATH%

set JAVA_HOME=. . .

start rmiregistry 1099

mvn -e exec:java -Dexec.mainClass="s.cmmdc.CmmdcImpl"

3. Din c

set Path=. . .\apache-maven-*\bin;%PATH%

set JAVA_HOME=. . .

mvn exec:java -Dexec.mainClass="c.cmmdc.CmmdcClient"

Dezvoltarea unui servlet prin maven

Dezvoltarea unui servlet prin maven4 se va exemplifica prin aplicatia ıncare servletul raspunde clientului cu mesajul Hi nume client, nume clientfiind parametru transmis de catre client la apelarea servlet-ului.

Container de servleti cu care lucreaza maven este jetty.Dezvoltarea revine la parcurgerea pasilor:

1. Generarea aplicatiei:

mvn archetype:create -DgroupId=hello

-DartifactId=helloname

-DarchetypeArtifactId=maven-archetype-webapp

4Iverson W., Building Web Applications with maven 2, http://www.java.net/author/will-iverson

Page 327: programare distribuita

A.3. APACHE-MAVEN 327

Se creaza structura de cataloage si fisiere

helloname

|--> src

| |--> main

| | |--> resources

| | |--> webapp

| | | |--> WEB-INF

| | | | | web.xml

| | | | index.jsp

| pom.xml

unde fisierul pom.xml este

1 <p r o j e c t xmlns=” h t t p : //maven . apache . org /POM/ 4 . 0 . 0 ”2 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”3 xs i : s chemaLocat ion=” h t t p : //maven . apache . org /POM/ 4 . 0 . 04 h t t p : //maven . apache . org /maven−v4 0 0 . xsd”>5 <modelVersion>4 . 0 . 0</ modelVersion>6 <groupId>h e l l o</ groupId>7 <a r t i f a c t I d>hel loname</ a r t i f a c t I d>8 <packaging>war</ packaging>9 <version>1.0−SNAPSHOT</version>

10 <name>hel loname Maven Webapp</name>11 <u r l>h t t p : //maven . apache . org</ u r l>12 <dependenc ies>13 <dependency>14 <groupId> j u n i t</ groupId>15 <a r t i f a c t I d> j u n i t</ a r t i f a c t I d>16 <version>3 . 8 . 1</version>17 <scope>t e s t</ scope>18 </dependency>19 </ dependenc ies>20 <bu i ld>21 <f inalName>hel loname</ finalName>22 </ bu i ld>23 </ p r o j e c t>

2. Completarea aplicatiei.

• Se completeaza structura creata anterior cu

helloname

|--> src

| |--> main

| | |--> java

| | | |--> hello

| | | | | HelloServlet.java

| | |--> resources

| | |--> webapp

| | | |--> WEB-INF

| | | | | web.xml

| | | | index.html

| pom.xml

HelloServlet.java este cel utilizat ın capitolul Servlet din cursul deProgramare distribuita.

Page 328: programare distribuita

328 ANEXA A. UNELTE DE DEZVOLTARE

• Fisierul web.xml este completat cu elementele specifice servlet-ului(servlet si servlet-mapping).

1 < !DOCTYPE web−app PUBLIC2 ”−//Sun Microsystems , Inc . //DTD Web Appl i ca t ion 2 .3//EN”3 ” h t tp : // java . sun . com/dtd/web−app 2 3 . dtd” >

5 <web−app>6 <di sp lay−name>Archetype Created Web Appl i ca t ion</ d i sp lay−name>7 <s e r v l e t>8 <s e r v l e t−name>h e l l o</ s e r v l e t−name>9 <s e r v l e t−c l a s s>h e l l o . H e l l o S e r v l e t</ s e r v l e t−c l a s s>

10 </ s e r v l e t>11 <s e r v l e t−mapping>12 <s e r v l e t−name>h e l l o</ s e r v l e t−name>13 <ur l−pattern>/ h e l l o</ ur l−pattern>14 </ s e r v l e t−mapping>15 </web−app>

• Fisierul index.jsp se ınlocuieste cu fisierul index.html utilizat laservletul mentionat anterior5.

• Fisierul pom.xml se completeaza cu

– Referintele la resursele javax.servlet.servlet-api, nece-sare compilarii.<dependency>

<groupId>javax.servlet</groupId>

<artifactId>servlet-api</artifactId>

<version>2.5</version>

<scope>provided</scope>

</dependency>

– Referintele serverului Web jetty<plugins>

<plugin>

<groupId>org.mortbay.jetty</groupId>

<artifactId>maven-jetty-plugin</artifactId>

</plugin>

</plugins>

Codul fisierului pom.xml devine

1 <p r o j e c t xmlns=” h t t p : //maven . apache . org /POM/ 4 . 0 . 0 ”2 xmlns :x s i=” h t t p : //www. w3 . org /2001/XMLSchema−i n s t ance ”3 xs i : s chemaLocat ion=” h t tp : //maven . apache . org /POM/ 4 . 0 . 04 h t t p : //maven . apache . org /maven−v4 0 0 . xsd”>5 <modelVersion>4 . 0 . 0</ modelVersion>6 <groupId>h e l l o</ groupId>7 <a r t i f a c t I d>hel loname</ a r t i f a c t I d>8 <packaging>war</ packaging>9 <version>1.0−SNAPSHOT</version>

10 <name>hel loname Maven Webapp</name>11 <u r l>h t t p : //maven . apache . org</ u r l>12 <dependenc ies>

5Atentie la parametri de apelare a servlet-ului, care eventual trebuie adaptati. Contextulaplicatiei coincide cu parametrul artifactId

Page 329: programare distribuita

A.3. APACHE-MAVEN 329

13 <dependency>14 <groupId> j u n i t</ groupId>15 <a r t i f a c t I d> j u n i t</ a r t i f a c t I d>16 <version>3 . 8 . 1</version>17 <scope>t e s t</ scope>18 </dependency>19 <dependency>20 <groupId>javax . s e r v l e t</ groupId>21 <a r t i f a c t I d>s e r v l e t−api</ a r t i f a c t I d>22 <version>2 .5</version>23 <scope>provided</ scope>24 </dependency>25 </ dependenc ies>26 <bu i ld>27 <f inalName>hel loname</ finalName>28 <p lug in s>29 <p lug in>30 <groupId>org . mortbay . j e t t y</ groupId>31 <a r t i f a c t I d>maven−j e t ty−p lug in</ a r t i f a c t I d>32 </ p lug in>33 </ p lug in s>34 </ bu i ld>35 </ p r o j e c t>

Clauza provided din elementul <scope> implica ne includerearesursei in arhiva war.

3. Prelucrarea revine la

(a) compilare: mvn compile

(b) arhivare: mvn package

(c) lansarea serverului Web jetty : mvn jetty:run

Serverul se opreste cu Ctrl+C.

(d) testarea servlet-ului: ıntr-un navigator se deschide paginahttp://localhost:8080/helloname.

Pentru a utiliza serverul Web apache-tomcat este suficient sa

1. desfasuram arhiva war: mvn tomcat:deploy

2. lansam serverul Web ın lucru: mvn tomcat:run

Serverul se opreste cu Ctrl+C.

Aplicatie JSP prin maven

Ne propunem sa calculam cel mai mare divizor comun a doua numere natu-rale ıntr-o pagina JSP utilizand o componenta Java pentru calculul propriu-zis(cf. cursului de Programare distribuita).

Page 330: programare distribuita

330 ANEXA A. UNELTE DE DEZVOLTARE

Deoarece maven produce o singura iesire se vor realiza doua proiecte maven:unul pentru componenta Java, care va fi arhivata si depusa ın depozitul localiar celalalt pentru aplicatia JSP.

1. Realizarea componentei Java.

(a) Generarea proiectului maven

mvn archetype:create -DgroupId=cmmdc -DartifactId=cmmdcjsp

Se ınlocuieste clasa App.java cu clasa CmmdcBean (curs Programaredistribuita).

(b) Prelucrarea consta din

i. mvn compile

ii. mvn package

iii. mvn install

2. Realizarea aplicatiei JSP.

(a) Generarea cadrului:

mvn archetype:create -DgroupId=jsp -DartifactId=cmmdcjsp

-DarchetypeArtifactId=maven-archetype-webapp

(b) Dezvoltarea aplicatiei:

i. Se completeaza aplicatia cu fisierele cmmdc.jsp si index.htmldin cursul Programare distribuita, desfasurarea fiindcmmdcjsp

|--> src

| |--> main

| | |--> resources

| | |--> webapp

| | | |--> WEB-INF

| | | | | web.xml

| | | index.html

| | | cmmdc.jsp

| pom.xml

ii. Fisierul pom.xml se completeaza cu referinta pentru compo-nenta Java<dependency>

<groupId>cmmdc</groupId>

<artifactId>cmmdcjsp</artifactId>

<version>1.0-SNAPSHOT</version>

</dependency>

si pentru serverul Web jetty<plugins>

<plugin>

<groupId>org.mortbay.jetty</groupId>

<artifactId>maven-jetty-plugin</artifactId>

</plugin>

</plugins>

Page 331: programare distribuita

A.3. APACHE-MAVEN 331

(c) Prelucrarea consta din

i. mvn package

ii. mvn jetty:run

Page 332: programare distribuita

332 ANEXA A. UNELTE DE DEZVOLTARE

Page 333: programare distribuita

Anexa B

Testare cu junit

Verificarea / testarea automata a programelor Java se poate face cu pro-dusul informatic junit. Deseori se formuleaza probleme de test ale caror rezul-tate sunt cunoscute, cu rolul de a verifica functionarea unui program de re-zolvare, pentru depistarea unor greseli.

S-a dezvoltat si o metodologie de lucru Test Driven Development - (TDD)care presupune pentru orice clasa elaborata realizarea unui program de testare,chiar a priori.

Un alt produs care are acelasi scop de verificare a rezultatelor este TestNG.junit permite verificarea automata a rezultatelor furnizate de un program,

pentru o multime de date de test.Instalarea produsului consta din dezarhivarea fisierului descarcat ıntr-un

catalog JUNIT HOME. Pentru compilare si executie, variabila de sistem classpath

trebuie sa contina referinta JUNIT HOME\junit-*.jar.Utilizarea produsului ıntr-un program Java consta din:

1. Declararea resurselor pachetului junit prinimport org.junit.*;

import static org.junit.Assert.*;

2. Declararea clasei cu testele junit - uzual ın metoda main.

org.junit.runner.JUnitCore.main("AppClass");

3. Eventuale operatii necesare ınainte sau dupa efectuarea testelor se pre-cizeaza respectiv, ın cate o metoda care a fost declarata cu [email protected] si respectiv, @org.junit.After.

4. Testele se definesc ın metode declarate cu adnotarea @org.junit.Test.

Clasa Assert poseda metodele de verificare ale unui rezultat:

333

Page 334: programare distribuita

334 ANEXA B. TESTARE CU JUNIT

• static void assertEquals(Tip asteptat, Tip actual)

unde Tip poate fi double, int, long, Object.

• static void assertEquals(double asteptat, double actual, doubledelta)

Testul reuseste daca |asteptat-actual | < delta.

• static void assertArrayEquals(Tip[ ] asteptat, Tip[ ] actual)

unde Tip poate fi byte, char, int, long, short, Object.

• static void assertTrue(boolean conditie)

• static void assertFalse(boolean conditie)

• static void assertNull(Object object)

• static void assertNotNull(Object object)

In cazul exemplului

1 import org . j u n i t . ∗ ;2 import stat ic org . j u n i t . Assert . ∗ ;

4 public class Exemplu{5 public double r e z u l t a t =1.0 ;6 public double eps=1e−6;

8 double getValue ( ){9 return 1 .0000001 ;

10 }

12 @Test13 public void t e s t ( ){14 a s s e r tEqua l s ( r e z u l t a t , getValue ( ) , eps ) ;15 }

17 public stat ic void main ( St r ing [ ] a rgs ){18 org . j u n i t . runner . JUnitCore . main ( ”Exemplu” ) ;19 }20 }

se obtine

JUnit version 4.5

.

Time: 0.03

OK (1 test)

Exemplul B.0.3 Testarea clasei App ( 2.2.1).

Page 335: programare distribuita

335

1 package s e r v e r ;2 import org . j u n i t . ∗ ;3 import stat ic org . j u n i t . Assert . ∗ ;

5 public class TestApp{6 private App app ;

8 @Before9 public void i n i t i a l i z a r e ( ){

10 app=new App ( ) ;11 }

13 @Test14 public void t e s t ( ){15 a s s e r tEqua l s (8 , app . cmmdc( 5 6 , 2 4 ) ) ;16 }

19 public stat ic void main ( St r ing [ ] a rgs ){20 org . j u n i t . runner . JUnitCore . main ( ” s e r v e r . TestApp” ) ;21 }22 }

Exemplul B.0.4 Testarea clasei MyMServer ( 2.2.1).

1 package s e r v e r . impl ;2 import s e r v e r . ∗ ;3 import org . j u n i t . ∗ ;4 import stat ic org . j u n i t . Assert . ∗ ;5 import java . net . ServerSocket ;6 import i s e r v e r . IMyMServer ;

8 public class TestMyMServer{9 private IMyMServer obj ;

11 @Before12 public void i n i t i a l i z a r e ( ){13 obj=new MyMServer ( ) ;14 }

16 @Test17 public void t e s t ( ){18 int port =7999;19 Object r e s u l t=obj . ge tServe rSocket ( port ) ;20 as se r tNotNul l ( ”Must not re turn a n u l l r e sponse ” , r e s u l t ) ;21 a s s e r tEqua l s ( ServerSocket . class , r e s u l t . g e tC la s s ( ) ) ;22 }

24 public stat ic void main ( St r ing [ ] a rgs ){25 org . j u n i t . runner . JUnitCore . main ( ” s e r v e r . impl . TestMyMServer” ) ;26 }27 }

Page 336: programare distribuita

336 ANEXA B. TESTARE CU JUNIT

Page 337: programare distribuita

Anexa C

Jurnalizare

Jurnalizarea adica afisarea / retinerea rezultatelor sau evenimentelor ıntr-un fisier. Deseori prezinta interes evolutia procesului de calcul prin prismaunor rezultate intermediare. In acest sens se pot utiliza:

• pachetul java.util.logging din jdk.

• apache-log4j-2.

• slf4j (Simple Logging Facade for Java), (www.QOS.ch, Quality of OpenSoftware).

• logback (logback.qos.ch).

Jurnalizare prin java.util.logging

Sablonul de programare cu afisarea mesajelor pe ecranul monitorului este

1 import java . u t i l . l o gg ing . Logger ;

3 public class Exemplu{4 stat ic Logger l o g g e r = Logger . getLogger ( Exemplu . class . getName ( ) ) ;

6 public stat ic void main ( St r ing args [ ] ) {7 l o g g e r . s eve r e ( ”SEVERE : He l lo ” ) ;8 l o g g e r . warning ( ”WARNING : He l lo ” ) ;9 l o g g e r . i n f o ( ”INFO : He l lo ” ) ;

10 }11 }

Programul afiseaza

Jan 23, 2013 2:34:40 PM Exemplu main

SEVERE: SEVERE : Hello

Jan 23, 2013 2:34:40 PM Exemplu main

337

Page 338: programare distribuita

338 ANEXA C. JURNALIZARE

WARNING: WARNING : Hello

Jan 23, 2013 2:34:40 PM Exemplu main

INFO: INFO : Hello

Daca dorim ca rezultatele sa fie ınscrise ıntr-un fisier, de exemplu logging.txtatunci clasa de mai sus se modifica ın

1 import java . u t i l . l o gg ing . Logger ;2 import java . u t i l . l o gg ing . F i l eHandler ;3 import java . u t i l . l o gg ing . SimpleFormatter ;4 import java . i o . IOException ;

6 public class Exemplu{7 stat ic Logger l o g g e r = Logger . getLogger ( Exemplu . class . getName ( ) ) ;

9 public stat ic void main ( St r ing [ ] a rgs ) {10 try{11 Fi l eHandle r l o g g i n g F i l e = new Fi l eHandle r ( ” l ogg ing . txt ” ) ;12 l o g g i n g F i l e . setFormatter (new SimpleFormatter ( ) ) ;13 l o g g e r . addHandler ( l o g g i n g F i l e ) ;14 }15 catch ( IOException e ){16 System . out . p r i n t l n ( e . getMessage ( ) ) ;17 }18 l o g g e r . s eve r e ( ”SEVERE : He l lo ” ) ;19 l o g g e r . warning ( ”WARNING : He l lo ” ) ;20 l o g g e r . i n f o ( ”INFO : He l lo ” ) ;21 }22 }

Jurnalizare prin logback

Jurnalizare cu retinerea rezultatelor ın fisier

1 package l o g t e s t ;2 import org . s l f 4 j . Logger ;3 import org . s l f 4 j . LoggerFactory ;

5 public class Exemplu{6 stat ic Logger l o g g e r=LoggerFactory . getLogger ( ”Exemplu” ) ;7 public stat ic void main ( St r ing args [ ] ) {8 l o g g e r . t r a c e ( ”TRACE : He l lo ” ) ;9 l o g g e r . debug ( ”DEBUG : He l lo ” ) ;

10 l o g g e r . i n f o ( ”INFO : He l lo ” ) ;11 l o g g e r . warn ( ”WARN : He l lo ” ) ;12 l o g g e r . e r r o r ( ”ERROR : He l lo ” ) ;13 }14 }

cu fisierul de configurare

1 <c o n f i g u r a t i o n>2 <appender name=”STDOUT” c l a s s=”ch . qos . logback . core . ConsoleAppender”>3 <encoder>4 <pattern>5 %d{HH:mm:ss . SSS} [%thread ] %−5l e v e l %l o g g e r {36} − %msg%n6 </ pattern>

Page 339: programare distribuita

339

7 </ encoder>8 </appender>

10 <appender name=”FILE” c l a s s=”ch . qos . logback . core . FileAppender ”>11 < f i l e>r e s u l t s . l og</ f i l e>12 <encoder>13 <pattern>14 %date %l e v e l [% thread ] %l o g g e r {10} [% f i l e :%l i n e ] %msg%n15 </ pattern>16 </ encoder>17 </appender>

19 <l o g g e r name=” l o g t e s t ” l e v e l=”TRACE”/>20 <root l e v e l=” t ra c e ”>21 <appender−r e f r e f=”STDOUT” />22 <appender−r e f r e f=”FILE” />23 </ root>24 </ c o n f i g u r a t i o n>

Jurnalizare prin apache-log4j-2

Jurnalizare cu retinerea rezultatelor ın fisier

1 import org . apache . l ogg ing . l o g 4 j . LogManager ;2 import org . apache . l ogg ing . l o g 4 j . Logger ;

4 public class Exemplu{5 stat ic Logger l o g g e r = LogManager . getLogger ( Exemplu . class ) ;

7 public stat ic void main ( St r ing args [ ] ) {8 l o g g e r . warn ( ”WARN : He l lo ” ) ;9 l o g g e r . debug ( ”DEBUG : He l lo ” ) ;

10 l o g g e r . i n f o ( ”INFO : He l lo ” ) ;11 l o g g e r . f a t a l ( ”FATAL : He l lo ” ) ;12 }13 }

cu fisierul de configurare

1 <?xml version=” 1 .0 ” encoding=”UTF−8”?>2 <c o n f i g u r a t i o n s t a t u s=”OFF”>3 <p r o p e r t i e s>4 <property name=” f i l ename ”>r e s u l t s . l og</ property>5 </ p r o p e r t i e s>6 <appenders>7 <Console name=” Console ” t a r g e t=”SYSTEM OUT”>8 <PatternLayout9 pattern=”%d{HH:mm:ss . SSS} [%t ] %−5l e v e l %l o g g e r {36} − %msg%n”/>

10 </ Console>11 <F i l e name=” F i l e ” f i leName=”${ f i l ename }”>12 <PatternLayout13 pattern=”%d{HH:mm:ss . SSS} [%t ] %−5l e v e l %l o g g e r {36} − %msg%n”/>14 </ F i l e>15 </ appenders>16 < l o g g e r s>17 <root l e v e l=” t ra c e ”>18 <appender−r e f r e f=” Console ”/>

Page 340: programare distribuita

340 ANEXA C. JURNALIZARE

19 <appender−r e f r e f=” F i l e ”/>20 </ root>21 </ l o g g e r s>22 </ c o n f i g u r a t i o n>

Page 341: programare distribuita

Anexa D

Componenta Java (Java Bean)

O componenta Java este o clasa care poate interactiona cu alte componenteJava, cu un document jsp, etc.

O componenta Java contine cel putin

• Un constructor fara nici un argument;

• O multime de campuri declarate private;

• Pentru fiecare asemenea camp

private Tip xyz;

trebuie definite cel putin una din metodele

public void setXyz(Tip xyz){

this.xyz=xyz;

}

public Tip getXyz(){

return xyz;

}

341

Page 342: programare distribuita

342 ANEXA D. COMPONENTA JAVA

Page 343: programare distribuita

Anexa E

Adnotari

O adnotare este o completare, o nota sau o ınsemnare care explica sauıntregeste un text.

O metadata este o adnotare a unei date.In Java o adnotare (annotation) este o metadata a unui element de cod

(identificator al unei entitati din codul Java).O adnotare poate sa-si faca efectul:

• asupra codului sursa, ınaintea compilarii;

• asupra codului obiect, dupa compilare, dar ınaintea executarii;

• ın timpul executiei codului.

Din punctul de vedere al sintaxei intereseaza

• definirea unei adnotari;

• declararea unei adnotari;

• procesarea unei adnotari.

E.1 Definirea unei adnotari

Sintaxa utilizata este

import java.lang.annotation.*;

modificator @interface NumeAdnotare{declarare Element 1

343

Page 344: programare distribuita

344 ANEXA E. ADNOTARI

declarare Element 2. . .

}unde declarare Element poate fi:

tip numeElement();tip numeElement() default valoare;

iar tip poate fi

• predefinit (int, short, long, byte, char, float, double, boolean);

• String

• Class

• enum

• adnotare

• tablou ale carei elemente sunt de un tip precizat anterior

Adnotarea se salveaza ca fisier text, sub numele NumeAdnotare.java.

Dupa numarul elementelor declarate ıntr-o adnotare, acesta poate fi

• 0 - caz ın care adnotarea este de tip marker;

• 1 sau mai multe elemente (single-element / multi-value annotation).

E.2 Declararea unei adnotari

O adnotare se poate referi la un pachet, clasa, interfata, metoda, camp.

Inaintea declararii elementului asupra caruia actioneaza, adnotarea se in-dica prin

@NumeAdnotare(numeElement 1=valoare,numeElement 2=valoare,. . . )

Page 345: programare distribuita

E.3. PROCESAREA UNEI ADNOTARI 345

E.3 Procesarea unei adnotari

Java declara adnotarile

Adnotari regulate Meta-adnotari

Override TargetDeprecated RetentionSuppressWarnings Documented

Inherited

Adnotarea Override

Adnotarea Override precizeaza faptul ca se suprascrie un element al claseiparinte.

1 import java . u t i l . Date ;2 public class TestOverr ide extends Date{3 @Override4 public St r ing toS t r i ng ( ){5 return super . t oS t r i ng ()+” TestOverr ide ” ;6 }

8 public stat ic void main ( St r ing [ ] a rgs ){9 Date d=new TestOverr ide ( ) ;

10 System . out . p r i n t l n (d . t oS t r i ng ( ) ) ;11 }12 }

Daca ın locul liniei 9 se pune Date d=new Date(); atunci nu mai aparemesajul TestOverride.

Adnotarea Deprecated

Adnotarea Deprecated are ca efect afisarea unui mesaj de avertisment ınmomentul compilarii.

Exemplificam cu clasele

1 public class MyDeprecated{2 @Deprecated3 public void doJob ( ){4 System . out . p r i n t l n ( ” This i s deprecated ” ) ;5 }6 }

1 public class TestDeprecated {2 public stat ic void main ( St r ing [ ] a rgs ){3 MyDeprecated obj=new MyDeprecated ( ) ;4 obj . doJob ( ) ;5 }6 }

Page 346: programare distribuita

346 ANEXA E. ADNOTARI

Mesajul de avertisment este

Note: TestDeprecated.java uses or overrides a deprecated API.

Note: Recompile with -Xlint:deprecation for details.

Comentand linia adnotarii are ca efect la o noua compilare disparitia mesajelorde avertisment.

Adnotarea SuppressWarnings

Adnotarea SuppressWarnings inhiba afisarea mesajelor de avertisment.Reluam exemplul anterior schimband clasa Test. In urma compilarii nu maiapar mesajele de avertisment mentionate mai sus.

1 @SuppressWarnings ( ” deprecat i on ” )2 public class TestSuppressWarnings{

4 public stat ic void main ( St r ing [ ] a rgs ){5 MyDeprecated obj=new MyDeprecated ( ) ;6 obj . doJob ( ) ;7 }8 }

Adnotarea Target

Adnotarea Target precizeaza elementul asupra careia actioneaza:

ElementType.TYPE

ElementType.FIELD

ElementType.METHOD

ElementType.PARAMETER

ElementType.CONSTRUCTOR

ElementType.LOCAL VARIABLE

ElementType.ANNOTATION TYPE

Adnotarea Retention

Adnotarea Retention precizeaza momentul actiunii adnotarii:RetentionPolicy.SOURCE

RetentionPolicy.CLASS

RetentionPolicy.RUNTIME

Page 347: programare distribuita

E.3. PROCESAREA UNEI ADNOTARI 347

Adnotarea Documented

Adnotarea Documented are ca efect mentionarea adnotarii ın documentulobtinut prin javadoc.

Fie clasele

1 import java . lang . annotat ion . Documented ;

3 @Documented4 public @inte r f a c e MyDocumented{}

si

1 public class TestDocumented{2 public stat ic void main ( St r ing [ ] a rgs ){3 new TestDocumented ( ) . doDocumented ( ) ;4 }

6 @MyDocumented7 public void doDocumented ( ){8 System . out . p r i n t l n ( ” Test Documented” ) ;9 }

10 }

javadoc se lanseaza prin

md docs

javadoc -d docs *Documented.java

Procesarea unei adnotari se refera ın primul rand la regasirea ın momentulexecutiei a valorilor elementelor adnotarii. In functie de valorile regasite se potimplementa actiuni specifice.

Procesarea unei adnotari se bazeaza pe metodele interfetei AnnotationElement,implementata de clasele Class, Constructor, Field, Method, Package:

• <T extends Annotation> T getAnnotation(Class<T> annotationClass)

• Annotation[] getAnnotations()

• Annotation[] getDeclaredAnnotations()

• boolean isAnnotationPresent(Class<? extends Annotation> an-notationClass)

Consideram adnotarea

1 import java . lang . annotat ion . Retent ion ;2 import java . lang . annotat ion . Target ;3 import java . lang . annotat ion . Retent ionPo l i cy ;4 import java . lang . annotat ion . ElementType ;

6 @Retention ( Retent ionPo l i cy .RUNTIME)

Page 348: programare distribuita

348 ANEXA E. ADNOTARI

7 @Target ( ElementType .METHOD)8 public @inte r f a c e MyAnnotation{9 St r ing doAction ( ) default ”” ;

10 int index ( ) default 0 ;11 }

pe care o utilizam ın clasa

1 import java . lang . r e f l e c t . Method ;

3 public class TestAnnotation{4 public stat ic void main ( St r ing [ ] a rgs ){5 TestAnnotation obj=new TestAnnotation ( ) ;6 obj . v e r i f ( obj ) ;7 }

9 @MyAnnotation ( doAction=”XYZ” , index =1)10 public void v e r i f ( Object o ){11 try{12 Class c l=o . ge tC la s s ( ) ;13 Method m=c l . getMethod ( ” v e r i f ” ,14 new Class [ ] { (new Object ( ) ) . g e tC la s s ( ) } ) ;15 i f (m. i sAnnotat ionPresent ( MyAnnotation . class ) ){16 MyAnnotation a=m. getAnnotat ion ( MyAnnotation . class ) ;17 i f ( a!=null ){18 St r ing numeElement=a . doAction ( ) ;19 System . out . p r i n t l n ( numeElement ) ;20 int index=a . index ( ) ;21 System . out . p r i n t l n ( index ) ;22 }23 }24 }25 catch ( Exception e ){26 System . out . p r i n t l n ( ”MyEx : ”+e . getMessage ( ) ) ;27 }28 }29 }

Clasa java.lang.Class furnizeaza o reprezentare (reflectare) a unei claseın timpul executiei. Metodapublic Method getMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException

furnizeaza o reprezentare (reflectare) a unei metode ın timpul executiei unuiprogram.

Page 349: programare distribuita

Anexa F

Utilizarea SGBD ın Java

Scopul acestei anexe este prezentarea bazelor utilizarii unui Sistem deGestiune a Bazelor de Date (SGBD - Data Bases Management System - DBMS)din Java. Exemplificam modul de operare si utilizare pentru crearea si ex-ploatarea unei baze de date corespunzatoare unei agende de adrese e-mail.

F.1 Derby / Javadb

Instalarea produsului consta ın dezarhivarea fisierului descarcat.Utilizarea produsului. Va fi utilizata varianta de retea bazata pe un

server al SGBD care utilizeaza implicit portul 1527.Se ıntreprind urmatoarele operatii:

1. Lansarea serverului Derby / Javadb:

set JAVA_HOME=. . .

set DB_HOME=. . .

set PATH=%DB_HOME%\bin;%PATH%

startNetworkServer.bat -h 0.0.0.0

Prezenta optiunii -h 0.0.0.0 asigura accesul la serverul SGBD de peorice calculator.

2. Crearea bazei de date se va face utilizand utilitarul ij din distributiaDerby / Javadb. Acesta se lanseaza prin:

set JAVA_HOME=. . .

set DB_HOME=. . .

set PATH=%DB_HOME%\bin;%PATH%

ij.bat

349

Page 350: programare distribuita

350 ANEXA F. UTILIZAREA SGBD IN JAVA

Exemplul F.1.1

Baza de date AgendaEMail se creaza executand

run ’CreateAgendaE.sql’;

unde fisierul CreateAgendaE.sql este

1 connect ’ jdbc : derby : AgendaEMail ; c r e a t e=true ’ ;2 create table adrese (3 id int generated always as identity ( s t a r t with 1 , increment by 1)4 primary key ,5 nume char (20) not null ,6 emai l char (30) not null7 ) ;

si ıncarcarea cu date

run ’ValuesAgendaE.sql’;

cu fisierul ValuesAgendaE.sql

1 insert into adrese (nume , emai l ) values ( ’ aaa ’ , ’ aaa@yahoo . com ’ ) ,2 ( ’ bbb ’ , ’ bbb@gmail . com ’ ) , ( ’ ccc ’ , ’ ccc@unitbv . ro ’ ) ,3 ( ’ aaa ’ , ’ xyz@unitbv . ro ’ ) ;

F.2 mysql

Instalarea produsului. Pentru instalare s-a descarcat varianta fara in-stalare automata mysqll-*.*.*-win*.zip. Acest fisier se dezarhiveaza ıntr-uncatalog MYSQL HOME.

Implicit, serverul mysql utilizeaza portul 3306, iar fisierele bazelor de datevor fi gazduite ın catalogul MYSQL HOME\data.

Pentru utilizarea ın aplicatii Java trebuie descarcat un conector mysql-connector-java-*.*.*.tar.gz, continand fisierul mysql-connector-java-*.*.*-bin.jar.

Utilizarea produsului.Se ıntreprind urmatoarele operatii:

1. Lansarea serverului mysql :

set MYSQL_HOME=. . .

set PATH=%MYSQL_HOME%\bin;%PATH%

mysqld

Page 351: programare distribuita

F.2. MYSQL 351

2. Accesul de pe orice calculator catre utilizatorul root din mysql se asiguraprin

grant all on *.* to root@’%’;

3. Unui utilizator i se poate atasa o parola, executand ıntr-o sesiune mysqlcomenzile

set password for ’root’@’localhost’=password(’parola’);

set password for ’root’@’127.0.01’=password(’parola’);

Parola se sterge prin

set password for ’root’@’localhost’=password(’’);

set password for ’root’@’127.0.01’=password(’’);

Daca utilizatorul are o parola atunci la apelarea utilitarului mysql va fiprezenta si optiunea -p.

4. Exemplul F.2.1

Crearea bazei de date AgendaEMail se va face prin intermediul fisieruluide comenzi

set MYSQL_HOME=d:\mysql-*-win32\bin

set path=%MYSQL_HOME%;%PATH%

mysql -u root -p< CreateAgendaE.sql

mysql -u root -p< ValuesAgendaE.sql

unde scriptul CreateAgendaE.sql este

1 create database AgendaEMail ;2 use AgendaEMail ;

4 create table adrese (5 id int primary key auto increment not null ,6 nume char (20) not null ,7 emai l char (30) not null8 ) ;

iar scriptul de populare cu date (ValuesAgendaE.sql) este

1 use AgendaEMail ;2 insert adrese values (1 , ”aaa” , ”aaa@yahoo . com” ) ;3 insert adrese values (2 , ”bbb” , ”bbb@gmail . com” ) ;4 insert adrese values (3 , ” ccc ” , ” ccc@unitbv . ro ” ) ;5 insert adrese values (1 , ”aaa” , ”xyz@unitbv . ro ” ) ;

5. Serverul mysql se opreste prin

set MYSQL_HOME=d:\mysql-*-win32

set PATH=%MYSQL_HOME%\bin;%PATH%

mysqladmin -u root shutdown

Page 352: programare distribuita

352 ANEXA F. UTILIZAREA SGBD IN JAVA

F.3 Sablonul de utilizare a unei baze de date

ıntr-un program Java

Interactiunea cu baze de date relationale implica:

1. Stabilirea corespondentei dintre date aflate ın obiecte si atribute / tabele(object to relational database mapping).

2. Apelarea actiunilor CRUD (Create, Read, Update, Delete).

Limbajul SQL (Structured Query Language) este dependent de SGBD uti-lizat. Dezvoltarea interactiunii dintre un program Java (client) cu o baza dedate dintr-un SGBD s-a nascut din dorinta de a asigura independenta stratuluiJava de SGBD. Solutia gasita consta ın introducerea unui strat suplimentar,ıntre Java si SGBD care asigura corespondenta ıntre obiectele Java cu tabeleleunei baze de date si permite o configurare simpla la schimbarea SGBD. Astfelse foloseste terminologia de aplicatie multistrat.

Materializarea acestor idei (Object Relational Mapping - ORM) se afla ın

• interfata de programare (API) Java Persistence API (JPA);

Exista mai multe implementari JPA.

• interfata de programare (API) Java Data Object (JDO);

• produsul Hibernate.

Hibernate contine si o implementare JPA.

• apache-empire

• ebean

Scopul urmarit este realizarea trecerii de la un SGBD la altul prin modificariminime ın stratul intermediar.

In cele ce urmeaza vom face abstractie de modelele mentionate anterior sivom trata ın modul cel mai simplu realizarea unei aplicatii care interactioneazacu o baza de date gestionata de un SGBD.

Pentru a avea acces la o baza de date trebuie stabilita o conexiune la aceabaza de date. In acest sens este necesar cunoasterea:

Page 353: programare distribuita

F.3. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE 353

• driver-ului de acces la sistemul de gestiune a bazei de date (SGBD)

Tip SGBD Driver Fisierul driver-ului

access sun.jdbc.odbc.JdbcOdbcDrivermysql com.mysql.jdbc.Driver mysql-connector-java-*.*.*-bin.jar

(www.mysql.com)derby org.apache.derby.jdbc.ClientDriver derbyclient.jarjavadb (distributia derby)

postgresql org.postgresql.Driver postgresql-*.*-*.jdbc4.jarhypeqsql org.hsqldb.jdbcDriver hsqldb.jaroraclexe oracle.jdbc.driver.OracleDriver ojdbc14.jar

Daca ıntr-un servlet se realizeaza o conexiune la o baza de date atuncifisierul driver-ului trebuie copiat ın catalogul lib al aplicatiei.

• adresa URI a bazei de date (String URIBazaDate), sub forma

Tip SGBD Referinta Baza de Date

mysql jdbc:mysql://host:3306/numeBazaDatederby / javadb jdbc:derby://host:1527/numeBazaDate

postgresql jdbc:postgresql://host:5432/numeBazaDatehypersql jdbc:hsqldb:hsql://host/numeBazaDate

oracle jdbc:oracle:thin:@host:1521:XE

Sablonul de prelucrare este

String URLBazaDate=. . .

Connection con=null;

try{

Class.forName(jdbcDriver).newInstance();

con=DriverManager.getConnection(URLBazaDate);

...

}

catch(ClassNotFoundException e){. . .}

catch(SQLException e){. . .}

Anumite SGBD asigura accesul la o baza de date daca sunt fixati parametriiusername si password. In acest caz se programeaza

con=DriverManager.getConnection(URLBazaDate,username,password);

Odata conexiunea cu baza de date stabilita se genereaza un obiect de tipStatement prin intermediul caruia se executa interogarea SQL.

Page 354: programare distribuita

354 ANEXA F. UTILIZAREA SGBD IN JAVA

Statement instructiune=con.createStatement();

String sql=. . . //fraza select;

Rezultatele interogarii bazei de date se obtine prin

try{

ResultSet rs=instructiune.executeQuery(sql);

while(rs.next()){

prelucrarea rezultatului

}

}

catch(SQLException e){...}

Exemplul F.3.1

O interogare simpla a bazei de date AgendaEMail se realizeaza cu programul

1 import java . s q l . Connection ;2 import java . s q l . DriverManager ;3 import java . s q l . Resu l tSet ;4 import java . s q l . Statement ;5 import java . u t i l . Scanner ;6 import java . u t i l . InputMismatchException ;

8 public class AgendaE{9 private stat ic St r ing jdbcURIDerby =

10 ” jdbc : derby :// l o c a l h o s t :1527/ AgendaEMail” ;11 private stat ic St r ing jdbcDriverDerby =12 ” org . apache . derby . jdbc . C l i en tDr ive r ” ;

14 private stat ic St r ing jdbcURIMysql =15 ” jdbc : mysql : // l o c a l h o s t :3306/ AgendaEMail? user=root ” ;16 private stat ic St r ing jdbcDriverMysql =17 ”com . mysql . jdbc . Dr iver ” ;

19 public stat ic void main ( St r ing [ ] a rgs ){20 St r ing dbms=null , username=null , password=null , jdbcURL=null ;21 switch ( args . l ength ){22 case 0 :23 System . out . p r i n t l n ( ”At l e a s t one argument r equ i r ed ” ) ;24 System . out . p r i n t l n ( ”DBMS username password” ) ;25 System . out . p r i n t l n ( ”DBMS derby , mysql” ) ;26 System . e x i t ( 0 ) ;27 break ;28 case 1 :29 dbms=args [ 0 ] ;30 break ;31 case 2 :32 dbms=args [ 0 ] ;33 username=args [ 1 ] ;34 password=”” ;35 break ;36 default :

Page 355: programare distribuita

F.3. SABLONUL DE UTILIZARE A UNEI BAZE DE DATE 355

37 dbms=args [ 0 ] ;38 username=args [ 1 ] ;39 password=args [ 2 ] ;40 }41 Connection conn = null ;42 try {43 switch (dbms){44 case ”derby” :45 Class . forName ( jdbcDriverDerby ) . newInstance ( ) ;46 jdbcURL=jdbcURIDerby ;47 break ;48 case ”mysql” :49 Class . forName ( jdbcDriverMysql ) . newInstance ( ) ;50 jdbcURL=jdbcURIMysql ;51 break ;52 default :53 System . out . p r i n t l n ( ”Unknown DBMS. . . ” ) ;54 System . e x i t ( 0 ) ;55 }56 System . out . p r i n t l n ( ”jdbcURI=”+jdbcURI ) ;57 i f ( password==null )58 conn = DriverManager . getConnect ion ( jdbcURI ) ;59 else60 conn=DriverManager . getConnect ion ( jdbcURI , username , password ) ;

62 Statement i n s t r u c t i u n e=conn . createStatement ( ) ;63 Scanner scanner=new Scanner ( System . in ) ;64 int pre l , no ;65 St r ing ch=”Y” ,nume=”” , emai l=”” , s q l=”” ;66 Resu l tSet r s=null ;

68 while ( ch . s tartsWith ( ”Y” ) ){69 do{70 System . out . p r i n t l n ( ” Continue ? (Y/N) ” ) ;71 ch=scanner . next ( ) . toUpperCase ( ) ;72 }73 while ( ( ! ch . s tartsWith ( ”Y”))&&(! ch . s tartsWith ( ”N” ) ) ) ;74 i f ( ch . s tartsWith ( ”Y” ) ){75 System . out . p r i n t l n ( ”Natura i n t e r o g a r i i ?” ) ;76 System . out . p r i n t l n ( ” (Dupa nume : 1 , Dupa emai l : 2 ) ” ) ;77 do{78 p r e l =0;79 try{80 p r e l=scanner . next Int ( ) ;81 }82 catch ( InputMismatchException e ){}83 }84 while ( ( pre l <1)&&(pre l >2)) ;85 switch ( p r e l ){86 case 1 :87 System . out . p r i n t l n ( ”Numele” ) ;88 nume=’ \ ’ ’+scanner . next ( ) . tr im ()+ ’ \ ’ ’ ;89 s q l=” s e l e c t ∗ from adrese where nume=”+nume ;90 r s=i n s t r u c t i u n e . executeQuery ( s q l ) ;91 break ;92 case 2 :93 System . out . p r i n t l n ( ”Email” ) ;94 emai l=’ \ ’ ’+scanner . next ( ) . tr im ()+ ’ \ ’ ’ ;95 s q l=” s e l e c t ∗ from adrese where emai l=”+emai l ;

Page 356: programare distribuita

356 ANEXA F. UTILIZAREA SGBD IN JAVA

96 r s=i n s t r u c t i u n e . executeQuery ( s q l ) ;97 break ;98 default : System . out . p r i n t l n ( ”Comanda eronata ” ) ;99 }

100 i f ( r s !=null ){101 System . out . p r i n t l n ( ” Resu l t s : ” ) ;102 while ( r s . next ( ) ){103 System . out . p r i n t l n ( ” id=” + rs . g e t In t ( ” id ” ) ) ;104 System . out . p r i n t l n ( ”nume=” + rs . g e t S t r i n g ( ”nume” ) ) ;105 System . out . p r i n t l n ( ” emai l=” + r s . g e t S t r i n g ( ” emai l ” ) ) ;106 System . out . p r i n t l n ( ”−−−−−−−−−−−−−−−−−” ) ;107 }108 }109 else {110 System . out . p r i n t l n ( ”No item found ! ” ) ;111 }112 }113 }114 }115 catch ( Exception e ) {116 // handle the ex ce p t io n117 e . pr intStackTrace ( ) ;118 }119 }120 }

Fraza select si interogarea se mai putea programa prin

String sql="select * from adrese where nume =?";

PreparedStatement prepStmt=con.prepareStatement(sql);

prepStmt.setString(1,nume);

RezultSet rs=prepStmt.executeQuery();

. . .

prepStmt.close();

In acest caz, valoarea variabilei nume este fara apostroafe.Compilarea si executia programului necesita declararea ın variabila classpath

a fisierelor

• Varianta Derby

derbyclient.jar din catalogul %DERBY INSTALL%\lib.

• Varianta mysql

%MYSQL CONNECTOR JAVA HOME%\mysql-connector-java-*.*.*-bin.jar

Executia programului presupune serverul SGBD activ.

Page 357: programare distribuita

Partea IV

TEME DE LABORATOR

357

Page 358: programare distribuita
Page 359: programare distribuita

Anexa G

Teme de aplicatii

G.1 Probleme propuse

1. Sa se realizeze conversia temperaturii exprimata ın grade Celsius ın gradeFahrenheit si invers. Formula de transformare este

tF = 1.8tC + 32oF

In RMI, programul server implementeaza interfata (la distanta)

package conversie;

public interface Grade extends java.rmi.Remote{

public double convert(String tip, double grate)

throws java.rmi.RemoteException;

}

unde tip este ”C2F” sau ”F2C”.

2. Sa se realizeze conversia a unei sume de bani ıntre USD, EURO si RON.

Programul server (RMI) implementeaza interfata

package exchange;

public interface IConversie extends java.rmi.Remote{

public double usdToEuro(double usd)

throws java.rmi.RemoteException;

public double usdToRol(double usd)

throws java.rmi.RemoteException;

public double euroToUsd(double euro)

throws java.rmi.RemoteException;

public double euroToRol(double euro)

throws java.rmi.RemoteException;

public double rolToEuro(double rol)

359

Page 360: programare distribuita

360 ANEXA G. TEME DE APLICATII

throws java.rmi.RemoteException;

public double rolToUsd(double rol)

throws java.rmi.RemoteException;

}

Rata zilnica de schimb preia dinamic sub forma unui fisier xml, apelandhttp://www.bnr.ro/nbrfxrates.xml.

3. Sa se realizeze conversia unui numar natural, din cifre arabe ın cifreromane si invers.

Pentru numere x ∈ (3999, 3999999], x = a ∗ 1000 + b se va folosi scriereasub forma (A)B, unde A,B reprezinta conversiile lui a, respectiv b.

Exemplu: Conversia numarului 2289463 este (MMCCLXXXIX)CDLXIII.

Pentru numere x ∈ (4000000, 3999999999], x = a∗1000000+b∗1000+c seva folosi scrierea sub forma [A](B)C, unde A,B,C reprezinta conversiilelui a, b, c.

4. Sa se realizeze conversia unui numar dintr-o baza ın alta.

5. Un server aduna la un numar (initializat cu 0) o valoare trimisa deun client returnand rezultatul. Exista o singura instanta a numarului,acelasi pentru orice client.

Sa se programeze serviciul descris mai sus.

6. Aplicatia producator – consumator.

Fie un sistem format din doua procese P1 si P2, primul producand nistedate care apoi vor fi preluate de cel de al doilea. Comunicarea ıntrecele doua procese se realizeaza prin intermediul unei zone de memorie– tampon, – de o anumita dimensiune, ın care procesul P1 introduceinformatii (sub forma unor ınregistrari), pe care apoi P2 le extrage.

Procesul P2 nu este nevoit sa astepte pentru fiecare ınregistrare ın parte,iar P1 nu astepta pana ce P2 este gata sa receptioneze ınregistrarea pro-dusa. Procesele evolueaza independent unul de celalat, P1 introducandın tampon ınregistrarea produsa, de unde P2 o va extrage la nevoie.

Se impun urmatoarele restrictii:

• Procesul P1 ıncearca sa introduca o ınregistrare ın tampon si con-stata ca acesta s-a umplut. In acest caz, el va trebui sa astepte panace se iveste un loc ın tampon (ceea ce se va ıntampla ca urmare aextrageri unei ınregistrari de catre P2).

Page 361: programare distribuita

G.1. PROBLEME PROPUSE 361

• Procesul P2 ıncearca sa extraga o ınregistrare si constata ca tam-ponul este gol. In acest caz el va trebui sa astepte pana ce apare oınregistrare ca urmare a introduceri unei ınregistrari ın tampon decatre P1.

Se defineste interfata RMI

package iprodcons;

public interface IBoundedBuffer extends java.rmi.Remote{

public void put(Object obj) throws java.rmi.RemoteException;

public Object get() throws java.rmi.RemoteException;

}

Se cere:

(a) Implementarea interfetei IBoundedBuffer.

(b) Realizarea a doua programe client Producator, care introduce obiecteın tampon si Consumator pentru extragerea lor.

7. Aplicatie de e-mail.

Un e-mail este definit printr-un ansamblu de 4 variabile de tip String

(de la (from), catre (to), subiect (subject), mesaj (body)).

package iemail;

import java.io.Serializable;

public class Email implements Serializable {

public String from = "";

public String subject = "";

public String to = "";

public String body = "";

public Email() {}

public Email(String from, String to, String subject, String body) {

this.from =from;

this.subject =subject;

this.to =to;

this.body =body;

}

}

Interfata aplicatiei RMI IEmailServer este

Page 362: programare distribuita

362 ANEXA G. TEME DE APLICATII

package iemail;

import java.rmi.*;

public interface IEmailServer extends Remote {

public boolean login(String name, String password)

throws RemoteException;

public void createUser(String name, String password)

throws RemoteException;

public void writeEmail(String from, String to,

String subject, String body) throws RemoteException,

UnknownUserException;

public void readEmail(String userName,ICallbackEmail ce)

throws RemoteException;

}

Un client / utilizator al serviciului sau serverului de e-mail este o instantaa clasei User.

package email;

import java.util.*;

import iemail.*;

public class User implements java.io.Serializable{

String name, password;

Vector emails = new Vector();

public User(String name, String password) {

this.name = name;

this.password = password;

}

public void addEmail(Email email) {

emails.addElement(email);

}

}

Pentru a putea folosi serverul de e-mail, un client trebuie ın prealabil sase ınregistreze (createUser).

Un client ınregistrat se poate conecta la serverul de e-mail (login) dupacare poate scrie (trimite) sau citi (receptiona) mesaje.

Se cere ca la adagarea unui mesaj (deci ınaintea apelarii metodei User.addEmail)sa se verifice daca emitentul este conectat si daca destinatarul este ınregistrat.ın caz contrar se genereaza exceptia UnknownUserException

package iemail;

public class UnknownUserException extends Exception {

public UnknownUserException() {

super();

}

Page 363: programare distribuita

G.1. PROBLEME PROPUSE 363

public UnknownUserException(String exception) {

super(exception);

}

}

Citirea mesajelor este lasata la latitudinea clientilor ın sensul ca clientulimplementeaza metoda printEmail al interfetei ICallbackEmail.

package iemail;

import java.rmi.*;

import java.rmi.server.*;

public interface ICallbackEmail extends Remote {

public void printEmail(Email email) throws RemoteException;

}

Solicitarea receptionarii mesajelor se realizeaza de catre server prin apelareametodei printEmail pentru fiecare mesaj primit de client.

Se cere:

(a) Implementarea interfetei IEmailServer.

(b) Realizarea a doua programe client AddClient pentru ınregistrareautilizatorilor si ClientEmail pentru exploatarea serviciului de e-mail. Fiecare din cele doua programe are ca parametri numele(identificatorul) clientului, parola si referinta serverului.

8. Integrare numerica.

Scopul aplicatiei este calculul unei integrale de un program server cufunctia de integrat detinuta de catre client. In cazul aplicatiei RMI,evaluarile functiei cerute de formula de integrare numerica se vor real-iza prin apel invers. Integrarea numerica va fi executat de un serverdisponibil clientilor prin mecanismul de fabrica de obiecte.

Interfata fabricii de obiecte este

package integ;

import java.rmi.*;

public interface IFabIntegrator extends Remote{

IIntegrator getIntegrator() throws RemoteException;

}

iar interfata IIntegrator este

package integ;

import java.rmi.*;

public interface IIntegrator extends Remote{

double adaptiveSimpson(double leftEnd, double rightEnd,

double epsilon, int initParam) throws RemoteException;

}

Page 364: programare distribuita

364 ANEXA G. TEME DE APLICATII

declara o metoda ce calculeaza un sir (Imk)k pana ın momentul |Imk

−Imk−1

| < ε.

Propunem utilizarea formulei lui Simpson∫ b

a

f(x)dx ≈ Im =b− a6m

[f(a) + 2m−1∑i=1

f(a2i) + 4m−1∑i=0

f(a2i+1) + f(b)]

unde ai = a+ i b−a2m.

Sirul (mk)k este definit prin mk = 2km0.

Semnificatia parametrilor metodei adaptiveSimpson este

leftEnd arightEnd bepsilon εinitParam m0

Interfata apelului invers este

package integ;

import java.rmi.*;

double function(double x)throws RemoteException;

}

Se cere implementarea aplicatiei cu minimizarea numarului de apelari ametodei function.

9. Agenda telefonica.

Pentru crearea si ıntretinerea unei agende telefonice utilizand RMI con-sideram:

Un ServerCarteTelefon realizeaza urmatoarele operatii:

• adauga o ınregisrare ın agenda telefonica;

O ınregistrare este alcatuita dintr-o pereche (nume, numar).

package itelef;

import java.io.Serializable;

public class Entry implements Serializable{

public String nume,numar;

public Entry(String nume,String numar){

this.nume=nume;

this.numar=numar;

}

}

Page 365: programare distribuita

G.1. PROBLEME PROPUSE 365

• sterge ınregistrarea corespunzatoare unui nume din agenda tele-fonica.

• interogarea agendei: furnizeaza numarul de telefon al unui nume;

• modificarea numarului de telefon corespunzator unui nume;

• afisarea ınregistrarilor;

• salvarea ınregistrarilor ıntr-un fisier;

• restaurarea ınregistrarilor dintr-un fisier.

Interfata corespunzatoare ICarteTelefon este

package itelef;

import java.rmi.*;

public interface ICarteTelefon extends Remote{

void addEntry(Entry e)throws RemoteException;

String lookupNumber(String p)throws RemoteException;

void deleteEntry(Entry e)throws RemoteException;

Entry[] list() throws RemoteException;

void save(String file)throws RemoteException;

void restore(String file)throws RemoteException,ClassNotFoundException;

void modifyEntry(Entry e)throws RemoteException;

}

Interfata fabricii de obiecte IFabCarteTelefon este

package itelef;

import java.rmi.*;

public interface IFabCarteTelefon extends Remote{

ICarteTelefon getCarteTelefon() throws RemoteException;

}

Se cere implementarea aplicatiei de creare si ıntretinere a agendei tele-fonice.

Se extinde aplicatia anterioara cu functiunea suplimentara a serverului dea retine toate modificarile efectuate de catre un client si care la solicitarepot fi afisate.

Modificarile se retin ıntr-o variabila mod de tip Vector. La solicitareaclientului, pentru fiecare modificare memorata, programul server ape-leaza metoda schimbStare declarata ın interfata

package itelef;

import java.rmi.*;

public interface IApelInvers extends Remote{

void schimbStare(Entry e) throws RemoteException;

}

Page 366: programare distribuita

366 ANEXA G. TEME DE APLICATII

Metoda schimbStare(Entry e) nu face altceva decat afiseaza campurilevariabilei e.

Interfata ICarteTelefon declara ın plus metoda

void apelInvers(IApelInvers obj)throws RemoteException;

Aceasta metoda va fi implementata ın programul ServerCarteTelefon.java.Elementelor retinute ın vectorul mod li se aplica metoda schimbStare().

Sa se implementeze acesta functiune utilizand tehnica apelului invers.

Se poate utiliza baza de date AGENDATELEFONICA formata din tabelul

TELEF

IDNUME

NUMAR

10. Sa se determine zodia (chinezeasca) corespunzatoare unei date calen-daristice. Obs. Inceputul anului nou chinezesc nu coincide cu ınceputulanului nou calendaristic.

Se va crea baza de date AN CHINEZESC alcatuita din tabelul

INCEPUT

ANLUNA

ZI

Se va tine seama de perioada de 12 ani de alternanta a zodiilor.

11. Se considera baza de date UNITATI DE MASURA formata din tabelul

CONVERSIE

UM SIUM SIMBOL

DENUMIRE (ROM)VAL

Exemplu:

1 M INCH Tol 0.02542 M FEET (FT) Picior 0.30483 KG UK ONCE Uncie (UK) 0.0311034 KG UK POUND Livra (UK) 0.373

Page 367: programare distribuita

G.1. PROBLEME PROPUSE 367

Sa se realizeze o aplicatie pentru conversia unitatilor de masura extinzandcontinutul bazei de date.

12. Se considera baza de date NORME-DIDACTICE formata din tabelele

CADRU-DIDACTIC MATERIA CURSURI

COD-CADRU-DIDACTIC COD-MATERIE COD-CURSNUME DENUMIRE COD-CADRU-DIDACTIC

COD-MATERIE

Sa se elaboreze programe de ıntretinere si interogare a bazei de date.

13. Se considera baza de date APROVIZIONARE formata din tabelele

RESURSA FURNIZOR CONTRACT

COD-RESURSA COD-FURNIZOR COD-CONTRACTDENUMIRE NUME COD-FURNIZOR

COD-RESURSACANTITATE

Sa se elaboreze programe de ıntretinere si interogare a bazei de date.

14. Se considera baza de date DESFACERE formata din tabelele

PRODUSE BENEFICIAR CONTRACT

COD-PRODUS COD-BENEFICIAR COD-CONTRACTDENUMIRE NUME COD-BENEFICIAR

COD-PRODUSCANTITATE

Sa se elaboreze programe de ıntretinere si interogare a bazei de date.

15. Validarea codului numeric personal.

Codul Numeric Personal (CNP) constituie numarul de ordine atribuit de

Evidenta populatiei unei persoane la nastere, de cetatenie romana, care se

ınscrie ın actele si certificatele de stare civila si se preia ın celelate acte cu

caracter oficial.

Structura unui CMP este

Page 368: programare distribuita

368 ANEXA G. TEME DE APLICATII

S AA LL ZZ JJ ZZZ C

| | | | | | |-> cifra de control

| | | | | |-> numar de ordine atribuit persoanei

| | | | |-> codul judetului

| | | |-> ziua nasterii

| | |-> Luna nasterii

| |-> Anul nasterii

|-> Cifra sexului (M/F)

1/2 nascuti intre 1 ian 1900 si 31 dec 1999

3/4 nascuti intre 1 ian 1800 si 31 dec 1899

5/6 nascuti intre 1 ian 2000 si 31 dec 2099

7/8 rezidenti

Verificarea cifrei de control: Se foloseste cheia de testare 279146358279.Primele 12 cifre ale CNP se ınmultesc pe rand de la stanga spre dreaptacu cifra corespunzatoare a cheii de testare. Cele 12 produse se aduna,iar suma se ımparte la 11. Daca restul ımpartirii este mai mic decat 10,atunci acesta va fi cifra de control. Daca restul ımpartirii este 10 atuncicifra de control este 1.

Sa se elaboreze un program pentru verificarea CNP.

16. Informatiile unui aeroport civil privind decolarile(plecari) si aterizari(sosiri)pe parcursul unei perioade sunt cuprinse ın tabelul activitate al bazei dedate aeroport

ACTIVITATE

IDFEL aterizare/decolareZITIMP ora/minutCOMPANIEOBSERVATIE de la/spre

Sa se realizeze o aplicatie de furnizare a datelor catre clienti (interogareabazei de date).

17. Se dau n tipuri de monede Mx1 ,Mx2 , . . . ,Mxn , xi reprezentand valoareamonedei, i = 1, 2, . . . , n. Sa se determine variantele de plata a unei sumeS cu un numar minim de monede din cele disponibile.

Page 369: programare distribuita

G.1. PROBLEME PROPUSE 369

Se vor trata cazurile:

(a) Numarul monedelor de fiecare tip este nelimitat.

(b) Numarul monedelor disponibile este marginit, respectiv de numerelek1, k2, . . . , kn(k1x1 + . . .+ knxn ≥ S).

18. Globul pamantesc este ımpartit ın 24 de fuse orare de cate 15o(24 ∗ 15 =360) pornind de la meridianul 0 spre stanga si dreapta.

• Dandu-se longitudinile a 2 puncte de pe glob sa se calculeze diferentade fus orar.

• Fixand ora ın primul punct sa se indice ora ın al doilea punct.

19. Sa se calculeze unghiurile unui triunghi dat prin coordonatele varfurilor.

20. Fixand coeficientii a, b, c, d, e, f ale conicei

ax2 + 2bxy + cy2 + 2dx+ 2ey + f = 0

sa se reduca conica la forma canonica.

21. Sa se calculeze suma multiplilor de 3 sau 5 mai mici decat un numar datn.

22. Fie polinomul trigonometric par Θ(θ) = α0 +∑n

j=1 αj cos jθ, n ≤ 10. Sase calculeze polinomul P (x) = Θ(arccos x).

23. Se da polinomul P (x) = a0 + a1x+ . . .+ anxn, n ≤ 10. Sa se determine

polinomul trigonometri par Θ(θ) = a0 + a1 cos θ + . . . + an cosn θ subforma Θ(θ) = α0 +

∑nj=1 αj cos jθ.

24. Fie p ∈ N∗ fixat si n ∈ N, 0 ≤ n ≤ 2p − 1 cu reprezentarea binaran = ap−1ap−2 . . . a1a02. Sa se determine numarul m care are reprezentareabinara m = a0a1 . . . ap−2ap−12.

De exemplu, pentru p = 6, n = 17 = 0100012 numarul cautat este m =1000102 = 34.

25. Sa se determine numarul de aparitii al fiecarui cuvant dintr-un text dat.

Page 370: programare distribuita

370 ANEXA G. TEME DE APLICATII

26. Sa se calculeze Bn (Numerele lui Bernoulli) definit prin

Bn =

1 daca n = 0

∑n−1k=0

n+ 1k

Bk

n+1daca n > 0

Calculele se fac ın Q.

Page 371: programare distribuita

Bibliografie

[1] ALBOAIE L., BURAGA S., 2006, Servicii Web. Ed. Polirom, Iasi.

[2] ATHANASIU I., COSTINESCU B., DRAGOI O.A., POPOVICI F.I.,1998, Limbajul Java. O perspectiva pragmatica. Ed. Computer LibrisAgora, Cluj-Napoca.

[3] BOIAN F.M., BOIAN R. F., 2004, Tehnologii fundamentale Java pentruaplicatii Web. Ed. Albastra, Cluj-Napoca.

[4] BOIAN F.M., 2011, Servicii Web; Modele, Platforme, Aplicatii. Ed. Al-bastra, Cluj-Napoca.

[5] BURAGA S.C., 2001, Tehnologii Web. Ed. Matrix Rom,Bucuresti.

[6] BURAGA S. (ed), 2007, Programarea ın Web 2.0., Ed. Polirom, Iasi.

[7] COULOURIS G., DOLLIMORE J., KINDBERG T., Distributed Systems.Concepts and Design. Addison Wesley, 2005.

[8] JURCA I., 2000, Programarea retelelor de calculatoare. Ed. de Vest,Timisoara.

[9] SCHEIBER E., 2007, Programare concurenta si paralel distribuita ın Java.Ed. Albastra, Cluj-Napoca.

[10] TANASA S., ANDREI S., OLARU C., 2011, Java de la 0 la extert. Ed.Polirom, Iasi.

[11] TANASA S., OLARU C., 2005, Dezvoltarea aplicatiilor Web folosindJava. Ed. Polirom, Iasi.

371